thingsboard-aplcache

Add social share buttons for public dashboards sharing. Improve

5/3/2017 8:24:26 AM

Details

ui/package.json 1(+1 -0)

diff --git a/ui/package.json b/ui/package.json
index 5f00611..ddcc96e 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -33,6 +33,7 @@
     "angular-messages": "1.5.8",
     "angular-route": "1.5.8",
     "angular-sanitize": "1.5.8",
+    "angular-socialshare": "^2.3.8",
     "angular-storage": "0.0.15",
     "angular-touch": "1.5.8",
     "angular-translate": "2.13.1",
diff --git a/ui/src/app/app.js b/ui/src/app/app.js
index e3b36e3..290e9cd 100644
--- a/ui/src/app/app.js
+++ b/ui/src/app/app.js
@@ -19,6 +19,7 @@ import angular from 'angular';
 import ngMaterial from 'angular-material';
 import ngMdIcons from 'angular-material-icons';
 import ngCookies from 'angular-cookies';
+import angularSocialshare from 'angular-socialshare';
 import 'angular-translate';
 import 'angular-translate-loader-static-files';
 import 'angular-translate-storage-local';
@@ -82,6 +83,7 @@ angular.module('thingsboard', [
     ngMaterial,
     ngMdIcons,
     ngCookies,
+    angularSocialshare,
     'pascalprecht.translate',
     'mdColorPicker',
     mdPickers,
diff --git a/ui/src/app/common/utils.service.js b/ui/src/app/common/utils.service.js
index 09d0fc8..6e05bbb 100644
--- a/ui/src/app/common/utils.service.js
+++ b/ui/src/app/common/utils.service.js
@@ -106,7 +106,8 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) {
         isDescriptorSchemaNotEmpty: isDescriptorSchemaNotEmpty,
         filterSearchTextEntities: filterSearchTextEntities,
         guid: guid,
-        createDatasoucesFromSubscriptionsInfo: createDatasoucesFromSubscriptionsInfo
+        createDatasoucesFromSubscriptionsInfo: createDatasoucesFromSubscriptionsInfo,
+        isLocalUrl: isLocalUrl
     }
 
     return service;
@@ -428,4 +429,15 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) {
         return deferred.promise;
     }
 
+    function isLocalUrl(url) {
+        var parser = document.createElement('a'); //eslint-disable-line
+        parser.href = url;
+        var host = parser.hostname;
+        if (host === "localhost" || host === "127.0.0.1") {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
 }
diff --git a/ui/src/app/components/socialshare-panel.directive.js b/ui/src/app/components/socialshare-panel.directive.js
new file mode 100644
index 0000000..891d913
--- /dev/null
+++ b/ui/src/app/components/socialshare-panel.directive.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* eslint-disable import/no-unresolved, import/default */
+
+import socialsharePanelTemplate from './socialshare-panel.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+
+export default angular.module('thingsboard.directives.socialsharePanel', [])
+    .directive('tbSocialSharePanel', SocialsharePanel)
+    .name;
+
+/*@ngInject*/
+function SocialsharePanel() {
+    return {
+        restrict: "E",
+        scope: true,
+        bindToController: {
+            shareTitle: '@',
+            shareText: '@',
+            shareLink: '@',
+            shareHashTags: '@'
+        },
+        controller: SocialsharePanelController,
+        controllerAs: 'vm',
+        templateUrl: socialsharePanelTemplate
+    };
+}
+
+/*@ngInject*/
+function SocialsharePanelController(utils) {
+
+    let vm = this;
+
+    vm.isShareLinkLocal = function() {
+        if (vm.shareLink && vm.shareLink.length > 0) {
+            return utils.isLocalUrl(vm.shareLink);
+        } else {
+            return true;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/ui/src/app/components/socialshare-panel.tpl.html b/ui/src/app/components/socialshare-panel.tpl.html
new file mode 100644
index 0000000..7b9560d
--- /dev/null
+++ b/ui/src/app/components/socialshare-panel.tpl.html
@@ -0,0 +1,62 @@
+<!--
+
+    Copyright © 2016-2017 The Thingsboard Authors
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+
+<div layout="row" ng-show="!vm.isShareLinkLocal()">
+    <md-button class="md-icon-button md-raised md-primary"
+               socialshare
+               socialshare-provider="facebook"
+               socialshare-title="{{ vm.shareTitle }}"
+               socialshare-text="{{ vm.shareText }}"
+               socialshare-url="{{ vm.shareLink }}">
+        <ng-md-icon icon="facebook" aria-label="Facebook"></ng-md-icon>
+        <md-tooltip md-direction="top">
+            {{ 'action.share-via' | translate:{provider:'Facebook'} }}
+        </md-tooltip>
+    </md-button>
+    <md-button class="md-icon-button md-raised md-primary"
+               socialshare
+               socialshare-provider="twitter"
+               socialshare-text="{{ vm.shareTitle }}"
+               socialshare-hashtags="{{ vm.shareHashTags }}"
+               socialshare-url="{{ vm.shareLink }}">
+        <ng-md-icon icon="twitter" aria-label="Twitter"></ng-md-icon>
+        <md-tooltip md-direction="top">
+            {{ 'action.share-via' | translate:{provider:'Twitter'} }}
+        </md-tooltip>
+    </md-button>
+    <md-button class="md-icon-button md-raised md-primary"
+               socialshare
+               socialshare-provider="linkedin"
+               socialshare-text="{{ vm.shareTitle }}"
+               socialshare-url="{{ vm.shareLink }}">
+        <ng-md-icon icon="linkedin" aria-label="Linkedin"></ng-md-icon>
+        <md-tooltip md-direction="top">
+            {{ 'action.share-via' | translate:{provider:'Linkedin'} }}
+        </md-tooltip>
+    </md-button>
+    <md-button class="md-icon-button md-raised md-primary"
+               socialshare
+               socialshare-provider="reddit"
+               socialshare-text="{{ vm.shareTitle }}"
+               socialshare-url="{{ vm.shareLink }}">
+        <md-icon md-svg-icon="mdi:reddit" aria-label="Reddit"></md-icon>
+        <md-tooltip md-direction="top">
+            {{ 'action.share-via' | translate:{provider:'Reddit'} }}
+        </md-tooltip>
+    </md-button>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/dashboard/dashboard.controller.js b/ui/src/app/dashboard/dashboard.controller.js
index d100522..9121f6a 100644
--- a/ui/src/app/dashboard/dashboard.controller.js
+++ b/ui/src/app/dashboard/dashboard.controller.js
@@ -48,6 +48,8 @@ export default function DashboardController(types, widgetService, userService,
 
     vm.isToolbarOpened = false;
 
+    vm.thingsboardVersion = THINGSBOARD_VERSION; //eslint-disable-line
+
     vm.currentDashboardId = $stateParams.dashboardId;
     if ($stateParams.customerId) {
         vm.currentCustomerId = $stateParams.customerId;
@@ -105,6 +107,9 @@ export default function DashboardController(types, widgetService, userService,
     vm.onRevertWidgetEdit = onRevertWidgetEdit;
     vm.helpLinkIdForWidgetType = helpLinkIdForWidgetType;
     vm.displayTitle = displayTitle;
+    vm.displayExport = displayExport;
+    vm.displayDashboardTimewindow = displayDashboardTimewindow;
+    vm.displayDevicesSelect = displayDevicesSelect;
 
     vm.widgetsBundle;
 
@@ -565,6 +570,33 @@ export default function DashboardController(types, widgetService, userService,
         }
     }
 
+    function displayExport() {
+        if (vm.dashboard && vm.dashboard.configuration.gridSettings &&
+            angular.isDefined(vm.dashboard.configuration.gridSettings.showDashboardExport)) {
+            return vm.dashboard.configuration.gridSettings.showDashboardExport;
+        } else {
+            return true;
+        }
+    }
+
+    function displayDashboardTimewindow() {
+        if (vm.dashboard && vm.dashboard.configuration.gridSettings &&
+            angular.isDefined(vm.dashboard.configuration.gridSettings.showDashboardTimewindow)) {
+            return vm.dashboard.configuration.gridSettings.showDashboardTimewindow;
+        } else {
+            return true;
+        }
+    }
+
+    function displayDevicesSelect() {
+        if (vm.dashboard && vm.dashboard.configuration.gridSettings &&
+            angular.isDefined(vm.dashboard.configuration.gridSettings.showDevicesSelect)) {
+            return vm.dashboard.configuration.gridSettings.showDevicesSelect;
+        } else {
+            return true;
+        }
+    }
+
     function onRevertWidgetEdit(widgetForm) {
         if (widgetForm.$dirty) {
             widgetForm.$setPristine();
diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html
index 7e314b8..9276e0f 100644
--- a/ui/src/app/dashboard/dashboard.tpl.html
+++ b/ui/src/app/dashboard/dashboard.tpl.html
@@ -49,16 +49,21 @@
                     </md-button>
                     <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true">
                     </tb-user-menu>
-                    <md-button aria-label="{{ 'action.export' | translate }}" class="md-icon-button"
+                    <md-button ng-show="vm.isEdit || vm.displayExport()"
+                               aria-label="{{ 'action.export' | translate }}" class="md-icon-button"
                                ng-click="vm.exportDashboard($event)">
                         <md-tooltip md-direction="bottom">
                             {{ 'dashboard.export' | translate }}
                         </md-tooltip>
                         <md-icon aria-label="{{ 'action.export' | translate }}" class="material-icons">file_download</md-icon>
                     </md-button>
-                    <tb-timewindow is-toolbar direction="left" tooltip-direction="bottom" aggregation ng-model="vm.dashboardConfiguration.timewindow">
+                    <tb-timewindow ng-show="vm.isEdit || vm.displayDashboardTimewindow()"
+                                   is-toolbar
+                                   direction="left"
+                                   tooltip-direction="bottom" aggregation
+                                   ng-model="vm.dashboardConfiguration.timewindow">
                     </tb-timewindow>
-                    <tb-aliases-device-select ng-show="!vm.isEdit"
+                    <tb-aliases-device-select ng-show="!vm.isEdit && vm.displayDevicesSelect()"
                                               tooltip-direction="bottom"
                                               ng-model="vm.aliasesInfo.deviceAliases"
                                               device-aliases-info="vm.aliasesInfo.deviceAliasesInfo">
@@ -304,6 +309,6 @@
         </section>
     </section>
     <section class="tb-powered-by-footer" ng-style="{'color': vm.dashboard.configuration.gridSettings.titleColor}">
-        <span>Powered by <a href="https://thingsboard.io" target="_blank">Thingsboard</a></span>
+        <span>Powered by <a href="https://thingsboard.io" target="_blank">Thingsboard v.{{ vm.thingsboardVersion }}</a></span>
     </section>
 </md-content>
diff --git a/ui/src/app/dashboard/dashboard-fieldset.tpl.html b/ui/src/app/dashboard/dashboard-fieldset.tpl.html
index 1d11fb2..954d881 100644
--- a/ui/src/app/dashboard/dashboard-fieldset.tpl.html
+++ b/ui/src/app/dashboard/dashboard-fieldset.tpl.html
@@ -36,20 +36,28 @@
 		<label translate>dashboard.assignedToCustomer</label>
 		<input ng-model="assignedCustomer.title" disabled>
 	</md-input-container>
-	<div layout="row" ng-show="!isEdit && isPublic && (dashboardScope === 'customer' || dashboardScope === 'tenant')">
-		<md-input-container class="md-block" flex>
-			<label translate>dashboard.public-link</label>
-			<input ng-model="publicLink" disabled>
-		</md-input-container>
-		<md-button class="md-icon-button" style="margin-top: 14px;"
-				   ngclipboard
-				   data-clipboard-text="{{ publicLink }}"
-				   ngclipboard-success="onPublicLinkCopied(e)">
-			<md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
-			<md-tooltip md-direction="top">
-				{{ 'dashboard.copy-public-link' | translate }}
-			</md-tooltip>
-		</md-button>
+	<div layout="column" ng-show="!isEdit && isPublic && (dashboardScope === 'customer' || dashboardScope === 'tenant')">
+		<tb-social-share-panel style="padding-bottom: 10px;"
+							   share-title="{{ 'dashboard.socialshare-title' | translate:{dashboardTitle: dashboard.title} }}"
+							   share-text="{{ 'dashboard.socialshare-text' | translate:{dashboardTitle: dashboard.title} }}"
+							   share-link="{{ publicLink }}"
+							   share-hash-tags="thingsboard, iot">
+		</tb-social-share-panel>
+		<div layout="row">
+			<md-input-container class="md-block" flex>
+				<label translate>dashboard.public-link</label>
+				<input ng-model="publicLink" disabled>
+			</md-input-container>
+			<md-button class="md-icon-button" style="margin-top: 14px;"
+					   ngclipboard
+					   data-clipboard-text="{{ publicLink }}"
+					   ngclipboard-success="onPublicLinkCopied(e)">
+				<md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
+				<md-tooltip md-direction="top">
+					{{ 'dashboard.copy-public-link' | translate }}
+				</md-tooltip>
+			</md-button>
+		</div>
 	</div>
 	<fieldset ng-disabled="loading || !isEdit">
 		<md-input-container class="md-block">
diff --git a/ui/src/app/dashboard/dashboards.controller.js b/ui/src/app/dashboard/dashboards.controller.js
index d0fa958..134baff 100644
--- a/ui/src/app/dashboard/dashboards.controller.js
+++ b/ui/src/app/dashboard/dashboards.controller.js
@@ -224,7 +224,7 @@ export function DashboardsController(userService, dashboardService, customerServ
                     onAction: function ($event, item) {
                         unassignFromCustomer($event, item, true);
                     },
-                    name: function() { return $translate.instant('action.unshare') },
+                    name: function() { return $translate.instant('action.make-private') },
                     details: function() { return $translate.instant('dashboard.make-private') },
                     icon: "reply",
                     isEnabled: function(dashboard) {
@@ -329,7 +329,7 @@ export function DashboardsController(userService, dashboardService, customerServ
                         onAction: function ($event, item) {
                             unassignFromCustomer($event, item, true);
                         },
-                        name: function() { return $translate.instant('action.unshare') },
+                        name: function() { return $translate.instant('action.make-private') },
                         details: function() { return $translate.instant('dashboard.make-private') },
                         icon: "reply",
                         isEnabled: function(dashboard) {
@@ -404,7 +404,28 @@ export function DashboardsController(userService, dashboardService, customerServ
     }
 
     function saveDashboard(dashboard) {
-        return dashboardService.saveDashboard(dashboard);
+        var deferred = $q.defer();
+        dashboardService.saveDashboard(dashboard).then(
+            function success(savedDashboard) {
+                var dashboards = [ savedDashboard ];
+                customerService.applyAssignedCustomersInfo(dashboards).then(
+                    function success(items) {
+                        if (items && items.length == 1) {
+                            deferred.resolve(items[0]);
+                        } else {
+                            deferred.reject();
+                        }
+                    },
+                    function fail() {
+                        deferred.reject();
+                    }
+                );
+            },
+            function fail() {
+                deferred.reject();
+            }
+        );
+        return deferred.promise;
     }
 
     function assignToCustomer($event, dashboardIds) {
diff --git a/ui/src/app/dashboard/dashboard-settings.controller.js b/ui/src/app/dashboard/dashboard-settings.controller.js
index aac6da3..06c64eb 100644
--- a/ui/src/app/dashboard/dashboard-settings.controller.js
+++ b/ui/src/app/dashboard/dashboard-settings.controller.js
@@ -31,6 +31,18 @@ export default function DashboardSettingsController($scope, $mdDialog, gridSetti
         vm.gridSettings.showTitle = true;
     }
 
+    if (angular.isUndefined(vm.gridSettings.showDevicesSelect)) {
+        vm.gridSettings.showDevicesSelect = true;
+    }
+
+    if (angular.isUndefined(vm.gridSettings.showDashboardTimewindow)) {
+        vm.gridSettings.showDashboardTimewindow = true;
+    }
+
+    if (angular.isUndefined(vm.gridSettings.showDashboardExport)) {
+        vm.gridSettings.showDashboardExport = true;
+    }
+
     vm.gridSettings.backgroundColor = vm.gridSettings.backgroundColor || 'rgba(0,0,0,0)';
     vm.gridSettings.titleColor = vm.gridSettings.titleColor || 'rgba(0,0,0,0.870588)';
     vm.gridSettings.columns = vm.gridSettings.columns || 24;
diff --git a/ui/src/app/dashboard/dashboard-settings.tpl.html b/ui/src/app/dashboard/dashboard-settings.tpl.html
index 2ed25d3..ec6f28b 100644
--- a/ui/src/app/dashboard/dashboard-settings.tpl.html
+++ b/ui/src/app/dashboard/dashboard-settings.tpl.html
@@ -48,6 +48,17 @@
                              md-color-history="false"
                         ></div>
                     </div>
+                    <div layout="row" layout-align="start center">
+                        <md-checkbox flex aria-label="{{ 'dashboard.display-device-selection' | translate }}"
+                                     ng-model="vm.gridSettings.showDevicesSelect">{{ 'dashboard.display-device-selection' | translate }}
+                        </md-checkbox>
+                        <md-checkbox flex aria-label="{{ 'dashboard.display-dashboard-timewindow' | translate }}"
+                                     ng-model="vm.gridSettings.showDashboardTimewindow">{{ 'dashboard.display-dashboard-timewindow' | translate }}
+                        </md-checkbox>
+                        <md-checkbox flex aria-label="{{ 'dashboard.display-dashboard-export' | translate }}"
+                                     ng-model="vm.gridSettings.showDashboardExport">{{ 'dashboard.display-dashboard-export' | translate }}
+                        </md-checkbox>
+                    </div>
                     <md-input-container class="md-block">
                         <label translate>dashboard.columns-count</label>
                         <input required type="number" step="any" name="columns" ng-model="vm.gridSettings.columns" min="10"
diff --git a/ui/src/app/dashboard/index.js b/ui/src/app/dashboard/index.js
index 4587001..88d71fb 100644
--- a/ui/src/app/dashboard/index.js
+++ b/ui/src/app/dashboard/index.js
@@ -30,6 +30,7 @@ import thingsboardDashboardSelect from '../components/dashboard-select.directive
 import thingsboardDashboard from '../components/dashboard.directive';
 import thingsboardExpandFullscreen from '../components/expand-fullscreen.directive';
 import thingsboardWidgetsBundleSelect from '../components/widgets-bundle-select.directive';
+import thingsboardSocialsharePanel from '../components/socialshare-panel.directive';
 import thingsboardTypes from '../common/types.constant';
 import thingsboardItemBuffer from '../services/item-buffer.service';
 import thingsboardImportExport from '../import-export';
@@ -64,7 +65,8 @@ export default angular.module('thingsboard.dashboard', [
     thingsboardDashboardSelect,
     thingsboardDashboard,
     thingsboardExpandFullscreen,
-    thingsboardWidgetsBundleSelect
+    thingsboardWidgetsBundleSelect,
+    thingsboardSocialsharePanel
 ])
     .config(DashboardRoutes)
     .controller('DashboardsController', DashboardsController)
diff --git a/ui/src/app/dashboard/make-dashboard-public-dialog.tpl.html b/ui/src/app/dashboard/make-dashboard-public-dialog.tpl.html
index 31f49fb..8d96b30 100644
--- a/ui/src/app/dashboard/make-dashboard-public-dialog.tpl.html
+++ b/ui/src/app/dashboard/make-dashboard-public-dialog.tpl.html
@@ -43,6 +43,12 @@
                         </md-button>
                     </div>
                     <div class="tb-notice" translate>dashboard.public-dashboard-notice</div>
+                    <tb-social-share-panel style="padding-top: 15px;"
+                            share-title="{{ 'dashboard.socialshare-title' | translate:{dashboardTitle:vm.dashboard.title} }}"
+                            share-text="{{ 'dashboard.socialshare-text' | translate:{dashboardTitle:vm.dashboard.title} }}"
+                            share-link="{{ vm.publicLink }}"
+                            share-hash-tags="thingsboard, iot">
+                    </tb-social-share-panel>
                 </md-content>
             </div>
         </md-dialog-content>
diff --git a/ui/src/app/device/device.controller.js b/ui/src/app/device/device.controller.js
index ed9ff6f..55b7083 100644
--- a/ui/src/app/device/device.controller.js
+++ b/ui/src/app/device/device.controller.js
@@ -185,7 +185,7 @@ export function DeviceController(userService, deviceService, customerService, $s
                 onAction: function ($event, item) {
                     unassignFromCustomer($event, item, true);
                 },
-                name: function() { return $translate.instant('action.unshare') },
+                name: function() { return $translate.instant('action.make-private') },
                 details: function() { return $translate.instant('device.make-private') },
                 icon: "reply",
                 isEnabled: function(device) {
@@ -271,7 +271,7 @@ export function DeviceController(userService, deviceService, customerService, $s
                         onAction: function ($event, item) {
                             unassignFromCustomer($event, item, true);
                         },
-                        name: function() { return $translate.instant('action.unshare') },
+                        name: function() { return $translate.instant('action.make-private') },
                         details: function() { return $translate.instant('device.make-private') },
                         icon: "reply",
                         isEnabled: function(device) {
@@ -364,8 +364,29 @@ export function DeviceController(userService, deviceService, customerService, $s
         return device ? device.name : '';
     }
 
-    function saveDevice (device) {
-        return deviceService.saveDevice(device);
+    function saveDevice(device) {
+        var deferred = $q.defer();
+        deviceService.saveDevice(device).then(
+            function success(savedDevice) {
+                var devices = [ savedDevice ];
+                customerService.applyAssignedCustomersInfo(devices).then(
+                    function success(items) {
+                        if (items && items.length == 1) {
+                            deferred.resolve(items[0]);
+                        } else {
+                            deferred.reject();
+                        }
+                    },
+                    function fail() {
+                        deferred.reject();
+                    }
+                );
+            },
+            function fail() {
+                deferred.reject();
+            }
+        );
+        return deferred.promise;
     }
 
     function isCustomerUser() {
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index 37a2b93..32b422b 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -44,7 +44,7 @@ export default angular.module('thingsboard.locale', [])
                     "assign": "Assign",
                     "unassign": "Unassign",
                     "share": "Share",
-                    "unshare": "Unshare",
+                    "make-private": "Make private",
                     "apply": "Apply",
                     "apply-changes": "Apply changes",
                     "edit-mode": "Edit mode",
@@ -63,7 +63,8 @@ export default angular.module('thingsboard.locale', [])
                     "copy": "Copy",
                     "paste": "Paste",
                     "import": "Import",
-                    "export": "Export"
+                    "export": "Export",
+                    "share-via": "Share via {{provider}}"
                 },
                 "aggregation": {
                     "aggregation": "Aggregation",
@@ -233,6 +234,8 @@ export default angular.module('thingsboard.locale', [])
                     "make-private-dashboard-title": "Are you sure you want to make the dashboard '{{dashboardTitle}}' private?",
                     "make-private-dashboard-text": "After the confirmation the dashboard will be made private and won't be accessible by others.",
                     "make-private-dashboard": "Make dashboard private",
+                    "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard",
+                    "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard",
                     "select-dashboard": "Select dashboard",
                     "no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.",
                     "dashboard-required": "Dashboard is required.",
@@ -262,6 +265,9 @@ export default angular.module('thingsboard.locale', [])
                     "max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.",
                     "display-title": "Display dashboard title",
                     "title-color": "Title color",
+                    "display-device-selection": "Display device selection",
+                    "display-dashboard-timewindow": "Display timewindow",
+                    "display-dashboard-export": "Display export",
                     "import": "Import dashboard",
                     "export": "Export dashboard",
                     "export-failed-error": "Unable to export dashboard: {{error}}",
diff --git a/ui/webpack.config.dev.js b/ui/webpack.config.dev.js
index c669ec5..fa019d3 100644
--- a/ui/webpack.config.dev.js
+++ b/ui/webpack.config.dev.js
@@ -60,6 +60,7 @@ module.exports = {
             allChunks: true,
         }),
         new webpack.DefinePlugin({
+            THINGSBOARD_VERSION: JSON.stringify(require('./package.json').version),
             '__DEVTOOLS__': false,
             'process.env': {
                 NODE_ENV: JSON.stringify('development'),
diff --git a/ui/webpack.config.prod.js b/ui/webpack.config.prod.js
index 09374fb..a746488 100644
--- a/ui/webpack.config.prod.js
+++ b/ui/webpack.config.prod.js
@@ -58,6 +58,7 @@ module.exports = {
             allChunks: true,
         }),
         new webpack.DefinePlugin({
+            THINGSBOARD_VERSION: JSON.stringify(require('./package.json').version),
             '__DEVTOOLS__': false,
             'process.env': {
                 NODE_ENV: JSON.stringify('production'),