Commit bfd654d84fe4a270a76e815eb8eb428cde02e62e

Authored by Igor Kulikov
1 parent 912c572a

Add social share buttons for public dashboards sharing. Improve dashboard toolba…

…r configuration. Add project version information to bottom right part of the dashboard.
@@ -33,6 +33,7 @@ @@ -33,6 +33,7 @@
33 "angular-messages": "1.5.8", 33 "angular-messages": "1.5.8",
34 "angular-route": "1.5.8", 34 "angular-route": "1.5.8",
35 "angular-sanitize": "1.5.8", 35 "angular-sanitize": "1.5.8",
  36 + "angular-socialshare": "^2.3.8",
36 "angular-storage": "0.0.15", 37 "angular-storage": "0.0.15",
37 "angular-touch": "1.5.8", 38 "angular-touch": "1.5.8",
38 "angular-translate": "2.13.1", 39 "angular-translate": "2.13.1",
@@ -19,6 +19,7 @@ import angular from 'angular'; @@ -19,6 +19,7 @@ import angular from 'angular';
19 import ngMaterial from 'angular-material'; 19 import ngMaterial from 'angular-material';
20 import ngMdIcons from 'angular-material-icons'; 20 import ngMdIcons from 'angular-material-icons';
21 import ngCookies from 'angular-cookies'; 21 import ngCookies from 'angular-cookies';
  22 +import angularSocialshare from 'angular-socialshare';
22 import 'angular-translate'; 23 import 'angular-translate';
23 import 'angular-translate-loader-static-files'; 24 import 'angular-translate-loader-static-files';
24 import 'angular-translate-storage-local'; 25 import 'angular-translate-storage-local';
@@ -82,6 +83,7 @@ angular.module('thingsboard', [ @@ -82,6 +83,7 @@ angular.module('thingsboard', [
82 ngMaterial, 83 ngMaterial,
83 ngMdIcons, 84 ngMdIcons,
84 ngCookies, 85 ngCookies,
  86 + angularSocialshare,
85 'pascalprecht.translate', 87 'pascalprecht.translate',
86 'mdColorPicker', 88 'mdColorPicker',
87 mdPickers, 89 mdPickers,
@@ -106,7 +106,8 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) { @@ -106,7 +106,8 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) {
106 isDescriptorSchemaNotEmpty: isDescriptorSchemaNotEmpty, 106 isDescriptorSchemaNotEmpty: isDescriptorSchemaNotEmpty,
107 filterSearchTextEntities: filterSearchTextEntities, 107 filterSearchTextEntities: filterSearchTextEntities,
108 guid: guid, 108 guid: guid,
109 - createDatasoucesFromSubscriptionsInfo: createDatasoucesFromSubscriptionsInfo 109 + createDatasoucesFromSubscriptionsInfo: createDatasoucesFromSubscriptionsInfo,
  110 + isLocalUrl: isLocalUrl
110 } 111 }
111 112
112 return service; 113 return service;
@@ -428,4 +429,15 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) { @@ -428,4 +429,15 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) {
428 return deferred.promise; 429 return deferred.promise;
429 } 430 }
430 431
  432 + function isLocalUrl(url) {
  433 + var parser = document.createElement('a'); //eslint-disable-line
  434 + parser.href = url;
  435 + var host = parser.hostname;
  436 + if (host === "localhost" || host === "127.0.0.1") {
  437 + return true;
  438 + } else {
  439 + return false;
  440 + }
  441 + }
  442 +
431 } 443 }
  1 +/*
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +/* eslint-disable import/no-unresolved, import/default */
  18 +
  19 +import socialsharePanelTemplate from './socialshare-panel.tpl.html';
  20 +
  21 +/* eslint-enable import/no-unresolved, import/default */
  22 +
  23 +
  24 +export default angular.module('thingsboard.directives.socialsharePanel', [])
  25 + .directive('tbSocialSharePanel', SocialsharePanel)
  26 + .name;
  27 +
  28 +/*@ngInject*/
  29 +function SocialsharePanel() {
  30 + return {
  31 + restrict: "E",
  32 + scope: true,
  33 + bindToController: {
  34 + shareTitle: '@',
  35 + shareText: '@',
  36 + shareLink: '@',
  37 + shareHashTags: '@'
  38 + },
  39 + controller: SocialsharePanelController,
  40 + controllerAs: 'vm',
  41 + templateUrl: socialsharePanelTemplate
  42 + };
  43 +}
  44 +
  45 +/*@ngInject*/
  46 +function SocialsharePanelController(utils) {
  47 +
  48 + let vm = this;
  49 +
  50 + vm.isShareLinkLocal = function() {
  51 + if (vm.shareLink && vm.shareLink.length > 0) {
  52 + return utils.isLocalUrl(vm.shareLink);
  53 + } else {
  54 + return true;
  55 + }
  56 + }
  57 +
  58 +}
  1 +<!--
  2 +
  3 + Copyright © 2016-2017 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +
  19 +<div layout="row" ng-show="!vm.isShareLinkLocal()">
  20 + <md-button class="md-icon-button md-raised md-primary"
  21 + socialshare
  22 + socialshare-provider="facebook"
  23 + socialshare-title="{{ vm.shareTitle }}"
  24 + socialshare-text="{{ vm.shareText }}"
  25 + socialshare-url="{{ vm.shareLink }}">
  26 + <ng-md-icon icon="facebook" aria-label="Facebook"></ng-md-icon>
  27 + <md-tooltip md-direction="top">
  28 + {{ 'action.share-via' | translate:{provider:'Facebook'} }}
  29 + </md-tooltip>
  30 + </md-button>
  31 + <md-button class="md-icon-button md-raised md-primary"
  32 + socialshare
  33 + socialshare-provider="twitter"
  34 + socialshare-text="{{ vm.shareTitle }}"
  35 + socialshare-hashtags="{{ vm.shareHashTags }}"
  36 + socialshare-url="{{ vm.shareLink }}">
  37 + <ng-md-icon icon="twitter" aria-label="Twitter"></ng-md-icon>
  38 + <md-tooltip md-direction="top">
  39 + {{ 'action.share-via' | translate:{provider:'Twitter'} }}
  40 + </md-tooltip>
  41 + </md-button>
  42 + <md-button class="md-icon-button md-raised md-primary"
  43 + socialshare
  44 + socialshare-provider="linkedin"
  45 + socialshare-text="{{ vm.shareTitle }}"
  46 + socialshare-url="{{ vm.shareLink }}">
  47 + <ng-md-icon icon="linkedin" aria-label="Linkedin"></ng-md-icon>
  48 + <md-tooltip md-direction="top">
  49 + {{ 'action.share-via' | translate:{provider:'Linkedin'} }}
  50 + </md-tooltip>
  51 + </md-button>
  52 + <md-button class="md-icon-button md-raised md-primary"
  53 + socialshare
  54 + socialshare-provider="reddit"
  55 + socialshare-text="{{ vm.shareTitle }}"
  56 + socialshare-url="{{ vm.shareLink }}">
  57 + <md-icon md-svg-icon="mdi:reddit" aria-label="Reddit"></md-icon>
  58 + <md-tooltip md-direction="top">
  59 + {{ 'action.share-via' | translate:{provider:'Reddit'} }}
  60 + </md-tooltip>
  61 + </md-button>
  62 +</div>
@@ -36,20 +36,28 @@ @@ -36,20 +36,28 @@
36 <label translate>dashboard.assignedToCustomer</label> 36 <label translate>dashboard.assignedToCustomer</label>
37 <input ng-model="assignedCustomer.title" disabled> 37 <input ng-model="assignedCustomer.title" disabled>
38 </md-input-container> 38 </md-input-container>
39 - <div layout="row" ng-show="!isEdit && isPublic && (dashboardScope === 'customer' || dashboardScope === 'tenant')">  
40 - <md-input-container class="md-block" flex>  
41 - <label translate>dashboard.public-link</label>  
42 - <input ng-model="publicLink" disabled>  
43 - </md-input-container>  
44 - <md-button class="md-icon-button" style="margin-top: 14px;"  
45 - ngclipboard  
46 - data-clipboard-text="{{ publicLink }}"  
47 - ngclipboard-success="onPublicLinkCopied(e)">  
48 - <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>  
49 - <md-tooltip md-direction="top">  
50 - {{ 'dashboard.copy-public-link' | translate }}  
51 - </md-tooltip>  
52 - </md-button> 39 + <div layout="column" ng-show="!isEdit && isPublic && (dashboardScope === 'customer' || dashboardScope === 'tenant')">
  40 + <tb-social-share-panel style="padding-bottom: 10px;"
  41 + share-title="{{ 'dashboard.socialshare-title' | translate:{dashboardTitle: dashboard.title} }}"
  42 + share-text="{{ 'dashboard.socialshare-text' | translate:{dashboardTitle: dashboard.title} }}"
  43 + share-link="{{ publicLink }}"
  44 + share-hash-tags="thingsboard, iot">
  45 + </tb-social-share-panel>
  46 + <div layout="row">
  47 + <md-input-container class="md-block" flex>
  48 + <label translate>dashboard.public-link</label>
  49 + <input ng-model="publicLink" disabled>
  50 + </md-input-container>
  51 + <md-button class="md-icon-button" style="margin-top: 14px;"
  52 + ngclipboard
  53 + data-clipboard-text="{{ publicLink }}"
  54 + ngclipboard-success="onPublicLinkCopied(e)">
  55 + <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
  56 + <md-tooltip md-direction="top">
  57 + {{ 'dashboard.copy-public-link' | translate }}
  58 + </md-tooltip>
  59 + </md-button>
  60 + </div>
53 </div> 61 </div>
54 <fieldset ng-disabled="loading || !isEdit"> 62 <fieldset ng-disabled="loading || !isEdit">
55 <md-input-container class="md-block"> 63 <md-input-container class="md-block">
@@ -31,6 +31,18 @@ export default function DashboardSettingsController($scope, $mdDialog, gridSetti @@ -31,6 +31,18 @@ export default function DashboardSettingsController($scope, $mdDialog, gridSetti
31 vm.gridSettings.showTitle = true; 31 vm.gridSettings.showTitle = true;
32 } 32 }
33 33
  34 + if (angular.isUndefined(vm.gridSettings.showDevicesSelect)) {
  35 + vm.gridSettings.showDevicesSelect = true;
  36 + }
  37 +
  38 + if (angular.isUndefined(vm.gridSettings.showDashboardTimewindow)) {
  39 + vm.gridSettings.showDashboardTimewindow = true;
  40 + }
  41 +
  42 + if (angular.isUndefined(vm.gridSettings.showDashboardExport)) {
  43 + vm.gridSettings.showDashboardExport = true;
  44 + }
  45 +
34 vm.gridSettings.backgroundColor = vm.gridSettings.backgroundColor || 'rgba(0,0,0,0)'; 46 vm.gridSettings.backgroundColor = vm.gridSettings.backgroundColor || 'rgba(0,0,0,0)';
35 vm.gridSettings.titleColor = vm.gridSettings.titleColor || 'rgba(0,0,0,0.870588)'; 47 vm.gridSettings.titleColor = vm.gridSettings.titleColor || 'rgba(0,0,0,0.870588)';
36 vm.gridSettings.columns = vm.gridSettings.columns || 24; 48 vm.gridSettings.columns = vm.gridSettings.columns || 24;
@@ -48,6 +48,17 @@ @@ -48,6 +48,17 @@
48 md-color-history="false" 48 md-color-history="false"
49 ></div> 49 ></div>
50 </div> 50 </div>
  51 + <div layout="row" layout-align="start center">
  52 + <md-checkbox flex aria-label="{{ 'dashboard.display-device-selection' | translate }}"
  53 + ng-model="vm.gridSettings.showDevicesSelect">{{ 'dashboard.display-device-selection' | translate }}
  54 + </md-checkbox>
  55 + <md-checkbox flex aria-label="{{ 'dashboard.display-dashboard-timewindow' | translate }}"
  56 + ng-model="vm.gridSettings.showDashboardTimewindow">{{ 'dashboard.display-dashboard-timewindow' | translate }}
  57 + </md-checkbox>
  58 + <md-checkbox flex aria-label="{{ 'dashboard.display-dashboard-export' | translate }}"
  59 + ng-model="vm.gridSettings.showDashboardExport">{{ 'dashboard.display-dashboard-export' | translate }}
  60 + </md-checkbox>
  61 + </div>
51 <md-input-container class="md-block"> 62 <md-input-container class="md-block">
52 <label translate>dashboard.columns-count</label> 63 <label translate>dashboard.columns-count</label>
53 <input required type="number" step="any" name="columns" ng-model="vm.gridSettings.columns" min="10" 64 <input required type="number" step="any" name="columns" ng-model="vm.gridSettings.columns" min="10"
@@ -48,6 +48,8 @@ export default function DashboardController(types, widgetService, userService, @@ -48,6 +48,8 @@ export default function DashboardController(types, widgetService, userService,
48 48
49 vm.isToolbarOpened = false; 49 vm.isToolbarOpened = false;
50 50
  51 + vm.thingsboardVersion = THINGSBOARD_VERSION; //eslint-disable-line
  52 +
51 vm.currentDashboardId = $stateParams.dashboardId; 53 vm.currentDashboardId = $stateParams.dashboardId;
52 if ($stateParams.customerId) { 54 if ($stateParams.customerId) {
53 vm.currentCustomerId = $stateParams.customerId; 55 vm.currentCustomerId = $stateParams.customerId;
@@ -105,6 +107,9 @@ export default function DashboardController(types, widgetService, userService, @@ -105,6 +107,9 @@ export default function DashboardController(types, widgetService, userService,
105 vm.onRevertWidgetEdit = onRevertWidgetEdit; 107 vm.onRevertWidgetEdit = onRevertWidgetEdit;
106 vm.helpLinkIdForWidgetType = helpLinkIdForWidgetType; 108 vm.helpLinkIdForWidgetType = helpLinkIdForWidgetType;
107 vm.displayTitle = displayTitle; 109 vm.displayTitle = displayTitle;
  110 + vm.displayExport = displayExport;
  111 + vm.displayDashboardTimewindow = displayDashboardTimewindow;
  112 + vm.displayDevicesSelect = displayDevicesSelect;
108 113
109 vm.widgetsBundle; 114 vm.widgetsBundle;
110 115
@@ -565,6 +570,33 @@ export default function DashboardController(types, widgetService, userService, @@ -565,6 +570,33 @@ export default function DashboardController(types, widgetService, userService,
565 } 570 }
566 } 571 }
567 572
  573 + function displayExport() {
  574 + if (vm.dashboard && vm.dashboard.configuration.gridSettings &&
  575 + angular.isDefined(vm.dashboard.configuration.gridSettings.showDashboardExport)) {
  576 + return vm.dashboard.configuration.gridSettings.showDashboardExport;
  577 + } else {
  578 + return true;
  579 + }
  580 + }
  581 +
  582 + function displayDashboardTimewindow() {
  583 + if (vm.dashboard && vm.dashboard.configuration.gridSettings &&
  584 + angular.isDefined(vm.dashboard.configuration.gridSettings.showDashboardTimewindow)) {
  585 + return vm.dashboard.configuration.gridSettings.showDashboardTimewindow;
  586 + } else {
  587 + return true;
  588 + }
  589 + }
  590 +
  591 + function displayDevicesSelect() {
  592 + if (vm.dashboard && vm.dashboard.configuration.gridSettings &&
  593 + angular.isDefined(vm.dashboard.configuration.gridSettings.showDevicesSelect)) {
  594 + return vm.dashboard.configuration.gridSettings.showDevicesSelect;
  595 + } else {
  596 + return true;
  597 + }
  598 + }
  599 +
568 function onRevertWidgetEdit(widgetForm) { 600 function onRevertWidgetEdit(widgetForm) {
569 if (widgetForm.$dirty) { 601 if (widgetForm.$dirty) {
570 widgetForm.$setPristine(); 602 widgetForm.$setPristine();
@@ -49,16 +49,21 @@ @@ -49,16 +49,21 @@
49 </md-button> 49 </md-button>
50 <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true"> 50 <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true">
51 </tb-user-menu> 51 </tb-user-menu>
52 - <md-button aria-label="{{ 'action.export' | translate }}" class="md-icon-button" 52 + <md-button ng-show="vm.isEdit || vm.displayExport()"
  53 + aria-label="{{ 'action.export' | translate }}" class="md-icon-button"
53 ng-click="vm.exportDashboard($event)"> 54 ng-click="vm.exportDashboard($event)">
54 <md-tooltip md-direction="bottom"> 55 <md-tooltip md-direction="bottom">
55 {{ 'dashboard.export' | translate }} 56 {{ 'dashboard.export' | translate }}
56 </md-tooltip> 57 </md-tooltip>
57 <md-icon aria-label="{{ 'action.export' | translate }}" class="material-icons">file_download</md-icon> 58 <md-icon aria-label="{{ 'action.export' | translate }}" class="material-icons">file_download</md-icon>
58 </md-button> 59 </md-button>
59 - <tb-timewindow is-toolbar direction="left" tooltip-direction="bottom" aggregation ng-model="vm.dashboardConfiguration.timewindow"> 60 + <tb-timewindow ng-show="vm.isEdit || vm.displayDashboardTimewindow()"
  61 + is-toolbar
  62 + direction="left"
  63 + tooltip-direction="bottom" aggregation
  64 + ng-model="vm.dashboardConfiguration.timewindow">
60 </tb-timewindow> 65 </tb-timewindow>
61 - <tb-aliases-device-select ng-show="!vm.isEdit" 66 + <tb-aliases-device-select ng-show="!vm.isEdit && vm.displayDevicesSelect()"
62 tooltip-direction="bottom" 67 tooltip-direction="bottom"
63 ng-model="vm.aliasesInfo.deviceAliases" 68 ng-model="vm.aliasesInfo.deviceAliases"
64 device-aliases-info="vm.aliasesInfo.deviceAliasesInfo"> 69 device-aliases-info="vm.aliasesInfo.deviceAliasesInfo">
@@ -304,6 +309,6 @@ @@ -304,6 +309,6 @@
304 </section> 309 </section>
305 </section> 310 </section>
306 <section class="tb-powered-by-footer" ng-style="{'color': vm.dashboard.configuration.gridSettings.titleColor}"> 311 <section class="tb-powered-by-footer" ng-style="{'color': vm.dashboard.configuration.gridSettings.titleColor}">
307 - <span>Powered by <a href="https://thingsboard.io" target="_blank">Thingsboard</a></span> 312 + <span>Powered by <a href="https://thingsboard.io" target="_blank">Thingsboard v.{{ vm.thingsboardVersion }}</a></span>
308 </section> 313 </section>
309 </md-content> 314 </md-content>
@@ -224,7 +224,7 @@ export function DashboardsController(userService, dashboardService, customerServ @@ -224,7 +224,7 @@ export function DashboardsController(userService, dashboardService, customerServ
224 onAction: function ($event, item) { 224 onAction: function ($event, item) {
225 unassignFromCustomer($event, item, true); 225 unassignFromCustomer($event, item, true);
226 }, 226 },
227 - name: function() { return $translate.instant('action.unshare') }, 227 + name: function() { return $translate.instant('action.make-private') },
228 details: function() { return $translate.instant('dashboard.make-private') }, 228 details: function() { return $translate.instant('dashboard.make-private') },
229 icon: "reply", 229 icon: "reply",
230 isEnabled: function(dashboard) { 230 isEnabled: function(dashboard) {
@@ -329,7 +329,7 @@ export function DashboardsController(userService, dashboardService, customerServ @@ -329,7 +329,7 @@ export function DashboardsController(userService, dashboardService, customerServ
329 onAction: function ($event, item) { 329 onAction: function ($event, item) {
330 unassignFromCustomer($event, item, true); 330 unassignFromCustomer($event, item, true);
331 }, 331 },
332 - name: function() { return $translate.instant('action.unshare') }, 332 + name: function() { return $translate.instant('action.make-private') },
333 details: function() { return $translate.instant('dashboard.make-private') }, 333 details: function() { return $translate.instant('dashboard.make-private') },
334 icon: "reply", 334 icon: "reply",
335 isEnabled: function(dashboard) { 335 isEnabled: function(dashboard) {
@@ -404,7 +404,28 @@ export function DashboardsController(userService, dashboardService, customerServ @@ -404,7 +404,28 @@ export function DashboardsController(userService, dashboardService, customerServ
404 } 404 }
405 405
406 function saveDashboard(dashboard) { 406 function saveDashboard(dashboard) {
407 - return dashboardService.saveDashboard(dashboard); 407 + var deferred = $q.defer();
  408 + dashboardService.saveDashboard(dashboard).then(
  409 + function success(savedDashboard) {
  410 + var dashboards = [ savedDashboard ];
  411 + customerService.applyAssignedCustomersInfo(dashboards).then(
  412 + function success(items) {
  413 + if (items && items.length == 1) {
  414 + deferred.resolve(items[0]);
  415 + } else {
  416 + deferred.reject();
  417 + }
  418 + },
  419 + function fail() {
  420 + deferred.reject();
  421 + }
  422 + );
  423 + },
  424 + function fail() {
  425 + deferred.reject();
  426 + }
  427 + );
  428 + return deferred.promise;
408 } 429 }
409 430
410 function assignToCustomer($event, dashboardIds) { 431 function assignToCustomer($event, dashboardIds) {
@@ -30,6 +30,7 @@ import thingsboardDashboardSelect from '../components/dashboard-select.directive @@ -30,6 +30,7 @@ import thingsboardDashboardSelect from '../components/dashboard-select.directive
30 import thingsboardDashboard from '../components/dashboard.directive'; 30 import thingsboardDashboard from '../components/dashboard.directive';
31 import thingsboardExpandFullscreen from '../components/expand-fullscreen.directive'; 31 import thingsboardExpandFullscreen from '../components/expand-fullscreen.directive';
32 import thingsboardWidgetsBundleSelect from '../components/widgets-bundle-select.directive'; 32 import thingsboardWidgetsBundleSelect from '../components/widgets-bundle-select.directive';
  33 +import thingsboardSocialsharePanel from '../components/socialshare-panel.directive';
33 import thingsboardTypes from '../common/types.constant'; 34 import thingsboardTypes from '../common/types.constant';
34 import thingsboardItemBuffer from '../services/item-buffer.service'; 35 import thingsboardItemBuffer from '../services/item-buffer.service';
35 import thingsboardImportExport from '../import-export'; 36 import thingsboardImportExport from '../import-export';
@@ -64,7 +65,8 @@ export default angular.module('thingsboard.dashboard', [ @@ -64,7 +65,8 @@ export default angular.module('thingsboard.dashboard', [
64 thingsboardDashboardSelect, 65 thingsboardDashboardSelect,
65 thingsboardDashboard, 66 thingsboardDashboard,
66 thingsboardExpandFullscreen, 67 thingsboardExpandFullscreen,
67 - thingsboardWidgetsBundleSelect 68 + thingsboardWidgetsBundleSelect,
  69 + thingsboardSocialsharePanel
68 ]) 70 ])
69 .config(DashboardRoutes) 71 .config(DashboardRoutes)
70 .controller('DashboardsController', DashboardsController) 72 .controller('DashboardsController', DashboardsController)
@@ -43,6 +43,12 @@ @@ -43,6 +43,12 @@
43 </md-button> 43 </md-button>
44 </div> 44 </div>
45 <div class="tb-notice" translate>dashboard.public-dashboard-notice</div> 45 <div class="tb-notice" translate>dashboard.public-dashboard-notice</div>
  46 + <tb-social-share-panel style="padding-top: 15px;"
  47 + share-title="{{ 'dashboard.socialshare-title' | translate:{dashboardTitle:vm.dashboard.title} }}"
  48 + share-text="{{ 'dashboard.socialshare-text' | translate:{dashboardTitle:vm.dashboard.title} }}"
  49 + share-link="{{ vm.publicLink }}"
  50 + share-hash-tags="thingsboard, iot">
  51 + </tb-social-share-panel>
46 </md-content> 52 </md-content>
47 </div> 53 </div>
48 </md-dialog-content> 54 </md-dialog-content>
@@ -185,7 +185,7 @@ export function DeviceController(userService, deviceService, customerService, $s @@ -185,7 +185,7 @@ export function DeviceController(userService, deviceService, customerService, $s
185 onAction: function ($event, item) { 185 onAction: function ($event, item) {
186 unassignFromCustomer($event, item, true); 186 unassignFromCustomer($event, item, true);
187 }, 187 },
188 - name: function() { return $translate.instant('action.unshare') }, 188 + name: function() { return $translate.instant('action.make-private') },
189 details: function() { return $translate.instant('device.make-private') }, 189 details: function() { return $translate.instant('device.make-private') },
190 icon: "reply", 190 icon: "reply",
191 isEnabled: function(device) { 191 isEnabled: function(device) {
@@ -271,7 +271,7 @@ export function DeviceController(userService, deviceService, customerService, $s @@ -271,7 +271,7 @@ export function DeviceController(userService, deviceService, customerService, $s
271 onAction: function ($event, item) { 271 onAction: function ($event, item) {
272 unassignFromCustomer($event, item, true); 272 unassignFromCustomer($event, item, true);
273 }, 273 },
274 - name: function() { return $translate.instant('action.unshare') }, 274 + name: function() { return $translate.instant('action.make-private') },
275 details: function() { return $translate.instant('device.make-private') }, 275 details: function() { return $translate.instant('device.make-private') },
276 icon: "reply", 276 icon: "reply",
277 isEnabled: function(device) { 277 isEnabled: function(device) {
@@ -364,8 +364,29 @@ export function DeviceController(userService, deviceService, customerService, $s @@ -364,8 +364,29 @@ export function DeviceController(userService, deviceService, customerService, $s
364 return device ? device.name : ''; 364 return device ? device.name : '';
365 } 365 }
366 366
367 - function saveDevice (device) {  
368 - return deviceService.saveDevice(device); 367 + function saveDevice(device) {
  368 + var deferred = $q.defer();
  369 + deviceService.saveDevice(device).then(
  370 + function success(savedDevice) {
  371 + var devices = [ savedDevice ];
  372 + customerService.applyAssignedCustomersInfo(devices).then(
  373 + function success(items) {
  374 + if (items && items.length == 1) {
  375 + deferred.resolve(items[0]);
  376 + } else {
  377 + deferred.reject();
  378 + }
  379 + },
  380 + function fail() {
  381 + deferred.reject();
  382 + }
  383 + );
  384 + },
  385 + function fail() {
  386 + deferred.reject();
  387 + }
  388 + );
  389 + return deferred.promise;
369 } 390 }
370 391
371 function isCustomerUser() { 392 function isCustomerUser() {
@@ -44,7 +44,7 @@ export default angular.module('thingsboard.locale', []) @@ -44,7 +44,7 @@ export default angular.module('thingsboard.locale', [])
44 "assign": "Assign", 44 "assign": "Assign",
45 "unassign": "Unassign", 45 "unassign": "Unassign",
46 "share": "Share", 46 "share": "Share",
47 - "unshare": "Unshare", 47 + "make-private": "Make private",
48 "apply": "Apply", 48 "apply": "Apply",
49 "apply-changes": "Apply changes", 49 "apply-changes": "Apply changes",
50 "edit-mode": "Edit mode", 50 "edit-mode": "Edit mode",
@@ -63,7 +63,8 @@ export default angular.module('thingsboard.locale', []) @@ -63,7 +63,8 @@ export default angular.module('thingsboard.locale', [])
63 "copy": "Copy", 63 "copy": "Copy",
64 "paste": "Paste", 64 "paste": "Paste",
65 "import": "Import", 65 "import": "Import",
66 - "export": "Export" 66 + "export": "Export",
  67 + "share-via": "Share via {{provider}}"
67 }, 68 },
68 "aggregation": { 69 "aggregation": {
69 "aggregation": "Aggregation", 70 "aggregation": "Aggregation",
@@ -233,6 +234,8 @@ export default angular.module('thingsboard.locale', []) @@ -233,6 +234,8 @@ export default angular.module('thingsboard.locale', [])
233 "make-private-dashboard-title": "Are you sure you want to make the dashboard '{{dashboardTitle}}' private?", 234 "make-private-dashboard-title": "Are you sure you want to make the dashboard '{{dashboardTitle}}' private?",
234 "make-private-dashboard-text": "After the confirmation the dashboard will be made private and won't be accessible by others.", 235 "make-private-dashboard-text": "After the confirmation the dashboard will be made private and won't be accessible by others.",
235 "make-private-dashboard": "Make dashboard private", 236 "make-private-dashboard": "Make dashboard private",
  237 + "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard",
  238 + "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard",
236 "select-dashboard": "Select dashboard", 239 "select-dashboard": "Select dashboard",
237 "no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.", 240 "no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.",
238 "dashboard-required": "Dashboard is required.", 241 "dashboard-required": "Dashboard is required.",
@@ -262,6 +265,9 @@ export default angular.module('thingsboard.locale', []) @@ -262,6 +265,9 @@ export default angular.module('thingsboard.locale', [])
262 "max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.", 265 "max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.",
263 "display-title": "Display dashboard title", 266 "display-title": "Display dashboard title",
264 "title-color": "Title color", 267 "title-color": "Title color",
  268 + "display-device-selection": "Display device selection",
  269 + "display-dashboard-timewindow": "Display timewindow",
  270 + "display-dashboard-export": "Display export",
265 "import": "Import dashboard", 271 "import": "Import dashboard",
266 "export": "Export dashboard", 272 "export": "Export dashboard",
267 "export-failed-error": "Unable to export dashboard: {{error}}", 273 "export-failed-error": "Unable to export dashboard: {{error}}",
@@ -60,6 +60,7 @@ module.exports = { @@ -60,6 +60,7 @@ module.exports = {
60 allChunks: true, 60 allChunks: true,
61 }), 61 }),
62 new webpack.DefinePlugin({ 62 new webpack.DefinePlugin({
  63 + THINGSBOARD_VERSION: JSON.stringify(require('./package.json').version),
63 '__DEVTOOLS__': false, 64 '__DEVTOOLS__': false,
64 'process.env': { 65 'process.env': {
65 NODE_ENV: JSON.stringify('development'), 66 NODE_ENV: JSON.stringify('development'),
@@ -58,6 +58,7 @@ module.exports = { @@ -58,6 +58,7 @@ module.exports = {
58 allChunks: true, 58 allChunks: true,
59 }), 59 }),
60 new webpack.DefinePlugin({ 60 new webpack.DefinePlugin({
  61 + THINGSBOARD_VERSION: JSON.stringify(require('./package.json').version),
61 '__DEVTOOLS__': false, 62 '__DEVTOOLS__': false,
62 'process.env': { 63 'process.env': {
63 NODE_ENV: JSON.stringify('production'), 64 NODE_ENV: JSON.stringify('production'),