Commit 17825b2cb4425a1153718b14b3a0f19243fb241c

Authored by Igor Kulikov
Committed by GitHub
2 parents c003b20b b1a1c0bd

Merge pull request #224 from thingsboard/feature/TB-70

TB-70: Introduce default entity for alias state parameter. Add actio…
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 "resources": [], 15 "resources": [],
16 "templateHtml": "<tb-alarms-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-alarms-table-widget>", 16 "templateHtml": "<tb-alarms-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-alarms-table-widget>",
17 "templateCss": "", 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 "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}", 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 "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}", 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 "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}" 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,16 +353,20 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
353 353
354 function entitiesToEntitiesInfo(entities) { 354 function entitiesToEntitiesInfo(entities) {
355 var entitiesInfo = []; 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 return entitiesInfo; 361 return entitiesInfo;
360 } 362 }
361 363
362 function entityRelationInfosToEntitiesInfo(entityRelations, direction) { 364 function entityRelationInfosToEntitiesInfo(entityRelations, direction) {
363 var entitiesInfo = []; 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 return entitiesInfo; 371 return entitiesInfo;
368 } 372 }
@@ -371,7 +375,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -371,7 +375,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
371 function resolveAlias(entityAlias, stateParams) { 375 function resolveAlias(entityAlias, stateParams) {
372 var deferred = $q.defer(); 376 var deferred = $q.defer();
373 var filter = entityAlias.filter; 377 var filter = entityAlias.filter;
374 - resolveAliasFilter(filter, stateParams, -1).then( 378 + resolveAliasFilter(filter, stateParams, -1, false).then(
375 function (result) { 379 function (result) {
376 var aliasInfo = { 380 var aliasInfo = {
377 alias: entityAlias.alias, 381 alias: entityAlias.alias,
@@ -404,10 +408,13 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -404,10 +408,13 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
404 entityId = stateParams.entityId; 408 entityId = stateParams.entityId;
405 } 409 }
406 } 410 }
  411 + if (!entityId) {
  412 + entityId = filter.defaultStateEntity;
  413 + }
407 return entityId; 414 return entityId;
408 } 415 }
409 416
410 - function resolveAliasFilter(filter, stateParams, maxItems) { 417 + function resolveAliasFilter(filter, stateParams, maxItems, failOnEmpty) {
411 var deferred = $q.defer(); 418 var deferred = $q.defer();
412 var result = { 419 var result = {
413 entities: [], 420 entities: [],
@@ -421,7 +428,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -421,7 +428,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
421 case types.aliasFilterType.entityList.value: 428 case types.aliasFilterType.entityList.value:
422 getEntities(filter.entityType, filter.entityList).then( 429 getEntities(filter.entityType, filter.entityList).then(
423 function success(entities) { 430 function success(entities) {
424 - if (entities && entities.length) { 431 + if (entities && entities.length || !failOnEmpty) {
425 result.entities = entitiesToEntitiesInfo(entities); 432 result.entities = entitiesToEntitiesInfo(entities);
426 deferred.resolve(result); 433 deferred.resolve(result);
427 } else { 434 } else {
@@ -436,7 +443,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -436,7 +443,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
436 case types.aliasFilterType.entityName.value: 443 case types.aliasFilterType.entityName.value:
437 getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then( 444 getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then(
438 function success(entities) { 445 function success(entities) {
439 - if (entities && entities.length) { 446 + if (entities && entities.length || !failOnEmpty) {
440 result.entities = entitiesToEntitiesInfo(entities); 447 result.entities = entitiesToEntitiesInfo(entities);
441 deferred.resolve(result); 448 deferred.resolve(result);
442 } else { 449 } else {
@@ -457,7 +464,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -457,7 +464,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
457 deferred.resolve(result); 464 deferred.resolve(result);
458 }, 465 },
459 function fail() { 466 function fail() {
460 - deferred.reject(); 467 + deferred.resolve(result);
461 } 468 }
462 ); 469 );
463 } else { 470 } else {
@@ -467,7 +474,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -467,7 +474,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
467 case types.aliasFilterType.assetType.value: 474 case types.aliasFilterType.assetType.value:
468 getEntitiesByNameFilter(types.entityType.asset, filter.assetNameFilter, maxItems, null, filter.assetType).then( 475 getEntitiesByNameFilter(types.entityType.asset, filter.assetNameFilter, maxItems, null, filter.assetType).then(
469 function success(entities) { 476 function success(entities) {
470 - if (entities && entities.length) { 477 + if (entities && entities.length || !failOnEmpty) {
471 result.entities = entitiesToEntitiesInfo(entities); 478 result.entities = entitiesToEntitiesInfo(entities);
472 deferred.resolve(result); 479 deferred.resolve(result);
473 } else { 480 } else {
@@ -482,7 +489,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -482,7 +489,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
482 case types.aliasFilterType.deviceType.value: 489 case types.aliasFilterType.deviceType.value:
483 getEntitiesByNameFilter(types.entityType.device, filter.deviceNameFilter, maxItems, null, filter.deviceType).then( 490 getEntitiesByNameFilter(types.entityType.device, filter.deviceNameFilter, maxItems, null, filter.deviceType).then(
484 function success(entities) { 491 function success(entities) {
485 - if (entities && entities.length) { 492 + if (entities && entities.length || !failOnEmpty) {
486 result.entities = entitiesToEntitiesInfo(entities); 493 result.entities = entitiesToEntitiesInfo(entities);
487 deferred.resolve(result); 494 deferred.resolve(result);
488 } else { 495 } else {
@@ -517,8 +524,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -517,8 +524,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
517 searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1; 524 searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1;
518 entityRelationService.findInfoByQuery(searchQuery).then( 525 entityRelationService.findInfoByQuery(searchQuery).then(
519 function success(allRelations) { 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 var limit = Math.min(allRelations.length, maxItems); 529 var limit = Math.min(allRelations.length, maxItems);
523 allRelations.length = limit; 530 allRelations.length = limit;
524 } 531 }
@@ -566,8 +573,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -566,8 +573,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
566 } 573 }
567 findByQueryPromise.then( 574 findByQueryPromise.then(
568 function success(entities) { 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 var limit = Math.min(entities.length, maxItems); 578 var limit = Math.min(entities.length, maxItems);
572 entities.length = limit; 579 entities.length = limit;
573 } 580 }
@@ -720,7 +727,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device @@ -720,7 +727,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
720 727
721 function checkEntityAlias(entityAlias) { 728 function checkEntityAlias(entityAlias) {
722 var deferred = $q.defer(); 729 var deferred = $q.defer();
723 - resolveAliasFilter(entityAlias.filter, null, 1).then( 730 + resolveAliasFilter(entityAlias.filter, null, 1, true).then(
724 function success(result) { 731 function success(result) {
725 if (result.stateEntity) { 732 if (result.stateEntity) {
726 deferred.resolve(true); 733 deferred.resolve(true);
@@ -737,7 +737,15 @@ export default class Subscription { @@ -737,7 +737,15 @@ export default class Subscription {
737 this.ctx.datasourceService.subscribeToDatasource(listener); 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 this.notifyDataLoaded(); 749 this.notifyDataLoaded();
742 this.onDataUpdated(); 750 this.onDataUpdated();
743 } 751 }
@@ -767,7 +775,14 @@ export default class Subscription { @@ -767,7 +775,14 @@ export default class Subscription {
767 775
768 this.ctx.alarmService.subscribeForAlarms(this.alarmSourceListener); 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 this.notifyDataLoaded(); 786 this.notifyDataLoaded();
772 this.onDataUpdated(); 787 this.onDataUpdated();
773 } 788 }
@@ -282,10 +282,30 @@ export default function EntityStateController($scope, $location, $state, $stateP @@ -282,10 +282,30 @@ export default function EntityStateController($scope, $location, $state, $stateP
282 282
283 function updateLocation() { 283 function updateLocation() {
284 if (vm.stateObject[vm.stateObject.length-1].id) { 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,7 +71,7 @@ export default function EntityAliasDialogController($scope, $mdDialog, $q, $filt
71 entity: null, 71 entity: null,
72 stateEntity: false 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 function success(result) { 75 function success(result) {
76 validationResult.stateEntity = result.stateEntity; 76 validationResult.stateEntity = result.stateEntity;
77 var entities = result.entities; 77 var entities = result.entities;
@@ -95,12 +95,16 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter @@ -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,6 +55,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
55 break; 55 break;
56 case types.aliasFilterType.stateEntity.value: 56 case types.aliasFilterType.stateEntity.value:
57 filter.stateEntityParamName = null; 57 filter.stateEntityParamName = null;
  58 + filter.defaultStateEntity = null;
58 break; 59 break;
59 case types.aliasFilterType.assetType.value: 60 case types.aliasFilterType.assetType.value:
60 filter.assetType = null; 61 filter.assetType = null;
@@ -69,6 +70,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc @@ -69,6 +70,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
69 case types.aliasFilterType.deviceSearchQuery.value: 70 case types.aliasFilterType.deviceSearchQuery.value:
70 filter.rootStateEntity = false; 71 filter.rootStateEntity = false;
71 filter.stateEntityParamName = null; 72 filter.stateEntityParamName = null;
  73 + filter.defaultStateEntity = null;
72 filter.rootEntity = null; 74 filter.rootEntity = null;
73 filter.direction = types.entitySearchDirection.from; 75 filter.direction = types.entitySearchDirection.from;
74 filter.maxLevel = 1; 76 filter.maxLevel = 1;
@@ -66,6 +66,14 @@ @@ -66,6 +66,14 @@
66 ng-model="filter.stateEntityParamName" 66 ng-model="filter.stateEntityParamName"
67 aria-label="{{ 'alias.state-entity-parameter-name' | translate }}"> 67 aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
68 </md-input-container> 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 </section> 77 </section>
70 <section layout="column" ng-if="filter.type == types.aliasFilterType.assetType.value" id="assetTypeFilter"> 78 <section layout="column" ng-if="filter.type == types.aliasFilterType.assetType.value" id="assetTypeFilter">
71 <tb-entity-subtype-autocomplete 79 <tb-entity-subtype-autocomplete
@@ -97,27 +105,35 @@ @@ -97,27 +105,35 @@
97 </section> 105 </section>
98 <section layout="column" ng-if="filter.type == types.aliasFilterType.relationsQuery.value" id="relationsQueryFilter"> 106 <section layout="column" ng-if="filter.type == types.aliasFilterType.relationsQuery.value" id="relationsQueryFilter">
99 <label class="tb-small">{{ 'alias.root-entity' | translate }}</label> 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 <tb-entity-select flex 115 <tb-entity-select flex
102 the-form="theForm" 116 the-form="theForm"
103 tb-required="!filter.rootStateEntity" 117 tb-required="!filter.rootStateEntity"
104 ng-disabled="filter.rootStateEntity" 118 ng-disabled="filter.rootStateEntity"
105 ng-model="filter.rootEntity"> 119 ng-model="filter.rootEntity">
106 </tb-entity-select> 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 </div> 137 </div>
122 </div> 138 </div>
123 <div flex layout="row"> 139 <div flex layout="row">
@@ -148,27 +164,35 @@ @@ -148,27 +164,35 @@
148 </section> 164 </section>
149 <section layout="column" ng-if="filter.type == types.aliasFilterType.assetSearchQuery.value" id="assetSearchQueryFilter"> 165 <section layout="column" ng-if="filter.type == types.aliasFilterType.assetSearchQuery.value" id="assetSearchQueryFilter">
150 <label class="tb-small">{{ 'alias.root-entity' | translate }}</label> 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 <tb-entity-select flex 174 <tb-entity-select flex
153 the-form="theForm" 175 the-form="theForm"
154 tb-required="!filter.rootStateEntity" 176 tb-required="!filter.rootStateEntity"
155 ng-disabled="filter.rootStateEntity" 177 ng-disabled="filter.rootStateEntity"
156 ng-model="filter.rootEntity"> 178 ng-model="filter.rootEntity">
157 </tb-entity-select> 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 </div> 196 </div>
173 </div> 197 </div>
174 <div flex layout="row"> 198 <div flex layout="row">
@@ -207,27 +231,35 @@ @@ -207,27 +231,35 @@
207 </section> 231 </section>
208 <section layout="column" ng-if="filter.type == types.aliasFilterType.deviceSearchQuery.value" id="deviceSearchQueryFilter"> 232 <section layout="column" ng-if="filter.type == types.aliasFilterType.deviceSearchQuery.value" id="deviceSearchQueryFilter">
209 <label class="tb-small">{{ 'alias.root-entity' | translate }}</label> 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 <tb-entity-select flex 241 <tb-entity-select flex
212 the-form="theForm" 242 the-form="theForm"
213 tb-required="!filter.rootStateEntity" 243 tb-required="!filter.rootStateEntity"
214 ng-disabled="filter.rootStateEntity" 244 ng-disabled="filter.rootStateEntity"
215 ng-model="filter.rootEntity"> 245 ng-model="filter.rootEntity">
216 </tb-entity-select> 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 </div> 263 </div>
232 </div> 264 </div>
233 <div flex layout="row"> 265 <div flex layout="row">
@@ -48,6 +48,7 @@ export default function EntitySelect($compile, $templateCache) { @@ -48,6 +48,7 @@ export default function EntitySelect($compile, $templateCache) {
48 } 48 }
49 49
50 ngModelCtrl.$render = function () { 50 ngModelCtrl.$render = function () {
  51 + destroyWatchers();
51 if (ngModelCtrl.$viewValue) { 52 if (ngModelCtrl.$viewValue) {
52 var value = ngModelCtrl.$viewValue; 53 var value = ngModelCtrl.$viewValue;
53 scope.model.entityType = value.entityType; 54 scope.model.entityType = value.entityType;
@@ -56,19 +57,43 @@ export default function EntitySelect($compile, $templateCache) { @@ -56,19 +57,43 @@ export default function EntitySelect($compile, $templateCache) {
56 scope.model.entityType = null; 57 scope.model.entityType = null;
57 scope.model.entityId = null; 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 $compile(element.contents())(scope); 98 $compile(element.contents())(scope);
74 } 99 }
@@ -188,6 +188,7 @@ export default angular.module('thingsboard.locale', []) @@ -188,6 +188,7 @@ export default angular.module('thingsboard.locale', [])
188 "root-state-entity": "Use dashboard state entity as root", 188 "root-state-entity": "Use dashboard state entity as root",
189 "root-entity": "Root entity", 189 "root-entity": "Root entity",
190 "state-entity-parameter-name": "State entity parameter name", 190 "state-entity-parameter-name": "State entity parameter name",
  191 + "default-state-entity": "Default state entity",
191 "default-entity-parameter-name": "By default", 192 "default-entity-parameter-name": "By default",
192 "max-relation-level": "Max relation level", 193 "max-relation-level": "Max relation level",
193 "unlimited-level": "Unlimited level", 194 "unlimited-level": "Unlimited level",
@@ -69,6 +69,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia @@ -69,6 +69,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
69 vm.displayDetails = true; 69 vm.displayDetails = true;
70 vm.allowAcknowledgment = true; 70 vm.allowAcknowledgment = true;
71 vm.allowClear = true; 71 vm.allowClear = true;
  72 + vm.actionCellDescriptors = [];
72 vm.displayPagination = true; 73 vm.displayPagination = true;
73 vm.defaultPageSize = 10; 74 vm.defaultPageSize = 10;
74 vm.defaultSortOrder = '-'+types.alarmFields.createdTime.value; 75 vm.defaultSortOrder = '-'+types.alarmFields.createdTime.value;
@@ -94,6 +95,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia @@ -94,6 +95,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
94 vm.onReorder = onReorder; 95 vm.onReorder = onReorder;
95 vm.onPaginate = onPaginate; 96 vm.onPaginate = onPaginate;
96 vm.onRowClick = onRowClick; 97 vm.onRowClick = onRowClick;
  98 + vm.onActionButtonClick = onActionButtonClick;
97 vm.isCurrent = isCurrent; 99 vm.isCurrent = isCurrent;
98 vm.openAlarmDetails = openAlarmDetails; 100 vm.openAlarmDetails = openAlarmDetails;
99 vm.ackAlarms = ackAlarms; 101 vm.ackAlarms = ackAlarms;
@@ -157,6 +159,8 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia @@ -157,6 +159,8 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
157 159
158 vm.ctx.widgetActions = [ vm.searchAction ]; 160 vm.ctx.widgetActions = [ vm.searchAction ];
159 161
  162 + vm.actionCellDescriptors = vm.ctx.actionsApi.getActionDescriptors('actionCellButton');
  163 +
160 if (vm.settings.alarmsTitle && vm.settings.alarmsTitle.length) { 164 if (vm.settings.alarmsTitle && vm.settings.alarmsTitle.length) {
161 vm.alarmsTitle = utils.customTranslation(vm.settings.alarmsTitle, vm.settings.alarmsTitle); 165 vm.alarmsTitle = utils.customTranslation(vm.settings.alarmsTitle, vm.settings.alarmsTitle);
162 } else { 166 } else {
@@ -280,9 +284,35 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia @@ -280,9 +284,35 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
280 } 284 }
281 285
282 function onRowClick($event, alarm) { 286 function onRowClick($event, alarm) {
  287 + if ($event) {
  288 + $event.stopPropagation();
  289 + }
283 if (vm.currentAlarm != alarm) { 290 if (vm.currentAlarm != alarm) {
284 vm.currentAlarm = alarm; 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 function isCurrent(alarm) { 318 function isCurrent(alarm) {
@@ -64,6 +64,7 @@ @@ -64,6 +64,7 @@
64 <tr md-row> 64 <tr md-row>
65 <th md-column md-order-by="{{ key.name }}" ng-repeat="key in vm.alarmSource.dataKeys"><span>{{ key.title }}</span></th> 65 <th md-column md-order-by="{{ key.name }}" ng-repeat="key in vm.alarmSource.dataKeys"><span>{{ key.title }}</span></th>
66 <th md-column ng-if="vm.displayDetails"><span>&nbsp</span></th> 66 <th md-column ng-if="vm.displayDetails"><span>&nbsp</span></th>
  67 + <th md-column ng-if="vm.actionCellDescriptors.length"><span>&nbsp</span></th>
67 </tr> 68 </tr>
68 </thead> 69 </thead>
69 <tbody md-body> 70 <tbody md-body>
@@ -83,6 +84,19 @@ @@ -83,6 +84,19 @@
83 </md-tooltip> 84 </md-tooltip>
84 </md-button> 85 </md-button>
85 </td> 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 </tr> 100 </tr>
87 </tbody> 101 </tbody>
88 </table> 102 </table>
@@ -107,6 +107,7 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra @@ -107,6 +107,7 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra
107 vm.datasources = vm.subscription.datasources; 107 vm.datasources = vm.subscription.datasources;
108 initializeConfig(); 108 initializeConfig();
109 updateDatasources(); 109 updateDatasources();
  110 + updateEntities();
110 } 111 }
111 }); 112 });
112 113
@@ -276,16 +277,16 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra @@ -276,16 +277,16 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra
276 } 277 }
277 if (vm.currentEntity != entity) { 278 if (vm.currentEntity != entity) {
278 vm.currentEntity = entity; 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