Commit 0c0b3dade41aaa80996cece0dc3ee7865dc44143
1 parent
ae4148d7
TB-61: Improve Alias Filter. Miltiple datasources resolution.
Showing
38 changed files
with
1415 additions
and
369 deletions
ui/src/app/api/alias-controller.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +const varsRegex = /\$\{([^\}]*)\}/g; | |
18 | + | |
19 | +export default class AliasController { | |
20 | + | |
21 | + constructor($scope, $q, $filter, utils, types, entityService, stateController, entityAliases) { | |
22 | + this.$scope = $scope; | |
23 | + this.$q = $q; | |
24 | + this.$filter = $filter; | |
25 | + this.utils = utils; | |
26 | + this.types = types; | |
27 | + this.entityService = entityService; | |
28 | + this.stateController = stateController; | |
29 | + this.entityAliases = angular.copy(entityAliases); | |
30 | + this.resolvedAliases = {}; | |
31 | + this.resolvedAliasesPromise = {}; | |
32 | + this.resolvedAliasesToStateEntities = {}; | |
33 | + } | |
34 | + | |
35 | + updateEntityAliases(newEntityAliases) { | |
36 | + var changedAliasIds = []; | |
37 | + for (var aliasId in newEntityAliases) { | |
38 | + var newEntityAlias = newEntityAliases[aliasId]; | |
39 | + var prevEntityAlias = this.entityAliases[aliasId]; | |
40 | + if (!angular.equals(newEntityAlias, prevEntityAlias)) { | |
41 | + changedAliasIds.push(aliasId); | |
42 | + this.setAliasUnresolved(aliasId); | |
43 | + } | |
44 | + } | |
45 | + for (aliasId in this.entityAliases) { | |
46 | + if (!newEntityAliases[aliasId]) { | |
47 | + changedAliasIds.push(aliasId); | |
48 | + this.setAliasUnresolved(aliasId); | |
49 | + } | |
50 | + } | |
51 | + this.entityAliases = angular.copy(newEntityAliases); | |
52 | + if (changedAliasIds.length) { | |
53 | + this.$scope.$broadcast('entityAliasesChanged', changedAliasIds); | |
54 | + } | |
55 | + } | |
56 | + | |
57 | + dashboardStateChanged() { | |
58 | + var newEntityId = this.stateController.getStateParams().entityId; | |
59 | + var changedAliasIds = []; | |
60 | + for (var aliasId in this.resolvedAliasesToStateEntities) { | |
61 | + var prevEntityId = this.resolvedAliasesToStateEntities[aliasId]; | |
62 | + if (!angular.equals(newEntityId, prevEntityId)) { | |
63 | + changedAliasIds.push(aliasId); | |
64 | + this.setAliasUnresolved(aliasId); | |
65 | + } | |
66 | + } | |
67 | + if (changedAliasIds.length) { | |
68 | + this.$scope.$broadcast('entityAliasesChanged', changedAliasIds); | |
69 | + } | |
70 | + } | |
71 | + | |
72 | + setAliasUnresolved(aliasId) { | |
73 | + delete this.resolvedAliases[aliasId]; | |
74 | + delete this.resolvedAliasesPromise[aliasId]; | |
75 | + delete this.resolvedAliasesToStateEntities[aliasId]; | |
76 | + } | |
77 | + | |
78 | + getEntityAliases() { | |
79 | + return this.entityAliases; | |
80 | + } | |
81 | + | |
82 | + getAliasInfo(aliasId) { | |
83 | + var deferred = this.$q.defer(); | |
84 | + var aliasInfo = this.resolvedAliases[aliasId]; | |
85 | + if (aliasInfo) { | |
86 | + deferred.resolve(aliasInfo); | |
87 | + return deferred.promise; | |
88 | + } else if (this.resolvedAliasesPromise[aliasId]) { | |
89 | + return this.resolvedAliasesPromise[aliasId]; | |
90 | + } else { | |
91 | + this.resolvedAliasesPromise[aliasId] = deferred.promise; | |
92 | + var aliasCtrl = this; | |
93 | + var entityAlias = this.entityAliases[aliasId]; | |
94 | + if (entityAlias) { | |
95 | + this.entityService.resolveAlias(entityAlias, this.stateController.getStateParams()).then( | |
96 | + function success(aliasInfo) { | |
97 | + aliasCtrl.resolvedAliases[aliasId] = aliasInfo; | |
98 | + if (entityAlias.filter.stateEntity) { | |
99 | + aliasCtrl.resolvedAliasesToStateEntities[aliasId] = | |
100 | + aliasCtrl.stateController.getStateParams().entityId; | |
101 | + } | |
102 | + deferred.resolve(aliasInfo); | |
103 | + }, | |
104 | + function fail() { | |
105 | + deferred.reject(); | |
106 | + } | |
107 | + ); | |
108 | + } else { | |
109 | + deferred.reject(); | |
110 | + } | |
111 | + return this.resolvedAliasesPromise[aliasId]; | |
112 | + } | |
113 | + } | |
114 | + | |
115 | + resolveDatasource(datasource) { | |
116 | + var deferred = this.$q.defer(); | |
117 | + if (datasource.type === this.types.datasourceType.entity) { | |
118 | + if (datasource.entityAliasId) { | |
119 | + this.getAliasInfo(datasource.entityAliasId).then( | |
120 | + function success(aliasInfo) { | |
121 | + datasource.aliasName = aliasInfo.alias; | |
122 | + if (aliasInfo.resolveMultiple) { | |
123 | + var resolvedEntities = aliasInfo.resolvedEntities; | |
124 | + if (resolvedEntities && resolvedEntities.length) { | |
125 | + var datasources = []; | |
126 | + for (var i=0;i<resolvedEntities.length;i++) { | |
127 | + var resolvedEntity = resolvedEntities[i]; | |
128 | + var newDatasource = angular.copy(datasource); | |
129 | + newDatasource.entityId = resolvedEntity.id; | |
130 | + newDatasource.entityType = resolvedEntity.entityType; | |
131 | + newDatasource.entityName = resolvedEntity.name; | |
132 | + newDatasource.name = resolvedEntity.name; | |
133 | + newDatasource.generated = i > 0 ? true : false; | |
134 | + datasources.push(newDatasource); | |
135 | + } | |
136 | + deferred.resolve(datasources); | |
137 | + } else { | |
138 | + deferred.reject(); | |
139 | + } | |
140 | + } else { | |
141 | + var entity = aliasInfo.currentEntity; | |
142 | + datasource.entityId = entity.id; | |
143 | + datasource.entityType = entity.entityType; | |
144 | + datasource.entityName = entity.name; | |
145 | + datasource.name = entity.name; | |
146 | + deferred.resolve([datasource]); | |
147 | + } | |
148 | + }, | |
149 | + function fail() { | |
150 | + deferred.reject(); | |
151 | + } | |
152 | + ); | |
153 | + } else { // entityId | |
154 | + datasource.aliasName = datasource.entityName; | |
155 | + datasource.name = datasource.entityName; | |
156 | + deferred.resolve([datasource]); | |
157 | + } | |
158 | + } else { // function | |
159 | + deferred.resolve([datasource]); | |
160 | + } | |
161 | + return deferred.promise; | |
162 | + } | |
163 | + | |
164 | + resolveDatasources(datasources) { | |
165 | + | |
166 | + function updateDataKeyLabel(dataKey, datasource) { | |
167 | + if (!dataKey.pattern) { | |
168 | + dataKey.pattern = angular.copy(dataKey.label); | |
169 | + } | |
170 | + var pattern = dataKey.pattern; | |
171 | + var label = dataKey.pattern; | |
172 | + var match = varsRegex.exec(pattern); | |
173 | + while (match !== null) { | |
174 | + var variable = match[0]; | |
175 | + var variableName = match[1]; | |
176 | + if (variableName === 'dsName') { | |
177 | + label = label.split(variable).join(datasource.name); | |
178 | + } else if (variableName === 'entityName') { | |
179 | + label = label.split(variable).join(datasource.entityName); | |
180 | + } else if (variableName === 'deviceName') { | |
181 | + label = label.split(variable).join(datasource.entityName); | |
182 | + } else if (variableName === 'aliasName') { | |
183 | + label = label.split(variable).join(datasource.aliasName); | |
184 | + } | |
185 | + match = varsRegex.exec(pattern); | |
186 | + } | |
187 | + dataKey.label = label; | |
188 | + } | |
189 | + | |
190 | + function updateDatasourceKeyLabels(datasource) { | |
191 | + for (var dk = 0; dk < datasource.dataKeys.length; dk++) { | |
192 | + updateDataKeyLabel(datasource.dataKeys[dk], datasource); | |
193 | + } | |
194 | + } | |
195 | + | |
196 | + var deferred = this.$q.defer(); | |
197 | + var newDatasources = angular.copy(datasources); | |
198 | + var datasorceResolveTasks = []; | |
199 | + var aliasCtrl = this; | |
200 | + newDatasources.forEach(function (datasource) { | |
201 | + var resolveDatasourceTask = aliasCtrl.resolveDatasource(datasource); | |
202 | + datasorceResolveTasks.push(resolveDatasourceTask); | |
203 | + }); | |
204 | + this.$q.all(datasorceResolveTasks).then( | |
205 | + function success(datasourcesArrays) { | |
206 | + var datasources = [].concat.apply([], datasourcesArrays); | |
207 | + datasources = aliasCtrl.$filter('orderBy')(datasources, '+generated'); | |
208 | + var index = 0; | |
209 | + var functionIndex = 0; | |
210 | + datasources.forEach(function(datasource) { | |
211 | + if (datasource.type === aliasCtrl.types.datasourceType.function) { | |
212 | + var name; | |
213 | + if (datasource.name && datasource.name.length) { | |
214 | + name = datasource.name; | |
215 | + } else { | |
216 | + functionIndex++; | |
217 | + name = aliasCtrl.types.datasourceType.function; | |
218 | + if (functionIndex > 1) { | |
219 | + name += ' ' + functionIndex; | |
220 | + } | |
221 | + } | |
222 | + datasource.name = name; | |
223 | + datasource.aliasName = name; | |
224 | + datasource.entityName = name; | |
225 | + } | |
226 | + datasource.dataKeys.forEach(function(dataKey) { | |
227 | + if (datasource.generated) { | |
228 | + dataKey._hash = Math.random(); | |
229 | + dataKey.color = aliasCtrl.utils.getMaterialColor(index); | |
230 | + } | |
231 | + index++; | |
232 | + }); | |
233 | + updateDatasourceKeyLabels(datasource); | |
234 | + }); | |
235 | + deferred.resolve(datasources); | |
236 | + }, | |
237 | + function fail() { | |
238 | + deferred.reject(); | |
239 | + } | |
240 | + ); | |
241 | + return deferred.promise; | |
242 | + } | |
243 | + | |
244 | + getInstantAliasInfo(aliasId) { | |
245 | + return this.resolvedAliases[aliasId]; | |
246 | + } | |
247 | + | |
248 | + updateCurrentAliasEntity(aliasId, currentEntity) { | |
249 | + var aliasInfo = this.resolvedAliases[aliasId]; | |
250 | + if (aliasInfo) { | |
251 | + var prevCurrentEntity = aliasInfo.currentEntity; | |
252 | + if (!angular.equals(currentEntity, prevCurrentEntity)) { | |
253 | + aliasInfo.currentEntity = currentEntity; | |
254 | + this.$scope.$broadcast('entityAliasesChanged', [aliasId]); | |
255 | + } | |
256 | + } | |
257 | + } | |
258 | + | |
259 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -27,10 +27,13 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
27 | 27 | getEntity: getEntity, |
28 | 28 | getEntities: getEntities, |
29 | 29 | getEntitiesByNameFilter: getEntitiesByNameFilter, |
30 | - processEntityAliases: processEntityAliases, | |
30 | + resolveAlias: resolveAlias, | |
31 | + resolveAliasFilter: resolveAliasFilter, | |
32 | + filterAliasByEntityTypes: filterAliasByEntityTypes, | |
33 | + //processEntityAliases: processEntityAliases, | |
31 | 34 | getEntityKeys: getEntityKeys, |
32 | 35 | checkEntityAlias: checkEntityAlias, |
33 | - createDatasoucesFromSubscriptionsInfo: createDatasoucesFromSubscriptionsInfo, | |
36 | + createDatasourcesFromSubscriptionsInfo: createDatasourcesFromSubscriptionsInfo, | |
34 | 37 | getRelatedEntities: getRelatedEntities, |
35 | 38 | saveRelatedEntity: saveRelatedEntity, |
36 | 39 | getRelatedEntity: getRelatedEntity, |
... | ... | @@ -244,81 +247,151 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
244 | 247 | return deferred.promise; |
245 | 248 | } |
246 | 249 | |
247 | - function entityToEntityInfo(entityType, entity) { | |
248 | - return { name: entity.name, entityType: entityType, id: entity.id.id }; | |
250 | + function entityToEntityInfo(entity) { | |
251 | + return { name: entity.name, entityType: entity.id.entityType, id: entity.id.id }; | |
249 | 252 | } |
250 | 253 | |
251 | - function entitiesToEntitiesInfo(entityType, entities) { | |
254 | + function entitiesToEntitiesInfo(entities) { | |
252 | 255 | var entitiesInfo = []; |
253 | 256 | for (var d = 0; d < entities.length; d++) { |
254 | - entitiesInfo.push(entityToEntityInfo(entityType, entities[d])); | |
257 | + entitiesInfo.push(entityToEntityInfo(entities[d])); | |
255 | 258 | } |
256 | 259 | return entitiesInfo; |
257 | 260 | } |
258 | 261 | |
259 | - function processEntityAlias(index, aliasIds, entityAliases, resolution, deferred) { | |
260 | - if (index < aliasIds.length) { | |
261 | - var aliasId = aliasIds[index]; | |
262 | - var entityAlias = entityAliases[aliasId]; | |
263 | - var alias = entityAlias.alias; | |
264 | - var entityFilter = entityAlias.entityFilter; | |
265 | - if (entityFilter.useFilter) { | |
266 | - var entityNameFilter = entityFilter.entityNameFilter; | |
267 | - getEntitiesByNameFilter(entityAlias.entityType, entityNameFilter, 100).then( | |
268 | - function(entities) { | |
269 | - if (entities && entities != null) { | |
270 | - var resolvedAlias = {alias: alias, entityType: entityAlias.entityType, entityId: entities[0].id.id}; | |
271 | - resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias; | |
272 | - resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entityAlias.entityType, entities); | |
273 | - index++; | |
274 | - processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); | |
275 | - } else { | |
276 | - if (!resolution.error) { | |
277 | - resolution.error = 'dashboard.invalid-aliases-config'; | |
262 | + function resolveAliasFilter(filter, stateParams) { | |
263 | + var deferred = $q.defer(); | |
264 | + var result = { | |
265 | + entities: [], | |
266 | + stateEntity: false | |
267 | + }; | |
268 | + switch (filter.type) { | |
269 | + case types.aliasFilterType.entityList.value: | |
270 | + if (filter.stateEntity) { | |
271 | + result.stateEntity = true; | |
272 | + if (stateParams && stateParams.entityId) { | |
273 | + getEntity(stateParams.entityId.entityType, stateParams.entityId.id).then( | |
274 | + function success(entity) { | |
275 | + result.entities = [entity]; | |
276 | + deferred.resolve(result); | |
277 | + }, | |
278 | + function fail() { | |
279 | + deferred.reject(); | |
278 | 280 | } |
279 | - index++; | |
280 | - processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); | |
281 | + ); | |
282 | + } else { | |
283 | + deferred.resolve(result); | |
284 | + } | |
285 | + } else { | |
286 | + getEntities(filter.entityType, filter.entityList).then( | |
287 | + function success(entities) { | |
288 | + if (entities && entities.length) { | |
289 | + result.entities = entities; | |
290 | + deferred.resolve(result); | |
291 | + } else { | |
292 | + deferred.reject(); | |
293 | + } | |
294 | + }, | |
295 | + function fail() { | |
296 | + deferred.reject(); | |
281 | 297 | } |
282 | - }); | |
283 | - } else { | |
284 | - var entityList = entityFilter.entityList; | |
285 | - getEntities(entityAlias.entityType, entityList).then( | |
298 | + ); | |
299 | + } | |
300 | + break; | |
301 | + case types.aliasFilterType.entityName.value: | |
302 | + getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, 100).then( | |
286 | 303 | function success(entities) { |
287 | - if (entities && entities.length > 0) { | |
288 | - var resolvedAlias = {alias: alias, entityType: entityAlias.entityType, entityId: entities[0].id.id}; | |
289 | - resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias; | |
290 | - resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entityAlias.entityType, entities); | |
291 | - index++; | |
292 | - processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); | |
304 | + if (entities && entities.length) { | |
305 | + result.entities = entities; | |
306 | + deferred.resolve(result); | |
293 | 307 | } else { |
294 | - if (!resolution.error) { | |
295 | - resolution.error = 'dashboard.invalid-aliases-config'; | |
296 | - } | |
297 | - index++; | |
298 | - processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); | |
308 | + deferred.reject(); | |
299 | 309 | } |
300 | 310 | }, |
301 | 311 | function fail() { |
312 | + deferred.reject(); | |
313 | + } | |
314 | + ); | |
315 | + break; | |
316 | + //TODO: | |
317 | + } | |
318 | + return deferred.promise; | |
319 | + } | |
320 | + | |
321 | + function resolveAlias(entityAlias, stateParams) { | |
322 | + var deferred = $q.defer(); | |
323 | + var filter = entityAlias.filter; | |
324 | + resolveAliasFilter(filter, stateParams).then( | |
325 | + function (result) { | |
326 | + var entities = result.entities; | |
327 | + var aliasInfo = { | |
328 | + alias: entityAlias.alias, | |
329 | + resolveMultiple: filter.resolveMultiple | |
330 | + }; | |
331 | + var resolvedEntities = entitiesToEntitiesInfo(entities); | |
332 | + aliasInfo.resolvedEntities = resolvedEntities; | |
333 | + aliasInfo.currentEntity = null; | |
334 | + if (aliasInfo.resolvedEntities.length) { | |
335 | + aliasInfo.currentEntity = aliasInfo.resolvedEntities[0]; | |
336 | + } | |
337 | + deferred.resolve(aliasInfo); | |
338 | + }, | |
339 | + function fail() { | |
340 | + deferred.reject(); | |
341 | + } | |
342 | + ); | |
343 | + return deferred.promise; | |
344 | + } | |
345 | + | |
346 | + function filterAliasByEntityTypes(entityAlias, entityTypes) { | |
347 | + var filter = entityAlias.filter; | |
348 | + switch (filter.type) { | |
349 | + case types.aliasFilterType.entityList.value: | |
350 | + if (filter.stateEntity) { | |
351 | + return true; | |
352 | + } else { | |
353 | + return entityTypes.indexOf(filter.entityType) > -1 ? true : false; | |
354 | + } | |
355 | + case types.aliasFilterType.entityName.value: | |
356 | + return entityTypes.indexOf(filter.entityType) > -1 ? true : false; | |
357 | + } | |
358 | + //TODO: | |
359 | + return false; | |
360 | + } | |
361 | + | |
362 | + /*function processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred) { | |
363 | + if (index < aliasIds.length) { | |
364 | + var aliasId = aliasIds[index]; | |
365 | + var entityAlias = entityAliases[aliasId]; | |
366 | + var alias = entityAlias.alias; | |
367 | + var filter = entityAlias.filter; | |
368 | + resolveAliasFilter(filter, stateParams).then( | |
369 | + function (entities) { | |
370 | + if (entities && entities.length) { | |
371 | + var entity = entities[0]; | |
372 | + var resolvedAlias = {alias: alias, entityType: entity.id.entityType, entityId: entity.id.id}; | |
373 | + resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias; | |
374 | + resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entities); | |
375 | + index++; | |
376 | + processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred); | |
377 | + } else { | |
302 | 378 | if (!resolution.error) { |
303 | 379 | resolution.error = 'dashboard.invalid-aliases-config'; |
304 | 380 | } |
305 | 381 | index++; |
306 | - processEntityAlias(index, aliasIds, entityAliases, resolution, deferred); | |
382 | + processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred); | |
307 | 383 | } |
308 | - ); | |
309 | - } | |
384 | + } | |
385 | + ); | |
310 | 386 | } else { |
311 | 387 | deferred.resolve(resolution); |
312 | 388 | } |
313 | - } | |
389 | + }*/ | |
314 | 390 | |
315 | - function processEntityAliases(entityAliases) { | |
391 | + /*function processEntityAliases(entityAliases, stateParams) { | |
316 | 392 | var deferred = $q.defer(); |
317 | 393 | var resolution = { |
318 | - aliasesInfo: { | |
319 | - entityAliases: {}, | |
320 | - entityAliasesInfo: {} | |
321 | - } | |
394 | + aliasesInfo: {} | |
322 | 395 | }; |
323 | 396 | var aliasIds = []; |
324 | 397 | if (entityAliases) { |
... | ... | @@ -326,9 +399,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
326 | 399 | aliasIds.push(aliasId); |
327 | 400 | } |
328 | 401 | } |
329 | - processEntityAlias(0, aliasIds, entityAliases, resolution, deferred); | |
402 | + processEntityAlias(0, aliasIds, entityAliases, stateParams, resolution, deferred); | |
330 | 403 | return deferred.promise; |
331 | - } | |
404 | + }*/ | |
332 | 405 | |
333 | 406 | function getEntityKeys(entityType, entityId, query, type) { |
334 | 407 | var deferred = $q.defer(); |
... | ... | @@ -354,8 +427,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
354 | 427 | } |
355 | 428 | } |
356 | 429 | deferred.resolve(result); |
357 | - }, function fail(response) { | |
358 | - deferred.reject(response.data); | |
430 | + }, function fail() { | |
431 | + deferred.reject(); | |
359 | 432 | }); |
360 | 433 | return deferred.promise; |
361 | 434 | } |
... | ... | @@ -387,7 +460,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
387 | 460 | return deferred.promise; |
388 | 461 | } |
389 | 462 | |
390 | - function createDatasoucesFromSubscriptionsInfo(subscriptionsInfo) { | |
463 | + function createDatasourcesFromSubscriptionsInfo(subscriptionsInfo) { | |
391 | 464 | var deferred = $q.defer(); |
392 | 465 | var datasources = []; |
393 | 466 | processSubscriptionsInfo(0, subscriptionsInfo, datasources, deferred); | ... | ... |
... | ... | @@ -39,6 +39,9 @@ export default class Subscription { |
39 | 39 | this.cafs = {}; |
40 | 40 | this.registrations = []; |
41 | 41 | |
42 | + var subscription = this; | |
43 | + var deferred = this.ctx.$q.defer(); | |
44 | + | |
42 | 45 | if (this.type === this.ctx.types.widgetType.rpc.value) { |
43 | 46 | this.callbacks.rpcStateChanged = this.callbacks.rpcStateChanged || function(){}; |
44 | 47 | this.callbacks.onRpcSuccess = this.callbacks.onRpcSuccess || function(){}; |
... | ... | @@ -56,7 +59,11 @@ export default class Subscription { |
56 | 59 | this.rpcEnabled = false; |
57 | 60 | this.executingRpcRequest = false; |
58 | 61 | this.executingPromises = []; |
59 | - this.initRpc(); | |
62 | + this.initRpc().then( | |
63 | + function() { | |
64 | + deferred.resolve(subscription); | |
65 | + } | |
66 | + ); | |
60 | 67 | } else { |
61 | 68 | this.callbacks.onDataUpdated = this.callbacks.onDataUpdated || function(){}; |
62 | 69 | this.callbacks.onDataUpdateError = this.callbacks.onDataUpdateError || function(){}; |
... | ... | @@ -103,11 +110,36 @@ export default class Subscription { |
103 | 110 | this.legendConfig.showMax === true || |
104 | 111 | this.legendConfig.showAvg === true || |
105 | 112 | this.legendConfig.showTotal === true); |
106 | - this.initDataSubscription(); | |
113 | + this.initDataSubscription().then( | |
114 | + function success() { | |
115 | + deferred.resolve(subscription); | |
116 | + }, | |
117 | + function fail() { | |
118 | + deferred.reject(); | |
119 | + } | |
120 | + ); | |
107 | 121 | } |
122 | + | |
123 | + return deferred.promise; | |
108 | 124 | } |
109 | 125 | |
110 | 126 | initDataSubscription() { |
127 | + var deferred = this.ctx.$q.defer(); | |
128 | + var subscription = this; | |
129 | + this.ctx.aliasController.resolveDatasources(this.datasources).then( | |
130 | + function success(datasources) { | |
131 | + subscription.datasources = datasources; | |
132 | + subscription.configureData(); | |
133 | + deferred.resolve(); | |
134 | + }, | |
135 | + function fail() { | |
136 | + deferred.reject(); | |
137 | + } | |
138 | + ); | |
139 | + return deferred.promise; | |
140 | + } | |
141 | + | |
142 | + configureData() { | |
111 | 143 | var dataIndex = 0; |
112 | 144 | for (var i = 0; i < this.datasources.length; i++) { |
113 | 145 | var datasource = this.datasources[i]; |
... | ... | @@ -199,21 +231,46 @@ export default class Subscription { |
199 | 231 | } |
200 | 232 | |
201 | 233 | initRpc() { |
234 | + var deferred = this.ctx.$q.defer(); | |
202 | 235 | if (this.targetDeviceAliasIds && this.targetDeviceAliasIds.length > 0) { |
203 | 236 | this.targetDeviceAliasId = this.targetDeviceAliasIds[0]; |
204 | - if (this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId]) { | |
205 | - this.targetDeviceId = this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId].entityId; | |
237 | + var subscription = this; | |
238 | + this.ctx.aliasController.getAliasInfo(this.targetDeviceAliasId).then( | |
239 | + function success(aliasInfo) { | |
240 | + if (aliasInfo.currentEntity && aliasInfo.currentEntity.entityType == subscription.ctx.types.entityType.device) { | |
241 | + subscription.targetDeviceId = aliasInfo.currentEntity.id; | |
242 | + if (subscription.targetDeviceId) { | |
243 | + subscription.rpcEnabled = true; | |
244 | + } else { | |
245 | + subscription.rpcEnabled = subscription.ctx.$scope.widgetEditMode ? true : false; | |
246 | + } | |
247 | + subscription.callbacks.rpcStateChanged(this); | |
248 | + deferred.resolve(); | |
249 | + } else { | |
250 | + subscription.rpcEnabled = false; | |
251 | + subscription.callbacks.rpcStateChanged(this); | |
252 | + deferred.resolve(); | |
253 | + } | |
254 | + }, | |
255 | + function fail () { | |
256 | + subscription.rpcEnabled = false; | |
257 | + subscription.callbacks.rpcStateChanged(this); | |
258 | + deferred.resolve(); | |
259 | + } | |
260 | + ); | |
261 | + } else { | |
262 | + if (this.targetDeviceIds && this.targetDeviceIds.length > 0) { | |
263 | + this.targetDeviceId = this.targetDeviceIds[0]; | |
206 | 264 | } |
207 | - } else if (this.targetDeviceIds && this.targetDeviceIds.length > 0) { | |
208 | - this.targetDeviceId = this.targetDeviceIds[0]; | |
209 | - } | |
210 | - | |
211 | - if (this.targetDeviceId) { | |
212 | - this.rpcEnabled = true; | |
213 | - } else { | |
214 | - this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false; | |
265 | + if (this.targetDeviceId) { | |
266 | + this.rpcEnabled = true; | |
267 | + } else { | |
268 | + this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false; | |
269 | + } | |
270 | + this.callbacks.rpcStateChanged(this); | |
271 | + deferred.resolve(); | |
215 | 272 | } |
216 | - this.callbacks.rpcStateChanged(this); | |
273 | + return deferred.promise; | |
217 | 274 | } |
218 | 275 | |
219 | 276 | clearRpcError() { |
... | ... | @@ -319,11 +376,11 @@ export default class Subscription { |
319 | 376 | this.onDataUpdated(); |
320 | 377 | } |
321 | 378 | |
322 | - onAliasesChanged() { | |
379 | + onAliasesChanged(aliasIds) { | |
323 | 380 | if (this.type === this.ctx.types.widgetType.rpc.value) { |
324 | - this.checkRpcTarget(); | |
381 | + return this.checkRpcTarget(aliasIds); | |
325 | 382 | } else { |
326 | - this.checkSubscriptions(); | |
383 | + return this.checkSubscriptions(aliasIds); | |
327 | 384 | } |
328 | 385 | } |
329 | 386 | |
... | ... | @@ -481,7 +538,7 @@ export default class Subscription { |
481 | 538 | var datasource = this.datasources[i]; |
482 | 539 | if (angular.isFunction(datasource)) |
483 | 540 | continue; |
484 | - var entityId = null; | |
541 | + /* var entityId = null; | |
485 | 542 | var entityType = null; |
486 | 543 | if (datasource.type === this.ctx.types.datasourceType.entity) { |
487 | 544 | var aliasName = null; |
... | ... | @@ -513,7 +570,7 @@ export default class Subscription { |
513 | 570 | } |
514 | 571 | for (var dk = 0; dk < datasource.dataKeys.length; dk++) { |
515 | 572 | updateDataKeyLabel(datasource.dataKeys[dk], datasource.name, entityName, aliasName); |
516 | - } | |
573 | + }*/ | |
517 | 574 | |
518 | 575 | var subscription = this; |
519 | 576 | |
... | ... | @@ -521,8 +578,8 @@ export default class Subscription { |
521 | 578 | subscriptionType: this.type, |
522 | 579 | subscriptionTimewindow: this.subscriptionTimewindow, |
523 | 580 | datasource: datasource, |
524 | - entityType: entityType, | |
525 | - entityId: entityId, | |
581 | + entityType: datasource.entityType, | |
582 | + entityId: datasource.entityId, | |
526 | 583 | dataUpdated: function (data, datasourceIndex, dataKeyIndex, apply) { |
527 | 584 | subscription.dataUpdated(data, datasourceIndex, dataKeyIndex, apply); |
528 | 585 | }, |
... | ... | @@ -557,8 +614,13 @@ export default class Subscription { |
557 | 614 | } |
558 | 615 | } |
559 | 616 | |
560 | - checkRpcTarget() { | |
561 | - var deviceId = null; | |
617 | + checkRpcTarget(aliasIds) { | |
618 | + if (aliasIds.indexOf(this.targetDeviceAliasId) > -1) { | |
619 | + return true; | |
620 | + } else { | |
621 | + return false; | |
622 | + } | |
623 | + /*var deviceId = null; | |
562 | 624 | if (this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId]) { |
563 | 625 | deviceId = this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId].entityId; |
564 | 626 | } |
... | ... | @@ -570,14 +632,20 @@ export default class Subscription { |
570 | 632 | this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false; |
571 | 633 | } |
572 | 634 | this.callbacks.rpcStateChanged(this); |
573 | - } | |
635 | + }*/ | |
574 | 636 | } |
575 | 637 | |
576 | - checkSubscriptions() { | |
638 | + checkSubscriptions(aliasIds) { | |
577 | 639 | var subscriptionsChanged = false; |
578 | 640 | for (var i = 0; i < this.datasourceListeners.length; i++) { |
579 | 641 | var listener = this.datasourceListeners[i]; |
580 | - var entityId = null; | |
642 | + if (listener.datasource.entityAliasId) { | |
643 | + if (aliasIds.indexOf(listener.datasource.entityAliasId) > -1) { | |
644 | + subscriptionsChanged = true; | |
645 | + break; | |
646 | + } | |
647 | + } | |
648 | + /*var entityId = null; | |
581 | 649 | var entityType = null; |
582 | 650 | var aliasName = null; |
583 | 651 | if (listener.datasource.type === this.ctx.types.datasourceType.entity) { |
... | ... | @@ -593,12 +661,13 @@ export default class Subscription { |
593 | 661 | subscriptionsChanged = true; |
594 | 662 | break; |
595 | 663 | } |
596 | - } | |
664 | + }*/ | |
597 | 665 | } |
598 | - if (subscriptionsChanged) { | |
666 | + return subscriptionsChanged; | |
667 | + /*if (subscriptionsChanged) { | |
599 | 668 | this.unsubscribe(); |
600 | 669 | this.subscribe(); |
601 | - } | |
670 | + }*/ | |
602 | 671 | } |
603 | 672 | |
604 | 673 | destroy() { |
... | ... | @@ -617,7 +686,7 @@ export default class Subscription { |
617 | 686 | |
618 | 687 | } |
619 | 688 | |
620 | -const varsRegex = /\$\{([^\}]*)\}/g; | |
689 | +/*const varsRegex = /\$\{([^\}]*)\}/g; | |
621 | 690 | |
622 | 691 | function updateDataKeyLabel(dataKey, dsName, entityName, aliasName) { |
623 | 692 | var pattern = dataKey.pattern; |
... | ... | @@ -638,7 +707,7 @@ function updateDataKeyLabel(dataKey, dsName, entityName, aliasName) { |
638 | 707 | match = varsRegex.exec(pattern); |
639 | 708 | } |
640 | 709 | dataKey.label = label; |
641 | -} | |
710 | +}*/ | |
642 | 711 | |
643 | 712 | function calculateMin(data) { |
644 | 713 | if (data.length > 0) { | ... | ... |
... | ... | @@ -40,39 +40,75 @@ function DashboardUtils(types, utils, timeService) { |
40 | 40 | return service; |
41 | 41 | |
42 | 42 | function validateAndUpdateEntityAliases(configuration) { |
43 | + var aliasId, entityAlias; | |
43 | 44 | if (angular.isUndefined(configuration.entityAliases)) { |
44 | 45 | configuration.entityAliases = {}; |
45 | 46 | if (configuration.deviceAliases) { |
46 | 47 | var deviceAliases = configuration.deviceAliases; |
47 | - for (var aliasId in deviceAliases) { | |
48 | + for (aliasId in deviceAliases) { | |
48 | 49 | var deviceAlias = deviceAliases[aliasId]; |
49 | - var alias = deviceAlias.alias; | |
50 | - var entityFilter = { | |
51 | - useFilter: false, | |
52 | - entityNameFilter: '', | |
53 | - entityList: [] | |
54 | - } | |
55 | - if (deviceAlias.deviceFilter) { | |
56 | - entityFilter.useFilter = deviceAlias.deviceFilter.useFilter; | |
57 | - entityFilter.entityNameFilter = deviceAlias.deviceFilter.deviceNameFilter; | |
58 | - entityFilter.entityList = deviceAlias.deviceFilter.deviceList; | |
59 | - } else if (deviceAlias.deviceId) { | |
60 | - entityFilter.entityList = [deviceAlias.deviceId]; | |
61 | - } | |
62 | - var entityAlias = { | |
63 | - id: aliasId, | |
64 | - alias: alias, | |
65 | - entityType: types.entityType.device, | |
66 | - entityFilter: entityFilter | |
67 | - }; | |
50 | + entityAlias = validateAndUpdateDeviceAlias(aliasId, deviceAlias); | |
68 | 51 | configuration.entityAliases[aliasId] = entityAlias; |
69 | 52 | } |
70 | 53 | delete configuration.deviceAliases; |
71 | 54 | } |
55 | + } else { | |
56 | + var entityAliases = configuration.entityAliases; | |
57 | + for (aliasId in entityAliases) { | |
58 | + entityAlias = entityAliases[aliasId]; | |
59 | + entityAliases[aliasId] = validateAndUpdateEntityAlias(entityAlias); | |
60 | + } | |
72 | 61 | } |
73 | 62 | return configuration; |
74 | 63 | } |
75 | 64 | |
65 | + function validateAndUpdateDeviceAlias(aliasId, deviceAlias) { | |
66 | + var alias = deviceAlias.alias; | |
67 | + var entityAlias = { | |
68 | + id: aliasId, | |
69 | + alias: alias, | |
70 | + filter: { | |
71 | + type: null, | |
72 | + entityType: types.entityType.device, | |
73 | + resolveMultiple: false | |
74 | + }, | |
75 | + } | |
76 | + if (deviceAlias.deviceFilter) { | |
77 | + entityAlias.filter.type = | |
78 | + deviceAlias.deviceFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value; | |
79 | + if (entityAlias.filter.type == types.aliasFilterType.entityList.value) { | |
80 | + entityAlias.filter.entityList = deviceAlias.deviceFilter.deviceList; | |
81 | + entityAlias.filter.stateEntity = false; | |
82 | + } else { | |
83 | + entityAlias.filter.entityNameFilter = deviceAlias.deviceFilter.deviceNameFilter; | |
84 | + } | |
85 | + } else { | |
86 | + entityAlias.filter.type = types.aliasFilterType.entityList.value; | |
87 | + entityAlias.filter.entityList = [deviceAlias.deviceId]; | |
88 | + entityAlias.filter.stateEntity = false; | |
89 | + } | |
90 | + return entityAlias; | |
91 | + } | |
92 | + | |
93 | + function validateAndUpdateEntityAlias(entityAlias) { | |
94 | + if (!entityAlias.filter) { | |
95 | + entityAlias.filter = { | |
96 | + type: entityAlias.entityFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value, | |
97 | + entityType: entityAlias.entityType, | |
98 | + resolveMultiple: false | |
99 | + } | |
100 | + if (entityAlias.filter.type == types.aliasFilterType.entityList.value) { | |
101 | + entityAlias.filter.entityList = entityAlias.entityFilter.entityList; | |
102 | + entityAlias.filter.stateEntity = false; | |
103 | + } else { | |
104 | + entityAlias.filter.entityNameFilter = entityAlias.entityFilter.entityNameFilter; | |
105 | + } | |
106 | + delete entityAlias.entityType; | |
107 | + delete entityAlias.entityFilter; | |
108 | + } | |
109 | + return entityAlias; | |
110 | + } | |
111 | + | |
76 | 112 | function validateAndUpdateWidget(widget) { |
77 | 113 | if (!widget.config) { |
78 | 114 | widget.config = {}; | ... | ... |
... | ... | @@ -65,6 +65,36 @@ export default angular.module('thingsboard.types', []) |
65 | 65 | clearedUnack: "CLEARED_UNACK", |
66 | 66 | clearedAck: "CLEARED_ACK" |
67 | 67 | }, |
68 | + aliasFilterType: { | |
69 | + entityList: { | |
70 | + value: 'entityList', | |
71 | + name: 'alias.filter-type-entity-list' | |
72 | + }, | |
73 | + entityName: { | |
74 | + value: 'entityName', | |
75 | + name: 'alias.filter-type-entity-name' | |
76 | + }, | |
77 | + assetType: { | |
78 | + value: 'assetType', | |
79 | + name: 'alias.filter-type-asset-type' | |
80 | + }, | |
81 | + deviceType: { | |
82 | + value: 'deviceType', | |
83 | + name: 'alias.filter-type-device-type' | |
84 | + }, | |
85 | + relationsQuery: { | |
86 | + value: 'relationsQuery', | |
87 | + name: 'alias.filter-type-relations-query' | |
88 | + }, | |
89 | + assetSearchQuery: { | |
90 | + value: 'assetSearchQuery', | |
91 | + name: 'alias.filter-type-asset-search-query' | |
92 | + }, | |
93 | + deviceSearchQuery: { | |
94 | + value: 'deviceSearchQuery', | |
95 | + name: 'alias.filter-type-device-search-query' | |
96 | + } | |
97 | + }, | |
68 | 98 | position: { |
69 | 99 | top: { |
70 | 100 | value: "top", | ... | ... |
... | ... | @@ -52,7 +52,7 @@ function Dashboard() { |
52 | 52 | bindToController: { |
53 | 53 | widgets: '=', |
54 | 54 | widgetLayouts: '=?', |
55 | - aliasesInfo: '=', | |
55 | + aliasController: '=', | |
56 | 56 | stateController: '=', |
57 | 57 | dashboardTimewindow: '=?', |
58 | 58 | columns: '=', |
... | ... | @@ -329,10 +329,6 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t |
329 | 329 | $scope.$broadcast('toggleDashboardEditMode', vm.isEdit); |
330 | 330 | }); |
331 | 331 | |
332 | - $scope.$watch('vm.aliasesInfo.entityAliases', function () { | |
333 | - $scope.$broadcast('entityAliasListChanged', vm.aliasesInfo); | |
334 | - }, true); | |
335 | - | |
336 | 332 | $scope.$on('gridster-resized', function (event, sizes, theGridster) { |
337 | 333 | if (checkIsLocalGridsterElement(theGridster)) { |
338 | 334 | vm.gridster = theGridster; | ... | ... |
... | ... | @@ -20,14 +20,14 @@ export default angular.module('thingsboard.dialogs.datakeyConfigDialog', [things |
20 | 20 | .name; |
21 | 21 | |
22 | 22 | /*@ngInject*/ |
23 | -function DatakeyConfigDialogController($scope, $mdDialog, entityService, dataKey, dataKeySettingsSchema, entityAlias, entityAliases) { | |
23 | +function DatakeyConfigDialogController($scope, $mdDialog, $q, entityService, dataKey, dataKeySettingsSchema, entityAlias, aliasController) { | |
24 | 24 | |
25 | 25 | var vm = this; |
26 | 26 | |
27 | 27 | vm.dataKey = dataKey; |
28 | 28 | vm.dataKeySettingsSchema = dataKeySettingsSchema; |
29 | 29 | vm.entityAlias = entityAlias; |
30 | - vm.entityAliases = entityAliases; | |
30 | + vm.aliasController = aliasController; | |
31 | 31 | |
32 | 32 | vm.hide = function () { |
33 | 33 | $mdDialog.hide(); |
... | ... | @@ -38,12 +38,28 @@ function DatakeyConfigDialogController($scope, $mdDialog, entityService, dataKey |
38 | 38 | }; |
39 | 39 | |
40 | 40 | vm.fetchEntityKeys = function (entityAliasId, query, type) { |
41 | - var alias = vm.entityAliases[entityAliasId]; | |
42 | - if (alias) { | |
43 | - return entityService.getEntityKeys(alias.entityType, alias.entityId, query, type); | |
44 | - } else { | |
45 | - return []; | |
46 | - } | |
41 | + var deferred = $q.defer(); | |
42 | + vm.aliasController.getAliasInfo(entityAliasId).then( | |
43 | + function success(aliasInfo) { | |
44 | + var entity = aliasInfo.currentEntity; | |
45 | + if (entity) { | |
46 | + entityService.getEntityKeys(entity.entityType, entity.id, query, type).then( | |
47 | + function success(keys) { | |
48 | + deferred.resolve(keys); | |
49 | + }, | |
50 | + function fail() { | |
51 | + deferred.resolve([]); | |
52 | + } | |
53 | + ); | |
54 | + } else { | |
55 | + deferred.resolve([]); | |
56 | + } | |
57 | + }, | |
58 | + function fail() { | |
59 | + deferred.resolve([]); | |
60 | + } | |
61 | + ); | |
62 | + return deferred.promise; | |
47 | 63 | }; |
48 | 64 | |
49 | 65 | vm.save = function () { | ... | ... |
... | ... | @@ -103,10 +103,9 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc |
103 | 103 | ngModelCtrl.$render = function () { |
104 | 104 | if (ngModelCtrl.$viewValue) { |
105 | 105 | var entityAliasId = ngModelCtrl.$viewValue.entityAliasId; |
106 | - if (scope.entityAliases[entityAliasId]) { | |
107 | - scope.entityAlias = {id: entityAliasId, alias: scope.entityAliases[entityAliasId].alias, | |
108 | - entityType: scope.entityAliases[entityAliasId].entityType, | |
109 | - entityId: scope.entityAliases[entityAliasId].entityId}; | |
106 | + var entityAliases = scope.aliasController.getEntityAliases(); | |
107 | + if (entityAliases[entityAliasId]) { | |
108 | + scope.entityAlias = entityAliases[entityAliasId]; | |
110 | 109 | } else { |
111 | 110 | scope.entityAlias = null; |
112 | 111 | } |
... | ... | @@ -182,7 +181,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc |
182 | 181 | dataKey: angular.copy(dataKey), |
183 | 182 | dataKeySettingsSchema: scope.datakeySettingsSchema, |
184 | 183 | entityAlias: scope.entityAlias, |
185 | - entityAliases: scope.entityAliases | |
184 | + aliasController: scope.aliasController | |
186 | 185 | }, |
187 | 186 | parent: angular.element($document[0].body), |
188 | 187 | fullscreen: true, |
... | ... | @@ -236,7 +235,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc |
236 | 235 | require: "^ngModel", |
237 | 236 | scope: { |
238 | 237 | widgetType: '=', |
239 | - entityAliases: '=', | |
238 | + aliasController: '=', | |
240 | 239 | datakeySettingsSchema: '=', |
241 | 240 | generateDataKey: '&', |
242 | 241 | fetchEntityKeys: '&', | ... | ... |
... | ... | @@ -18,7 +18,7 @@ |
18 | 18 | <section flex layout='column' layout-align="center" layout-gt-sm='row' layout-align-gt-sm="start center"> |
19 | 19 | <tb-entity-alias-select |
20 | 20 | tb-required="true" |
21 | - entity-aliases="entityAliases" | |
21 | + alias-controller="aliasController" | |
22 | 22 | ng-model="entityAlias" |
23 | 23 | on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias})"> |
24 | 24 | </tb-entity-alias-select> | ... | ... |
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | ng-switch-when="entity" |
38 | 38 | ng-required="model.type === types.datasourceType.entity" |
39 | 39 | widget-type="widgetType" |
40 | - entity-aliases="entityAliases" | |
40 | + alias-controller="aliasController" | |
41 | 41 | generate-data-key="generateDataKey({chip: chip, type: type})" |
42 | 42 | fetch-entity-keys="fetchEntityKeys({entityAliasId: entityAliasId, query: query, type: type})" |
43 | 43 | on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias})"> | ... | ... |
... | ... | @@ -31,7 +31,7 @@ export default angular.module('thingsboard.directives.entityAliasSelect', []) |
31 | 31 | .name; |
32 | 32 | |
33 | 33 | /*@ngInject*/ |
34 | -function EntityAliasSelect($compile, $templateCache, $mdConstant) { | |
34 | +function EntityAliasSelect($compile, $templateCache, $mdConstant, entityService) { | |
35 | 35 | |
36 | 36 | var linker = function (scope, element, attrs, ngModelCtrl) { |
37 | 37 | var template = $templateCache.get(entityAliasSelectTemplate); |
... | ... | @@ -49,19 +49,18 @@ function EntityAliasSelect($compile, $templateCache, $mdConstant) { |
49 | 49 | ngModelCtrl.$setValidity('entityAlias', valid); |
50 | 50 | }; |
51 | 51 | |
52 | - scope.$watch('entityAliases', function () { | |
52 | + scope.$watch('aliasController', function () { | |
53 | 53 | scope.entityAliasList = []; |
54 | - for (var aliasId in scope.entityAliases) { | |
54 | + var entityAliases = scope.aliasController.getEntityAliases(); | |
55 | + for (var aliasId in entityAliases) { | |
55 | 56 | if (scope.allowedEntityTypes) { |
56 | - if (scope.allowedEntityTypes.indexOf(scope.entityAliases[aliasId].entityType) === -1) { | |
57 | + if (!entityService.filterAliasByEntityTypes(entityAliases[aliasId], scope.allowedEntityTypes)) { | |
57 | 58 | continue; |
58 | 59 | } |
59 | 60 | } |
60 | - var entityAlias = {id: aliasId, alias: scope.entityAliases[aliasId].alias, | |
61 | - entityType: scope.entityAliases[aliasId].entityType, entityId: scope.entityAliases[aliasId].entityId}; | |
62 | - scope.entityAliasList.push(entityAlias); | |
61 | + scope.entityAliasList.push(entityAliases[aliasId]); | |
63 | 62 | } |
64 | - }, true); | |
63 | + }); | |
65 | 64 | |
66 | 65 | scope.$watch('entityAlias', function () { |
67 | 66 | scope.updateView(); |
... | ... | @@ -141,7 +140,7 @@ function EntityAliasSelect($compile, $templateCache, $mdConstant) { |
141 | 140 | link: linker, |
142 | 141 | scope: { |
143 | 142 | tbRequired: '=?', |
144 | - entityAliases: '=', | |
143 | + aliasController: '=', | |
145 | 144 | allowedEntityTypes: '=?', |
146 | 145 | onCreateEntityAlias: '&' |
147 | 146 | } | ... | ... |
... | ... | @@ -128,13 +128,9 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti |
128 | 128 | } else if (scope.widgetType === types.widgetType.rpc.value && scope.isDataEnabled) { |
129 | 129 | if (config.targetDeviceAliasIds && config.targetDeviceAliasIds.length > 0) { |
130 | 130 | var aliasId = config.targetDeviceAliasIds[0]; |
131 | - if (scope.entityAliases[aliasId]) { | |
132 | - scope.targetDeviceAlias.value = { | |
133 | - id: aliasId, | |
134 | - alias: scope.entityAliases[aliasId].alias, | |
135 | - entityType: scope.entityAliases[aliasId].entityType, | |
136 | - entityId: scope.entityAliases[aliasId].entityId | |
137 | - }; | |
131 | + var entityAliases = scope.aliasController.getEntityAliases(); | |
132 | + if (entityAliases[aliasId]) { | |
133 | + scope.targetDeviceAlias.value = entityAliases[aliasId]; | |
138 | 134 | } else { |
139 | 135 | scope.targetDeviceAlias.value = null; |
140 | 136 | } |
... | ... | @@ -395,7 +391,7 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti |
395 | 391 | widgetType: '=', |
396 | 392 | widgetSettingsSchema: '=', |
397 | 393 | datakeySettingsSchema: '=', |
398 | - entityAliases: '=', | |
394 | + aliasController: '=', | |
399 | 395 | functionsOnly: '=', |
400 | 396 | fetchEntityKeys: '&', |
401 | 397 | onCreateEntityAlias: '&', | ... | ... |
... | ... | @@ -60,7 +60,7 @@ |
60 | 60 | style="padding: 0 0 0 10px; margin: 5px;"> |
61 | 61 | <tb-datasource flex ng-model="datasource.value" |
62 | 62 | widget-type="widgetType" |
63 | - entity-aliases="entityAliases" | |
63 | + alias-controller="aliasController" | |
64 | 64 | functions-only="functionsOnly" |
65 | 65 | datakey-settings-schema="datakeySettingsSchema" |
66 | 66 | generate-data-key="generateDataKey(chip,type)" |
... | ... | @@ -104,7 +104,7 @@ |
104 | 104 | <v-pane-content style="padding: 0 5px;"> |
105 | 105 | <tb-entity-alias-select flex |
106 | 106 | tb-required="widgetType === types.widgetType.rpc.value && !widgetEditMode" |
107 | - entity-aliases="entityAliases" | |
107 | + alias-controller="aliasController" | |
108 | 108 | allowed-entity-types="[types.entityType.device]" |
109 | 109 | ng-model="targetDeviceAlias.value" |
110 | 110 | on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias, allowedEntityTypes: allowedEntityTypes})"> | ... | ... |
... | ... | @@ -22,7 +22,7 @@ import Subscription from '../api/subscription'; |
22 | 22 | /*@ngInject*/ |
23 | 23 | export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, $filter, tbRaf, types, utils, timeService, |
24 | 24 | datasourceService, entityService, deviceService, visibleRect, isEdit, stDiff, dashboardTimewindow, |
25 | - dashboardTimewindowApi, widget, aliasesInfo, stateController, widgetType) { | |
25 | + dashboardTimewindowApi, widget, aliasController, stateController, widgetType) { | |
26 | 26 | |
27 | 27 | var vm = this; |
28 | 28 | |
... | ... | @@ -37,6 +37,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
37 | 37 | $scope.executingRpcRequest = false; |
38 | 38 | |
39 | 39 | var gridsterItemInited = false; |
40 | + var subscriptionInited = false; | |
40 | 41 | |
41 | 42 | var cafs = {}; |
42 | 43 | |
... | ... | @@ -149,7 +150,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
149 | 150 | dashboardTimewindowApi: dashboardTimewindowApi, |
150 | 151 | types: types, |
151 | 152 | stDiff: stDiff, |
152 | - aliasesInfo: aliasesInfo | |
153 | + aliasController: aliasController | |
153 | 154 | }; |
154 | 155 | |
155 | 156 | var widgetTypeInstance; |
... | ... | @@ -203,8 +204,13 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
203 | 204 | |
204 | 205 | vm.gridsterItemInitialized = gridsterItemInitialized; |
205 | 206 | |
206 | - initialize(); | |
207 | - | |
207 | + initialize().then( | |
208 | + function(){ | |
209 | + if (checkSize()) { | |
210 | + onInit(); | |
211 | + } | |
212 | + } | |
213 | + ); | |
208 | 214 | |
209 | 215 | /* |
210 | 216 | options = { |
... | ... | @@ -233,28 +239,42 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
233 | 239 | } |
234 | 240 | } |
235 | 241 | |
236 | - entityService.createDatasoucesFromSubscriptionsInfo(subscriptionsInfo).then( | |
242 | + entityService.createDatasourcesFromSubscriptionsInfo(subscriptionsInfo).then( | |
237 | 243 | function (datasources) { |
238 | 244 | options.datasources = datasources; |
239 | - var subscription = createSubscription(options, subscribe); | |
240 | - if (useDefaultComponents) { | |
241 | - defaultSubscriptionOptions(subscription, options); | |
242 | - } | |
243 | - deferred.resolve(subscription); | |
245 | + createSubscription(options, subscribe).then( | |
246 | + function success(subscription) { | |
247 | + if (useDefaultComponents) { | |
248 | + defaultSubscriptionOptions(subscription, options); | |
249 | + } | |
250 | + deferred.resolve(subscription); | |
251 | + }, | |
252 | + function fail() { | |
253 | + deferred.reject(); | |
254 | + } | |
255 | + ); | |
244 | 256 | } |
245 | 257 | ); |
246 | 258 | return deferred.promise; |
247 | 259 | } |
248 | 260 | |
249 | 261 | function createSubscription(options, subscribe) { |
262 | + var deferred = $q.defer(); | |
250 | 263 | options.dashboardTimewindow = dashboardTimewindow; |
251 | - var subscription = | |
252 | - new Subscription(subscriptionContext, options); | |
253 | - widgetContext.subscriptions[subscription.id] = subscription; | |
254 | - if (subscribe) { | |
255 | - subscription.subscribe(); | |
256 | - } | |
257 | - return subscription; | |
264 | + new Subscription(subscriptionContext, options).then( | |
265 | + function success(subscription) { | |
266 | + widgetContext.subscriptions[subscription.id] = subscription; | |
267 | + if (subscribe) { | |
268 | + subscription.subscribe(); | |
269 | + } | |
270 | + deferred.resolve(subscription); | |
271 | + }, | |
272 | + function fail() { | |
273 | + deferred.reject(); | |
274 | + } | |
275 | + ); | |
276 | + | |
277 | + return deferred.promise; | |
258 | 278 | } |
259 | 279 | |
260 | 280 | function defaultComponentsOptions(options) { |
... | ... | @@ -310,8 +330,8 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
310 | 330 | } |
311 | 331 | |
312 | 332 | function createDefaultSubscription() { |
313 | - var subscription; | |
314 | 333 | var options; |
334 | + var deferred = $q.defer(); | |
315 | 335 | if (widget.type !== types.widgetType.rpc.value && widget.type !== types.widgetType.static.value) { |
316 | 336 | options = { |
317 | 337 | type: widget.type, |
... | ... | @@ -319,16 +339,23 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
319 | 339 | }; |
320 | 340 | defaultComponentsOptions(options); |
321 | 341 | |
322 | - subscription = createSubscription(options); | |
323 | - | |
324 | - defaultSubscriptionOptions(subscription, options); | |
342 | + createSubscription(options).then( | |
343 | + function success(subscription) { | |
344 | + defaultSubscriptionOptions(subscription, options); | |
325 | 345 | |
326 | - // backward compatibility | |
346 | + // backward compatibility | |
327 | 347 | |
328 | - widgetContext.datasources = subscription.datasources; | |
329 | - widgetContext.data = subscription.data; | |
330 | - widgetContext.hiddenData = subscription.hiddenData; | |
331 | - widgetContext.timeWindow = subscription.timeWindow; | |
348 | + widgetContext.datasources = subscription.datasources; | |
349 | + widgetContext.data = subscription.data; | |
350 | + widgetContext.hiddenData = subscription.hiddenData; | |
351 | + widgetContext.timeWindow = subscription.timeWindow; | |
352 | + widgetContext.defaultSubscription = subscription; | |
353 | + deferred.resolve(); | |
354 | + }, | |
355 | + function fail() { | |
356 | + deferred.reject(); | |
357 | + } | |
358 | + ); | |
332 | 359 | |
333 | 360 | } else if (widget.type === types.widgetType.rpc.value) { |
334 | 361 | $scope.loadingData = false; |
... | ... | @@ -356,24 +383,27 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
356 | 383 | $scope.rpcRejection = null; |
357 | 384 | } |
358 | 385 | } |
359 | - subscription = createSubscription(options); | |
386 | + createSubscription(options).then( | |
387 | + function success(subscription) { | |
388 | + widgetContext.defaultSubscription = subscription; | |
389 | + deferred.resolve(); | |
390 | + }, | |
391 | + function fail() { | |
392 | + deferred.reject(); | |
393 | + } | |
394 | + ); | |
360 | 395 | } else if (widget.type === types.widgetType.static.value) { |
361 | 396 | $scope.loadingData = false; |
397 | + deferred.resolve(); | |
398 | + } else { | |
399 | + deferred.resolve(); | |
362 | 400 | } |
363 | - if (subscription) { | |
364 | - widgetContext.defaultSubscription = subscription; | |
365 | - } | |
401 | + return deferred.promise; | |
366 | 402 | } |
367 | 403 | |
368 | 404 | |
369 | 405 | function initialize() { |
370 | 406 | |
371 | - if (!vm.useCustomDatasources) { | |
372 | - createDefaultSubscription(); | |
373 | - } else { | |
374 | - $scope.loadingData = false; | |
375 | - } | |
376 | - | |
377 | 407 | $scope.$on('toggleDashboardEditMode', function (event, isEdit) { |
378 | 408 | onEditModeChanged(isEdit); |
379 | 409 | }); |
... | ... | @@ -398,11 +428,14 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
398 | 428 | onMobileModeChanged(newIsMobile); |
399 | 429 | }); |
400 | 430 | |
401 | - $scope.$on('entityAliasListChanged', function (event, aliasesInfo) { | |
402 | - subscriptionContext.aliasesInfo = aliasesInfo; | |
431 | + $scope.$on('entityAliasesChanged', function (event, aliasIds) { | |
432 | + var subscriptionChanged = false; | |
403 | 433 | for (var id in widgetContext.subscriptions) { |
404 | 434 | var subscription = widgetContext.subscriptions[id]; |
405 | - subscription.onAliasesChanged(); | |
435 | + subscriptionChanged = subscriptionChanged || subscription.onAliasesChanged(aliasIds); | |
436 | + } | |
437 | + if (subscriptionChanged && !vm.useCustomDatasources) { | |
438 | + reInit(); | |
406 | 439 | } |
407 | 440 | }); |
408 | 441 | |
... | ... | @@ -410,6 +443,44 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
410 | 443 | removeResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef |
411 | 444 | onDestroy(); |
412 | 445 | }); |
446 | + | |
447 | + var deferred = $q.defer(); | |
448 | + if (!vm.useCustomDatasources) { | |
449 | + createDefaultSubscription().then( | |
450 | + function success() { | |
451 | + subscriptionInited = true; | |
452 | + deferred.resolve(); | |
453 | + }, | |
454 | + function fail() { | |
455 | + subscriptionInited = true; | |
456 | + deferred.reject(); | |
457 | + } | |
458 | + ); | |
459 | + } else { | |
460 | + $scope.loadingData = false; | |
461 | + subscriptionInited = true; | |
462 | + deferred.resolve(); | |
463 | + } | |
464 | + return deferred.promise; | |
465 | + } | |
466 | + | |
467 | + function reInit() { | |
468 | + onDestroy(); | |
469 | + if (!vm.useCustomDatasources) { | |
470 | + createDefaultSubscription().then( | |
471 | + function success() { | |
472 | + subscriptionInited = true; | |
473 | + onInit(); | |
474 | + }, | |
475 | + function fail() { | |
476 | + subscriptionInited = true; | |
477 | + onInit(); | |
478 | + } | |
479 | + ); | |
480 | + } else { | |
481 | + subscriptionInited = true; | |
482 | + onInit(); | |
483 | + } | |
413 | 484 | } |
414 | 485 | |
415 | 486 | function handleWidgetException(e) { |
... | ... | @@ -418,7 +489,9 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
418 | 489 | } |
419 | 490 | |
420 | 491 | function onInit() { |
421 | - if (!widgetContext.inited) { | |
492 | + if (!widgetContext.inited && | |
493 | + subscriptionInited && | |
494 | + gridsterItemInited) { | |
422 | 495 | widgetContext.inited = true; |
423 | 496 | try { |
424 | 497 | widgetTypeInstance.onInit(); |
... | ... | @@ -462,7 +535,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
462 | 535 | handleWidgetException(e); |
463 | 536 | } |
464 | 537 | }); |
465 | - } else if (gridsterItemInited) { | |
538 | + } else { | |
466 | 539 | onInit(); |
467 | 540 | } |
468 | 541 | } |
... | ... | @@ -544,6 +617,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q |
544 | 617 | var subscription = widgetContext.subscriptions[id]; |
545 | 618 | subscription.destroy(); |
546 | 619 | } |
620 | + subscriptionInited = false; | |
547 | 621 | widgetContext.subscriptions = []; |
548 | 622 | if (widgetContext.inited) { |
549 | 623 | widgetContext.inited = false; | ... | ... |
... | ... | @@ -20,12 +20,13 @@ import entityAliasesTemplate from '../entity/entity-aliases.tpl.html'; |
20 | 20 | /* eslint-enable import/no-unresolved, import/default */ |
21 | 21 | |
22 | 22 | /*@ngInject*/ |
23 | -export default function AddWidgetController($scope, widgetService, entityService, $mdDialog, $q, $document, types, dashboard, aliasesInfo, widget, widgetInfo) { | |
23 | +export default function AddWidgetController($scope, widgetService, entityService, $mdDialog, $q, $document, types, dashboard, | |
24 | + aliasController, widget, widgetInfo) { | |
24 | 25 | |
25 | 26 | var vm = this; |
26 | 27 | |
27 | 28 | vm.dashboard = dashboard; |
28 | - vm.aliasesInfo = aliasesInfo; | |
29 | + vm.aliasController = aliasController; | |
29 | 30 | vm.widget = widget; |
30 | 31 | vm.widgetInfo = widgetInfo; |
31 | 32 | |
... | ... | @@ -85,7 +86,7 @@ export default function AddWidgetController($scope, widgetService, entityService |
85 | 86 | } |
86 | 87 | |
87 | 88 | function cancel () { |
88 | - $mdDialog.cancel({aliasesInfo: vm.aliasesInfo}); | |
89 | + $mdDialog.cancel(); | |
89 | 90 | } |
90 | 91 | |
91 | 92 | function add () { |
... | ... | @@ -94,23 +95,39 @@ export default function AddWidgetController($scope, widgetService, entityService |
94 | 95 | vm.widget.config = vm.widgetConfig.config; |
95 | 96 | vm.widget.config.mobileOrder = vm.widgetConfig.layout.mobileOrder; |
96 | 97 | vm.widget.config.mobileHeight = vm.widgetConfig.layout.mobileHeight; |
97 | - $mdDialog.hide({widget: vm.widget, aliasesInfo: vm.aliasesInfo}); | |
98 | + $mdDialog.hide({widget: vm.widget}); | |
98 | 99 | } |
99 | 100 | } |
100 | 101 | |
101 | 102 | function fetchEntityKeys (entityAliasId, query, type) { |
102 | - var entityAlias = vm.aliasesInfo.entityAliases[entityAliasId]; | |
103 | - if (entityAlias && entityAlias.entityId) { | |
104 | - return entityService.getEntityKeys(entityAlias.entityType, entityAlias.entityId, query, type); | |
105 | - } else { | |
106 | - return $q.when([]); | |
107 | - } | |
103 | + var deferred = $q.defer(); | |
104 | + vm.aliasController.getAliasInfo(entityAliasId).then( | |
105 | + function success(aliasInfo) { | |
106 | + var entity = aliasInfo.currentEntity; | |
107 | + if (entity) { | |
108 | + entityService.getEntityKeys(entity.entityType, entity.id, query, type).then( | |
109 | + function success(keys) { | |
110 | + deferred.resolve(keys); | |
111 | + }, | |
112 | + function fail() { | |
113 | + deferred.resolve([]); | |
114 | + } | |
115 | + ); | |
116 | + } else { | |
117 | + deferred.resolve([]); | |
118 | + } | |
119 | + }, | |
120 | + function fail() { | |
121 | + deferred.resolve([]); | |
122 | + } | |
123 | + ); | |
124 | + return deferred.promise; | |
108 | 125 | } |
109 | 126 | |
110 | 127 | function createEntityAlias (event, alias, allowedEntityTypes) { |
111 | 128 | |
112 | 129 | var deferred = $q.defer(); |
113 | - var singleEntityAlias = {id: null, alias: alias, entityType: types.entityType.device, entityFilter: null}; | |
130 | + var singleEntityAlias = {id: null, alias: alias, filter: {}}; | |
114 | 131 | |
115 | 132 | $mdDialog.show({ |
116 | 133 | controller: 'EntityAliasesController', |
... | ... | @@ -130,16 +147,9 @@ export default function AddWidgetController($scope, widgetService, entityService |
130 | 147 | skipHide: true, |
131 | 148 | targetEvent: event |
132 | 149 | }).then(function (singleEntityAlias) { |
133 | - vm.dashboard.configuration.entityAliases[singleEntityAlias.id] = | |
134 | - { alias: singleEntityAlias.alias, entityType: singleEntityAlias.entityType, entityFilter: singleEntityAlias.entityFilter }; | |
135 | - entityService.processEntityAliases(vm.dashboard.configuration.entityAliases).then( | |
136 | - function(resolution) { | |
137 | - if (!resolution.error) { | |
138 | - vm.aliasesInfo = resolution.aliasesInfo; | |
139 | - } | |
140 | - deferred.resolve(singleEntityAlias); | |
141 | - } | |
142 | - ); | |
150 | + vm.dashboard.configuration.entityAliases[singleEntityAlias.id] = singleEntityAlias; | |
151 | + vm.aliasController.updateEntityAliases(vm.dashboard.configuration.entityAliases); | |
152 | + deferred.resolve(singleEntityAlias); | |
143 | 153 | }, function () { |
144 | 154 | deferred.reject(); |
145 | 155 | }); | ... | ... |
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | ng-model="vm.widgetConfig" |
38 | 38 | widget-settings-schema="vm.settingsSchema" |
39 | 39 | datakey-settings-schema="vm.dataKeySettingsSchema" |
40 | - entity-aliases="vm.aliasesInfo.entityAliases" | |
40 | + alias-controller="vm.aliasController" | |
41 | 41 | functions-only="vm.functionsOnly" |
42 | 42 | fetch-entity-keys="vm.fetchEntityKeys(entityAliasId, query, type)" |
43 | 43 | on-create-entity-alias="vm.createEntityAlias(event, alias, allowedEntityTypes)" | ... | ... |
... | ... | @@ -24,8 +24,10 @@ import selectTargetLayoutTemplate from './layouts/select-target-layout.tpl.html' |
24 | 24 | |
25 | 25 | /* eslint-enable import/no-unresolved, import/default */ |
26 | 26 | |
27 | +import AliasController from '../api/alias-controller'; | |
28 | + | |
27 | 29 | /*@ngInject*/ |
28 | -export default function DashboardController(types, dashboardUtils, widgetService, userService, | |
30 | +export default function DashboardController(types, utils, dashboardUtils, widgetService, userService, | |
29 | 31 | dashboardService, timeService, entityService, itembuffer, importExport, hotkeys, $window, $rootScope, |
30 | 32 | $scope, $element, $state, $stateParams, $mdDialog, $mdMedia, $timeout, $document, $q, $translate, $filter) { |
31 | 33 | |
... | ... | @@ -349,7 +351,13 @@ export default function DashboardController(types, dashboardUtils, widgetService |
349 | 351 | dashboardService.getDashboard($stateParams.dashboardId) |
350 | 352 | .then(function success(dashboard) { |
351 | 353 | vm.dashboard = dashboardUtils.validateAndUpdateDashboard(dashboard); |
352 | - entityService.processEntityAliases(vm.dashboard.configuration.entityAliases) | |
354 | + vm.dashboardConfiguration = vm.dashboard.configuration; | |
355 | + vm.dashboardCtx.dashboard = vm.dashboard; | |
356 | + vm.dashboardCtx.dashboardTimewindow = vm.dashboardConfiguration.timewindow; | |
357 | + vm.dashboardCtx.aliasController = new AliasController($scope, $q, $filter, utils, | |
358 | + types, entityService, vm.dashboardCtx.stateController, vm.dashboardConfiguration.entityAliases); | |
359 | + | |
360 | + /* entityService.processEntityAliases(vm.dashboard.configuration.entityAliases) | |
353 | 361 | .then( |
354 | 362 | function(resolution) { |
355 | 363 | if (resolution.error && !isTenantAdmin()) { |
... | ... | @@ -362,7 +370,7 @@ export default function DashboardController(types, dashboardUtils, widgetService |
362 | 370 | vm.dashboardCtx.dashboardTimewindow = vm.dashboardConfiguration.timewindow; |
363 | 371 | } |
364 | 372 | } |
365 | - ); | |
373 | + );*/ | |
366 | 374 | }, function fail() { |
367 | 375 | vm.configurationError = true; |
368 | 376 | }); |
... | ... | @@ -373,6 +381,7 @@ export default function DashboardController(types, dashboardUtils, widgetService |
373 | 381 | var layoutsData = dashboardUtils.getStateLayoutsData(vm.dashboard, state); |
374 | 382 | if (layoutsData) { |
375 | 383 | vm.dashboardCtx.state = state; |
384 | + vm.dashboardCtx.aliasController.dashboardStateChanged(); | |
376 | 385 | var layoutVisibilityChanged = false; |
377 | 386 | for (var l in vm.layouts) { |
378 | 387 | var layout = vm.layouts[l]; |
... | ... | @@ -916,7 +925,7 @@ export default function DashboardController(types, dashboardUtils, widgetService |
916 | 925 | templateUrl: addWidgetTemplate, |
917 | 926 | locals: { |
918 | 927 | dashboard: vm.dashboard, |
919 | - aliasesInfo: vm.dashboardCtx.aliasesInfo, | |
928 | + aliasController: vm.dashboardCtx.aliasController, | |
920 | 929 | widget: newWidget, |
921 | 930 | widgetInfo: widgetTypeInfo |
922 | 931 | }, |
... | ... | @@ -930,10 +939,8 @@ export default function DashboardController(types, dashboardUtils, widgetService |
930 | 939 | } |
931 | 940 | }).then(function (result) { |
932 | 941 | var widget = result.widget; |
933 | - vm.dashboardCtx.aliasesInfo = result.aliasesInfo; | |
934 | 942 | addWidget(widget); |
935 | - }, function (rejection) { | |
936 | - vm.dashboardCtx.aliasesInfo = rejection.aliasesInfo; | |
943 | + }, function () { | |
937 | 944 | }); |
938 | 945 | } |
939 | 946 | } |
... | ... | @@ -1025,7 +1032,7 @@ export default function DashboardController(types, dashboardUtils, widgetService |
1025 | 1032 | notifyDashboardUpdated(); |
1026 | 1033 | } |
1027 | 1034 | |
1028 | - function showAliasesResolutionError(error) { | |
1035 | +/* function showAliasesResolutionError(error) { | |
1029 | 1036 | var alert = $mdDialog.alert() |
1030 | 1037 | .parent(angular.element($document[0].body)) |
1031 | 1038 | .clickOutsideToClose(true) |
... | ... | @@ -1037,20 +1044,10 @@ export default function DashboardController(types, dashboardUtils, widgetService |
1037 | 1044 | alert._options.fullscreen = true; |
1038 | 1045 | |
1039 | 1046 | $mdDialog.show(alert); |
1040 | - } | |
1047 | + }*/ | |
1041 | 1048 | |
1042 | 1049 | function entityAliasesUpdated() { |
1043 | - var deferred = $q.defer(); | |
1044 | - entityService.processEntityAliases(vm.dashboard.configuration.entityAliases) | |
1045 | - .then( | |
1046 | - function(resolution) { | |
1047 | - if (resolution.aliasesInfo) { | |
1048 | - vm.dashboardCtx.aliasesInfo = resolution.aliasesInfo; | |
1049 | - } | |
1050 | - deferred.resolve(); | |
1051 | - } | |
1052 | - ); | |
1053 | - return deferred.promise; | |
1050 | + vm.dashboardCtx.aliasController.updateEntityAliases(vm.dashboard.configuration.entityAliases); | |
1054 | 1051 | } |
1055 | 1052 | |
1056 | 1053 | function notifyDashboardUpdated() { | ... | ... |
... | ... | @@ -57,8 +57,7 @@ |
57 | 57 | </tb-timewindow> |
58 | 58 | <tb-aliases-entity-select ng-show="!vm.isEdit && vm.displayEntitiesSelect()" |
59 | 59 | tooltip-direction="bottom" |
60 | - ng-model="vm.dashboardCtx.aliasesInfo.entityAliases" | |
61 | - entity-aliases-info="vm.dashboardCtx.aliasesInfo.entityAliasesInfo"> | |
60 | + alias-controller="vm.dashboardCtx.aliasController"> | |
62 | 61 | </tb-aliases-entity-select> |
63 | 62 | <md-button ng-show="vm.isEdit" aria-label="{{ 'entity.aliases' | translate }}" class="md-icon-button" |
64 | 63 | ng-click="vm.openEntityAliases($event)"> |
... | ... | @@ -179,7 +178,7 @@ |
179 | 178 | <form name="vm.widgetForm" ng-if="vm.isEditingWidget"> |
180 | 179 | <tb-edit-widget |
181 | 180 | dashboard="vm.dashboard" |
182 | - aliases-info="vm.dashboardCtx.aliasesInfo" | |
181 | + alias-controller="vm.dashboardCtx.aliasController" | |
183 | 182 | widget="vm.editingWidget" |
184 | 183 | widget-layout="vm.editingWidgetLayout" |
185 | 184 | the-form="vm.widgetForm"> | ... | ... |
... | ... | @@ -68,18 +68,34 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid |
68 | 68 | }); |
69 | 69 | |
70 | 70 | scope.fetchEntityKeys = function (entityAliasId, query, type) { |
71 | - var entityAlias = scope.aliasesInfo.entityAliases[entityAliasId]; | |
72 | - if (entityAlias && entityAlias.entityId) { | |
73 | - return entityService.getEntityKeys(entityAlias.entityType, entityAlias.entityId, query, type); | |
74 | - } else { | |
75 | - return $q.when([]); | |
76 | - } | |
71 | + var deferred = $q.defer(); | |
72 | + scope.aliasController.getAliasInfo(entityAliasId).then( | |
73 | + function success(aliasInfo) { | |
74 | + var entity = aliasInfo.currentEntity; | |
75 | + if (entity) { | |
76 | + entityService.getEntityKeys(entity.entityType, entity.id, query, type).then( | |
77 | + function success(keys) { | |
78 | + deferred.resolve(keys); | |
79 | + }, | |
80 | + function fail() { | |
81 | + deferred.resolve([]); | |
82 | + } | |
83 | + ); | |
84 | + } else { | |
85 | + deferred.resolve([]); | |
86 | + } | |
87 | + }, | |
88 | + function fail() { | |
89 | + deferred.resolve([]); | |
90 | + } | |
91 | + ); | |
92 | + return deferred.promise; | |
77 | 93 | }; |
78 | 94 | |
79 | 95 | scope.createEntityAlias = function (event, alias, allowedEntityTypes) { |
80 | 96 | |
81 | 97 | var deferred = $q.defer(); |
82 | - var singleEntityAlias = {id: null, alias: alias, entityType: types.entityType.device, entityFilter: null}; | |
98 | + var singleEntityAlias = {id: null, alias: alias, filter: {}}; | |
83 | 99 | |
84 | 100 | $mdDialog.show({ |
85 | 101 | controller: 'EntityAliasesController', |
... | ... | @@ -99,16 +115,9 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid |
99 | 115 | skipHide: true, |
100 | 116 | targetEvent: event |
101 | 117 | }).then(function (singleEntityAlias) { |
102 | - scope.dashboard.configuration.entityAliases[singleEntityAlias.id] = | |
103 | - { alias: singleEntityAlias.alias, entityType: singleEntityAlias.entityType, entityFilter: singleEntityAlias.entityFilter }; | |
104 | - entityService.processEntityAliases(scope.dashboard.configuration.entityAliases).then( | |
105 | - function(resolution) { | |
106 | - if (!resolution.error) { | |
107 | - scope.aliasesInfo = resolution.aliasesInfo; | |
108 | - } | |
109 | - deferred.resolve(singleEntityAlias); | |
110 | - } | |
111 | - ); | |
118 | + scope.dashboard.configuration.entityAliases[singleEntityAlias.id] = singleEntityAlias; | |
119 | + scope.aliasController.updateEntityAliases(scope.dashboard.configuration.entityAliases); | |
120 | + deferred.resolve(singleEntityAlias); | |
112 | 121 | }, function () { |
113 | 122 | deferred.reject(); |
114 | 123 | }); |
... | ... | @@ -124,7 +133,7 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid |
124 | 133 | link: linker, |
125 | 134 | scope: { |
126 | 135 | dashboard: '=', |
127 | - aliasesInfo: '=', | |
136 | + aliasController: '=', | |
128 | 137 | widget: '=', |
129 | 138 | widgetLayout: '=', |
130 | 139 | theForm: '=' | ... | ... |
... | ... | @@ -21,7 +21,7 @@ |
21 | 21 | is-data-enabled="isDataEnabled" |
22 | 22 | widget-settings-schema="settingsSchema" |
23 | 23 | datakey-settings-schema="dataKeySettingsSchema" |
24 | - entity-aliases="aliasesInfo.entityAliases" | |
24 | + alias-controller="aliasController" | |
25 | 25 | functions-only="functionsOnly" |
26 | 26 | fetch-entity-keys="fetchEntityKeys(entityAliasId, query, type)" |
27 | 27 | on-create-entity-alias="createEntityAlias(event, alias, allowedEntityTypes)" | ... | ... |
... | ... | @@ -45,7 +45,7 @@ |
45 | 45 | widget-layouts="vm.layoutCtx.widgetLayouts" |
46 | 46 | columns="vm.layoutCtx.gridSettings.columns" |
47 | 47 | margins="vm.layoutCtx.gridSettings.margins" |
48 | - aliases-info="vm.dashboardCtx.aliasesInfo" | |
48 | + alias-controller="vm.dashboardCtx.aliasController" | |
49 | 49 | state-controller="vm.dashboardCtx.stateController" |
50 | 50 | dashboard-timewindow="vm.dashboardCtx.dashboardTimewindow" |
51 | 51 | is-edit="vm.isEdit" | ... | ... |
... | ... | @@ -15,17 +15,30 @@ |
15 | 15 | */ |
16 | 16 | |
17 | 17 | /*@ngInject*/ |
18 | -export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, types, entityAliases, entityAliasesInfo, onEntityAliasesUpdate) { | |
18 | +export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, types, aliasController, onEntityAliasesUpdate) { | |
19 | 19 | |
20 | 20 | var vm = this; |
21 | 21 | vm._mdPanelRef = mdPanelRef; |
22 | - vm.entityAliases = entityAliases; | |
23 | - vm.entityAliasesInfo = entityAliasesInfo; | |
22 | + vm.aliasController = aliasController; | |
24 | 23 | vm.onEntityAliasesUpdate = onEntityAliasesUpdate; |
24 | + vm.entityAliases = {}; | |
25 | + vm.entityAliasesInfo = {}; | |
25 | 26 | |
26 | - $scope.$watch('vm.entityAliases', function () { | |
27 | + vm.currentAliasEntityChanged = currentAliasEntityChanged; | |
28 | + | |
29 | + var allEntityAliases = vm.aliasController.getEntityAliases(); | |
30 | + for (var aliasId in allEntityAliases) { | |
31 | + var aliasInfo = vm.aliasController.getInstantAliasInfo(aliasId); | |
32 | + if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity) { | |
33 | + vm.entityAliasesInfo[aliasId] = angular.copy(aliasInfo); | |
34 | + } | |
35 | + } | |
36 | + | |
37 | + function currentAliasEntityChanged(aliasId, currentEntity) { | |
38 | + vm.aliasController.updateCurrentAliasEntity(aliasId, currentEntity); | |
27 | 39 | if (onEntityAliasesUpdate) { |
28 | - onEntityAliasesUpdate(vm.entityAliases); | |
40 | + onEntityAliasesUpdate(); | |
29 | 41 | } |
30 | - }, true); | |
42 | + } | |
43 | + | |
31 | 44 | } | ... | ... |
... | ... | @@ -18,12 +18,12 @@ |
18 | 18 | <md-content flex layout="column"> |
19 | 19 | <section flex layout="column"> |
20 | 20 | <md-content flex class="md-padding" layout="column"> |
21 | - <div flex layout="row" ng-repeat="(aliasId, entityAlias) in vm.entityAliases"> | |
21 | + <div flex layout="row" ng-repeat="(aliasId, entityAliasInfo) in vm.entityAliasesInfo"> | |
22 | 22 | <md-input-container flex> |
23 | - <label>{{entityAlias.alias}}</label> | |
24 | - <md-select ng-model="vm.entityAliases[aliasId].entityId"> | |
25 | - <md-option ng-repeat="entityInfo in vm.entityAliasesInfo[aliasId]" ng-value="entityInfo.id"> | |
26 | - {{entityInfo.name}} | |
23 | + <label>{{entityAliasInfo.alias}}</label> | |
24 | + <md-select ng-model="entityAliasInfo.currentEntity" ng-change="vm.currentAliasEntityChanged(aliasId, entityAliasInfo.currentEntity)"> | |
25 | + <md-option ng-repeat="resolvedEntity in entityAliasInfo.resolvedEntities" ng-value="resolvedEntity"> | |
26 | + {{resolvedEntity.name}} | |
27 | 27 | </md-option> |
28 | 28 | </md-select> |
29 | 29 | </md-input-container> | ... | ... |
... | ... | @@ -29,7 +29,7 @@ import aliasesEntitySelectPanelTemplate from './aliases-entity-select-panel.tpl. |
29 | 29 | /*@ngInject*/ |
30 | 30 | export default function AliasesEntitySelectDirective($compile, $templateCache, $mdMedia, types, $mdPanel, $document, $translate) { |
31 | 31 | |
32 | - var linker = function (scope, element, attrs, ngModelCtrl) { | |
32 | + var linker = function (scope, element, attrs) { | |
33 | 33 | |
34 | 34 | /* tbAliasesEntitySelect (ng-model) |
35 | 35 | * { |
... | ... | @@ -81,10 +81,8 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $ |
81 | 81 | position: position, |
82 | 82 | fullscreen: false, |
83 | 83 | locals: { |
84 | - 'entityAliases': angular.copy(scope.model), | |
85 | - 'entityAliasesInfo': scope.entityAliasesInfo, | |
86 | - 'onEntityAliasesUpdate': function (entityAliases) { | |
87 | - scope.model = entityAliases; | |
84 | + 'aliasController': scope.aliasController, | |
85 | + 'onEntityAliasesUpdate': function () { | |
88 | 86 | scope.updateView(); |
89 | 87 | } |
90 | 88 | }, |
... | ... | @@ -97,40 +95,31 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $ |
97 | 95 | } |
98 | 96 | |
99 | 97 | scope.updateView = function () { |
100 | - var value = angular.copy(scope.model); | |
101 | - ngModelCtrl.$setViewValue(value); | |
102 | 98 | updateDisplayValue(); |
103 | 99 | } |
104 | 100 | |
105 | - ngModelCtrl.$render = function () { | |
106 | - if (ngModelCtrl.$viewValue) { | |
107 | - var value = ngModelCtrl.$viewValue; | |
108 | - scope.model = angular.copy(value); | |
109 | - updateDisplayValue(); | |
110 | - } | |
111 | - } | |
112 | - | |
113 | 101 | function updateDisplayValue() { |
114 | 102 | var displayValue; |
115 | 103 | var singleValue = true; |
116 | 104 | var currentAliasId; |
117 | - for (var aliasId in scope.model) { | |
118 | - if (!currentAliasId) { | |
119 | - currentAliasId = aliasId; | |
120 | - } else { | |
121 | - singleValue = false; | |
122 | - break; | |
105 | + var entityAliases = scope.aliasController.getEntityAliases(); | |
106 | + for (var aliasId in entityAliases) { | |
107 | + var entityAlias = entityAliases[aliasId]; | |
108 | + if (!entityAlias.filter.resolveMultiple) { | |
109 | + var resolvedAlias = scope.aliasController.getInstantAliasInfo(aliasId); | |
110 | + if (resolvedAlias && resolvedAlias.currentEntity) { | |
111 | + if (!currentAliasId) { | |
112 | + currentAliasId = aliasId; | |
113 | + } else { | |
114 | + singleValue = false; | |
115 | + break; | |
116 | + } | |
117 | + } | |
123 | 118 | } |
124 | 119 | } |
125 | 120 | if (singleValue && currentAliasId) { |
126 | - var entityId = scope.model[currentAliasId].entityId; | |
127 | - var entitiesInfo = scope.entityAliasesInfo[currentAliasId]; | |
128 | - for (var i=0;i<entitiesInfo.length;i++) { | |
129 | - if (entitiesInfo[i].id === entityId) { | |
130 | - displayValue = entitiesInfo[i].name; | |
131 | - break; | |
132 | - } | |
133 | - } | |
121 | + var aliasInfo = scope.aliasController.getInstantAliasInfo(currentAliasId); | |
122 | + displayValue = aliasInfo.currentEntity.name; | |
134 | 123 | } else { |
135 | 124 | displayValue = $translate.instant('entity.entities'); |
136 | 125 | } |
... | ... | @@ -142,9 +131,8 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $ |
142 | 131 | |
143 | 132 | return { |
144 | 133 | restrict: "E", |
145 | - require: "^ngModel", | |
146 | 134 | scope: { |
147 | - entityAliasesInfo:'=' | |
135 | + aliasController:'=' | |
148 | 136 | }, |
149 | 137 | link: linker |
150 | 138 | }; | ... | ... |
... | ... | @@ -85,32 +85,29 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
85 | 85 | |
86 | 86 | for (aliasId in config.entityAliases) { |
87 | 87 | var entityAlias = config.entityAliases[aliasId]; |
88 | - var result = {id: aliasId, alias: entityAlias.alias, entityType: entityAlias.entityType, entityFilter: entityAlias.entityFilter, changed: true}; | |
88 | + var result = {id: aliasId, alias: entityAlias.alias, filter: entityAlias.filter, changed: true}; | |
89 | 89 | checkEntityAlias(result); |
90 | 90 | vm.entityAliases.push(result); |
91 | 91 | } |
92 | 92 | } |
93 | 93 | |
94 | 94 | function checkEntityAlias(entityAlias) { |
95 | - if (!entityAlias.entityType) { | |
96 | - entityAlias.entityType = types.entityType.device; | |
97 | - } | |
98 | - if (!entityAlias.entityFilter || entityAlias.entityFilter == null) { | |
99 | - entityAlias.entityFilter = { | |
100 | - useFilter: false, | |
101 | - entityNameFilter: '', | |
102 | - entityList: [], | |
103 | - }; | |
95 | + if (!entityAlias.filter || entityAlias.filter == null) { | |
96 | + entityAlias.filter = {}; | |
104 | 97 | } |
105 | 98 | } |
106 | 99 | |
107 | - function onFilterEntityChanged(entity, entityAlias) { | |
100 | + function onFilterEntityChanged(entity, stateEntity, entityAlias) { | |
108 | 101 | if (entityAlias) { |
109 | 102 | if (!entityAlias.alias || entityAlias.alias.length == 0) { |
110 | 103 | entityAlias.changed = false; |
111 | 104 | } |
112 | - if (!entityAlias.changed && entity && entityAlias.entityType) { | |
113 | - entityAlias.alias = entity.name; | |
105 | + if (!entityAlias.changed && entityAlias.filter && entityAlias.filter.type) { | |
106 | + if (stateEntity) { | |
107 | + entityAlias.alias = $translate.instant('alias.state-entity'); | |
108 | + } else { | |
109 | + entityAlias.alias = entity.name; | |
110 | + } | |
114 | 111 | } |
115 | 112 | } |
116 | 113 | } |
... | ... | @@ -121,8 +118,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
121 | 118 | aliasId = Math.max(vm.entityAliases[a].id, aliasId); |
122 | 119 | } |
123 | 120 | aliasId++; |
124 | - var entityAlias = {id: aliasId, alias: '', entityType: types.entityType.device, | |
125 | - entityFilter: {useFilter: false, entityNameFilter: '', entityList: []}, changed: false}; | |
121 | + var entityAlias = {id: aliasId, alias: '', filter: {}, changed: false}; | |
126 | 122 | vm.entityAliases.push(entityAlias); |
127 | 123 | } |
128 | 124 | |
... | ... | @@ -160,15 +156,6 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
160 | 156 | $mdDialog.cancel(); |
161 | 157 | } |
162 | 158 | |
163 | - function cleanupEntityFilter(entityFilter) { | |
164 | - if (entityFilter.useFilter) { | |
165 | - entityFilter.entityList = []; | |
166 | - } else { | |
167 | - entityFilter.entityNameFilter = ''; | |
168 | - } | |
169 | - return entityFilter; | |
170 | - } | |
171 | - | |
172 | 159 | function save() { |
173 | 160 | |
174 | 161 | var entityAliases = {}; |
... | ... | @@ -181,7 +168,6 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
181 | 168 | |
182 | 169 | if (vm.isSingleEntityAlias) { |
183 | 170 | maxAliasId = 0; |
184 | - vm.singleEntityAlias.entityFilter = cleanupEntityFilter(vm.singleEntityAlias.entityFilter); | |
185 | 171 | for (i = 0; i < vm.entityAliases.length; i ++) { |
186 | 172 | aliasId = vm.entityAliases[i].id; |
187 | 173 | alias = vm.entityAliases[i].alias; |
... | ... | @@ -199,7 +185,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
199 | 185 | alias = vm.entityAliases[i].alias; |
200 | 186 | if (!uniqueAliasList[alias]) { |
201 | 187 | uniqueAliasList[alias] = alias; |
202 | - entityAliases[aliasId] = {alias: alias, entityType: vm.entityAliases[i].entityType, entityFilter: cleanupEntityFilter(vm.entityAliases[i].entityFilter)}; | |
188 | + entityAliases[aliasId] = {id: aliasId, alias: alias, filter: vm.entityAliases[i].filter}; | |
203 | 189 | } else { |
204 | 190 | valid = false; |
205 | 191 | break; | ... | ... |
... | ... | @@ -32,20 +32,15 @@ |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset ng-disabled="loading"> |
34 | 34 | <div ng-show="vm.isSingleEntityAlias" layout="row"> |
35 | - <tb-entity-type-select style="min-width: 100px;" | |
36 | - ng-model="vm.singleEntityAlias.entityType" | |
37 | - allowed-entity-types="vm.allowedEntityTypes"> | |
38 | - </tb-entity-type-select> | |
39 | - <tb-entity-filter flex entity-type="vm.singleEntityAlias.entityType" ng-model="vm.singleEntityAlias.entityFilter"> | |
35 | + <tb-entity-filter flex allowed-entity-types="vm.allowedEntityTypes" ng-model="vm.singleEntityAlias.filter"> | |
40 | 36 | </tb-entity-filter> |
41 | 37 | </div> |
42 | 38 | <div ng-show="!vm.isSingleEntityAlias" flex layout="row" layout-align="start center"> |
43 | 39 | <span flex="5"></span> |
44 | 40 | <div flex layout="row" layout-align="start center" |
45 | 41 | style="padding: 0 0 0 10px; margin: 5px;"> |
46 | - <span translate flex="20" style="min-width: 100px;">entity.alias</span> | |
47 | - <span translate flex="20" style="min-width: 100px;">entity.type</span> | |
48 | - <span translate flex="60" style="min-width: 190px; padding-left: 10px;">entity.entities</span> | |
42 | + <span translate flex="20" style="min-width: 150px;">entity.alias</span> | |
43 | + <span translate flex="80" style="min-width: 240px; padding-left: 10px;">alias.entity-filter</span> | |
49 | 44 | <span style="min-width: 40px;"></span> |
50 | 45 | </div> |
51 | 46 | </div> |
... | ... | @@ -53,23 +48,17 @@ |
53 | 48 | <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index"> |
54 | 49 | <span flex="5">{{$index + 1}}.</span> |
55 | 50 | <div class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center"> |
56 | - <md-input-container flex="20" style="min-width: 100px;" md-no-float class="md-block"> | |
51 | + <md-input-container flex="20" style="min-width: 150px;" md-no-float class="md-block"> | |
57 | 52 | <input required ng-change="entityAlias.changed=true" name="alias" placeholder="{{ 'entity.alias' | translate }}" ng-model="entityAlias.alias"> |
58 | 53 | <div ng-messages="aliasForm.alias.$error"> |
59 | 54 | <div translate ng-message="required">entity.alias-required</div> |
60 | 55 | </div> |
61 | 56 | </md-input-container> |
62 | - <section flex="20" layout="column" style="min-width: 100px;" > | |
63 | - <tb-entity-type-select hide-label style="padding-left: 10px;" | |
64 | - ng-model="entityAlias.entityType" | |
65 | - allowed-entity-types="vm.allowedEntityTypes"> | |
66 | - </tb-entity-type-select> | |
67 | - </section> | |
68 | - <section flex="60" layout="column"> | |
57 | + <section flex="80" layout="column"> | |
69 | 58 | <tb-entity-filter style="padding-left: 10px;" |
70 | - entity-type="entityAlias.entityType" | |
71 | - ng-model="entityAlias.entityFilter" | |
72 | - on-matching-entity-change="vm.onFilterEntityChanged(entity, entityAlias)"> | |
59 | + allowed-entity-types="vm.allowedEntityTypes" | |
60 | + ng-model="entityAlias.filter" | |
61 | + on-matching-entity-change="vm.onFilterEntityChanged(entity, stateEntity, entityAlias)"> | |
73 | 62 | </tb-entity-filter> |
74 | 63 | </section> |
75 | 64 | <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;" | ... | ... |
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +/*@ngInject*/ | |
18 | +export default function EntityFilterDialogController($scope, $mdDialog, $q, entityService, types, isAdd, allowedEntityTypes, filter) { | |
19 | + | |
20 | + var vm = this; | |
21 | + | |
22 | + vm.types = types; | |
23 | + vm.isAdd = isAdd; | |
24 | + vm.allowedEntityTypes = allowedEntityTypes; | |
25 | + vm.filter = filter; | |
26 | + | |
27 | + vm.cancel = cancel; | |
28 | + vm.save = save; | |
29 | + | |
30 | + $scope.$watch('vm.filter.type', function (newType, prevType) { | |
31 | + if (newType && newType != prevType) { | |
32 | + updateFilter(); | |
33 | + } | |
34 | + }); | |
35 | + | |
36 | + $scope.$watch('theForm.$pristine', function() { | |
37 | + if ($scope.theForm && !$scope.theForm.$pristine) { | |
38 | + $scope.theForm.$setValidity('entityFilter', true); | |
39 | + } | |
40 | + }); | |
41 | + | |
42 | + function updateFilter() { | |
43 | + var filter = {}; | |
44 | + filter.type = vm.filter.type; | |
45 | + filter.resolveMultiple = vm.filter.resolveMultiple; | |
46 | + switch (filter.type) { | |
47 | + case types.aliasFilterType.entityList.value: | |
48 | + filter.entityType = null; | |
49 | + filter.entityList = []; | |
50 | + filter.stateEntity = false; | |
51 | + break; | |
52 | + case types.aliasFilterType.entityName.value: | |
53 | + filter.entityType = null; | |
54 | + filter.entityNameFilter = ''; | |
55 | + break; | |
56 | + //TODO: | |
57 | + } | |
58 | + vm.filter = filter; | |
59 | + } | |
60 | + | |
61 | + function validate() { | |
62 | + var deferred = $q.defer(); | |
63 | + var validationResult = { | |
64 | + entity: null, | |
65 | + stateEntity: false | |
66 | + } | |
67 | + entityService.resolveAliasFilter(vm.filter).then( | |
68 | + function success(result) { | |
69 | + validationResult.stateEntity = result.stateEntity; | |
70 | + var entities = result.entities; | |
71 | + if (entities.length) { | |
72 | + validationResult.entity = entities[0]; | |
73 | + } | |
74 | + deferred.resolve(validationResult); | |
75 | + }, | |
76 | + function fail() { | |
77 | + deferred.reject(); | |
78 | + } | |
79 | + ); | |
80 | + return deferred.promise; | |
81 | + } | |
82 | + | |
83 | + function cancel() { | |
84 | + $mdDialog.cancel(); | |
85 | + } | |
86 | + | |
87 | + function save() { | |
88 | + $scope.theForm.$setPristine(); | |
89 | + validate().then( | |
90 | + function success(validationResult) { | |
91 | + $mdDialog.hide({ | |
92 | + filter: vm.filter, | |
93 | + entity: validationResult.entity, | |
94 | + stateEntity: validationResult.stateEntity | |
95 | + }); | |
96 | + }, | |
97 | + function fail() { | |
98 | + $scope.theForm.$setValidity('entityFilter', false); | |
99 | + } | |
100 | + ) | |
101 | + } | |
102 | + | |
103 | +} | |
104 | + | ... | ... |
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<md-dialog class="tb-entity-filter-dialog" style="width: 600px;" aria-label="{{ 'alias.entity-filter' | translate }}"> | |
19 | + <form name="theForm" ng-submit="vm.save()"> | |
20 | + <md-toolbar> | |
21 | + <div class="md-toolbar-tools"> | |
22 | + <h2>{{ (vm.isAdd ? 'alias.create-entity-filter' : 'alias.edit-entity-filter') | translate }}</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="!loading" ng-show="loading"></md-progress-linear> | |
30 | + <span style="min-height: 5px;" flex="" ng-show="!loading"></span> | |
31 | + <md-dialog-content> | |
32 | + <div class="md-dialog-content"> | |
33 | + <fieldset ng-disabled="loading"> | |
34 | + <div flex layout="column"> | |
35 | + <md-input-container> | |
36 | + <label>{{ 'alias.filter-type' | translate }}</label> | |
37 | + <md-select required name="filterType" | |
38 | + ng-model="vm.filter.type" aria-label="{{ 'alias.filter-type' | translate }}"> | |
39 | + <md-option ng-repeat="type in vm.types.aliasFilterType" ng-value="type.value"> | |
40 | + {{type.name | translate}} | |
41 | + </md-option> | |
42 | + </md-select> | |
43 | + <div ng-messages="theForm.filterType.$error"> | |
44 | + <div ng-message="required" translate>alias.filter-type-required</div> | |
45 | + </div> | |
46 | + </md-input-container> | |
47 | + <section layout="column" ng-if="vm.filter.type == vm.types.aliasFilterType.entityList.value" id="entityListFilter"> | |
48 | + <md-checkbox flex aria-label="{{ 'alias.use-state-entity' | translate }}" | |
49 | + ng-model="vm.filter.stateEntity">{{ 'alias.use-state-entity' | translate }} | |
50 | + </md-checkbox> | |
51 | + <tb-entity-type-select | |
52 | + ng-if="!vm.filter.stateEntity" | |
53 | + ng-model="vm.filter.entityType" | |
54 | + the-form="theForm" | |
55 | + ng-disabled="vm.filter.stateEntity" | |
56 | + tb-required="!vm.filter.stateEntity" | |
57 | + allowed-entity-types="vm.allowedEntityTypes"> | |
58 | + </tb-entity-type-select> | |
59 | + <tb-entity-list | |
60 | + ng-if="!vm.filter.stateEntity" | |
61 | + ng-model="vm.filter.entityList" | |
62 | + ng-disabled="vm.filter.stateEntity" | |
63 | + tb-required="!vm.filter.stateEntity" | |
64 | + entity-type="vm.filter.entityType"> | |
65 | + </tb-entity-list> | |
66 | + </section> | |
67 | + <section flex layout="column" ng-if="vm.filter.type == vm.types.aliasFilterType.entityName.value" id="entityNameFilter"> | |
68 | + <tb-entity-type-select | |
69 | + ng-model="vm.filter.entityType" | |
70 | + the-form="theForm" | |
71 | + tb-required="true" | |
72 | + allowed-entity-types="vm.allowedEntityTypes"> | |
73 | + </tb-entity-type-select> | |
74 | + <md-input-container flex> | |
75 | + <label translate>entity.name-starts-with</label> | |
76 | + <input required name="entityNameFilter" | |
77 | + ng-model="vm.filter.entityNameFilter" | |
78 | + aria-label="{{ 'entity.name-starts-with' | translate }}"> | |
79 | + <div ng-messages="theForm.entityNameFilter.$error"> | |
80 | + <div ng-message="required" translate>entity.entity-name-filter-required</div> | |
81 | + </div> | |
82 | + | |
83 | + </md-input-container> | |
84 | + </section> | |
85 | + <div class="tb-error-messages" ng-messages="theForm.$error" role="alert"> | |
86 | + <div translate ng-message="entityFilter" class="tb-error-message">alias.entity-filter-no-entity-matched</div> | |
87 | + </div> | |
88 | + </div> | |
89 | + </fieldset> | |
90 | + </div> | |
91 | + </md-dialog-content> | |
92 | + <md-dialog-actions layout="row"> | |
93 | + <span flex></span> | |
94 | + <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> | |
95 | + {{ 'action.save' | translate }} | |
96 | + </md-button> | |
97 | + <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> | |
98 | + </md-dialog-actions> | |
99 | + </form> | |
100 | +</md-dialog> | |
\ No newline at end of file | ... | ... |
... | ... | @@ -17,13 +17,16 @@ |
17 | 17 | /* eslint-disable import/no-unresolved, import/default */ |
18 | 18 | |
19 | 19 | import entityFilterTemplate from './entity-filter.tpl.html'; |
20 | +import entityFilterDialogTemplate from './entity-filter-dialog.tpl.html'; | |
20 | 21 | |
21 | 22 | /* eslint-enable import/no-unresolved, import/default */ |
22 | 23 | |
24 | +import EntityFilterDialogController from './entity-filter-dialog.controller'; | |
25 | + | |
23 | 26 | import './entity-filter.scss'; |
24 | 27 | |
25 | 28 | /*@ngInject*/ |
26 | -export default function EntityFilterDirective($compile, $templateCache, $q, entityService) { | |
29 | +export default function EntityFilterDirective($compile, $templateCache, $q, $document, $mdDialog, types) { | |
27 | 30 | |
28 | 31 | var linker = function (scope, element, attrs, ngModelCtrl) { |
29 | 32 | |
... | ... | @@ -31,8 +34,9 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti |
31 | 34 | element.html(template); |
32 | 35 | |
33 | 36 | scope.ngModelCtrl = ngModelCtrl; |
37 | + scope.types = types; | |
34 | 38 | |
35 | - scope.fetchEntities = function(searchText, limit) { | |
39 | + /* scope.fetchEntities = function(searchText, limit) { | |
36 | 40 | var deferred = $q.defer(); |
37 | 41 | entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(function success(result) { |
38 | 42 | if (result) { |
... | ... | @@ -44,13 +48,13 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti |
44 | 48 | deferred.reject(); |
45 | 49 | }); |
46 | 50 | return deferred.promise; |
47 | - } | |
51 | + }*/ | |
48 | 52 | |
49 | 53 | scope.updateValidity = function() { |
50 | 54 | if (ngModelCtrl.$viewValue) { |
51 | 55 | var value = ngModelCtrl.$viewValue; |
52 | - var valid; | |
53 | - if (value.useFilter) { | |
56 | + ngModelCtrl.$setValidity('filter', value.type ? true : false); | |
57 | + /*if (value.useFilter) { | |
54 | 58 | ngModelCtrl.$setValidity('entityList', true); |
55 | 59 | if (angular.isDefined(value.entityNameFilter) && value.entityNameFilter.length > 0) { |
56 | 60 | ngModelCtrl.$setValidity('entityNameFilter', true); |
... | ... | @@ -64,18 +68,22 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti |
64 | 68 | ngModelCtrl.$setValidity('entityNameFilterDeviceMatch', true); |
65 | 69 | valid = angular.isDefined(value.entityList) && value.entityList.length > 0; |
66 | 70 | ngModelCtrl.$setValidity('entityList', valid); |
67 | - } | |
71 | + }*/ | |
72 | + | |
68 | 73 | } |
69 | 74 | } |
70 | 75 | |
71 | 76 | ngModelCtrl.$render = function () { |
72 | - destroyWatchers(); | |
73 | - scope.model = { | |
74 | - useFilter: false, | |
75 | - entityList: [], | |
76 | - entityNameFilter: '' | |
77 | - } | |
77 | + //destroyWatchers(); | |
78 | 78 | if (ngModelCtrl.$viewValue) { |
79 | + scope.model = angular.copy(ngModelCtrl.$viewValue); | |
80 | + } else { | |
81 | + scope.model = { | |
82 | + type: null, | |
83 | + resolveMultiple: false | |
84 | + } | |
85 | + } | |
86 | + /* if (ngModelCtrl.$viewValue) { | |
79 | 87 | var value = ngModelCtrl.$viewValue; |
80 | 88 | var model = scope.model; |
81 | 89 | model.useFilter = value.useFilter === true ? true: false; |
... | ... | @@ -96,10 +104,52 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti |
96 | 104 | } |
97 | 105 | } |
98 | 106 | ) |
107 | + }*/ | |
108 | + } | |
109 | + | |
110 | + scope.$watch('model.resolveMultiple', function () { | |
111 | + if (ngModelCtrl.$viewValue) { | |
112 | + var value = ngModelCtrl.$viewValue; | |
113 | + value.resolveMultiple = scope.model.resolveMultiple; | |
114 | + ngModelCtrl.$setViewValue(value); | |
115 | + scope.updateValidity(); | |
99 | 116 | } |
117 | + }); | |
118 | + | |
119 | + scope.editFilter = function($event) { | |
120 | + openEntityFilterDialog($event, false); | |
121 | + } | |
122 | + | |
123 | + scope.createFilter = function($event) { | |
124 | + openEntityFilterDialog($event, true); | |
100 | 125 | } |
101 | 126 | |
102 | - function updateMatchingEntity() { | |
127 | + function openEntityFilterDialog($event, isAdd) { | |
128 | + $mdDialog.show({ | |
129 | + controller: EntityFilterDialogController, | |
130 | + controllerAs: 'vm', | |
131 | + templateUrl: entityFilterDialogTemplate, | |
132 | + locals: { | |
133 | + isAdd: isAdd, | |
134 | + allowedEntityTypes: scope.allowedEntityTypes, | |
135 | + filter: angular.copy(scope.model) | |
136 | + }, | |
137 | + parent: angular.element($document[0].body), | |
138 | + fullscreen: true, | |
139 | + skipHide: true, | |
140 | + targetEvent: $event | |
141 | + }).then(function (result) { | |
142 | + scope.model = result.filter; | |
143 | + ngModelCtrl.$setViewValue(result.filter); | |
144 | + scope.updateValidity(); | |
145 | + if (scope.onMatchingEntityChange) { | |
146 | + scope.onMatchingEntityChange({entity: result.entity, stateEntity: result.stateEntity}); | |
147 | + } | |
148 | + }, function () { | |
149 | + }); | |
150 | + } | |
151 | + | |
152 | + /* function updateMatchingEntity() { | |
103 | 153 | if (scope.model.useFilter) { |
104 | 154 | scope.model.matchingEntity = scope.model.matchingFilterEntity; |
105 | 155 | } else { |
... | ... | @@ -206,7 +256,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti |
206 | 256 | } |
207 | 257 | } |
208 | 258 | }); |
209 | - } | |
259 | + }*/ | |
210 | 260 | |
211 | 261 | $compile(element.contents())(scope); |
212 | 262 | |
... | ... | @@ -217,8 +267,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti |
217 | 267 | require: "^ngModel", |
218 | 268 | link: linker, |
219 | 269 | scope: { |
220 | - entityType: '=', | |
221 | - isEdit: '=', | |
270 | + allowedEntityTypes: '=?', | |
222 | 271 | onMatchingEntityChange: '&' |
223 | 272 | } |
224 | 273 | }; | ... | ... |
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 | --> |
18 | 18 | <section layout='column' class="tb-entity-filter"> |
19 | 19 | <section layout='row'> |
20 | - <section layout="column" flex ng-show="!model.useFilter"> | |
20 | + <!--section layout="column" flex ng-show="!model.useFilter"> | |
21 | 21 | <md-chips flex |
22 | 22 | id="entity_list_chips" |
23 | 23 | ng-required="!useFilter" |
... | ... | @@ -51,17 +51,44 @@ |
51 | 51 | <label translate>entity.name-starts-with</label> |
52 | 52 | <input ng-model="model.entityNameFilter" aria-label="{{ 'entity.name-starts-with' | translate }}"> |
53 | 53 | </md-input-container> |
54 | + </section--> | |
55 | + <section layout="row" flex layout-align="start center"> | |
56 | + <div flex ng-if="model.type">{{ types.aliasFilterType[model.type].name | translate }}</div> | |
57 | + <md-button ng-if="model.type" ng-disabled="loading" class="md-icon-button md-primary" | |
58 | + style="min-width: 40px;" | |
59 | + ng-click="editFilter($event)" | |
60 | + aria-label="{{ 'alias.edit-entity-filter' | translate }}"> | |
61 | + <md-tooltip md-direction="top"> | |
62 | + {{ 'alias.edit-entity-filter' | translate }} | |
63 | + </md-tooltip> | |
64 | + <md-icon aria-label="{{ 'alias.edit-entity-filter' | translate }}" | |
65 | + class="material-icons"> | |
66 | + edit | |
67 | + </md-icon> | |
68 | + </md-button> | |
69 | + <div ng-if="!model.type" layout="row" layout-align="center start"> | |
70 | + <md-button ng-disabled="loading" class="md-primary md-raised" | |
71 | + ng-click="createFilter($event)" | |
72 | + aria-label="{{ 'alias.create-entity-filter' | translate }}"> | |
73 | + <md-icon aria-label="{{ 'alias.create-entity-filter' | translate }}" | |
74 | + class="material-icons"> | |
75 | + add | |
76 | + </md-icon> | |
77 | + {{ 'alias.create-entity-filter' | translate }} | |
78 | + </md-button> | |
79 | + </div> | |
54 | 80 | </section> |
55 | 81 | <section class="tb-filter-switch" layout="column" layout-align="center center"> |
56 | - <label class="tb-small filter-label" translate>entity.use-entity-name-filter</label> | |
57 | - <md-switch class="filter-switch" ng-model="model.useFilter" aria-label="use-filter-switcher"> | |
82 | + <label class="tb-small filter-label" translate>alias.resolve-multiple</label> | |
83 | + <md-switch class="filter-switch" ng-model="model.resolveMultiple" aria-label="resolve-multiple-switcher"> | |
58 | 84 | </md-switch> |
59 | 85 | </section> |
60 | 86 | </section> |
61 | 87 | <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" role="alert"> |
62 | - <div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div> | |
88 | + <div translate ng-message="filter" class="tb-error-message">alias.entity-filter-required</div> | |
89 | + <!--div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div> | |
63 | 90 | <div translate ng-message="entityNameFilter" class="tb-error-message">entity.entity-name-filter-required</div> |
64 | 91 | <div translate translate-values='{ entity: model.entityNameFilter }' ng-message="entityNameFilterEntityMatch" |
65 | - class="tb-error-message">entity.entity-name-filter-no-entity-matched</div> | |
92 | + class="tb-error-message">entity.entity-name-filter-no-entity-matched</div--> | |
66 | 93 | </div> |
67 | 94 | </section> |
\ No newline at end of file | ... | ... |
ui/src/app/entity/entity-list.directive.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +/* eslint-disable import/no-unresolved, import/default */ | |
18 | + | |
19 | +import entityListTemplate from './entity-list.tpl.html'; | |
20 | + | |
21 | +/* eslint-enable import/no-unresolved, import/default */ | |
22 | + | |
23 | +import './entity-list.scss'; | |
24 | + | |
25 | +/*@ngInject*/ | |
26 | +export default function EntityListDirective($compile, $templateCache, $q, $mdUtil, entityService) { | |
27 | + | |
28 | + var linker = function (scope, element, attrs, ngModelCtrl) { | |
29 | + | |
30 | + var template = $templateCache.get(entityListTemplate); | |
31 | + element.html(template); | |
32 | + | |
33 | + scope.ngModelCtrl = ngModelCtrl; | |
34 | + | |
35 | + scope.$watch('tbRequired', function () { | |
36 | + scope.updateValidity(); | |
37 | + }); | |
38 | + | |
39 | + scope.fetchEntities = function(searchText, limit) { | |
40 | + var deferred = $q.defer(); | |
41 | + entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then( | |
42 | + function success(result) { | |
43 | + if (result) { | |
44 | + deferred.resolve(result); | |
45 | + } else { | |
46 | + deferred.resolve([]); | |
47 | + } | |
48 | + }, | |
49 | + function fail() { | |
50 | + deferred.reject(); | |
51 | + } | |
52 | + ); | |
53 | + return deferred.promise; | |
54 | + } | |
55 | + | |
56 | + scope.updateValidity = function() { | |
57 | + var value = ngModelCtrl.$viewValue; | |
58 | + var valid = !scope.tbRequired || value && value.length > 0; | |
59 | + ngModelCtrl.$setValidity('entityList', valid); | |
60 | + } | |
61 | + | |
62 | + ngModelCtrl.$render = function () { | |
63 | + destroyWatchers(); | |
64 | + var value = ngModelCtrl.$viewValue; | |
65 | + scope.entityList = []; | |
66 | + if (value && value.length > 0) { | |
67 | + entityService.getEntities(scope.entityType, value).then(function (entities) { | |
68 | + scope.entityList = entities; | |
69 | + initWatchers(); | |
70 | + }); | |
71 | + } else { | |
72 | + initWatchers(); | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + function initWatchers() { | |
77 | + scope.entityTypeDeregistration = scope.$watch('entityType', function (newEntityType, prevEntityType) { | |
78 | + if (!angular.equals(newEntityType, prevEntityType)) { | |
79 | + scope.entityList = []; | |
80 | + } | |
81 | + }); | |
82 | + scope.entityListDeregistration = scope.$watch('entityList', function () { | |
83 | + var ids = []; | |
84 | + if (scope.entityList && scope.entityList.length > 0) { | |
85 | + for (var i=0;i<scope.entityList.length;i++) { | |
86 | + ids.push(scope.entityList[i].id.id); | |
87 | + } | |
88 | + } | |
89 | + var value = ngModelCtrl.$viewValue; | |
90 | + if (!angular.equals(ids, value)) { | |
91 | + ngModelCtrl.$setViewValue(ids); | |
92 | + } | |
93 | + scope.updateValidity(); | |
94 | + }, true); | |
95 | + } | |
96 | + | |
97 | + function destroyWatchers() { | |
98 | + if (scope.entityTypeDeregistration) { | |
99 | + scope.entityTypeDeregistration(); | |
100 | + scope.entityTypeDeregistration = null; | |
101 | + } | |
102 | + if (scope.entityListDeregistration) { | |
103 | + scope.entityListDeregistration(); | |
104 | + scope.entityListDeregistration = null; | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + $compile(element.contents())(scope); | |
109 | + | |
110 | + $mdUtil.nextTick(function(){ | |
111 | + var inputElement = angular.element('input', element); | |
112 | + inputElement.on('blur', function() { | |
113 | + scope.inputTouched = true; | |
114 | + } ); | |
115 | + }); | |
116 | + | |
117 | + } | |
118 | + | |
119 | + return { | |
120 | + restrict: "E", | |
121 | + require: "^ngModel", | |
122 | + link: linker, | |
123 | + scope: { | |
124 | + disabled:'=ngDisabled', | |
125 | + tbRequired: '=?', | |
126 | + entityType: '=' | |
127 | + } | |
128 | + }; | |
129 | + | |
130 | +} | ... | ... |
ui/src/app/entity/entity-list.scss
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +/*.tb-entity-list { | |
18 | + #entity_list_chips { | |
19 | + .md-chips { | |
20 | + padding-bottom: 1px; | |
21 | + } | |
22 | + } | |
23 | + .tb-error-messages { | |
24 | + margin-top: -11px; | |
25 | + height: 35px; | |
26 | + .tb-error-message { | |
27 | + padding-left: 1px; | |
28 | + } | |
29 | + } | |
30 | +}*/ | |
\ No newline at end of file | ... | ... |
ui/src/app/entity/entity-list.tpl.html
0 → 100644
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2017 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | + | |
19 | +<section flex layout='column' class="tb-entity-list"> | |
20 | + <md-chips flex | |
21 | + readonly="disabled" | |
22 | + id="entity_list_chips" | |
23 | + ng-required="tbRequired" | |
24 | + ng-model="entityList" | |
25 | + md-autocomplete-snap | |
26 | + md-require-match="true"> | |
27 | + <md-autocomplete | |
28 | + md-no-cache="true" | |
29 | + id="entity" | |
30 | + md-selected-item="selectedEntity" | |
31 | + md-search-text="entitySearchText" | |
32 | + md-items="item in fetchEntities(entitySearchText, 10)" | |
33 | + md-item-text="item.name" | |
34 | + md-min-length="0" | |
35 | + placeholder="{{ 'entity.entity-list' | translate }}"> | |
36 | + <md-item-template> | |
37 | + <span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span> | |
38 | + </md-item-template> | |
39 | + <md-not-found> | |
40 | + <span translate translate-values='{ entity: entitySearchText }'>entity.no-entities-matching</span> | |
41 | + </md-not-found> | |
42 | + </md-autocomplete> | |
43 | + <md-chip-template> | |
44 | + <span> | |
45 | + <strong>{{$chip.name}}</strong> | |
46 | + </span> | |
47 | + </md-chip-template> | |
48 | + </md-chips> | |
49 | + <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" ng-if="inputTouched" role="alert"> | |
50 | + <div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div> | |
51 | + </div> | |
52 | +</section> | |
\ No newline at end of file | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import EntityTypeSelectDirective from './entity-type-select.directive'; |
19 | 19 | import EntitySubtypeSelectDirective from './entity-subtype-select.directive'; |
20 | 20 | import EntitySubtypeAutocompleteDirective from './entity-subtype-autocomplete.directive'; |
21 | 21 | import EntityAutocompleteDirective from './entity-autocomplete.directive'; |
22 | +import EntityListDirective from './entity-list.directive'; | |
22 | 23 | import EntitySelectDirective from './entity-select.directive'; |
23 | 24 | import EntityFilterDirective from './entity-filter.directive'; |
24 | 25 | import AliasesEntitySelectPanelController from './aliases-entity-select-panel.controller'; |
... | ... | @@ -38,6 +39,7 @@ export default angular.module('thingsboard.entity', []) |
38 | 39 | .directive('tbEntitySubtypeSelect', EntitySubtypeSelectDirective) |
39 | 40 | .directive('tbEntitySubtypeAutocomplete', EntitySubtypeAutocompleteDirective) |
40 | 41 | .directive('tbEntityAutocomplete', EntityAutocompleteDirective) |
42 | + .directive('tbEntityList', EntityListDirective) | |
41 | 43 | .directive('tbEntitySelect', EntitySelectDirective) |
42 | 44 | .directive('tbEntityFilter', EntityFilterDirective) |
43 | 45 | .directive('tbAliasesEntitySelect', AliasesEntitySelectDirective) | ... | ... |
... | ... | @@ -112,6 +112,25 @@ export default angular.module('thingsboard.locale', []) |
112 | 112 | "no-alarms-matching": "No alarms matching '{{entity}}' were found.", |
113 | 113 | "alarm-required": "Alarm is required" |
114 | 114 | }, |
115 | + "alias": { | |
116 | + "filter-type-entity-list": "Entity list", | |
117 | + "filter-type-entity-name": "Entity name", | |
118 | + "filter-type-asset-type": "Asset type", | |
119 | + "filter-type-device-type": "Device type", | |
120 | + "filter-type-relations-query": "Relations query", | |
121 | + "filter-type-asset-search-query": "Asset search query", | |
122 | + "filter-type-device-search-query": "Device search query", | |
123 | + "entity-filter": "Entity filter", | |
124 | + "create-entity-filter": "Create entity filter", | |
125 | + "edit-entity-filter": "Edit entity filter", | |
126 | + "entity-filter-required": "Entity filter is required.", | |
127 | + "resolve-multiple": "Multiple", | |
128 | + "filter-type": "Filter type", | |
129 | + "filter-type-required": "Filter type is required.", | |
130 | + "use-state-entity": "Use state entity", | |
131 | + "state-entity": "State entity", | |
132 | + "entity-filter-no-entity-matched": "No entities matching specified filter were found.", | |
133 | + }, | |
115 | 134 | "asset": { |
116 | 135 | "asset": "Asset", |
117 | 136 | "assets": "Assets", | ... | ... |
... | ... | @@ -264,14 +264,9 @@ function ItemBuffer($q, bufferStore, types, utils, dashboardUtils) { |
264 | 264 | } |
265 | 265 | dashboardUtils.addWidgetToLayout(theDashboard, targetState, targetLayout, widget, originalColumns, originalSize, row, column); |
266 | 266 | if (callAliasUpdateFunction) { |
267 | - onAliasesUpdateFunction().then( | |
268 | - function() { | |
269 | - deferred.resolve(theDashboard); | |
270 | - } | |
271 | - ); | |
272 | - } else { | |
273 | - deferred.resolve(theDashboard); | |
267 | + onAliasesUpdateFunction(); | |
274 | 268 | } |
269 | + deferred.resolve(theDashboard); | |
275 | 270 | return deferred.promise; |
276 | 271 | } |
277 | 272 | ... | ... |