Commit 9ef646765e4bf4e07396b55f70534ca37671cd36
1 parent
0a83091a
TB-61: Improve Aliases management. Implement Asset type and Device type alias filter.
Showing
25 changed files
with
784 additions
and
457 deletions
... | ... | @@ -95,8 +95,7 @@ export default class AliasController { |
95 | 95 | this.entityService.resolveAlias(entityAlias, this.stateController.getStateParams()).then( |
96 | 96 | function success(aliasInfo) { |
97 | 97 | aliasCtrl.resolvedAliases[aliasId] = aliasInfo; |
98 | - if (entityAlias.filter.stateEntity) { | |
99 | - aliasInfo.stateEntity = true; | |
98 | + if (aliasInfo.stateEntity) { | |
100 | 99 | aliasCtrl.resolvedAliasesToStateEntities[aliasId] = |
101 | 100 | aliasCtrl.stateController.getStateParams().entityId; |
102 | 101 | } | ... | ... |
... | ... | @@ -31,6 +31,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
31 | 31 | resolveAliasFilter: resolveAliasFilter, |
32 | 32 | checkEntityAlias: checkEntityAlias, |
33 | 33 | filterAliasByEntityTypes: filterAliasByEntityTypes, |
34 | + getAliasFilterTypesByEntityTypes: getAliasFilterTypesByEntityTypes, | |
34 | 35 | getEntityKeys: getEntityKeys, |
35 | 36 | createDatasourcesFromSubscriptionsInfo: createDatasourcesFromSubscriptionsInfo, |
36 | 37 | getRelatedEntities: getRelatedEntities, |
... | ... | @@ -223,17 +224,21 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
223 | 224 | return promise; |
224 | 225 | } |
225 | 226 | |
226 | - function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config, subType) { | |
227 | - var deferred = $q.defer(); | |
228 | - var pageLink = {limit: limit, textSearch: entityNameFilter}; | |
227 | + function getEntitiesByPageLink(entityType, pageLink, config, subType, data, deferred) { | |
229 | 228 | var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config, subType); |
230 | 229 | if (promise) { |
231 | 230 | promise.then( |
232 | 231 | function success(result) { |
233 | - if (result.data && result.data.length > 0) { | |
234 | - deferred.resolve(result.data); | |
232 | + data = data.concat(result.data); | |
233 | + if (result.hasNext) { | |
234 | + pageLink = result.nextPageLink; | |
235 | + getEntitiesByPageLink(entityType, pageLink, config, subType, data, deferred); | |
235 | 236 | } else { |
236 | - deferred.resolve(null); | |
237 | + if (data && data.length > 0) { | |
238 | + deferred.resolve(data); | |
239 | + } else { | |
240 | + deferred.resolve(null); | |
241 | + } | |
237 | 242 | } |
238 | 243 | }, |
239 | 244 | function fail() { |
... | ... | @@ -243,6 +248,34 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
243 | 248 | } else { |
244 | 249 | deferred.resolve(null); |
245 | 250 | } |
251 | + } | |
252 | + | |
253 | + function getEntitiesByNameFilter(entityType, entityNameFilter, limit, config, subType) { | |
254 | + var deferred = $q.defer(); | |
255 | + var pageLink = {limit: limit, textSearch: entityNameFilter}; | |
256 | + if (limit == -1) { // all | |
257 | + var data = []; | |
258 | + pageLink.limit = 100; | |
259 | + getEntitiesByPageLink(entityType, pageLink, config, subType, data, deferred); | |
260 | + } else { | |
261 | + var promise = getEntitiesByPageLinkPromise(entityType, pageLink, config, subType); | |
262 | + if (promise) { | |
263 | + promise.then( | |
264 | + function success(result) { | |
265 | + if (result.data && result.data.length > 0) { | |
266 | + deferred.resolve(result.data); | |
267 | + } else { | |
268 | + deferred.resolve(null); | |
269 | + } | |
270 | + }, | |
271 | + function fail() { | |
272 | + deferred.resolve(null); | |
273 | + } | |
274 | + ); | |
275 | + } else { | |
276 | + deferred.resolve(null); | |
277 | + } | |
278 | + } | |
246 | 279 | return deferred.promise; |
247 | 280 | } |
248 | 281 | |
... | ... | @@ -261,11 +294,12 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
261 | 294 | function resolveAlias(entityAlias, stateParams) { |
262 | 295 | var deferred = $q.defer(); |
263 | 296 | var filter = entityAlias.filter; |
264 | - resolveAliasFilter(filter, stateParams, 100).then( | |
297 | + resolveAliasFilter(filter, stateParams, -1).then( | |
265 | 298 | function (result) { |
266 | 299 | var entities = result.entities; |
267 | 300 | var aliasInfo = { |
268 | 301 | alias: entityAlias.alias, |
302 | + stateEntity: result.stateEntity, | |
269 | 303 | resolveMultiple: filter.resolveMultiple |
270 | 304 | }; |
271 | 305 | var resolvedEntities = entitiesToEntitiesInfo(entities); |
... | ... | @@ -291,39 +325,68 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
291 | 325 | }; |
292 | 326 | switch (filter.type) { |
293 | 327 | case types.aliasFilterType.entityList.value: |
294 | - if (filter.stateEntity) { | |
295 | - result.stateEntity = true; | |
296 | - if (stateParams && stateParams.entityId) { | |
297 | - getEntity(stateParams.entityId.entityType, stateParams.entityId.id).then( | |
298 | - function success(entity) { | |
299 | - result.entities = [entity]; | |
300 | - deferred.resolve(result); | |
301 | - }, | |
302 | - function fail() { | |
303 | - deferred.reject(); | |
304 | - } | |
305 | - ); | |
306 | - } else { | |
307 | - deferred.resolve(result); | |
328 | + getEntities(filter.entityType, filter.entityList).then( | |
329 | + function success(entities) { | |
330 | + if (entities && entities.length) { | |
331 | + result.entities = entities; | |
332 | + deferred.resolve(result); | |
333 | + } else { | |
334 | + deferred.reject(); | |
335 | + } | |
336 | + }, | |
337 | + function fail() { | |
338 | + deferred.reject(); | |
308 | 339 | } |
309 | - } else { | |
310 | - getEntities(filter.entityType, filter.entityList).then( | |
311 | - function success(entities) { | |
312 | - if (entities && entities.length) { | |
313 | - result.entities = entities; | |
314 | - deferred.resolve(result); | |
315 | - } else { | |
316 | - deferred.reject(); | |
317 | - } | |
340 | + ); | |
341 | + break; | |
342 | + case types.aliasFilterType.entityName.value: | |
343 | + getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then( | |
344 | + function success(entities) { | |
345 | + if (entities && entities.length) { | |
346 | + result.entities = entities; | |
347 | + deferred.resolve(result); | |
348 | + } else { | |
349 | + deferred.reject(); | |
350 | + } | |
351 | + }, | |
352 | + function fail() { | |
353 | + deferred.reject(); | |
354 | + } | |
355 | + ); | |
356 | + break; | |
357 | + case types.aliasFilterType.stateEntity.value: | |
358 | + result.stateEntity = true; | |
359 | + if (stateParams && stateParams.entityId) { | |
360 | + getEntity(stateParams.entityId.entityType, stateParams.entityId.id).then( | |
361 | + function success(entity) { | |
362 | + result.entities = [entity]; | |
363 | + deferred.resolve(result); | |
318 | 364 | }, |
319 | 365 | function fail() { |
320 | 366 | deferred.reject(); |
321 | 367 | } |
322 | 368 | ); |
369 | + } else { | |
370 | + deferred.resolve(result); | |
323 | 371 | } |
324 | 372 | break; |
325 | - case types.aliasFilterType.entityName.value: | |
326 | - getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then( | |
373 | + case types.aliasFilterType.assetType.value: | |
374 | + getEntitiesByNameFilter(types.entityType.asset, filter.assetNameFilter, maxItems, null, filter.assetType).then( | |
375 | + function success(entities) { | |
376 | + if (entities && entities.length) { | |
377 | + result.entities = entities; | |
378 | + deferred.resolve(result); | |
379 | + } else { | |
380 | + deferred.reject(); | |
381 | + } | |
382 | + }, | |
383 | + function fail() { | |
384 | + deferred.reject(); | |
385 | + } | |
386 | + ); | |
387 | + break; | |
388 | + case types.aliasFilterType.deviceType.value: | |
389 | + getEntitiesByNameFilter(types.entityType.device, filter.deviceNameFilter, maxItems, null, filter.deviceType).then( | |
327 | 390 | function success(entities) { |
328 | 391 | if (entities && entities.length) { |
329 | 392 | result.entities = entities; |
... | ... | @@ -337,27 +400,81 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
337 | 400 | } |
338 | 401 | ); |
339 | 402 | break; |
340 | - //TODO: | |
403 | + | |
404 | + //TODO: Alias filter | |
341 | 405 | } |
342 | 406 | return deferred.promise; |
343 | 407 | } |
344 | 408 | |
345 | 409 | function filterAliasByEntityTypes(entityAlias, entityTypes) { |
346 | 410 | var filter = entityAlias.filter; |
347 | - switch (filter.type) { | |
348 | - case types.aliasFilterType.entityList.value: | |
349 | - if (filter.stateEntity) { | |
350 | - return true; | |
351 | - } else { | |
411 | + if (filterAliasFilterTypeByEntityTypes(filter.type, entityTypes)) { | |
412 | + switch (filter.type) { | |
413 | + case types.aliasFilterType.entityList.value: | |
352 | 414 | return entityTypes.indexOf(filter.entityType) > -1 ? true : false; |
353 | - } | |
415 | + case types.aliasFilterType.entityName.value: | |
416 | + return entityTypes.indexOf(filter.entityType) > -1 ? true : false; | |
417 | + case types.aliasFilterType.stateEntity.value: | |
418 | + return true; | |
419 | + case types.aliasFilterType.assetType.value: | |
420 | + return entityTypes.indexOf(types.entityType.asset) > -1 ? true : false; | |
421 | + case types.aliasFilterType.deviceType.value: | |
422 | + return entityTypes.indexOf(types.entityType.device) > -1 ? true : false; | |
423 | + } | |
424 | + } | |
425 | + //TODO: Alias filter | |
426 | + return false; | |
427 | + } | |
428 | + | |
429 | + function filterAliasFilterTypeByEntityType(aliasFilterType, entityType) { | |
430 | + switch (aliasFilterType) { | |
431 | + case types.aliasFilterType.entityList.value: | |
432 | + return true; | |
354 | 433 | case types.aliasFilterType.entityName.value: |
355 | - return entityTypes.indexOf(filter.entityType) > -1 ? true : false; | |
434 | + return true; | |
435 | + case types.aliasFilterType.stateEntity.value: | |
436 | + return true; | |
437 | + case types.aliasFilterType.assetType.value: | |
438 | + return entityType === types.entityType.asset; | |
439 | + case types.aliasFilterType.deviceType.value: | |
440 | + return entityType === types.entityType.device; | |
441 | + case types.aliasFilterType.relationsQuery.value: | |
442 | + return true; | |
443 | + case types.aliasFilterType.assetSearchQuery.value: | |
444 | + return entityType === types.entityType.asset; | |
445 | + case types.aliasFilterType.deviceSearchQuery.value: | |
446 | + return entityType === types.entityType.device; | |
356 | 447 | } |
357 | - //TODO: | |
358 | 448 | return false; |
359 | 449 | } |
360 | 450 | |
451 | + function filterAliasFilterTypeByEntityTypes(aliasFilterType, entityTypes) { | |
452 | + if (!entityTypes || !entityTypes.length) { | |
453 | + return true; | |
454 | + } | |
455 | + var valid = false; | |
456 | + entityTypes.forEach(function(entityType) { | |
457 | + valid = valid || filterAliasFilterTypeByEntityType(aliasFilterType, entityType); | |
458 | + }); | |
459 | + return valid; | |
460 | + } | |
461 | + | |
462 | + function getAliasFilterTypesByEntityTypes(entityTypes) { | |
463 | + var allAliasFilterTypes = types.aliasFilterType; | |
464 | + if (!entityTypes || !entityTypes.length) { | |
465 | + return allAliasFilterTypes; | |
466 | + } | |
467 | + var result = {}; | |
468 | + for (var type in allAliasFilterTypes) { | |
469 | + var aliasFilterType = allAliasFilterTypes[type]; | |
470 | + if (filterAliasFilterTypeByEntityTypes(aliasFilterType.value, entityTypes)) { | |
471 | + result[type] = aliasFilterType; | |
472 | + } | |
473 | + } | |
474 | + return result; | |
475 | + } | |
476 | + | |
477 | + | |
361 | 478 | function checkEntityAlias(entityAlias) { |
362 | 479 | var deferred = $q.defer(); |
363 | 480 | resolveAliasFilter(entityAlias.filter, null, 1).then( |
... | ... | @@ -380,50 +497,6 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
380 | 497 | return deferred.promise; |
381 | 498 | } |
382 | 499 | |
383 | - /*function processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred) { | |
384 | - if (index < aliasIds.length) { | |
385 | - var aliasId = aliasIds[index]; | |
386 | - var entityAlias = entityAliases[aliasId]; | |
387 | - var alias = entityAlias.alias; | |
388 | - var filter = entityAlias.filter; | |
389 | - resolveAliasFilter(filter, stateParams).then( | |
390 | - function (entities) { | |
391 | - if (entities && entities.length) { | |
392 | - var entity = entities[0]; | |
393 | - var resolvedAlias = {alias: alias, entityType: entity.id.entityType, entityId: entity.id.id}; | |
394 | - resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias; | |
395 | - resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entities); | |
396 | - index++; | |
397 | - processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred); | |
398 | - } else { | |
399 | - if (!resolution.error) { | |
400 | - resolution.error = 'dashboard.invalid-aliases-config'; | |
401 | - } | |
402 | - index++; | |
403 | - processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred); | |
404 | - } | |
405 | - } | |
406 | - ); | |
407 | - } else { | |
408 | - deferred.resolve(resolution); | |
409 | - } | |
410 | - }*/ | |
411 | - | |
412 | - /*function processEntityAliases(entityAliases, stateParams) { | |
413 | - var deferred = $q.defer(); | |
414 | - var resolution = { | |
415 | - aliasesInfo: {} | |
416 | - }; | |
417 | - var aliasIds = []; | |
418 | - if (entityAliases) { | |
419 | - for (var aliasId in entityAliases) { | |
420 | - aliasIds.push(aliasId); | |
421 | - } | |
422 | - } | |
423 | - processEntityAlias(0, aliasIds, entityAliases, stateParams, resolution, deferred); | |
424 | - return deferred.promise; | |
425 | - }*/ | |
426 | - | |
427 | 500 | function getEntityKeys(entityType, entityId, query, type) { |
428 | 501 | var deferred = $q.defer(); |
429 | 502 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; |
... | ... | @@ -889,4 +962,4 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
889 | 962 | } |
890 | 963 | } |
891 | 964 | |
892 | -} | |
\ No newline at end of file | ||
965 | +} | ... | ... |
... | ... | @@ -258,17 +258,17 @@ export default class Subscription { |
258 | 258 | } else { |
259 | 259 | subscription.rpcEnabled = subscription.ctx.$scope.widgetEditMode ? true : false; |
260 | 260 | } |
261 | - subscription.callbacks.rpcStateChanged(this); | |
261 | + subscription.callbacks.rpcStateChanged(subscription); | |
262 | 262 | deferred.resolve(); |
263 | 263 | } else { |
264 | 264 | subscription.rpcEnabled = false; |
265 | - subscription.callbacks.rpcStateChanged(this); | |
265 | + subscription.callbacks.rpcStateChanged(subscription); | |
266 | 266 | deferred.resolve(); |
267 | 267 | } |
268 | 268 | }, |
269 | 269 | function fail () { |
270 | 270 | subscription.rpcEnabled = false; |
271 | - subscription.callbacks.rpcStateChanged(this); | |
271 | + subscription.callbacks.rpcStateChanged(subscription); | |
272 | 272 | deferred.resolve(); |
273 | 273 | } |
274 | 274 | ); | ... | ... |
... | ... | @@ -110,14 +110,12 @@ function DashboardUtils(types, utils, timeService) { |
110 | 110 | deviceAlias.deviceFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value; |
111 | 111 | if (entityAlias.filter.type == types.aliasFilterType.entityList.value) { |
112 | 112 | entityAlias.filter.entityList = deviceAlias.deviceFilter.deviceList; |
113 | - entityAlias.filter.stateEntity = false; | |
114 | 113 | } else { |
115 | 114 | entityAlias.filter.entityNameFilter = deviceAlias.deviceFilter.deviceNameFilter; |
116 | 115 | } |
117 | 116 | } else { |
118 | 117 | entityAlias.filter.type = types.aliasFilterType.entityList.value; |
119 | 118 | entityAlias.filter.entityList = [deviceAlias.deviceId]; |
120 | - entityAlias.filter.stateEntity = false; | |
121 | 119 | } |
122 | 120 | return entityAlias; |
123 | 121 | } |
... | ... | @@ -132,7 +130,6 @@ function DashboardUtils(types, utils, timeService) { |
132 | 130 | } |
133 | 131 | if (entityAlias.filter.type == types.aliasFilterType.entityList.value) { |
134 | 132 | entityAlias.filter.entityList = entityAlias.entityFilter.entityList; |
135 | - entityAlias.filter.stateEntity = false; | |
136 | 133 | } else { |
137 | 134 | entityAlias.filter.entityNameFilter = entityAlias.entityFilter.entityNameFilter; |
138 | 135 | } |
... | ... | @@ -342,7 +339,6 @@ function DashboardUtils(types, utils, timeService) { |
342 | 339 | function createSingleEntityFilter(entityType, entityId) { |
343 | 340 | return { |
344 | 341 | type: types.aliasFilterType.entityList.value, |
345 | - stateEntity: false, | |
346 | 342 | entityList: [entityId], |
347 | 343 | entityType: entityType, |
348 | 344 | resolveMultiple: false | ... | ... |
... | ... | @@ -74,6 +74,10 @@ export default angular.module('thingsboard.types', []) |
74 | 74 | value: 'entityName', |
75 | 75 | name: 'alias.filter-type-entity-name' |
76 | 76 | }, |
77 | + stateEntity: { | |
78 | + value: 'stateEntity', | |
79 | + name: 'alias.filter-type-state-entity' | |
80 | + }, | |
77 | 81 | assetType: { |
78 | 82 | value: 'assetType', |
79 | 83 | name: 'alias.filter-type-asset-type' |
... | ... | @@ -139,6 +143,53 @@ export default angular.module('thingsboard.types', []) |
139 | 143 | dashboard: "DASHBOARD", |
140 | 144 | alarm: "ALARM" |
141 | 145 | }, |
146 | + entityTypeTranslations: { | |
147 | + "DEVICE": { | |
148 | + type: 'entity.type-device', | |
149 | + list: 'entity.list-of-devices', | |
150 | + nameStartsWith: 'entity.device-name-starts-with' | |
151 | + }, | |
152 | + "ASSET": { | |
153 | + type: 'entity.type-asset', | |
154 | + list: 'entity.list-of-assets', | |
155 | + nameStartsWith: 'entity.asset-name-starts-with' | |
156 | + }, | |
157 | + "RULE": { | |
158 | + type: 'entity.type-rule', | |
159 | + list: 'entity.list-of-rules', | |
160 | + nameStartsWith: 'entity.rule-name-starts-with' | |
161 | + }, | |
162 | + "PLUGIN": { | |
163 | + type: 'entity.type-plugin', | |
164 | + list: 'entity.list-of-plugins', | |
165 | + nameStartsWith: 'entity.plugin-name-starts-with' | |
166 | + }, | |
167 | + "TENANT": { | |
168 | + type: 'entity.type-tenant', | |
169 | + list: 'entity.list-of-tenants', | |
170 | + nameStartsWith: 'entity.tenant-name-starts-with' | |
171 | + }, | |
172 | + "CUSTOMER": { | |
173 | + type: 'entity.type-customer', | |
174 | + list: 'entity.list-of-customers', | |
175 | + nameStartsWith: 'entity.customer-name-starts-with' | |
176 | + }, | |
177 | + "USER": { | |
178 | + type: 'entity.type-user', | |
179 | + list: 'entity.list-of-users', | |
180 | + nameStartsWith: 'entity.user-name-starts-with' | |
181 | + }, | |
182 | + "DASHBOARD": { | |
183 | + type: 'entity.type-dashboard', | |
184 | + list: 'entity.list-of-dashboards', | |
185 | + nameStartsWith: 'entity.dashboard-name-starts-with' | |
186 | + }, | |
187 | + "ALARM": { | |
188 | + type: 'entity.type-alarm', | |
189 | + list: 'entity.list-of-alarms', | |
190 | + nameStartsWith: 'entity.alarm-name-starts-with' | |
191 | + } | |
192 | + }, | |
142 | 193 | entitySearchDirection: { |
143 | 194 | from: "FROM", |
144 | 195 | to: "TO" | ... | ... |
... | ... | @@ -109,8 +109,7 @@ function Utils($mdColorPalette, $rootScope, $window, types) { |
109 | 109 | cleanCopy: cleanCopy, |
110 | 110 | isLocalUrl: isLocalUrl, |
111 | 111 | validateDatasources: validateDatasources, |
112 | - createKey: createKey, | |
113 | - entityTypeName: entityTypeName | |
112 | + createKey: createKey | |
114 | 113 | } |
115 | 114 | |
116 | 115 | return service; |
... | ... | @@ -358,27 +357,4 @@ function Utils($mdColorPalette, $rootScope, $window, types) { |
358 | 357 | return dataKey; |
359 | 358 | } |
360 | 359 | |
361 | - function entityTypeName (type) { | |
362 | - switch (type) { | |
363 | - case types.entityType.device: | |
364 | - return 'entity.type-device'; | |
365 | - case types.entityType.asset: | |
366 | - return 'entity.type-asset'; | |
367 | - case types.entityType.rule: | |
368 | - return 'entity.type-rule'; | |
369 | - case types.entityType.plugin: | |
370 | - return 'entity.type-plugin'; | |
371 | - case types.entityType.tenant: | |
372 | - return 'entity.type-tenant'; | |
373 | - case types.entityType.customer: | |
374 | - return 'entity.type-customer'; | |
375 | - case types.entityType.user: | |
376 | - return 'entity.type-user'; | |
377 | - case types.entityType.dashboard: | |
378 | - return 'entity.type-dashboard'; | |
379 | - case types.entityType.alarm: | |
380 | - return 'entity.type-alarm'; | |
381 | - } | |
382 | - } | |
383 | - | |
384 | 360 | } | ... | ... |
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | */ |
16 | 16 | /* eslint-disable import/no-unresolved, import/default */ |
17 | 17 | |
18 | -import entityAliasesTemplate from '../entity/entity-aliases.tpl.html'; | |
18 | +import entityAliasDialogTemplate from '../entity/entity-alias-dialog.tpl.html'; | |
19 | 19 | |
20 | 20 | /* eslint-enable import/no-unresolved, import/default */ |
21 | 21 | |
... | ... | @@ -130,17 +130,14 @@ export default function AddWidgetController($scope, widgetService, entityService |
130 | 130 | var singleEntityAlias = {id: null, alias: alias, filter: {}}; |
131 | 131 | |
132 | 132 | $mdDialog.show({ |
133 | - controller: 'EntityAliasesController', | |
133 | + controller: 'EntityAliasDialogController', | |
134 | 134 | controllerAs: 'vm', |
135 | - templateUrl: entityAliasesTemplate, | |
135 | + templateUrl: entityAliasDialogTemplate, | |
136 | 136 | locals: { |
137 | - config: { | |
138 | - entityAliases: angular.copy(vm.dashboard.configuration.entityAliases), | |
139 | - widgets: null, | |
140 | - isSingleEntityAlias: true, | |
141 | - singleEntityAlias: singleEntityAlias, | |
142 | - allowedEntityTypes: allowedEntityTypes | |
143 | - } | |
137 | + isAdd: true, | |
138 | + allowedEntityTypes: allowedEntityTypes, | |
139 | + entityAliases: vm.dashboard.configuration.entityAliases, | |
140 | + alias: singleEntityAlias | |
144 | 141 | }, |
145 | 142 | parent: angular.element($document[0].body), |
146 | 143 | fullscreen: true, | ... | ... |
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | */ |
16 | 16 | /* eslint-disable import/no-unresolved, import/default */ |
17 | 17 | |
18 | -import entityAliasesTemplate from '../entity/entity-aliases.tpl.html'; | |
18 | +import entityAliasDialogTemplate from '../entity/entity-alias-dialog.tpl.html'; | |
19 | 19 | import editWidgetTemplate from './edit-widget.tpl.html'; |
20 | 20 | |
21 | 21 | /* eslint-enable import/no-unresolved, import/default */ |
... | ... | @@ -98,17 +98,14 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid |
98 | 98 | var singleEntityAlias = {id: null, alias: alias, filter: {}}; |
99 | 99 | |
100 | 100 | $mdDialog.show({ |
101 | - controller: 'EntityAliasesController', | |
101 | + controller: 'EntityAliasDialogController', | |
102 | 102 | controllerAs: 'vm', |
103 | - templateUrl: entityAliasesTemplate, | |
103 | + templateUrl: entityAliasDialogTemplate, | |
104 | 104 | locals: { |
105 | - config: { | |
106 | - entityAliases: angular.copy(scope.dashboard.configuration.entityAliases), | |
107 | - widgets: null, | |
108 | - isSingleEntityAlias: true, | |
109 | - singleEntityAlias: singleEntityAlias, | |
110 | - allowedEntityTypes: allowedEntityTypes | |
111 | - } | |
105 | + isAdd: true, | |
106 | + allowedEntityTypes: allowedEntityTypes, | |
107 | + entityAliases: scope.dashboard.configuration.entityAliases, | |
108 | + alias: singleEntityAlias | |
112 | 109 | }, |
113 | 110 | parent: angular.element($document[0].body), |
114 | 111 | fullscreen: true, | ... | ... |
ui/src/app/entity/entity-alias-dialog.controller.js
renamed from
ui/src/app/entity/entity-filter-dialog.controller.js
... | ... | @@ -14,22 +14,48 @@ |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 | |
17 | +import './entity-alias-dialog.scss'; | |
18 | + | |
17 | 19 | /*@ngInject*/ |
18 | -export default function EntityFilterDialogController($scope, $mdDialog, $q, entityService, types, isAdd, allowedEntityTypes, filter) { | |
20 | +export default function EntityAliasDialogController($scope, $mdDialog, $q, $filter, utils, entityService, types, isAdd, allowedEntityTypes, entityAliases, alias) { | |
19 | 21 | |
20 | 22 | var vm = this; |
21 | 23 | |
22 | 24 | vm.types = types; |
23 | 25 | vm.isAdd = isAdd; |
24 | 26 | vm.allowedEntityTypes = allowedEntityTypes; |
25 | - vm.filter = filter; | |
27 | + if (angular.isArray(entityAliases)) { | |
28 | + vm.entityAliases = entityAliases; | |
29 | + } else { | |
30 | + vm.entityAliases = []; | |
31 | + for (var aliasId in entityAliases) { | |
32 | + vm.entityAliases.push(entityAliases[aliasId]); | |
33 | + } | |
34 | + } | |
35 | + if (vm.isAdd && !alias) { | |
36 | + vm.alias = { | |
37 | + alias: '', | |
38 | + filter: { | |
39 | + resolveMultiple: false | |
40 | + } | |
41 | + }; | |
42 | + } else { | |
43 | + vm.alias = alias; | |
44 | + } | |
26 | 45 | |
27 | 46 | vm.cancel = cancel; |
28 | 47 | vm.save = save; |
29 | 48 | |
30 | - $scope.$watch('vm.filter.type', function (newType, prevType) { | |
31 | - if (newType && newType != prevType) { | |
32 | - updateFilter(); | |
49 | + $scope.$watch('vm.alias.alias', function (newAlias) { | |
50 | + if (newAlias) { | |
51 | + var valid = true; | |
52 | + var result = $filter('filter')(vm.entityAliases, {alias: newAlias}, true); | |
53 | + if (result && result.length) { | |
54 | + if (vm.isAdd || vm.alias.id != result[0].id) { | |
55 | + valid = false; | |
56 | + } | |
57 | + } | |
58 | + $scope.theForm.aliasName.$setValidity('duplicateAliasName', valid); | |
33 | 59 | } |
34 | 60 | }); |
35 | 61 | |
... | ... | @@ -39,32 +65,13 @@ export default function EntityFilterDialogController($scope, $mdDialog, $q, enti |
39 | 65 | } |
40 | 66 | }); |
41 | 67 | |
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 | 68 | function validate() { |
62 | 69 | var deferred = $q.defer(); |
63 | 70 | var validationResult = { |
64 | 71 | entity: null, |
65 | 72 | stateEntity: false |
66 | 73 | } |
67 | - entityService.resolveAliasFilter(vm.filter, null, 1).then( | |
74 | + entityService.resolveAliasFilter(vm.alias.filter, null, 1).then( | |
68 | 75 | function success(result) { |
69 | 76 | validationResult.stateEntity = result.stateEntity; |
70 | 77 | var entities = result.entities; |
... | ... | @@ -87,12 +94,11 @@ export default function EntityFilterDialogController($scope, $mdDialog, $q, enti |
87 | 94 | function save() { |
88 | 95 | $scope.theForm.$setPristine(); |
89 | 96 | validate().then( |
90 | - function success(validationResult) { | |
91 | - $mdDialog.hide({ | |
92 | - filter: vm.filter, | |
93 | - entity: validationResult.entity, | |
94 | - stateEntity: validationResult.stateEntity | |
95 | - }); | |
97 | + function success() { | |
98 | + if (vm.isAdd) { | |
99 | + vm.alias.id = utils.guid(); | |
100 | + } | |
101 | + $mdDialog.hide(vm.alias); | |
96 | 102 | }, |
97 | 103 | function fail() { |
98 | 104 | $scope.theForm.$setValidity('entityFilter', false); |
... | ... | @@ -101,4 +107,3 @@ export default function EntityFilterDialogController($scope, $mdDialog, $q, enti |
101 | 107 | } |
102 | 108 | |
103 | 109 | } |
104 | - | ... | ... |
ui/src/app/entity/entity-alias-dialog.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-alias-dialog { | |
18 | + .tb-resolve-multiple-switch { | |
19 | + padding-left: 10px; | |
20 | + .resolve-multiple-switch { | |
21 | + margin: 0; | |
22 | + } | |
23 | + .resolve-multiple-label { | |
24 | + margin: 5px 0; | |
25 | + } | |
26 | + } | |
27 | +} | |
\ No newline at end of file | ... | ... |
ui/src/app/entity/entity-alias-dialog.tpl.html
renamed from
ui/src/app/entity/entity-filter-dialog.tpl.html
... | ... | @@ -15,11 +15,11 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<md-dialog class="tb-entity-filter-dialog" style="width: 600px;" aria-label="{{ 'alias.entity-filter' | translate }}"> | |
18 | +<md-dialog class="tb-entity-alias-dialog" style="width: 600px;" aria-label="{{ (vm.isAdd ? 'alias.add' : 'alias.edit') | translate }}"> | |
19 | 19 | <form name="theForm" ng-submit="vm.save()"> |
20 | 20 | <md-toolbar> |
21 | 21 | <div class="md-toolbar-tools"> |
22 | - <h2>{{ (vm.isAdd ? 'alias.create-entity-filter' : 'alias.edit-entity-filter') | translate }}</h2> | |
22 | + <h2>{{ (vm.isAdd ? 'alias.add' : 'alias.edit') | translate }}</h2> | |
23 | 23 | <span flex></span> |
24 | 24 | <md-button class="md-icon-button" ng-click="vm.cancel()"> |
25 | 25 | <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
... | ... | @@ -32,56 +32,29 @@ |
32 | 32 | <div class="md-dialog-content"> |
33 | 33 | <fieldset ng-disabled="loading"> |
34 | 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> | |
35 | + <div layout="row"> | |
36 | + <md-input-container flex class="md-block"> | |
37 | + <label translate>alias.name</label> | |
38 | + <input required name="aliasName" | |
39 | + ng-model="vm.alias.alias" | |
40 | + aria-label="{{ 'alias.name' | translate }}"> | |
41 | + <div ng-messages="theForm.aliasName.$error"> | |
42 | + <div ng-message="required" translate>alias.name-required</div> | |
43 | + <div ng-message="duplicateAliasName" translate>alias.duplicate-alias</div> | |
81 | 44 | </div> |
82 | - | |
83 | 45 | </md-input-container> |
84 | - </section> | |
46 | + <section class="tb-resolve-multiple-switch" layout="column" layout-align="start center"> | |
47 | + <label class="tb-small resolve-multiple-label" translate>alias.resolve-multiple</label> | |
48 | + <md-switch class="resolve-multiple-switch" ng-model="vm.alias.filter.resolveMultiple" | |
49 | + aria-label="{{ 'alias.resolve-multiple' | translate }}"> | |
50 | + </md-switch> | |
51 | + </section> | |
52 | + </div> | |
53 | + <tb-entity-filter | |
54 | + ng-model="vm.alias.filter" | |
55 | + allowed-entity-types="vm.allowedEntityTypes" | |
56 | + the-form="theForm"> | |
57 | + </tb-entity-filter> | |
85 | 58 | <div class="tb-error-messages" ng-messages="theForm.$error" role="alert"> |
86 | 59 | <div translate ng-message="entityFilter" class="tb-error-message">alias.entity-filter-no-entity-matched</div> |
87 | 60 | </div> |
... | ... | @@ -92,9 +65,9 @@ |
92 | 65 | <md-dialog-actions layout="row"> |
93 | 66 | <span flex></span> |
94 | 67 | <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> |
95 | - {{ 'action.save' | translate }} | |
68 | + {{ (vm.isAdd ? 'action.add' : 'action.save') | translate }} | |
96 | 69 | </md-button> |
97 | 70 | <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> |
98 | 71 | </md-dialog-actions> |
99 | 72 | </form> |
100 | -</md-dialog> | |
\ No newline at end of file | ||
73 | +</md-dialog> | ... | ... |
... | ... | @@ -15,22 +15,27 @@ |
15 | 15 | */ |
16 | 16 | import './entity-aliases.scss'; |
17 | 17 | |
18 | +/* eslint-disable import/no-unresolved, import/default */ | |
19 | + | |
20 | +import entityAliasDialogTemplate from './entity-alias-dialog.tpl.html'; | |
21 | + | |
22 | +/* eslint-enable import/no-unresolved, import/default */ | |
23 | + | |
18 | 24 | /*@ngInject*/ |
19 | 25 | export default function EntityAliasesController(utils, entityService, toast, $scope, $mdDialog, $document, $q, $translate, |
20 | 26 | types, config) { |
21 | 27 | |
22 | 28 | var vm = this; |
23 | 29 | |
24 | - vm.isSingleEntityAlias = config.isSingleEntityAlias; | |
25 | - vm.singleEntityAlias = config.singleEntityAlias; | |
30 | + vm.types = types; | |
26 | 31 | vm.entityAliases = []; |
27 | 32 | vm.title = config.customTitle ? config.customTitle : 'entity.aliases'; |
28 | 33 | vm.disableAdd = config.disableAdd; |
29 | 34 | vm.aliasToWidgetsMap = {}; |
30 | 35 | vm.allowedEntityTypes = config.allowedEntityTypes; |
31 | 36 | |
32 | - vm.onFilterEntityChanged = onFilterEntityChanged; | |
33 | 37 | vm.addAlias = addAlias; |
38 | + vm.editAlias = editAlias; | |
34 | 39 | vm.removeAlias = removeAlias; |
35 | 40 | |
36 | 41 | vm.cancel = cancel; |
... | ... | @@ -79,42 +84,61 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
79 | 84 | } |
80 | 85 | } |
81 | 86 | |
82 | - if (vm.isSingleEntityAlias) { | |
83 | - checkEntityAlias(vm.singleEntityAlias); | |
84 | - } | |
85 | - | |
86 | 87 | for (aliasId in config.entityAliases) { |
87 | 88 | var entityAlias = config.entityAliases[aliasId]; |
88 | - var result = {id: aliasId, alias: entityAlias.alias, filter: entityAlias.filter, changed: true}; | |
89 | - checkEntityAlias(result); | |
89 | + var filter = entityAlias.filter; | |
90 | + if (!filter) { | |
91 | + filter = { | |
92 | + resolveMultiple: false | |
93 | + }; | |
94 | + } | |
95 | + if (!filter.resolveMultiple) { | |
96 | + filter.resolveMultiple = false; | |
97 | + } | |
98 | + var result = {id: aliasId, alias: entityAlias.alias, filter: filter}; | |
90 | 99 | vm.entityAliases.push(result); |
91 | 100 | } |
92 | 101 | } |
93 | 102 | |
94 | - function checkEntityAlias(entityAlias) { | |
95 | - if (!entityAlias.filter || entityAlias.filter == null) { | |
96 | - entityAlias.filter = {}; | |
97 | - } | |
103 | + function addAlias($event) { | |
104 | + openAliasDialog($event); | |
98 | 105 | } |
99 | 106 | |
100 | - function onFilterEntityChanged(entity, stateEntity, entityAlias) { | |
101 | - if (entityAlias) { | |
102 | - if (!entityAlias.alias || entityAlias.alias.length == 0) { | |
103 | - entityAlias.changed = false; | |
104 | - } | |
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 | - } | |
111 | - } | |
112 | - } | |
107 | + function editAlias($event, entityAlias) { | |
108 | + openAliasDialog($event, entityAlias); | |
113 | 109 | } |
114 | 110 | |
115 | - function addAlias() { | |
116 | - var entityAlias = {id: utils.guid(), alias: '', filter: {}, changed: false}; | |
117 | - vm.entityAliases.push(entityAlias); | |
111 | + function openAliasDialog($event, entityAlias) { | |
112 | + var isAdd = entityAlias ? false : true; | |
113 | + var aliasIndex; | |
114 | + if (!isAdd) { | |
115 | + aliasIndex = vm.entityAliases.indexOf(entityAlias); | |
116 | + } | |
117 | + $mdDialog.show({ | |
118 | + controller: 'EntityAliasDialogController', | |
119 | + controllerAs: 'vm', | |
120 | + templateUrl: entityAliasDialogTemplate, | |
121 | + locals: { | |
122 | + isAdd: isAdd, | |
123 | + allowedEntityTypes: vm.allowedEntityTypes, | |
124 | + entityAliases: vm.entityAliases, | |
125 | + alias: isAdd ? null : angular.copy(entityAlias) | |
126 | + }, | |
127 | + parent: angular.element($document[0].body), | |
128 | + fullscreen: true, | |
129 | + skipHide: true, | |
130 | + targetEvent: $event | |
131 | + }).then(function (alias) { | |
132 | + if (isAdd) { | |
133 | + vm.entityAliases.push(alias); | |
134 | + } else { | |
135 | + vm.entityAliases[aliasIndex] = alias; | |
136 | + } | |
137 | + if ($scope.theForm) { | |
138 | + $scope.theForm.$setDirty(); | |
139 | + } | |
140 | + }, function () { | |
141 | + }); | |
118 | 142 | } |
119 | 143 | |
120 | 144 | function removeAlias($event, entityAlias) { |
... | ... | @@ -157,43 +181,30 @@ export default function EntityAliasesController(utils, entityService, toast, $sc |
157 | 181 | var uniqueAliasList = {}; |
158 | 182 | |
159 | 183 | var valid = true; |
160 | - var aliasId; | |
161 | - var alias; | |
162 | - var i; | |
163 | - | |
164 | - if (vm.isSingleEntityAlias) { | |
165 | - if (!vm.singleEntityAlias.id) { | |
166 | - vm.singleEntityAlias.id = utils.guid(); | |
167 | - } | |
168 | - for (i = 0; i < vm.entityAliases.length; i ++) { | |
169 | - alias = vm.entityAliases[i].alias; | |
170 | - if (alias === vm.singleEntityAlias.alias) { | |
171 | - valid = false; | |
172 | - break; | |
173 | - } | |
174 | - } | |
175 | - } else { | |
176 | - for (i = 0; i < vm.entityAliases.length; i++) { | |
177 | - aliasId = vm.entityAliases[i].id; | |
178 | - alias = vm.entityAliases[i].alias; | |
179 | - if (!uniqueAliasList[alias]) { | |
180 | - uniqueAliasList[alias] = alias; | |
181 | - entityAliases[aliasId] = {id: aliasId, alias: alias, filter: vm.entityAliases[i].filter}; | |
182 | - } else { | |
183 | - valid = false; | |
184 | - break; | |
185 | - } | |
184 | + var message, aliasId, alias, filter; | |
185 | + | |
186 | + for (var i = 0; i < vm.entityAliases.length; i++) { | |
187 | + aliasId = vm.entityAliases[i].id; | |
188 | + alias = vm.entityAliases[i].alias; | |
189 | + filter = vm.entityAliases[i].filter; | |
190 | + if (uniqueAliasList[alias]) { | |
191 | + valid = false; | |
192 | + message = $translate.instant('entity.duplicate-alias-error', {alias: alias}); | |
193 | + break; | |
194 | + } else if (!filter || !filter.type) { | |
195 | + valid = false; | |
196 | + message = $translate.instant('entity.missing-entity-filter-error', {alias: alias}); | |
197 | + break; | |
198 | + } else { | |
199 | + uniqueAliasList[alias] = alias; | |
200 | + entityAliases[aliasId] = {id: aliasId, alias: alias, filter: filter}; | |
186 | 201 | } |
187 | 202 | } |
188 | 203 | if (valid) { |
189 | 204 | $scope.theForm.$setPristine(); |
190 | - if (vm.isSingleEntityAlias) { | |
191 | - $mdDialog.hide(vm.singleEntityAlias); | |
192 | - } else { | |
193 | - $mdDialog.hide(entityAliases); | |
194 | - } | |
205 | + $mdDialog.hide(entityAliases); | |
195 | 206 | } else { |
196 | - toast.showError($translate.instant('entity.duplicate-alias-error', {alias: alias})); | |
207 | + toast.showError(message); | |
197 | 208 | } |
198 | 209 | } |
199 | 210 | ... | ... |
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | .tb-aliases-dialog { |
18 | 18 | .md-dialog-content { |
19 | 19 | padding-bottom: 0px; |
20 | + padding-top: 0px; | |
20 | 21 | } |
21 | 22 | .tb-aliases-header { |
22 | 23 | min-height: 40px; |
... | ... | @@ -33,5 +34,16 @@ |
33 | 34 | md-input-container { |
34 | 35 | margin: 0px; |
35 | 36 | } |
37 | + .tb-resolve-multiple-switch { | |
38 | + padding-left: 10px; | |
39 | + .resolve-multiple-switch { | |
40 | + margin: 0; | |
41 | + } | |
42 | + } | |
43 | + .md-button { | |
44 | + &.md-icon-button { | |
45 | + margin: 0px; | |
46 | + } | |
47 | + } | |
36 | 48 | } |
37 | 49 | } | ... | ... |
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | <form name="theForm" ng-submit="vm.save()"> |
20 | 20 | <md-toolbar> |
21 | 21 | <div class="md-toolbar-tools"> |
22 | - <h2>{{ vm.isSingleEntityAlias ? ('entity.configure-alias' | translate:vm.singleEntityAlias ) : (vm.title | translate) }}</h2> | |
22 | + <h2>{{ vm.title | translate }}</h2> | |
23 | 23 | <span flex></span> |
24 | 24 | <md-button class="md-icon-button" ng-click="vm.cancel()"> |
25 | 25 | <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> |
... | ... | @@ -28,66 +28,72 @@ |
28 | 28 | </md-toolbar> |
29 | 29 | <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear> |
30 | 30 | <span style="min-height: 5px;" flex="" ng-show="!loading"></span> |
31 | - <div class="tb-aliases-header" ng-show="!vm.isSingleEntityAlias" flex layout="row" layout-align="start center"> | |
31 | + <div class="tb-aliases-header" flex layout="row" layout-align="start center"> | |
32 | 32 | <span flex="5"></span> |
33 | 33 | <div flex layout="row" layout-align="start center"> |
34 | - <span class="tb-header-label" translate flex="20" style="min-width: 150px;">entity.alias</span> | |
35 | - <div flex="80" layout="row" layout-align="start center" style="min-width: 240px; padding-left: 10px;"> | |
36 | - <span class="tb-header-label" translate flex="70">alias.entity-filter</span> | |
37 | - <span class="tb-header-label" translate flex="30" style="padding-left: 10px;" >alias.resolve-multiple</span> | |
38 | - </div> | |
39 | - <span style="min-width: 40px; margin: 0 6px;"></span> | |
34 | + <span class="tb-header-label" translate flex="20" style="min-width: 150px;">alias.name</span> | |
35 | + <span class="tb-header-label" translate flex="70" style="padding-left: 10px;">alias.entity-filter</span> | |
36 | + <span class="tb-header-label" translate flex="10" style="padding-left: 10px; min-width: 120px;">alias.resolve-multiple</span> | |
37 | + <span style="min-width: 80px;"></span> | |
40 | 38 | </div> |
41 | 39 | </div> |
42 | - <md-divider ng-show="!vm.isSingleEntityAlias"></md-divider> | |
40 | + <md-divider></md-divider> | |
43 | 41 | <md-dialog-content> |
44 | 42 | <div class="md-dialog-content"> |
45 | 43 | <fieldset ng-disabled="loading"> |
46 | - <div ng-show="vm.isSingleEntityAlias" layout="row"> | |
47 | - <tb-entity-filter flex | |
48 | - allowed-entity-types="vm.allowedEntityTypes" | |
49 | - ng-model="vm.singleEntityAlias.filter"> | |
50 | - </tb-entity-filter> | |
51 | - </div> | |
52 | - <div ng-show="!vm.isSingleEntityAlias" style="height: 100%; overflow: auto; padding-bottom: 20px;"> | |
53 | - <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index"> | |
54 | - <span flex="5">{{$index + 1}}.</span> | |
55 | - <div class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center"> | |
56 | - <md-input-container flex="20" style="min-width: 150px;" md-no-float class="md-block"> | |
57 | - <input required ng-change="entityAlias.changed=true" name="alias" placeholder="{{ 'entity.alias' | translate }}" ng-model="entityAlias.alias"> | |
58 | - <div ng-messages="aliasForm.alias.$error"> | |
59 | - <div translate ng-message="required">entity.alias-required</div> | |
60 | - </div> | |
61 | - </md-input-container> | |
62 | - <tb-entity-filter flex="80" style="min-width: 240px; padding-left: 10px;" | |
63 | - hide-labels | |
64 | - allowed-entity-types="vm.allowedEntityTypes" | |
65 | - ng-model="entityAlias.filter" | |
66 | - on-matching-entity-change="vm.onFilterEntityChanged(entity, stateEntity, entityAlias)"> | |
67 | - </tb-entity-filter> | |
68 | - <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;" | |
69 | - ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}"> | |
70 | - <md-tooltip md-direction="top"> | |
71 | - {{ 'entity.remove-alias' | translate }} | |
72 | - </md-tooltip> | |
73 | - <md-icon aria-label="{{ 'action.delete' | translate }}" class="material-icons"> | |
74 | - close | |
75 | - </md-icon> | |
76 | - </md-button> | |
77 | - </div> | |
78 | - </div> | |
44 | + <div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index"> | |
45 | + <span flex="5">{{$index + 1}}.</span> | |
46 | + <di class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center"> | |
47 | + <md-input-container flex="20" style="min-width: 150px;" md-no-float class="md-block"> | |
48 | + <input required name="alias" placeholder="{{ 'entity.alias' | translate }}" ng-model="entityAlias.alias"> | |
49 | + <div ng-messages="aliasForm.alias.$error"> | |
50 | + <div translate ng-message="required">entity.alias-required</div> | |
51 | + </div> | |
52 | + </md-input-container> | |
53 | + <tb-entity-filter-view | |
54 | + flex="70" style="padding-left: 10px;" | |
55 | + ng-model="entityAlias.filter"> | |
56 | + </tb-entity-filter-view> | |
57 | + <section flex="10" style="padding-left: 10px; min-width: 120px;" | |
58 | + class="tb-resolve-multiple-switch" | |
59 | + layout="column" | |
60 | + layout-align="center center"> | |
61 | + <md-switch class="resolve-multiple-switch" | |
62 | + ng-model="entityAlias.filter.resolveMultiple" | |
63 | + aria-label="resolve-multiple-switcher"> | |
64 | + </md-switch> | |
65 | + </section> | |
66 | + <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;" | |
67 | + ng-click="vm.editAlias($event, entityAlias)" aria-label="{{ 'action.edit' | translate }}"> | |
68 | + <md-tooltip md-direction="top"> | |
69 | + {{ 'alias.edit' | translate }} | |
70 | + </md-tooltip> | |
71 | + <md-icon aria-label="{{ 'alias.edit' | translate }}" class="material-icons"> | |
72 | + edit | |
73 | + </md-icon> | |
74 | + </md-button> | |
75 | + <md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;" | |
76 | + ng-click="vm.removeAlias($event, entityAlias)" aria-label="{{ 'action.remove' | translate }}"> | |
77 | + <md-tooltip md-direction="top"> | |
78 | + {{ 'entity.remove-alias' | translate }} | |
79 | + </md-tooltip> | |
80 | + <md-icon aria-label="{{ 'action.delete' | translate }}" class="material-icons"> | |
81 | + close | |
82 | + </md-icon> | |
83 | + </md-button> | |
84 | + </di> | |
79 | 85 | </div> |
80 | 86 | </fieldset> |
81 | 87 | </div> |
82 | 88 | </md-dialog-content> |
83 | 89 | <md-dialog-actions layout="row"> |
84 | - <md-button ng-show="!vm.isSingleEntityAlias && !vm.disableAdd" ng-disabled="loading" class="md-primary md-raised" | |
90 | + <md-button ng-show="!vm.disableAdd" ng-disabled="loading" class="md-primary md-raised" | |
85 | 91 | ng-click="vm.addAlias($event)" |
86 | - aria-label="{{ 'action.add' | translate }}"> | |
92 | + aria-label="{{ 'alias.add' | translate }}"> | |
87 | 93 | <md-tooltip md-direction="top"> |
88 | - {{ 'entity.add-alias' | translate }} | |
94 | + {{ 'alias.add' | translate }} | |
89 | 95 | </md-tooltip> |
90 | - <span translate>action.add</span> | |
96 | + <span translate>alias.add</span> | |
91 | 97 | </md-button> |
92 | 98 | <span flex></span> |
93 | 99 | <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary"> | ... | ... |
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 entityFilterViewTemplate from './entity-filter-view.tpl.html'; | |
20 | + | |
21 | +/* eslint-enable import/no-unresolved, import/default */ | |
22 | + | |
23 | +import './entity-filter-view.scss'; | |
24 | + | |
25 | +/*@ngInject*/ | |
26 | +export default function EntityFilterViewDirective($compile, $templateCache, $q, $document, $mdDialog, $translate, types/*, entityService*/) { | |
27 | + | |
28 | + var linker = function (scope, element, attrs, ngModelCtrl) { | |
29 | + | |
30 | + var template = $templateCache.get(entityFilterViewTemplate); | |
31 | + element.html(template); | |
32 | + | |
33 | + scope.ngModelCtrl = ngModelCtrl; | |
34 | + scope.types = types; | |
35 | + scope.filterDisplayValue = ''; | |
36 | + | |
37 | + scope.$watch('filter', function () { | |
38 | + scope.updateDisplayValue(); | |
39 | + }); | |
40 | + | |
41 | + scope.updateDisplayValue = function() { | |
42 | + if (scope.filter && scope.filter.type) { | |
43 | + var entityType; | |
44 | + var prefix; | |
45 | + switch (scope.filter.type) { | |
46 | + case types.aliasFilterType.entityList.value: | |
47 | + entityType = scope.filter.entityType; | |
48 | + var count = scope.filter.entityList.length; | |
49 | + scope.filterDisplayValue = $translate.instant(types.entityTypeTranslations[entityType].list, {count: count}, 'messageformat'); | |
50 | + break; | |
51 | + case types.aliasFilterType.entityName.value: | |
52 | + entityType = scope.filter.entityType; | |
53 | + prefix = scope.filter.entityNameFilter; | |
54 | + scope.filterDisplayValue = $translate.instant(types.entityTypeTranslations[entityType].nameStartsWith, {prefix: prefix}); | |
55 | + break; | |
56 | + case types.aliasFilterType.stateEntity.value: | |
57 | + scope.filterDisplayValue = $translate.instant('alias.filter-type-state-entity-description'); | |
58 | + break; | |
59 | + case types.aliasFilterType.assetType.value: | |
60 | + var assetType = scope.filter.assetType; | |
61 | + prefix = scope.filter.assetNameFilter; | |
62 | + if (prefix && prefix.length) { | |
63 | + scope.filterDisplayValue = $translate.instant('alias.filter-type-asset-type-and-name-description', {assetType: assetType, prefix: prefix}); | |
64 | + } else { | |
65 | + scope.filterDisplayValue = $translate.instant('alias.filter-type-asset-type-description', {assetType: assetType}); | |
66 | + } | |
67 | + break; | |
68 | + case types.aliasFilterType.deviceType.value: | |
69 | + var deviceType = scope.filter.deviceType; | |
70 | + prefix = scope.filter.deviceNameFilter; | |
71 | + if (prefix && prefix.length) { | |
72 | + scope.filterDisplayValue = $translate.instant('alias.filter-type-device-type-and-name-description', {deviceType: deviceType, prefix: prefix}); | |
73 | + } else { | |
74 | + scope.filterDisplayValue = $translate.instant('alias.filter-type-device-type-description', {deviceType: deviceType}); | |
75 | + } | |
76 | + break; | |
77 | + //TODO: Alias filter | |
78 | + default: | |
79 | + scope.filterDisplayValue = scope.filter.type; | |
80 | + break; | |
81 | + } | |
82 | + } else { | |
83 | + scope.filterDisplayValue = ''; | |
84 | + } | |
85 | + } | |
86 | + | |
87 | + ngModelCtrl.$render = function () { | |
88 | + if (ngModelCtrl.$viewValue) { | |
89 | + scope.filter = ngModelCtrl.$viewValue; | |
90 | + } else { | |
91 | + scope.filter = null; | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + $compile(element.contents())(scope); | |
96 | + | |
97 | + } | |
98 | + | |
99 | + return { | |
100 | + restrict: "E", | |
101 | + require: "^ngModel", | |
102 | + link: linker, | |
103 | + scope: true | |
104 | + }; | |
105 | + | |
106 | +} | ... | ... |
ui/src/app/entity/entity-filter-view.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-filter-view { | |
18 | + .entity-filter-empty { | |
19 | + color: rgba(221, 44, 0, 0.87); | |
20 | + font-size: 14px; | |
21 | + line-height: 16px; | |
22 | + } | |
23 | + .entity-filter-type { | |
24 | + font-size: 14px; | |
25 | + line-height: 16px; | |
26 | + color: rgba(0, 0, 0, 0.570588); | |
27 | + } | |
28 | + .entity-filter-value { | |
29 | + font-size: 14px; | |
30 | + line-height: 16px; | |
31 | + color: rgba(0, 0, 0, 0.570588); | |
32 | + } | |
33 | +} | |
\ No newline at end of file | ... | ... |
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 | +<div layout='column' class="tb-entity-filter-view"> | |
20 | + <div ng-if="!filter || !filter.type" class="entity-filter-empty" translate>alias.no-entity-filter-specified</div> | |
21 | + <div ng-if="filter && filter.type" layout="column"> | |
22 | + <div class="entity-filter-value">{{ filterDisplayValue }}</div> | |
23 | + </div> | |
24 | +</div> | ... | ... |
... | ... | @@ -17,16 +17,13 @@ |
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'; | |
21 | 20 | |
22 | 21 | /* eslint-enable import/no-unresolved, import/default */ |
23 | 22 | |
24 | -import EntityFilterDialogController from './entity-filter-dialog.controller'; | |
25 | - | |
26 | 23 | import './entity-filter.scss'; |
27 | 24 | |
28 | 25 | /*@ngInject*/ |
29 | -export default function EntityFilterDirective($compile, $templateCache, $q, $document, $mdDialog, types) { | |
26 | +export default function EntityFilterDirective($compile, $templateCache, $q, $document, $mdDialog, types, entityService) { | |
30 | 27 | |
31 | 28 | var linker = function (scope, element, attrs, ngModelCtrl) { |
32 | 29 | |
... | ... | @@ -35,66 +32,59 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc |
35 | 32 | |
36 | 33 | scope.ngModelCtrl = ngModelCtrl; |
37 | 34 | scope.types = types; |
38 | - scope.hideLabels = angular.isDefined(attrs.hideLabels); | |
35 | + scope.aliasFilterTypes = entityService.getAliasFilterTypesByEntityTypes(scope.allowedEntityTypes); | |
39 | 36 | |
40 | - scope.updateValidity = function() { | |
41 | - if (ngModelCtrl.$viewValue) { | |
42 | - var value = ngModelCtrl.$viewValue; | |
43 | - ngModelCtrl.$setValidity('filter', value.type ? true : false); | |
37 | + scope.$watch('filter.type', function (newType, prevType) { | |
38 | + if (newType && newType != prevType) { | |
39 | + updateFilter(); | |
44 | 40 | } |
45 | - } | |
41 | + }); | |
46 | 42 | |
47 | - ngModelCtrl.$render = function () { | |
48 | - if (ngModelCtrl.$viewValue) { | |
49 | - scope.model = angular.copy(ngModelCtrl.$viewValue); | |
50 | - } else { | |
51 | - scope.model = { | |
52 | - type: null, | |
53 | - resolveMultiple: false | |
54 | - } | |
43 | + function updateFilter() { | |
44 | + var filter = {}; | |
45 | + filter.type = scope.filter.type; | |
46 | + filter.resolveMultiple = scope.filter.resolveMultiple; | |
47 | + switch (filter.type) { | |
48 | + case types.aliasFilterType.entityList.value: | |
49 | + filter.entityType = null; | |
50 | + filter.entityList = []; | |
51 | + break; | |
52 | + case types.aliasFilterType.entityName.value: | |
53 | + filter.entityType = null; | |
54 | + filter.entityNameFilter = ''; | |
55 | + break; | |
56 | + case types.aliasFilterType.stateEntity.value: | |
57 | + break; | |
58 | + case types.aliasFilterType.assetType.value: | |
59 | + filter.assetType = null; | |
60 | + filter.assetNameFilter = ''; | |
61 | + break; | |
62 | + case types.aliasFilterType.deviceType.value: | |
63 | + filter.deviceType = null; | |
64 | + filter.deviceNameFilter = ''; | |
65 | + break; | |
66 | + //TODO: Alias filter | |
55 | 67 | } |
68 | + scope.filter = filter; | |
56 | 69 | } |
57 | 70 | |
58 | - scope.$watch('model.resolveMultiple', function () { | |
59 | - if (ngModelCtrl.$viewValue) { | |
60 | - var value = ngModelCtrl.$viewValue; | |
61 | - value.resolveMultiple = scope.model.resolveMultiple; | |
62 | - ngModelCtrl.$setViewValue(value); | |
63 | - scope.updateValidity(); | |
64 | - } | |
71 | + scope.$watch('filter', function () { | |
72 | + scope.updateView(); | |
65 | 73 | }); |
66 | 74 | |
67 | - scope.editFilter = function($event) { | |
68 | - openEntityFilterDialog($event, false); | |
75 | + scope.updateView = function() { | |
76 | + ngModelCtrl.$setViewValue(scope.filter); | |
69 | 77 | } |
70 | 78 | |
71 | - scope.createFilter = function($event) { | |
72 | - openEntityFilterDialog($event, true); | |
73 | - } | |
74 | - | |
75 | - function openEntityFilterDialog($event, isAdd) { | |
76 | - $mdDialog.show({ | |
77 | - controller: EntityFilterDialogController, | |
78 | - controllerAs: 'vm', | |
79 | - templateUrl: entityFilterDialogTemplate, | |
80 | - locals: { | |
81 | - isAdd: isAdd, | |
82 | - allowedEntityTypes: scope.allowedEntityTypes, | |
83 | - filter: angular.copy(scope.model) | |
84 | - }, | |
85 | - parent: angular.element($document[0].body), | |
86 | - fullscreen: true, | |
87 | - skipHide: true, | |
88 | - targetEvent: $event | |
89 | - }).then(function (result) { | |
90 | - scope.model = result.filter; | |
91 | - ngModelCtrl.$setViewValue(result.filter); | |
92 | - scope.updateValidity(); | |
93 | - if (scope.onMatchingEntityChange) { | |
94 | - scope.onMatchingEntityChange({entity: result.entity, stateEntity: result.stateEntity}); | |
79 | + ngModelCtrl.$render = function () { | |
80 | + if (ngModelCtrl.$viewValue) { | |
81 | + scope.filter = ngModelCtrl.$viewValue; | |
82 | + } else { | |
83 | + scope.filter = { | |
84 | + type: null, | |
85 | + resolveMultiple: false | |
95 | 86 | } |
96 | - }, function () { | |
97 | - }); | |
87 | + } | |
98 | 88 | } |
99 | 89 | |
100 | 90 | $compile(element.contents())(scope); |
... | ... | @@ -106,8 +96,8 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc |
106 | 96 | require: "^ngModel", |
107 | 97 | link: linker, |
108 | 98 | scope: { |
109 | - allowedEntityTypes: '=?', | |
110 | - onMatchingEntityChange: '&' | |
99 | + theForm: '=', | |
100 | + allowedEntityTypes: '=?' | |
111 | 101 | } |
112 | 102 | }; |
113 | 103 | ... | ... |
... | ... | @@ -13,22 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | + | |
16 | 17 | .tb-entity-filter { |
17 | - .tb-filter-switch { | |
18 | - padding-left: 10px; | |
19 | - .filter-switch { | |
20 | - margin: 0; | |
21 | - } | |
22 | - .filter-label { | |
23 | - margin: 5px 0; | |
24 | - } | |
25 | - } | |
26 | - .tb-error-messages { | |
27 | - margin-top: -11px; | |
28 | - height: 35px; | |
29 | - .tb-error-message { | |
30 | - padding-left: 8px; | |
31 | - padding-top: 14px; | |
32 | - } | |
33 | - } | |
18 | + | |
34 | 19 | } |
\ No newline at end of file | ... | ... |
... | ... | @@ -15,37 +15,77 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<section layout='row' class="tb-entity-filter"> | |
19 | - <section layout="row" flex="70"> | |
20 | - <section flex layout="column" layout-align="center start"> | |
21 | - <div ng-if="model.type">{{ types.aliasFilterType[model.type].name | translate }}</div> | |
22 | - <md-button ng-if="!model.type" | |
23 | - ng-disabled="loading" class="md-primary" | |
24 | - ng-click="createFilter($event)" | |
25 | - aria-label="{{ 'alias.create-entity-filter' | translate }}"> | |
26 | - <md-icon aria-label="{{ 'alias.create-entity-filter' | translate }}" | |
27 | - class="material-icons"> | |
28 | - add | |
29 | - </md-icon> | |
30 | - {{ 'alias.create-entity-filter' | translate }} | |
31 | - </md-button> | |
32 | - </section> | |
33 | - <md-button ng-if="model.type" ng-disabled="loading" class="md-icon-button md-primary" | |
34 | - style="min-width: 40px;" | |
35 | - ng-click="editFilter($event)" | |
36 | - aria-label="{{ 'alias.edit-entity-filter' | translate }}"> | |
37 | - <md-tooltip md-direction="top"> | |
38 | - {{ 'alias.edit-entity-filter' | translate }} | |
39 | - </md-tooltip> | |
40 | - <md-icon aria-label="{{ 'alias.edit-entity-filter' | translate }}" | |
41 | - class="material-icons"> | |
42 | - edit | |
43 | - </md-icon> | |
44 | - </md-button> | |
18 | +<div layout='column' class="tb-entity-filter"> | |
19 | + <md-input-container class="md-block"> | |
20 | + <label>{{ 'alias.filter-type' | translate }}</label> | |
21 | + <md-select required name="filterType" | |
22 | + ng-model="filter.type" aria-label="{{ 'alias.filter-type' | translate }}"> | |
23 | + <md-option ng-repeat="type in aliasFilterTypes" ng-value="type.value"> | |
24 | + {{type.name | translate}} | |
25 | + </md-option> | |
26 | + </md-select> | |
27 | + <div ng-messages="theForm.filterType.$error"> | |
28 | + <div ng-message="required" translate>alias.filter-type-required</div> | |
29 | + </div> | |
30 | + </md-input-container> | |
31 | + <section layout="column" ng-if="filter.type == types.aliasFilterType.entityList.value" id="entityListFilter"> | |
32 | + <tb-entity-type-select | |
33 | + ng-model="filter.entityType" | |
34 | + the-form="theForm" | |
35 | + tb-required="true" | |
36 | + allowed-entity-types="allowedEntityTypes"> | |
37 | + </tb-entity-type-select> | |
38 | + <tb-entity-list | |
39 | + ng-model="filter.entityList" | |
40 | + tb-required="true" | |
41 | + entity-type="filter.entityType"> | |
42 | + </tb-entity-list> | |
45 | 43 | </section> |
46 | - <section class="tb-filter-switch" layout="column" flex="30" layout-align="center center"> | |
47 | - <label ng-if="!hideLabels" class="tb-small filter-label" translate>alias.resolve-multiple</label> | |
48 | - <md-switch class="filter-switch" ng-model="model.resolveMultiple" aria-label="resolve-multiple-switcher"> | |
49 | - </md-switch> | |
44 | + <section flex layout="column" ng-if="filter.type == types.aliasFilterType.entityName.value" id="entityNameFilter"> | |
45 | + <tb-entity-type-select | |
46 | + ng-model="filter.entityType" | |
47 | + the-form="theForm" | |
48 | + tb-required="true" | |
49 | + allowed-entity-types="allowedEntityTypes"> | |
50 | + </tb-entity-type-select> | |
51 | + <md-input-container class="md-block"> | |
52 | + <label translate>entity.name-starts-with</label> | |
53 | + <input required name="entityNameFilter" | |
54 | + ng-model="filter.entityNameFilter" | |
55 | + aria-label="{{ 'entity.name-starts-with' | translate }}"> | |
56 | + <div ng-messages="theForm.entityNameFilter.$error"> | |
57 | + <div ng-message="required" translate>entity.entity-name-filter-required</div> | |
58 | + </div> | |
59 | + </md-input-container> | |
50 | 60 | </section> |
51 | -</section> | |
61 | + <section layout="column" ng-if="filter.type == types.aliasFilterType.stateEntity.value" id="stateEntityFilter"> | |
62 | + </section> | |
63 | + <section layout="column" ng-if="filter.type == types.aliasFilterType.assetType.value" id="assetTypeFilter"> | |
64 | + <tb-entity-subtype-autocomplete | |
65 | + tb-required="true" | |
66 | + the-form="theForm" | |
67 | + ng-model="filter.assetType" | |
68 | + entity-type="types.entityType.asset"> | |
69 | + </tb-entity-subtype-autocomplete> | |
70 | + <md-input-container class="md-block"> | |
71 | + <label translate>asset.name-starts-with</label> | |
72 | + <input name="assetNameFilter" | |
73 | + ng-model="filter.assetNameFilter" | |
74 | + aria-label="{{ 'asset.name-starts-with' | translate }}"> | |
75 | + </md-input-container> | |
76 | + </section> | |
77 | + <section layout="column" ng-if="filter.type == types.aliasFilterType.deviceType.value" id="deviceTypeFilter"> | |
78 | + <tb-entity-subtype-autocomplete | |
79 | + tb-required="true" | |
80 | + the-form="theForm" | |
81 | + ng-model="filter.deviceType" | |
82 | + entity-type="types.entityType.device"> | |
83 | + </tb-entity-subtype-autocomplete> | |
84 | + <md-input-container class="md-block"> | |
85 | + <label translate>device.name-starts-with</label> | |
86 | + <input name="deviceNameFilter" | |
87 | + ng-model="filter.deviceNameFilter" | |
88 | + aria-label="{{ 'device.name-starts-with' | translate }}"> | |
89 | + </md-input-container> | |
90 | + </section> | |
91 | +</div> | ... | ... |
... | ... | @@ -71,7 +71,7 @@ export default function EntityTypeSelect($compile, $templateCache, utils, userSe |
71 | 71 | } |
72 | 72 | |
73 | 73 | scope.typeName = function(type) { |
74 | - return utils.entityTypeName(type); | |
74 | + return type ? types.entityTypeTranslations[type].type : ''; | |
75 | 75 | } |
76 | 76 | |
77 | 77 | scope.updateValidity = function () { | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | |
17 | 17 | import EntityAliasesController from './entity-aliases.controller'; |
18 | +import EntityAliasDialogController from './entity-alias-dialog.controller'; | |
18 | 19 | import EntityTypeSelectDirective from './entity-type-select.directive'; |
19 | 20 | import EntitySubtypeSelectDirective from './entity-subtype-select.directive'; |
20 | 21 | import EntitySubtypeAutocompleteDirective from './entity-subtype-autocomplete.directive'; |
... | ... | @@ -22,6 +23,7 @@ import EntityAutocompleteDirective from './entity-autocomplete.directive'; |
22 | 23 | import EntityListDirective from './entity-list.directive'; |
23 | 24 | import EntitySelectDirective from './entity-select.directive'; |
24 | 25 | import EntityFilterDirective from './entity-filter.directive'; |
26 | +import EntityFilterViewDirective from './entity-filter-view.directive'; | |
25 | 27 | import AliasesEntitySelectPanelController from './aliases-entity-select-panel.controller'; |
26 | 28 | import AliasesEntitySelectDirective from './aliases-entity-select.directive'; |
27 | 29 | import AddAttributeDialogController from './attribute/add-attribute-dialog.controller'; |
... | ... | @@ -32,6 +34,7 @@ import RelationTypeAutocompleteDirective from './relation/relation-type-autocomp |
32 | 34 | |
33 | 35 | export default angular.module('thingsboard.entity', []) |
34 | 36 | .controller('EntityAliasesController', EntityAliasesController) |
37 | + .controller('EntityAliasDialogController', EntityAliasDialogController) | |
35 | 38 | .controller('AliasesEntitySelectPanelController', AliasesEntitySelectPanelController) |
36 | 39 | .controller('AddAttributeDialogController', AddAttributeDialogController) |
37 | 40 | .controller('AddWidgetToDashboardDialogController', AddWidgetToDashboardDialogController) |
... | ... | @@ -42,6 +45,7 @@ export default angular.module('thingsboard.entity', []) |
42 | 45 | .directive('tbEntityList', EntityListDirective) |
43 | 46 | .directive('tbEntitySelect', EntitySelectDirective) |
44 | 47 | .directive('tbEntityFilter', EntityFilterDirective) |
48 | + .directive('tbEntityFilterView', EntityFilterViewDirective) | |
45 | 49 | .directive('tbAliasesEntitySelect', AliasesEntitySelectDirective) |
46 | 50 | .directive('tbAttributeTable', AttributeTableDirective) |
47 | 51 | .directive('tbRelationTable', RelationTableDirective) | ... | ... |
... | ... | @@ -218,9 +218,9 @@ function RelationTableController($scope, $q, $mdDialog, $document, $translate, $ |
218 | 218 | function success(allRelations) { |
219 | 219 | allRelations.forEach(function(relation) { |
220 | 220 | if (vm.direction == vm.types.entitySearchDirection.from) { |
221 | - relation.toEntityTypeName = $translate.instant(utils.entityTypeName(relation.to.entityType)); | |
221 | + relation.toEntityTypeName = $translate.instant(types.entityTypeTranslations[relation.to.entityType].type); | |
222 | 222 | } else { |
223 | - relation.fromEntityTypeName = $translate.instant(utils.entityTypeName(relation.from.entityType)); | |
223 | + relation.fromEntityTypeName = $translate.instant(types.entityTypeTranslations[relation.from.entityType].type); | |
224 | 224 | } |
225 | 225 | }); |
226 | 226 | vm.allRelations = allRelations; | ... | ... |
... | ... | @@ -365,7 +365,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
365 | 365 | alias = aliasInfo.aliasName; |
366 | 366 | filter = { |
367 | 367 | type: types.aliasFilterType.entityList.value, |
368 | - stateEntity: false, | |
369 | 368 | entityType: types.entityType.device, |
370 | 369 | entityList: [aliasInfo.deviceId], |
371 | 370 | resolveMultiple: false |
... | ... | @@ -378,7 +377,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
378 | 377 | resolveMultiple: false |
379 | 378 | } |
380 | 379 | if (filter.type == types.aliasFilterType.entityList.value) { |
381 | - filter.stateEntity = false; | |
382 | 380 | filter.entityList = aliasInfo.deviceFilter.deviceList |
383 | 381 | } else { |
384 | 382 | filter.entityNameFilter = aliasInfo.deviceFilter.deviceNameFilter; |
... | ... | @@ -391,7 +389,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
391 | 389 | resolveMultiple: false |
392 | 390 | } |
393 | 391 | if (filter.type == types.aliasFilterType.entityList.value) { |
394 | - filter.stateEntity = false; | |
395 | 392 | filter.entityList = aliasInfo.entityFilter.entityList; |
396 | 393 | } else { |
397 | 394 | filter.entityNameFilter = aliasInfo.entityFilter.entityNameFilter; |
... | ... | @@ -662,8 +659,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
662 | 659 | entityAliases: missingEntityAliases, |
663 | 660 | widgets: widgets, |
664 | 661 | isSingleWidget: isSingleWidget, |
665 | - isSingleEntityAlias: false, | |
666 | - singleEntityAlias: null, | |
667 | 662 | customTitle: customTitle, |
668 | 663 | disableAdd: true |
669 | 664 | } | ... | ... |
... | ... | @@ -113,23 +113,30 @@ export default angular.module('thingsboard.locale', []) |
113 | 113 | "alarm-required": "Alarm is required" |
114 | 114 | }, |
115 | 115 | "alias": { |
116 | + "add": "Add alias", | |
117 | + "edit": "Edit alias", | |
118 | + "name": "Alias name", | |
119 | + "name-required": "Alias name is required", | |
120 | + "duplicate-alias": "Alias with same name is already exists.", | |
116 | 121 | "filter-type-entity-list": "Entity list", |
117 | 122 | "filter-type-entity-name": "Entity name", |
123 | + "filter-type-state-entity": "Entity from dashboard state", | |
124 | + "filter-type-state-entity-description": "Entity taken from dashboard state parameters", | |
118 | 125 | "filter-type-asset-type": "Asset type", |
126 | + "filter-type-asset-type-description": "Assets of type '{{assetType}}'", | |
127 | + "filter-type-asset-type-and-name-description": "Assets of type '{{assetType}}' and with name starting with '{{prefix}}'", | |
119 | 128 | "filter-type-device-type": "Device type", |
129 | + "filter-type-device-type-description": "Devices of type '{{deviceType}}'", | |
130 | + "filter-type-device-type-and-name-description": "Devices of type '{{deviceType}}' and with name starting with '{{prefix}}'", | |
120 | 131 | "filter-type-relations-query": "Relations query", |
121 | 132 | "filter-type-asset-search-query": "Asset search query", |
122 | 133 | "filter-type-device-search-query": "Device search query", |
123 | 134 | "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 | 135 | "resolve-multiple": "Resolve as multiple entities", |
128 | 136 | "filter-type": "Filter type", |
129 | 137 | "filter-type-required": "Filter type is required.", |
130 | - "use-state-entity": "Use state entity", | |
131 | - "state-entity": "State entity", | |
132 | 138 | "entity-filter-no-entity-matched": "No entities matching specified filter were found.", |
139 | + "no-entity-filter-specified": "No entity filter specified" | |
133 | 140 | }, |
134 | 141 | "asset": { |
135 | 142 | "asset": "Asset", |
... | ... | @@ -185,7 +192,8 @@ export default angular.module('thingsboard.locale', []) |
185 | 192 | "idCopiedMessage": "Asset Id has been copied to clipboard", |
186 | 193 | "select-asset": "Select asset", |
187 | 194 | "no-assets-matching": "No assets matching '{{entity}}' were found.", |
188 | - "asset-required": "Asset is required" | |
195 | + "asset-required": "Asset is required", | |
196 | + "name-starts-with": "Asset name starts with" | |
189 | 197 | }, |
190 | 198 | "attribute": { |
191 | 199 | "attributes": "Attributes", |
... | ... | @@ -463,7 +471,7 @@ export default angular.module('thingsboard.locale', []) |
463 | 471 | "alias-required": "Device alias is required.", |
464 | 472 | "remove-alias": "Remove device alias", |
465 | 473 | "add-alias": "Add device alias", |
466 | - "name-starts-with": "Name starts with", | |
474 | + "name-starts-with": "Device name starts with", | |
467 | 475 | "device-list": "Device list", |
468 | 476 | "use-device-name-filter": "Use filter", |
469 | 477 | "device-list-empty": "No devices selected.", |
... | ... | @@ -549,6 +557,7 @@ export default angular.module('thingsboard.locale', []) |
549 | 557 | "unable-delete-entity-alias-title": "Unable to delete entity alias", |
550 | 558 | "unable-delete-entity-alias-text": "Entity alias '{{entityAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", |
551 | 559 | "duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Entity aliases must be unique whithin the dashboard.", |
560 | + "missing-entity-filter-error": "Filter is missing for alias '{{alias}}'.", | |
552 | 561 | "configure-alias": "Configure '{{alias}}' alias", |
553 | 562 | "alias": "Alias", |
554 | 563 | "alias-required": "Entity alias is required.", |
... | ... | @@ -562,24 +571,42 @@ export default angular.module('thingsboard.locale', []) |
562 | 571 | "entity-name-filter-required": "Entity name filter is required.", |
563 | 572 | "entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.", |
564 | 573 | "all-subtypes": "All", |
574 | + "select-entities": "Select entities", | |
575 | + "no-aliases-found": "No aliases found.", | |
576 | + "no-alias-matching": "'{{alias}}' not found.", | |
577 | + "create-new-alias": "Create a new one!", | |
578 | + "no-keys-found": "No keys found.", | |
579 | + "no-key-matching": "'{{key}}' not found.", | |
580 | + "create-new-key": "Create a new one!", | |
565 | 581 | "type": "Type", |
566 | 582 | "type-required": "Entity type is required.", |
567 | 583 | "type-device": "Device", |
584 | + "list-of-devices": "{ count, select, 1 {One device} other {List of # devices} }", | |
585 | + "device-name-starts-with": "Devices whose names start with '{{prefix}}'", | |
568 | 586 | "type-asset": "Asset", |
587 | + "list-of-assets": "{ count, select, 1 {One asset} other {List of # assets} }", | |
588 | + "asset-name-starts-with": "Assets whose names start with '{{prefix}}'", | |
569 | 589 | "type-rule": "Rule", |
590 | + "list-of-rules": "{ count, select, 1 {One rule} other {List of # rules} }", | |
591 | + "rule-name-starts-with": "Rules whose names start with '{{prefix}}'", | |
570 | 592 | "type-plugin": "Plugin", |
593 | + "list-of-plugins": "{ count, select, 1 {One plugin} other {List of # plugins} }", | |
594 | + "plugin-name-starts-with": "Plugins whose names start with '{{prefix}}'", | |
571 | 595 | "type-tenant": "Tenant", |
596 | + "list-of-tenants": "{ count, select, 1 {One tenant} other {List of # tenants} }", | |
597 | + "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'", | |
572 | 598 | "type-customer": "Customer", |
599 | + "list-of-customers": "{ count, select, 1 {One customer} other {List of # customers} }", | |
600 | + "customer-name-starts-with": "Customers whose names start with '{{prefix}}'", | |
573 | 601 | "type-user": "User", |
602 | + "list-of-users": "{ count, select, 1 {One user} other {List of # users} }", | |
603 | + "user-name-starts-with": "Users whose names start with '{{prefix}}'", | |
574 | 604 | "type-dashboard": "Dashboard", |
605 | + "list-of-dashboards": "{ count, select, 1 {One dashboard} other {List of # dashboards} }", | |
606 | + "dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'", | |
575 | 607 | "type-alarm": "Alarm", |
576 | - "select-entities": "Select entities", | |
577 | - "no-aliases-found": "No aliases found.", | |
578 | - "no-alias-matching": "'{{alias}}' not found.", | |
579 | - "create-new-alias": "Create a new one!", | |
580 | - "no-keys-found": "No keys found.", | |
581 | - "no-key-matching": "'{{key}}' not found.", | |
582 | - "create-new-key": "Create a new one!" | |
608 | + "list-of-alarms": "{ count, select, 1 {One alarms} other {List of # alarms} }", | |
609 | + "alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'" | |
583 | 610 | }, |
584 | 611 | "event": { |
585 | 612 | "event-type": "Event type", | ... | ... |