Commit 6be5f9aa4d315facb772f681c95f05ff3546c698
1 parent
f35c1156
Manage edge dashboards functionality
Showing
15 changed files
with
603 additions
and
28 deletions
... | ... | @@ -689,4 +689,26 @@ public class DashboardController extends BaseController { |
689 | 689 | throw handleException(e); |
690 | 690 | } |
691 | 691 | } |
692 | + | |
693 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
694 | + @RequestMapping(value = "/edge/{edgeId}/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
695 | + @ResponseBody | |
696 | + public TimePageData<DashboardInfo> getEdgeDashboards( | |
697 | + @PathVariable("edgeId") String strEdgeId, | |
698 | + @RequestParam int limit, | |
699 | + @RequestParam(required = false) Long startTime, | |
700 | + @RequestParam(required = false) Long endTime, | |
701 | + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
702 | + @RequestParam(required = false) String offset) throws ThingsboardException { | |
703 | + checkParameter("edgeId", strEdgeId); | |
704 | + try { | |
705 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
706 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | |
707 | + checkEdgeId(edgeId, Operation.READ); | |
708 | + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
709 | + return checkNotNull(dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get()); | |
710 | + } catch (Exception e) { | |
711 | + throw handleException(e); | |
712 | + } | |
713 | + } | |
692 | 714 | } | ... | ... |
... | ... | @@ -62,4 +62,6 @@ public interface DashboardService { |
62 | 62 | void unassignEdgeDashboards(TenantId tenantId, EdgeId edgeId); |
63 | 63 | |
64 | 64 | void updateEdgeDashboards(TenantId tenantId, EdgeId edgeId); |
65 | + | |
66 | + ListenableFuture<TimePageData<DashboardInfo>> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); | |
65 | 67 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2019 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 | + */ | |
1 | 16 | package org.thingsboard.server.common.data; |
2 | 17 | |
3 | 18 | import lombok.AllArgsConstructor; |
4 | -import lombok.Data; | |
5 | -import lombok.NoArgsConstructor; | |
19 | +import lombok.Getter; | |
20 | +import lombok.Setter; | |
6 | 21 | import org.thingsboard.server.common.data.id.EdgeId; |
7 | 22 | |
8 | -@Data | |
9 | -@NoArgsConstructor | |
10 | 23 | @AllArgsConstructor |
11 | 24 | public class ShortEdgeInfo { |
12 | 25 | |
26 | + @Getter @Setter | |
13 | 27 | private EdgeId edgeId; |
28 | + | |
29 | + @Getter @Setter | |
14 | 30 | private String title; |
31 | + | |
32 | + @Override | |
33 | + public boolean equals(Object o) { | |
34 | + if (this == o) return true; | |
35 | + if (o == null || getClass() != o.getClass()) return false; | |
36 | + | |
37 | + ShortEdgeInfo that = (ShortEdgeInfo) o; | |
38 | + | |
39 | + return edgeId.equals(that.edgeId); | |
40 | + } | |
41 | + | |
42 | + @Override | |
43 | + public int hashCode() { | |
44 | + return edgeId.hashCode(); | |
45 | + } | |
15 | 46 | } | ... | ... |
... | ... | @@ -299,6 +299,23 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb |
299 | 299 | new EdgeDashboardsUpdater(edge).removeEntities(tenantId, edge); |
300 | 300 | } |
301 | 301 | |
302 | + @Override | |
303 | + public ListenableFuture<TimePageData<DashboardInfo>> findDashboardsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) { | |
304 | + log.trace("Executing findDashboardsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); | |
305 | + Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | |
306 | + Validator.validateId(edgeId, "Incorrect customerId " + edgeId); | |
307 | + Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); | |
308 | + ListenableFuture<List<DashboardInfo>> dashboards = dashboardInfoDao.findDashboardsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); | |
309 | + | |
310 | + return Futures.transform(dashboards, new Function<List<DashboardInfo>, TimePageData<DashboardInfo>>() { | |
311 | + @Nullable | |
312 | + @Override | |
313 | + public TimePageData<DashboardInfo> apply(@Nullable List<DashboardInfo> dashboards) { | |
314 | + return new TimePageData<>(dashboards, pageLink); | |
315 | + } | |
316 | + }); | |
317 | + } | |
318 | + | |
302 | 319 | private Dashboard updateAssignedEdge(TenantId tenantId, DashboardId dashboardId, Edge edge) { |
303 | 320 | Dashboard dashboard = findDashboardById(tenantId, dashboardId); |
304 | 321 | if (dashboard.updateAssignedEdge(edge)) { | ... | ... |
... | ... | @@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; |
25 | 25 | import org.springframework.util.StringUtils; |
26 | 26 | import org.thingsboard.server.common.data.DashboardInfo; |
27 | 27 | import org.thingsboard.server.common.data.ShortCustomerInfo; |
28 | +import org.thingsboard.server.common.data.ShortEdgeInfo; | |
28 | 29 | import org.thingsboard.server.common.data.id.DashboardId; |
29 | 30 | import org.thingsboard.server.common.data.id.TenantId; |
30 | 31 | import org.thingsboard.server.dao.model.BaseSqlEntity; |
... | ... | @@ -47,6 +48,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements |
47 | 48 | private static final ObjectMapper objectMapper = new ObjectMapper(); |
48 | 49 | private static final JavaType assignedCustomersType = |
49 | 50 | objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); |
51 | + private static final JavaType assignedEdgesType = | |
52 | + objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortEdgeInfo.class); | |
50 | 53 | |
51 | 54 | @Column(name = ModelConstants.DASHBOARD_TENANT_ID_PROPERTY) |
52 | 55 | private String tenantId; |
... | ... | @@ -60,6 +63,9 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements |
60 | 63 | @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) |
61 | 64 | private String assignedCustomers; |
62 | 65 | |
66 | + @Column(name = ModelConstants.DASHBOARD_ASSIGNED_EDGES_PROPERTY) | |
67 | + private String assignedEdges; | |
68 | + | |
63 | 69 | public DashboardInfoEntity() { |
64 | 70 | super(); |
65 | 71 | } |
... | ... | @@ -79,6 +85,13 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements |
79 | 85 | log.error("Unable to serialize assigned customers to string!", e); |
80 | 86 | } |
81 | 87 | } |
88 | + if (dashboardInfo.getAssignedEdges() != null) { | |
89 | + try { | |
90 | + this.assignedEdges = objectMapper.writeValueAsString(dashboardInfo.getAssignedEdges()); | |
91 | + } catch (JsonProcessingException e) { | |
92 | + log.error("Unable to serialize assigned edges to string!", e); | |
93 | + } | |
94 | + } | |
82 | 95 | } |
83 | 96 | |
84 | 97 | @Override |
... | ... | @@ -110,6 +123,13 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements |
110 | 123 | log.warn("Unable to parse assigned customers!", e); |
111 | 124 | } |
112 | 125 | } |
126 | + if (!StringUtils.isEmpty(assignedEdges)) { | |
127 | + try { | |
128 | + dashboardInfo.setAssignedEdges(objectMapper.readValue(assignedEdges, assignedEdgesType)); | |
129 | + } catch (IOException e) { | |
130 | + log.warn("Unable to parse assigned edges!", e); | |
131 | + } | |
132 | + } | |
113 | 133 | return dashboardInfo; |
114 | 134 | } |
115 | 135 | ... | ... |
... | ... | @@ -45,7 +45,10 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { |
45 | 45 | getPublicDashboardLink: getPublicDashboardLink, |
46 | 46 | updateDashboardEdges: updateDashboardEdges, |
47 | 47 | addDashboardEdges: addDashboardEdges, |
48 | - removeDashboardEdges: removeDashboardEdges | |
48 | + removeDashboardEdges: removeDashboardEdges, | |
49 | + getEdgeDashboards: getEdgeDashboards, | |
50 | + assignDashboardToEdge: assignDashboardToEdge, | |
51 | + unassignDashboardFromEdge: unassignDashboardFromEdge | |
49 | 52 | } |
50 | 53 | |
51 | 54 | return service; |
... | ... | @@ -285,6 +288,20 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { |
285 | 288 | } |
286 | 289 | dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); |
287 | 290 | } |
291 | + dashboard.assignedEdgesIds = []; | |
292 | + if (dashboard.assignedEdges && dashboard.assignedEdges.length) { | |
293 | + // var assignedEdgesTitles = []; | |
294 | + for (var j = 0; j < dashboard.assignedEdges.length; j++) { | |
295 | + var assignedEdge = dashboard.assignedEdges[j]; | |
296 | + dashboard.assignedEdgesIds.push(assignedEdge.edgeId.id); | |
297 | + // if (assignedCustomer.public) { | |
298 | + // dashboard.publicCustomerId = assignedCustomer.customerId.id; | |
299 | + // } else { | |
300 | + // assignedCustomersTitles.push(assignedCustomer.title); | |
301 | + // } | |
302 | + } | |
303 | + // dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); | |
304 | + } | |
288 | 305 | return dashboard; |
289 | 306 | } |
290 | 307 | |
... | ... | @@ -292,6 +309,7 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { |
292 | 309 | delete dashboard.publicCustomerId; |
293 | 310 | delete dashboard.assignedCustomersText; |
294 | 311 | delete dashboard.assignedCustomersIds; |
312 | + delete dashboard.assignedEdgeIds; | |
295 | 313 | return dashboard; |
296 | 314 | } |
297 | 315 | |
... | ... | @@ -327,4 +345,44 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { |
327 | 345 | }); |
328 | 346 | return deferred.promise; |
329 | 347 | } |
348 | + | |
349 | + function getEdgeDashboards(edgeId, pageLink, config) { | |
350 | + var deferred = $q.defer(); | |
351 | + var url = '/api/edge/' + edgeId + '/dashboards?limit=' + pageLink.limit; | |
352 | + if (angular.isDefined(pageLink.idOffset)) { | |
353 | + url += '&offset=' + pageLink.idOffset; | |
354 | + } | |
355 | + $http.get(url, config).then(function success(response) { | |
356 | + response.data = prepareDashboards(response.data); | |
357 | + if (pageLink.textSearch) { | |
358 | + response.data.data = $filter('filter')(response.data.data, {title: pageLink.textSearch}); | |
359 | + } | |
360 | + deferred.resolve(response.data); | |
361 | + }, function fail() { | |
362 | + deferred.reject(); | |
363 | + }); | |
364 | + return deferred.promise; | |
365 | + } | |
366 | + | |
367 | + function assignDashboardToEdge(edgeId, dashboardId) { | |
368 | + var deferred = $q.defer(); | |
369 | + var url = '/api/edge/' + edgeId + '/dashboard/' + dashboardId; | |
370 | + $http.post(url, null).then(function success(response) { | |
371 | + deferred.resolve(prepareDashboard(response.data)); | |
372 | + }, function fail() { | |
373 | + deferred.reject(); | |
374 | + }); | |
375 | + return deferred.promise; | |
376 | + } | |
377 | + | |
378 | + function unassignDashboardFromEdge(edgeId, dashboardId) { | |
379 | + var deferred = $q.defer(); | |
380 | + var url = '/api/edge/' + edgeId + '/dashboard/' + dashboardId; | |
381 | + $http.delete(url).then(function success(response) { | |
382 | + deferred.resolve(prepareDashboard(response.data)); | |
383 | + }, function fail() { | |
384 | + deferred.reject(); | |
385 | + }); | |
386 | + return deferred.promise; | |
387 | + } | |
330 | 388 | } | ... | ... |
... | ... | @@ -89,7 +89,7 @@ export default function CustomerController(customerService, $state, $stateParams |
89 | 89 | return $translate.instant('customer.manage-customer-edges') |
90 | 90 | } |
91 | 91 | }, |
92 | - icon: "toys" | |
92 | + icon: "wifi_tethering" | |
93 | 93 | }, |
94 | 94 | { |
95 | 95 | onAction: function ($event, item) { | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2019 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 | +/*@ngInject*/ | |
17 | +export default function AddDashboardsToEdgeController(dashboardService, $mdDialog, $q, edgeId, dashboards) { | |
18 | + | |
19 | + var vm = this; | |
20 | + | |
21 | + vm.dashboards = dashboards; | |
22 | + vm.searchText = ''; | |
23 | + | |
24 | + vm.assign = assign; | |
25 | + vm.cancel = cancel; | |
26 | + vm.hasData = hasData; | |
27 | + vm.noData = noData; | |
28 | + vm.searchDashboardTextUpdated = searchDashboardTextUpdated; | |
29 | + vm.toggleDashboardSelection = toggleDashboardSelection; | |
30 | + | |
31 | + vm.theDashboards = { | |
32 | + getItemAtIndex: function (index) { | |
33 | + if (index > vm.dashboards.data.length) { | |
34 | + vm.theDashboards.fetchMoreItems_(index); | |
35 | + return null; | |
36 | + } | |
37 | + var item = vm.dashboards.data[index]; | |
38 | + if (item) { | |
39 | + item.indexNumber = index + 1; | |
40 | + } | |
41 | + return item; | |
42 | + }, | |
43 | + | |
44 | + getLength: function () { | |
45 | + if (vm.dashboards.hasNext) { | |
46 | + return vm.dashboards.data.length + vm.dashboards.nextPageLink.limit; | |
47 | + } else { | |
48 | + return vm.dashboards.data.length; | |
49 | + } | |
50 | + }, | |
51 | + | |
52 | + fetchMoreItems_: function () { | |
53 | + if (vm.dashboards.hasNext && !vm.dashboards.pending) { | |
54 | + vm.dashboards.pending = true; | |
55 | + dashboardService.getTenantDashboards(vm.dashboards.nextPageLink).then( | |
56 | + function success(dashboards) { | |
57 | + vm.dashboards.data = vm.dashboards.data.concat(dashboards.data); | |
58 | + vm.dashboards.nextPageLink = dashboards.nextPageLink; | |
59 | + vm.dashboards.hasNext = dashboards.hasNext; | |
60 | + if (vm.dashboards.hasNext) { | |
61 | + vm.dashboards.nextPageLink.limit = vm.dashboards.pageSize; | |
62 | + } | |
63 | + vm.dashboards.pending = false; | |
64 | + }, | |
65 | + function fail() { | |
66 | + vm.dashboards.hasNext = false; | |
67 | + vm.dashboards.pending = false; | |
68 | + }); | |
69 | + } | |
70 | + } | |
71 | + } | |
72 | + | |
73 | + function cancel () { | |
74 | + $mdDialog.cancel(); | |
75 | + } | |
76 | + | |
77 | + function assign () { | |
78 | + var tasks = []; | |
79 | + for (var dashboardId in vm.dashboards.selections) { | |
80 | + tasks.push(dashboardService.assignDashboardToEdge(edgeId, dashboardId)); | |
81 | + } | |
82 | + $q.all(tasks).then(function () { | |
83 | + $mdDialog.hide(); | |
84 | + }); | |
85 | + } | |
86 | + | |
87 | + function noData () { | |
88 | + return vm.dashboards.data.length == 0 && !vm.dashboards.hasNext; | |
89 | + } | |
90 | + | |
91 | + function hasData () { | |
92 | + return vm.dashboards.data.length > 0; | |
93 | + } | |
94 | + | |
95 | + function toggleDashboardSelection ($event, dashboard) { | |
96 | + $event.stopPropagation(); | |
97 | + var selected = angular.isDefined(dashboard.selected) && dashboard.selected; | |
98 | + dashboard.selected = !selected; | |
99 | + if (dashboard.selected) { | |
100 | + vm.dashboards.selections[dashboard.id.id] = true; | |
101 | + vm.dashboards.selectedCount++; | |
102 | + } else { | |
103 | + delete vm.dashboards.selections[dashboard.id.id]; | |
104 | + vm.dashboards.selectedCount--; | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + function searchDashboardTextUpdated () { | |
109 | + vm.dashboards = { | |
110 | + pageSize: vm.dashboards.pageSize, | |
111 | + data: [], | |
112 | + nextPageLink: { | |
113 | + limit: vm.dashboards.pageSize, | |
114 | + textSearch: vm.searchText | |
115 | + }, | |
116 | + selections: {}, | |
117 | + selectedCount: 0, | |
118 | + hasNext: true, | |
119 | + pending: false | |
120 | + }; | |
121 | + } | |
122 | +} | |
\ No newline at end of file | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2019 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 | +<md-dialog aria-label="{{ 'dashboard.assign-dashboard-to-edge' | translate }}"> | |
19 | + <form name="theForm" ng-submit="vm.assign()"> | |
20 | + <md-toolbar> | |
21 | + <div class="md-toolbar-tools"> | |
22 | + <h2 translate>dashboard.assign-dashboard-to-edge</h2> | |
23 | + <span flex></span> | |
24 | + <md-button class="md-icon-button" ng-click="vm.cancel()"> | |
25 | + <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> | |
26 | + </md-button> | |
27 | + </div> | |
28 | + </md-toolbar> | |
29 | + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> | |
30 | + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> | |
31 | + <md-dialog-content> | |
32 | + <div class="md-dialog-content"> | |
33 | + <fieldset> | |
34 | + <span translate>dashboard.assign-dashboard-to-edge-text</span> | |
35 | + <md-input-container class="md-block" style='margin-bottom: 0px;'> | |
36 | + <label> </label> | |
37 | + <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons"> | |
38 | + search | |
39 | + </md-icon> | |
40 | + <input id="dashboard-search" autofocus ng-model="vm.searchText" | |
41 | + ng-change="vm.searchDashboardTextUpdated()" | |
42 | + placeholder="{{ 'common.enter-search' | translate }}"/> | |
43 | + </md-input-container> | |
44 | + <div style='min-height: 150px;'> | |
45 | + <span translate layout-align="center center" | |
46 | + style="text-transform: uppercase; display: flex; height: 150px;" | |
47 | + class="md-subhead" | |
48 | + ng-show="vm.noData()">dashboard.no-dashboards-text</span> | |
49 | + <md-virtual-repeat-container ng-show="vm.hasData()" | |
50 | + tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex | |
51 | + style='min-height: 150px; width: 100%;'> | |
52 | + <md-list> | |
53 | + <md-list-item md-virtual-repeat="dashboard in vm.theDashboards" md-on-demand | |
54 | + class="repeated-item" flex> | |
55 | + <md-checkbox ng-click="vm.toggleDashboardSelection($event, dashboard)" | |
56 | + aria-label="{{ 'item.selected' | translate }}" | |
57 | + ng-checked="dashboard.selected"></md-checkbox> | |
58 | + <span> {{ dashboard.title }} </span> | |
59 | + </md-list-item> | |
60 | + </md-list> | |
61 | + </md-virtual-repeat-container> | |
62 | + </div> | |
63 | + </fieldset> | |
64 | + </div> | |
65 | + </md-dialog-content> | |
66 | + <md-dialog-actions layout="row"> | |
67 | + <span flex></span> | |
68 | + <md-button ng-disabled="$root.loading || vm.dashboards.selectedCount == 0" type="submit" | |
69 | + class="md-raised md-primary"> | |
70 | + {{ 'action.assign' | translate }} | |
71 | + </md-button> | |
72 | + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | | |
73 | + translate }} | |
74 | + </md-button> | |
75 | + </md-dialog-actions> | |
76 | + </form> | |
77 | +</md-dialog> | |
\ No newline at end of file | ... | ... |
... | ... | @@ -124,4 +124,25 @@ export default function DashboardRoutes($stateProvider) { |
124 | 124 | label: '{"icon": "dashboard", "label": "customer.dashboard"}' |
125 | 125 | } |
126 | 126 | }) |
127 | + .state('home.edges.dashboards', { | |
128 | + url: '/:edgeId/dashboards', | |
129 | + params: {'topIndex': 0}, | |
130 | + module: 'private', | |
131 | + auth: ['TENANT_ADMIN'], | |
132 | + views: { | |
133 | + "content@home": { | |
134 | + templateUrl: dashboardsTemplate, | |
135 | + controllerAs: 'vm', | |
136 | + controller: 'DashboardsController' | |
137 | + } | |
138 | + }, | |
139 | + data: { | |
140 | + dashboardsType: 'edge', | |
141 | + searchEnabled: true, | |
142 | + pageTitle: 'edge.dashboards' | |
143 | + }, | |
144 | + ncyBreadcrumb: { | |
145 | + label: '{"icon": "dashboard", "label": "{{ vm.edgeDashboardsTitle }}", "translate": "false"}' | |
146 | + } | |
147 | + }) | |
127 | 148 | } | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import addDashboardsToCustomerTemplate from './add-dashboards-to-customer.tpl.ht |
21 | 21 | import makeDashboardPublicDialogTemplate from './make-dashboard-public-dialog.tpl.html'; |
22 | 22 | import manageAssignedCustomersTemplate from './manage-assigned-customers.tpl.html'; |
23 | 23 | import manageAssignedEdgesTemplate from './manage-assigned-edges.tpl.html'; |
24 | +import addDashboardsToEdgeTemplate from './add-dashboards-to-edge.tpl.html'; | |
24 | 25 | |
25 | 26 | /* eslint-enable import/no-unresolved, import/default */ |
26 | 27 | |
... | ... | @@ -60,6 +61,7 @@ export function DashboardsController(userService, dashboardService, customerServ |
60 | 61 | $state, $stateParams, $mdDialog, $document, $q, $translate) { |
61 | 62 | |
62 | 63 | var customerId = $stateParams.customerId; |
64 | + var edgeId = $stateParams.edgeId; | |
63 | 65 | |
64 | 66 | var dashboardActionsList = [ |
65 | 67 | { |
... | ... | @@ -215,7 +217,7 @@ export function DashboardsController(userService, dashboardService, customerServ |
215 | 217 | }, |
216 | 218 | name: function() { return $translate.instant('action.assign') }, |
217 | 219 | details: function() { return $translate.instant('dashboard.manage-assigned-edges') }, |
218 | - icon: "assignment", | |
220 | + icon: "wifi_tethering", | |
219 | 221 | isEnabled: function(dashboard) { |
220 | 222 | return dashboard; |
221 | 223 | } |
... | ... | @@ -256,6 +258,32 @@ export function DashboardsController(userService, dashboardService, customerServ |
256 | 258 | ); |
257 | 259 | |
258 | 260 | dashboardGroupActionsList.push( |
261 | + { | |
262 | + onAction: function ($event, items) { | |
263 | + assignDashboardsToEdges($event, items); | |
264 | + }, | |
265 | + name: function() { return $translate.instant('dashboard.assign-dashboards') }, | |
266 | + details: function(selectedCount) { | |
267 | + return $translate.instant('dashboard.assign-dashboards-to-edge-text', {count: selectedCount}, "messageformat"); | |
268 | + }, | |
269 | + icon: "wifi_tethering" | |
270 | + } | |
271 | + ); | |
272 | + | |
273 | + dashboardGroupActionsList.push( | |
274 | + { | |
275 | + onAction: function ($event, items) { | |
276 | + unassignDashboardsFromEdges($event, items); | |
277 | + }, | |
278 | + name: function() { return $translate.instant('dashboard.unassign-dashboards') }, | |
279 | + details: function(selectedCount) { | |
280 | + return $translate.instant('dashboard.unassign-dashboards-from-edge-action-text', {count: selectedCount}, "messageformat"); | |
281 | + }, | |
282 | + icon: "portable_wifi_off" | |
283 | + } | |
284 | + ); | |
285 | + | |
286 | + dashboardGroupActionsList.push( | |
259 | 287 | { |
260 | 288 | onAction: function ($event, items) { |
261 | 289 | assignDashboardsToCustomers($event, items); |
... | ... | @@ -386,6 +414,60 @@ export function DashboardsController(userService, dashboardService, customerServ |
386 | 414 | } else if (vm.dashboardsScope === 'customer_user') { |
387 | 415 | vm.dashboardGridConfig.addItemAction = {}; |
388 | 416 | } |
417 | + } else if (vm.dashboardsScope === 'edge') { | |
418 | + fetchDashboardsFunction = function (pageLink) { | |
419 | + return dashboardService.getEdgeDashboards(edgeId, pageLink); | |
420 | + }; | |
421 | + deleteDashboardFunction = function (dashboardId) { | |
422 | + return dashboardService.unassignDashboardFromEdge(edgeId, dashboardId); | |
423 | + }; | |
424 | + refreshDashboardsParamsFunction = function () { | |
425 | + return {"edgeId": edgeId, "topIndex": vm.topIndex}; | |
426 | + }; | |
427 | + | |
428 | + dashboardActionsList.push( | |
429 | + { | |
430 | + onAction: function ($event, item) { | |
431 | + exportDashboard($event, item); | |
432 | + }, | |
433 | + name: function() { $translate.instant('action.export') }, | |
434 | + details: function() { return $translate.instant('dashboard.export') }, | |
435 | + icon: "file_download" | |
436 | + } | |
437 | + ); | |
438 | + | |
439 | + dashboardActionsList.push( | |
440 | + { | |
441 | + onAction: function ($event, item) { | |
442 | + unassignFromEdge($event, item, edgeId); | |
443 | + }, | |
444 | + name: function() { return $translate.instant('action.unassign') }, | |
445 | + details: function() { return $translate.instant('dashboard.unassign-from-edge') }, | |
446 | + icon: "assignment_return" | |
447 | + } | |
448 | + ); | |
449 | + | |
450 | + dashboardGroupActionsList.push( | |
451 | + { | |
452 | + onAction: function ($event, items) { | |
453 | + unassignDashboardsFromEdge($event, items, edgeId); | |
454 | + }, | |
455 | + name: function() { return $translate.instant('dashboard.unassign-dashboards') }, | |
456 | + details: function(selectedCount) { | |
457 | + return $translate.instant('dashboard.unassign-dashboards-from-edge-action-title', {count: selectedCount}, "messageformat"); | |
458 | + }, | |
459 | + icon: "assignment_return" | |
460 | + } | |
461 | + ); | |
462 | + | |
463 | + vm.dashboardGridConfig.addItemAction = { | |
464 | + onAction: function ($event) { | |
465 | + addDashboardsToEdge($event); | |
466 | + }, | |
467 | + name: function() { return $translate.instant('dashboard.assign-dashboards') }, | |
468 | + details: function() { return $translate.instant('dashboard.assign-new-dashboard') }, | |
469 | + icon: "add" | |
470 | + }; | |
389 | 471 | } |
390 | 472 | |
391 | 473 | vm.dashboardGridConfig.refreshParamsFunc = refreshDashboardsParamsFunction; |
... | ... | @@ -628,21 +710,40 @@ export function DashboardsController(userService, dashboardService, customerServ |
628 | 710 | showManageAssignedEdgesDialog($event, [dashboard.id.id], 'manage', dashboard.assignedEdgesIds); |
629 | 711 | } |
630 | 712 | |
631 | - // function assignDashboardsToEdges($event, items) { | |
632 | - // var dashboardIds = []; | |
633 | - // for (var id in items.selections) { | |
634 | - // dashboardIds.push(id); | |
635 | - // } | |
636 | - // showManageAssignedEdgesDialog($event, dashboardIds, 'assign'); | |
637 | - // } | |
638 | - // | |
639 | - // function unassignDashboardsFromEdges($event, items) { | |
640 | - // var dashboardIds = []; | |
641 | - // for (var id in items.selections) { | |
642 | - // dashboardIds.push(id); | |
643 | - // } | |
644 | - // showManageAssignedEdgesDialog($event, dashboardIds, 'unassign'); | |
645 | - // } | |
713 | + function assignDashboardsToEdges($event, items) { | |
714 | + var dashboardIds = []; | |
715 | + for (var id in items.selections) { | |
716 | + dashboardIds.push(id); | |
717 | + } | |
718 | + showManageAssignedEdgesDialog($event, dashboardIds, 'assign'); | |
719 | + } | |
720 | + | |
721 | + function unassignDashboardsFromEdges($event, items) { | |
722 | + var dashboardIds = []; | |
723 | + for (var id in items.selections) { | |
724 | + dashboardIds.push(id); | |
725 | + } | |
726 | + showManageAssignedEdgesDialog($event, dashboardIds, 'unassign'); | |
727 | + } | |
728 | + | |
729 | + function unassignDashboardsFromEdge($event, items, edgeId) { | |
730 | + var confirm = $mdDialog.confirm() | |
731 | + .targetEvent($event) | |
732 | + .title($translate.instant('dashboard.unassign-dashboards-title', {count: items.selectedCount}, 'messageformat')) | |
733 | + .htmlContent($translate.instant('dashboard.unassign-dashboards-from-edge-text')) | |
734 | + .ariaLabel($translate.instant('dashboard.unassign-dashboards')) | |
735 | + .cancel($translate.instant('action.no')) | |
736 | + .ok($translate.instant('action.yes')); | |
737 | + $mdDialog.show(confirm).then(function () { | |
738 | + var tasks = []; | |
739 | + for (var id in items.selections) { | |
740 | + tasks.push(dashboardService.unassignDashboardFromEdge(edgeId, id)); | |
741 | + } | |
742 | + $q.all(tasks).then(function () { | |
743 | + vm.grid.refreshList(); | |
744 | + }); | |
745 | + }); | |
746 | + } | |
646 | 747 | |
647 | 748 | function showManageAssignedEdgesDialog($event, dashboardIds, actionType, assignedEdges) { |
648 | 749 | if ($event) { |
... | ... | @@ -661,4 +762,61 @@ export function DashboardsController(userService, dashboardService, customerServ |
661 | 762 | }, function () { |
662 | 763 | }); |
663 | 764 | } |
765 | + | |
766 | + function addDashboardsToEdge($event) { | |
767 | + if ($event) { | |
768 | + $event.stopPropagation(); | |
769 | + } | |
770 | + var pageSize = 10; | |
771 | + dashboardService.getTenantDashboards({limit: pageSize, textSearch: ''}).then( | |
772 | + function success(_dashboards) { | |
773 | + var dashboards = { | |
774 | + pageSize: pageSize, | |
775 | + data: _dashboards.data, | |
776 | + nextPageLink: _dashboards.nextPageLink, | |
777 | + selections: {}, | |
778 | + selectedCount: 0, | |
779 | + hasNext: _dashboards.hasNext, | |
780 | + pending: false | |
781 | + }; | |
782 | + if (dashboards.hasNext) { | |
783 | + dashboards.nextPageLink.limit = pageSize; | |
784 | + } | |
785 | + $mdDialog.show({ | |
786 | + controller: 'AddDashboardsToEdgeController', | |
787 | + controllerAs: 'vm', | |
788 | + templateUrl: addDashboardsToEdgeTemplate, | |
789 | + locals: {edgeId: edgeId, dashboards: dashboards}, | |
790 | + parent: angular.element($document[0].body), | |
791 | + fullscreen: true, | |
792 | + targetEvent: $event | |
793 | + }).then(function () { | |
794 | + vm.grid.refreshList(); | |
795 | + }, function () { | |
796 | + }); | |
797 | + }, | |
798 | + function fail() { | |
799 | + }); | |
800 | + } | |
801 | + | |
802 | + function unassignFromEdge($event, dashboard, edgeId) { | |
803 | + if ($event) { | |
804 | + $event.stopPropagation(); | |
805 | + } | |
806 | + var title = $translate.instant('dashboard.unassign-dashboard-title', {dashboardTitle: dashboard.title}); | |
807 | + var content = $translate.instant('dashboard.unassign-dashboard-from-edge-text'); | |
808 | + var label = $translate.instant('dashboard.unassign-dashboard'); | |
809 | + var confirm = $mdDialog.confirm() | |
810 | + .targetEvent($event) | |
811 | + .title(title) | |
812 | + .htmlContent(content) | |
813 | + .ariaLabel(label) | |
814 | + .cancel($translate.instant('action.no')) | |
815 | + .ok($translate.instant('action.yes')); | |
816 | + $mdDialog.show(confirm).then(function () { | |
817 | + dashboardService.unassignDashboardFromEdge(edgeId, dashboard.id.id).then(function success() { | |
818 | + vm.grid.refreshList(); | |
819 | + }); | |
820 | + }); | |
821 | + } | |
664 | 822 | } | ... | ... |
... | ... | @@ -47,6 +47,7 @@ import AddWidgetController from './add-widget.controller'; |
47 | 47 | import DashboardDirective from './dashboard.directive'; |
48 | 48 | import EditWidgetDirective from './edit-widget.directive'; |
49 | 49 | import DashboardToolbar from './dashboard-toolbar.directive'; |
50 | +import AddDashboardsToEdgeController from './add-dashboards-to-edge.controller'; | |
50 | 51 | |
51 | 52 | export default angular.module('thingsboard.dashboard', [ |
52 | 53 | uiRouter, |
... | ... | @@ -79,6 +80,7 @@ export default angular.module('thingsboard.dashboard', [ |
79 | 80 | .controller('ManageAssignedCustomersController', ManageAssignedCustomersController) |
80 | 81 | .controller('ManageAssignedEdgesController', ManageAssignedEdgesController) |
81 | 82 | .controller('AddWidgetController', AddWidgetController) |
83 | + .controller('AddDashboardsToEdgeController', AddDashboardsToEdgeController) | |
82 | 84 | .directive('tbDashboardDetails', DashboardDirective) |
83 | 85 | .directive('tbEditWidget', EditWidgetDirective) |
84 | 86 | .directive('tbDashboardToolbar', DashboardToolbar) | ... | ... |
... | ... | @@ -219,6 +219,19 @@ export function EdgeController($rootScope, userService, edgeService, customerSer |
219 | 219 | edgeActionsList.push( |
220 | 220 | { |
221 | 221 | onAction: function ($event, item) { |
222 | + openEdgeDashboards($event, item); | |
223 | + }, | |
224 | + name: function() { return $translate.instant('dashboard.dashboards') }, | |
225 | + details: function() { | |
226 | + return $translate.instant('edge.manage-edge-dashboards'); | |
227 | + }, | |
228 | + icon: "dashboard" | |
229 | + } | |
230 | + ); | |
231 | + | |
232 | + edgeActionsList.push( | |
233 | + { | |
234 | + onAction: function ($event, item) { | |
222 | 235 | vm.grid.deleteItem($event, item); |
223 | 236 | }, |
224 | 237 | name: function() { return $translate.instant('action.delete') }, |
... | ... | @@ -240,6 +253,8 @@ export function EdgeController($rootScope, userService, edgeService, customerSer |
240 | 253 | } |
241 | 254 | ); |
242 | 255 | |
256 | + | |
257 | + | |
243 | 258 | edgeGroupActionsList.push( |
244 | 259 | { |
245 | 260 | onAction: function ($event) { |
... | ... | @@ -531,4 +546,18 @@ export function EdgeController($rootScope, userService, edgeService, customerSer |
531 | 546 | }); |
532 | 547 | }); |
533 | 548 | } |
549 | + | |
550 | + function openEdgeDashboards($event, edge) { | |
551 | + if ($event) { | |
552 | + $event.stopPropagation(); | |
553 | + } | |
554 | + $state.go('home.edges.dashboards', {edgeId: edge.id.id}); | |
555 | + } | |
556 | + | |
557 | + // function openEdgeRuleChains($event, edge) { | |
558 | + // if ($event) { | |
559 | + // $event.stopPropagation(); | |
560 | + // } | |
561 | + // $state.go('home.edges.rule-chains', {edgeId: edge.id.id}); | |
562 | + // } | |
534 | 563 | } | ... | ... |
... | ... | @@ -569,7 +569,20 @@ |
569 | 569 | "hide-details": "Hide details", |
570 | 570 | "select-state": "Select target state", |
571 | 571 | "state-controller": "State controller", |
572 | - "manage-assigned-edges": "Manage assigned edges" | |
572 | + "manage-assigned-edges": "Manage assigned edges", | |
573 | + "unassign-dashboard-from-edge-text": "After the confirmation the dashboard will be unassigned and won't be accessible by the edge.", | |
574 | + "assigned-edges": "Assigned edges", | |
575 | + "unassign-from-edge": "Unassign from edge", | |
576 | + "unassign-dashboards-from-edge-action-title": "Unassign { count, plural, 1 {1 dashboard} other {# dashboards} } from edge", | |
577 | + "unassign-dashboards-from-edge-text": "After the confirmation all selected dashboards will be unassigned and won't be accessible by the edge.", | |
578 | + "assign-dashboard-to-edge": "Assign Dashboard(s) To Edge", | |
579 | + "assign-dashboard-to-edge-text": "Please select the dashboards to assign to the edge", | |
580 | + "assign-dashboards-to-edge-text": "Assign { count, plural, 1 {1 dashboard} other {# dashboards} } to edges", | |
581 | + "unassign-dashboards-from-edge-action-text": "Unassign { count, plural, 1 {1 dashboard} other {# dashboards} } from edges", | |
582 | + "assign-to-edges": "Assign Dashboard(s) To Edges", | |
583 | + "assign-to-edges-text": "Please select the edges to assign the dashboard(s)", | |
584 | + "unassign-from-edges": "Unassign Dashboard(s) From Edges", | |
585 | + "unassign-from-edges-text": "Please select the edges to unassign from the dashboard(s)" | |
573 | 586 | }, |
574 | 587 | "datakey": { |
575 | 588 | "settings": "Settings", |
... | ... | @@ -759,7 +772,10 @@ |
759 | 772 | "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.", |
760 | 773 | "import": "Import edge", |
761 | 774 | "label": "Label", |
762 | - "assign-new-edge": "Assign new edge" | |
775 | + "assign-new-edge": "Assign new edge", | |
776 | + "manage-edge-dashboards": "Manage edge dashboards", | |
777 | + "unassign-from-edge": "Unassign from edge", | |
778 | + "dashboards": "Edge Dashboards" | |
763 | 779 | }, |
764 | 780 | "error": { |
765 | 781 | "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", | ... | ... |
... | ... | @@ -188,7 +188,7 @@ function Menu(userService, $state, $rootScope) { |
188 | 188 | name: 'edge.edges', |
189 | 189 | type: 'link', |
190 | 190 | state: 'home.edges', |
191 | - icon: 'toys' | |
191 | + icon: 'router' | |
192 | 192 | }, |
193 | 193 | { |
194 | 194 | name: 'widget.widget-library', |
... | ... | @@ -265,7 +265,7 @@ function Menu(userService, $state, $rootScope) { |
265 | 265 | places: [ |
266 | 266 | { |
267 | 267 | name: 'edge.edges', |
268 | - icon: 'toys', | |
268 | + icon: 'router', | |
269 | 269 | state: 'home.edges' |
270 | 270 | } |
271 | 271 | ] |
... | ... | @@ -326,7 +326,7 @@ function Menu(userService, $state, $rootScope) { |
326 | 326 | name: 'edge.edges', |
327 | 327 | type: 'link', |
328 | 328 | state: 'home.edges', |
329 | - icon: 'toys' | |
329 | + icon: 'router' | |
330 | 330 | }, |
331 | 331 | { |
332 | 332 | name: 'dashboard.dashboards', |
... | ... | @@ -371,7 +371,7 @@ function Menu(userService, $state, $rootScope) { |
371 | 371 | places: [ |
372 | 372 | { |
373 | 373 | name: 'edge.edges', |
374 | - icon: 'toys', | |
374 | + icon: 'router', | |
375 | 375 | state: 'home.edges' |
376 | 376 | } |
377 | 377 | ] | ... | ... |