Showing
16 changed files
with
1590 additions
and
1 deletions
ui/src/app/api/entity-view.service.js
0 → 100644
1 | +/* | ||
2 | + * Copyright © 2016-2018 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 | +import thingsboardTypes from '../common/types.constant'; | ||
17 | + | ||
18 | +export default angular.module('thingsboard.api.entityView', [thingsboardTypes]) | ||
19 | + .factory('entityViewService', EntityViewService) | ||
20 | + .name; | ||
21 | + | ||
22 | +/*@ngInject*/ | ||
23 | +function EntityViewService($http, $q, $window, userService, attributeService, customerService, types) { | ||
24 | + | ||
25 | + var service = { | ||
26 | + assignEntityViewToCustomer: assignEntityViewToCustomer, | ||
27 | + deleteEntityView: deleteEntityView, | ||
28 | + getCustomerEntityViews: getCustomerEntityViews, | ||
29 | + getEntityView: getEntityView, | ||
30 | + getEntityViews: getEntityViews, | ||
31 | + getTenantEntityViews: getTenantEntityViews, | ||
32 | + saveEntityView: saveEntityView, | ||
33 | + unassignEntityViewFromCustomer: unassignEntityViewFromCustomer, | ||
34 | + getEntityViewAttributes: getEntityViewAttributes, | ||
35 | + subscribeForEntityViewAttributes: subscribeForEntityViewAttributes, | ||
36 | + unsubscribeForEntityViewAttributes: unsubscribeForEntityViewAttributes, | ||
37 | + findByQuery: findByQuery, | ||
38 | + getEntityViewTypes: getEntityViewTypes | ||
39 | + } | ||
40 | + | ||
41 | + return service; | ||
42 | + | ||
43 | + function getTenantEntityViews(pageLink, applyCustomersInfo, config, type) { | ||
44 | + var deferred = $q.defer(); | ||
45 | + var url = '/api/tenant/entityViews?limit=' + pageLink.limit; | ||
46 | + if (angular.isDefined(pageLink.textSearch)) { | ||
47 | + url += '&textSearch=' + pageLink.textSearch; | ||
48 | + } | ||
49 | + if (angular.isDefined(pageLink.idOffset)) { | ||
50 | + url += '&idOffset=' + pageLink.idOffset; | ||
51 | + } | ||
52 | + if (angular.isDefined(pageLink.textOffset)) { | ||
53 | + url += '&textOffset=' + pageLink.textOffset; | ||
54 | + } | ||
55 | + if (angular.isDefined(type) && type.length) { | ||
56 | + url += '&type=' + type; | ||
57 | + } | ||
58 | + $http.get(url, config).then(function success(response) { | ||
59 | + if (applyCustomersInfo) { | ||
60 | + customerService.applyAssignedCustomersInfo(response.data.data).then( | ||
61 | + function success(data) { | ||
62 | + response.data.data = data; | ||
63 | + deferred.resolve(response.data); | ||
64 | + }, | ||
65 | + function fail() { | ||
66 | + deferred.reject(); | ||
67 | + } | ||
68 | + ); | ||
69 | + } else { | ||
70 | + deferred.resolve(response.data); | ||
71 | + } | ||
72 | + }, function fail() { | ||
73 | + deferred.reject(); | ||
74 | + }); | ||
75 | + return deferred.promise; | ||
76 | + } | ||
77 | + | ||
78 | + function getCustomerEntityViews(customerId, pageLink, applyCustomersInfo, config, type) { | ||
79 | + var deferred = $q.defer(); | ||
80 | + var url = '/api/customer/' + customerId + '/entityViews?limit=' + pageLink.limit; | ||
81 | + if (angular.isDefined(pageLink.textSearch)) { | ||
82 | + url += '&textSearch=' + pageLink.textSearch; | ||
83 | + } | ||
84 | + if (angular.isDefined(pageLink.idOffset)) { | ||
85 | + url += '&idOffset=' + pageLink.idOffset; | ||
86 | + } | ||
87 | + if (angular.isDefined(pageLink.textOffset)) { | ||
88 | + url += '&textOffset=' + pageLink.textOffset; | ||
89 | + } | ||
90 | + if (angular.isDefined(type) && type.length) { | ||
91 | + url += '&type=' + type; | ||
92 | + } | ||
93 | + $http.get(url, config).then(function success(response) { | ||
94 | + if (applyCustomersInfo) { | ||
95 | + customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( | ||
96 | + function success(data) { | ||
97 | + response.data.data = data; | ||
98 | + deferred.resolve(response.data); | ||
99 | + }, | ||
100 | + function fail() { | ||
101 | + deferred.reject(); | ||
102 | + } | ||
103 | + ); | ||
104 | + } else { | ||
105 | + deferred.resolve(response.data); | ||
106 | + } | ||
107 | + }, function fail() { | ||
108 | + deferred.reject(); | ||
109 | + }); | ||
110 | + | ||
111 | + return deferred.promise; | ||
112 | + } | ||
113 | + | ||
114 | + function getEntityView(entityViewId, ignoreErrors, config) { | ||
115 | + var deferred = $q.defer(); | ||
116 | + var url = '/api/entityView/' + entityViewId; | ||
117 | + if (!config) { | ||
118 | + config = {}; | ||
119 | + } | ||
120 | + config = Object.assign(config, { ignoreErrors: ignoreErrors }); | ||
121 | + $http.get(url, config).then(function success(response) { | ||
122 | + deferred.resolve(response.data); | ||
123 | + }, function fail(response) { | ||
124 | + deferred.reject(response.data); | ||
125 | + }); | ||
126 | + return deferred.promise; | ||
127 | + } | ||
128 | + | ||
129 | + function getEntityViews(entityViewIds, config) { | ||
130 | + var deferred = $q.defer(); | ||
131 | + var ids = ''; | ||
132 | + for (var i=0;i<entityViewIds.length;i++) { | ||
133 | + if (i>0) { | ||
134 | + ids += ','; | ||
135 | + } | ||
136 | + ids += entityViewIds[i]; | ||
137 | + } | ||
138 | + var url = '/api/entityViews?entityViewIds=' + ids; | ||
139 | + $http.get(url, config).then(function success(response) { | ||
140 | + var entityViews = response.data; | ||
141 | + entityViews.sort(function (entityView1, entityView2) { | ||
142 | + var id1 = entityView1.id.id; | ||
143 | + var id2 = entityView2.id.id; | ||
144 | + var index1 = entityViewIds.indexOf(id1); | ||
145 | + var index2 = entityViewIds.indexOf(id2); | ||
146 | + return index1 - index2; | ||
147 | + }); | ||
148 | + deferred.resolve(entityViews); | ||
149 | + }, function fail(response) { | ||
150 | + deferred.reject(response.data); | ||
151 | + }); | ||
152 | + return deferred.promise; | ||
153 | + } | ||
154 | + | ||
155 | + function saveEntityView(entityView) { | ||
156 | + var deferred = $q.defer(); | ||
157 | + var url = '/api/entityView'; | ||
158 | + $http.post(url, entityView).then(function success(response) { | ||
159 | + deferred.resolve(response.data); | ||
160 | + }, function fail() { | ||
161 | + deferred.reject(); | ||
162 | + }); | ||
163 | + return deferred.promise; | ||
164 | + } | ||
165 | + | ||
166 | + function deleteEntityView(entityViewId) { | ||
167 | + var deferred = $q.defer(); | ||
168 | + var url = '/api/entityView/' + entityViewId; | ||
169 | + $http.delete(url).then(function success() { | ||
170 | + deferred.resolve(); | ||
171 | + }, function fail() { | ||
172 | + deferred.reject(); | ||
173 | + }); | ||
174 | + return deferred.promise; | ||
175 | + } | ||
176 | + | ||
177 | + function assignEntityViewToCustomer(customerId, entityViewId) { | ||
178 | + var deferred = $q.defer(); | ||
179 | + var url = '/api/customer/' + customerId + '/entityView/' + entityViewId; | ||
180 | + $http.post(url, null).then(function success(response) { | ||
181 | + deferred.resolve(response.data); | ||
182 | + }, function fail() { | ||
183 | + deferred.reject(); | ||
184 | + }); | ||
185 | + return deferred.promise; | ||
186 | + } | ||
187 | + | ||
188 | + function unassignEntityViewFromCustomer(entityViewId) { | ||
189 | + var deferred = $q.defer(); | ||
190 | + var url = '/api/customer/entityView/' + entityViewId; | ||
191 | + $http.delete(url).then(function success(response) { | ||
192 | + deferred.resolve(response.data); | ||
193 | + }, function fail() { | ||
194 | + deferred.reject(); | ||
195 | + }); | ||
196 | + return deferred.promise; | ||
197 | + } | ||
198 | + | ||
199 | + function getEntityViewAttributes(entityViewId, attributeScope, query, successCallback, config) { | ||
200 | + return attributeService.getEntityAttributes(types.entityType.entityView, entityViewId, attributeScope, query, successCallback, config); | ||
201 | + } | ||
202 | + | ||
203 | + function subscribeForEntityViewAttributes(entityViewId, attributeScope) { | ||
204 | + return attributeService.subscribeForEntityAttributes(types.entityType.entityView, entityViewId, attributeScope); | ||
205 | + } | ||
206 | + | ||
207 | + function unsubscribeForEntityViewAttributes(subscriptionId) { | ||
208 | + attributeService.unsubscribeForEntityAttributes(subscriptionId); | ||
209 | + } | ||
210 | + | ||
211 | + function findByQuery(query, ignoreErrors, config) { | ||
212 | + var deferred = $q.defer(); | ||
213 | + var url = '/api/entityViews'; | ||
214 | + if (!config) { | ||
215 | + config = {}; | ||
216 | + } | ||
217 | + config = Object.assign(config, { ignoreErrors: ignoreErrors }); | ||
218 | + $http.post(url, query, config).then(function success(response) { | ||
219 | + deferred.resolve(response.data); | ||
220 | + }, function fail() { | ||
221 | + deferred.reject(); | ||
222 | + }); | ||
223 | + return deferred.promise; | ||
224 | + } | ||
225 | + | ||
226 | + function getEntityViewTypes(config) { | ||
227 | + var deferred = $q.defer(); | ||
228 | + var url = '/api/entityView/types'; | ||
229 | + $http.get(url, config).then(function success(response) { | ||
230 | + deferred.resolve(response.data); | ||
231 | + }, function fail() { | ||
232 | + deferred.reject(); | ||
233 | + }); | ||
234 | + return deferred.promise; | ||
235 | + } | ||
236 | + | ||
237 | +} |
@@ -67,6 +67,7 @@ import thingsboardClipboard from './services/clipboard.service'; | @@ -67,6 +67,7 @@ import thingsboardClipboard from './services/clipboard.service'; | ||
67 | import thingsboardHome from './layout'; | 67 | import thingsboardHome from './layout'; |
68 | import thingsboardApiLogin from './api/login.service'; | 68 | import thingsboardApiLogin from './api/login.service'; |
69 | import thingsboardApiDevice from './api/device.service'; | 69 | import thingsboardApiDevice from './api/device.service'; |
70 | +import thingsboardApiEntityView from './api/entity-view.service'; | ||
70 | import thingsboardApiUser from './api/user.service'; | 71 | import thingsboardApiUser from './api/user.service'; |
71 | import thingsboardApiEntityRelation from './api/entity-relation.service'; | 72 | import thingsboardApiEntityRelation from './api/entity-relation.service'; |
72 | import thingsboardApiAsset from './api/asset.service'; | 73 | import thingsboardApiAsset from './api/asset.service'; |
@@ -133,6 +134,7 @@ angular.module('thingsboard', [ | @@ -133,6 +134,7 @@ angular.module('thingsboard', [ | ||
133 | thingsboardHome, | 134 | thingsboardHome, |
134 | thingsboardApiLogin, | 135 | thingsboardApiLogin, |
135 | thingsboardApiDevice, | 136 | thingsboardApiDevice, |
137 | + thingsboardApiEntityView, | ||
136 | thingsboardApiUser, | 138 | thingsboardApiUser, |
137 | thingsboardApiEntityRelation, | 139 | thingsboardApiEntityRelation, |
138 | thingsboardApiAsset, | 140 | thingsboardApiAsset, |
@@ -327,7 +327,8 @@ export default angular.module('thingsboard.types', []) | @@ -327,7 +327,8 @@ export default angular.module('thingsboard.types', []) | ||
327 | dashboard: "DASHBOARD", | 327 | dashboard: "DASHBOARD", |
328 | alarm: "ALARM", | 328 | alarm: "ALARM", |
329 | rulechain: "RULE_CHAIN", | 329 | rulechain: "RULE_CHAIN", |
330 | - rulenode: "RULE_NODE" | 330 | + rulenode: "RULE_NODE", |
331 | + entityview: "ENTITY_VIEW" | ||
331 | }, | 332 | }, |
332 | aliasEntityType: { | 333 | aliasEntityType: { |
333 | current_customer: "CURRENT_CUSTOMER" | 334 | current_customer: "CURRENT_CUSTOMER" |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 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="{{ 'entity-view.add' | translate }}" tb-help="'entityViews'" help-container-id="help-container"> | ||
19 | + <form name="theForm" ng-submit="vm.add()"> | ||
20 | + <md-toolbar> | ||
21 | + <div class="md-toolbar-tools"> | ||
22 | + <h2 translate>entity-view.add</h2> | ||
23 | + <span flex></span> | ||
24 | + <div id="help-container"></div> | ||
25 | + <md-button class="md-icon-button" ng-click="vm.cancel()"> | ||
26 | + <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> | ||
27 | + </md-button> | ||
28 | + </div> | ||
29 | + </md-toolbar> | ||
30 | + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> | ||
31 | + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> | ||
32 | + <md-dialog-content> | ||
33 | + <div class="md-dialog-content"> | ||
34 | + <tb-entity-view entity-view="vm.item" is-edit="true" the-form="theForm"></tb-entity-view> | ||
35 | + </div> | ||
36 | + </md-dialog-content> | ||
37 | + <md-dialog-actions layout="row"> | ||
38 | + <span flex></span> | ||
39 | + <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> | ||
40 | + {{ 'action.add' | translate }} | ||
41 | + </md-button> | ||
42 | + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> | ||
43 | + </md-dialog-actions> | ||
44 | + </form> | ||
45 | +</md-dialog> |
1 | +/* | ||
2 | + * Copyright © 2016-2018 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 AddEntityViewsToCustomerController(entityViewService, $mdDialog, $q, customerId, entityViews) { | ||
18 | + | ||
19 | + var vm = this; | ||
20 | + | ||
21 | + vm.entityViews = entityViews; | ||
22 | + vm.searchText = ''; | ||
23 | + | ||
24 | + vm.assign = assign; | ||
25 | + vm.cancel = cancel; | ||
26 | + vm.hasData = hasData; | ||
27 | + vm.noData = noData; | ||
28 | + vm.searchEntityViewTextUpdated = searchEntityViewTextUpdated; | ||
29 | + vm.toggleEntityViewSelection = toggleEntityViewSelection; | ||
30 | + | ||
31 | + vm.theEntityViews = { | ||
32 | + getItemAtIndex: function (index) { | ||
33 | + if (index > vm.entityViews.data.length) { | ||
34 | + vm.theEntityViews.fetchMoreItems_(index); | ||
35 | + return null; | ||
36 | + } | ||
37 | + var item = vm.entityViews.data[index]; | ||
38 | + if (item) { | ||
39 | + item.indexNumber = index + 1; | ||
40 | + } | ||
41 | + return item; | ||
42 | + }, | ||
43 | + | ||
44 | + getLength: function () { | ||
45 | + if (vm.entityViews.hasNext) { | ||
46 | + return vm.entityViews.data.length + vm.entityViews.nextPageLink.limit; | ||
47 | + } else { | ||
48 | + return vm.entityViews.data.length; | ||
49 | + } | ||
50 | + }, | ||
51 | + | ||
52 | + fetchMoreItems_: function () { | ||
53 | + if (vm.entityViews.hasNext && !vm.entityViews.pending) { | ||
54 | + vm.entityViews.pending = true; | ||
55 | + entityViewService.getTenantEntityViews(vm.entityViews.nextPageLink, false).then( | ||
56 | + function success(entityViews) { | ||
57 | + vm.entityViews.data = vm.entityViews.data.concat(entityViews.data); | ||
58 | + vm.entityViews.nextPageLink = entityViews.nextPageLink; | ||
59 | + vm.entityViews.hasNext = entityViews.hasNext; | ||
60 | + if (vm.entityViews.hasNext) { | ||
61 | + vm.entityViews.nextPageLink.limit = vm.entityViews.pageSize; | ||
62 | + } | ||
63 | + vm.entityViews.pending = false; | ||
64 | + }, | ||
65 | + function fail() { | ||
66 | + vm.entityViews.hasNext = false; | ||
67 | + vm.entityViews.pending = false; | ||
68 | + }); | ||
69 | + } | ||
70 | + } | ||
71 | + }; | ||
72 | + | ||
73 | + function cancel () { | ||
74 | + $mdDialog.cancel(); | ||
75 | + } | ||
76 | + | ||
77 | + function assign() { | ||
78 | + var tasks = []; | ||
79 | + for (var entityViewId in vm.entityViews.selections) { | ||
80 | + tasks.push(entityViewService.assignEntityViewToCustomer(customerId, entityViewId)); | ||
81 | + } | ||
82 | + $q.all(tasks).then(function () { | ||
83 | + $mdDialog.hide(); | ||
84 | + }); | ||
85 | + } | ||
86 | + | ||
87 | + function noData() { | ||
88 | + return vm.entityViews.data.length == 0 && !vm.entityViews.hasNext; | ||
89 | + } | ||
90 | + | ||
91 | + function hasData() { | ||
92 | + return vm.entityViews.data.length > 0; | ||
93 | + } | ||
94 | + | ||
95 | + function toggleEntityViewSelection($event, entityView) { | ||
96 | + $event.stopPropagation(); | ||
97 | + var selected = angular.isDefined(entityView.selected) && entityView.selected; | ||
98 | + entityView.selected = !selected; | ||
99 | + if (entityView.selected) { | ||
100 | + vm.entityViews.selections[entityView.id.id] = true; | ||
101 | + vm.entityViews.selectedCount++; | ||
102 | + } else { | ||
103 | + delete vm.entityViews.selections[entityView.id.id]; | ||
104 | + vm.entityViews.selectedCount--; | ||
105 | + } | ||
106 | + } | ||
107 | + | ||
108 | + function searchEntityViewTextUpdated() { | ||
109 | + vm.entityViews = { | ||
110 | + pageSize: vm.entityViews.pageSize, | ||
111 | + data: [], | ||
112 | + nextPageLink: { | ||
113 | + limit: vm.entityViews.pageSize, | ||
114 | + textSearch: vm.searchText | ||
115 | + }, | ||
116 | + selections: {}, | ||
117 | + selectedCount: 0, | ||
118 | + hasNext: true, | ||
119 | + pending: false | ||
120 | + }; | ||
121 | + } | ||
122 | + | ||
123 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 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="{{ 'entity-view.assign-to-customer' | translate }}"> | ||
19 | + <form name="theForm" ng-submit="vm.assign()"> | ||
20 | + <md-toolbar> | ||
21 | + <div class="md-toolbar-tools"> | ||
22 | + <h2 translate>entity-view.assign-entity-view-to-customer</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>entity-view.assign-entity-view-to-customer-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="entity-view-search" autofocus ng-model="vm.searchText" | ||
41 | + ng-change="vm.searchEntityViewTextUpdated()" | ||
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()">entity-view.no-entity-views-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="entityView in vm.theEntityViews" md-on-demand | ||
54 | + class="repeated-item" flex> | ||
55 | + <md-checkbox ng-click="vm.toggleEntityViewSelection($event, entityView)" | ||
56 | + aria-label="{{ 'item.selected' | translate }}" | ||
57 | + ng-checked="entityView.selected"></md-checkbox> | ||
58 | + <span> {{ entityView.name }} </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.entityViews.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> |
1 | +/* | ||
2 | + * Copyright © 2016-2018 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 AssignEntityViewToCustomerController(customerService, entityViewService, $mdDialog, $q, entityViewIds, customers) { | ||
18 | + | ||
19 | + var vm = this; | ||
20 | + | ||
21 | + vm.customers = customers; | ||
22 | + vm.searchText = ''; | ||
23 | + | ||
24 | + vm.assign = assign; | ||
25 | + vm.cancel = cancel; | ||
26 | + vm.isCustomerSelected = isCustomerSelected; | ||
27 | + vm.hasData = hasData; | ||
28 | + vm.noData = noData; | ||
29 | + vm.searchCustomerTextUpdated = searchCustomerTextUpdated; | ||
30 | + vm.toggleCustomerSelection = toggleCustomerSelection; | ||
31 | + | ||
32 | + vm.theCustomers = { | ||
33 | + getItemAtIndex: function (index) { | ||
34 | + if (index > vm.customers.data.length) { | ||
35 | + vm.theCustomers.fetchMoreItems_(index); | ||
36 | + return null; | ||
37 | + } | ||
38 | + var item = vm.customers.data[index]; | ||
39 | + if (item) { | ||
40 | + item.indexNumber = index + 1; | ||
41 | + } | ||
42 | + return item; | ||
43 | + }, | ||
44 | + | ||
45 | + getLength: function () { | ||
46 | + if (vm.customers.hasNext) { | ||
47 | + return vm.customers.data.length + vm.customers.nextPageLink.limit; | ||
48 | + } else { | ||
49 | + return vm.customers.data.length; | ||
50 | + } | ||
51 | + }, | ||
52 | + | ||
53 | + fetchMoreItems_: function () { | ||
54 | + if (vm.customers.hasNext && !vm.customers.pending) { | ||
55 | + vm.customers.pending = true; | ||
56 | + customerService.getCustomers(vm.customers.nextPageLink).then( | ||
57 | + function success(customers) { | ||
58 | + vm.customers.data = vm.customers.data.concat(customers.data); | ||
59 | + vm.customers.nextPageLink = customers.nextPageLink; | ||
60 | + vm.customers.hasNext = customers.hasNext; | ||
61 | + if (vm.customers.hasNext) { | ||
62 | + vm.customers.nextPageLink.limit = vm.customers.pageSize; | ||
63 | + } | ||
64 | + vm.customers.pending = false; | ||
65 | + }, | ||
66 | + function fail() { | ||
67 | + vm.customers.hasNext = false; | ||
68 | + vm.customers.pending = false; | ||
69 | + }); | ||
70 | + } | ||
71 | + } | ||
72 | + }; | ||
73 | + | ||
74 | + function cancel() { | ||
75 | + $mdDialog.cancel(); | ||
76 | + } | ||
77 | + | ||
78 | + function assign() { | ||
79 | + var tasks = []; | ||
80 | + for (var i=0; i < entityViewIds.length;i++) { | ||
81 | + tasks.push(entityViewService.assignEntityViewToCustomer(vm.customers.selection.id.id, entityViewIds[i])); | ||
82 | + } | ||
83 | + $q.all(tasks).then(function () { | ||
84 | + $mdDialog.hide(); | ||
85 | + }); | ||
86 | + } | ||
87 | + | ||
88 | + function noData() { | ||
89 | + return vm.customers.data.length == 0 && !vm.customers.hasNext; | ||
90 | + } | ||
91 | + | ||
92 | + function hasData() { | ||
93 | + return vm.customers.data.length > 0; | ||
94 | + } | ||
95 | + | ||
96 | + function toggleCustomerSelection($event, customer) { | ||
97 | + $event.stopPropagation(); | ||
98 | + if (vm.isCustomerSelected(customer)) { | ||
99 | + vm.customers.selection = null; | ||
100 | + } else { | ||
101 | + vm.customers.selection = customer; | ||
102 | + } | ||
103 | + } | ||
104 | + | ||
105 | + function isCustomerSelected(customer) { | ||
106 | + return vm.customers.selection != null && customer && | ||
107 | + customer.id.id === vm.customers.selection.id.id; | ||
108 | + } | ||
109 | + | ||
110 | + function searchCustomerTextUpdated() { | ||
111 | + vm.customers = { | ||
112 | + pageSize: vm.customers.pageSize, | ||
113 | + data: [], | ||
114 | + nextPageLink: { | ||
115 | + limit: vm.customers.pageSize, | ||
116 | + textSearch: vm.searchText | ||
117 | + }, | ||
118 | + selection: null, | ||
119 | + hasNext: true, | ||
120 | + pending: false | ||
121 | + }; | ||
122 | + } | ||
123 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 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="{{ 'entity-view.assign-entity-view-to-customer' | translate }}"> | ||
19 | + <form name="theForm" ng-submit="vm.assign()"> | ||
20 | + <md-toolbar> | ||
21 | + <div class="md-toolbar-tools"> | ||
22 | + <h2 translate>entity-view.assign-entity-view-to-customer</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>entity-view.assign-to-customer-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="customer-search" autofocus ng-model="vm.searchText" | ||
41 | + ng-change="vm.searchCustomerTextUpdated()" | ||
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()">customer.no-customers-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="customer in vm.theCustomers" md-on-demand | ||
54 | + class="repeated-item" flex> | ||
55 | + <md-checkbox ng-click="vm.toggleCustomerSelection($event, customer)" | ||
56 | + aria-label="{{ 'item.selected' | translate }}" | ||
57 | + ng-checked="vm.isCustomerSelected(customer)"></md-checkbox> | ||
58 | + <span> {{ customer.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.customers.selection==null" type="submit" class="md-raised md-primary"> | ||
69 | + {{ 'action.assign' | translate }} | ||
70 | + </md-button> | ||
71 | + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | | ||
72 | + translate }} | ||
73 | + </md-button> | ||
74 | + </md-dialog-actions> | ||
75 | + </form> | ||
76 | +</md-dialog> |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 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 | +<div flex layout="column" style="margin-top: -10px;"> | ||
19 | + <div style="text-transform: uppercase; padding-bottom: 5px;">{{vm.item.type}}</div> | ||
20 | + <div class="tb-card-description">{{vm.item.additionalInfo.description}}</div> | ||
21 | + <div style="padding-top: 5px;" class="tb-small" ng-show="vm.isAssignedToCustomer()">{{'entity-view.assignedToCustomer' | translate}} '{{vm.item.assignedCustomer.title}}'</div> | ||
22 | +</div> |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 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-button ng-click="onAssignToCustomer({event: $event})" | ||
19 | + ng-show="!isEdit && entityViewScope === 'tenant' && !isAssignedToCustomer" | ||
20 | + class="md-raised md-primary">{{ 'entity-view.assign-to-customer' | translate }}</md-button> | ||
21 | +<md-button ng-click="onUnassignFromCustomer({event: $event})" | ||
22 | + ng-show="!isEdit && (entityViewScope === 'customer' || entityViewScope === 'tenant') && isAssignedToCustomer" | ||
23 | + class="md-raised md-primary">{{'entity-view.unassign-from-customer' | translate }}</md-button> | ||
24 | +<md-button ng-click="onDeleteEntityView({event: $event})" | ||
25 | + ng-show="!isEdit && entityViewScope === 'tenant'" | ||
26 | + class="md-raised md-primary">{{ 'entity-view.delete' | translate }}</md-button> | ||
27 | + | ||
28 | +<div layout="row"> | ||
29 | + <md-button ngclipboard data-clipboard-action="copy" | ||
30 | + ngclipboard-success="onEntityViewIdCopied(e)" | ||
31 | + data-clipboard-text="{{entityView.id.id}}" ng-show="!isEdit" | ||
32 | + class="md-raised"> | ||
33 | + <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon> | ||
34 | + <span translate>entity-view.copyId</span> | ||
35 | + </md-button> | ||
36 | +</div> | ||
37 | + | ||
38 | +<md-content class="md-padding" layout="column"> | ||
39 | + <md-input-container class="md-block" | ||
40 | + ng-show="!isEdit && isAssignedToCustomer && entityViewScope === 'tenant'"> | ||
41 | + <label translate>entity-view.assignedToCustomer</label> | ||
42 | + <input ng-model="assignedCustomer.title" disabled> | ||
43 | + </md-input-container> | ||
44 | + <fieldset ng-disabled="$root.loading || !isEdit"> | ||
45 | + <md-input-container class="md-block"> | ||
46 | + <label translate>entity-view.name</label> | ||
47 | + <input required name="name" ng-model="entityView.name"> | ||
48 | + <div ng-messages="theForm.name.$error"> | ||
49 | + <div translate ng-message="required">entity-view.name-required</div> | ||
50 | + </div> | ||
51 | + </md-input-container> | ||
52 | + <tb-entity-subtype-autocomplete | ||
53 | + ng-disabled="$root.loading || !isEdit" | ||
54 | + tb-required="true" | ||
55 | + the-form="theForm" | ||
56 | + ng-model="entityView.type" | ||
57 | + entity-type="types.entityType.entityview"> | ||
58 | + </tb-entity-subtype-autocomplete> | ||
59 | + <md-input-container class="md-block"> | ||
60 | + <label translate>entity-view.description</label> | ||
61 | + <textarea ng-model="entityView.additionalInfo.description" rows="2"></textarea> | ||
62 | + </md-input-container> | ||
63 | + </fieldset> | ||
64 | +</md-content> |
1 | +/* | ||
2 | + * Copyright © 2016-2018 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 | +/* eslint-disable import/no-unresolved, import/default */ | ||
17 | + | ||
18 | +import addEntityViewTemplate from './add-entity-view.tpl.html'; | ||
19 | +import entityViewCard from './entity-view-card.tpl.html'; | ||
20 | +import assignToCustomerTemplate from './assign-to-customer.tpl.html'; | ||
21 | +import addEntityViewsToCustomerTemplate from './add-entity-views-to-customer.tpl.html'; | ||
22 | + | ||
23 | +/* eslint-enable import/no-unresolved, import/default */ | ||
24 | + | ||
25 | +/*@ngInject*/ | ||
26 | +export function EntityViewCardController(types) { | ||
27 | + | ||
28 | + var vm = this; | ||
29 | + | ||
30 | + vm.types = types; | ||
31 | + | ||
32 | + vm.isAssignedToCustomer = function() { | ||
33 | + if (vm.item && vm.item.customerId && vm.parentCtl.entityViewsScope === 'tenant' && | ||
34 | + vm.item.customerId.id != vm.types.id.nullUid && !vm.item.assignedCustomer.isPublic) { | ||
35 | + return true; | ||
36 | + } | ||
37 | + return false; | ||
38 | + } | ||
39 | + | ||
40 | + vm.isPublic = function() { | ||
41 | + if (vm.item && vm.item.assignedCustomer && vm.parentCtl.entityViewsScope === 'tenant' && vm.item.assignedCustomer.isPublic) { | ||
42 | + return true; | ||
43 | + } | ||
44 | + return false; | ||
45 | + } | ||
46 | +} | ||
47 | + | ||
48 | + | ||
49 | +/*@ngInject*/ | ||
50 | +export function EntityViewController($rootScope, userService, entityViewService, customerService, $state, $stateParams, | ||
51 | + $document, $mdDialog, $q, $translate, types) { | ||
52 | + | ||
53 | + var customerId = $stateParams.customerId; | ||
54 | + | ||
55 | + var entityViewActionsList = []; | ||
56 | + | ||
57 | + var entityViewGroupActionsList = []; | ||
58 | + | ||
59 | + var vm = this; | ||
60 | + | ||
61 | + vm.types = types; | ||
62 | + | ||
63 | + vm.entityViewGridConfig = { | ||
64 | + deleteItemTitleFunc: deleteEntityViewTitle, | ||
65 | + deleteItemContentFunc: deleteEntityViewText, | ||
66 | + deleteItemsTitleFunc: deleteEntityViewsTitle, | ||
67 | + deleteItemsActionTitleFunc: deleteEntityViewsActionTitle, | ||
68 | + deleteItemsContentFunc: deleteEntityViewsText, | ||
69 | + | ||
70 | + saveItemFunc: saveEntityView, | ||
71 | + | ||
72 | + getItemTitleFunc: getEntityViewTitle, | ||
73 | + | ||
74 | + itemCardController: 'EntityViewCardController', | ||
75 | + itemCardTemplateUrl: entityViewCard, | ||
76 | + parentCtl: vm, | ||
77 | + | ||
78 | + actionsList: entityViewActionsList, | ||
79 | + groupActionsList: entityViewGroupActionsList, | ||
80 | + | ||
81 | + onGridInited: gridInited, | ||
82 | + | ||
83 | + addItemTemplateUrl: addEntityViewTemplate, | ||
84 | + | ||
85 | + addItemText: function() { return $translate.instant('entity-view.add-entity-view-text') }, | ||
86 | + noItemsText: function() { return $translate.instant('entity-view.no-entity-views-text') }, | ||
87 | + itemDetailsText: function() { return $translate.instant('entity-view.entity-view-details') }, | ||
88 | + isDetailsReadOnly: isCustomerUser, | ||
89 | + isSelectionEnabled: function () { | ||
90 | + return !isCustomerUser(); | ||
91 | + } | ||
92 | + }; | ||
93 | + | ||
94 | + if (angular.isDefined($stateParams.items) && $stateParams.items !== null) { | ||
95 | + vm.entityViewGridConfig.items = $stateParams.items; | ||
96 | + } | ||
97 | + | ||
98 | + if (angular.isDefined($stateParams.topIndex) && $stateParams.topIndex > 0) { | ||
99 | + vm.entityViewGridConfig.topIndex = $stateParams.topIndex; | ||
100 | + } | ||
101 | + | ||
102 | + vm.entityViewsScope = $state.$current.data.entityViewsType; | ||
103 | + | ||
104 | + vm.assignToCustomer = assignToCustomer; | ||
105 | + vm.makePublic = makePublic; | ||
106 | + vm.unassignFromCustomer = unassignFromCustomer; | ||
107 | + | ||
108 | + initController(); | ||
109 | + | ||
110 | + function initController() { | ||
111 | + var fetchEntityViewsFunction = null; | ||
112 | + var deleteEntityViewFunction = null; | ||
113 | + var refreshEntityViewsParamsFunction = null; | ||
114 | + | ||
115 | + var user = userService.getCurrentUser(); | ||
116 | + | ||
117 | + if (user.authority === 'CUSTOMER_USER') { | ||
118 | + vm.entityViewsScope = 'customer_user'; | ||
119 | + customerId = user.customerId; | ||
120 | + } | ||
121 | + if (customerId) { | ||
122 | + vm.customerEntityViewsTitle = $translate.instant('customer.entity-views'); | ||
123 | + customerService.getShortCustomerInfo(customerId).then( | ||
124 | + function success(info) { | ||
125 | + if (info.isPublic) { | ||
126 | + vm.customerEntityViewsTitle = $translate.instant('customer.public-entity-views'); | ||
127 | + } | ||
128 | + } | ||
129 | + ); | ||
130 | + } | ||
131 | + | ||
132 | + if (vm.entityViewsScope === 'tenant') { | ||
133 | + fetchEntityViewsFunction = function (pageLink, entityViewType) { | ||
134 | + return entityViewService.getTenantEntityViews(pageLink, true, null, entityViewType); | ||
135 | + }; | ||
136 | + deleteEntityViewFunction = function (entityViewId) { | ||
137 | + return entityViewService.deleteEntityView(entityViewId); | ||
138 | + }; | ||
139 | + refreshEntityViewsParamsFunction = function() { | ||
140 | + return {"topIndex": vm.topIndex}; | ||
141 | + }; | ||
142 | + | ||
143 | + entityViewActionsList.push( | ||
144 | + { | ||
145 | + onAction: function ($event, item) { | ||
146 | + assignToCustomer($event, [ item.id.id ]); | ||
147 | + }, | ||
148 | + name: function() { return $translate.instant('action.assign') }, | ||
149 | + details: function() { return $translate.instant('entity-view.assign-to-customer') }, | ||
150 | + icon: "assignment_ind", | ||
151 | + isEnabled: function(entityView) { | ||
152 | + return entityView && (!entityView.customerId || entityView.customerId.id === types.id.nullUid); | ||
153 | + } | ||
154 | + } | ||
155 | + ); | ||
156 | + | ||
157 | + entityViewActionsList.push( | ||
158 | + { | ||
159 | + onAction: function ($event, item) { | ||
160 | + unassignFromCustomer($event, item, false); | ||
161 | + }, | ||
162 | + name: function() { return $translate.instant('action.unassign') }, | ||
163 | + details: function() { return $translate.instant('entity-view.unassign-from-customer') }, | ||
164 | + icon: "assignment_return", | ||
165 | + isEnabled: function(entityView) { | ||
166 | + return entityView && entityView.customerId && entityView.customerId.id !== types.id.nullUid && !entityView.assignedCustomer.isPublic; | ||
167 | + } | ||
168 | + } | ||
169 | + ); | ||
170 | + | ||
171 | + entityViewActionsList.push({ | ||
172 | + onAction: function ($event, item) { | ||
173 | + unassignFromCustomer($event, item, true); | ||
174 | + }, | ||
175 | + name: function() { return $translate.instant('action.make-private') }, | ||
176 | + details: function() { return $translate.instant('entity-view.make-private') }, | ||
177 | + icon: "reply", | ||
178 | + isEnabled: function(entityView) { | ||
179 | + return entityView && entityView.customerId && entityView.customerId.id !== types.id.nullUid && entityView.assignedCustomer.isPublic; | ||
180 | + } | ||
181 | + }); | ||
182 | + | ||
183 | + entityViewActionsList.push( | ||
184 | + { | ||
185 | + onAction: function ($event, item) { | ||
186 | + vm.grid.deleteItem($event, item); | ||
187 | + }, | ||
188 | + name: function() { return $translate.instant('action.delete') }, | ||
189 | + details: function() { return $translate.instant('entity-view.delete') }, | ||
190 | + icon: "delete" | ||
191 | + } | ||
192 | + ); | ||
193 | + | ||
194 | + entityViewGroupActionsList.push( | ||
195 | + { | ||
196 | + onAction: function ($event, items) { | ||
197 | + assignEntiyViewsToCustomer($event, items); | ||
198 | + }, | ||
199 | + name: function() { return $translate.instant('entity-view.assign-entity-views') }, | ||
200 | + details: function(selectedCount) { | ||
201 | + return $translate.instant('entity-view.assign-entity-views-text', {count: selectedCount}, "messageformat"); | ||
202 | + }, | ||
203 | + icon: "assignment_ind" | ||
204 | + } | ||
205 | + ); | ||
206 | + | ||
207 | + entityViewGroupActionsList.push( | ||
208 | + { | ||
209 | + onAction: function ($event) { | ||
210 | + vm.grid.deleteItems($event); | ||
211 | + }, | ||
212 | + name: function() { return $translate.instant('entity-view.delete-entity-views') }, | ||
213 | + details: deleteEntityViewsActionTitle, | ||
214 | + icon: "delete" | ||
215 | + } | ||
216 | + ); | ||
217 | + | ||
218 | + | ||
219 | + | ||
220 | + } else if (vm.entityViewsScope === 'customer' || vm.entityViewsScope === 'customer_user') { | ||
221 | + fetchEntityViewsFunction = function (pageLink, entityViewType) { | ||
222 | + return entityViewService.getCustomerEntityViews(customerId, pageLink, true, null, entityViewType); | ||
223 | + }; | ||
224 | + deleteentityViewFunction = function (entityViewId) { | ||
225 | + return entityViewService.unassignEntityViewFromCustomer(entityViewId); | ||
226 | + }; | ||
227 | + refreshentityViewsParamsFunction = function () { | ||
228 | + return {"customerId": customerId, "topIndex": vm.topIndex}; | ||
229 | + }; | ||
230 | + | ||
231 | + if (vm.entityViewsScope === 'customer') { | ||
232 | + entityViewActionsList.push( | ||
233 | + { | ||
234 | + onAction: function ($event, item) { | ||
235 | + unassignFromCustomer($event, item, false); | ||
236 | + }, | ||
237 | + name: function() { return $translate.instant('action.unassign') }, | ||
238 | + details: function() { return $translate.instant('entity-view.unassign-from-customer') }, | ||
239 | + icon: "assignment_return", | ||
240 | + isEnabled: function(entityView) { | ||
241 | + return entityView && !entityView.assignedCustomer.isPublic; | ||
242 | + } | ||
243 | + } | ||
244 | + ); | ||
245 | + | ||
246 | + entityViewGroupActionsList.push( | ||
247 | + { | ||
248 | + onAction: function ($event, items) { | ||
249 | + unassignEntityViewsFromCustomer($event, items); | ||
250 | + }, | ||
251 | + name: function() { return $translate.instant('entity-view.unassign-entity-views') }, | ||
252 | + details: function(selectedCount) { | ||
253 | + return $translate.instant('entity-view.unassign-entity-views-action-title', {count: selectedCount}, "messageformat"); | ||
254 | + }, | ||
255 | + icon: "assignment_return" | ||
256 | + } | ||
257 | + ); | ||
258 | + | ||
259 | + vm.entityViewGridConfig.addItemAction = { | ||
260 | + onAction: function ($event) { | ||
261 | + addEntityViewsToCustomer($event); | ||
262 | + }, | ||
263 | + name: function() { return $translate.instant('entity-view.assign-entity-views') }, | ||
264 | + details: function() { return $translate.instant('entity-view.assign-new-entity-view') }, | ||
265 | + icon: "add" | ||
266 | + }; | ||
267 | + | ||
268 | + | ||
269 | + } else if (vm.entityViewsScope === 'customer_user') { | ||
270 | + vm.entityViewGridConfig.addItemAction = {}; | ||
271 | + } | ||
272 | + } | ||
273 | + | ||
274 | + vm.entityViewGridConfig.refreshParamsFunc = refreshentityViewsParamsFunction; | ||
275 | + vm.entityViewGridConfig.fetchItemsFunc = fetchentityViewsFunction; | ||
276 | + vm.entityViewGridConfig.deleteItemFunc = deleteentityViewFunction; | ||
277 | + | ||
278 | + } | ||
279 | + | ||
280 | + function deleteEntityViewTitle(entityView) { | ||
281 | + return $translate.instant('entity-view.delete-entity-view-title', {entityViewName: entityView.name}); | ||
282 | + } | ||
283 | + | ||
284 | + function deleteEntityViewText() { | ||
285 | + return $translate.instant('entity-view.delete-entity-view-text'); | ||
286 | + } | ||
287 | + | ||
288 | + function deleteEntityViewsTitle(selectedCount) { | ||
289 | + return $translate.instant('entity-view.delete-entity-views-title', {count: selectedCount}, 'messageformat'); | ||
290 | + } | ||
291 | + | ||
292 | + function deleteEntityViewsActionTitle(selectedCount) { | ||
293 | + return $translate.instant('entity-view.delete-entity-views-action-title', {count: selectedCount}, 'messageformat'); | ||
294 | + } | ||
295 | + | ||
296 | + function deleteEntityViewsText () { | ||
297 | + return $translate.instant('entity-view.delete-entity-views-text'); | ||
298 | + } | ||
299 | + | ||
300 | + function gridInited(grid) { | ||
301 | + vm.grid = grid; | ||
302 | + } | ||
303 | + | ||
304 | + function getEntityViewTitle(entityView) { | ||
305 | + return entityView ? entityView.name : ''; | ||
306 | + } | ||
307 | + | ||
308 | + function saveEntityView(entityView) { | ||
309 | + var deferred = $q.defer(); | ||
310 | + entityViewService.saveEntityView(entityView).then( | ||
311 | + function success(savedEntityView) { | ||
312 | + $rootScope.$broadcast('entityViewSaved'); | ||
313 | + var entityViews = [ savedEntityView ]; | ||
314 | + customerService.applyAssignedCustomersInfo(entityViews).then( | ||
315 | + function success(items) { | ||
316 | + if (items && items.length == 1) { | ||
317 | + deferred.resolve(items[0]); | ||
318 | + } else { | ||
319 | + deferred.reject(); | ||
320 | + } | ||
321 | + }, | ||
322 | + function fail() { | ||
323 | + deferred.reject(); | ||
324 | + } | ||
325 | + ); | ||
326 | + }, | ||
327 | + function fail() { | ||
328 | + deferred.reject(); | ||
329 | + } | ||
330 | + ); | ||
331 | + return deferred.promise; | ||
332 | + } | ||
333 | + | ||
334 | + function isCustomerUser() { | ||
335 | + return vm.entityViewsScope === 'customer_user'; | ||
336 | + } | ||
337 | + | ||
338 | + function assignToCustomer($event, entityViewIds) { | ||
339 | + if ($event) { | ||
340 | + $event.stopPropagation(); | ||
341 | + } | ||
342 | + var pageSize = 10; | ||
343 | + customerService.getCustomers({limit: pageSize, textSearch: ''}).then( | ||
344 | + function success(_customers) { | ||
345 | + var customers = { | ||
346 | + pageSize: pageSize, | ||
347 | + data: _customers.data, | ||
348 | + nextPageLink: _customers.nextPageLink, | ||
349 | + selection: null, | ||
350 | + hasNext: _customers.hasNext, | ||
351 | + pending: false | ||
352 | + }; | ||
353 | + if (customers.hasNext) { | ||
354 | + customers.nextPageLink.limit = pageSize; | ||
355 | + } | ||
356 | + $mdDialog.show({ | ||
357 | + controller: 'AssignEntityViewToCustomerController', | ||
358 | + controllerAs: 'vm', | ||
359 | + templateUrl: assignToCustomerTemplate, | ||
360 | + locals: {entityViewIds: entityViewIds, customers: customers}, | ||
361 | + parent: angular.element($document[0].body), | ||
362 | + fullscreen: true, | ||
363 | + targetEvent: $event | ||
364 | + }).then(function () { | ||
365 | + vm.grid.refreshList(); | ||
366 | + }, function () { | ||
367 | + }); | ||
368 | + }, | ||
369 | + function fail() { | ||
370 | + }); | ||
371 | + } | ||
372 | + | ||
373 | + function addEntityViewsToCustomer($event) { | ||
374 | + if ($event) { | ||
375 | + $event.stopPropagation(); | ||
376 | + } | ||
377 | + var pageSize = 10; | ||
378 | + entityViewService.getTenantEntityViews({limit: pageSize, textSearch: ''}, false).then( | ||
379 | + function success(_entityViews) { | ||
380 | + var entityViews = { | ||
381 | + pageSize: pageSize, | ||
382 | + data: _entityViews.data, | ||
383 | + nextPageLink: _entityViews.nextPageLink, | ||
384 | + selections: {}, | ||
385 | + selectedCount: 0, | ||
386 | + hasNext: _entityViews.hasNext, | ||
387 | + pending: false | ||
388 | + }; | ||
389 | + if (entityViews.hasNext) { | ||
390 | + entityViews.nextPageLink.limit = pageSize; | ||
391 | + } | ||
392 | + $mdDialog.show({ | ||
393 | + controller: 'AddEntityViewsToCustomerController', | ||
394 | + controllerAs: 'vm', | ||
395 | + templateUrl: addEntityViewsToCustomerTemplate, | ||
396 | + locals: {customerId: customerId, entityViews: entityViews}, | ||
397 | + parent: angular.element($document[0].body), | ||
398 | + fullscreen: true, | ||
399 | + targetEvent: $event | ||
400 | + }).then(function () { | ||
401 | + vm.grid.refreshList(); | ||
402 | + }, function () { | ||
403 | + }); | ||
404 | + }, | ||
405 | + function fail() { | ||
406 | + }); | ||
407 | + } | ||
408 | + | ||
409 | + function assignEntityViewsToCustomer($event, items) { | ||
410 | + var entityViewIds = []; | ||
411 | + for (var id in items.selections) { | ||
412 | + entityViewIds.push(id); | ||
413 | + } | ||
414 | + assignToCustomer($event, entityViewIds); | ||
415 | + } | ||
416 | + | ||
417 | + function unassignFromCustomer($event, entityView, isPublic) { | ||
418 | + if ($event) { | ||
419 | + $event.stopPropagation(); | ||
420 | + } | ||
421 | + var title; | ||
422 | + var content; | ||
423 | + var label; | ||
424 | + if (isPublic) { | ||
425 | + title = $translate.instant('entity-view.make-private-entity-view-title', {entityViewName: entityView.name}); | ||
426 | + content = $translate.instant('entity-view.make-private-entity-view-text'); | ||
427 | + label = $translate.instant('entity-view.make-private'); | ||
428 | + } else { | ||
429 | + title = $translate.instant('entity-view.unassign-entity-view-title', {entityViewName: entityView.name}); | ||
430 | + content = $translate.instant('entity-view.unassign-entity-view-text'); | ||
431 | + label = $translate.instant('entity-view.unassign-entity-view'); | ||
432 | + } | ||
433 | + var confirm = $mdDialog.confirm() | ||
434 | + .targetEvent($event) | ||
435 | + .title(title) | ||
436 | + .htmlContent(content) | ||
437 | + .ariaLabel(label) | ||
438 | + .cancel($translate.instant('action.no')) | ||
439 | + .ok($translate.instant('action.yes')); | ||
440 | + $mdDialog.show(confirm).then(function () { | ||
441 | + entityViewService.unassignEntityViewFromCustomer(entityView.id.id).then(function success() { | ||
442 | + vm.grid.refreshList(); | ||
443 | + }); | ||
444 | + }); | ||
445 | + } | ||
446 | + | ||
447 | + function unassignEntityViewsFromCustomer($event, items) { | ||
448 | + var confirm = $mdDialog.confirm() | ||
449 | + .targetEvent($event) | ||
450 | + .title($translate.instant('entity-view.unassign-entity-views-title', {count: items.selectedCount}, 'messageformat')) | ||
451 | + .htmlContent($translate.instant('entity-view.unassign-entity-views-text')) | ||
452 | + .ariaLabel($translate.instant('entity-view.unassign-entity-view')) | ||
453 | + .cancel($translate.instant('action.no')) | ||
454 | + .ok($translate.instant('action.yes')); | ||
455 | + $mdDialog.show(confirm).then(function () { | ||
456 | + var tasks = []; | ||
457 | + for (var id in items.selections) { | ||
458 | + tasks.push(entityViewService.unassignEntityViewFromCustomer(id)); | ||
459 | + } | ||
460 | + $q.all(tasks).then(function () { | ||
461 | + vm.grid.refreshList(); | ||
462 | + }); | ||
463 | + }); | ||
464 | + } | ||
465 | + | ||
466 | + function makePublic($event, entityView) { | ||
467 | + if ($event) { | ||
468 | + $event.stopPropagation(); | ||
469 | + } | ||
470 | + var confirm = $mdDialog.confirm() | ||
471 | + .targetEvent($event) | ||
472 | + .title($translate.instant('entity-view.make-public-entity-view-title', {entityViewName: entityView.name})) | ||
473 | + .htmlContent($translate.instant('entity-view.make-public-entity-view-text')) | ||
474 | + .ariaLabel($translate.instant('entity-view.make-public')) | ||
475 | + .cancel($translate.instant('action.no')) | ||
476 | + .ok($translate.instant('action.yes')); | ||
477 | + $mdDialog.show(confirm).then(function () { | ||
478 | + entityViewService.makeEntityViewPublic(entityView.id.id).then(function success() { | ||
479 | + vm.grid.refreshList(); | ||
480 | + }); | ||
481 | + }); | ||
482 | + } | ||
483 | +} |
1 | +/* | ||
2 | + * Copyright © 2016-2018 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 | +/* eslint-disable import/no-unresolved, import/default */ | ||
17 | + | ||
18 | +import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html'; | ||
19 | + | ||
20 | +/* eslint-enable import/no-unresolved, import/default */ | ||
21 | + | ||
22 | +/*@ngInject*/ | ||
23 | +export default function EntityViewDirective($compile, $templateCache, toast, $translate, types, clipboardService, entityViewService, customerService) { | ||
24 | + var linker = function (scope, element) { | ||
25 | + var template = $templateCache.get(entityViewFieldsetTemplate); | ||
26 | + element.html(template); | ||
27 | + | ||
28 | + scope.types = types; | ||
29 | + scope.isAssignedToCustomer = false; | ||
30 | + scope.assignedCustomer = null; | ||
31 | + | ||
32 | + scope.$watch('entityView', function(newVal) { | ||
33 | + if (newVal) { | ||
34 | + if (scope.entityView.customerId && scope.entityView.customerId.id !== types.id.nullUid) { | ||
35 | + scope.isAssignedToCustomer = true; | ||
36 | + customerService.getShortCustomerInfo(scope.entityView.customerId.id).then( | ||
37 | + function success(customer) { | ||
38 | + scope.assignedCustomer = customer; | ||
39 | + } | ||
40 | + ); | ||
41 | + } else { | ||
42 | + scope.isAssignedToCustomer = false; | ||
43 | + scope.assignedCustomer = null; | ||
44 | + } | ||
45 | + } | ||
46 | + }); | ||
47 | + | ||
48 | + scope.onEntityViewIdCopied = function() { | ||
49 | + toast.showSuccess($translate.instant('entity-view.idCopiedMessage'), 750, angular.element(element).parent().parent(), 'bottom left'); | ||
50 | + }; | ||
51 | + | ||
52 | + $compile(element.contents())(scope); | ||
53 | + } | ||
54 | + return { | ||
55 | + restrict: "E", | ||
56 | + link: linker, | ||
57 | + scope: { | ||
58 | + entityView: '=', | ||
59 | + isEdit: '=', | ||
60 | + entityViewScope: '=', | ||
61 | + theForm: '=', | ||
62 | + onAssignToCustomer: '&', | ||
63 | + onUnassignFromCustomer: '&', | ||
64 | + onDeleteEntityView: '&' | ||
65 | + } | ||
66 | + }; | ||
67 | +} |
ui/src/app/entity-view/entity-view.routes.js
0 → 100644
1 | +/* | ||
2 | + * Copyright © 2016-2018 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 | +/* eslint-disable import/no-unresolved, import/default */ | ||
17 | + | ||
18 | +import entityViewsTemplate from './entity-views.tpl.html'; | ||
19 | + | ||
20 | +/* eslint-enable import/no-unresolved, import/default */ | ||
21 | + | ||
22 | +/*@ngInject*/ | ||
23 | +export default function EntityViewRoutes($stateProvider, types) { | ||
24 | + $stateProvider | ||
25 | + .state('home.entityViews', { | ||
26 | + url: '/entityViews', | ||
27 | + params: {'topIndex': 0}, | ||
28 | + module: 'private', | ||
29 | + auth: ['TENANT_ADMIN', 'CUSTOMER_USER'], | ||
30 | + views: { | ||
31 | + "content@home": { | ||
32 | + templateUrl: entityViewsTemplate, | ||
33 | + controller: 'EntityViewController', | ||
34 | + controllerAs: 'vm' | ||
35 | + } | ||
36 | + }, | ||
37 | + data: { | ||
38 | + entityViewsTypes: 'tenant', | ||
39 | + searchEnabled: true, | ||
40 | + searchByEntitySubtype: true, | ||
41 | + searchEntityType: types.entityType.entityview, | ||
42 | + pageTitle: 'entity-views.entity-views' | ||
43 | + }, | ||
44 | + ncyBreadcrumb: { | ||
45 | + label: '{"icon": "devices_other", "label": "entity-view.entity-views"}' | ||
46 | + } | ||
47 | + }) | ||
48 | + .state('home.customers.entityViews', { | ||
49 | + url: '/:customerId/entityViews', | ||
50 | + params: {'topIndex': 0}, | ||
51 | + module: 'private', | ||
52 | + auth: ['TENANT_ADMIN'], | ||
53 | + views: { | ||
54 | + "content@home": { | ||
55 | + templateUrl: entityViewsTemplate, | ||
56 | + controllerAs: 'vm', | ||
57 | + controller: 'EntityViewController' | ||
58 | + } | ||
59 | + }, | ||
60 | + data: { | ||
61 | + entityViewsTypes: 'customer', | ||
62 | + searchEnabled: true, | ||
63 | + searchByEntitySubtype: true, | ||
64 | + searchEntityType: types.entityType.entityview, | ||
65 | + pageTitle: 'customer.entity-views' | ||
66 | + }, | ||
67 | + ncyBreadcrumb: { | ||
68 | + label: '{"icon": "devices_other", "label": "{{ vm.customerEntityViewsTitle }}", "translate": "false"}' | ||
69 | + } | ||
70 | + }); | ||
71 | + | ||
72 | +} |
ui/src/app/entity-view/entity-views.tpl.html
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 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 | +<tb-grid grid-configuration="vm.entityViewGridConfig"> | ||
19 | + <details-buttons tb-help="'entityViews'" help-container-id="help-container"> | ||
20 | + <div id="help-container"></div> | ||
21 | + </details-buttons> | ||
22 | + <md-tabs ng-class="{'tb-headless': vm.grid.detailsConfig.isDetailsEditMode}" | ||
23 | + id="tabs" md-border-bottom flex class="tb-absolute-fill"> | ||
24 | + <md-tab label="{{ 'entity-view.details' | translate }}"> | ||
25 | + <tb-entity-view entity-view="vm.grid.operatingItem()" | ||
26 | + is-edit="vm.grid.detailsConfig.isDetailsEditMode" | ||
27 | + entity-view-scope="vm.entityViewsScope" | ||
28 | + the-form="vm.grid.detailsForm" | ||
29 | + on-assign-to-customer="vm.assignToCustomer(event, [ vm.grid.detailsConfig.currentItem.id.id ])" | ||
30 | + on-make-public="vm.makePublic(event, vm.grid.detailsConfig.currentItem)" | ||
31 | + on-unassign-from-customer="vm.unassignFromCustomer(event, vm.grid.detailsConfig.currentItem, isPublic)" | ||
32 | + on-manage-credentials="vm.manageCredentials(event, vm.grid.detailsConfig.currentItem)" | ||
33 | + on-delete-entity-view="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-entity-view> | ||
34 | + </md-tab> | ||
35 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}"> | ||
36 | + <tb-attribute-table flex | ||
37 | + entity-id="vm.grid.operatingItem().id.id" | ||
38 | + entity-type="{{vm.types.entityType.entityview}}" | ||
39 | + entity-name="vm.grid.operatingItem().name" | ||
40 | + default-attribute-scope="{{vm.types.attributesScope.client.value}}"> | ||
41 | + </tb-attribute-table> | ||
42 | + </md-tab> | ||
43 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}"> | ||
44 | + <tb-attribute-table flex | ||
45 | + entity-id="vm.grid.operatingItem().id.id" | ||
46 | + entity-type="{{vm.types.entityType.entityview}}" | ||
47 | + entity-name="vm.grid.operatingItem().name" | ||
48 | + default-attribute-scope="{{vm.types.latestTelemetry.value}}" | ||
49 | + disable-attribute-scope-selection="true"> | ||
50 | + </tb-attribute-table> | ||
51 | + </md-tab> | ||
52 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}"> | ||
53 | + <tb-alarm-table flex entity-type="vm.types.entityType.entityview" | ||
54 | + entity-id="vm.grid.operatingItem().id.id"> | ||
55 | + </tb-alarm-table> | ||
56 | + </md-tab> | ||
57 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'entity-view.events' | translate }}"> | ||
58 | + <tb-event-table flex entity-type="vm.types.entityType.entityview" | ||
59 | + entity-id="vm.grid.operatingItem().id.id" | ||
60 | + tenant-id="vm.grid.operatingItem().tenantId.id" | ||
61 | + default-event-type="{{vm.types.eventType.error.value}}"> | ||
62 | + </tb-event-table> | ||
63 | + </md-tab> | ||
64 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> | ||
65 | + <tb-relation-table flex | ||
66 | + entity-id="vm.grid.operatingItem().id.id" | ||
67 | + entity-type="{{vm.types.entityType.entityview}}"> | ||
68 | + </tb-relation-table> | ||
69 | + </md-tab> | ||
70 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.operatingItem().additionalInfo.gateway" md-on-select="vm.grid.triggerResize()" label="{{ 'extension.extensions' | translate }}"> | ||
71 | + <tb-extension-table flex | ||
72 | + entity-id="vm.grid.operatingItem().id.id" | ||
73 | + entity-name="vm.grid.operatingItem().name" | ||
74 | + entity-type="{{vm.types.entityType.entityview}}"> | ||
75 | + </tb-extension-table> | ||
76 | + </md-tab> | ||
77 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.isTenantAdmin()" md-on-select="vm.grid.triggerResize()" label="{{ 'audit-log.audit-logs' | translate }}"> | ||
78 | + <tb-audit-log-table flex entity-type="vm.types.entityType.entityview" | ||
79 | + entity-id="vm.grid.operatingItem().id.id" | ||
80 | + audit-log-mode="{{vm.types.auditLogMode.entity}}"> | ||
81 | + </tb-audit-log-table> | ||
82 | + </md-tab> | ||
83 | +</tb-grid> |
ui/src/app/entity-view/index.js
0 → 100644
1 | +/* | ||
2 | + * Copyright © 2016-2018 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 | +import uiRouter from 'angular-ui-router'; | ||
17 | +import thingsboardGrid from '../components/grid.directive'; | ||
18 | +import thingsboardApiUser from '../api/user.service'; | ||
19 | +import thingsboardApiEntityView from '../api/entity-view.service'; | ||
20 | +import thingsboardApiCustomer from '../api/customer.service'; | ||
21 | + | ||
22 | +import EntityViewRoutes from './entity-view.routes'; | ||
23 | +import EntityViewCardController from './entity-view.controller'; | ||
24 | +import AssignEntityViewToCustomerController from './assign-to-customer.controller'; | ||
25 | +import AddEntityViewsToCustomerController from './add-entity-views-to-customer.controller'; | ||
26 | +import EntityViewDirective from './entity-view.directive'; | ||
27 | + | ||
28 | +export default angular.module('thingsboard.entityView', [ | ||
29 | + uiRouter, | ||
30 | + thingsboardGrid, | ||
31 | + thingsboardApiUser, | ||
32 | + thingsboardApiEntityView, | ||
33 | + thingsboardApiCustomer | ||
34 | +]) | ||
35 | + .config(EntityViewRoutes) | ||
36 | + .controller('EntityViewController', EntityViewCardController) | ||
37 | + .controller('EntityViewCardController', EntityViewCardController) | ||
38 | + .controller('AssignEntityViewToCustomerController', AssignEntityViewToCustomerController) | ||
39 | + .controller('AddEntityViewsToCustomerController', AddEntityViewsToCustomerController) | ||
40 | + .directive('tbEntityView', EntityViewDirective) | ||
41 | + .name; |
@@ -338,10 +338,12 @@ | @@ -338,10 +338,12 @@ | ||
338 | "dashboard": "Customer Dashboard", | 338 | "dashboard": "Customer Dashboard", |
339 | "dashboards": "Customer Dashboards", | 339 | "dashboards": "Customer Dashboards", |
340 | "devices": "Customer Devices", | 340 | "devices": "Customer Devices", |
341 | + "entity-views": "Customer Entity Views", | ||
341 | "assets": "Customer Assets", | 342 | "assets": "Customer Assets", |
342 | "public-dashboards": "Public Dashboards", | 343 | "public-dashboards": "Public Dashboards", |
343 | "public-devices": "Public Devices", | 344 | "public-devices": "Public Devices", |
344 | "public-assets": "Public Assets", | 345 | "public-assets": "Public Assets", |
346 | + "public-entity-views": "Public Entity Views", | ||
345 | "add": "Add Customer", | 347 | "add": "Add Customer", |
346 | "delete": "Delete customer", | 348 | "delete": "Delete customer", |
347 | "manage-customer-users": "Manage customer users", | 349 | "manage-customer-users": "Manage customer users", |
@@ -750,6 +752,77 @@ | @@ -750,6 +752,77 @@ | ||
750 | "no-entities-prompt": "No entities found", | 752 | "no-entities-prompt": "No entities found", |
751 | "no-data": "No data to display" | 753 | "no-data": "No data to display" |
752 | }, | 754 | }, |
755 | + "entity-view": { | ||
756 | + "entity-view": "Entity View", | ||
757 | + "entity-views": "Entity Views", | ||
758 | + "management": "Entity View management", | ||
759 | + "view-entity-views": "View Entity Views", | ||
760 | + "entity-view-alias": "Entity View alias", | ||
761 | + "aliases": "Entity View aliases", | ||
762 | + "no-alias-matching": "'{{alias}}' not found.", | ||
763 | + "no-aliases-found": "No aliases found.", | ||
764 | + "no-key-matching": "'{{key}}' not found.", | ||
765 | + "no-keys-found": "No keys found.", | ||
766 | + "create-new-alias": "Create a new one!", | ||
767 | + "create-new-key": "Create a new one!", | ||
768 | + "duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Entity View aliases must be unique whithin the dashboard.", | ||
769 | + "configure-alias": "Configure '{{alias}}' alias", | ||
770 | + "no-entity-views-matching": "No entity views matching '{{entity}}' were found.", | ||
771 | + "alias": "Alias", | ||
772 | + "alias-required": "Entity View alias is required.", | ||
773 | + "remove-alias": "Remove entity view alias", | ||
774 | + "add-alias": "Add entity view alias", | ||
775 | + "name-starts-with": "Entity View name starts with", | ||
776 | + "entity-view-list": "Entity View list", | ||
777 | + "use-entity-view-name-filter": "Use filter", | ||
778 | + "entity-view-list-empty": "No entity views selected.", | ||
779 | + "entity-view-name-filter-required": "Entity view name filter is required.", | ||
780 | + "entity-view-name-filter-no-entity-view-matched": "No entity views starting with '{{entityView}}' were found.", | ||
781 | + "add": "Add Entity View", | ||
782 | + "assign-to-customer": "Assign to customer", | ||
783 | + "assign-entity-view-to-customer": "Assign Entity View(s) To Customer", | ||
784 | + "assign-entity-view-to-customer-text": "Please select the entity views to assign to the customer", | ||
785 | + "no-entity-views-text": "No entity views found", | ||
786 | + "assign-to-customer-text": "Please select the customer to assign the entity view(s)", | ||
787 | + "entity-view-details": "Entity view details", | ||
788 | + "add-entity-view-text": "Add new entity view", | ||
789 | + "delete": "Delete entity view", | ||
790 | + "assign-entity-views": "Assign entity views", | ||
791 | + "assign-entity-views-text": "Assign { count, plural, 1 {1 entityView} other {# entityViews} } to customer", | ||
792 | + "delete-entity-views": "Delete entity views", | ||
793 | + "unassign-from-customer": "Unassign from customer", | ||
794 | + "unassign-entity-views": "Unassign entity views", | ||
795 | + "unassign-entity-views-action-title": "Unassign { count, plural, 1 {1 entityView} other {# entityViews} } from customer", | ||
796 | + "assign-new-entity-view": "Assign new entity view", | ||
797 | + "delete-entity-view-title": "Are you sure you want to delete the entity view '{{entityViewName}}'?", | ||
798 | + "delete-entity-view-text": "Be careful, after the confirmation the entity view and all related data will become unrecoverable.", | ||
799 | + "delete-entity-views-title": "Are you sure you want to entity view { count, plural, 1 {1 entityView} other {# entityViews} }?", | ||
800 | + "delete-entity-views-action-title": "Delete { count, plural, 1 {1 entityView} other {# entityViews} }", | ||
801 | + "delete-entity-views-text": "Be careful, after the confirmation all selected entity views will be removed and all related data will become unrecoverable.", | ||
802 | + "unassign-entity-view-title": "Are you sure you want to unassign the entity view '{{entityViewName}}'?", | ||
803 | + "unassign-entity-view-text": "After the confirmation the entity view will be unassigned and won't be accessible by the customer.", | ||
804 | + "unassign-entity-view": "Unassign entity view", | ||
805 | + "unassign-entity-views-title": "Are you sure you want to unassign { count, plural, 1 {1 entityView} other {# entityViews} }?", | ||
806 | + "unassign-entity-views-text": "After the confirmation all selected entity views will be unassigned and won't be accessible by the customer.", | ||
807 | + "entity-view-type": "Entity View type", | ||
808 | + "entity-view-type-required": "Entity View type is required.", | ||
809 | + "select-entity-view-type": "Select entity view type", | ||
810 | + "enter-entity-view-type": "Enter entity view type", | ||
811 | + "any-entity-view": "Any entity view", | ||
812 | + "no-entity-view-types-matching": "No entity view types matching '{{entitySubtype}}' were found.", | ||
813 | + "entity-view-type-list-empty": "No entity view types selected.", | ||
814 | + "entity-view-types": "Entity View types", | ||
815 | + "name": "Name", | ||
816 | + "name-required": "Name is required.", | ||
817 | + "description": "Description", | ||
818 | + "events": "Events", | ||
819 | + "details": "Details", | ||
820 | + "copyId": "Copy entity view Id", | ||
821 | + "assignedToCustomer": "Assigned to customer", | ||
822 | + "unable-entity-view-device-alias-title": "Unable to delete entity view alias", | ||
823 | + "unable-entity-view-device-alias-text": "Device alias '{{entityViewAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", | ||
824 | + "select-entity-view": "Select entity view" | ||
825 | + }, | ||
753 | "event": { | 826 | "event": { |
754 | "event-type": "Event type", | 827 | "event-type": "Event type", |
755 | "type-error": "Error", | 828 | "type-error": "Error", |