thingsboard/ui-ngx/src/app/core/api/alias-controller.ts

328 lines
12 KiB
TypeScript
Raw Normal View History

2019-09-10 15:12:10 +03:00
///
2020-02-20 10:26:43 +02:00
/// Copyright © 2016-2020 The Thingsboard Authors
2019-09-10 15:12:10 +03:00
///
/// 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.
///
import { AliasInfo, IAliasController, StateControllerHolder, StateEntityInfo } from '@core/api/widget-api.models';
import { forkJoin, Observable, of, ReplaySubject, Subject } from 'rxjs';
import { DataKey, Datasource, DatasourceType } from '@app/shared/models/widget.models';
2020-02-26 18:15:04 +02:00
import { deepClone, isEqual } from '@core/utils';
import { EntityService } from '@core/http/entity.service';
import { UtilsService } from '@core/services/utils.service';
import { EntityAliases } from '@shared/models/alias.models';
import { EntityInfo } from '@shared/models/entity.models';
import { map } from 'rxjs/operators';
export class AliasController implements IAliasController {
private entityAliasesChangedSubject = new Subject<Array<string>>();
entityAliasesChanged: Observable<Array<string>> = this.entityAliasesChangedSubject.asObservable();
private entityAliasResolvedSubject = new Subject<string>();
entityAliasResolved: Observable<string> = this.entityAliasResolvedSubject.asObservable();
entityAliases: EntityAliases;
resolvedAliases: {[aliasId: string]: AliasInfo} = {};
resolvedAliasesObservable: {[aliasId: string]: Observable<AliasInfo>} = {};
resolvedAliasesToStateEntities: {[aliasId: string]: StateEntityInfo} = {};
constructor(private utils: UtilsService,
private entityService: EntityService,
private stateControllerHolder: StateControllerHolder,
private origEntityAliases: EntityAliases) {
this.entityAliases = deepClone(this.origEntityAliases);
}
updateEntityAliases(newEntityAliases: EntityAliases) {
const changedAliasIds: Array<string> = [];
for (const aliasId of Object.keys(newEntityAliases)) {
const newEntityAlias = newEntityAliases[aliasId];
const prevEntityAlias = this.entityAliases[aliasId];
2020-02-26 18:15:04 +02:00
if (!isEqual(newEntityAlias, prevEntityAlias)) {
changedAliasIds.push(aliasId);
this.setAliasUnresolved(aliasId);
}
}
for (const aliasId of Object.keys(this.entityAliases)) {
if (!newEntityAliases[aliasId]) {
changedAliasIds.push(aliasId);
this.setAliasUnresolved(aliasId);
}
}
this.entityAliases = deepClone(newEntityAliases);
if (changedAliasIds.length) {
this.entityAliasesChangedSubject.next(changedAliasIds);
}
}
dashboardStateChanged() {
const changedAliasIds: Array<string> = [];
for (const aliasId of Object.keys(this.resolvedAliasesToStateEntities)) {
const stateEntityInfo = this.resolvedAliasesToStateEntities[aliasId];
const newEntityId = this.stateControllerHolder().getEntityId(stateEntityInfo.entityParamName);
const prevEntityId = stateEntityInfo.entityId;
2020-02-26 18:15:04 +02:00
if (!isEqual(newEntityId, prevEntityId)) {
changedAliasIds.push(aliasId);
this.setAliasUnresolved(aliasId);
}
}
if (changedAliasIds.length) {
this.entityAliasesChangedSubject.next(changedAliasIds);
}
}
private setAliasUnresolved(aliasId: string) {
delete this.resolvedAliases[aliasId];
delete this.resolvedAliasesObservable[aliasId];
delete this.resolvedAliasesToStateEntities[aliasId];
}
getEntityAliases(): EntityAliases {
return this.entityAliases;
}
getEntityAliasId(aliasName: string): string {
for (const aliasId of Object.keys(this.entityAliases)) {
const alias = this.entityAliases[aliasId];
if (alias.alias === aliasName) {
return aliasId;
}
}
return null;
}
getAliasInfo(aliasId: string): Observable<AliasInfo> {
const aliasInfo = this.resolvedAliases[aliasId];
if (aliasInfo) {
return of(aliasInfo);
} else if (this.resolvedAliasesObservable[aliasId]) {
return this.resolvedAliasesObservable[aliasId];
} else {
const resolvedAliasSubject = new ReplaySubject<AliasInfo>();
this.resolvedAliasesObservable[aliasId] = resolvedAliasSubject.asObservable();
const entityAlias = this.entityAliases[aliasId];
if (entityAlias) {
this.entityService.resolveAlias(entityAlias, this.stateControllerHolder().getStateParams()).subscribe(
(resolvedAliasInfo) => {
this.resolvedAliases[aliasId] = resolvedAliasInfo;
delete this.resolvedAliasesObservable[aliasId];
if (resolvedAliasInfo.stateEntity) {
const stateEntityInfo: StateEntityInfo = {
entityParamName: resolvedAliasInfo.entityParamName,
entityId: this.stateControllerHolder().getEntityId(resolvedAliasInfo.entityParamName)
};
this.resolvedAliasesToStateEntities[aliasId] = stateEntityInfo;
}
this.entityAliasResolvedSubject.next(aliasId);
resolvedAliasSubject.next(resolvedAliasInfo);
resolvedAliasSubject.complete();
},
() => {
resolvedAliasSubject.error(null);
delete this.resolvedAliasesObservable[aliasId];
}
);
} else {
resolvedAliasSubject.error(null);
const res = this.resolvedAliasesObservable[aliasId];
delete this.resolvedAliasesObservable[aliasId];
return res;
}
return this.resolvedAliasesObservable[aliasId];
}
}
private resolveDatasource(datasource: Datasource, isSingle?: boolean): Observable<Array<Datasource>> {
if (datasource.type === DatasourceType.entity) {
if (datasource.entityAliasId) {
return this.getAliasInfo(datasource.entityAliasId).pipe(
map((aliasInfo) => {
datasource.aliasName = aliasInfo.alias;
if (aliasInfo.resolveMultiple && !isSingle) {
let newDatasource: Datasource;
const resolvedEntities = aliasInfo.resolvedEntities;
if (resolvedEntities && resolvedEntities.length) {
const datasources: Array<Datasource> = [];
for (let i = 0; i < resolvedEntities.length; i++) {
const resolvedEntity = resolvedEntities[i];
newDatasource = deepClone(datasource);
if (resolvedEntity.origEntity) {
newDatasource.entity = deepClone(resolvedEntity.origEntity);
} else {
newDatasource.entity = {};
}
newDatasource.entityId = resolvedEntity.id;
newDatasource.entityType = resolvedEntity.entityType;
newDatasource.entityName = resolvedEntity.name;
newDatasource.entityLabel = resolvedEntity.label;
newDatasource.entityDescription = resolvedEntity.entityDescription;
newDatasource.name = resolvedEntity.name;
newDatasource.generated = i > 0 ? true : false;
datasources.push(newDatasource);
}
return datasources;
} else {
if (aliasInfo.stateEntity) {
newDatasource = deepClone(datasource);
newDatasource.unresolvedStateEntity = true;
return [newDatasource];
} else {
return [];
// throw new Error('Unable to resolve datasource.');
}
}
} else {
const entity = aliasInfo.currentEntity;
if (entity) {
if (entity.origEntity) {
datasource.entity = deepClone(entity.origEntity);
} else {
datasource.entity = {};
}
datasource.entityId = entity.id;
datasource.entityType = entity.entityType;
datasource.entityName = entity.name;
datasource.entityLabel = entity.label;
datasource.name = entity.name;
datasource.entityDescription = entity.entityDescription;
return [datasource];
} else {
if (aliasInfo.stateEntity) {
datasource.unresolvedStateEntity = true;
return [datasource];
} else {
return [];
// throw new Error('Unable to resolve datasource.');
}
}
}
})
);
} else {
datasource.aliasName = datasource.entityName;
datasource.name = datasource.entityName;
return of([datasource]);
}
} else {
return of([datasource]);
}
}
resolveAlarmSource(alarmSource: Datasource): Observable<Datasource> {
return this.resolveDatasource(alarmSource, true).pipe(
map((datasources) => {
const datasource = datasources[0];
if (datasource.type === DatasourceType.function) {
let name: string;
if (datasource.name && datasource.name.length) {
name = datasource.name;
} else {
name = DatasourceType.function;
}
datasource.name = name;
datasource.aliasName = name;
datasource.entityName = name;
} else if (datasource.unresolvedStateEntity) {
datasource.name = 'Unresolved';
datasource.entityName = 'Unresolved';
}
return datasource;
})
);
}
resolveDatasources(datasources: Array<Datasource>): Observable<Array<Datasource>> {
const newDatasources = deepClone(datasources);
const observables = new Array<Observable<Array<Datasource>>>();
newDatasources.forEach((datasource) => {
observables.push(this.resolveDatasource(datasource));
});
return forkJoin(observables).pipe(
map((arrayOfDatasources) => {
const result = new Array<Datasource>();
arrayOfDatasources.forEach((datasourcesArray) => {
result.push(...datasourcesArray);
});
result.sort((d1, d2) => {
const i1 = d1.generated ? 1 : 0;
const i2 = d2.generated ? 1 : 0;
return i1 - i2;
});
let index = 0;
let functionIndex = 0;
result.forEach((datasource) => {
if (datasource.type === DatasourceType.function) {
let name: string;
if (datasource.name && datasource.name.length) {
name = datasource.name;
} else {
functionIndex++;
name = DatasourceType.function;
if (functionIndex > 1) {
name += ' ' + functionIndex;
}
}
datasource.name = name;
datasource.aliasName = name;
datasource.entityName = name;
} else if (datasource.unresolvedStateEntity) {
datasource.name = 'Unresolved';
datasource.entityName = 'Unresolved';
}
datasource.dataKeys.forEach((dataKey) => {
if (datasource.generated) {
dataKey._hash = Math.random();
dataKey.color = this.utils.getMaterialColor(index);
}
index++;
});
this.updateDatasourceKeyLabels(datasource);
});
return result;
})
);
}
private updateDatasourceKeyLabels(datasource: Datasource) {
datasource.dataKeys.forEach((dataKey) => {
this.updateDataKeyLabel(dataKey, datasource);
});
}
private updateDataKeyLabel(dataKey: DataKey, datasource: Datasource) {
if (!dataKey.pattern) {
dataKey.pattern = deepClone(dataKey.label);
}
dataKey.label = this.utils.createLabelFromDatasource(datasource, dataKey.pattern);
}
getInstantAliasInfo(aliasId: string): AliasInfo {
return this.resolvedAliases[aliasId];
}
updateCurrentAliasEntity(aliasId: string, currentEntity: EntityInfo) {
const aliasInfo = this.resolvedAliases[aliasId];
if (aliasInfo) {
const prevCurrentEntity = aliasInfo.currentEntity;
2020-02-26 18:15:04 +02:00
if (!isEqual(currentEntity, prevCurrentEntity)) {
aliasInfo.currentEntity = currentEntity;
this.entityAliasesChangedSubject.next([aliasId]);
}
}
}
2019-09-10 15:12:10 +03:00
}