thingsboard-aplcache
Changes
ui/src/app/api/entity.service.js 39(+23 -16)
ui/src/app/api/subscription.js 19(+17 -2)
ui/src/app/entity/entity-filter.tpl.html 122(+77 -45)
ui/src/app/entity/entity-select.directive.js 43(+34 -9)
ui/src/app/locale/locale.constant.js 1(+1 -0)
ui/src/app/widget/lib/alarms-table-widget.js 30(+30 -0)
Details
diff --git a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json
index aec4dd0..164366d 100644
--- a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json
+++ b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json
@@ -15,7 +15,7 @@
"resources": [],
"templateHtml": "<tb-alarms-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-alarms-table-widget>",
"templateCss": "",
- "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",
+ "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",
"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}",
"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}",
"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}"
ui/src/app/api/entity.service.js 39(+23 -16)
diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js
index b20d0b3..344edf5 100644
--- a/ui/src/app/api/entity.service.js
+++ b/ui/src/app/api/entity.service.js
@@ -353,16 +353,20 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
function entitiesToEntitiesInfo(entities) {
var entitiesInfo = [];
- for (var d = 0; d < entities.length; d++) {
- entitiesInfo.push(entityToEntityInfo(entities[d]));
+ if (entities) {
+ for (var d = 0; d < entities.length; d++) {
+ entitiesInfo.push(entityToEntityInfo(entities[d]));
+ }
}
return entitiesInfo;
}
function entityRelationInfosToEntitiesInfo(entityRelations, direction) {
var entitiesInfo = [];
- for (var d = 0; d < entityRelations.length; d++) {
- entitiesInfo.push(entityRelationInfoToEntityInfo(entityRelations[d], direction));
+ if (entityRelations) {
+ for (var d = 0; d < entityRelations.length; d++) {
+ entitiesInfo.push(entityRelationInfoToEntityInfo(entityRelations[d], direction));
+ }
}
return entitiesInfo;
}
@@ -371,7 +375,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
function resolveAlias(entityAlias, stateParams) {
var deferred = $q.defer();
var filter = entityAlias.filter;
- resolveAliasFilter(filter, stateParams, -1).then(
+ resolveAliasFilter(filter, stateParams, -1, false).then(
function (result) {
var aliasInfo = {
alias: entityAlias.alias,
@@ -404,10 +408,13 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
entityId = stateParams.entityId;
}
}
+ if (!entityId) {
+ entityId = filter.defaultStateEntity;
+ }
return entityId;
}
- function resolveAliasFilter(filter, stateParams, maxItems) {
+ function resolveAliasFilter(filter, stateParams, maxItems, failOnEmpty) {
var deferred = $q.defer();
var result = {
entities: [],
@@ -421,7 +428,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
case types.aliasFilterType.entityList.value:
getEntities(filter.entityType, filter.entityList).then(
function success(entities) {
- if (entities && entities.length) {
+ if (entities && entities.length || !failOnEmpty) {
result.entities = entitiesToEntitiesInfo(entities);
deferred.resolve(result);
} else {
@@ -436,7 +443,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
case types.aliasFilterType.entityName.value:
getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, maxItems).then(
function success(entities) {
- if (entities && entities.length) {
+ if (entities && entities.length || !failOnEmpty) {
result.entities = entitiesToEntitiesInfo(entities);
deferred.resolve(result);
} else {
@@ -457,7 +464,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
deferred.resolve(result);
},
function fail() {
- deferred.reject();
+ deferred.resolve(result);
}
);
} else {
@@ -467,7 +474,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
case types.aliasFilterType.assetType.value:
getEntitiesByNameFilter(types.entityType.asset, filter.assetNameFilter, maxItems, null, filter.assetType).then(
function success(entities) {
- if (entities && entities.length) {
+ if (entities && entities.length || !failOnEmpty) {
result.entities = entitiesToEntitiesInfo(entities);
deferred.resolve(result);
} else {
@@ -482,7 +489,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
case types.aliasFilterType.deviceType.value:
getEntitiesByNameFilter(types.entityType.device, filter.deviceNameFilter, maxItems, null, filter.deviceType).then(
function success(entities) {
- if (entities && entities.length) {
+ if (entities && entities.length || !failOnEmpty) {
result.entities = entitiesToEntitiesInfo(entities);
deferred.resolve(result);
} else {
@@ -517,8 +524,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
searchQuery.parameters.maxLevel = filter.maxLevel && filter.maxLevel > 0 ? filter.maxLevel : -1;
entityRelationService.findInfoByQuery(searchQuery).then(
function success(allRelations) {
- if (allRelations && allRelations.length) {
- if (angular.isDefined(maxItems) && maxItems > 0) {
+ if (allRelations && allRelations.length || !failOnEmpty) {
+ if (angular.isDefined(maxItems) && maxItems > 0 && allRelations) {
var limit = Math.min(allRelations.length, maxItems);
allRelations.length = limit;
}
@@ -566,8 +573,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
}
findByQueryPromise.then(
function success(entities) {
- if (entities && entities.length) {
- if (angular.isDefined(maxItems) && maxItems > 0) {
+ if (entities && entities.length || !failOnEmpty) {
+ if (angular.isDefined(maxItems) && maxItems > 0 && entities) {
var limit = Math.min(entities.length, maxItems);
entities.length = limit;
}
@@ -720,7 +727,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
function checkEntityAlias(entityAlias) {
var deferred = $q.defer();
- resolveAliasFilter(entityAlias.filter, null, 1).then(
+ resolveAliasFilter(entityAlias.filter, null, 1, true).then(
function success(result) {
if (result.stateEntity) {
deferred.resolve(true);
ui/src/app/api/subscription.js 19(+17 -2)
diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js
index 4a6f743..fd26629 100644
--- a/ui/src/app/api/subscription.js
+++ b/ui/src/app/api/subscription.js
@@ -737,7 +737,15 @@ export default class Subscription {
this.ctx.datasourceService.subscribeToDatasource(listener);
}
- if (datasource.unresolvedStateEntity || !datasource.dataKeys.length) {
+ var forceUpdate = false;
+ if (datasource.unresolvedStateEntity ||
+ !datasource.dataKeys.length ||
+ (datasource.type === this.ctx.types.datasourceType.entity && !datasource.entityId)
+ ) {
+ forceUpdate = true;
+ }
+
+ if (forceUpdate) {
this.notifyDataLoaded();
this.onDataUpdated();
}
@@ -767,7 +775,14 @@ export default class Subscription {
this.ctx.alarmService.subscribeForAlarms(this.alarmSourceListener);
- if (this.alarmSource.unresolvedStateEntity) {
+ var forceUpdate = false;
+ if (this.alarmSource.unresolvedStateEntity ||
+ (this.alarmSource.type === this.ctx.types.datasourceType.entity && !this.alarmSource.entityId)
+ ) {
+ forceUpdate = true;
+ }
+
+ if (forceUpdate) {
this.notifyDataLoaded();
this.onDataUpdated();
}
diff --git a/ui/src/app/dashboard/states/entity-state-controller.js b/ui/src/app/dashboard/states/entity-state-controller.js
index f0512d7..1e2c2ad 100644
--- a/ui/src/app/dashboard/states/entity-state-controller.js
+++ b/ui/src/app/dashboard/states/entity-state-controller.js
@@ -282,10 +282,30 @@ export default function EntityStateController($scope, $location, $state, $stateP
function updateLocation() {
if (vm.stateObject[vm.stateObject.length-1].id) {
- $location.search({state : utils.objToBase64(vm.stateObject)});
+ if (isDefaultState()) {
+ $location.search({state : null});
+ } else {
+ $location.search({state : utils.objToBase64(vm.stateObject)});
+ }
}
}
+ function isDefaultState() {
+ if (vm.stateObject.length == 1) {
+ var state = vm.stateObject[0];
+ var rootStateId = dashboardUtils.getRootStateId(vm.states);
+ if (state.id == rootStateId && (!state.params || isEmpty(state.params))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ function isEmpty(map) {
+ for(var key in map) {
+ return !map.hasOwnProperty(key);
+ }
+ return true;
+ }
}
diff --git a/ui/src/app/entity/alias/entity-alias-dialog.controller.js b/ui/src/app/entity/alias/entity-alias-dialog.controller.js
index a5b221a..d1f353d 100644
--- a/ui/src/app/entity/alias/entity-alias-dialog.controller.js
+++ b/ui/src/app/entity/alias/entity-alias-dialog.controller.js
@@ -71,7 +71,7 @@ export default function EntityAliasDialogController($scope, $mdDialog, $q, $filt
entity: null,
stateEntity: false
}
- entityService.resolveAliasFilter(vm.alias.filter, null, 1).then(
+ entityService.resolveAliasFilter(vm.alias.filter, null, 1, true).then(
function success(result) {
validationResult.stateEntity = result.stateEntity;
var entities = result.entities;
diff --git a/ui/src/app/entity/entity-autocomplete.directive.js b/ui/src/app/entity/entity-autocomplete.directive.js
index 8f8153d..4610426 100644
--- a/ui/src/app/entity/entity-autocomplete.directive.js
+++ b/ui/src/app/entity/entity-autocomplete.directive.js
@@ -95,12 +95,16 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter
}
});
- scope.$watch('entity', function () {
- scope.updateView();
+ scope.$watch('entity', function (newVal, prevVal) {
+ if (!angular.equals(newVal, prevVal)) {
+ scope.updateView();
+ }
});
- scope.$watch('disabled', function () {
- scope.updateView();
+ scope.$watch('disabled', function (newVal, prevVal) {
+ if (!angular.equals(newVal, prevVal)) {
+ scope.updateView();
+ }
});
diff --git a/ui/src/app/entity/entity-filter.directive.js b/ui/src/app/entity/entity-filter.directive.js
index db7a744..c68458d 100644
--- a/ui/src/app/entity/entity-filter.directive.js
+++ b/ui/src/app/entity/entity-filter.directive.js
@@ -55,6 +55,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
break;
case types.aliasFilterType.stateEntity.value:
filter.stateEntityParamName = null;
+ filter.defaultStateEntity = null;
break;
case types.aliasFilterType.assetType.value:
filter.assetType = null;
@@ -69,6 +70,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, $doc
case types.aliasFilterType.deviceSearchQuery.value:
filter.rootStateEntity = false;
filter.stateEntityParamName = null;
+ filter.defaultStateEntity = null;
filter.rootEntity = null;
filter.direction = types.entitySearchDirection.from;
filter.maxLevel = 1;
ui/src/app/entity/entity-filter.tpl.html 122(+77 -45)
diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html
index dae2817..132a15e 100644
--- a/ui/src/app/entity/entity-filter.tpl.html
+++ b/ui/src/app/entity/entity-filter.tpl.html
@@ -66,6 +66,14 @@
ng-model="filter.stateEntityParamName"
aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
</md-input-container>
+ <div layout="column">
+ <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label>
+ <tb-entity-select flex
+ the-form="theForm"
+ tb-required="false"
+ ng-model="filter.defaultStateEntity">
+ </tb-entity-select>
+ </div>
</section>
<section layout="column" ng-if="filter.type == types.aliasFilterType.assetType.value" id="assetTypeFilter">
<tb-entity-subtype-autocomplete
@@ -97,27 +105,35 @@
</section>
<section layout="column" ng-if="filter.type == types.aliasFilterType.relationsQuery.value" id="relationsQueryFilter">
<label class="tb-small">{{ 'alias.root-entity' | translate }}</label>
- <div flex layout="row">
+ <section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;">
+ <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity"
+ aria-label="{{ 'alias.root-state-entity' | translate }}">
+ </md-switch>
+ <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
+ </section>
+ <div flex layout="row" ng-if="!filter.rootStateEntity">
<tb-entity-select flex
the-form="theForm"
tb-required="!filter.rootStateEntity"
ng-disabled="filter.rootStateEntity"
ng-model="filter.rootEntity">
</tb-entity-select>
- <div layout="column">
- <section class="tb-root-state-entity-switch" layout="column" layout-align="start center">
- <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
- <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity"
- aria-label="{{ 'alias.root-state-entity' | translate }}">
- </md-switch>
- </section>
- <md-input-container ng-if="filter.rootStateEntity" class="md-block">
- <label translate>alias.state-entity-parameter-name</label>
- <input name="stateEntityParamName"
- placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"
- ng-model="filter.stateEntityParamName"
- aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
- </md-input-container>
+ </div>
+ <div flex layout="row" ng-if="filter.rootStateEntity">
+ <md-input-container class="md-block" style="margin-top: 32px;">
+ <label translate>alias.state-entity-parameter-name</label>
+ <input name="stateEntityParamName"
+ placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"
+ ng-model="filter.stateEntityParamName"
+ aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
+ </md-input-container>
+ <div flex layout="column">
+ <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label>
+ <tb-entity-select flex
+ the-form="theForm"
+ tb-required="false"
+ ng-model="filter.defaultStateEntity">
+ </tb-entity-select>
</div>
</div>
<div flex layout="row">
@@ -148,27 +164,35 @@
</section>
<section layout="column" ng-if="filter.type == types.aliasFilterType.assetSearchQuery.value" id="assetSearchQueryFilter">
<label class="tb-small">{{ 'alias.root-entity' | translate }}</label>
- <div flex layout="row">
+ <section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;">
+ <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity"
+ aria-label="{{ 'alias.root-state-entity' | translate }}">
+ </md-switch>
+ <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
+ </section>
+ <div flex layout="row" ng-if="!filter.rootStateEntity">
<tb-entity-select flex
the-form="theForm"
tb-required="!filter.rootStateEntity"
ng-disabled="filter.rootStateEntity"
ng-model="filter.rootEntity">
</tb-entity-select>
- <div layout="column">
- <section class="tb-root-state-entity-switch" layout="column" layout-align="start center">
- <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
- <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity"
- aria-label="{{ 'alias.root-state-entity' | translate }}">
- </md-switch>
- </section>
- <md-input-container ng-if="filter.rootStateEntity" class="md-block">
- <label translate>alias.state-entity-parameter-name</label>
- <input name="stateEntityParamName"
- placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"
- ng-model="filter.stateEntityParamName"
- aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
- </md-input-container>
+ </div>
+ <div flex layout="row" ng-if="filter.rootStateEntity">
+ <md-input-container class="md-block" style="margin-top: 32px;">
+ <label translate>alias.state-entity-parameter-name</label>
+ <input name="stateEntityParamName"
+ placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"
+ ng-model="filter.stateEntityParamName"
+ aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
+ </md-input-container>
+ <div flex layout="column">
+ <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label>
+ <tb-entity-select flex
+ the-form="theForm"
+ tb-required="false"
+ ng-model="filter.defaultStateEntity">
+ </tb-entity-select>
</div>
</div>
<div flex layout="row">
@@ -207,27 +231,35 @@
</section>
<section layout="column" ng-if="filter.type == types.aliasFilterType.deviceSearchQuery.value" id="deviceSearchQueryFilter">
<label class="tb-small">{{ 'alias.root-entity' | translate }}</label>
- <div flex layout="row">
+ <section class="tb-root-state-entity-switch" layout="row" layout-align="start center" style="padding-left: 0px;">
+ <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity"
+ aria-label="{{ 'alias.root-state-entity' | translate }}">
+ </md-switch>
+ <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
+ </section>
+ <div flex layout="row" ng-if="!filter.rootStateEntity">
<tb-entity-select flex
the-form="theForm"
tb-required="!filter.rootStateEntity"
ng-disabled="filter.rootStateEntity"
ng-model="filter.rootEntity">
</tb-entity-select>
- <div layout="column">
- <section class="tb-root-state-entity-switch" layout="column" layout-align="start center">
- <label class="tb-small root-state-entity-label" translate>alias.root-state-entity</label>
- <md-switch class="root-state-entity-switch" ng-model="filter.rootStateEntity"
- aria-label="{{ 'alias.root-state-entity' | translate }}">
- </md-switch>
- </section>
- <md-input-container ng-if="filter.rootStateEntity" class="md-block">
- <label translate>alias.state-entity-parameter-name</label>
- <input name="stateEntityParamName"
- placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"
- ng-model="filter.stateEntityParamName"
- aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
- </md-input-container>
+ </div>
+ <div flex layout="row" ng-if="filter.rootStateEntity">
+ <md-input-container class="md-block" style="margin-top: 32px;">
+ <label translate>alias.state-entity-parameter-name</label>
+ <input name="stateEntityParamName"
+ placeholder="{{ 'alias.default-entity-parameter-name' | translate }}"
+ ng-model="filter.stateEntityParamName"
+ aria-label="{{ 'alias.state-entity-parameter-name' | translate }}">
+ </md-input-container>
+ <div flex layout="column">
+ <label class="tb-small">{{ 'alias.default-state-entity' | translate }}</label>
+ <tb-entity-select flex
+ the-form="theForm"
+ tb-required="false"
+ ng-model="filter.defaultStateEntity">
+ </tb-entity-select>
</div>
</div>
<div flex layout="row">
ui/src/app/entity/entity-select.directive.js 43(+34 -9)
diff --git a/ui/src/app/entity/entity-select.directive.js b/ui/src/app/entity/entity-select.directive.js
index 705c6b8..2778a79 100644
--- a/ui/src/app/entity/entity-select.directive.js
+++ b/ui/src/app/entity/entity-select.directive.js
@@ -48,6 +48,7 @@ export default function EntitySelect($compile, $templateCache) {
}
ngModelCtrl.$render = function () {
+ destroyWatchers();
if (ngModelCtrl.$viewValue) {
var value = ngModelCtrl.$viewValue;
scope.model.entityType = value.entityType;
@@ -56,19 +57,43 @@ export default function EntitySelect($compile, $templateCache) {
scope.model.entityType = null;
scope.model.entityId = null;
}
+ initWatchers();
}
- scope.$watch('model.entityType', function () {
- scope.updateView();
- });
+ function initWatchers() {
+ scope.entityTypeDeregistration = scope.$watch('model.entityType', function (newVal, prevVal) {
+ if (!angular.equals(newVal, prevVal)) {
+ scope.updateView();
+ }
+ });
+
+ scope.entityIdDeregistration = scope.$watch('model.entityId', function (newVal, prevVal) {
+ if (!angular.equals(newVal, prevVal)) {
+ scope.updateView();
+ }
+ });
- scope.$watch('model.entityId', function () {
- scope.updateView();
- });
+ scope.disabledDeregistration = scope.$watch('disabled', function (newVal, prevVal) {
+ if (!angular.equals(newVal, prevVal)) {
+ scope.updateView();
+ }
+ });
+ }
- scope.$watch('disabled', function () {
- scope.updateView();
- });
+ function destroyWatchers() {
+ if (scope.entityTypeDeregistration) {
+ scope.entityTypeDeregistration();
+ scope.entityTypeDeregistration = null;
+ }
+ if (scope.entityIdDeregistration) {
+ scope.entityIdDeregistration();
+ scope.entityIdDeregistration = null;
+ }
+ if (scope.disabledDeregistration) {
+ scope.disabledDeregistration();
+ scope.disabledDeregistration = null;
+ }
+ }
$compile(element.contents())(scope);
}
ui/src/app/locale/locale.constant.js 1(+1 -0)
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index 6513ce8..f16fe9a 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -188,6 +188,7 @@ export default angular.module('thingsboard.locale', [])
"root-state-entity": "Use dashboard state entity as root",
"root-entity": "Root entity",
"state-entity-parameter-name": "State entity parameter name",
+ "default-state-entity": "Default state entity",
"default-entity-parameter-name": "By default",
"max-relation-level": "Max relation level",
"unlimited-level": "Unlimited level",
ui/src/app/widget/lib/alarms-table-widget.js 30(+30 -0)
diff --git a/ui/src/app/widget/lib/alarms-table-widget.js b/ui/src/app/widget/lib/alarms-table-widget.js
index 7618e6a..a91c2a0 100644
--- a/ui/src/app/widget/lib/alarms-table-widget.js
+++ b/ui/src/app/widget/lib/alarms-table-widget.js
@@ -69,6 +69,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
vm.displayDetails = true;
vm.allowAcknowledgment = true;
vm.allowClear = true;
+ vm.actionCellDescriptors = [];
vm.displayPagination = true;
vm.defaultPageSize = 10;
vm.defaultSortOrder = '-'+types.alarmFields.createdTime.value;
@@ -94,6 +95,7 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
vm.onReorder = onReorder;
vm.onPaginate = onPaginate;
vm.onRowClick = onRowClick;
+ vm.onActionButtonClick = onActionButtonClick;
vm.isCurrent = isCurrent;
vm.openAlarmDetails = openAlarmDetails;
vm.ackAlarms = ackAlarms;
@@ -157,6 +159,8 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
vm.ctx.widgetActions = [ vm.searchAction ];
+ vm.actionCellDescriptors = vm.ctx.actionsApi.getActionDescriptors('actionCellButton');
+
if (vm.settings.alarmsTitle && vm.settings.alarmsTitle.length) {
vm.alarmsTitle = utils.customTranslation(vm.settings.alarmsTitle, vm.settings.alarmsTitle);
} else {
@@ -280,9 +284,35 @@ function AlarmsTableWidgetController($element, $scope, $filter, $mdMedia, $mdDia
}
function onRowClick($event, alarm) {
+ if ($event) {
+ $event.stopPropagation();
+ }
if (vm.currentAlarm != alarm) {
vm.currentAlarm = alarm;
}
+ var descriptors = vm.ctx.actionsApi.getActionDescriptors('rowClick');
+ if (descriptors.length) {
+ var entityId;
+ var entityName;
+ if (vm.currentAlarm && vm.currentAlarm.originator) {
+ entityId = vm.currentAlarm.originator;
+ entityName = vm.currentAlarm.originatorName;
+ }
+ vm.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName);
+ }
+ }
+
+ function onActionButtonClick($event, alarm, actionDescriptor) {
+ if ($event) {
+ $event.stopPropagation();
+ }
+ var entityId;
+ var entityName;
+ if (alarm && alarm.originator) {
+ entityId = alarm.originator;
+ entityName = alarm.originatorName;
+ }
+ vm.ctx.actionsApi.handleWidgetAction($event, actionDescriptor, entityId, entityName);
}
function isCurrent(alarm) {
diff --git a/ui/src/app/widget/lib/alarms-table-widget.tpl.html b/ui/src/app/widget/lib/alarms-table-widget.tpl.html
index 942b2af..b7416e9 100644
--- a/ui/src/app/widget/lib/alarms-table-widget.tpl.html
+++ b/ui/src/app/widget/lib/alarms-table-widget.tpl.html
@@ -64,6 +64,7 @@
<tr md-row>
<th md-column md-order-by="{{ key.name }}" ng-repeat="key in vm.alarmSource.dataKeys"><span>{{ key.title }}</span></th>
<th md-column ng-if="vm.displayDetails"><span> </span></th>
+ <th md-column ng-if="vm.actionCellDescriptors.length"><span> </span></th>
</tr>
</thead>
<tbody md-body>
@@ -83,6 +84,19 @@
</md-tooltip>
</md-button>
</td>
+ <td md-cell ng-if="vm.actionCellDescriptors.length" class="tb-action-cell"
+ ng-style="{minWidth: vm.actionCellDescriptors.length*36+'px',
+ maxWidth: vm.actionCellDescriptors.length*36+'px',
+ width: vm.actionCellDescriptors.length*36+'px'}">
+ <md-button class="md-icon-button" ng-repeat="actionDescriptor in vm.actionCellDescriptors"
+ aria-label="{{ actionDescriptor.displayName }}"
+ ng-click="vm.onActionButtonClick($event, alarm, actionDescriptor)">
+ <md-icon aria-label="{{ actionDescriptor.displayName }}" class="material-icons">{{actionDescriptor.icon}}</md-icon>
+ <md-tooltip md-direction="top">
+ {{ actionDescriptor.displayName }}
+ </md-tooltip>
+ </md-button>
+ </td>
</tr>
</tbody>
</table>
diff --git a/ui/src/app/widget/lib/entities-table-widget.js b/ui/src/app/widget/lib/entities-table-widget.js
index f0b5835..7d97fe4 100644
--- a/ui/src/app/widget/lib/entities-table-widget.js
+++ b/ui/src/app/widget/lib/entities-table-widget.js
@@ -107,6 +107,7 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra
vm.datasources = vm.subscription.datasources;
initializeConfig();
updateDatasources();
+ updateEntities();
}
});
@@ -276,16 +277,16 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $tra
}
if (vm.currentEntity != entity) {
vm.currentEntity = entity;
- var descriptors = vm.ctx.actionsApi.getActionDescriptors('rowClick');
- if (descriptors.length) {
- var entityId;
- var entityName;
- if (vm.currentEntity) {
- entityId = vm.currentEntity.id;
- entityName = vm.currentEntity.entityName;
- }
- vm.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName);
+ }
+ var descriptors = vm.ctx.actionsApi.getActionDescriptors('rowClick');
+ if (descriptors.length) {
+ var entityId;
+ var entityName;
+ if (vm.currentEntity) {
+ entityId = vm.currentEntity.id;
+ entityName = vm.currentEntity.entityName;
}
+ vm.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName);
}
}