Commit bfd654d84fe4a270a76e815eb8eb428cde02e62e
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.
Showing
17 changed files
with
290 additions
and
29 deletions
@@ -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'), |