TB-61: Improve Alias Filter. Miltiple datasources resolution.

This commit is contained in:
Igor Kulikov 2017-06-07 17:09:04 +03:00
parent ae4148d7fa
commit 0c0b3dade4
38 changed files with 1420 additions and 374 deletions

View File

@ -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]);
}
}
}
}

View File

@ -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) {
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();
}
);
} 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();
}
);
}
break;
case types.aliasFilterType.entityName.value:
getEntitiesByNameFilter(filter.entityType, filter.entityNameFilter, 100).then(
function success(entities) {
if (entities && entities.length) {
result.entities = entities;
deferred.resolve(result);
} else {
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 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';
}
index++;
processEntityAlias(index, aliasIds, entityAliases, resolution, deferred);
}
});
} else {
var entityList = entityFilter.entityList;
getEntities(entityAlias.entityType, entityList).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);
} else {
if (!resolution.error) {
resolution.error = 'dashboard.invalid-aliases-config';
}
index++;
processEntityAlias(index, aliasIds, entityAliases, resolution, deferred);
}
},
function fail() {
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);

View File

@ -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;
}
this.callbacks.rpcStateChanged(this);
deferred.resolve();
}
if (this.targetDeviceId) {
this.rpcEnabled = true;
} else {
this.rpcEnabled = this.ctx.$scope.widgetEditMode ? true : false;
}
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) {

View File

@ -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 = {};

View File

@ -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",

View File

@ -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;

View File

@ -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,

View File

@ -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 () {

View File

@ -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: '&',

View File

@ -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>

View File

@ -76,7 +76,7 @@ function Datasource($compile, $templateCache, types) {
restrict: "E",
require: "^ngModel",
scope: {
entityAliases: '=',
aliasController: '=',
widgetType: '=',
functionsOnly: '=',
datakeySettingsSchema: '=',

View File

@ -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})">

View File

@ -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: '&'
}

View File

@ -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: '&',

View File

@ -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})">

View File

@ -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);
createSubscription(options).then(
function success(subscription) {
defaultSubscriptionOptions(subscription, options);
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;

View File

@ -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();
});

View File

@ -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)"

View File

@ -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() {

View File

@ -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">

View File

@ -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: '='

View File

@ -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)"

View File

@ -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"

View File

@ -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 () {
if (onEntityAliasesUpdate) {
onEntityAliasesUpdate(vm.entityAliases);
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);
}
}, true);
}
function currentAliasEntityChanged(aliasId, currentEntity) {
vm.aliasController.updateCurrentAliasEntity(aliasId, currentEntity);
if (onEntityAliasesUpdate) {
onEntityAliasesUpdate();
}
}
}

View File

@ -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>

View File

@ -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
};

View File

@ -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;

View File

@ -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;"

View File

@ -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);
}
)
}
}

View File

@ -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>

View File

@ -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
}
}
)
}
}*/
}
function updateMatchingEntity() {
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 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: '&'
}
};

View File

@ -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>

View File

@ -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: '='
}
};
}

View File

@ -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;
}
}
}*/

View File

@ -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>

View File

@ -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)

View File

@ -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",

View File

@ -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;
}