From 6be5f9aa4d315facb772f681c95f05ff3546c698 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 15 Oct 2019 16:15:18 +0300 Subject: [PATCH] Manage edge dashboards functionality --- .../controller/DashboardController.java | 22 ++ .../dao/dashboard/DashboardService.java | 2 + .../server/common/data/ShortEdgeInfo.java | 39 +++- .../dao/dashboard/DashboardServiceImpl.java | 17 ++ .../dao/model/sql/DashboardInfoEntity.java | 20 ++ ui/src/app/api/dashboard.service.js | 60 +++++- ui/src/app/customer/customer.controller.js | 2 +- .../add-dashboards-to-edge.controller.js | 122 +++++++++++ .../dashboard/add-dashboards-to-edge.tpl.html | 77 +++++++ ui/src/app/dashboard/dashboard.routes.js | 21 ++ ui/src/app/dashboard/dashboards.controller.js | 190 ++++++++++++++++-- ui/src/app/dashboard/index.js | 2 + ui/src/app/edge/edge.controller.js | 29 +++ ui/src/app/locale/locale.constant-en_US.json | 20 +- ui/src/app/services/menu.service.js | 8 +- 15 files changed, 603 insertions(+), 28 deletions(-) create mode 100644 ui/src/app/dashboard/add-dashboards-to-edge.controller.js create mode 100644 ui/src/app/dashboard/add-dashboards-to-edge.tpl.html diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 252eeb90cd..077714a8aa 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -689,4 +689,26 @@ public class DashboardController extends BaseController { throw handleException(e); } } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/edge/{edgeId}/dashboards", params = { "limit" }, method = RequestMethod.GET) + @ResponseBody + public TimePageData getEdgeDashboards( + @PathVariable("edgeId") String strEdgeId, + @RequestParam int limit, + @RequestParam(required = false) Long startTime, + @RequestParam(required = false) Long endTime, + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, + @RequestParam(required = false) String offset) throws ThingsboardException { + checkParameter("edgeId", strEdgeId); + try { + TenantId tenantId = getCurrentUser().getTenantId(); + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + checkEdgeId(edgeId, Operation.READ); + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); + return checkNotNull(dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get()); + } catch (Exception e) { + throw handleException(e); + } + } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java index 696fb0564d..2d168d78ed 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java @@ -62,4 +62,6 @@ public interface DashboardService { void unassignEdgeDashboards(TenantId tenantId, EdgeId edgeId); void updateEdgeDashboards(TenantId tenantId, EdgeId edgeId); + + ListenableFuture> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ShortEdgeInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/ShortEdgeInfo.java index 48f2a5faed..5a28264d64 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ShortEdgeInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ShortEdgeInfo.java @@ -1,15 +1,46 @@ +/** + * Copyright © 2016-2019 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. + */ package org.thingsboard.server.common.data; import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.Getter; +import lombok.Setter; import org.thingsboard.server.common.data.id.EdgeId; -@Data -@NoArgsConstructor @AllArgsConstructor public class ShortEdgeInfo { + @Getter @Setter private EdgeId edgeId; + + @Getter @Setter private String title; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ShortEdgeInfo that = (ShortEdgeInfo) o; + + return edgeId.equals(that.edgeId); + } + + @Override + public int hashCode() { + return edgeId.hashCode(); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index a9aded5968..8e5ff3a2e6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -299,6 +299,23 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb new EdgeDashboardsUpdater(edge).removeEntities(tenantId, edge); } + @Override + public ListenableFuture> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) { + log.trace("Executing findDashboardsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); + Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + Validator.validateId(edgeId, "Incorrect customerId " + edgeId); + Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); + ListenableFuture> dashboards = dashboardInfoDao.findDashboardsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); + + return Futures.transform(dashboards, new Function, TimePageData>() { + @Nullable + @Override + public TimePageData apply(@Nullable List dashboards) { + return new TimePageData<>(dashboards, pageLink); + } + }); + } + private Dashboard updateAssignedEdge(TenantId tenantId, DashboardId dashboardId, Edge edge) { Dashboard dashboard = findDashboardById(tenantId, dashboardId); if (dashboard.updateAssignedEdge(edge)) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java index 174edfd039..624833c927 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java @@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.ShortCustomerInfo; +import org.thingsboard.server.common.data.ShortEdgeInfo; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -47,6 +48,8 @@ public class DashboardInfoEntity extends BaseSqlEntity implements private static final ObjectMapper objectMapper = new ObjectMapper(); private static final JavaType assignedCustomersType = objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); + private static final JavaType assignedEdgesType = + objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortEdgeInfo.class); @Column(name = ModelConstants.DASHBOARD_TENANT_ID_PROPERTY) private String tenantId; @@ -60,6 +63,9 @@ public class DashboardInfoEntity extends BaseSqlEntity implements @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) private String assignedCustomers; + @Column(name = ModelConstants.DASHBOARD_ASSIGNED_EDGES_PROPERTY) + private String assignedEdges; + public DashboardInfoEntity() { super(); } @@ -79,6 +85,13 @@ public class DashboardInfoEntity extends BaseSqlEntity implements log.error("Unable to serialize assigned customers to string!", e); } } + if (dashboardInfo.getAssignedEdges() != null) { + try { + this.assignedEdges = objectMapper.writeValueAsString(dashboardInfo.getAssignedEdges()); + } catch (JsonProcessingException e) { + log.error("Unable to serialize assigned edges to string!", e); + } + } } @Override @@ -110,6 +123,13 @@ public class DashboardInfoEntity extends BaseSqlEntity implements log.warn("Unable to parse assigned customers!", e); } } + if (!StringUtils.isEmpty(assignedEdges)) { + try { + dashboardInfo.setAssignedEdges(objectMapper.readValue(assignedEdges, assignedEdgesType)); + } catch (IOException e) { + log.warn("Unable to parse assigned edges!", e); + } + } return dashboardInfo; } diff --git a/ui/src/app/api/dashboard.service.js b/ui/src/app/api/dashboard.service.js index b0b72e626e..af314998da 100644 --- a/ui/src/app/api/dashboard.service.js +++ b/ui/src/app/api/dashboard.service.js @@ -45,7 +45,10 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { getPublicDashboardLink: getPublicDashboardLink, updateDashboardEdges: updateDashboardEdges, addDashboardEdges: addDashboardEdges, - removeDashboardEdges: removeDashboardEdges + removeDashboardEdges: removeDashboardEdges, + getEdgeDashboards: getEdgeDashboards, + assignDashboardToEdge: assignDashboardToEdge, + unassignDashboardFromEdge: unassignDashboardFromEdge } return service; @@ -285,6 +288,20 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { } dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); } + dashboard.assignedEdgesIds = []; + if (dashboard.assignedEdges && dashboard.assignedEdges.length) { + // var assignedEdgesTitles = []; + for (var j = 0; j < dashboard.assignedEdges.length; j++) { + var assignedEdge = dashboard.assignedEdges[j]; + dashboard.assignedEdgesIds.push(assignedEdge.edgeId.id); + // if (assignedCustomer.public) { + // dashboard.publicCustomerId = assignedCustomer.customerId.id; + // } else { + // assignedCustomersTitles.push(assignedCustomer.title); + // } + } + // dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); + } return dashboard; } @@ -292,6 +309,7 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { delete dashboard.publicCustomerId; delete dashboard.assignedCustomersText; delete dashboard.assignedCustomersIds; + delete dashboard.assignedEdgeIds; return dashboard; } @@ -327,4 +345,44 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { }); return deferred.promise; } + + function getEdgeDashboards(edgeId, pageLink, config) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/dashboards?limit=' + pageLink.limit; + if (angular.isDefined(pageLink.idOffset)) { + url += '&offset=' + pageLink.idOffset; + } + $http.get(url, config).then(function success(response) { + response.data = prepareDashboards(response.data); + if (pageLink.textSearch) { + response.data.data = $filter('filter')(response.data.data, {title: pageLink.textSearch}); + } + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function assignDashboardToEdge(edgeId, dashboardId) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/dashboard/' + dashboardId; + $http.post(url, null).then(function success(response) { + deferred.resolve(prepareDashboard(response.data)); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function unassignDashboardFromEdge(edgeId, dashboardId) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/dashboard/' + dashboardId; + $http.delete(url).then(function success(response) { + deferred.resolve(prepareDashboard(response.data)); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } } diff --git a/ui/src/app/customer/customer.controller.js b/ui/src/app/customer/customer.controller.js index 2d20a59e2b..9240ccedee 100644 --- a/ui/src/app/customer/customer.controller.js +++ b/ui/src/app/customer/customer.controller.js @@ -89,7 +89,7 @@ export default function CustomerController(customerService, $state, $stateParams return $translate.instant('customer.manage-customer-edges') } }, - icon: "toys" + icon: "wifi_tethering" }, { onAction: function ($event, item) { diff --git a/ui/src/app/dashboard/add-dashboards-to-edge.controller.js b/ui/src/app/dashboard/add-dashboards-to-edge.controller.js new file mode 100644 index 0000000000..f9c28d8112 --- /dev/null +++ b/ui/src/app/dashboard/add-dashboards-to-edge.controller.js @@ -0,0 +1,122 @@ +/* + * Copyright © 2016-2019 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. + */ +/*@ngInject*/ +export default function AddDashboardsToEdgeController(dashboardService, $mdDialog, $q, edgeId, dashboards) { + + var vm = this; + + vm.dashboards = dashboards; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.hasData = hasData; + vm.noData = noData; + vm.searchDashboardTextUpdated = searchDashboardTextUpdated; + vm.toggleDashboardSelection = toggleDashboardSelection; + + vm.theDashboards = { + getItemAtIndex: function (index) { + if (index > vm.dashboards.data.length) { + vm.theDashboards.fetchMoreItems_(index); + return null; + } + var item = vm.dashboards.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.dashboards.hasNext) { + return vm.dashboards.data.length + vm.dashboards.nextPageLink.limit; + } else { + return vm.dashboards.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.dashboards.hasNext && !vm.dashboards.pending) { + vm.dashboards.pending = true; + dashboardService.getTenantDashboards(vm.dashboards.nextPageLink).then( + function success(dashboards) { + vm.dashboards.data = vm.dashboards.data.concat(dashboards.data); + vm.dashboards.nextPageLink = dashboards.nextPageLink; + vm.dashboards.hasNext = dashboards.hasNext; + if (vm.dashboards.hasNext) { + vm.dashboards.nextPageLink.limit = vm.dashboards.pageSize; + } + vm.dashboards.pending = false; + }, + function fail() { + vm.dashboards.hasNext = false; + vm.dashboards.pending = false; + }); + } + } + } + + function cancel () { + $mdDialog.cancel(); + } + + function assign () { + var tasks = []; + for (var dashboardId in vm.dashboards.selections) { + tasks.push(dashboardService.assignDashboardToEdge(edgeId, dashboardId)); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData () { + return vm.dashboards.data.length == 0 && !vm.dashboards.hasNext; + } + + function hasData () { + return vm.dashboards.data.length > 0; + } + + function toggleDashboardSelection ($event, dashboard) { + $event.stopPropagation(); + var selected = angular.isDefined(dashboard.selected) && dashboard.selected; + dashboard.selected = !selected; + if (dashboard.selected) { + vm.dashboards.selections[dashboard.id.id] = true; + vm.dashboards.selectedCount++; + } else { + delete vm.dashboards.selections[dashboard.id.id]; + vm.dashboards.selectedCount--; + } + } + + function searchDashboardTextUpdated () { + vm.dashboards = { + pageSize: vm.dashboards.pageSize, + data: [], + nextPageLink: { + limit: vm.dashboards.pageSize, + textSearch: vm.searchText + }, + selections: {}, + selectedCount: 0, + hasNext: true, + pending: false + }; + } +} \ No newline at end of file diff --git a/ui/src/app/dashboard/add-dashboards-to-edge.tpl.html b/ui/src/app/dashboard/add-dashboards-to-edge.tpl.html new file mode 100644 index 0000000000..a53ee3490a --- /dev/null +++ b/ui/src/app/dashboard/add-dashboards-to-edge.tpl.html @@ -0,0 +1,77 @@ + + +
+ +
+

dashboard.assign-dashboard-to-edge

+ + + + +
+
+ + + +
+
+ dashboard.assign-dashboard-to-edge-text + + + + search + + + +
+ dashboard.no-dashboards-text + + + + + {{ dashboard.title }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/dashboard/dashboard.routes.js b/ui/src/app/dashboard/dashboard.routes.js index 52527dbd73..81d7a029d7 100644 --- a/ui/src/app/dashboard/dashboard.routes.js +++ b/ui/src/app/dashboard/dashboard.routes.js @@ -124,4 +124,25 @@ export default function DashboardRoutes($stateProvider) { label: '{"icon": "dashboard", "label": "customer.dashboard"}' } }) + .state('home.edges.dashboards', { + url: '/:edgeId/dashboards', + params: {'topIndex': 0}, + module: 'private', + auth: ['TENANT_ADMIN'], + views: { + "content@home": { + templateUrl: dashboardsTemplate, + controllerAs: 'vm', + controller: 'DashboardsController' + } + }, + data: { + dashboardsType: 'edge', + searchEnabled: true, + pageTitle: 'edge.dashboards' + }, + ncyBreadcrumb: { + label: '{"icon": "dashboard", "label": "{{ vm.edgeDashboardsTitle }}", "translate": "false"}' + } + }) } diff --git a/ui/src/app/dashboard/dashboards.controller.js b/ui/src/app/dashboard/dashboards.controller.js index 7239c24c71..8f2c80a2c5 100644 --- a/ui/src/app/dashboard/dashboards.controller.js +++ b/ui/src/app/dashboard/dashboards.controller.js @@ -21,6 +21,7 @@ import addDashboardsToCustomerTemplate from './add-dashboards-to-customer.tpl.ht import makeDashboardPublicDialogTemplate from './make-dashboard-public-dialog.tpl.html'; import manageAssignedCustomersTemplate from './manage-assigned-customers.tpl.html'; import manageAssignedEdgesTemplate from './manage-assigned-edges.tpl.html'; +import addDashboardsToEdgeTemplate from './add-dashboards-to-edge.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ @@ -60,6 +61,7 @@ export function DashboardsController(userService, dashboardService, customerServ $state, $stateParams, $mdDialog, $document, $q, $translate) { var customerId = $stateParams.customerId; + var edgeId = $stateParams.edgeId; var dashboardActionsList = [ { @@ -215,7 +217,7 @@ export function DashboardsController(userService, dashboardService, customerServ }, name: function() { return $translate.instant('action.assign') }, details: function() { return $translate.instant('dashboard.manage-assigned-edges') }, - icon: "assignment", + icon: "wifi_tethering", isEnabled: function(dashboard) { return dashboard; } @@ -255,6 +257,32 @@ export function DashboardsController(userService, dashboardService, customerServ } ); + dashboardGroupActionsList.push( + { + onAction: function ($event, items) { + assignDashboardsToEdges($event, items); + }, + name: function() { return $translate.instant('dashboard.assign-dashboards') }, + details: function(selectedCount) { + return $translate.instant('dashboard.assign-dashboards-to-edge-text', {count: selectedCount}, "messageformat"); + }, + icon: "wifi_tethering" + } + ); + + dashboardGroupActionsList.push( + { + onAction: function ($event, items) { + unassignDashboardsFromEdges($event, items); + }, + name: function() { return $translate.instant('dashboard.unassign-dashboards') }, + details: function(selectedCount) { + return $translate.instant('dashboard.unassign-dashboards-from-edge-action-text', {count: selectedCount}, "messageformat"); + }, + icon: "portable_wifi_off" + } + ); + dashboardGroupActionsList.push( { onAction: function ($event, items) { @@ -386,6 +414,60 @@ export function DashboardsController(userService, dashboardService, customerServ } else if (vm.dashboardsScope === 'customer_user') { vm.dashboardGridConfig.addItemAction = {}; } + } else if (vm.dashboardsScope === 'edge') { + fetchDashboardsFunction = function (pageLink) { + return dashboardService.getEdgeDashboards(edgeId, pageLink); + }; + deleteDashboardFunction = function (dashboardId) { + return dashboardService.unassignDashboardFromEdge(edgeId, dashboardId); + }; + refreshDashboardsParamsFunction = function () { + return {"edgeId": edgeId, "topIndex": vm.topIndex}; + }; + + dashboardActionsList.push( + { + onAction: function ($event, item) { + exportDashboard($event, item); + }, + name: function() { $translate.instant('action.export') }, + details: function() { return $translate.instant('dashboard.export') }, + icon: "file_download" + } + ); + + dashboardActionsList.push( + { + onAction: function ($event, item) { + unassignFromEdge($event, item, edgeId); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('dashboard.unassign-from-edge') }, + icon: "assignment_return" + } + ); + + dashboardGroupActionsList.push( + { + onAction: function ($event, items) { + unassignDashboardsFromEdge($event, items, edgeId); + }, + name: function() { return $translate.instant('dashboard.unassign-dashboards') }, + details: function(selectedCount) { + return $translate.instant('dashboard.unassign-dashboards-from-edge-action-title', {count: selectedCount}, "messageformat"); + }, + icon: "assignment_return" + } + ); + + vm.dashboardGridConfig.addItemAction = { + onAction: function ($event) { + addDashboardsToEdge($event); + }, + name: function() { return $translate.instant('dashboard.assign-dashboards') }, + details: function() { return $translate.instant('dashboard.assign-new-dashboard') }, + icon: "add" + }; } vm.dashboardGridConfig.refreshParamsFunc = refreshDashboardsParamsFunction; @@ -628,21 +710,40 @@ export function DashboardsController(userService, dashboardService, customerServ showManageAssignedEdgesDialog($event, [dashboard.id.id], 'manage', dashboard.assignedEdgesIds); } - // function assignDashboardsToEdges($event, items) { - // var dashboardIds = []; - // for (var id in items.selections) { - // dashboardIds.push(id); - // } - // showManageAssignedEdgesDialog($event, dashboardIds, 'assign'); - // } - // - // function unassignDashboardsFromEdges($event, items) { - // var dashboardIds = []; - // for (var id in items.selections) { - // dashboardIds.push(id); - // } - // showManageAssignedEdgesDialog($event, dashboardIds, 'unassign'); - // } + function assignDashboardsToEdges($event, items) { + var dashboardIds = []; + for (var id in items.selections) { + dashboardIds.push(id); + } + showManageAssignedEdgesDialog($event, dashboardIds, 'assign'); + } + + function unassignDashboardsFromEdges($event, items) { + var dashboardIds = []; + for (var id in items.selections) { + dashboardIds.push(id); + } + showManageAssignedEdgesDialog($event, dashboardIds, 'unassign'); + } + + function unassignDashboardsFromEdge($event, items, edgeId) { + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title($translate.instant('dashboard.unassign-dashboards-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('dashboard.unassign-dashboards-from-edge-text')) + .ariaLabel($translate.instant('dashboard.unassign-dashboards')) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + var tasks = []; + for (var id in items.selections) { + tasks.push(dashboardService.unassignDashboardFromEdge(edgeId, id)); + } + $q.all(tasks).then(function () { + vm.grid.refreshList(); + }); + }); + } function showManageAssignedEdgesDialog($event, dashboardIds, actionType, assignedEdges) { if ($event) { @@ -661,4 +762,61 @@ export function DashboardsController(userService, dashboardService, customerServ }, function () { }); } + + function addDashboardsToEdge($event) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + dashboardService.getTenantDashboards({limit: pageSize, textSearch: ''}).then( + function success(_dashboards) { + var dashboards = { + pageSize: pageSize, + data: _dashboards.data, + nextPageLink: _dashboards.nextPageLink, + selections: {}, + selectedCount: 0, + hasNext: _dashboards.hasNext, + pending: false + }; + if (dashboards.hasNext) { + dashboards.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AddDashboardsToEdgeController', + controllerAs: 'vm', + templateUrl: addDashboardsToEdgeTemplate, + locals: {edgeId: edgeId, dashboards: dashboards}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function unassignFromEdge($event, dashboard, edgeId) { + if ($event) { + $event.stopPropagation(); + } + var title = $translate.instant('dashboard.unassign-dashboard-title', {dashboardTitle: dashboard.title}); + var content = $translate.instant('dashboard.unassign-dashboard-from-edge-text'); + var label = $translate.instant('dashboard.unassign-dashboard'); + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title(title) + .htmlContent(content) + .ariaLabel(label) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + dashboardService.unassignDashboardFromEdge(edgeId, dashboard.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } } diff --git a/ui/src/app/dashboard/index.js b/ui/src/app/dashboard/index.js index e01924fdca..1d85abaf11 100644 --- a/ui/src/app/dashboard/index.js +++ b/ui/src/app/dashboard/index.js @@ -47,6 +47,7 @@ import AddWidgetController from './add-widget.controller'; import DashboardDirective from './dashboard.directive'; import EditWidgetDirective from './edit-widget.directive'; import DashboardToolbar from './dashboard-toolbar.directive'; +import AddDashboardsToEdgeController from './add-dashboards-to-edge.controller'; export default angular.module('thingsboard.dashboard', [ uiRouter, @@ -79,6 +80,7 @@ export default angular.module('thingsboard.dashboard', [ .controller('ManageAssignedCustomersController', ManageAssignedCustomersController) .controller('ManageAssignedEdgesController', ManageAssignedEdgesController) .controller('AddWidgetController', AddWidgetController) + .controller('AddDashboardsToEdgeController', AddDashboardsToEdgeController) .directive('tbDashboardDetails', DashboardDirective) .directive('tbEditWidget', EditWidgetDirective) .directive('tbDashboardToolbar', DashboardToolbar) diff --git a/ui/src/app/edge/edge.controller.js b/ui/src/app/edge/edge.controller.js index e157f9539b..a9bef21ee0 100644 --- a/ui/src/app/edge/edge.controller.js +++ b/ui/src/app/edge/edge.controller.js @@ -216,6 +216,19 @@ export function EdgeController($rootScope, userService, edgeService, customerSer } }); + edgeActionsList.push( + { + onAction: function ($event, item) { + openEdgeDashboards($event, item); + }, + name: function() { return $translate.instant('dashboard.dashboards') }, + details: function() { + return $translate.instant('edge.manage-edge-dashboards'); + }, + icon: "dashboard" + } + ); + edgeActionsList.push( { onAction: function ($event, item) { @@ -240,6 +253,8 @@ export function EdgeController($rootScope, userService, edgeService, customerSer } ); + + edgeGroupActionsList.push( { onAction: function ($event) { @@ -531,4 +546,18 @@ export function EdgeController($rootScope, userService, edgeService, customerSer }); }); } + + function openEdgeDashboards($event, edge) { + if ($event) { + $event.stopPropagation(); + } + $state.go('home.edges.dashboards', {edgeId: edge.id.id}); + } + + // function openEdgeRuleChains($event, edge) { + // if ($event) { + // $event.stopPropagation(); + // } + // $state.go('home.edges.rule-chains', {edgeId: edge.id.id}); + // } } diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index a2f5e296af..1e17728095 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -569,7 +569,20 @@ "hide-details": "Hide details", "select-state": "Select target state", "state-controller": "State controller", - "manage-assigned-edges": "Manage assigned edges" + "manage-assigned-edges": "Manage assigned edges", + "unassign-dashboard-from-edge-text": "After the confirmation the dashboard will be unassigned and won't be accessible by the edge.", + "assigned-edges": "Assigned edges", + "unassign-from-edge": "Unassign from edge", + "unassign-dashboards-from-edge-action-title": "Unassign { count, plural, 1 {1 dashboard} other {# dashboards} } from edge", + "unassign-dashboards-from-edge-text": "After the confirmation all selected dashboards will be unassigned and won't be accessible by the edge.", + "assign-dashboard-to-edge": "Assign Dashboard(s) To Edge", + "assign-dashboard-to-edge-text": "Please select the dashboards to assign to the edge", + "assign-dashboards-to-edge-text": "Assign { count, plural, 1 {1 dashboard} other {# dashboards} } to edges", + "unassign-dashboards-from-edge-action-text": "Unassign { count, plural, 1 {1 dashboard} other {# dashboards} } from edges", + "assign-to-edges": "Assign Dashboard(s) To Edges", + "assign-to-edges-text": "Please select the edges to assign the dashboard(s)", + "unassign-from-edges": "Unassign Dashboard(s) From Edges", + "unassign-from-edges-text": "Please select the edges to unassign from the dashboard(s)" }, "datakey": { "settings": "Settings", @@ -759,7 +772,10 @@ "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.", "import": "Import edge", "label": "Label", - "assign-new-edge": "Assign new edge" + "assign-new-edge": "Assign new edge", + "manage-edge-dashboards": "Manage edge dashboards", + "unassign-from-edge": "Unassign from edge", + "dashboards": "Edge Dashboards" }, "error": { "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", diff --git a/ui/src/app/services/menu.service.js b/ui/src/app/services/menu.service.js index 09bdea44c5..4a3c43b75a 100644 --- a/ui/src/app/services/menu.service.js +++ b/ui/src/app/services/menu.service.js @@ -188,7 +188,7 @@ function Menu(userService, $state, $rootScope) { name: 'edge.edges', type: 'link', state: 'home.edges', - icon: 'toys' + icon: 'router' }, { name: 'widget.widget-library', @@ -265,7 +265,7 @@ function Menu(userService, $state, $rootScope) { places: [ { name: 'edge.edges', - icon: 'toys', + icon: 'router', state: 'home.edges' } ] @@ -326,7 +326,7 @@ function Menu(userService, $state, $rootScope) { name: 'edge.edges', type: 'link', state: 'home.edges', - icon: 'toys' + icon: 'router' }, { name: 'dashboard.dashboards', @@ -371,7 +371,7 @@ function Menu(userService, $state, $rootScope) { places: [ { name: 'edge.edges', - icon: 'toys', + icon: 'router', state: 'home.edges' } ]