Entity Admin widgets. Introduce updateAliases method of alias controller.

This commit is contained in:
Igor Kulikov 2020-02-27 17:06:32 +02:00
parent 1d960b96bc
commit 1157df05e9
12 changed files with 73 additions and 43 deletions

File diff suppressed because one or more lines are too long

View File

@ -95,6 +95,7 @@ public abstract class AbstractAssetEntity<T extends Asset> extends BaseSqlEntity
this.customerId = assetEntity.getCustomerId();
this.type = assetEntity.getType();
this.name = assetEntity.getName();
this.label = assetEntity.getLabel();
this.searchText = assetEntity.getSearchText();
this.additionalInfo = assetEntity.getAdditionalInfo();
}

View File

@ -26,7 +26,7 @@ import { map } from 'rxjs/operators';
export class AliasController implements IAliasController {
private entityAliasesChangedSubject = new Subject<Array<string>>();
entityAliasesChangedSubject = new Subject<Array<string>>();
entityAliasesChanged: Observable<Array<string>> = this.entityAliasesChangedSubject.asObservable();
private entityAliasResolvedSubject = new Subject<string>();
@ -69,6 +69,23 @@ export class AliasController implements IAliasController {
}
}
updateAliases(aliasIds?: Array<string>) {
if (!aliasIds) {
aliasIds = [];
for (const aliasId of Object.keys(this.resolvedAliases)) {
aliasIds.push(aliasId);
}
}
const tasks: Observable<AliasInfo>[] = [];
for (const aliasId of aliasIds) {
this.setAliasUnresolved(aliasId);
tasks.push(this.getAliasInfo(aliasId));
}
forkJoin(tasks).subscribe(() => {
this.entityAliasesChangedSubject.next(aliasIds);
});
}
dashboardStateChanged() {
const changedAliasIds: Array<string> = [];
for (const aliasId of Object.keys(this.resolvedAliasesToStateEntities)) {
@ -85,7 +102,7 @@ export class AliasController implements IAliasController {
}
}
private setAliasUnresolved(aliasId: string) {
setAliasUnresolved(aliasId: string) {
delete this.resolvedAliases[aliasId];
delete this.resolvedAliasesObservable[aliasId];
delete this.resolvedAliasesToStateEntities[aliasId];
@ -225,7 +242,7 @@ export class AliasController implements IAliasController {
resolveAlarmSource(alarmSource: Datasource): Observable<Datasource> {
return this.resolveDatasource(alarmSource, true).pipe(
map((datasources) => {
const datasource = datasources[0];
const datasource = datasources && datasources.length ? datasources[0] : deepClone(alarmSource);
if (datasource.type === DatasourceType.function) {
let name: string;
if (datasource.name && datasource.name.length) {

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Observable } from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { EntityId } from '@app/shared/models/id/entity-id';
import {
DataSet,
@ -99,6 +99,7 @@ export interface IAliasController {
getEntityAliases(): EntityAliases;
updateCurrentAliasEntity(aliasId: string, currentEntity: EntityInfo);
updateEntityAliases(entityAliases: EntityAliases);
updateAliases(aliasIds?: Array<string>);
dashboardStateChanged();
}
@ -218,6 +219,7 @@ export interface SubscriptionEntityInfo {
export interface IWidgetSubscription {
options: WidgetSubscriptionOptions;
id: string;
init$: Observable<IWidgetSubscription>;
ctx: WidgetSubscriptionContext;

View File

@ -127,7 +127,7 @@ export class WidgetSubscription implements IWidgetSubscription {
targetDeviceName: string;
executingSubjects: Array<Subject<any>>;
constructor(subscriptionContext: WidgetSubscriptionContext, options: WidgetSubscriptionOptions) {
constructor(subscriptionContext: WidgetSubscriptionContext, public options: WidgetSubscriptionOptions) {
const subscriptionSubject = new ReplaySubject<IWidgetSubscription>();
this.init$ = subscriptionSubject.asObservable();
this.ctx = subscriptionContext;
@ -878,8 +878,8 @@ export class WidgetSubscription implements IWidgetSubscription {
}
private checkAlarmSource(aliasIds: Array<string>): boolean {
if (this.alarmSource && this.alarmSource.entityAliasId) {
return aliasIds.indexOf(this.alarmSource.entityAliasId) > -1;
if (this.options.alarmSource && this.options.alarmSource.entityAliasId) {
return aliasIds.indexOf(this.options.alarmSource.entityAliasId) > -1;
} else {
return false;
}
@ -887,11 +887,14 @@ export class WidgetSubscription implements IWidgetSubscription {
private checkSubscriptions(aliasIds: Array<string>): boolean {
let subscriptionsChanged = false;
for (const listener of this.datasourceListeners) {
if (listener.datasource.entityAliasId) {
if (aliasIds.indexOf(listener.datasource.entityAliasId) > -1) {
subscriptionsChanged = true;
break;
const datasources = this.options.datasources;
if (datasources) {
for (const datasource of datasources) {
if (datasource.entityAliasId) {
if (aliasIds.indexOf(datasource.entityAliasId) > -1) {
subscriptionsChanged = true;
break;
}
}
}
}

View File

@ -20,6 +20,7 @@ import { forkJoin, Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { EntityId } from '@shared/models/id/entity-id';
import { AttributeData, AttributeScope } from '@shared/models/telemetry/telemetry.models';
import { isDefinedAndNotNull } from '@core/utils';
@Injectable({
providedIn: 'root'
@ -31,10 +32,12 @@ export class AttributeService {
) { }
public getEntityAttributes(entityId: EntityId, attributeScope: AttributeScope,
config?: RequestConfig): Observable<Array<AttributeData>> {
return this.http.get<Array<AttributeData>>(`/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/values/attributes/` +
`${attributeScope}`,
defaultHttpOptionsFromConfig(config));
keys?: Array<string>, config?: RequestConfig): Observable<Array<AttributeData>> {
let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/values/attributes/${attributeScope}`;
if (keys && keys.length) {
url += `?keys=${keys.join(',')}`;
}
return this.http.get<Array<AttributeData>>(url, defaultHttpOptionsFromConfig(config));
}
public deleteEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, attributes: Array<AttributeData>,
@ -58,7 +61,7 @@ export class AttributeService {
const attributesData: {[key: string]: any} = {};
const deleteAttributes: AttributeData[] = [];
attributes.forEach((attribute) => {
if (attribute.value !== null) {
if (isDefinedAndNotNull(attribute.value)) {
attributesData[attribute.key] = attribute.value;
} else {
deleteAttributes.push(attribute);
@ -85,7 +88,7 @@ export class AttributeService {
const timeseriesData: {[key: string]: any} = {};
const deleteTimeseries: AttributeData[] = [];
timeseries.forEach((attribute) => {
if (attribute.value !== null) {
if (isDefinedAndNotNull(attribute.value)) {
timeseriesData[attribute.key] = attribute.value;
} else {
deleteTimeseries.push(attribute);

View File

@ -109,15 +109,20 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl
}
private validate(): boolean {
for (const resource of this.action.customResources) {
if (!resource.url) {
return false;
if (this.action.customResources) {
for (const resource of this.action.customResources) {
if (!resource.url) {
return false;
}
}
}
return true;
}
public addResource() {
if (!this.action.customResources) {
this.action.customResources = [];
}
this.action.customResources.push({url: ''});
this.notifyActionUpdated();
}

View File

@ -28,7 +28,7 @@ import { PageLink } from '@shared/models/page/page-link';
import { catchError, map, publishReplay, refCount, share, take, tap } from 'rxjs/operators';
import { entityTypeTranslations } from '@shared/models/entity-type.models';
import { UtilsService } from '@core/services/utils.service';
import { deepClone, isUndefined } from '@core/utils';
import { deepClone, isDefined, isUndefined } from '@core/utils';
import customSampleJs from '!raw-loader!./custom-sample-js.raw';
import customSampleCss from '!raw-loader!./custom-sample-css.raw';
@ -72,7 +72,7 @@ export function toCustomAction(action: WidgetActionDescriptorInfo): CustomAction
customFunction: action.customFunction
};
}
result.customResources = action ? deepClone(action.customResources) : [];
result.customResources = action && isDefined(action.customResources) ? deepClone(action.customResources) : [];
return result;
}

View File

@ -102,8 +102,4 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid
}));
}
widgetForceReInit() {
this.ctx.widgetForceReInit();
}
}

View File

@ -304,7 +304,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
const dataKeys: Array<DataKey> = [];
const datasource = this.subscription.datasources[0];
const datasource = this.subscription.options.datasources ? this.subscription.options.datasources[0] : null;
if (datasource) {
datasource.dataKeys.forEach((entityDataKey) => {

View File

@ -263,7 +263,6 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
this.widgetContext.servicesMap = ServicesMap;
this.widgetContext.isEdit = this.isEdit;
this.widgetContext.isMobile = this.isMobile;
this.widgetContext.widgetForceReInit = this.reInit.bind(this);
this.widgetContext.subscriptionApi = {
createSubscription: this.createSubscription.bind(this),
@ -1096,7 +1095,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
this.cssParser.createStyleElement(actionNamespace, customCss, 'nonamespace');
}
const resourceTasks: Observable<string>[] = [];
if (customResources.length > 0) {
if (isDefined(customResources) && customResources.length > 0) {
customResources.forEach((resource) => {
resourceTasks.push(
this.resources.loadResource(resource.url).pipe(

View File

@ -14,7 +14,6 @@
/// limitations under the License.
///
import { ExceptionData } from '@shared/models/error.models';
import { IDashboardComponent } from '@home/models/dashboard-component.models';
import {
DataSet,
@ -51,7 +50,7 @@ import { AssetService } from '@app/core/http/asset.service';
import { DialogService } from '@core/services/dialog.service';
import { CustomDialogService } from '@home/components/widget/dialog/custom-dialog.service';
import { isDefined, formatValue } from '@core/utils';
import { Observable, of, ReplaySubject } from 'rxjs';
import { forkJoin, Observable, of, ReplaySubject } from 'rxjs';
import { WidgetSubscription } from '@core/api/widget-subscription';
export interface IWidgetAction {
@ -161,8 +160,6 @@ export class WidgetContext {
isEdit: boolean;
isMobile: boolean;
widgetForceReInit?: () => void;
widgetNamespace?: string;
subscriptionApi?: WidgetSubscriptionApi;
@ -187,6 +184,11 @@ export class WidgetContext {
ngZone?: NgZone;
rxjs = {
forkJoin,
of
};
detectChanges(updateWidgetParams: boolean = false) {
if (!this.destroyed) {
if (updateWidgetParams) {
@ -208,11 +210,14 @@ export class WidgetContext {
}
}
updateAliases(aliasIds?: Array<string>) {
this.aliasController.updateAliases(aliasIds);
}
reset() {
this.destroyed = false;
this.hideTitlePanel = false;
this.widgetTitle = undefined;
this.customHeaderActions = undefined;
this.widgetActions = undefined;
}
}
@ -226,7 +231,6 @@ export interface IDynamicWidgetComponent {
rpcErrorText: string;
rpcRejection: HttpErrorResponse;
raf: RafService;
widgetForceReInit(): void;
[key: string]: any;
}