Commit 17825b2cb4425a1153718b14b3a0f19243fb241c
Committed by
GitHub
Merge pull request #224 from thingsboard/feature/TB-70
TB-70: Introduce default entity for alias state parameter. Add actio…
Showing
13 changed files
with
239 additions
and
88 deletions
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | "resources": [], |
16 | 16 | "templateHtml": "<tb-alarms-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-alarms-table-widget>", |
17 | 17 | "templateCss": "", |
18 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('alarms-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.onDestroy = function() {\n}\n", | |
18 | + "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('alarms-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", | |
19 | 19 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"AlarmTableSettings\",\n \"properties\": {\n \"alarmsTitle\": {\n \"title\": \"Alarms table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSelection\": {\n \"title\": \"Enable alarms selection\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSearch\": {\n \"title\": \"Enable alarms search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayDetails\": {\n \"title\": \"Display alarm details\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowAcknowledgment\": {\n \"title\": \"Allow alarms acknowledgment\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowClear\": {\n \"title\": \"Allow alarms clear\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"-createdTime\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"alarmsTitle\",\n \"enableSelection\",\n \"enableSearch\",\n \"displayDetails\",\n \"allowAcknowledgment\",\n \"allowClear\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\"\n ]\n}", |
20 | 20 | "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, alarm, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", |
21 | 21 | "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\"},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"18px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5}" | ... | ... |
... | ... | @@ -353,16 +353,20 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
353 | 353 | |
354 | 354 | function entitiesToEntitiesInfo(entities) { |
355 | 355 | var entitiesInfo = []; |
356 | - for (var d = 0; d < entities.length; d++) { | |
357 | - entitiesInfo.push(entityToEntityInfo(entities[d])); | |
356 | + if (entities) { | |
357 | + for (var d = 0; d < entities.length; d++) { | |
358 | + entitiesInfo.push(entityToEntityInfo(entities[d])); | |
359 | + } | |
358 | 360 | } |
359 | 361 | return entitiesInfo; |
360 | 362 | } |
361 | 363 | |
362 | 364 | function entityRelationInfosToEntitiesInfo(entityRelations, direction) { |
363 | 365 | var entitiesInfo = []; |
364 | - for (var d = 0; d < entityRelations.length; d++) { | |
365 | - entitiesInfo.push(entityRelationInfoToEntityInfo(entityRelations[d], direction)); | |
366 | + if (entityRelations) { | |
367 | + for (var d = 0; d < entityRelations.length; d++) { | |
368 | + entitiesInfo.push(entityRelationInfoToEntityInfo(entityRelations[d], direction)); | |
369 | + } | |
366 | 370 | } |
367 | 371 | return entitiesInfo; |
368 | 372 | } |
... | ... | @@ -371,7 +375,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
371 | 375 | function resolveAlias(entityAlias, stateParams) { |
372 | 376 | var deferred = $q.defer(); |
373 | 377 | var filter = entityAlias.filter; |
374 | - resolveAliasFilter(filter, stateParams, -1).then( | |
378 | + resolveAliasFilter(filter, stateParams, -1, false).then( | |
375 | 379 | function (result) { |
376 | 380 | var aliasInfo = { |
377 | 381 | alias: entityAlias.alias, |
... | ... | @@ -404,10 +408,13 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
404 | 408 | entityId = stateParams.entityId; |
405 | 409 | } |
406 | 410 | } |
411 | + if (!entityId) { | |
412 | + entityId = filter.defaultStateEntity; | |
413 | + } | |
407 | 414 | return entityId; |
408 | 415 | } |
409 | 416 | |
410 | - function resolveAliasFilter(filter, stateParams, maxItems) { | |
417 | + function resolveAliasFilter(filter, stateParams, maxItems, failOnEmpty) { | |
411 | 418 | var deferred = $q.defer(); |
412 | 419 | var result = { |
413 | 420 | entities: [], |
... | ... | @@ -421,7 +428,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
421 | 428 | case types.aliasFilterType.entityList.value: |
422 | 429 | getEntities(filter.entityType, filter.entityList).then( |
423 | 430 | function success(entities) { |
424 | - if (entities && entities.length) { | |
431 | + if (entities && entities.length || !failOnEmpty) { | |
425 | 432 | result.entities = entitiesToEntitiesInfo(entities); |
426 | 433 | deferred.resolve(result); |
427 | 434 | } else { |
... | ... | @@ -436,7 +443,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
436 | 443 | case types.aliasFilterType.entityName.value: |
437 | 444 | getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then( |
438 | 445 | function success(entities) { |
439 | - if (entities && entities.length) { | |
446 | + if (entities && entities.length || !failOnEmpty) { | |
440 | 447 | result.entities = entitiesToEntitiesInfo(entities); |
441 | 448 | deferred.resolve(result); |
442 | 449 | } else { |
... | ... | @@ -457,7 +464,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
457 | 464 | deferred.resolve(result); |
458 | 465 | }, |
459 | 466 | function fail() { |
460 | - deferred.reject(); | |
467 | + deferred.resolve(result); | |
461 | 468 | } |
462 | 469 | ); |
463 | 470 | } else { |
... | ... | @@ -467,7 +474,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
467 | 474 | case types.aliasFilterType.assetType.value: |
468 | 475 | getEntitiesByNameFilter(types.entityType.asset, filter.assetNameFilter, maxItems, null, filter.assetType).then( |
469 | 476 | function success(entities) { |
470 | - if (entities && entities.length) { | |
477 | + if (entities && entities.length || !failOnEmpty) { | |
471 | 478 | result.entities = entitiesToEntitiesInfo(entities); |
472 | 479 | deferred.resolve(result); |
473 | 480 | } else { |
... | ... | @@ -482,7 +489,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
482 | 489 | case types.aliasFilterType.deviceType.value: |
483 | 490 | getEntitiesByNameFilter(types.entityType.device, filter.deviceNameFilter, maxItems, null, filter.deviceType).then( |
484 | 491 | function success(entities) { |
485 | - if (entities && entities.length) { | |
492 | + if (entities && entities.length || !failOnEmpty) { | |
486 | 493 | result.entities = entitiesToEntitiesInfo(entities); |
487 | 494 | deferred.resolve(result); |
488 | 495 | } else { |
... | ... | @@ -517,8 +524,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
517 | 524 | searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1; |
518 | 525 | entityRelationService.findInfoByQuery(searchQuery).then( |
519 | 526 | function success(allRelations) { |
520 | - if (allRelations && allRelations.length) { | |
521 | - if (angular.isDefined(maxItems) && maxItems > 0) { | |
527 | + if (allRelations && allRelations.length || !failOnEmpty) { | |
528 | + if (angular.isDefined(maxItems) && maxItems > 0 && allRelations) { | |
522 | 529 | var limit = Math.min(allRelations.length, maxItems); |
523 | 530 | allRelations.length = limit; |
524 | 531 | } |
... | ... | @@ -566,8 +573,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
566 | 573 | } |
567 | 574 | findByQueryPromise.then( |
568 | 575 | function success(entities) { |
569 | - if (entities && entities.length) { | |
570 | - if (angular.isDefined(maxItems) && maxItems > 0) { | |
576 | + if (entities && entities.length || !failOnEmpty) { | |
577 | + if (angular.isDefined(maxItems) && maxItems > 0 && entities) { | |
571 | 578 | var limit = Math.min(entities.length, maxItems); |
572 | 579 | entities.length = limit; |
573 | 580 | } |
... | ... | @@ -720,7 +727,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device |
720 | 727 | |
721 | 728 | function checkEntityAlias(entityAlias) { |
722 | 729 | var deferred = $q.defer(); |
723 | - resolveAliasFilter(entityAlias.filter, null, 1).then( | |
730 | + resolveAliasFilter(entityAlias.filter, null, 1, true).then( | |
724 | 731 | function success(result) { |
725 | 732 | if (result.stateEntity) { |
726 | 733 | deferred.resolve(true); | ... | ... |
... | ... | @@ -737,7 +737,15 @@ export default class Subscription { |
737 | 737 | this.ctx.datasourceService.subscribeToDatasource(listener); |
738 | 738 | } |
739 | 739 | |
740 | - if (datasource.unresolvedStateEntity || !datasource.dataKeys.length) { | |
740 | + var forceUpdate = false; | |
741 | + if (datasource.unresolvedStateEntity || | |
742 | + !datasource.dataKeys.length || | |
743 | + (datasource.type === this.ctx.types.datasourceType.entity && !datasource.entityId) | |
744 | + ) { | |
745 | + forceUpdate = true; | |
746 | + } | |
747 | + | |
748 | + if (forceUpdate) { | |
741 | 749 | this.notifyDataLoaded(); |
742 | 750 | this.onDataUpdated(); |
743 | 751 | } |
... | ... | @@ -767,7 +775,14 @@ export default class Subscription { |
767 | 775 | |
768 | 776 | this.ctx.alarmService.subscribeForAlarms(this.alarmSourceListener); |
769 | 777 | |
770 | - if (this.alarmSource.unresolvedStateEntity) { | |
778 | + var forceUpdate = false; | |
779 | + if (this.alarmSource.unresolvedStateEntity || | |
780 | + (this.alarmSource.type === this.ctx.types.datasourceType.entity && !this.alarmSource.entityId) | |
781 | + ) { | |
782 | + forceUpdate = true; | |
783 | + } | |
784 | + | |
785 | + if (forceUpdate) { | |
771 | 786 | this.notifyDataLoaded(); |
772 | 787 | this.onDataUpdated(); |
773 | 788 | } | ... | ... |
... | ... | @@ -282,10 +282,30 @@ export default function EntityStateController($scope, $location, $state, $stateP |
282 | 282 | |
283 | 283 | function updateLocation() { |
284 | 284 | if (vm.stateObject[vm.stateObject.length-1].id) { |
285 | - $location.search({state : utils.objToBase64(vm.stateObject)}); | |
285 | + if (isDefaultState()) { | |
286 | + $location.search({state : null}); | |
287 | + } else { | |
288 | + $location.search({state : utils.objToBase64(vm.stateObject)}); | |
289 | + } | |
286 | 290 | } |
287 | 291 | } |
288 | 292 | |
293 | + function isDefaultState() { | |
294 | + if (vm.stateObject.length == 1) { | |
295 | + var state = vm.stateObject[0]; | |
296 | + var rootStateId = dashboardUtils.getRootStateId(vm.states); | |
297 | + if (state.id == rootStateId && (!state.params || isEmpty(state.params))) { | |
298 | + return true; | |
299 | + } | |
300 | + } | |
301 | + return false; | |
302 | + } | |
289 | 303 | |
304 | + function isEmpty(map) { | |
305 | + for(var key in map) { | |
306 | + return !map.hasOwnProperty(key); | |
307 | + } | |
308 | + return true; | |
309 | + } | |
290 | 310 | |
291 | 311 | } | ... | ... |
... | ... | @@ -71,7 +71,7 @@ export default function EntityAliasDialogController($scope, $mdDialog, $q, $filt |
71 | 71 | entity: null, |
72 | 72 | stateEntity: false |
73 | 73 | } |
74 | - entityService.resolveAliasFilter(vm.alias.filter, null, 1).then( | |
74 | + entityService.resolveAliasFilter(vm.alias.filter, null, 1, true).then( | |
75 | 75 | function success(result) { |
76 | 76 | validationResult.stateEntity = result.stateEntity; |
77 | 77 | var entities = result.entities; | ... | ... |
... | ... | @@ -95,12 +95,16 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter |
95 | 95 | } |
96 | 96 | }); |
97 | 97 | |
98 | - scope.$watch('entity', function () { | |
99 | - scope.updateView(); | |
98 | + scope.$watch('entity', function (newVal, prevVal) { | |
99 | + if (!angular.equals(newVal, prevVal)) { | |
100 | + scope.updateView(); | |
101 | + } | |
100 | 102 | }); |
101 | 103 | |
102 | - scope.$watch('disabled', function () { | |
103 | - scope.updateView(); | |
104 | + scope.$watch('disabled', function (newVal, prevVal) { | |
105 | + if (!angular.equals(newVal, prevVal)) { | |
106 | + scope.updateView(); | |
107 | + } | |
104 | 108 | }); |
105 | 109 | |
106 | 110 | ... | ... |
... | ... | @@ -55,6 +55,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc |
55 | 55 | break; |
56 | 56 | case types.aliasFilterType.stateEntity.value: |
57 | 57 | filter.stateEntityParamName = null; |
58 | + filter.defaultStateEntity = null; | |
58 | 59 | break; |
59 | 60 | case types.aliasFilterType.assetType.value: |
60 | 61 | filter.assetType = null; |
... | ... | @@ -69,6 +70,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc |
69 | 70 | case types.aliasFilterType.deviceSearchQuery.value: |
70 | 71 | filter.rootStateEntity = false; |
71 | 72 | filter.stateEntityParamName = null; |
73 | + filter.defaultStateEntity = null; | |
72 | 74 | filter.rootEntity = null; |
73 | 75 | filter.direction = types.entitySearchDirection.from; |
74 | 76 | filter.maxLevel = 1; | ... | ... |
... | ... | @@ -66,6 +66,14 @@ |
66 | 66 | ng-model="filter.stateEntityParamName" |
67 | 67 | aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> |
68 | 68 | </md-input-container> |
69 | + <div layout="column"> | |
70 | + <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label> | |
71 | + <tb-entity-select flex | |
72 | + the-form="theForm" | |
73 | + tb-required="false" | |
74 | + ng-model="filter.defaultStateEntity"> | |
75 | + </tb-entity-select> | |
76 | + </div> | |
69 | 77 | </section> |
70 | 78 | <section layout="column" ng-if="filter.type == types.aliasFilterType.assetType.value" id="assetTypeFilter"> |
71 | 79 | <tb-entity-subtype-autocomplete |
... | ... | @@ -97,27 +105,35 @@ |
97 | 105 | </section> |
98 | 106 | <section layout="column" ng-if="filter.type == types.aliasFilterType.relationsQuery.value" id="relationsQueryFilter"> |
99 | 107 | <label class="tb-small">{{ 'alias.root-entity' | translate }}</label> |
100 | - <div flex layout="row"> | |
108 | + <section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;"> | |
109 | + <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity" | |
110 | + aria-label="{{ 'alias.root-state-entity' | translate }}"> | |
111 | + </md-switch> | |
112 | + <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label> | |
113 | + </section> | |
114 | + <div flex layout="row" ng-if="!filter.rootStateEntity"> | |
101 | 115 | <tb-entity-select flex |
102 | 116 | the-form="theForm" |
103 | 117 | tb-required="!filter.rootStateEntity" |
104 | 118 | ng-disabled="filter.rootStateEntity" |
105 | 119 | ng-model="filter.rootEntity"> |
106 | 120 | </tb-entity-select> |
107 | - <div layout="column"> | |
108 | - <section class="tb-root-state-entity-switch" layout="column" layout-align="start center"> | |
109 | - <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label> | |
110 | - <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity" | |
111 | - aria-label="{{ 'alias.root-state-entity' | translate }}"> | |
112 | - </md-switch> | |
113 | - </section> | |
114 | - <md-input-container ng-if="filter.rootStateEntity" class="md-block"> | |
115 | - <label translate>alias.state-entity-parameter-name</label> | |
116 | - <input name="stateEntityParamName" | |
117 | - placeholder="{{ 'alias.default-entity-parameter-name' | translate }}" | |
118 | - ng-model="filter.stateEntityParamName" | |
119 | - aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> | |
120 | - </md-input-container> | |
121 | + </div> | |
122 | + <div flex layout="row" ng-if="filter.rootStateEntity"> | |
123 | + <md-input-container class="md-block" style="margin-top: 32px;"> | |
124 | + <label translate>alias.state-entity-parameter-name</label> | |
125 | + <input name="stateEntityParamName" | |
126 | + placeholder="{{ 'alias.default-entity-parameter-name' | translate }}" | |
127 | + ng-model="filter.stateEntityParamName" | |
128 | + aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> | |
129 | + </md-input-container> | |
130 | + <div flex layout="column"> | |
131 | + <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label> | |
132 | + <tb-entity-select flex | |
133 | + the-form="theForm" | |
134 | + tb-required="false" | |
135 | + ng-model="filter.defaultStateEntity"> | |
136 | + </tb-entity-select> | |
121 | 137 | </div> |
122 | 138 | </div> |
123 | 139 | <div flex layout="row"> |
... | ... | @@ -148,27 +164,35 @@ |
148 | 164 | </section> |
149 | 165 | <section layout="column" ng-if="filter.type == types.aliasFilterType.assetSearchQuery.value" id="assetSearchQueryFilter"> |
150 | 166 | <label class="tb-small">{{ 'alias.root-entity' | translate }}</label> |
151 | - <div flex layout="row"> | |
167 | + <section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;"> | |
168 | + <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity" | |
169 | + aria-label="{{ 'alias.root-state-entity' | translate }}"> | |
170 | + </md-switch> | |
171 | + <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label> | |
172 | + </section> | |
173 | + <div flex layout="row" ng-if="!filter.rootStateEntity"> | |
152 | 174 | <tb-entity-select flex |
153 | 175 | the-form="theForm" |
154 | 176 | tb-required="!filter.rootStateEntity" |
155 | 177 | ng-disabled="filter.rootStateEntity" |
156 | 178 | ng-model="filter.rootEntity"> |
157 | 179 | </tb-entity-select> |
158 | - <div layout="column"> | |
159 | - <section class="tb-root-state-entity-switch" layout="column" layout-align="start center"> | |
160 | - <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label> | |
161 | - <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity" | |
162 | - aria-label="{{ 'alias.root-state-entity' | translate }}"> | |
163 | - </md-switch> | |
164 | - </section> | |
165 | - <md-input-container ng-if="filter.rootStateEntity" class="md-block"> | |
166 | - <label translate>alias.state-entity-parameter-name</label> | |
167 | - <input name="stateEntityParamName" | |
168 | - placeholder="{{ 'alias.default-entity-parameter-name' | translate }}" | |
169 | - ng-model="filter.stateEntityParamName" | |
170 | - aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> | |
171 | - </md-input-container> | |
180 | + </div> | |
181 | + <div flex layout="row" ng-if="filter.rootStateEntity"> | |
182 | + <md-input-container class="md-block" style="margin-top: 32px;"> | |
183 | + <label translate>alias.state-entity-parameter-name</label> | |
184 | + <input name="stateEntityParamName" | |
185 | + placeholder="{{ 'alias.default-entity-parameter-name' | translate }}" | |
186 | + ng-model="filter.stateEntityParamName" | |
187 | + aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> | |
188 | + </md-input-container> | |
189 | + <div flex layout="column"> | |
190 | + <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label> | |
191 | + <tb-entity-select flex | |
192 | + the-form="theForm" | |
193 | + tb-required="false" | |
194 | + ng-model="filter.defaultStateEntity"> | |
195 | + </tb-entity-select> | |
172 | 196 | </div> |
173 | 197 | </div> |
174 | 198 | <div flex layout="row"> |
... | ... | @@ -207,27 +231,35 @@ |
207 | 231 | </section> |
208 | 232 | <section layout="column" ng-if="filter.type == types.aliasFilterType.deviceSearchQuery.value" id="deviceSearchQueryFilter"> |
209 | 233 | <label class="tb-small">{{ 'alias.root-entity' | translate }}</label> |
210 | - <div flex layout="row"> | |
234 | + <section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;"> | |
235 | + <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity" | |
236 | + aria-label="{{ 'alias.root-state-entity' | translate }}"> | |
237 | + </md-switch> | |
238 | + <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label> | |
239 | + </section> | |
240 | + <div flex layout="row" ng-if="!filter.rootStateEntity"> | |
211 | 241 | <tb-entity-select flex |
212 | 242 | the-form="theForm" |
213 | 243 | tb-required="!filter.rootStateEntity" |
214 | 244 | ng-disabled="filter.rootStateEntity" |
215 | 245 | ng-model="filter.rootEntity"> |
216 | 246 | </tb-entity-select> |
217 | - <div layout="column"> | |
218 | - <section class="tb-root-state-entity-switch" layout="column" layout-align="start center"> | |
219 | - <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label> | |
220 | - <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity" | |
221 | - aria-label="{{ 'alias.root-state-entity' | translate }}"> | |
222 | - </md-switch> | |
223 | - </section> | |
224 | - <md-input-container ng-if="filter.rootStateEntity" class="md-block"> | |
225 | - <label translate>alias.state-entity-parameter-name</label> | |
226 | - <input name="stateEntityParamName" | |
227 | - placeholder="{{ 'alias.default-entity-parameter-name' | translate }}" | |
228 | - ng-model="filter.stateEntityParamName" | |
229 | - aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> | |
230 | - </md-input-container> | |
247 | + </div> | |
248 | + <div flex layout="row" ng-if="filter.rootStateEntity"> | |
249 | + <md-input-container class="md-block" style="margin-top: 32px;"> | |
250 | + <label translate>alias.state-entity-parameter-name</label> | |
251 | + <input name="stateEntityParamName" | |
252 | + placeholder="{{ 'alias.default-entity-parameter-name' | translate }}" | |
253 | + ng-model="filter.stateEntityParamName" | |
254 | + aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> | |
255 | + </md-input-container> | |
256 | + <div flex layout="column"> | |
257 | + <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label> | |
258 | + <tb-entity-select flex | |
259 | + the-form="theForm" | |
260 | + tb-required="false" | |
261 | + ng-model="filter.defaultStateEntity"> | |
262 | + </tb-entity-select> | |
231 | 263 | </div> |
232 | 264 | </div> |
233 | 265 | <div flex layout="row"> | ... | ... |
... | ... | @@ -48,6 +48,7 @@ export default function EntitySelect($compile, $templateCache) { |
48 | 48 | } |
49 | 49 | |
50 | 50 | ngModelCtrl.$render = function () { |
51 | + destroyWatchers(); | |
51 | 52 | if (ngModelCtrl.$viewValue) { |
52 | 53 | var value = ngModelCtrl.$viewValue; |
53 | 54 | scope.model.entityType = value.entityType; |
... | ... | @@ -56,19 +57,43 @@ export default function EntitySelect($compile, $templateCache) { |
56 | 57 | scope.model.entityType = null; |
57 | 58 | scope.model.entityId = null; |
58 | 59 | } |
60 | + initWatchers(); | |
59 | 61 | } |
60 | 62 | |
61 | - scope.$watch('model.entityType', function () { | |
62 | - scope.updateView(); | |
63 | - }); | |
63 | + function initWatchers() { | |
64 | + scope.entityTypeDeregistration = scope.$watch('model.entityType', function (newVal, prevVal) { | |
65 | + if (!angular.equals(newVal, prevVal)) { | |
66 | + scope.updateView(); | |
67 | + } | |
68 | + }); | |
69 | + | |
70 | + scope.entityIdDeregistration = scope.$watch('model.entityId', function (newVal, prevVal) { | |
71 | + if (!angular.equals(newVal, prevVal)) { | |
72 | + scope.updateView(); | |
73 | + } | |
74 | + }); | |
64 | 75 | |
65 | - scope.$watch('model.entityId', function () { | |
66 | - scope.updateView(); | |
67 | - }); | |
76 | + scope.disabledDeregistration = scope.$watch('disabled', function (newVal, prevVal) { | |
77 | + if (!angular.equals(newVal, prevVal)) { | |
78 | + scope.updateView(); | |
79 | + } | |
80 | + }); | |
81 | + } | |
68 | 82 | |
69 | - scope.$watch('disabled', function () { | |
70 | - scope.updateView(); | |
71 | - }); | |
83 | + function destroyWatchers() { | |
84 | + if (scope.entityTypeDeregistration) { | |
85 | + scope.entityTypeDeregistration(); | |
86 | + scope.entityTypeDeregistration = null; | |
87 | + } | |
88 | + if (scope.entityIdDeregistration) { | |
89 | + scope.entityIdDeregistration(); | |
90 | + scope.entityIdDeregistration = null; | |
91 | + } | |
92 | + if (scope.disabledDeregistration) { | |
93 | + scope.disabledDeregistration(); | |
94 | + scope.disabledDeregistration = null; | |
95 | + } | |
96 | + } | |
72 | 97 | |
73 | 98 | $compile(element.contents())(scope); |
74 | 99 | } | ... | ... |
... | ... | @@ -188,6 +188,7 @@ export default angular.module('thingsboard.locale', []) |
188 | 188 | "root-state-entity": "Use dashboard state entity as root", |
189 | 189 | "root-entity": "Root entity", |
190 | 190 | "state-entity-parameter-name": "State entity parameter name", |
191 | + "default-state-entity": "Default state entity", | |
191 | 192 | "default-entity-parameter-name": "By default", |
192 | 193 | "max-relation-level": "Max relation level", |
193 | 194 | "unlimited-level": "Unlimited level", | ... | ... |
... | ... | @@ -69,6 +69,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia |
69 | 69 | vm.displayDetails = true; |
70 | 70 | vm.allowAcknowledgment = true; |
71 | 71 | vm.allowClear = true; |
72 | + vm.actionCellDescriptors = []; | |
72 | 73 | vm.displayPagination = true; |
73 | 74 | vm.defaultPageSize = 10; |
74 | 75 | vm.defaultSortOrder = '-'+types.alarmFields.createdTime.value; |
... | ... | @@ -94,6 +95,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia |
94 | 95 | vm.onReorder = onReorder; |
95 | 96 | vm.onPaginate = onPaginate; |
96 | 97 | vm.onRowClick = onRowClick; |
98 | + vm.onActionButtonClick = onActionButtonClick; | |
97 | 99 | vm.isCurrent = isCurrent; |
98 | 100 | vm.openAlarmDetails = openAlarmDetails; |
99 | 101 | vm.ackAlarms = ackAlarms; |
... | ... | @@ -157,6 +159,8 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia |
157 | 159 | |
158 | 160 | vm.ctx.widgetActions = [ vm.searchAction ]; |
159 | 161 | |
162 | + vm.actionCellDescriptors = vm.ctx.actionsApi.getActionDescriptors('actionCellButton'); | |
163 | + | |
160 | 164 | if (vm.settings.alarmsTitle && vm.settings.alarmsTitle.length) { |
161 | 165 | vm.alarmsTitle = utils.customTranslation(vm.settings.alarmsTitle, vm.settings.alarmsTitle); |
162 | 166 | } else { |
... | ... | @@ -280,9 +284,35 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia |
280 | 284 | } |
281 | 285 | |
282 | 286 | function onRowClick($event, alarm) { |
287 | + if ($event) { | |
288 | + $event.stopPropagation(); | |
289 | + } | |
283 | 290 | if (vm.currentAlarm != alarm) { |
284 | 291 | vm.currentAlarm = alarm; |
285 | 292 | } |
293 | + var descriptors = vm.ctx.actionsApi.getActionDescriptors('rowClick'); | |
294 | + if (descriptors.length) { | |
295 | + var entityId; | |
296 | + var entityName; | |
297 | + if (vm.currentAlarm && vm.currentAlarm.originator) { | |
298 | + entityId = vm.currentAlarm.originator; | |
299 | + entityName = vm.currentAlarm.originatorName; | |
300 | + } | |
301 | + vm.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName); | |
302 | + } | |
303 | + } | |
304 | + | |
305 | + function onActionButtonClick($event, alarm, actionDescriptor) { | |
306 | + if ($event) { | |
307 | + $event.stopPropagation(); | |
308 | + } | |
309 | + var entityId; | |
310 | + var entityName; | |
311 | + if (alarm && alarm.originator) { | |
312 | + entityId = alarm.originator; | |
313 | + entityName = alarm.originatorName; | |
314 | + } | |
315 | + vm.ctx.actionsApi.handleWidgetAction($event, actionDescriptor, entityId, entityName); | |
286 | 316 | } |
287 | 317 | |
288 | 318 | function isCurrent(alarm) { | ... | ... |
... | ... | @@ -64,6 +64,7 @@ |
64 | 64 | <tr md-row> |
65 | 65 | <th md-column md-order-by="{{ key.name }}" ng-repeat="key in vm.alarmSource.dataKeys"><span>{{ key.title }}</span></th> |
66 | 66 | <th md-column ng-if="vm.displayDetails"><span> </span></th> |
67 | + <th md-column ng-if="vm.actionCellDescriptors.length"><span> </span></th> | |
67 | 68 | </tr> |
68 | 69 | </thead> |
69 | 70 | <tbody md-body> |
... | ... | @@ -83,6 +84,19 @@ |
83 | 84 | </md-tooltip> |
84 | 85 | </md-button> |
85 | 86 | </td> |
87 | + <td md-cell ng-if="vm.actionCellDescriptors.length" class="tb-action-cell" | |
88 | + ng-style="{minWidth: vm.actionCellDescriptors.length*36+'px', | |
89 | + maxWidth: vm.actionCellDescriptors.length*36+'px', | |
90 | + width: vm.actionCellDescriptors.length*36+'px'}"> | |
91 | + <md-button class="md-icon-button" ng-repeat="actionDescriptor in vm.actionCellDescriptors" | |
92 | + aria-label="{{ actionDescriptor.displayName }}" | |
93 | + ng-click="vm.onActionButtonClick($event, alarm, actionDescriptor)"> | |
94 | + <md-icon aria-label="{{ actionDescriptor.displayName }}" class="material-icons">{{actionDescriptor.icon}}</md-icon> | |
95 | + <md-tooltip md-direction="top"> | |
96 | + {{ actionDescriptor.displayName }} | |
97 | + </md-tooltip> | |
98 | + </md-button> | |
99 | + </td> | |
86 | 100 | </tr> |
87 | 101 | </tbody> |
88 | 102 | </table> | ... | ... |
... | ... | @@ -107,6 +107,7 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra |
107 | 107 | vm.datasources = vm.subscription.datasources; |
108 | 108 | initializeConfig(); |
109 | 109 | updateDatasources(); |
110 | + updateEntities(); | |
110 | 111 | } |
111 | 112 | }); |
112 | 113 | |
... | ... | @@ -276,16 +277,16 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra |
276 | 277 | } |
277 | 278 | if (vm.currentEntity != entity) { |
278 | 279 | vm.currentEntity = entity; |
279 | - var descriptors = vm.ctx.actionsApi.getActionDescriptors('rowClick'); | |
280 | - if (descriptors.length) { | |
281 | - var entityId; | |
282 | - var entityName; | |
283 | - if (vm.currentEntity) { | |
284 | - entityId = vm.currentEntity.id; | |
285 | - entityName = vm.currentEntity.entityName; | |
286 | - } | |
287 | - vm.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName); | |
280 | + } | |
281 | + var descriptors = vm.ctx.actionsApi.getActionDescriptors('rowClick'); | |
282 | + if (descriptors.length) { | |
283 | + var entityId; | |
284 | + var entityName; | |
285 | + if (vm.currentEntity) { | |
286 | + entityId = vm.currentEntity.id; | |
287 | + entityName = vm.currentEntity.entityName; | |
288 | 288 | } |
289 | + vm.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName); | |
289 | 290 | } |
290 | 291 | } |
291 | 292 | ... | ... |