thingsboard-aplcache
Changes
ui/src/app/api/entity.service.js 29(+28 -1)
ui/src/app/dashboard/dashboard.controller.js 17(+15 -2)
ui/src/app/dashboard/dashboard.scss 80(+8 -72)
ui/src/app/dashboard/dashboard.tpl.html 190(+89 -101)
ui/src/app/dashboard/dashboard-toolbar.scss 114(+114 -0)
ui/src/app/dashboard/index.js 2(+2 -0)
ui/src/app/locale/locale.constant.js 1(+1 -0)
ui/src/scss/constants.scss 2(+2 -0)
Details
ui/src/app/api/entity.service.js 29(+28 -1)
diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js
index 43c537c..a70308b 100644
--- a/ui/src/app/api/entity.service.js
+++ b/ui/src/app/api/entity.service.js
@@ -36,7 +36,8 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
saveRelatedEntity: saveRelatedEntity,
getRelatedEntity: getRelatedEntity,
deleteRelatedEntity: deleteRelatedEntity,
- moveEntity: moveEntity
+ moveEntity: moveEntity,
+ copyEntity: copyEntity
};
return service;
@@ -626,6 +627,32 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
return deferred.promise;
}
+ function copyEntity(entity, targetParentId, keys) {
+ var deferred = $q.defer();
+ if (!entity.id && !entity.id.id) {
+ deferred.reject();
+ } else {
+ getRelatedEntity(entity.id, keys).then(
+ function success(relatedEntity) {
+ delete relatedEntity.id.id;
+ relatedEntity.name = entity.name;
+ saveRelatedEntity(relatedEntity, targetParentId, keys).then(
+ function success(savedEntity) {
+ deferred.resolve(savedEntity);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ }
+ return deferred.promise;
+ }
+
function saveEntityPromise(entity) {
var entityType = entity.id.entityType;
if (!entity.id.id) {
diff --git a/ui/src/app/common/dashboard-utils.service.js b/ui/src/app/common/dashboard-utils.service.js
index 57317b5..78136df 100644
--- a/ui/src/app/common/dashboard-utils.service.js
+++ b/ui/src/app/common/dashboard-utils.service.js
@@ -179,6 +179,7 @@ function DashboardUtils(types, utils, timeService) {
dashboard.configuration.settings.showEntitiesSelect = true;
dashboard.configuration.settings.showDashboardTimewindow = true;
dashboard.configuration.settings.showDashboardExport = true;
+ dashboard.configuration.settings.toolbarAlwaysOpen = false;
} else {
if (angular.isUndefined(dashboard.configuration.settings.stateControllerId)) {
dashboard.configuration.settings.stateControllerId = 'default';
diff --git a/ui/src/app/components/expand-fullscreen.directive.js b/ui/src/app/components/expand-fullscreen.directive.js
index 37491e7..b70fd94 100644
--- a/ui/src/app/components/expand-fullscreen.directive.js
+++ b/ui/src/app/components/expand-fullscreen.directive.js
@@ -24,7 +24,7 @@ export default angular.module('thingsboard.directives.expandFullscreen', [])
/* eslint-disable angular/angularelement */
/*@ngInject*/
-function ExpandFullscreen($compile, $document) {
+function ExpandFullscreen($compile, $document, $timeout) {
var uniqueId = 1;
var linker = function (scope, element, attrs) {
@@ -97,10 +97,6 @@ function ExpandFullscreen($compile, $document) {
scope.expanded = !scope.expanded;
}
- var expandButton = null;
- if (attrs.expandButtonId) {
- expandButton = $('#' + attrs.expandButtonId, element)[0];
- }
var buttonSize;
if (attrs.expandButtonSize) {
buttonSize = attrs.expandButtonSize;
@@ -115,27 +111,38 @@ function ExpandFullscreen($compile, $document) {
'options=\'{"easing": "circ-in-out", "duration": 375, "rotation": "none"}\'>' +
'</ng-md-icon>';
- if (expandButton) {
- expandButton = angular.element(expandButton);
- if (scope.hideExpandButton()) {
- expandButton.remove();
- } else {
- expandButton.attr('md-ink-ripple', 'false');
- expandButton.append(html);
+ if (attrs.expandButtonId) {
+ $timeout(function() {
+ var expandButton = $('#' + attrs.expandButtonId, element)[0];
+ renderExpandButton(expandButton);
+ });
+ } else {
+ renderExpandButton();
+ }
+
+ function renderExpandButton(expandButton) {
+ if (expandButton) {
+ expandButton = angular.element(expandButton);
+ if (scope.hideExpandButton()) {
+ expandButton.remove();
+ } else {
+ expandButton.attr('md-ink-ripple', 'false');
+ expandButton.append(html);
- $compile(expandButton.contents())(scope);
+ $compile(expandButton.contents())(scope);
- expandButton.on("click", scope.toggleExpand);
- }
- } else if (!scope.hideExpandButton()) {
- var button = angular.element('<md-button class="tb-fullscreen-button-style tb-fullscreen-button-pos md-icon-button" ' +
- 'md-ink-ripple="false" ng-click="toggleExpand($event)">' +
- html +
- '</md-button>');
+ expandButton.on("click", scope.toggleExpand);
+ }
+ } else if (!scope.hideExpandButton()) {
+ var button = angular.element('<md-button class="tb-fullscreen-button-style tb-fullscreen-button-pos md-icon-button" ' +
+ 'md-ink-ripple="false" ng-click="toggleExpand($event)">' +
+ html +
+ '</md-button>');
- $compile(button)(scope);
+ $compile(button)(scope);
- element.prepend(button);
+ element.prepend(button);
+ }
}
}
ui/src/app/dashboard/dashboard.controller.js 17(+15 -2)
diff --git a/ui/src/app/dashboard/dashboard.controller.js b/ui/src/app/dashboard/dashboard.controller.js
index c446be4..ecf072d 100644
--- a/ui/src/app/dashboard/dashboard.controller.js
+++ b/ui/src/app/dashboard/dashboard.controller.js
@@ -63,7 +63,9 @@ export default function DashboardController(types, dashboardUtils, widgetService
}
Object.defineProperty(vm, 'toolbarOpened', {
- get: function() { return !vm.widgetEditMode && ($scope.forceFullscreen || vm.isToolbarOpened || vm.isEdit || vm.showRightLayoutSwitch()); },
+ get: function() {
+ return !vm.widgetEditMode &&
+ (toolbarAlwaysOpen() || $scope.forceFullscreen || vm.isToolbarOpened || vm.isEdit || vm.showRightLayoutSwitch()); },
set: function() { }
});
@@ -103,9 +105,11 @@ export default function DashboardController(types, dashboardUtils, widgetService
}
vm.showCloseToolbar = function() {
- return !$scope.forceFullscreen && !vm.isEdit && !vm.showRightLayoutSwitch();
+ return !vm.toolbarAlwaysOpen() && !$scope.forceFullscreen && !vm.isEdit && !vm.showRightLayoutSwitch();
}
+ vm.toolbarAlwaysOpen = toolbarAlwaysOpen;
+
vm.showRightLayoutSwitch = function() {
return vm.isMobile && vm.layouts.right.show;
}
@@ -738,6 +742,15 @@ export default function DashboardController(types, dashboardUtils, widgetService
return link;
}
+ function toolbarAlwaysOpen() {
+ if (vm.dashboard && vm.dashboard.configuration.settings &&
+ angular.isDefined(vm.dashboard.configuration.settings.toolbarAlwaysOpen)) {
+ return vm.dashboard.configuration.settings.toolbarAlwaysOpen;
+ } else {
+ return false;
+ }
+ }
+
function displayTitle() {
if (vm.dashboard && vm.dashboard.configuration.settings &&
angular.isDefined(vm.dashboard.configuration.settings.showTitle)) {
ui/src/app/dashboard/dashboard.scss 80(+8 -72)
diff --git a/ui/src/app/dashboard/dashboard.scss b/ui/src/app/dashboard/dashboard.scss
index bc5ec56..ca2bbab 100644
--- a/ui/src/app/dashboard/dashboard.scss
+++ b/ui/src/app/dashboard/dashboard.scss
@@ -68,87 +68,23 @@ section.tb-dashboard-toolbar {
pointer-events: none;
&.tb-dashboard-toolbar-opened {
right: 0px;
- @include transition(right .3s cubic-bezier(.55,0,.55,.2));
+ // @include transition(right .3s cubic-bezier(.55,0,.55,.2));
}
&.tb-dashboard-toolbar-closed {
right: 18px;
@include transition(right .3s cubic-bezier(.55,0,.55,.2) .2s);
}
- md-fab-toolbar {
- &.md-is-open {
- md-fab-trigger {
- .md-button {
- &.md-fab {
- opacity: 1;
- @include transition(opacity .3s cubic-bezier(.55,0,.55,.2));
- }
- }
- }
- }
- md-fab-trigger {
- .md-button {
- &.md-fab {
- line-height: 36px;
- width: 36px;
- height: 36px;
- margin: 4px 0 0 4px;
- opacity: 0.5;
- @include transition(opacity .3s cubic-bezier(.55,0,.55,.2) .2s);
- md-icon {
- position: absolute;
- top: 25%;
- margin: 0;
- line-height: 18px;
- height: 18px;
- width: 18px;
- min-height: 18px;
- min-width: 18px;
- }
- }
- }
- }
- .md-fab-toolbar-wrapper {
- height: 50px;
- md-toolbar {
- min-height: 46px;
- height: 46px;
- md-fab-actions {
- font-size: 16px;
- margin-top: 0px;
- .close-action {
- margin-right: -18px;
- }
- .md-fab-action-item {
- width: 100%;
- height: 46px;
- .tb-dashboard-action-panels {
- height: 46px;
- flex-direction: row-reverse;
- .tb-dashboard-action-panel {
- height: 46px;
- flex-direction: row-reverse;
- div {
- height: 46px;
- }
- md-select {
- pointer-events: all;
- }
- tb-states-component {
- pointer-events: all;
- }
- }
- }
- }
- }
- }
- }
- }
}
.tb-dashboard-container {
&.tb-dashboard-toolbar-opened {
- margin-top: 50px;
- @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2));
+ &.is-fullscreen {
+ margin-top: 64px;
+ }
+ &:not(.is-fullscreen) {
+ margin-top: 50px;
+ @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2));
+ }
}
&.tb-dashboard-toolbar-closed {
margin-top: 0px;
ui/src/app/dashboard/dashboard.tpl.html 190(+89 -101)
diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html
index 94e016e..8338612 100644
--- a/ui/src/app/dashboard/dashboard.tpl.html
+++ b/ui/src/app/dashboard/dashboard.tpl.html
@@ -19,110 +19,98 @@
hide-expand-button="vm.widgetEditMode || vm.iframeMode || forceFullscreen" expand-tooltip-direction="bottom">
<section class="tb-dashboard-toolbar" ng-show="vm.showDashboardToolbar()"
ng-class="{ 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">
- <md-fab-toolbar ng-show="!vm.widgetEditMode" md-open="vm.toolbarOpened"
- md-direction="left">
- <md-fab-trigger class="align-with-text">
- <md-button aria-label="menu" class="md-fab md-primary" ng-click="vm.openToolbar()">
- <md-tooltip ng-show="!vm.toolbarOpened" md-direction="bottom">
- {{ 'dashboard.open-toolbar' | translate }}
- </md-tooltip>
- <md-icon aria-label="dashboard-toolbar" class="material-icons">more_horiz</md-icon>
- </md-button>
- </md-fab-trigger>
- <md-toolbar>
- <md-fab-actions class="md-toolbar-tools">
- <div class="tb-dashboard-action-panels" flex layout="row" layout-align="start center">
- <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="start center">
- <md-button ng-show="vm.showCloseToolbar()" aria-label="close-toolbar" class="md-icon-button close-action" ng-click="vm.closeToolbar()">
- <md-tooltip md-direction="bottom">
- {{ 'dashboard.close-toolbar' | translate }}
- </md-tooltip>
- <md-icon aria-label="close-toolbar" class="material-icons">arrow_forward</md-icon>
- </md-button>
- <md-button ng-show="vm.showRightLayoutSwitch()" aria-label="switch-layouts" class="md-icon-button" ng-click="vm.toggleLayouts()">
- <ng-md-icon icon="{{vm.isRightLayoutOpened ? 'arrow_back' : 'menu'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon>
- <md-tooltip md-direction="bottom">
- {{ (vm.isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }}
- </md-tooltip>
- </md-button>
- <md-button id="dashboard-expand-button"
- aria-label="{{ 'fullscreen.fullscreen' | translate }}"
- class="md-icon-button">
- </md-button>
- <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true">
- </tb-user-menu>
- <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 ng-show="vm.isEdit || vm.displayDashboardTimewindow()"
- is-toolbar
- direction="left"
- tooltip-direction="bottom" aggregation
- ng-model="vm.dashboardCtx.dashboardTimewindow">
- </tb-timewindow>
- <tb-aliases-entity-select ng-show="!vm.isEdit && vm.displayEntitiesSelect()"
- tooltip-direction="bottom"
- ng-model="vm.dashboardCtx.aliasesInfo.entityAliases"
- entity-aliases-info="vm.dashboardCtx.aliasesInfo.entityAliasesInfo">
- </tb-aliases-entity-select>
- <md-button ng-show="vm.isEdit" aria-label="{{ 'entity.aliases' | translate }}" class="md-icon-button"
- ng-click="vm.openEntityAliases($event)">
- <md-tooltip md-direction="bottom">
- {{ 'entity.aliases' | translate }}
- </md-tooltip>
- <md-icon aria-label="{{ 'entity.aliases' | translate }}" class="material-icons">devices_other</md-icon>
- </md-button>
- <md-button ng-show="vm.isEdit" aria-label="{{ 'dashboard.settings' | translate }}" class="md-icon-button"
- ng-click="vm.openDashboardSettings($event)">
- <md-tooltip md-direction="bottom">
- {{ 'dashboard.settings' | translate }}
- </md-tooltip>
- <md-icon aria-label="{{ 'dashboard.settings' | translate }}" class="material-icons">settings</md-icon>
- </md-button>
- <tb-dashboard-select ng-show="!vm.isEdit && !vm.widgetEditMode && vm.displayDashboardsSelect()"
- ng-model="vm.currentDashboardId"
- dashboards-scope="{{vm.currentDashboardScope}}"
- customer-id="vm.currentCustomerId">
- </tb-dashboard-select>
- </div>
- <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="end center">
- <div layout="row" layout-align="start center" ng-show="vm.isEdit">
- <md-button aria-label="{{ 'dashboard.manage-states' | translate }}" class="md-icon-button"
- ng-click="vm.manageDashboardStates($event)">
- <md-tooltip md-direction="bottom">
- {{ 'dashboard.manage-states' | translate }}
- </md-tooltip>
- <md-icon aria-label="{{ 'dashboard.manage-states' | translate }}" class="material-icons">layers</md-icon>
- </md-button>
- <md-button aria-label="{{ 'layout.manage' | translate }}" class="md-icon-button"
- ng-click="vm.manageDashboardLayouts($event)">
- <md-tooltip md-direction="bottom">
- {{ 'layout.manage' | translate }}
- </md-tooltip>
- <md-icon aria-label="{{ 'layout.manage' | translate }}" class="material-icons">view_compact</md-icon>
- </md-button>
- </div>
- <div layout="row" layout-align="start center">
- <tb-states-component ng-if="vm.isEdit" states-controller-id="'default'"
- dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
- </tb-states-component>
- <tb-states-component ng-if="!vm.isEdit" states-controller-id="vm.dashboardConfiguration.settings.stateControllerId"
- dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
- </tb-states-component>
- </div>
- </div>
+ <tb-dashboard-toolbar ng-show="!vm.widgetEditMode" force-fullscreen="forceFullscreen"
+ toolbar-opened="vm.toolbarOpened" on-trigger-click="vm.openToolbar()">
+ <div class="tb-dashboard-action-panels" flex layout="row" layout-align="start center">
+ <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="start center">
+ <md-button ng-show="vm.showCloseToolbar()" aria-label="close-toolbar" class="md-icon-button close-action" ng-click="vm.closeToolbar()">
+ <md-tooltip md-direction="bottom">
+ {{ 'dashboard.close-toolbar' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="close-toolbar" class="material-icons">arrow_forward</md-icon>
+ </md-button>
+ <md-button ng-show="vm.showRightLayoutSwitch()" aria-label="switch-layouts" class="md-icon-button" ng-click="vm.toggleLayouts()">
+ <ng-md-icon icon="{{vm.isRightLayoutOpened ? 'arrow_back' : 'menu'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon>
+ <md-tooltip md-direction="bottom">
+ {{ (vm.isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }}
+ </md-tooltip>
+ </md-button>
+ <md-button id="dashboard-expand-button"
+ aria-label="{{ 'fullscreen.fullscreen' | translate }}"
+ class="md-icon-button">
+ </md-button>
+ <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true">
+ </tb-user-menu>
+ <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 ng-show="vm.isEdit || vm.displayDashboardTimewindow()"
+ is-toolbar
+ direction="left"
+ tooltip-direction="bottom" aggregation
+ ng-model="vm.dashboardCtx.dashboardTimewindow">
+ </tb-timewindow>
+ <tb-aliases-entity-select ng-show="!vm.isEdit && vm.displayEntitiesSelect()"
+ tooltip-direction="bottom"
+ ng-model="vm.dashboardCtx.aliasesInfo.entityAliases"
+ entity-aliases-info="vm.dashboardCtx.aliasesInfo.entityAliasesInfo">
+ </tb-aliases-entity-select>
+ <md-button ng-show="vm.isEdit" aria-label="{{ 'entity.aliases' | translate }}" class="md-icon-button"
+ ng-click="vm.openEntityAliases($event)">
+ <md-tooltip md-direction="bottom">
+ {{ 'entity.aliases' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="{{ 'entity.aliases' | translate }}" class="material-icons">devices_other</md-icon>
+ </md-button>
+ <md-button ng-show="vm.isEdit" aria-label="{{ 'dashboard.settings' | translate }}" class="md-icon-button"
+ ng-click="vm.openDashboardSettings($event)">
+ <md-tooltip md-direction="bottom">
+ {{ 'dashboard.settings' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="{{ 'dashboard.settings' | translate }}" class="material-icons">settings</md-icon>
+ </md-button>
+ <tb-dashboard-select ng-show="!vm.isEdit && !vm.widgetEditMode && vm.displayDashboardsSelect()"
+ ng-model="vm.currentDashboardId"
+ dashboards-scope="{{vm.currentDashboardScope}}"
+ customer-id="vm.currentCustomerId">
+ </tb-dashboard-select>
+ </div>
+ <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="end center">
+ <div layout="row" layout-align="start center" ng-show="vm.isEdit">
+ <md-button aria-label="{{ 'dashboard.manage-states' | translate }}" class="md-icon-button"
+ ng-click="vm.manageDashboardStates($event)">
+ <md-tooltip md-direction="bottom">
+ {{ 'dashboard.manage-states' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="{{ 'dashboard.manage-states' | translate }}" class="material-icons">layers</md-icon>
+ </md-button>
+ <md-button aria-label="{{ 'layout.manage' | translate }}" class="md-icon-button"
+ ng-click="vm.manageDashboardLayouts($event)">
+ <md-tooltip md-direction="bottom">
+ {{ 'layout.manage' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="{{ 'layout.manage' | translate }}" class="material-icons">view_compact</md-icon>
+ </md-button>
</div>
- </md-fab-actions>
- </md-toolbar>
- </md-fab-toolbar>
+ <div layout="row" layout-align="start center">
+ <tb-states-component ng-if="vm.isEdit" states-controller-id="'default'"
+ dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
+ </tb-states-component>
+ <tb-states-component ng-if="!vm.isEdit" states-controller-id="vm.dashboardConfiguration.settings.stateControllerId"
+ dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
+ </tb-states-component>
+ </div>
+ </div>
+ </div>
+ </tb-dashboard-toolbar>
</section>
<section class="tb-dashboard-container tb-absolute-fill"
- ng-class="{ 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">
+ ng-class="{ 'is-fullscreen': forceFullscreen, 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">
<section ng-show="!loading && vm.dashboardConfigurationError()" layout-align="center center"
ng-style="{'color': vm.dashboard.configuration.settings.titleColor}"
ng-class="{'tb-padded' : !vm.widgetEditMode}"
diff --git a/ui/src/app/dashboard/dashboard-settings.controller.js b/ui/src/app/dashboard/dashboard-settings.controller.js
index dbe4cbe..ac98709 100644
--- a/ui/src/app/dashboard/dashboard-settings.controller.js
+++ b/ui/src/app/dashboard/dashboard-settings.controller.js
@@ -57,6 +57,10 @@ export default function DashboardSettingsController($scope, $mdDialog, statesCon
if (angular.isUndefined(vm.settings.showDashboardExport)) {
vm.settings.showDashboardExport = true;
}
+
+ if (angular.isUndefined(vm.settings.toolbarAlwaysOpen)) {
+ vm.settings.toolbarAlwaysOpen = false;
+ }
}
if (vm.gridSettings) {
diff --git a/ui/src/app/dashboard/dashboard-settings.tpl.html b/ui/src/app/dashboard/dashboard-settings.tpl.html
index 88fc66d..f3ff704 100644
--- a/ui/src/app/dashboard/dashboard-settings.tpl.html
+++ b/ui/src/app/dashboard/dashboard-settings.tpl.html
@@ -41,6 +41,9 @@
</md-select>
</md-input-container>
<div layout="row" layout-align="start center">
+ <md-checkbox flex aria-label="{{ 'dashboard.toolbar-always-open' | translate }}"
+ ng-model="vm.settings.toolbarAlwaysOpen">{{ 'dashboard.toolbar-always-open' | translate }}
+ </md-checkbox>
<md-checkbox flex aria-label="{{ 'dashboard.display-title' | translate }}"
ng-model="vm.settings.showTitle">{{ 'dashboard.display-title' | translate }}
</md-checkbox>
diff --git a/ui/src/app/dashboard/dashboard-toolbar.directive.js b/ui/src/app/dashboard/dashboard-toolbar.directive.js
new file mode 100644
index 0000000..63a34f8
--- /dev/null
+++ b/ui/src/app/dashboard/dashboard-toolbar.directive.js
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+import './dashboard-toolbar.scss';
+
+import 'javascript-detect-element-resize/detect-element-resize';
+
+/* eslint-disable import/no-unresolved, import/default */
+
+import dashboardToolbarTemplate from './dashboard-toolbar.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+/*@ngInject*/
+export default function DashboardToolbar() {
+ return {
+ restrict: "E",
+ scope: true,
+ transclude: true,
+ bindToController: {
+ toolbarOpened: '=',
+ forceFullscreen: '=',
+ onTriggerClick: '&'
+ },
+ controller: DashboardToolbarController,
+ controllerAs: 'vm',
+ templateUrl: dashboardToolbarTemplate
+ };
+}
+
+/* eslint-disable angular/angularelement */
+
+
+/*@ngInject*/
+function DashboardToolbarController($scope, $element, $timeout, mdFabToolbarAnimation) {
+
+ let vm = this;
+
+ vm.mdFabToolbarElement = angular.element($element[0].querySelector('md-fab-toolbar'));
+
+ $timeout(function() {
+ vm.mdFabBackgroundElement = angular.element(vm.mdFabToolbarElement[0].querySelector('.md-fab-toolbar-background'));
+ vm.mdFabTriggerElement = angular.element(vm.mdFabToolbarElement[0].querySelector('md-fab-trigger button'));
+ });
+
+ addResizeListener(vm.mdFabToolbarElement[0], triggerFabResize); // eslint-disable-line no-undef
+
+ $scope.$on("$destroy", function () {
+ removeResizeListener(vm.mdFabToolbarElement[0], triggerFabResize); // eslint-disable-line no-undef
+ });
+
+ function triggerFabResize() {
+ var ctrl = vm.mdFabToolbarElement.controller('mdFabToolbar');
+ if (ctrl.isOpen) {
+ if (!vm.mdFabBackgroundElement[0].offsetWidth) {
+ mdFabToolbarAnimation.addClass(vm.mdFabToolbarElement, 'md-is-open', function () {
+ });
+ } else {
+ var color = window.getComputedStyle(vm.mdFabTriggerElement[0]).getPropertyValue('background-color'); //eslint-disable-line
+
+ var width = vm.mdFabToolbarElement[0].offsetWidth;
+ var scale = 2 * (width / vm.mdFabTriggerElement[0].offsetWidth);
+ vm.mdFabBackgroundElement[0].style.backgroundColor = color;
+ vm.mdFabBackgroundElement[0].style.borderRadius = width + 'px';
+
+ var transform = vm.mdFabBackgroundElement[0].style.transform;
+ var targetTransform = 'scale(' + scale + ')';
+ if (!transform || !angular.equals(transform, targetTransform)) {
+ vm.mdFabBackgroundElement[0].style.transform = targetTransform;
+ }
+ }
+ }
+ }
+}
+
ui/src/app/dashboard/dashboard-toolbar.scss 114(+114 -0)
diff --git a/ui/src/app/dashboard/dashboard-toolbar.scss b/ui/src/app/dashboard/dashboard-toolbar.scss
new file mode 100644
index 0000000..af4889e
--- /dev/null
+++ b/ui/src/app/dashboard/dashboard-toolbar.scss
@@ -0,0 +1,114 @@
+/**
+ * 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.
+ */
+
+@import "~compass-sass-mixins/lib/compass";
+@import '../../scss/constants';
+
+tb-dashboard-toolbar {
+ md-fab-toolbar {
+ &.md-is-open {
+ md-fab-trigger {
+ .md-button {
+ &.md-fab {
+ opacity: 1;
+ @include transition(opacity .3s cubic-bezier(.55,0,.55,.2));
+ .md-fab-toolbar-background {
+ background-color: $primary-default !important;
+ }
+ }
+ }
+ }
+ }
+ md-fab-trigger {
+ .md-button {
+ &.md-fab {
+ line-height: 36px;
+ width: 36px;
+ height: 36px;
+ margin: 4px 0 0 4px;
+ opacity: 0.5;
+ @include transition(opacity .3s cubic-bezier(.55,0,.55,.2) .2s);
+ md-icon {
+ position: absolute;
+ top: 25%;
+ margin: 0;
+ line-height: 18px;
+ height: 18px;
+ width: 18px;
+ min-height: 18px;
+ min-width: 18px;
+ }
+ }
+ }
+ }
+ &.is-fullscreen {
+ &.md-is-open {
+ md-fab-trigger {
+ .md-button {
+ &.md-fab {
+ .md-fab-toolbar-background {
+ transition-delay: 0ms !important;
+ transition-duration: 0ms !important;
+ }
+ }
+ }
+ }
+ }
+ .md-fab-toolbar-wrapper {
+ height: 64px;
+ md-toolbar {
+ min-height: 64px;
+ height: 64px;
+ }
+ }
+ }
+ .md-fab-toolbar-wrapper {
+ height: 50px;
+ md-toolbar {
+ min-height: 50px;
+ height: 50px;
+ md-fab-actions {
+ font-size: 16px;
+ margin-top: 0px;
+ .close-action {
+ margin-right: -18px;
+ }
+ .md-fab-action-item {
+ width: 100%;
+ height: 46px;
+ .tb-dashboard-action-panels {
+ height: 46px;
+ flex-direction: row-reverse;
+ .tb-dashboard-action-panel {
+ height: 46px;
+ flex-direction: row-reverse;
+ div {
+ height: 46px;
+ }
+ md-select {
+ pointer-events: all;
+ }
+ tb-states-component {
+ pointer-events: all;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/src/app/dashboard/dashboard-toolbar.tpl.html b/ui/src/app/dashboard/dashboard-toolbar.tpl.html
new file mode 100644
index 0000000..46192ff
--- /dev/null
+++ b/ui/src/app/dashboard/dashboard-toolbar.tpl.html
@@ -0,0 +1,35 @@
+<!--
+
+ 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.
+
+-->
+
+<md-fab-toolbar md-open="vm.toolbarOpened"
+ md-direction="left"
+ ng-class="{'is-fullscreen': vm.forceFullscreen, 'md-whiteframe-z1': vm.forceFullscreen}">
+ <md-fab-trigger class="align-with-text">
+ <md-button aria-label="menu" class="md-fab md-primary" ng-click="vm.onTriggerClick()">
+ <md-tooltip ng-show="!vm.toolbarOpened" md-direction="bottom">
+ {{ 'dashboard.open-toolbar' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="dashboard-toolbar" class="material-icons">more_horiz</md-icon>
+ </md-button>
+ </md-fab-trigger>
+ <md-toolbar>
+ <md-fab-actions class="md-toolbar-tools">
+ <div ng-transclude></div>
+ </md-fab-actions>
+ </md-toolbar>
+</md-fab-toolbar>
ui/src/app/dashboard/index.js 2(+2 -0)
diff --git a/ui/src/app/dashboard/index.js b/ui/src/app/dashboard/index.js
index 73a97a1..d940f09 100644
--- a/ui/src/app/dashboard/index.js
+++ b/ui/src/app/dashboard/index.js
@@ -45,6 +45,7 @@ import AddDashboardsToCustomerController from './add-dashboards-to-customer.cont
import AddWidgetController from './add-widget.controller';
import DashboardDirective from './dashboard.directive';
import EditWidgetDirective from './edit-widget.directive';
+import DashboardToolbar from './dashboard-toolbar.directive';
export default angular.module('thingsboard.dashboard', [
uiRouter,
@@ -78,4 +79,5 @@ export default angular.module('thingsboard.dashboard', [
.controller('AddWidgetController', AddWidgetController)
.directive('tbDashboardDetails', DashboardDirective)
.directive('tbEditWidget', EditWidgetDirective)
+ .directive('tbDashboardToolbar', DashboardToolbar)
.name;
ui/src/app/locale/locale.constant.js 1(+1 -0)
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index 6e6308d..622754c 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -328,6 +328,7 @@ export default angular.module('thingsboard.locale', [])
"min-vertical-margin-message": "Only 0 is allowed as minimum vertical margin value.",
"max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.",
"display-title": "Display dashboard title",
+ "toolbar-always-open": "Keep toolbar opened",
"title-color": "Title color",
"display-dashboards-selection": "Display dashboards selection",
"display-entities-selection": "Display entities selection",
ui/src/scss/constants.scss 2(+2 -0)
diff --git a/ui/src/scss/constants.scss b/ui/src/scss/constants.scss
index 73697fc..c56d40b 100644
--- a/ui/src/scss/constants.scss
+++ b/ui/src/scss/constants.scss
@@ -20,10 +20,12 @@
$gray: #eee;
$primary-palette-color: 'indigo';
+$default: '500';
$hue-1: '300';
$hue-2: '800';
$hue-3: 'a100';
+$primary-default: #305680; //material-color($primary-palette-color, $default);
$primary-hue-1: material-color($primary-palette-color, $hue-1);
$primary-hue-2: material-color($primary-palette-color, $hue-2);
$primary-hue-3: rgb(207, 216, 220);