Commit ffc7a57e59b5b6d670cd65b72a15889abd884948

Authored by Igor Kulikov
1 parent 34c6c30e

UI: Improve dashboard toolbar. Implement entity copy function.

... ... @@ -36,7 +36,8 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
36 36 saveRelatedEntity: saveRelatedEntity,
37 37 getRelatedEntity: getRelatedEntity,
38 38 deleteRelatedEntity: deleteRelatedEntity,
39   - moveEntity: moveEntity
  39 + moveEntity: moveEntity,
  40 + copyEntity: copyEntity
40 41 };
41 42
42 43 return service;
... ... @@ -626,6 +627,32 @@ function EntityService($http, $q, $filter, $translate, userService, deviceServic
626 627 return deferred.promise;
627 628 }
628 629
  630 + function copyEntity(entity, targetParentId, keys) {
  631 + var deferred = $q.defer();
  632 + if (!entity.id && !entity.id.id) {
  633 + deferred.reject();
  634 + } else {
  635 + getRelatedEntity(entity.id, keys).then(
  636 + function success(relatedEntity) {
  637 + delete relatedEntity.id.id;
  638 + relatedEntity.name = entity.name;
  639 + saveRelatedEntity(relatedEntity, targetParentId, keys).then(
  640 + function success(savedEntity) {
  641 + deferred.resolve(savedEntity);
  642 + },
  643 + function fail() {
  644 + deferred.reject();
  645 + }
  646 + );
  647 + },
  648 + function fail() {
  649 + deferred.reject();
  650 + }
  651 + );
  652 + }
  653 + return deferred.promise;
  654 + }
  655 +
629 656 function saveEntityPromise(entity) {
630 657 var entityType = entity.id.entityType;
631 658 if (!entity.id.id) {
... ...
... ... @@ -179,6 +179,7 @@ function DashboardUtils(types, utils, timeService) {
179 179 dashboard.configuration.settings.showEntitiesSelect = true;
180 180 dashboard.configuration.settings.showDashboardTimewindow = true;
181 181 dashboard.configuration.settings.showDashboardExport = true;
  182 + dashboard.configuration.settings.toolbarAlwaysOpen = false;
182 183 } else {
183 184 if (angular.isUndefined(dashboard.configuration.settings.stateControllerId)) {
184 185 dashboard.configuration.settings.stateControllerId = 'default';
... ...
... ... @@ -24,7 +24,7 @@ export default angular.module('thingsboard.directives.expandFullscreen', [])
24 24 /* eslint-disable angular/angularelement */
25 25
26 26 /*@ngInject*/
27   -function ExpandFullscreen($compile, $document) {
  27 +function ExpandFullscreen($compile, $document, $timeout) {
28 28
29 29 var uniqueId = 1;
30 30 var linker = function (scope, element, attrs) {
... ... @@ -97,10 +97,6 @@ function ExpandFullscreen($compile, $document) {
97 97 scope.expanded = !scope.expanded;
98 98 }
99 99
100   - var expandButton = null;
101   - if (attrs.expandButtonId) {
102   - expandButton = $('#' + attrs.expandButtonId, element)[0];
103   - }
104 100 var buttonSize;
105 101 if (attrs.expandButtonSize) {
106 102 buttonSize = attrs.expandButtonSize;
... ... @@ -115,27 +111,38 @@ function ExpandFullscreen($compile, $document) {
115 111 'options=\'{"easing": "circ-in-out", "duration": 375, "rotation": "none"}\'>' +
116 112 '</ng-md-icon>';
117 113
118   - if (expandButton) {
119   - expandButton = angular.element(expandButton);
120   - if (scope.hideExpandButton()) {
121   - expandButton.remove();
122   - } else {
123   - expandButton.attr('md-ink-ripple', 'false');
124   - expandButton.append(html);
  114 + if (attrs.expandButtonId) {
  115 + $timeout(function() {
  116 + var expandButton = $('#' + attrs.expandButtonId, element)[0];
  117 + renderExpandButton(expandButton);
  118 + });
  119 + } else {
  120 + renderExpandButton();
  121 + }
  122 +
  123 + function renderExpandButton(expandButton) {
  124 + if (expandButton) {
  125 + expandButton = angular.element(expandButton);
  126 + if (scope.hideExpandButton()) {
  127 + expandButton.remove();
  128 + } else {
  129 + expandButton.attr('md-ink-ripple', 'false');
  130 + expandButton.append(html);
125 131
126   - $compile(expandButton.contents())(scope);
  132 + $compile(expandButton.contents())(scope);
127 133
128   - expandButton.on("click", scope.toggleExpand);
129   - }
130   - } else if (!scope.hideExpandButton()) {
131   - var button = angular.element('<md-button class="tb-fullscreen-button-style tb-fullscreen-button-pos md-icon-button" ' +
132   - 'md-ink-ripple="false" ng-click="toggleExpand($event)">' +
133   - html +
134   - '</md-button>');
  134 + expandButton.on("click", scope.toggleExpand);
  135 + }
  136 + } else if (!scope.hideExpandButton()) {
  137 + var button = angular.element('<md-button class="tb-fullscreen-button-style tb-fullscreen-button-pos md-icon-button" ' +
  138 + 'md-ink-ripple="false" ng-click="toggleExpand($event)">' +
  139 + html +
  140 + '</md-button>');
135 141
136   - $compile(button)(scope);
  142 + $compile(button)(scope);
137 143
138   - element.prepend(button);
  144 + element.prepend(button);
  145 + }
139 146 }
140 147 }
141 148
... ...
... ... @@ -57,6 +57,10 @@ export default function DashboardSettingsController($scope, $mdDialog, statesCon
57 57 if (angular.isUndefined(vm.settings.showDashboardExport)) {
58 58 vm.settings.showDashboardExport = true;
59 59 }
  60 +
  61 + if (angular.isUndefined(vm.settings.toolbarAlwaysOpen)) {
  62 + vm.settings.toolbarAlwaysOpen = false;
  63 + }
60 64 }
61 65
62 66 if (vm.gridSettings) {
... ...
... ... @@ -41,6 +41,9 @@
41 41 </md-select>
42 42 </md-input-container>
43 43 <div layout="row" layout-align="start center">
  44 + <md-checkbox flex aria-label="{{ 'dashboard.toolbar-always-open' | translate }}"
  45 + ng-model="vm.settings.toolbarAlwaysOpen">{{ 'dashboard.toolbar-always-open' | translate }}
  46 + </md-checkbox>
44 47 <md-checkbox flex aria-label="{{ 'dashboard.display-title' | translate }}"
45 48 ng-model="vm.settings.showTitle">{{ 'dashboard.display-title' | translate }}
46 49 </md-checkbox>
... ...
  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 +import './dashboard-toolbar.scss';
  18 +
  19 +import 'javascript-detect-element-resize/detect-element-resize';
  20 +
  21 +/* eslint-disable import/no-unresolved, import/default */
  22 +
  23 +import dashboardToolbarTemplate from './dashboard-toolbar.tpl.html';
  24 +
  25 +/* eslint-enable import/no-unresolved, import/default */
  26 +
  27 +/*@ngInject*/
  28 +export default function DashboardToolbar() {
  29 + return {
  30 + restrict: "E",
  31 + scope: true,
  32 + transclude: true,
  33 + bindToController: {
  34 + toolbarOpened: '=',
  35 + forceFullscreen: '=',
  36 + onTriggerClick: '&'
  37 + },
  38 + controller: DashboardToolbarController,
  39 + controllerAs: 'vm',
  40 + templateUrl: dashboardToolbarTemplate
  41 + };
  42 +}
  43 +
  44 +/* eslint-disable angular/angularelement */
  45 +
  46 +
  47 +/*@ngInject*/
  48 +function DashboardToolbarController($scope, $element, $timeout, mdFabToolbarAnimation) {
  49 +
  50 + let vm = this;
  51 +
  52 + vm.mdFabToolbarElement = angular.element($element[0].querySelector('md-fab-toolbar'));
  53 +
  54 + $timeout(function() {
  55 + vm.mdFabBackgroundElement = angular.element(vm.mdFabToolbarElement[0].querySelector('.md-fab-toolbar-background'));
  56 + vm.mdFabTriggerElement = angular.element(vm.mdFabToolbarElement[0].querySelector('md-fab-trigger button'));
  57 + });
  58 +
  59 + addResizeListener(vm.mdFabToolbarElement[0], triggerFabResize); // eslint-disable-line no-undef
  60 +
  61 + $scope.$on("$destroy", function () {
  62 + removeResizeListener(vm.mdFabToolbarElement[0], triggerFabResize); // eslint-disable-line no-undef
  63 + });
  64 +
  65 + function triggerFabResize() {
  66 + var ctrl = vm.mdFabToolbarElement.controller('mdFabToolbar');
  67 + if (ctrl.isOpen) {
  68 + if (!vm.mdFabBackgroundElement[0].offsetWidth) {
  69 + mdFabToolbarAnimation.addClass(vm.mdFabToolbarElement, 'md-is-open', function () {
  70 + });
  71 + } else {
  72 + var color = window.getComputedStyle(vm.mdFabTriggerElement[0]).getPropertyValue('background-color'); //eslint-disable-line
  73 +
  74 + var width = vm.mdFabToolbarElement[0].offsetWidth;
  75 + var scale = 2 * (width / vm.mdFabTriggerElement[0].offsetWidth);
  76 + vm.mdFabBackgroundElement[0].style.backgroundColor = color;
  77 + vm.mdFabBackgroundElement[0].style.borderRadius = width + 'px';
  78 +
  79 + var transform = vm.mdFabBackgroundElement[0].style.transform;
  80 + var targetTransform = 'scale(' + scale + ')';
  81 + if (!transform || !angular.equals(transform, targetTransform)) {
  82 + vm.mdFabBackgroundElement[0].style.transform = targetTransform;
  83 + }
  84 + }
  85 + }
  86 + }
  87 +}
  88 +
... ...
  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 +@import "~compass-sass-mixins/lib/compass";
  18 +@import '../../scss/constants';
  19 +
  20 +tb-dashboard-toolbar {
  21 + md-fab-toolbar {
  22 + &.md-is-open {
  23 + md-fab-trigger {
  24 + .md-button {
  25 + &.md-fab {
  26 + opacity: 1;
  27 + @include transition(opacity .3s cubic-bezier(.55,0,.55,.2));
  28 + .md-fab-toolbar-background {
  29 + background-color: $primary-default !important;
  30 + }
  31 + }
  32 + }
  33 + }
  34 + }
  35 + md-fab-trigger {
  36 + .md-button {
  37 + &.md-fab {
  38 + line-height: 36px;
  39 + width: 36px;
  40 + height: 36px;
  41 + margin: 4px 0 0 4px;
  42 + opacity: 0.5;
  43 + @include transition(opacity .3s cubic-bezier(.55,0,.55,.2) .2s);
  44 + md-icon {
  45 + position: absolute;
  46 + top: 25%;
  47 + margin: 0;
  48 + line-height: 18px;
  49 + height: 18px;
  50 + width: 18px;
  51 + min-height: 18px;
  52 + min-width: 18px;
  53 + }
  54 + }
  55 + }
  56 + }
  57 + &.is-fullscreen {
  58 + &.md-is-open {
  59 + md-fab-trigger {
  60 + .md-button {
  61 + &.md-fab {
  62 + .md-fab-toolbar-background {
  63 + transition-delay: 0ms !important;
  64 + transition-duration: 0ms !important;
  65 + }
  66 + }
  67 + }
  68 + }
  69 + }
  70 + .md-fab-toolbar-wrapper {
  71 + height: 64px;
  72 + md-toolbar {
  73 + min-height: 64px;
  74 + height: 64px;
  75 + }
  76 + }
  77 + }
  78 + .md-fab-toolbar-wrapper {
  79 + height: 50px;
  80 + md-toolbar {
  81 + min-height: 50px;
  82 + height: 50px;
  83 + md-fab-actions {
  84 + font-size: 16px;
  85 + margin-top: 0px;
  86 + .close-action {
  87 + margin-right: -18px;
  88 + }
  89 + .md-fab-action-item {
  90 + width: 100%;
  91 + height: 46px;
  92 + .tb-dashboard-action-panels {
  93 + height: 46px;
  94 + flex-direction: row-reverse;
  95 + .tb-dashboard-action-panel {
  96 + height: 46px;
  97 + flex-direction: row-reverse;
  98 + div {
  99 + height: 46px;
  100 + }
  101 + md-select {
  102 + pointer-events: all;
  103 + }
  104 + tb-states-component {
  105 + pointer-events: all;
  106 + }
  107 + }
  108 + }
  109 + }
  110 + }
  111 + }
  112 + }
  113 + }
  114 +}
\ No newline at end of file
... ...
  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 +<md-fab-toolbar md-open="vm.toolbarOpened"
  20 + md-direction="left"
  21 + ng-class="{'is-fullscreen': vm.forceFullscreen, 'md-whiteframe-z1': vm.forceFullscreen}">
  22 + <md-fab-trigger class="align-with-text">
  23 + <md-button aria-label="menu" class="md-fab md-primary" ng-click="vm.onTriggerClick()">
  24 + <md-tooltip ng-show="!vm.toolbarOpened" md-direction="bottom">
  25 + {{ 'dashboard.open-toolbar' | translate }}
  26 + </md-tooltip>
  27 + <md-icon aria-label="dashboard-toolbar" class="material-icons">more_horiz</md-icon>
  28 + </md-button>
  29 + </md-fab-trigger>
  30 + <md-toolbar>
  31 + <md-fab-actions class="md-toolbar-tools">
  32 + <div ng-transclude></div>
  33 + </md-fab-actions>
  34 + </md-toolbar>
  35 +</md-fab-toolbar>
... ...
... ... @@ -63,7 +63,9 @@ export default function DashboardController(types, dashboardUtils, widgetService
63 63 }
64 64
65 65 Object.defineProperty(vm, 'toolbarOpened', {
66   - get: function() { return !vm.widgetEditMode && ($scope.forceFullscreen || vm.isToolbarOpened || vm.isEdit || vm.showRightLayoutSwitch()); },
  66 + get: function() {
  67 + return !vm.widgetEditMode &&
  68 + (toolbarAlwaysOpen() || $scope.forceFullscreen || vm.isToolbarOpened || vm.isEdit || vm.showRightLayoutSwitch()); },
67 69 set: function() { }
68 70 });
69 71
... ... @@ -103,9 +105,11 @@ export default function DashboardController(types, dashboardUtils, widgetService
103 105 }
104 106
105 107 vm.showCloseToolbar = function() {
106   - return !$scope.forceFullscreen && !vm.isEdit && !vm.showRightLayoutSwitch();
  108 + return !vm.toolbarAlwaysOpen() && !$scope.forceFullscreen && !vm.isEdit && !vm.showRightLayoutSwitch();
107 109 }
108 110
  111 + vm.toolbarAlwaysOpen = toolbarAlwaysOpen;
  112 +
109 113 vm.showRightLayoutSwitch = function() {
110 114 return vm.isMobile && vm.layouts.right.show;
111 115 }
... ... @@ -738,6 +742,15 @@ export default function DashboardController(types, dashboardUtils, widgetService
738 742 return link;
739 743 }
740 744
  745 + function toolbarAlwaysOpen() {
  746 + if (vm.dashboard && vm.dashboard.configuration.settings &&
  747 + angular.isDefined(vm.dashboard.configuration.settings.toolbarAlwaysOpen)) {
  748 + return vm.dashboard.configuration.settings.toolbarAlwaysOpen;
  749 + } else {
  750 + return false;
  751 + }
  752 + }
  753 +
741 754 function displayTitle() {
742 755 if (vm.dashboard && vm.dashboard.configuration.settings &&
743 756 angular.isDefined(vm.dashboard.configuration.settings.showTitle)) {
... ...
... ... @@ -68,87 +68,23 @@ section.tb-dashboard-toolbar {
68 68 pointer-events: none;
69 69 &.tb-dashboard-toolbar-opened {
70 70 right: 0px;
71   - @include transition(right .3s cubic-bezier(.55,0,.55,.2));
  71 + // @include transition(right .3s cubic-bezier(.55,0,.55,.2));
72 72 }
73 73 &.tb-dashboard-toolbar-closed {
74 74 right: 18px;
75 75 @include transition(right .3s cubic-bezier(.55,0,.55,.2) .2s);
76 76 }
77   - md-fab-toolbar {
78   - &.md-is-open {
79   - md-fab-trigger {
80   - .md-button {
81   - &.md-fab {
82   - opacity: 1;
83   - @include transition(opacity .3s cubic-bezier(.55,0,.55,.2));
84   - }
85   - }
86   - }
87   - }
88   - md-fab-trigger {
89   - .md-button {
90   - &.md-fab {
91   - line-height: 36px;
92   - width: 36px;
93   - height: 36px;
94   - margin: 4px 0 0 4px;
95   - opacity: 0.5;
96   - @include transition(opacity .3s cubic-bezier(.55,0,.55,.2) .2s);
97   - md-icon {
98   - position: absolute;
99   - top: 25%;
100   - margin: 0;
101   - line-height: 18px;
102   - height: 18px;
103   - width: 18px;
104   - min-height: 18px;
105   - min-width: 18px;
106   - }
107   - }
108   - }
109   - }
110   - .md-fab-toolbar-wrapper {
111   - height: 50px;
112   - md-toolbar {
113   - min-height: 46px;
114   - height: 46px;
115   - md-fab-actions {
116   - font-size: 16px;
117   - margin-top: 0px;
118   - .close-action {
119   - margin-right: -18px;
120   - }
121   - .md-fab-action-item {
122   - width: 100%;
123   - height: 46px;
124   - .tb-dashboard-action-panels {
125   - height: 46px;
126   - flex-direction: row-reverse;
127   - .tb-dashboard-action-panel {
128   - height: 46px;
129   - flex-direction: row-reverse;
130   - div {
131   - height: 46px;
132   - }
133   - md-select {
134   - pointer-events: all;
135   - }
136   - tb-states-component {
137   - pointer-events: all;
138   - }
139   - }
140   - }
141   - }
142   - }
143   - }
144   - }
145   - }
146 77 }
147 78
148 79 .tb-dashboard-container {
149 80 &.tb-dashboard-toolbar-opened {
150   - margin-top: 50px;
151   - @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2));
  81 + &.is-fullscreen {
  82 + margin-top: 64px;
  83 + }
  84 + &:not(.is-fullscreen) {
  85 + margin-top: 50px;
  86 + @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2));
  87 + }
152 88 }
153 89 &.tb-dashboard-toolbar-closed {
154 90 margin-top: 0px;
... ...
... ... @@ -19,110 +19,98 @@
19 19 hide-expand-button="vm.widgetEditMode || vm.iframeMode || forceFullscreen" expand-tooltip-direction="bottom">
20 20 <section class="tb-dashboard-toolbar" ng-show="vm.showDashboardToolbar()"
21 21 ng-class="{ 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">
22   - <md-fab-toolbar ng-show="!vm.widgetEditMode" md-open="vm.toolbarOpened"
23   - md-direction="left">
24   - <md-fab-trigger class="align-with-text">
25   - <md-button aria-label="menu" class="md-fab md-primary" ng-click="vm.openToolbar()">
26   - <md-tooltip ng-show="!vm.toolbarOpened" md-direction="bottom">
27   - {{ 'dashboard.open-toolbar' | translate }}
28   - </md-tooltip>
29   - <md-icon aria-label="dashboard-toolbar" class="material-icons">more_horiz</md-icon>
30   - </md-button>
31   - </md-fab-trigger>
32   - <md-toolbar>
33   - <md-fab-actions class="md-toolbar-tools">
34   - <div class="tb-dashboard-action-panels" flex layout="row" layout-align="start center">
35   - <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="start center">
36   - <md-button ng-show="vm.showCloseToolbar()" aria-label="close-toolbar" class="md-icon-button close-action" ng-click="vm.closeToolbar()">
37   - <md-tooltip md-direction="bottom">
38   - {{ 'dashboard.close-toolbar' | translate }}
39   - </md-tooltip>
40   - <md-icon aria-label="close-toolbar" class="material-icons">arrow_forward</md-icon>
41   - </md-button>
42   - <md-button ng-show="vm.showRightLayoutSwitch()" aria-label="switch-layouts" class="md-icon-button" ng-click="vm.toggleLayouts()">
43   - <ng-md-icon icon="{{vm.isRightLayoutOpened ? 'arrow_back' : 'menu'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon>
44   - <md-tooltip md-direction="bottom">
45   - {{ (vm.isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }}
46   - </md-tooltip>
47   - </md-button>
48   - <md-button id="dashboard-expand-button"
49   - aria-label="{{ 'fullscreen.fullscreen' | translate }}"
50   - class="md-icon-button">
51   - </md-button>
52   - <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true">
53   - </tb-user-menu>
54   - <md-button ng-show="vm.isEdit || vm.displayExport()"
55   - aria-label="{{ 'action.export' | translate }}" class="md-icon-button"
56   - ng-click="vm.exportDashboard($event)">
57   - <md-tooltip md-direction="bottom">
58   - {{ 'dashboard.export' | translate }}
59   - </md-tooltip>
60   - <md-icon aria-label="{{ 'action.export' | translate }}" class="material-icons">file_download</md-icon>
61   - </md-button>
62   - <tb-timewindow ng-show="vm.isEdit || vm.displayDashboardTimewindow()"
63   - is-toolbar
64   - direction="left"
65   - tooltip-direction="bottom" aggregation
66   - ng-model="vm.dashboardCtx.dashboardTimewindow">
67   - </tb-timewindow>
68   - <tb-aliases-entity-select ng-show="!vm.isEdit && vm.displayEntitiesSelect()"
69   - tooltip-direction="bottom"
70   - ng-model="vm.dashboardCtx.aliasesInfo.entityAliases"
71   - entity-aliases-info="vm.dashboardCtx.aliasesInfo.entityAliasesInfo">
72   - </tb-aliases-entity-select>
73   - <md-button ng-show="vm.isEdit" aria-label="{{ 'entity.aliases' | translate }}" class="md-icon-button"
74   - ng-click="vm.openEntityAliases($event)">
75   - <md-tooltip md-direction="bottom">
76   - {{ 'entity.aliases' | translate }}
77   - </md-tooltip>
78   - <md-icon aria-label="{{ 'entity.aliases' | translate }}" class="material-icons">devices_other</md-icon>
79   - </md-button>
80   - <md-button ng-show="vm.isEdit" aria-label="{{ 'dashboard.settings' | translate }}" class="md-icon-button"
81   - ng-click="vm.openDashboardSettings($event)">
82   - <md-tooltip md-direction="bottom">
83   - {{ 'dashboard.settings' | translate }}
84   - </md-tooltip>
85   - <md-icon aria-label="{{ 'dashboard.settings' | translate }}" class="material-icons">settings</md-icon>
86   - </md-button>
87   - <tb-dashboard-select ng-show="!vm.isEdit && !vm.widgetEditMode && vm.displayDashboardsSelect()"
88   - ng-model="vm.currentDashboardId"
89   - dashboards-scope="{{vm.currentDashboardScope}}"
90   - customer-id="vm.currentCustomerId">
91   - </tb-dashboard-select>
92   - </div>
93   - <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="end center">
94   - <div layout="row" layout-align="start center" ng-show="vm.isEdit">
95   - <md-button aria-label="{{ 'dashboard.manage-states' | translate }}" class="md-icon-button"
96   - ng-click="vm.manageDashboardStates($event)">
97   - <md-tooltip md-direction="bottom">
98   - {{ 'dashboard.manage-states' | translate }}
99   - </md-tooltip>
100   - <md-icon aria-label="{{ 'dashboard.manage-states' | translate }}" class="material-icons">layers</md-icon>
101   - </md-button>
102   - <md-button aria-label="{{ 'layout.manage' | translate }}" class="md-icon-button"
103   - ng-click="vm.manageDashboardLayouts($event)">
104   - <md-tooltip md-direction="bottom">
105   - {{ 'layout.manage' | translate }}
106   - </md-tooltip>
107   - <md-icon aria-label="{{ 'layout.manage' | translate }}" class="material-icons">view_compact</md-icon>
108   - </md-button>
109   - </div>
110   - <div layout="row" layout-align="start center">
111   - <tb-states-component ng-if="vm.isEdit" states-controller-id="'default'"
112   - dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
113   - </tb-states-component>
114   - <tb-states-component ng-if="!vm.isEdit" states-controller-id="vm.dashboardConfiguration.settings.stateControllerId"
115   - dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
116   - </tb-states-component>
117   - </div>
118   - </div>
  22 + <tb-dashboard-toolbar ng-show="!vm.widgetEditMode" force-fullscreen="forceFullscreen"
  23 + toolbar-opened="vm.toolbarOpened" on-trigger-click="vm.openToolbar()">
  24 + <div class="tb-dashboard-action-panels" flex layout="row" layout-align="start center">
  25 + <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="start center">
  26 + <md-button ng-show="vm.showCloseToolbar()" aria-label="close-toolbar" class="md-icon-button close-action" ng-click="vm.closeToolbar()">
  27 + <md-tooltip md-direction="bottom">
  28 + {{ 'dashboard.close-toolbar' | translate }}
  29 + </md-tooltip>
  30 + <md-icon aria-label="close-toolbar" class="material-icons">arrow_forward</md-icon>
  31 + </md-button>
  32 + <md-button ng-show="vm.showRightLayoutSwitch()" aria-label="switch-layouts" class="md-icon-button" ng-click="vm.toggleLayouts()">
  33 + <ng-md-icon icon="{{vm.isRightLayoutOpened ? 'arrow_back' : 'menu'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon>
  34 + <md-tooltip md-direction="bottom">
  35 + {{ (vm.isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }}
  36 + </md-tooltip>
  37 + </md-button>
  38 + <md-button id="dashboard-expand-button"
  39 + aria-label="{{ 'fullscreen.fullscreen' | translate }}"
  40 + class="md-icon-button">
  41 + </md-button>
  42 + <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true">
  43 + </tb-user-menu>
  44 + <md-button ng-show="vm.isEdit || vm.displayExport()"
  45 + aria-label="{{ 'action.export' | translate }}" class="md-icon-button"
  46 + ng-click="vm.exportDashboard($event)">
  47 + <md-tooltip md-direction="bottom">
  48 + {{ 'dashboard.export' | translate }}
  49 + </md-tooltip>
  50 + <md-icon aria-label="{{ 'action.export' | translate }}" class="material-icons">file_download</md-icon>
  51 + </md-button>
  52 + <tb-timewindow ng-show="vm.isEdit || vm.displayDashboardTimewindow()"
  53 + is-toolbar
  54 + direction="left"
  55 + tooltip-direction="bottom" aggregation
  56 + ng-model="vm.dashboardCtx.dashboardTimewindow">
  57 + </tb-timewindow>
  58 + <tb-aliases-entity-select ng-show="!vm.isEdit && vm.displayEntitiesSelect()"
  59 + tooltip-direction="bottom"
  60 + ng-model="vm.dashboardCtx.aliasesInfo.entityAliases"
  61 + entity-aliases-info="vm.dashboardCtx.aliasesInfo.entityAliasesInfo">
  62 + </tb-aliases-entity-select>
  63 + <md-button ng-show="vm.isEdit" aria-label="{{ 'entity.aliases' | translate }}" class="md-icon-button"
  64 + ng-click="vm.openEntityAliases($event)">
  65 + <md-tooltip md-direction="bottom">
  66 + {{ 'entity.aliases' | translate }}
  67 + </md-tooltip>
  68 + <md-icon aria-label="{{ 'entity.aliases' | translate }}" class="material-icons">devices_other</md-icon>
  69 + </md-button>
  70 + <md-button ng-show="vm.isEdit" aria-label="{{ 'dashboard.settings' | translate }}" class="md-icon-button"
  71 + ng-click="vm.openDashboardSettings($event)">
  72 + <md-tooltip md-direction="bottom">
  73 + {{ 'dashboard.settings' | translate }}
  74 + </md-tooltip>
  75 + <md-icon aria-label="{{ 'dashboard.settings' | translate }}" class="material-icons">settings</md-icon>
  76 + </md-button>
  77 + <tb-dashboard-select ng-show="!vm.isEdit && !vm.widgetEditMode && vm.displayDashboardsSelect()"
  78 + ng-model="vm.currentDashboardId"
  79 + dashboards-scope="{{vm.currentDashboardScope}}"
  80 + customer-id="vm.currentCustomerId">
  81 + </tb-dashboard-select>
  82 + </div>
  83 + <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="end center">
  84 + <div layout="row" layout-align="start center" ng-show="vm.isEdit">
  85 + <md-button aria-label="{{ 'dashboard.manage-states' | translate }}" class="md-icon-button"
  86 + ng-click="vm.manageDashboardStates($event)">
  87 + <md-tooltip md-direction="bottom">
  88 + {{ 'dashboard.manage-states' | translate }}
  89 + </md-tooltip>
  90 + <md-icon aria-label="{{ 'dashboard.manage-states' | translate }}" class="material-icons">layers</md-icon>
  91 + </md-button>
  92 + <md-button aria-label="{{ 'layout.manage' | translate }}" class="md-icon-button"
  93 + ng-click="vm.manageDashboardLayouts($event)">
  94 + <md-tooltip md-direction="bottom">
  95 + {{ 'layout.manage' | translate }}
  96 + </md-tooltip>
  97 + <md-icon aria-label="{{ 'layout.manage' | translate }}" class="material-icons">view_compact</md-icon>
  98 + </md-button>
119 99 </div>
120   - </md-fab-actions>
121   - </md-toolbar>
122   - </md-fab-toolbar>
  100 + <div layout="row" layout-align="start center">
  101 + <tb-states-component ng-if="vm.isEdit" states-controller-id="'default'"
  102 + dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
  103 + </tb-states-component>
  104 + <tb-states-component ng-if="!vm.isEdit" states-controller-id="vm.dashboardConfiguration.settings.stateControllerId"
  105 + dashboard-ctrl="vm" states="vm.dashboardConfiguration.states">
  106 + </tb-states-component>
  107 + </div>
  108 + </div>
  109 + </div>
  110 + </tb-dashboard-toolbar>
123 111 </section>
124 112 <section class="tb-dashboard-container tb-absolute-fill"
125   - ng-class="{ 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">
  113 + ng-class="{ 'is-fullscreen': forceFullscreen, 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">
126 114 <section ng-show="!loading && vm.dashboardConfigurationError()" layout-align="center center"
127 115 ng-style="{'color': vm.dashboard.configuration.settings.titleColor}"
128 116 ng-class="{'tb-padded' : !vm.widgetEditMode}"
... ...
... ... @@ -45,6 +45,7 @@ import AddDashboardsToCustomerController from './add-dashboards-to-customer.cont
45 45 import AddWidgetController from './add-widget.controller';
46 46 import DashboardDirective from './dashboard.directive';
47 47 import EditWidgetDirective from './edit-widget.directive';
  48 +import DashboardToolbar from './dashboard-toolbar.directive';
48 49
49 50 export default angular.module('thingsboard.dashboard', [
50 51 uiRouter,
... ... @@ -78,4 +79,5 @@ export default angular.module('thingsboard.dashboard', [
78 79 .controller('AddWidgetController', AddWidgetController)
79 80 .directive('tbDashboardDetails', DashboardDirective)
80 81 .directive('tbEditWidget', EditWidgetDirective)
  82 + .directive('tbDashboardToolbar', DashboardToolbar)
81 83 .name;
... ...
... ... @@ -328,6 +328,7 @@ export default angular.module('thingsboard.locale', [])
328 328 "min-vertical-margin-message": "Only 0 is allowed as minimum vertical margin value.",
329 329 "max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.",
330 330 "display-title": "Display dashboard title",
  331 + "toolbar-always-open": "Keep toolbar opened",
331 332 "title-color": "Title color",
332 333 "display-dashboards-selection": "Display dashboards selection",
333 334 "display-entities-selection": "Display entities selection",
... ...
... ... @@ -20,10 +20,12 @@
20 20 $gray: #eee;
21 21
22 22 $primary-palette-color: 'indigo';
  23 +$default: '500';
23 24 $hue-1: '300';
24 25 $hue-2: '800';
25 26 $hue-3: 'a100';
26 27
  28 +$primary-default: #305680; //material-color($primary-palette-color, $default);
27 29 $primary-hue-1: material-color($primary-palette-color, $hue-1);
28 30 $primary-hue-2: material-color($primary-palette-color, $hue-2);
29 31 $primary-hue-3: rgb(207, 216, 220);
... ...