thingsboard-developers
Changes
ui/src/app/api/alias-controller.js 259(+259 -0)
ui/src/app/api/entity.service.js 185(+129 -56)
ui/src/app/api/subscription.js 129(+99 -30)
ui/src/app/common/dashboard-utils.service.js 76(+56 -20)
ui/src/app/common/types.constant.js 30(+30 -0)
ui/src/app/components/widget.controller.js 156(+115 -41)
ui/src/app/dashboard/add-widget.controller.js 52(+31 -21)
ui/src/app/dashboard/dashboard.controller.js 37(+17 -20)
ui/src/app/dashboard/edit-widget.directive.js 45(+27 -18)
ui/src/app/entity/entity-aliases.controller.js 38(+12 -26)
ui/src/app/entity/entity-aliases.tpl.html 27(+8 -19)
ui/src/app/entity/entity-filter.directive.js 81(+65 -16)
ui/src/app/entity/entity-filter.tpl.html 37(+32 -5)
ui/src/app/entity/entity-filter-dialog.controller.js 104(+104 -0)
ui/src/app/entity/entity-filter-dialog.tpl.html 100(+100 -0)
ui/src/app/entity/entity-list.directive.js 130(+130 -0)
ui/src/app/entity/entity-list.scss 30(+30 -0)
ui/src/app/entity/entity-list.tpl.html 52(+52 -0)
ui/src/app/entity/index.js 2(+2 -0)
ui/src/app/locale/locale.constant.js 19(+19 -0)
Details
ui/src/app/api/alias-controller.js 259(+259 -0)
diff --git a/ui/src/app/api/alias-controller.js b/ui/src/app/api/alias-controller.js
new file mode 100644
index 0000000..7794363
--- /dev/null
+++ b/ui/src/app/api/alias-controller.js
@@ -0,0 +1,259 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const varsRegex = /\$\{([^\}]*)\}/g;
+
+export default class AliasController {
+
+ constructor($scope, $q, $filter, utils, types, entityService, stateController, entityAliases) {
+ this.$scope = $scope;
+ this.$q = $q;
+ this.$filter = $filter;
+ this.utils = utils;
+ this.types = types;
+ this.entityService = entityService;
+ this.stateController = stateController;
+ this.entityAliases = angular.copy(entityAliases);
+ this.resolvedAliases = {};
+ this.resolvedAliasesPromise = {};
+ this.resolvedAliasesToStateEntities = {};
+ }
+
+ updateEntityAliases(newEntityAliases) {
+ var changedAliasIds = [];
+ for (var aliasId in newEntityAliases) {
+ var newEntityAlias = newEntityAliases[aliasId];
+ var prevEntityAlias = this.entityAliases[aliasId];
+ if (!angular.equals(newEntityAlias, prevEntityAlias)) {
+ changedAliasIds.push(aliasId);
+ this.setAliasUnresolved(aliasId);
+ }
+ }
+ for (aliasId in this.entityAliases) {
+ if (!newEntityAliases[aliasId]) {
+ changedAliasIds.push(aliasId);
+ this.setAliasUnresolved(aliasId);
+ }
+ }
+ this.entityAliases = angular.copy(newEntityAliases);
+ if (changedAliasIds.length) {
+ this.$scope.$broadcast('entityAliasesChanged', changedAliasIds);
+ }
+ }
+
+ dashboardStateChanged() {
+ var newEntityId = this.stateController.getStateParams().entityId;
+ var changedAliasIds = [];
+ for (var aliasId in this.resolvedAliasesToStateEntities) {
+ var prevEntityId = this.resolvedAliasesToStateEntities[aliasId];
+ if (!angular.equals(newEntityId, prevEntityId)) {
+ changedAliasIds.push(aliasId);
+ this.setAliasUnresolved(aliasId);
+ }
+ }
+ if (changedAliasIds.length) {
+ this.$scope.$broadcast('entityAliasesChanged', changedAliasIds);
+ }
+ }
+
+ setAliasUnresolved(aliasId) {
+ delete this.resolvedAliases[aliasId];
+ delete this.resolvedAliasesPromise[aliasId];
+ delete this.resolvedAliasesToStateEntities[aliasId];
+ }
+
+ getEntityAliases() {
+ return this.entityAliases;
+ }
+
+ getAliasInfo(aliasId) {
+ var deferred = this.$q.defer();
+ var aliasInfo = this.resolvedAliases[aliasId];
+ if (aliasInfo) {
+ deferred.resolve(aliasInfo);
+ return deferred.promise;
+ } else if (this.resolvedAliasesPromise[aliasId]) {
+ return this.resolvedAliasesPromise[aliasId];
+ } else {
+ this.resolvedAliasesPromise[aliasId] = deferred.promise;
+ var aliasCtrl = this;
+ var entityAlias = this.entityAliases[aliasId];
+ if (entityAlias) {
+ this.entityService.resolveAlias(entityAlias, this.stateController.getStateParams()).then(
+ function success(aliasInfo) {
+ aliasCtrl.resolvedAliases[aliasId] = aliasInfo;
+ if (entityAlias.filter.stateEntity) {
+ aliasCtrl.resolvedAliasesToStateEntities[aliasId] =
+ aliasCtrl.stateController.getStateParams().entityId;
+ }
+ deferred.resolve(aliasInfo);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ } else {
+ deferred.reject();
+ }
+ return this.resolvedAliasesPromise[aliasId];
+ }
+ }
+
+ resolveDatasource(datasource) {
+ var deferred = this.$q.defer();
+ if (datasource.type === this.types.datasourceType.entity) {
+ if (datasource.entityAliasId) {
+ this.getAliasInfo(datasource.entityAliasId).then(
+ function success(aliasInfo) {
+ datasource.aliasName = aliasInfo.alias;
+ if (aliasInfo.resolveMultiple) {
+ var resolvedEntities = aliasInfo.resolvedEntities;
+ if (resolvedEntities && resolvedEntities.length) {
+ var datasources = [];
+ for (var i=0;i<resolvedEntities.length;i++) {
+ var resolvedEntity = resolvedEntities[i];
+ var newDatasource = angular.copy(datasource);
+ newDatasource.entityId = resolvedEntity.id;
+ newDatasource.entityType = resolvedEntity.entityType;
+ newDatasource.entityName = resolvedEntity.name;
+ newDatasource.name = resolvedEntity.name;
+ newDatasource.generated = i > 0 ? true : false;
+ datasources.push(newDatasource);
+ }
+ deferred.resolve(datasources);
+ } else {
+ deferred.reject();
+ }
+ } else {
+ var entity = aliasInfo.currentEntity;
+ datasource.entityId = entity.id;
+ datasource.entityType = entity.entityType;
+ datasource.entityName = entity.name;
+ datasource.name = entity.name;
+ deferred.resolve([datasource]);
+ }
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ } else { // entityId
+ datasource.aliasName = datasource.entityName;
+ datasource.name = datasource.entityName;
+ deferred.resolve([datasource]);
+ }
+ } else { // function
+ deferred.resolve([datasource]);
+ }
+ return deferred.promise;
+ }
+
+ resolveDatasources(datasources) {
+
+ function updateDataKeyLabel(dataKey, datasource) {
+ if (!dataKey.pattern) {
+ dataKey.pattern = angular.copy(dataKey.label);
+ }
+ var pattern = dataKey.pattern;
+ var label = dataKey.pattern;
+ var match = varsRegex.exec(pattern);
+ while (match !== null) {
+ var variable = match[0];
+ var variableName = match[1];
+ if (variableName === 'dsName') {
+ label = label.split(variable).join(datasource.name);
+ } else if (variableName === 'entityName') {
+ label = label.split(variable).join(datasource.entityName);
+ } else if (variableName === 'deviceName') {
+ label = label.split(variable).join(datasource.entityName);
+ } else if (variableName === 'aliasName') {
+ label = label.split(variable).join(datasource.aliasName);
+ }
+ match = varsRegex.exec(pattern);
+ }
+ dataKey.label = label;
+ }
+
+ function updateDatasourceKeyLabels(datasource) {
+ for (var dk = 0; dk < datasource.dataKeys.length; dk++) {
+ updateDataKeyLabel(datasource.dataKeys[dk], datasource);
+ }
+ }
+
+ var deferred = this.$q.defer();
+ var newDatasources = angular.copy(datasources);
+ var datasorceResolveTasks = [];
+ var aliasCtrl = this;
+ newDatasources.forEach(function (datasource) {
+ var resolveDatasourceTask = aliasCtrl.resolveDatasource(datasource);
+ datasorceResolveTasks.push(resolveDatasourceTask);
+ });
+ this.$q.all(datasorceResolveTasks).then(
+ function success(datasourcesArrays) {
+ var datasources = [].concat.apply([], datasourcesArrays);
+ datasources = aliasCtrl.$filter('orderBy')(datasources, '+generated');
+ var index = 0;
+ var functionIndex = 0;
+ datasources.forEach(function(datasource) {
+ if (datasource.type === aliasCtrl.types.datasourceType.function) {
+ var name;
+ if (datasource.name && datasource.name.length) {
+ name = datasource.name;
+ } else {
+ functionIndex++;
+ name = aliasCtrl.types.datasourceType.function;
+ if (functionIndex > 1) {
+ name += ' ' + functionIndex;
+ }
+ }
+ datasource.name = name;
+ datasource.aliasName = name;
+ datasource.entityName = name;
+ }
+ datasource.dataKeys.forEach(function(dataKey) {
+ if (datasource.generated) {
+ dataKey._hash = Math.random();
+ dataKey.color = aliasCtrl.utils.getMaterialColor(index);
+ }
+ index++;
+ });
+ updateDatasourceKeyLabels(datasource);
+ });
+ deferred.resolve(datasources);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ return deferred.promise;
+ }
+
+ getInstantAliasInfo(aliasId) {
+ return this.resolvedAliases[aliasId];
+ }
+
+ updateCurrentAliasEntity(aliasId, currentEntity) {
+ var aliasInfo = this.resolvedAliases[aliasId];
+ if (aliasInfo) {
+ var prevCurrentEntity = aliasInfo.currentEntity;
+ if (!angular.equals(currentEntity, prevCurrentEntity)) {
+ aliasInfo.currentEntity = currentEntity;
+ this.$scope.$broadcast('entityAliasesChanged', [aliasId]);
+ }
+ }
+ }
+
+}
\ No newline at end of file
ui/src/app/api/entity.service.js 185(+129 -56)
diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js
index 891f9d8..8c28a9b 100644
--- a/ui/src/app/api/entity.service.js
+++ b/ui/src/app/api/entity.service.js
@@ -27,10 +27,13 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
getEntity: getEntity,
getEntities: getEntities,
getEntitiesByNameFilter: getEntitiesByNameFilter,
- processEntityAliases: processEntityAliases,
+ resolveAlias: resolveAlias,
+ resolveAliasFilter: resolveAliasFilter,
+ filterAliasByEntityTypes: filterAliasByEntityTypes,
+ //processEntityAliases: processEntityAliases,
getEntityKeys: getEntityKeys,
checkEntityAlias: checkEntityAlias,
- createDatasoucesFromSubscriptionsInfo: createDatasoucesFromSubscriptionsInfo,
+ createDatasourcesFromSubscriptionsInfo: createDatasourcesFromSubscriptionsInfo,
getRelatedEntities: getRelatedEntities,
saveRelatedEntity: saveRelatedEntity,
getRelatedEntity: getRelatedEntity,
@@ -244,81 +247,151 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return deferred.promise;
}
- function entityToEntityInfo(entityType, entity) {
- return { name: entity.name, entityType: entityType, id: entity.id.id };
+ function entityToEntityInfo(entity) {
+ return { name: entity.name, entityType: entity.id.entityType, id: entity.id.id };
}
- function entitiesToEntitiesInfo(entityType, entities) {
+ function entitiesToEntitiesInfo(entities) {
var entitiesInfo = [];
for (var d = 0; d < entities.length; d++) {
- entitiesInfo.push(entityToEntityInfo(entityType, entities[d]));
+ entitiesInfo.push(entityToEntityInfo(entities[d]));
}
return entitiesInfo;
}
- function processEntityAlias(index, aliasIds, entityAliases, resolution, deferred) {
- if (index < aliasIds.length) {
- var aliasId = aliasIds[index];
- var entityAlias = entityAliases[aliasId];
- var alias = entityAlias.alias;
- var entityFilter = entityAlias.entityFilter;
- if (entityFilter.useFilter) {
- var entityNameFilter = entityFilter.entityNameFilter;
- getEntitiesByNameFilter(entityAlias.entityType, entityNameFilter, 100).then(
- function(entities) {
- if (entities && entities != null) {
- var resolvedAlias = {alias: alias, entityType: entityAlias.entityType, entityId: entities[0].id.id};
- resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias;
- resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entityAlias.entityType, entities);
- index++;
- processEntityAlias(index, aliasIds, entityAliases, resolution, deferred);
- } else {
- if (!resolution.error) {
- resolution.error = 'dashboard.invalid-aliases-config';
+ function resolveAliasFilter(filter, stateParams) {
+ var deferred = $q.defer();
+ var result = {
+ entities: [],
+ stateEntity: false
+ };
+ switch (filter.type) {
+ case types.aliasFilterType.entityList.value:
+ if (filter.stateEntity) {
+ result.stateEntity = true;
+ if (stateParams && stateParams.entityId) {
+ getEntity(stateParams.entityId.entityType, stateParams.entityId.id).then(
+ function success(entity) {
+ result.entities = [entity];
+ deferred.resolve(result);
+ },
+ function fail() {
+ deferred.reject();
}
- index++;
- processEntityAlias(index, aliasIds, entityAliases, resolution, deferred);
+ );
+ } else {
+ deferred.resolve(result);
+ }
+ } else {
+ getEntities(filter.entityType, filter.entityList).then(
+ function success(entities) {
+ if (entities && entities.length) {
+ result.entities = entities;
+ deferred.resolve(result);
+ } else {
+ deferred.reject();
+ }
+ },
+ function fail() {
+ deferred.reject();
}
- });
- } else {
- var entityList = entityFilter.entityList;
- getEntities(entityAlias.entityType, entityList).then(
+ );
+ }
+ break;
+ case types.aliasFilterType.entityName.value:
+ getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, 100).then(
function success(entities) {
- if (entities && entities.length > 0) {
- var resolvedAlias = {alias: alias, entityType: entityAlias.entityType, entityId: entities[0].id.id};
- resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias;
- resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entityAlias.entityType, entities);
- index++;
- processEntityAlias(index, aliasIds, entityAliases, resolution, deferred);
+ if (entities && entities.length) {
+ result.entities = entities;
+ deferred.resolve(result);
} else {
- if (!resolution.error) {
- resolution.error = 'dashboard.invalid-aliases-config';
- }
- index++;
- processEntityAlias(index, aliasIds, entityAliases, resolution, deferred);
+ deferred.reject();
}
},
function fail() {
+ deferred.reject();
+ }
+ );
+ break;
+ //TODO:
+ }
+ return deferred.promise;
+ }
+
+ function resolveAlias(entityAlias, stateParams) {
+ var deferred = $q.defer();
+ var filter = entityAlias.filter;
+ resolveAliasFilter(filter, stateParams).then(
+ function (result) {
+ var entities = result.entities;
+ var aliasInfo = {
+ alias: entityAlias.alias,
+ resolveMultiple: filter.resolveMultiple
+ };
+ var resolvedEntities = entitiesToEntitiesInfo(entities);
+ aliasInfo.resolvedEntities = resolvedEntities;
+ aliasInfo.currentEntity = null;
+ if (aliasInfo.resolvedEntities.length) {
+ aliasInfo.currentEntity = aliasInfo.resolvedEntities[0];
+ }
+ deferred.resolve(aliasInfo);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ return deferred.promise;
+ }
+
+ function filterAliasByEntityTypes(entityAlias, entityTypes) {
+ var filter = entityAlias.filter;
+ switch (filter.type) {
+ case types.aliasFilterType.entityList.value:
+ if (filter.stateEntity) {
+ return true;
+ } else {
+ return entityTypes.indexOf(filter.entityType) > -1 ? true : false;
+ }
+ case types.aliasFilterType.entityName.value:
+ return entityTypes.indexOf(filter.entityType) > -1 ? true : false;
+ }
+ //TODO:
+ return false;
+ }
+
+ /*function processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred) {
+ if (index < aliasIds.length) {
+ var aliasId = aliasIds[index];
+ var entityAlias = entityAliases[aliasId];
+ var alias = entityAlias.alias;
+ var filter = entityAlias.filter;
+ resolveAliasFilter(filter, stateParams).then(
+ function (entities) {
+ if (entities && entities.length) {
+ var entity = entities[0];
+ var resolvedAlias = {alias: alias, entityType: entity.id.entityType, entityId: entity.id.id};
+ resolution.aliasesInfo.entityAliases[aliasId] = resolvedAlias;
+ resolution.aliasesInfo.entityAliasesInfo[aliasId] = entitiesToEntitiesInfo(entities);
+ index++;
+ processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred);
+ } else {
if (!resolution.error) {
resolution.error = 'dashboard.invalid-aliases-config';
}
index++;
- processEntityAlias(index, aliasIds, entityAliases, resolution, deferred);
+ processEntityAlias(index, aliasIds, entityAliases, stateParams, resolution, deferred);
}
- );
- }
+ }
+ );
} else {
deferred.resolve(resolution);
}
- }
+ }*/
- function processEntityAliases(entityAliases) {
+ /*function processEntityAliases(entityAliases, stateParams) {
var deferred = $q.defer();
var resolution = {
- aliasesInfo: {
- entityAliases: {},
- entityAliasesInfo: {}
- }
+ aliasesInfo: {}
};
var aliasIds = [];
if (entityAliases) {
@@ -326,9 +399,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
aliasIds.push(aliasId);
}
}
- processEntityAlias(0, aliasIds, entityAliases, resolution, deferred);
+ processEntityAlias(0, aliasIds, entityAliases, stateParams, resolution, deferred);
return deferred.promise;
- }
+ }*/
function getEntityKeys(entityType, entityId, query, type) {
var deferred = $q.defer();
@@ -354,8 +427,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
}
}
deferred.resolve(result);
- }, function fail(response) {
- deferred.reject(response.data);
+ }, function fail() {
+ deferred.reject();
});
return deferred.promise;
}
@@ -387,7 +460,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return deferred.promise;
}
- function createDatasoucesFromSubscriptionsInfo(subscriptionsInfo) {
+ function createDatasourcesFromSubscriptionsInfo(subscriptionsInfo) {
var deferred = $q.defer();
var datasources = [];
processSubscriptionsInfo(0, subscriptionsInfo, datasources, deferred);
ui/src/app/api/subscription.js 129(+99 -30)
diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js
index fb774a1..471203c 100644
--- a/ui/src/app/api/subscription.js
+++ b/ui/src/app/api/subscription.js
@@ -39,6 +39,9 @@ export default class Subscription {
this.cafs = {};
this.registrations = [];
+ var subscription = this;
+ var deferred = this.ctx.$q.defer();
+
if (this.type === this.ctx.types.widgetType.rpc.value) {
this.callbacks.rpcStateChanged = this.callbacks.rpcStateChanged || function(){};
this.callbacks.onRpcSuccess = this.callbacks.onRpcSuccess || function(){};
@@ -56,7 +59,11 @@ export default class Subscription {
this.rpcEnabled = false;
this.executingRpcRequest = false;
this.executingPromises = [];
- this.initRpc();
+ this.initRpc().then(
+ function() {
+ deferred.resolve(subscription);
+ }
+ );
} else {
this.callbacks.onDataUpdated = this.callbacks.onDataUpdated || function(){};
this.callbacks.onDataUpdateError = this.callbacks.onDataUpdateError || function(){};
@@ -103,11 +110,36 @@ export default class Subscription {
this.legendConfig.showMax === true ||
this.legendConfig.showAvg === true ||
this.legendConfig.showTotal === true);
- this.initDataSubscription();
+ this.initDataSubscription().then(
+ function success() {
+ deferred.resolve(subscription);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
}
+
+ return deferred.promise;
}
initDataSubscription() {
+ var deferred = this.ctx.$q.defer();
+ var subscription = this;
+ this.ctx.aliasController.resolveDatasources(this.datasources).then(
+ function success(datasources) {
+ subscription.datasources = datasources;
+ subscription.configureData();
+ deferred.resolve();
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ return deferred.promise;
+ }
+
+ configureData() {
var dataIndex = 0;
for (var i = 0; i < this.datasources.length; i++) {
var datasource = this.datasources[i];
@@ -199,21 +231,46 @@ export default class Subscription {
}
initRpc() {
+ var deferred = this.ctx.$q.defer();
if (this.targetDeviceAliasIds && this.targetDeviceAliasIds.length > 0) {
this.targetDeviceAliasId = this.targetDeviceAliasIds[0];
- if (this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId]) {
- this.targetDeviceId = this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId].entityId;
+ var subscription = this;
+ this.ctx.aliasController.getAliasInfo(this.targetDeviceAliasId).then(
+ function success(aliasInfo) {
+ if (aliasInfo.currentEntity && aliasInfo.currentEntity.entityType == subscription.ctx.types.entityType.device) {
+ subscription.targetDeviceId = aliasInfo.currentEntity.id;
+ if (subscription.targetDeviceId) {
+ subscription.rpcEnabled = true;
+ } else {
+ subscription.rpcEnabled = subscription.ctx.$scope.widgetEditMode ? true : false;
+ }
+ subscription.callbacks.rpcStateChanged(this);
+ deferred.resolve();
+ } else {
+ subscription.rpcEnabled = false;
+ subscription.callbacks.rpcStateChanged(this);
+ deferred.resolve();
+ }
+ },
+ function fail () {
+ subscription.rpcEnabled = false;
+ subscription.callbacks.rpcStateChanged(this);
+ deferred.resolve();
+ }
+ );
+ } else {
+ if (this.targetDeviceIds && this.targetDeviceIds.length > 0) {
+ this.targetDeviceId = this.targetDeviceIds[0];
}
- } else if (this.targetDeviceIds && this.targetDeviceIds.length > 0) {
- this.targetDeviceId = this.targetDeviceIds[0];
- }
-
- if (this.targetDeviceId) {
- this.rpcEnabled = true;
- } else {
- this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false;
+ if (this.targetDeviceId) {
+ this.rpcEnabled = true;
+ } else {
+ this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false;
+ }
+ this.callbacks.rpcStateChanged(this);
+ deferred.resolve();
}
- this.callbacks.rpcStateChanged(this);
+ return deferred.promise;
}
clearRpcError() {
@@ -319,11 +376,11 @@ export default class Subscription {
this.onDataUpdated();
}
- onAliasesChanged() {
+ onAliasesChanged(aliasIds) {
if (this.type === this.ctx.types.widgetType.rpc.value) {
- this.checkRpcTarget();
+ return this.checkRpcTarget(aliasIds);
} else {
- this.checkSubscriptions();
+ return this.checkSubscriptions(aliasIds);
}
}
@@ -481,7 +538,7 @@ export default class Subscription {
var datasource = this.datasources[i];
if (angular.isFunction(datasource))
continue;
- var entityId = null;
+ /* var entityId = null;
var entityType = null;
if (datasource.type === this.ctx.types.datasourceType.entity) {
var aliasName = null;
@@ -513,7 +570,7 @@ export default class Subscription {
}
for (var dk = 0; dk < datasource.dataKeys.length; dk++) {
updateDataKeyLabel(datasource.dataKeys[dk], datasource.name, entityName, aliasName);
- }
+ }*/
var subscription = this;
@@ -521,8 +578,8 @@ export default class Subscription {
subscriptionType: this.type,
subscriptionTimewindow: this.subscriptionTimewindow,
datasource: datasource,
- entityType: entityType,
- entityId: entityId,
+ entityType: datasource.entityType,
+ entityId: datasource.entityId,
dataUpdated: function (data, datasourceIndex, dataKeyIndex, apply) {
subscription.dataUpdated(data, datasourceIndex, dataKeyIndex, apply);
},
@@ -557,8 +614,13 @@ export default class Subscription {
}
}
- checkRpcTarget() {
- var deviceId = null;
+ checkRpcTarget(aliasIds) {
+ if (aliasIds.indexOf(this.targetDeviceAliasId) > -1) {
+ return true;
+ } else {
+ return false;
+ }
+ /*var deviceId = null;
if (this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId]) {
deviceId = this.ctx.aliasesInfo.entityAliases[this.targetDeviceAliasId].entityId;
}
@@ -570,14 +632,20 @@ export default class Subscription {
this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false;
}
this.callbacks.rpcStateChanged(this);
- }
+ }*/
}
- checkSubscriptions() {
+ checkSubscriptions(aliasIds) {
var subscriptionsChanged = false;
for (var i = 0; i < this.datasourceListeners.length; i++) {
var listener = this.datasourceListeners[i];
- var entityId = null;
+ if (listener.datasource.entityAliasId) {
+ if (aliasIds.indexOf(listener.datasource.entityAliasId) > -1) {
+ subscriptionsChanged = true;
+ break;
+ }
+ }
+ /*var entityId = null;
var entityType = null;
var aliasName = null;
if (listener.datasource.type === this.ctx.types.datasourceType.entity) {
@@ -593,12 +661,13 @@ export default class Subscription {
subscriptionsChanged = true;
break;
}
- }
+ }*/
}
- if (subscriptionsChanged) {
+ return subscriptionsChanged;
+ /*if (subscriptionsChanged) {
this.unsubscribe();
this.subscribe();
- }
+ }*/
}
destroy() {
@@ -617,7 +686,7 @@ export default class Subscription {
}
-const varsRegex = /\$\{([^\}]*)\}/g;
+/*const varsRegex = /\$\{([^\}]*)\}/g;
function updateDataKeyLabel(dataKey, dsName, entityName, aliasName) {
var pattern = dataKey.pattern;
@@ -638,7 +707,7 @@ function updateDataKeyLabel(dataKey, dsName, entityName, aliasName) {
match = varsRegex.exec(pattern);
}
dataKey.label = label;
-}
+}*/
function calculateMin(data) {
if (data.length > 0) {
ui/src/app/common/dashboard-utils.service.js 76(+56 -20)
diff --git a/ui/src/app/common/dashboard-utils.service.js b/ui/src/app/common/dashboard-utils.service.js
index 78136df..51a0215 100644
--- a/ui/src/app/common/dashboard-utils.service.js
+++ b/ui/src/app/common/dashboard-utils.service.js
@@ -40,39 +40,75 @@ function DashboardUtils(types, utils, timeService) {
return service;
function validateAndUpdateEntityAliases(configuration) {
+ var aliasId, entityAlias;
if (angular.isUndefined(configuration.entityAliases)) {
configuration.entityAliases = {};
if (configuration.deviceAliases) {
var deviceAliases = configuration.deviceAliases;
- for (var aliasId in deviceAliases) {
+ for (aliasId in deviceAliases) {
var deviceAlias = deviceAliases[aliasId];
- var alias = deviceAlias.alias;
- var entityFilter = {
- useFilter: false,
- entityNameFilter: '',
- entityList: []
- }
- if (deviceAlias.deviceFilter) {
- entityFilter.useFilter = deviceAlias.deviceFilter.useFilter;
- entityFilter.entityNameFilter = deviceAlias.deviceFilter.deviceNameFilter;
- entityFilter.entityList = deviceAlias.deviceFilter.deviceList;
- } else if (deviceAlias.deviceId) {
- entityFilter.entityList = [deviceAlias.deviceId];
- }
- var entityAlias = {
- id: aliasId,
- alias: alias,
- entityType: types.entityType.device,
- entityFilter: entityFilter
- };
+ entityAlias = validateAndUpdateDeviceAlias(aliasId, deviceAlias);
configuration.entityAliases[aliasId] = entityAlias;
}
delete configuration.deviceAliases;
}
+ } else {
+ var entityAliases = configuration.entityAliases;
+ for (aliasId in entityAliases) {
+ entityAlias = entityAliases[aliasId];
+ entityAliases[aliasId] = validateAndUpdateEntityAlias(entityAlias);
+ }
}
return configuration;
}
+ function validateAndUpdateDeviceAlias(aliasId, deviceAlias) {
+ var alias = deviceAlias.alias;
+ var entityAlias = {
+ id: aliasId,
+ alias: alias,
+ filter: {
+ type: null,
+ entityType: types.entityType.device,
+ resolveMultiple: false
+ },
+ }
+ if (deviceAlias.deviceFilter) {
+ entityAlias.filter.type =
+ deviceAlias.deviceFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value;
+ if (entityAlias.filter.type == types.aliasFilterType.entityList.value) {
+ entityAlias.filter.entityList = deviceAlias.deviceFilter.deviceList;
+ entityAlias.filter.stateEntity = false;
+ } else {
+ entityAlias.filter.entityNameFilter = deviceAlias.deviceFilter.deviceNameFilter;
+ }
+ } else {
+ entityAlias.filter.type = types.aliasFilterType.entityList.value;
+ entityAlias.filter.entityList = [deviceAlias.deviceId];
+ entityAlias.filter.stateEntity = false;
+ }
+ return entityAlias;
+ }
+
+ function validateAndUpdateEntityAlias(entityAlias) {
+ if (!entityAlias.filter) {
+ entityAlias.filter = {
+ type: entityAlias.entityFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value,
+ entityType: entityAlias.entityType,
+ resolveMultiple: false
+ }
+ if (entityAlias.filter.type == types.aliasFilterType.entityList.value) {
+ entityAlias.filter.entityList = entityAlias.entityFilter.entityList;
+ entityAlias.filter.stateEntity = false;
+ } else {
+ entityAlias.filter.entityNameFilter = entityAlias.entityFilter.entityNameFilter;
+ }
+ delete entityAlias.entityType;
+ delete entityAlias.entityFilter;
+ }
+ return entityAlias;
+ }
+
function validateAndUpdateWidget(widget) {
if (!widget.config) {
widget.config = {};
ui/src/app/common/types.constant.js 30(+30 -0)
diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js
index 44e59a2..40b6639 100644
--- a/ui/src/app/common/types.constant.js
+++ b/ui/src/app/common/types.constant.js
@@ -65,6 +65,36 @@ export default angular.module('thingsboard.types', [])
clearedUnack: "CLEARED_UNACK",
clearedAck: "CLEARED_ACK"
},
+ aliasFilterType: {
+ entityList: {
+ value: 'entityList',
+ name: 'alias.filter-type-entity-list'
+ },
+ entityName: {
+ value: 'entityName',
+ name: 'alias.filter-type-entity-name'
+ },
+ assetType: {
+ value: 'assetType',
+ name: 'alias.filter-type-asset-type'
+ },
+ deviceType: {
+ value: 'deviceType',
+ name: 'alias.filter-type-device-type'
+ },
+ relationsQuery: {
+ value: 'relationsQuery',
+ name: 'alias.filter-type-relations-query'
+ },
+ assetSearchQuery: {
+ value: 'assetSearchQuery',
+ name: 'alias.filter-type-asset-search-query'
+ },
+ deviceSearchQuery: {
+ value: 'deviceSearchQuery',
+ name: 'alias.filter-type-device-search-query'
+ }
+ },
position: {
top: {
value: "top",
diff --git a/ui/src/app/components/dashboard.directive.js b/ui/src/app/components/dashboard.directive.js
index f26121c..965b838 100644
--- a/ui/src/app/components/dashboard.directive.js
+++ b/ui/src/app/components/dashboard.directive.js
@@ -52,7 +52,7 @@ function Dashboard() {
bindToController: {
widgets: '=',
widgetLayouts: '=?',
- aliasesInfo: '=',
+ aliasController: '=',
stateController: '=',
dashboardTimewindow: '=?',
columns: '=',
@@ -329,10 +329,6 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, t
$scope.$broadcast('toggleDashboardEditMode', vm.isEdit);
});
- $scope.$watch('vm.aliasesInfo.entityAliases', function () {
- $scope.$broadcast('entityAliasListChanged', vm.aliasesInfo);
- }, true);
-
$scope.$on('gridster-resized', function (event, sizes, theGridster) {
if (checkIsLocalGridsterElement(theGridster)) {
vm.gridster = theGridster;
diff --git a/ui/src/app/components/dashboard.tpl.html b/ui/src/app/components/dashboard.tpl.html
index 69934ac..8d77a6f 100644
--- a/ui/src/app/components/dashboard.tpl.html
+++ b/ui/src/app/components/dashboard.tpl.html
@@ -89,7 +89,7 @@
<div flex tb-widget
locals="{ visibleRect: vm.visibleRect,
widget: widget,
- aliasesInfo: vm.aliasesInfo,
+ aliasController: vm.aliasController,
stateController: vm.stateController,
isEdit: vm.isEdit,
stDiff: vm.stDiff,
diff --git a/ui/src/app/components/datakey-config-dialog.controller.js b/ui/src/app/components/datakey-config-dialog.controller.js
index a8741f5..ccaac21 100644
--- a/ui/src/app/components/datakey-config-dialog.controller.js
+++ b/ui/src/app/components/datakey-config-dialog.controller.js
@@ -20,14 +20,14 @@ export default angular.module('thingsboard.dialogs.datakeyConfigDialog', [things
.name;
/*@ngInject*/
-function DatakeyConfigDialogController($scope, $mdDialog, entityService, dataKey, dataKeySettingsSchema, entityAlias, entityAliases) {
+function DatakeyConfigDialogController($scope, $mdDialog, $q, entityService, dataKey, dataKeySettingsSchema, entityAlias, aliasController) {
var vm = this;
vm.dataKey = dataKey;
vm.dataKeySettingsSchema = dataKeySettingsSchema;
vm.entityAlias = entityAlias;
- vm.entityAliases = entityAliases;
+ vm.aliasController = aliasController;
vm.hide = function () {
$mdDialog.hide();
@@ -38,12 +38,28 @@ function DatakeyConfigDialogController($scope, $mdDialog, entityService, dataKey
};
vm.fetchEntityKeys = function (entityAliasId, query, type) {
- var alias = vm.entityAliases[entityAliasId];
- if (alias) {
- return entityService.getEntityKeys(alias.entityType, alias.entityId, query, type);
- } else {
- return [];
- }
+ var deferred = $q.defer();
+ vm.aliasController.getAliasInfo(entityAliasId).then(
+ function success(aliasInfo) {
+ var entity = aliasInfo.currentEntity;
+ if (entity) {
+ entityService.getEntityKeys(entity.entityType, entity.id, query, type).then(
+ function success(keys) {
+ deferred.resolve(keys);
+ },
+ function fail() {
+ deferred.resolve([]);
+ }
+ );
+ } else {
+ deferred.resolve([]);
+ }
+ },
+ function fail() {
+ deferred.resolve([]);
+ }
+ );
+ return deferred.promise;
};
vm.save = function () {
diff --git a/ui/src/app/components/datasource.directive.js b/ui/src/app/components/datasource.directive.js
index 2c06a38..eb9eafc 100644
--- a/ui/src/app/components/datasource.directive.js
+++ b/ui/src/app/components/datasource.directive.js
@@ -76,7 +76,7 @@ function Datasource($compile, $templateCache, types) {
restrict: "E",
require: "^ngModel",
scope: {
- entityAliases: '=',
+ aliasController: '=',
widgetType: '=',
functionsOnly: '=',
datakeySettingsSchema: '=',
diff --git a/ui/src/app/components/datasource.tpl.html b/ui/src/app/components/datasource.tpl.html
index 88ff247..0e91d98 100644
--- a/ui/src/app/components/datasource.tpl.html
+++ b/ui/src/app/components/datasource.tpl.html
@@ -37,7 +37,7 @@
ng-switch-when="entity"
ng-required="model.type === types.datasourceType.entity"
widget-type="widgetType"
- entity-aliases="entityAliases"
+ alias-controller="aliasController"
generate-data-key="generateDataKey({chip: chip, type: type})"
fetch-entity-keys="fetchEntityKeys({entityAliasId: entityAliasId, query: query, type: type})"
on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias})">
diff --git a/ui/src/app/components/datasource-entity.directive.js b/ui/src/app/components/datasource-entity.directive.js
index 97732b9..da43274 100644
--- a/ui/src/app/components/datasource-entity.directive.js
+++ b/ui/src/app/components/datasource-entity.directive.js
@@ -103,10 +103,9 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
ngModelCtrl.$render = function () {
if (ngModelCtrl.$viewValue) {
var entityAliasId = ngModelCtrl.$viewValue.entityAliasId;
- if (scope.entityAliases[entityAliasId]) {
- scope.entityAlias = {id: entityAliasId, alias: scope.entityAliases[entityAliasId].alias,
- entityType: scope.entityAliases[entityAliasId].entityType,
- entityId: scope.entityAliases[entityAliasId].entityId};
+ var entityAliases = scope.aliasController.getEntityAliases();
+ if (entityAliases[entityAliasId]) {
+ scope.entityAlias = entityAliases[entityAliasId];
} else {
scope.entityAlias = null;
}
@@ -182,7 +181,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
dataKey: angular.copy(dataKey),
dataKeySettingsSchema: scope.datakeySettingsSchema,
entityAlias: scope.entityAlias,
- entityAliases: scope.entityAliases
+ aliasController: scope.aliasController
},
parent: angular.element($document[0].body),
fullscreen: true,
@@ -236,7 +235,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc
require: "^ngModel",
scope: {
widgetType: '=',
- entityAliases: '=',
+ aliasController: '=',
datakeySettingsSchema: '=',
generateDataKey: '&',
fetchEntityKeys: '&',
diff --git a/ui/src/app/components/datasource-entity.tpl.html b/ui/src/app/components/datasource-entity.tpl.html
index 97ee1b5..2fb4608 100644
--- a/ui/src/app/components/datasource-entity.tpl.html
+++ b/ui/src/app/components/datasource-entity.tpl.html
@@ -18,7 +18,7 @@
<section flex layout='column' layout-align="center" layout-gt-sm='row' layout-align-gt-sm="start center">
<tb-entity-alias-select
tb-required="true"
- entity-aliases="entityAliases"
+ alias-controller="aliasController"
ng-model="entityAlias"
on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias})">
</tb-entity-alias-select>
diff --git a/ui/src/app/components/entity-alias-select.directive.js b/ui/src/app/components/entity-alias-select.directive.js
index 204b83f..ca2db85 100644
--- a/ui/src/app/components/entity-alias-select.directive.js
+++ b/ui/src/app/components/entity-alias-select.directive.js
@@ -31,7 +31,7 @@ export default angular.module('thingsboard.directives.entityAliasSelect', [])
.name;
/*@ngInject*/
-function EntityAliasSelect($compile, $templateCache, $mdConstant) {
+function EntityAliasSelect($compile, $templateCache, $mdConstant, entityService) {
var linker = function (scope, element, attrs, ngModelCtrl) {
var template = $templateCache.get(entityAliasSelectTemplate);
@@ -49,19 +49,18 @@ function EntityAliasSelect($compile, $templateCache, $mdConstant) {
ngModelCtrl.$setValidity('entityAlias', valid);
};
- scope.$watch('entityAliases', function () {
+ scope.$watch('aliasController', function () {
scope.entityAliasList = [];
- for (var aliasId in scope.entityAliases) {
+ var entityAliases = scope.aliasController.getEntityAliases();
+ for (var aliasId in entityAliases) {
if (scope.allowedEntityTypes) {
- if (scope.allowedEntityTypes.indexOf(scope.entityAliases[aliasId].entityType) === -1) {
+ if (!entityService.filterAliasByEntityTypes(entityAliases[aliasId], scope.allowedEntityTypes)) {
continue;
}
}
- var entityAlias = {id: aliasId, alias: scope.entityAliases[aliasId].alias,
- entityType: scope.entityAliases[aliasId].entityType, entityId: scope.entityAliases[aliasId].entityId};
- scope.entityAliasList.push(entityAlias);
+ scope.entityAliasList.push(entityAliases[aliasId]);
}
- }, true);
+ });
scope.$watch('entityAlias', function () {
scope.updateView();
@@ -141,7 +140,7 @@ function EntityAliasSelect($compile, $templateCache, $mdConstant) {
link: linker,
scope: {
tbRequired: '=?',
- entityAliases: '=',
+ aliasController: '=',
allowedEntityTypes: '=?',
onCreateEntityAlias: '&'
}
ui/src/app/components/widget.controller.js 156(+115 -41)
diff --git a/ui/src/app/components/widget.controller.js b/ui/src/app/components/widget.controller.js
index 6fc4bba..103ad13 100644
--- a/ui/src/app/components/widget.controller.js
+++ b/ui/src/app/components/widget.controller.js
@@ -22,7 +22,7 @@ import Subscription from '../api/subscription';
/*@ngInject*/
export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, $filter, tbRaf, types, utils, timeService,
datasourceService, entityService, deviceService, visibleRect, isEdit, stDiff, dashboardTimewindow,
- dashboardTimewindowApi, widget, aliasesInfo, stateController, widgetType) {
+ dashboardTimewindowApi, widget, aliasController, stateController, widgetType) {
var vm = this;
@@ -37,6 +37,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
$scope.executingRpcRequest = false;
var gridsterItemInited = false;
+ var subscriptionInited = false;
var cafs = {};
@@ -149,7 +150,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
dashboardTimewindowApi: dashboardTimewindowApi,
types: types,
stDiff: stDiff,
- aliasesInfo: aliasesInfo
+ aliasController: aliasController
};
var widgetTypeInstance;
@@ -203,8 +204,13 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
vm.gridsterItemInitialized = gridsterItemInitialized;
- initialize();
-
+ initialize().then(
+ function(){
+ if (checkSize()) {
+ onInit();
+ }
+ }
+ );
/*
options = {
@@ -233,28 +239,42 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
}
}
- entityService.createDatasoucesFromSubscriptionsInfo(subscriptionsInfo).then(
+ entityService.createDatasourcesFromSubscriptionsInfo(subscriptionsInfo).then(
function (datasources) {
options.datasources = datasources;
- var subscription = createSubscription(options, subscribe);
- if (useDefaultComponents) {
- defaultSubscriptionOptions(subscription, options);
- }
- deferred.resolve(subscription);
+ createSubscription(options, subscribe).then(
+ function success(subscription) {
+ if (useDefaultComponents) {
+ defaultSubscriptionOptions(subscription, options);
+ }
+ deferred.resolve(subscription);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
}
);
return deferred.promise;
}
function createSubscription(options, subscribe) {
+ var deferred = $q.defer();
options.dashboardTimewindow = dashboardTimewindow;
- var subscription =
- new Subscription(subscriptionContext, options);
- widgetContext.subscriptions[subscription.id] = subscription;
- if (subscribe) {
- subscription.subscribe();
- }
- return subscription;
+ new Subscription(subscriptionContext, options).then(
+ function success(subscription) {
+ widgetContext.subscriptions[subscription.id] = subscription;
+ if (subscribe) {
+ subscription.subscribe();
+ }
+ deferred.resolve(subscription);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+
+ return deferred.promise;
}
function defaultComponentsOptions(options) {
@@ -310,8 +330,8 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
}
function createDefaultSubscription() {
- var subscription;
var options;
+ var deferred = $q.defer();
if (widget.type !== types.widgetType.rpc.value && widget.type !== types.widgetType.static.value) {
options = {
type: widget.type,
@@ -319,16 +339,23 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
};
defaultComponentsOptions(options);
- subscription = createSubscription(options);
-
- defaultSubscriptionOptions(subscription, options);
+ createSubscription(options).then(
+ function success(subscription) {
+ defaultSubscriptionOptions(subscription, options);
- // backward compatibility
+ // backward compatibility
- widgetContext.datasources = subscription.datasources;
- widgetContext.data = subscription.data;
- widgetContext.hiddenData = subscription.hiddenData;
- widgetContext.timeWindow = subscription.timeWindow;
+ widgetContext.datasources = subscription.datasources;
+ widgetContext.data = subscription.data;
+ widgetContext.hiddenData = subscription.hiddenData;
+ widgetContext.timeWindow = subscription.timeWindow;
+ widgetContext.defaultSubscription = subscription;
+ deferred.resolve();
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
} else if (widget.type === types.widgetType.rpc.value) {
$scope.loadingData = false;
@@ -356,24 +383,27 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
$scope.rpcRejection = null;
}
}
- subscription = createSubscription(options);
+ createSubscription(options).then(
+ function success(subscription) {
+ widgetContext.defaultSubscription = subscription;
+ deferred.resolve();
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
} else if (widget.type === types.widgetType.static.value) {
$scope.loadingData = false;
+ deferred.resolve();
+ } else {
+ deferred.resolve();
}
- if (subscription) {
- widgetContext.defaultSubscription = subscription;
- }
+ return deferred.promise;
}
function initialize() {
- if (!vm.useCustomDatasources) {
- createDefaultSubscription();
- } else {
- $scope.loadingData = false;
- }
-
$scope.$on('toggleDashboardEditMode', function (event, isEdit) {
onEditModeChanged(isEdit);
});
@@ -398,11 +428,14 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
onMobileModeChanged(newIsMobile);
});
- $scope.$on('entityAliasListChanged', function (event, aliasesInfo) {
- subscriptionContext.aliasesInfo = aliasesInfo;
+ $scope.$on('entityAliasesChanged', function (event, aliasIds) {
+ var subscriptionChanged = false;
for (var id in widgetContext.subscriptions) {
var subscription = widgetContext.subscriptions[id];
- subscription.onAliasesChanged();
+ subscriptionChanged = subscriptionChanged || subscription.onAliasesChanged(aliasIds);
+ }
+ if (subscriptionChanged && !vm.useCustomDatasources) {
+ reInit();
}
});
@@ -410,6 +443,44 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
removeResizeListener(widgetContext.$containerParent[0], onResize); // eslint-disable-line no-undef
onDestroy();
});
+
+ var deferred = $q.defer();
+ if (!vm.useCustomDatasources) {
+ createDefaultSubscription().then(
+ function success() {
+ subscriptionInited = true;
+ deferred.resolve();
+ },
+ function fail() {
+ subscriptionInited = true;
+ deferred.reject();
+ }
+ );
+ } else {
+ $scope.loadingData = false;
+ subscriptionInited = true;
+ deferred.resolve();
+ }
+ return deferred.promise;
+ }
+
+ function reInit() {
+ onDestroy();
+ if (!vm.useCustomDatasources) {
+ createDefaultSubscription().then(
+ function success() {
+ subscriptionInited = true;
+ onInit();
+ },
+ function fail() {
+ subscriptionInited = true;
+ onInit();
+ }
+ );
+ } else {
+ subscriptionInited = true;
+ onInit();
+ }
}
function handleWidgetException(e) {
@@ -418,7 +489,9 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
}
function onInit() {
- if (!widgetContext.inited) {
+ if (!widgetContext.inited &&
+ subscriptionInited &&
+ gridsterItemInited) {
widgetContext.inited = true;
try {
widgetTypeInstance.onInit();
@@ -462,7 +535,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
handleWidgetException(e);
}
});
- } else if (gridsterItemInited) {
+ } else {
onInit();
}
}
@@ -544,6 +617,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
var subscription = widgetContext.subscriptions[id];
subscription.destroy();
}
+ subscriptionInited = false;
widgetContext.subscriptions = [];
if (widgetContext.inited) {
widgetContext.inited = false;
diff --git a/ui/src/app/components/widget-config.directive.js b/ui/src/app/components/widget-config.directive.js
index c3793be..d5b4239 100644
--- a/ui/src/app/components/widget-config.directive.js
+++ b/ui/src/app/components/widget-config.directive.js
@@ -128,13 +128,9 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti
} else if (scope.widgetType === types.widgetType.rpc.value && scope.isDataEnabled) {
if (config.targetDeviceAliasIds && config.targetDeviceAliasIds.length > 0) {
var aliasId = config.targetDeviceAliasIds[0];
- if (scope.entityAliases[aliasId]) {
- scope.targetDeviceAlias.value = {
- id: aliasId,
- alias: scope.entityAliases[aliasId].alias,
- entityType: scope.entityAliases[aliasId].entityType,
- entityId: scope.entityAliases[aliasId].entityId
- };
+ var entityAliases = scope.aliasController.getEntityAliases();
+ if (entityAliases[aliasId]) {
+ scope.targetDeviceAlias.value = entityAliases[aliasId];
} else {
scope.targetDeviceAlias.value = null;
}
@@ -395,7 +391,7 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti
widgetType: '=',
widgetSettingsSchema: '=',
datakeySettingsSchema: '=',
- entityAliases: '=',
+ aliasController: '=',
functionsOnly: '=',
fetchEntityKeys: '&',
onCreateEntityAlias: '&',
diff --git a/ui/src/app/components/widget-config.tpl.html b/ui/src/app/components/widget-config.tpl.html
index 808e07b..0500e91 100644
--- a/ui/src/app/components/widget-config.tpl.html
+++ b/ui/src/app/components/widget-config.tpl.html
@@ -60,7 +60,7 @@
style="padding: 0 0 0 10px; margin: 5px;">
<tb-datasource flex ng-model="datasource.value"
widget-type="widgetType"
- entity-aliases="entityAliases"
+ alias-controller="aliasController"
functions-only="functionsOnly"
datakey-settings-schema="datakeySettingsSchema"
generate-data-key="generateDataKey(chip,type)"
@@ -104,7 +104,7 @@
<v-pane-content style="padding: 0 5px;">
<tb-entity-alias-select flex
tb-required="widgetType === types.widgetType.rpc.value && !widgetEditMode"
- entity-aliases="entityAliases"
+ alias-controller="aliasController"
allowed-entity-types="[types.entityType.device]"
ng-model="targetDeviceAlias.value"
on-create-entity-alias="onCreateEntityAlias({event: event, alias: alias, allowedEntityTypes: allowedEntityTypes})">
ui/src/app/dashboard/add-widget.controller.js 52(+31 -21)
diff --git a/ui/src/app/dashboard/add-widget.controller.js b/ui/src/app/dashboard/add-widget.controller.js
index 2f23cf9..586fb46 100644
--- a/ui/src/app/dashboard/add-widget.controller.js
+++ b/ui/src/app/dashboard/add-widget.controller.js
@@ -20,12 +20,13 @@ import entityAliasesTemplate from '../entity/entity-aliases.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
-export default function AddWidgetController($scope, widgetService, entityService, $mdDialog, $q, $document, types, dashboard, aliasesInfo, widget, widgetInfo) {
+export default function AddWidgetController($scope, widgetService, entityService, $mdDialog, $q, $document, types, dashboard,
+ aliasController, widget, widgetInfo) {
var vm = this;
vm.dashboard = dashboard;
- vm.aliasesInfo = aliasesInfo;
+ vm.aliasController = aliasController;
vm.widget = widget;
vm.widgetInfo = widgetInfo;
@@ -85,7 +86,7 @@ export default function AddWidgetController($scope, widgetService, entityService
}
function cancel () {
- $mdDialog.cancel({aliasesInfo: vm.aliasesInfo});
+ $mdDialog.cancel();
}
function add () {
@@ -94,23 +95,39 @@ export default function AddWidgetController($scope, widgetService, entityService
vm.widget.config = vm.widgetConfig.config;
vm.widget.config.mobileOrder = vm.widgetConfig.layout.mobileOrder;
vm.widget.config.mobileHeight = vm.widgetConfig.layout.mobileHeight;
- $mdDialog.hide({widget: vm.widget, aliasesInfo: vm.aliasesInfo});
+ $mdDialog.hide({widget: vm.widget});
}
}
function fetchEntityKeys (entityAliasId, query, type) {
- var entityAlias = vm.aliasesInfo.entityAliases[entityAliasId];
- if (entityAlias && entityAlias.entityId) {
- return entityService.getEntityKeys(entityAlias.entityType, entityAlias.entityId, query, type);
- } else {
- return $q.when([]);
- }
+ var deferred = $q.defer();
+ vm.aliasController.getAliasInfo(entityAliasId).then(
+ function success(aliasInfo) {
+ var entity = aliasInfo.currentEntity;
+ if (entity) {
+ entityService.getEntityKeys(entity.entityType, entity.id, query, type).then(
+ function success(keys) {
+ deferred.resolve(keys);
+ },
+ function fail() {
+ deferred.resolve([]);
+ }
+ );
+ } else {
+ deferred.resolve([]);
+ }
+ },
+ function fail() {
+ deferred.resolve([]);
+ }
+ );
+ return deferred.promise;
}
function createEntityAlias (event, alias, allowedEntityTypes) {
var deferred = $q.defer();
- var singleEntityAlias = {id: null, alias: alias, entityType: types.entityType.device, entityFilter: null};
+ var singleEntityAlias = {id: null, alias: alias, filter: {}};
$mdDialog.show({
controller: 'EntityAliasesController',
@@ -130,16 +147,9 @@ export default function AddWidgetController($scope, widgetService, entityService
skipHide: true,
targetEvent: event
}).then(function (singleEntityAlias) {
- vm.dashboard.configuration.entityAliases[singleEntityAlias.id] =
- { alias: singleEntityAlias.alias, entityType: singleEntityAlias.entityType, entityFilter: singleEntityAlias.entityFilter };
- entityService.processEntityAliases(vm.dashboard.configuration.entityAliases).then(
- function(resolution) {
- if (!resolution.error) {
- vm.aliasesInfo = resolution.aliasesInfo;
- }
- deferred.resolve(singleEntityAlias);
- }
- );
+ vm.dashboard.configuration.entityAliases[singleEntityAlias.id] = singleEntityAlias;
+ vm.aliasController.updateEntityAliases(vm.dashboard.configuration.entityAliases);
+ deferred.resolve(singleEntityAlias);
}, function () {
deferred.reject();
});
diff --git a/ui/src/app/dashboard/add-widget.tpl.html b/ui/src/app/dashboard/add-widget.tpl.html
index 870e203..7617760 100644
--- a/ui/src/app/dashboard/add-widget.tpl.html
+++ b/ui/src/app/dashboard/add-widget.tpl.html
@@ -37,7 +37,7 @@
ng-model="vm.widgetConfig"
widget-settings-schema="vm.settingsSchema"
datakey-settings-schema="vm.dataKeySettingsSchema"
- entity-aliases="vm.aliasesInfo.entityAliases"
+ alias-controller="vm.aliasController"
functions-only="vm.functionsOnly"
fetch-entity-keys="vm.fetchEntityKeys(entityAliasId, query, type)"
on-create-entity-alias="vm.createEntityAlias(event, alias, allowedEntityTypes)"
ui/src/app/dashboard/dashboard.controller.js 37(+17 -20)
diff --git a/ui/src/app/dashboard/dashboard.controller.js b/ui/src/app/dashboard/dashboard.controller.js
index 31892a6..195184b 100644
--- a/ui/src/app/dashboard/dashboard.controller.js
+++ b/ui/src/app/dashboard/dashboard.controller.js
@@ -24,8 +24,10 @@ import selectTargetLayoutTemplate from './layouts/select-target-layout.tpl.html'
/* eslint-enable import/no-unresolved, import/default */
+import AliasController from '../api/alias-controller';
+
/*@ngInject*/
-export default function DashboardController(types, dashboardUtils, widgetService, userService,
+export default function DashboardController(types, utils, dashboardUtils, widgetService, userService,
dashboardService, timeService, entityService, itembuffer, importExport, hotkeys, $window, $rootScope,
$scope, $element, $state, $stateParams, $mdDialog, $mdMedia, $timeout, $document, $q, $translate, $filter) {
@@ -349,7 +351,13 @@ export default function DashboardController(types, dashboardUtils, widgetService
dashboardService.getDashboard($stateParams.dashboardId)
.then(function success(dashboard) {
vm.dashboard = dashboardUtils.validateAndUpdateDashboard(dashboard);
- entityService.processEntityAliases(vm.dashboard.configuration.entityAliases)
+ vm.dashboardConfiguration = vm.dashboard.configuration;
+ vm.dashboardCtx.dashboard = vm.dashboard;
+ vm.dashboardCtx.dashboardTimewindow = vm.dashboardConfiguration.timewindow;
+ vm.dashboardCtx.aliasController = new AliasController($scope, $q, $filter, utils,
+ types, entityService, vm.dashboardCtx.stateController, vm.dashboardConfiguration.entityAliases);
+
+ /* entityService.processEntityAliases(vm.dashboard.configuration.entityAliases)
.then(
function(resolution) {
if (resolution.error && !isTenantAdmin()) {
@@ -362,7 +370,7 @@ export default function DashboardController(types, dashboardUtils, widgetService
vm.dashboardCtx.dashboardTimewindow = vm.dashboardConfiguration.timewindow;
}
}
- );
+ );*/
}, function fail() {
vm.configurationError = true;
});
@@ -373,6 +381,7 @@ export default function DashboardController(types, dashboardUtils, widgetService
var layoutsData = dashboardUtils.getStateLayoutsData(vm.dashboard, state);
if (layoutsData) {
vm.dashboardCtx.state = state;
+ vm.dashboardCtx.aliasController.dashboardStateChanged();
var layoutVisibilityChanged = false;
for (var l in vm.layouts) {
var layout = vm.layouts[l];
@@ -916,7 +925,7 @@ export default function DashboardController(types, dashboardUtils, widgetService
templateUrl: addWidgetTemplate,
locals: {
dashboard: vm.dashboard,
- aliasesInfo: vm.dashboardCtx.aliasesInfo,
+ aliasController: vm.dashboardCtx.aliasController,
widget: newWidget,
widgetInfo: widgetTypeInfo
},
@@ -930,10 +939,8 @@ export default function DashboardController(types, dashboardUtils, widgetService
}
}).then(function (result) {
var widget = result.widget;
- vm.dashboardCtx.aliasesInfo = result.aliasesInfo;
addWidget(widget);
- }, function (rejection) {
- vm.dashboardCtx.aliasesInfo = rejection.aliasesInfo;
+ }, function () {
});
}
}
@@ -1025,7 +1032,7 @@ export default function DashboardController(types, dashboardUtils, widgetService
notifyDashboardUpdated();
}
- function showAliasesResolutionError(error) {
+/* function showAliasesResolutionError(error) {
var alert = $mdDialog.alert()
.parent(angular.element($document[0].body))
.clickOutsideToClose(true)
@@ -1037,20 +1044,10 @@ export default function DashboardController(types, dashboardUtils, widgetService
alert._options.fullscreen = true;
$mdDialog.show(alert);
- }
+ }*/
function entityAliasesUpdated() {
- var deferred = $q.defer();
- entityService.processEntityAliases(vm.dashboard.configuration.entityAliases)
- .then(
- function(resolution) {
- if (resolution.aliasesInfo) {
- vm.dashboardCtx.aliasesInfo = resolution.aliasesInfo;
- }
- deferred.resolve();
- }
- );
- return deferred.promise;
+ vm.dashboardCtx.aliasController.updateEntityAliases(vm.dashboard.configuration.entityAliases);
}
function notifyDashboardUpdated() {
diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html
index 8338612..202268f 100644
--- a/ui/src/app/dashboard/dashboard.tpl.html
+++ b/ui/src/app/dashboard/dashboard.tpl.html
@@ -57,8 +57,7 @@
</tb-timewindow>
<tb-aliases-entity-select ng-show="!vm.isEdit && vm.displayEntitiesSelect()"
tooltip-direction="bottom"
- ng-model="vm.dashboardCtx.aliasesInfo.entityAliases"
- entity-aliases-info="vm.dashboardCtx.aliasesInfo.entityAliasesInfo">
+ alias-controller="vm.dashboardCtx.aliasController">
</tb-aliases-entity-select>
<md-button ng-show="vm.isEdit" aria-label="{{ 'entity.aliases' | translate }}" class="md-icon-button"
ng-click="vm.openEntityAliases($event)">
@@ -179,7 +178,7 @@
<form name="vm.widgetForm" ng-if="vm.isEditingWidget">
<tb-edit-widget
dashboard="vm.dashboard"
- aliases-info="vm.dashboardCtx.aliasesInfo"
+ alias-controller="vm.dashboardCtx.aliasController"
widget="vm.editingWidget"
widget-layout="vm.editingWidgetLayout"
the-form="vm.widgetForm">
ui/src/app/dashboard/edit-widget.directive.js 45(+27 -18)
diff --git a/ui/src/app/dashboard/edit-widget.directive.js b/ui/src/app/dashboard/edit-widget.directive.js
index 7cba4ee..4bd4e3d 100644
--- a/ui/src/app/dashboard/edit-widget.directive.js
+++ b/ui/src/app/dashboard/edit-widget.directive.js
@@ -68,18 +68,34 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid
});
scope.fetchEntityKeys = function (entityAliasId, query, type) {
- var entityAlias = scope.aliasesInfo.entityAliases[entityAliasId];
- if (entityAlias && entityAlias.entityId) {
- return entityService.getEntityKeys(entityAlias.entityType, entityAlias.entityId, query, type);
- } else {
- return $q.when([]);
- }
+ var deferred = $q.defer();
+ scope.aliasController.getAliasInfo(entityAliasId).then(
+ function success(aliasInfo) {
+ var entity = aliasInfo.currentEntity;
+ if (entity) {
+ entityService.getEntityKeys(entity.entityType, entity.id, query, type).then(
+ function success(keys) {
+ deferred.resolve(keys);
+ },
+ function fail() {
+ deferred.resolve([]);
+ }
+ );
+ } else {
+ deferred.resolve([]);
+ }
+ },
+ function fail() {
+ deferred.resolve([]);
+ }
+ );
+ return deferred.promise;
};
scope.createEntityAlias = function (event, alias, allowedEntityTypes) {
var deferred = $q.defer();
- var singleEntityAlias = {id: null, alias: alias, entityType: types.entityType.device, entityFilter: null};
+ var singleEntityAlias = {id: null, alias: alias, filter: {}};
$mdDialog.show({
controller: 'EntityAliasesController',
@@ -99,16 +115,9 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid
skipHide: true,
targetEvent: event
}).then(function (singleEntityAlias) {
- scope.dashboard.configuration.entityAliases[singleEntityAlias.id] =
- { alias: singleEntityAlias.alias, entityType: singleEntityAlias.entityType, entityFilter: singleEntityAlias.entityFilter };
- entityService.processEntityAliases(scope.dashboard.configuration.entityAliases).then(
- function(resolution) {
- if (!resolution.error) {
- scope.aliasesInfo = resolution.aliasesInfo;
- }
- deferred.resolve(singleEntityAlias);
- }
- );
+ scope.dashboard.configuration.entityAliases[singleEntityAlias.id] = singleEntityAlias;
+ scope.aliasController.updateEntityAliases(scope.dashboard.configuration.entityAliases);
+ deferred.resolve(singleEntityAlias);
}, function () {
deferred.reject();
});
@@ -124,7 +133,7 @@ export default function EditWidgetDirective($compile, $templateCache, types, wid
link: linker,
scope: {
dashboard: '=',
- aliasesInfo: '=',
+ aliasController: '=',
widget: '=',
widgetLayout: '=',
theForm: '='
diff --git a/ui/src/app/dashboard/edit-widget.tpl.html b/ui/src/app/dashboard/edit-widget.tpl.html
index 279d311..a9ff0b6 100644
--- a/ui/src/app/dashboard/edit-widget.tpl.html
+++ b/ui/src/app/dashboard/edit-widget.tpl.html
@@ -21,7 +21,7 @@
is-data-enabled="isDataEnabled"
widget-settings-schema="settingsSchema"
datakey-settings-schema="dataKeySettingsSchema"
- entity-aliases="aliasesInfo.entityAliases"
+ alias-controller="aliasController"
functions-only="functionsOnly"
fetch-entity-keys="fetchEntityKeys(entityAliasId, query, type)"
on-create-entity-alias="createEntityAlias(event, alias, allowedEntityTypes)"
diff --git a/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html b/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html
index ea84858..4a4b25e 100644
--- a/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html
+++ b/ui/src/app/dashboard/layouts/dashboard-layout.tpl.html
@@ -45,7 +45,7 @@
widget-layouts="vm.layoutCtx.widgetLayouts"
columns="vm.layoutCtx.gridSettings.columns"
margins="vm.layoutCtx.gridSettings.margins"
- aliases-info="vm.dashboardCtx.aliasesInfo"
+ alias-controller="vm.dashboardCtx.aliasController"
state-controller="vm.dashboardCtx.stateController"
dashboard-timewindow="vm.dashboardCtx.dashboardTimewindow"
is-edit="vm.isEdit"
diff --git a/ui/src/app/entity/aliases-entity-select.directive.js b/ui/src/app/entity/aliases-entity-select.directive.js
index 7512409..7e174ef 100644
--- a/ui/src/app/entity/aliases-entity-select.directive.js
+++ b/ui/src/app/entity/aliases-entity-select.directive.js
@@ -29,7 +29,7 @@ import aliasesEntitySelectPanelTemplate from './aliases-entity-select-panel.tpl.
/*@ngInject*/
export default function AliasesEntitySelectDirective($compile, $templateCache, $mdMedia, types, $mdPanel, $document, $translate) {
- var linker = function (scope, element, attrs, ngModelCtrl) {
+ var linker = function (scope, element, attrs) {
/* tbAliasesEntitySelect (ng-model)
* {
@@ -81,10 +81,8 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $
position: position,
fullscreen: false,
locals: {
- 'entityAliases': angular.copy(scope.model),
- 'entityAliasesInfo': scope.entityAliasesInfo,
- 'onEntityAliasesUpdate': function (entityAliases) {
- scope.model = entityAliases;
+ 'aliasController': scope.aliasController,
+ 'onEntityAliasesUpdate': function () {
scope.updateView();
}
},
@@ -97,40 +95,31 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $
}
scope.updateView = function () {
- var value = angular.copy(scope.model);
- ngModelCtrl.$setViewValue(value);
updateDisplayValue();
}
- ngModelCtrl.$render = function () {
- if (ngModelCtrl.$viewValue) {
- var value = ngModelCtrl.$viewValue;
- scope.model = angular.copy(value);
- updateDisplayValue();
- }
- }
-
function updateDisplayValue() {
var displayValue;
var singleValue = true;
var currentAliasId;
- for (var aliasId in scope.model) {
- if (!currentAliasId) {
- currentAliasId = aliasId;
- } else {
- singleValue = false;
- break;
+ var entityAliases = scope.aliasController.getEntityAliases();
+ for (var aliasId in entityAliases) {
+ var entityAlias = entityAliases[aliasId];
+ if (!entityAlias.filter.resolveMultiple) {
+ var resolvedAlias = scope.aliasController.getInstantAliasInfo(aliasId);
+ if (resolvedAlias && resolvedAlias.currentEntity) {
+ if (!currentAliasId) {
+ currentAliasId = aliasId;
+ } else {
+ singleValue = false;
+ break;
+ }
+ }
}
}
if (singleValue && currentAliasId) {
- var entityId = scope.model[currentAliasId].entityId;
- var entitiesInfo = scope.entityAliasesInfo[currentAliasId];
- for (var i=0;i<entitiesInfo.length;i++) {
- if (entitiesInfo[i].id === entityId) {
- displayValue = entitiesInfo[i].name;
- break;
- }
- }
+ var aliasInfo = scope.aliasController.getInstantAliasInfo(currentAliasId);
+ displayValue = aliasInfo.currentEntity.name;
} else {
displayValue = $translate.instant('entity.entities');
}
@@ -142,9 +131,8 @@ export default function AliasesEntitySelectDirective($compile, $templateCache, $
return {
restrict: "E",
- require: "^ngModel",
scope: {
- entityAliasesInfo:'='
+ aliasController:'='
},
link: linker
};
diff --git a/ui/src/app/entity/aliases-entity-select-panel.controller.js b/ui/src/app/entity/aliases-entity-select-panel.controller.js
index 4128f94..8439269 100644
--- a/ui/src/app/entity/aliases-entity-select-panel.controller.js
+++ b/ui/src/app/entity/aliases-entity-select-panel.controller.js
@@ -15,17 +15,30 @@
*/
/*@ngInject*/
-export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, types, entityAliases, entityAliasesInfo, onEntityAliasesUpdate) {
+export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, types, aliasController, onEntityAliasesUpdate) {
var vm = this;
vm._mdPanelRef = mdPanelRef;
- vm.entityAliases = entityAliases;
- vm.entityAliasesInfo = entityAliasesInfo;
+ vm.aliasController = aliasController;
vm.onEntityAliasesUpdate = onEntityAliasesUpdate;
+ vm.entityAliases = {};
+ vm.entityAliasesInfo = {};
- $scope.$watch('vm.entityAliases', function () {
+ vm.currentAliasEntityChanged = currentAliasEntityChanged;
+
+ var allEntityAliases = vm.aliasController.getEntityAliases();
+ for (var aliasId in allEntityAliases) {
+ var aliasInfo = vm.aliasController.getInstantAliasInfo(aliasId);
+ if (aliasInfo && !aliasInfo.resolveMultiple && aliasInfo.currentEntity) {
+ vm.entityAliasesInfo[aliasId] = angular.copy(aliasInfo);
+ }
+ }
+
+ function currentAliasEntityChanged(aliasId, currentEntity) {
+ vm.aliasController.updateCurrentAliasEntity(aliasId, currentEntity);
if (onEntityAliasesUpdate) {
- onEntityAliasesUpdate(vm.entityAliases);
+ onEntityAliasesUpdate();
}
- }, true);
+ }
+
}
diff --git a/ui/src/app/entity/aliases-entity-select-panel.tpl.html b/ui/src/app/entity/aliases-entity-select-panel.tpl.html
index d9c5f2f..edc8e5a 100644
--- a/ui/src/app/entity/aliases-entity-select-panel.tpl.html
+++ b/ui/src/app/entity/aliases-entity-select-panel.tpl.html
@@ -18,12 +18,12 @@
<md-content flex layout="column">
<section flex layout="column">
<md-content flex class="md-padding" layout="column">
- <div flex layout="row" ng-repeat="(aliasId, entityAlias) in vm.entityAliases">
+ <div flex layout="row" ng-repeat="(aliasId, entityAliasInfo) in vm.entityAliasesInfo">
<md-input-container flex>
- <label>{{entityAlias.alias}}</label>
- <md-select ng-model="vm.entityAliases[aliasId].entityId">
- <md-option ng-repeat="entityInfo in vm.entityAliasesInfo[aliasId]" ng-value="entityInfo.id">
- {{entityInfo.name}}
+ <label>{{entityAliasInfo.alias}}</label>
+ <md-select ng-model="entityAliasInfo.currentEntity" ng-change="vm.currentAliasEntityChanged(aliasId, entityAliasInfo.currentEntity)">
+ <md-option ng-repeat="resolvedEntity in entityAliasInfo.resolvedEntities" ng-value="resolvedEntity">
+ {{resolvedEntity.name}}
</md-option>
</md-select>
</md-input-container>
ui/src/app/entity/entity-aliases.controller.js 38(+12 -26)
diff --git a/ui/src/app/entity/entity-aliases.controller.js b/ui/src/app/entity/entity-aliases.controller.js
index f1e2e38..088f8b9 100644
--- a/ui/src/app/entity/entity-aliases.controller.js
+++ b/ui/src/app/entity/entity-aliases.controller.js
@@ -85,32 +85,29 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
for (aliasId in config.entityAliases) {
var entityAlias = config.entityAliases[aliasId];
- var result = {id: aliasId, alias: entityAlias.alias, entityType: entityAlias.entityType, entityFilter: entityAlias.entityFilter, changed: true};
+ var result = {id: aliasId, alias: entityAlias.alias, filter: entityAlias.filter, changed: true};
checkEntityAlias(result);
vm.entityAliases.push(result);
}
}
function checkEntityAlias(entityAlias) {
- if (!entityAlias.entityType) {
- entityAlias.entityType = types.entityType.device;
- }
- if (!entityAlias.entityFilter || entityAlias.entityFilter == null) {
- entityAlias.entityFilter = {
- useFilter: false,
- entityNameFilter: '',
- entityList: [],
- };
+ if (!entityAlias.filter || entityAlias.filter == null) {
+ entityAlias.filter = {};
}
}
- function onFilterEntityChanged(entity, entityAlias) {
+ function onFilterEntityChanged(entity, stateEntity, entityAlias) {
if (entityAlias) {
if (!entityAlias.alias || entityAlias.alias.length == 0) {
entityAlias.changed = false;
}
- if (!entityAlias.changed && entity && entityAlias.entityType) {
- entityAlias.alias = entity.name;
+ if (!entityAlias.changed && entityAlias.filter && entityAlias.filter.type) {
+ if (stateEntity) {
+ entityAlias.alias = $translate.instant('alias.state-entity');
+ } else {
+ entityAlias.alias = entity.name;
+ }
}
}
}
@@ -121,8 +118,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
aliasId = Math.max(vm.entityAliases[a].id, aliasId);
}
aliasId++;
- var entityAlias = {id: aliasId, alias: '', entityType: types.entityType.device,
- entityFilter: {useFilter: false, entityNameFilter: '', entityList: []}, changed: false};
+ var entityAlias = {id: aliasId, alias: '', filter: {}, changed: false};
vm.entityAliases.push(entityAlias);
}
@@ -160,15 +156,6 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
$mdDialog.cancel();
}
- function cleanupEntityFilter(entityFilter) {
- if (entityFilter.useFilter) {
- entityFilter.entityList = [];
- } else {
- entityFilter.entityNameFilter = '';
- }
- return entityFilter;
- }
-
function save() {
var entityAliases = {};
@@ -181,7 +168,6 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
if (vm.isSingleEntityAlias) {
maxAliasId = 0;
- vm.singleEntityAlias.entityFilter = cleanupEntityFilter(vm.singleEntityAlias.entityFilter);
for (i = 0; i < vm.entityAliases.length; i ++) {
aliasId = vm.entityAliases[i].id;
alias = vm.entityAliases[i].alias;
@@ -199,7 +185,7 @@ export default function EntityAliasesController(utils, entityService, toast, $sc
alias = vm.entityAliases[i].alias;
if (!uniqueAliasList[alias]) {
uniqueAliasList[alias] = alias;
- entityAliases[aliasId] = {alias: alias, entityType: vm.entityAliases[i].entityType, entityFilter: cleanupEntityFilter(vm.entityAliases[i].entityFilter)};
+ entityAliases[aliasId] = {id: aliasId, alias: alias, filter: vm.entityAliases[i].filter};
} else {
valid = false;
break;
ui/src/app/entity/entity-aliases.tpl.html 27(+8 -19)
diff --git a/ui/src/app/entity/entity-aliases.tpl.html b/ui/src/app/entity/entity-aliases.tpl.html
index bc9e269..ef8b032 100644
--- a/ui/src/app/entity/entity-aliases.tpl.html
+++ b/ui/src/app/entity/entity-aliases.tpl.html
@@ -32,20 +32,15 @@
<div class="md-dialog-content">
<fieldset ng-disabled="loading">
<div ng-show="vm.isSingleEntityAlias" layout="row">
- <tb-entity-type-select style="min-width: 100px;"
- ng-model="vm.singleEntityAlias.entityType"
- allowed-entity-types="vm.allowedEntityTypes">
- </tb-entity-type-select>
- <tb-entity-filter flex entity-type="vm.singleEntityAlias.entityType" ng-model="vm.singleEntityAlias.entityFilter">
+ <tb-entity-filter flex allowed-entity-types="vm.allowedEntityTypes" ng-model="vm.singleEntityAlias.filter">
</tb-entity-filter>
</div>
<div ng-show="!vm.isSingleEntityAlias" flex layout="row" layout-align="start center">
<span flex="5"></span>
<div flex layout="row" layout-align="start center"
style="padding: 0 0 0 10px; margin: 5px;">
- <span translate flex="20" style="min-width: 100px;">entity.alias</span>
- <span translate flex="20" style="min-width: 100px;">entity.type</span>
- <span translate flex="60" style="min-width: 190px; padding-left: 10px;">entity.entities</span>
+ <span translate flex="20" style="min-width: 150px;">entity.alias</span>
+ <span translate flex="80" style="min-width: 240px; padding-left: 10px;">alias.entity-filter</span>
<span style="min-width: 40px;"></span>
</div>
</div>
@@ -53,23 +48,17 @@
<div ng-form name="aliasForm" flex layout="row" layout-align="start center" ng-repeat="entityAlias in vm.entityAliases track by $index">
<span flex="5">{{$index + 1}}.</span>
<div class="md-whiteframe-4dp tb-alias" flex layout="row" layout-align="start center">
- <md-input-container flex="20" style="min-width: 100px;" md-no-float class="md-block">
+ <md-input-container flex="20" style="min-width: 150px;" md-no-float class="md-block">
<input required ng-change="entityAlias.changed=true" name="alias" placeholder="{{ 'entity.alias' | translate }}" ng-model="entityAlias.alias">
<div ng-messages="aliasForm.alias.$error">
<div translate ng-message="required">entity.alias-required</div>
</div>
</md-input-container>
- <section flex="20" layout="column" style="min-width: 100px;" >
- <tb-entity-type-select hide-label style="padding-left: 10px;"
- ng-model="entityAlias.entityType"
- allowed-entity-types="vm.allowedEntityTypes">
- </tb-entity-type-select>
- </section>
- <section flex="60" layout="column">
+ <section flex="80" layout="column">
<tb-entity-filter style="padding-left: 10px;"
- entity-type="entityAlias.entityType"
- ng-model="entityAlias.entityFilter"
- on-matching-entity-change="vm.onFilterEntityChanged(entity, entityAlias)">
+ allowed-entity-types="vm.allowedEntityTypes"
+ ng-model="entityAlias.filter"
+ on-matching-entity-change="vm.onFilterEntityChanged(entity, stateEntity, entityAlias)">
</tb-entity-filter>
</section>
<md-button ng-disabled="loading" class="md-icon-button md-primary" style="min-width: 40px;"
ui/src/app/entity/entity-filter.directive.js 81(+65 -16)
diff --git a/ui/src/app/entity/entity-filter.directive.js b/ui/src/app/entity/entity-filter.directive.js
index b1d92c6..beded8a 100644
--- a/ui/src/app/entity/entity-filter.directive.js
+++ b/ui/src/app/entity/entity-filter.directive.js
@@ -17,13 +17,16 @@
/* eslint-disable import/no-unresolved, import/default */
import entityFilterTemplate from './entity-filter.tpl.html';
+import entityFilterDialogTemplate from './entity-filter-dialog.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
+import EntityFilterDialogController from './entity-filter-dialog.controller';
+
import './entity-filter.scss';
/*@ngInject*/
-export default function EntityFilterDirective($compile, $templateCache, $q, entityService) {
+export default function EntityFilterDirective($compile, $templateCache, $q, $document, $mdDialog, types) {
var linker = function (scope, element, attrs, ngModelCtrl) {
@@ -31,8 +34,9 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti
element.html(template);
scope.ngModelCtrl = ngModelCtrl;
+ scope.types = types;
- scope.fetchEntities = function(searchText, limit) {
+ /* scope.fetchEntities = function(searchText, limit) {
var deferred = $q.defer();
entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(function success(result) {
if (result) {
@@ -44,13 +48,13 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti
deferred.reject();
});
return deferred.promise;
- }
+ }*/
scope.updateValidity = function() {
if (ngModelCtrl.$viewValue) {
var value = ngModelCtrl.$viewValue;
- var valid;
- if (value.useFilter) {
+ ngModelCtrl.$setValidity('filter', value.type ? true : false);
+ /*if (value.useFilter) {
ngModelCtrl.$setValidity('entityList', true);
if (angular.isDefined(value.entityNameFilter) && value.entityNameFilter.length > 0) {
ngModelCtrl.$setValidity('entityNameFilter', true);
@@ -64,18 +68,22 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti
ngModelCtrl.$setValidity('entityNameFilterDeviceMatch', true);
valid = angular.isDefined(value.entityList) && value.entityList.length > 0;
ngModelCtrl.$setValidity('entityList', valid);
- }
+ }*/
+
}
}
ngModelCtrl.$render = function () {
- destroyWatchers();
- scope.model = {
- useFilter: false,
- entityList: [],
- entityNameFilter: ''
- }
+ //destroyWatchers();
if (ngModelCtrl.$viewValue) {
+ scope.model = angular.copy(ngModelCtrl.$viewValue);
+ } else {
+ scope.model = {
+ type: null,
+ resolveMultiple: false
+ }
+ }
+ /* if (ngModelCtrl.$viewValue) {
var value = ngModelCtrl.$viewValue;
var model = scope.model;
model.useFilter = value.useFilter === true ? true: false;
@@ -96,10 +104,52 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti
}
}
)
+ }*/
+ }
+
+ scope.$watch('model.resolveMultiple', function () {
+ if (ngModelCtrl.$viewValue) {
+ var value = ngModelCtrl.$viewValue;
+ value.resolveMultiple = scope.model.resolveMultiple;
+ ngModelCtrl.$setViewValue(value);
+ scope.updateValidity();
}
+ });
+
+ scope.editFilter = function($event) {
+ openEntityFilterDialog($event, false);
+ }
+
+ scope.createFilter = function($event) {
+ openEntityFilterDialog($event, true);
}
- function updateMatchingEntity() {
+ function openEntityFilterDialog($event, isAdd) {
+ $mdDialog.show({
+ controller: EntityFilterDialogController,
+ controllerAs: 'vm',
+ templateUrl: entityFilterDialogTemplate,
+ locals: {
+ isAdd: isAdd,
+ allowedEntityTypes: scope.allowedEntityTypes,
+ filter: angular.copy(scope.model)
+ },
+ parent: angular.element($document[0].body),
+ fullscreen: true,
+ skipHide: true,
+ targetEvent: $event
+ }).then(function (result) {
+ scope.model = result.filter;
+ ngModelCtrl.$setViewValue(result.filter);
+ scope.updateValidity();
+ if (scope.onMatchingEntityChange) {
+ scope.onMatchingEntityChange({entity: result.entity, stateEntity: result.stateEntity});
+ }
+ }, function () {
+ });
+ }
+
+ /* function updateMatchingEntity() {
if (scope.model.useFilter) {
scope.model.matchingEntity = scope.model.matchingFilterEntity;
} else {
@@ -206,7 +256,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti
}
}
});
- }
+ }*/
$compile(element.contents())(scope);
@@ -217,8 +267,7 @@ export default function EntityFilterDirective($compile, $templateCache, $q, enti
require: "^ngModel",
link: linker,
scope: {
- entityType: '=',
- isEdit: '=',
+ allowedEntityTypes: '=?',
onMatchingEntityChange: '&'
}
};
ui/src/app/entity/entity-filter.tpl.html 37(+32 -5)
diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html
index 7e49ba9..9a5337a 100644
--- a/ui/src/app/entity/entity-filter.tpl.html
+++ b/ui/src/app/entity/entity-filter.tpl.html
@@ -17,7 +17,7 @@
-->
<section layout='column' class="tb-entity-filter">
<section layout='row'>
- <section layout="column" flex ng-show="!model.useFilter">
+ <!--section layout="column" flex ng-show="!model.useFilter">
<md-chips flex
id="entity_list_chips"
ng-required="!useFilter"
@@ -51,17 +51,44 @@
<label translate>entity.name-starts-with</label>
<input ng-model="model.entityNameFilter" aria-label="{{ 'entity.name-starts-with' | translate }}">
</md-input-container>
+ </section-->
+ <section layout="row" flex layout-align="start center">
+ <div flex ng-if="model.type">{{ types.aliasFilterType[model.type].name | translate }}</div>
+ <md-button ng-if="model.type" ng-disabled="loading" class="md-icon-button md-primary"
+ style="min-width: 40px;"
+ ng-click="editFilter($event)"
+ aria-label="{{ 'alias.edit-entity-filter' | translate }}">
+ <md-tooltip md-direction="top">
+ {{ 'alias.edit-entity-filter' | translate }}
+ </md-tooltip>
+ <md-icon aria-label="{{ 'alias.edit-entity-filter' | translate }}"
+ class="material-icons">
+ edit
+ </md-icon>
+ </md-button>
+ <div ng-if="!model.type" layout="row" layout-align="center start">
+ <md-button ng-disabled="loading" class="md-primary md-raised"
+ ng-click="createFilter($event)"
+ aria-label="{{ 'alias.create-entity-filter' | translate }}">
+ <md-icon aria-label="{{ 'alias.create-entity-filter' | translate }}"
+ class="material-icons">
+ add
+ </md-icon>
+ {{ 'alias.create-entity-filter' | translate }}
+ </md-button>
+ </div>
</section>
<section class="tb-filter-switch" layout="column" layout-align="center center">
- <label class="tb-small filter-label" translate>entity.use-entity-name-filter</label>
- <md-switch class="filter-switch" ng-model="model.useFilter" aria-label="use-filter-switcher">
+ <label class="tb-small filter-label" translate>alias.resolve-multiple</label>
+ <md-switch class="filter-switch" ng-model="model.resolveMultiple" aria-label="resolve-multiple-switcher">
</md-switch>
</section>
</section>
<div class="tb-error-messages" ng-messages="ngModelCtrl.$error" role="alert">
- <div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div>
+ <div translate ng-message="filter" class="tb-error-message">alias.entity-filter-required</div>
+ <!--div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div>
<div translate ng-message="entityNameFilter" class="tb-error-message">entity.entity-name-filter-required</div>
<div translate translate-values='{ entity: model.entityNameFilter }' ng-message="entityNameFilterEntityMatch"
- class="tb-error-message">entity.entity-name-filter-no-entity-matched</div>
+ class="tb-error-message">entity.entity-name-filter-no-entity-matched</div-->
</div>
</section>
\ No newline at end of file
ui/src/app/entity/entity-filter-dialog.controller.js 104(+104 -0)
diff --git a/ui/src/app/entity/entity-filter-dialog.controller.js b/ui/src/app/entity/entity-filter-dialog.controller.js
new file mode 100644
index 0000000..2b1a30d
--- /dev/null
+++ b/ui/src/app/entity/entity-filter-dialog.controller.js
@@ -0,0 +1,104 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*@ngInject*/
+export default function EntityFilterDialogController($scope, $mdDialog, $q, entityService, types, isAdd, allowedEntityTypes, filter) {
+
+ var vm = this;
+
+ vm.types = types;
+ vm.isAdd = isAdd;
+ vm.allowedEntityTypes = allowedEntityTypes;
+ vm.filter = filter;
+
+ vm.cancel = cancel;
+ vm.save = save;
+
+ $scope.$watch('vm.filter.type', function (newType, prevType) {
+ if (newType && newType != prevType) {
+ updateFilter();
+ }
+ });
+
+ $scope.$watch('theForm.$pristine', function() {
+ if ($scope.theForm && !$scope.theForm.$pristine) {
+ $scope.theForm.$setValidity('entityFilter', true);
+ }
+ });
+
+ function updateFilter() {
+ var filter = {};
+ filter.type = vm.filter.type;
+ filter.resolveMultiple = vm.filter.resolveMultiple;
+ switch (filter.type) {
+ case types.aliasFilterType.entityList.value:
+ filter.entityType = null;
+ filter.entityList = [];
+ filter.stateEntity = false;
+ break;
+ case types.aliasFilterType.entityName.value:
+ filter.entityType = null;
+ filter.entityNameFilter = '';
+ break;
+ //TODO:
+ }
+ vm.filter = filter;
+ }
+
+ function validate() {
+ var deferred = $q.defer();
+ var validationResult = {
+ entity: null,
+ stateEntity: false
+ }
+ entityService.resolveAliasFilter(vm.filter).then(
+ function success(result) {
+ validationResult.stateEntity = result.stateEntity;
+ var entities = result.entities;
+ if (entities.length) {
+ validationResult.entity = entities[0];
+ }
+ deferred.resolve(validationResult);
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ return deferred.promise;
+ }
+
+ function cancel() {
+ $mdDialog.cancel();
+ }
+
+ function save() {
+ $scope.theForm.$setPristine();
+ validate().then(
+ function success(validationResult) {
+ $mdDialog.hide({
+ filter: vm.filter,
+ entity: validationResult.entity,
+ stateEntity: validationResult.stateEntity
+ });
+ },
+ function fail() {
+ $scope.theForm.$setValidity('entityFilter', false);
+ }
+ )
+ }
+
+}
+
ui/src/app/entity/entity-filter-dialog.tpl.html 100(+100 -0)
diff --git a/ui/src/app/entity/entity-filter-dialog.tpl.html b/ui/src/app/entity/entity-filter-dialog.tpl.html
new file mode 100644
index 0000000..4343b39
--- /dev/null
+++ b/ui/src/app/entity/entity-filter-dialog.tpl.html
@@ -0,0 +1,100 @@
+<!--
+
+ Copyright © 2016-2017 The Thingsboard Authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<md-dialog class="tb-entity-filter-dialog" style="width: 600px;" aria-label="{{ 'alias.entity-filter' | translate }}">
+ <form name="theForm" ng-submit="vm.save()">
+ <md-toolbar>
+ <div class="md-toolbar-tools">
+ <h2>{{ (vm.isAdd ? 'alias.create-entity-filter' : 'alias.edit-entity-filter') | translate }}</h2>
+ <span flex></span>
+ <md-button class="md-icon-button" ng-click="vm.cancel()">
+ <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>
+ </md-button>
+ </div>
+ </md-toolbar>
+ <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!loading" ng-show="loading"></md-progress-linear>
+ <span style="min-height: 5px;" flex="" ng-show="!loading"></span>
+ <md-dialog-content>
+ <div class="md-dialog-content">
+ <fieldset ng-disabled="loading">
+ <div flex layout="column">
+ <md-input-container>
+ <label>{{ 'alias.filter-type' | translate }}</label>
+ <md-select required name="filterType"
+ ng-model="vm.filter.type" aria-label="{{ 'alias.filter-type' | translate }}">
+ <md-option ng-repeat="type in vm.types.aliasFilterType" ng-value="type.value">
+ {{type.name | translate}}
+ </md-option>
+ </md-select>
+ <div ng-messages="theForm.filterType.$error">
+ <div ng-message="required" translate>alias.filter-type-required</div>
+ </div>
+ </md-input-container>
+ <section layout="column" ng-if="vm.filter.type == vm.types.aliasFilterType.entityList.value" id="entityListFilter">
+ <md-checkbox flex aria-label="{{ 'alias.use-state-entity' | translate }}"
+ ng-model="vm.filter.stateEntity">{{ 'alias.use-state-entity' | translate }}
+ </md-checkbox>
+ <tb-entity-type-select
+ ng-if="!vm.filter.stateEntity"
+ ng-model="vm.filter.entityType"
+ the-form="theForm"
+ ng-disabled="vm.filter.stateEntity"
+ tb-required="!vm.filter.stateEntity"
+ allowed-entity-types="vm.allowedEntityTypes">
+ </tb-entity-type-select>
+ <tb-entity-list
+ ng-if="!vm.filter.stateEntity"
+ ng-model="vm.filter.entityList"
+ ng-disabled="vm.filter.stateEntity"
+ tb-required="!vm.filter.stateEntity"
+ entity-type="vm.filter.entityType">
+ </tb-entity-list>
+ </section>
+ <section flex layout="column" ng-if="vm.filter.type == vm.types.aliasFilterType.entityName.value" id="entityNameFilter">
+ <tb-entity-type-select
+ ng-model="vm.filter.entityType"
+ the-form="theForm"
+ tb-required="true"
+ allowed-entity-types="vm.allowedEntityTypes">
+ </tb-entity-type-select>
+ <md-input-container flex>
+ <label translate>entity.name-starts-with</label>
+ <input required name="entityNameFilter"
+ ng-model="vm.filter.entityNameFilter"
+ aria-label="{{ 'entity.name-starts-with' | translate }}">
+ <div ng-messages="theForm.entityNameFilter.$error">
+ <div ng-message="required" translate>entity.entity-name-filter-required</div>
+ </div>
+
+ </md-input-container>
+ </section>
+ <div class="tb-error-messages" ng-messages="theForm.$error" role="alert">
+ <div translate ng-message="entityFilter" class="tb-error-message">alias.entity-filter-no-entity-matched</div>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ </md-dialog-content>
+ <md-dialog-actions layout="row">
+ <span flex></span>
+ <md-button ng-disabled="loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">
+ {{ 'action.save' | translate }}
+ </md-button>
+ <md-button ng-disabled="loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>
+ </md-dialog-actions>
+ </form>
+</md-dialog>
\ No newline at end of file
ui/src/app/entity/entity-list.directive.js 130(+130 -0)
diff --git a/ui/src/app/entity/entity-list.directive.js b/ui/src/app/entity/entity-list.directive.js
new file mode 100644
index 0000000..0863153
--- /dev/null
+++ b/ui/src/app/entity/entity-list.directive.js
@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* eslint-disable import/no-unresolved, import/default */
+
+import entityListTemplate from './entity-list.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+import './entity-list.scss';
+
+/*@ngInject*/
+export default function EntityListDirective($compile, $templateCache, $q, $mdUtil, entityService) {
+
+ var linker = function (scope, element, attrs, ngModelCtrl) {
+
+ var template = $templateCache.get(entityListTemplate);
+ element.html(template);
+
+ scope.ngModelCtrl = ngModelCtrl;
+
+ scope.$watch('tbRequired', function () {
+ scope.updateValidity();
+ });
+
+ scope.fetchEntities = function(searchText, limit) {
+ var deferred = $q.defer();
+ entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit).then(
+ function success(result) {
+ if (result) {
+ deferred.resolve(result);
+ } else {
+ deferred.resolve([]);
+ }
+ },
+ function fail() {
+ deferred.reject();
+ }
+ );
+ return deferred.promise;
+ }
+
+ scope.updateValidity = function() {
+ var value = ngModelCtrl.$viewValue;
+ var valid = !scope.tbRequired || value && value.length > 0;
+ ngModelCtrl.$setValidity('entityList', valid);
+ }
+
+ ngModelCtrl.$render = function () {
+ destroyWatchers();
+ var value = ngModelCtrl.$viewValue;
+ scope.entityList = [];
+ if (value && value.length > 0) {
+ entityService.getEntities(scope.entityType, value).then(function (entities) {
+ scope.entityList = entities;
+ initWatchers();
+ });
+ } else {
+ initWatchers();
+ }
+ }
+
+ function initWatchers() {
+ scope.entityTypeDeregistration = scope.$watch('entityType', function (newEntityType, prevEntityType) {
+ if (!angular.equals(newEntityType, prevEntityType)) {
+ scope.entityList = [];
+ }
+ });
+ scope.entityListDeregistration = scope.$watch('entityList', function () {
+ var ids = [];
+ if (scope.entityList && scope.entityList.length > 0) {
+ for (var i=0;i<scope.entityList.length;i++) {
+ ids.push(scope.entityList[i].id.id);
+ }
+ }
+ var value = ngModelCtrl.$viewValue;
+ if (!angular.equals(ids, value)) {
+ ngModelCtrl.$setViewValue(ids);
+ }
+ scope.updateValidity();
+ }, true);
+ }
+
+ function destroyWatchers() {
+ if (scope.entityTypeDeregistration) {
+ scope.entityTypeDeregistration();
+ scope.entityTypeDeregistration = null;
+ }
+ if (scope.entityListDeregistration) {
+ scope.entityListDeregistration();
+ scope.entityListDeregistration = null;
+ }
+ }
+
+ $compile(element.contents())(scope);
+
+ $mdUtil.nextTick(function(){
+ var inputElement = angular.element('input', element);
+ inputElement.on('blur', function() {
+ scope.inputTouched = true;
+ } );
+ });
+
+ }
+
+ return {
+ restrict: "E",
+ require: "^ngModel",
+ link: linker,
+ scope: {
+ disabled:'=ngDisabled',
+ tbRequired: '=?',
+ entityType: '='
+ }
+ };
+
+}
ui/src/app/entity/entity-list.scss 30(+30 -0)
diff --git a/ui/src/app/entity/entity-list.scss b/ui/src/app/entity/entity-list.scss
new file mode 100644
index 0000000..437e292
--- /dev/null
+++ b/ui/src/app/entity/entity-list.scss
@@ -0,0 +1,30 @@
+/**
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*.tb-entity-list {
+ #entity_list_chips {
+ .md-chips {
+ padding-bottom: 1px;
+ }
+ }
+ .tb-error-messages {
+ margin-top: -11px;
+ height: 35px;
+ .tb-error-message {
+ padding-left: 1px;
+ }
+ }
+}*/
\ No newline at end of file
ui/src/app/entity/entity-list.tpl.html 52(+52 -0)
diff --git a/ui/src/app/entity/entity-list.tpl.html b/ui/src/app/entity/entity-list.tpl.html
new file mode 100644
index 0000000..6bbb920
--- /dev/null
+++ b/ui/src/app/entity/entity-list.tpl.html
@@ -0,0 +1,52 @@
+<!--
+
+ Copyright © 2016-2017 The Thingsboard Authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<section flex layout='column' class="tb-entity-list">
+ <md-chips flex
+ readonly="disabled"
+ id="entity_list_chips"
+ ng-required="tbRequired"
+ ng-model="entityList"
+ md-autocomplete-snap
+ md-require-match="true">
+ <md-autocomplete
+ md-no-cache="true"
+ id="entity"
+ md-selected-item="selectedEntity"
+ md-search-text="entitySearchText"
+ md-items="item in fetchEntities(entitySearchText, 10)"
+ md-item-text="item.name"
+ md-min-length="0"
+ placeholder="{{ 'entity.entity-list' | translate }}">
+ <md-item-template>
+ <span md-highlight-text="entitySearchText" md-highlight-flags="^i">{{item.name}}</span>
+ </md-item-template>
+ <md-not-found>
+ <span translate translate-values='{ entity: entitySearchText }'>entity.no-entities-matching</span>
+ </md-not-found>
+ </md-autocomplete>
+ <md-chip-template>
+ <span>
+ <strong>{{$chip.name}}</strong>
+ </span>
+ </md-chip-template>
+ </md-chips>
+ <div class="tb-error-messages" ng-messages="ngModelCtrl.$error" ng-if="inputTouched" role="alert">
+ <div translate ng-message="entityList" class="tb-error-message">entity.entity-list-empty</div>
+ </div>
+</section>
\ No newline at end of file
ui/src/app/entity/index.js 2(+2 -0)
diff --git a/ui/src/app/entity/index.js b/ui/src/app/entity/index.js
index e8cc437..6be118f 100644
--- a/ui/src/app/entity/index.js
+++ b/ui/src/app/entity/index.js
@@ -19,6 +19,7 @@ import EntityTypeSelectDirective from './entity-type-select.directive';
import EntitySubtypeSelectDirective from './entity-subtype-select.directive';
import EntitySubtypeAutocompleteDirective from './entity-subtype-autocomplete.directive';
import EntityAutocompleteDirective from './entity-autocomplete.directive';
+import EntityListDirective from './entity-list.directive';
import EntitySelectDirective from './entity-select.directive';
import EntityFilterDirective from './entity-filter.directive';
import AliasesEntitySelectPanelController from './aliases-entity-select-panel.controller';
@@ -38,6 +39,7 @@ export default angular.module('thingsboard.entity', [])
.directive('tbEntitySubtypeSelect', EntitySubtypeSelectDirective)
.directive('tbEntitySubtypeAutocomplete', EntitySubtypeAutocompleteDirective)
.directive('tbEntityAutocomplete', EntityAutocompleteDirective)
+ .directive('tbEntityList', EntityListDirective)
.directive('tbEntitySelect', EntitySelectDirective)
.directive('tbEntityFilter', EntityFilterDirective)
.directive('tbAliasesEntitySelect', AliasesEntitySelectDirective)
ui/src/app/locale/locale.constant.js 19(+19 -0)
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index fcde13c..a23845e 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -112,6 +112,25 @@ export default angular.module('thingsboard.locale', [])
"no-alarms-matching": "No alarms matching '{{entity}}' were found.",
"alarm-required": "Alarm is required"
},
+ "alias": {
+ "filter-type-entity-list": "Entity list",
+ "filter-type-entity-name": "Entity name",
+ "filter-type-asset-type": "Asset type",
+ "filter-type-device-type": "Device type",
+ "filter-type-relations-query": "Relations query",
+ "filter-type-asset-search-query": "Asset search query",
+ "filter-type-device-search-query": "Device search query",
+ "entity-filter": "Entity filter",
+ "create-entity-filter": "Create entity filter",
+ "edit-entity-filter": "Edit entity filter",
+ "entity-filter-required": "Entity filter is required.",
+ "resolve-multiple": "Multiple",
+ "filter-type": "Filter type",
+ "filter-type-required": "Filter type is required.",
+ "use-state-entity": "Use state entity",
+ "state-entity": "State entity",
+ "entity-filter-no-entity-matched": "No entities matching specified filter were found.",
+ },
"asset": {
"asset": "Asset",
"assets": "Assets",
diff --git a/ui/src/app/services/item-buffer.service.js b/ui/src/app/services/item-buffer.service.js
index afb63bf..3aa4809 100644
--- a/ui/src/app/services/item-buffer.service.js
+++ b/ui/src/app/services/item-buffer.service.js
@@ -264,14 +264,9 @@ function ItemBuffer($q, bufferStore, types, utils, dashboardUtils) {
}
dashboardUtils.addWidgetToLayout(theDashboard, targetState, targetLayout, widget, originalColumns, originalSize, row, column);
if (callAliasUpdateFunction) {
- onAliasesUpdateFunction().then(
- function() {
- deferred.resolve(theDashboard);
- }
- );
- } else {
- deferred.resolve(theDashboard);
+ onAliasesUpdateFunction();
}
+ deferred.resolve(theDashboard);
return deferred.promise;
}