From ffc7a57e59b5b6d670cd65b72a15889abd884948 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 25 May 2017 15:52:28 +0300 Subject: [PATCH] UI: Improve dashboard toolbar. Implement entity copy function. --- ui/src/app/api/entity.service.js | 29 ++- ui/src/app/common/dashboard-utils.service.js | 1 + .../components/expand-fullscreen.directive.js | 51 +++-- .../dashboard-settings.controller.js | 4 + .../app/dashboard/dashboard-settings.tpl.html | 3 + .../dashboard/dashboard-toolbar.directive.js | 88 ++++++++ ui/src/app/dashboard/dashboard-toolbar.scss | 114 +++++++++++ .../app/dashboard/dashboard-toolbar.tpl.html | 35 ++++ ui/src/app/dashboard/dashboard.controller.js | 17 +- ui/src/app/dashboard/dashboard.scss | 80 +------- ui/src/app/dashboard/dashboard.tpl.html | 190 ++++++++---------- ui/src/app/dashboard/index.js | 2 + ui/src/app/locale/locale.constant.js | 1 + ui/src/scss/constants.scss | 2 + 14 files changed, 419 insertions(+), 198 deletions(-) create mode 100644 ui/src/app/dashboard/dashboard-toolbar.directive.js create mode 100644 ui/src/app/dashboard/dashboard-toolbar.scss create mode 100644 ui/src/app/dashboard/dashboard-toolbar.tpl.html diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index 43c537cafc..a70308b52f 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 57317b5b71..78136dfb2e 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 37491e71df..b70fd9479a 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"}\'>' + ''; - 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('' + - html + - ''); + expandButton.on("click", scope.toggleExpand); + } + } else if (!scope.hideExpandButton()) { + var button = angular.element('' + + html + + ''); - $compile(button)(scope); + $compile(button)(scope); - element.prepend(button); + element.prepend(button); + } } } diff --git a/ui/src/app/dashboard/dashboard-settings.controller.js b/ui/src/app/dashboard/dashboard-settings.controller.js index dbe4cbe992..ac987093e6 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 88fc66d651..f3ff704c60 100644 --- a/ui/src/app/dashboard/dashboard-settings.tpl.html +++ b/ui/src/app/dashboard/dashboard-settings.tpl.html @@ -41,6 +41,9 @@
+ {{ 'dashboard.toolbar-always-open' | translate }} + {{ 'dashboard.display-title' | translate }} 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 0000000000..63a34f8918 --- /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; + } + } + } + } +} + diff --git a/ui/src/app/dashboard/dashboard-toolbar.scss b/ui/src/app/dashboard/dashboard-toolbar.scss new file mode 100644 index 0000000000..af4889ed03 --- /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 0000000000..46192ffa7b --- /dev/null +++ b/ui/src/app/dashboard/dashboard-toolbar.tpl.html @@ -0,0 +1,35 @@ + + + + + + + {{ 'dashboard.open-toolbar' | translate }} + + more_horiz + + + + +
+
+
+
diff --git a/ui/src/app/dashboard/dashboard.controller.js b/ui/src/app/dashboard/dashboard.controller.js index c446be43cd..ecf072d7a7 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)) { diff --git a/ui/src/app/dashboard/dashboard.scss b/ui/src/app/dashboard/dashboard.scss index bc5ec56a33..ca2bbabfc1 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; diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html index 94e016eaa7..8338612484 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">
- - - - - {{ 'dashboard.open-toolbar' | translate }} - - more_horiz - - - - -
-
- - - {{ 'dashboard.close-toolbar' | translate }} - - arrow_forward - - - - - {{ (vm.isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }} - - - - - - - - - {{ 'dashboard.export' | translate }} - - file_download - - - - - - - - {{ 'entity.aliases' | translate }} - - devices_other - - - - {{ 'dashboard.settings' | translate }} - - settings - - - -
-
-
- - - {{ 'dashboard.manage-states' | translate }} - - layers - - - - {{ 'layout.manage' | translate }} - - view_compact - -
-
- - - - -
-
+ +
+
+ + + {{ 'dashboard.close-toolbar' | translate }} + + arrow_forward + + + + + {{ (vm.isRightLayoutOpened ? 'dashboard.hide-details' : 'dashboard.show-details') | translate }} + + + + + + + + + {{ 'dashboard.export' | translate }} + + file_download + + + + + + + + {{ 'entity.aliases' | translate }} + + devices_other + + + + {{ 'dashboard.settings' | translate }} + + settings + + + +
+
+
+ + + {{ 'dashboard.manage-states' | translate }} + + layers + + + + {{ 'layout.manage' | translate }} + + view_compact +
- - - +
+ + + + +
+
+
+
+ ng-class="{ 'is-fullscreen': forceFullscreen, 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }">