Browse Source

UI: Add JS modules support to get/set value converters of behavior.

pull/12186/head
Igor Kulikov 2 years ago
parent
commit
290e2faf6a
  1. 118
      ui-ngx/src/app/modules/home/components/widget/lib/action/action-widget.models.ts
  2. 1
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.html
  3. 1
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings-panel.component.html
  4. 3
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts
  5. 5
      ui-ngx/src/app/shared/models/action-widget-settings.models.ts

118
ui-ngx/src/app/modules/home/components/widget/lib/action/action-widget.models.ts

@ -22,7 +22,17 @@ import {
telemetryTypeTranslationsShort
} from '@shared/models/telemetry/telemetry.models';
import { WidgetContext } from '@home/models/widget-component.models';
import { BehaviorSubject, forkJoin, Observable, Observer, of, Subscription, throwError } from 'rxjs';
import {
BehaviorSubject,
forkJoin,
Observable,
Observer,
of,
ReplaySubject,
Subscription,
switchMap,
throwError
} from 'rxjs';
import { catchError, delay, map, share, take } from 'rxjs/operators';
import { AfterViewInit, ChangeDetectorRef, Directive, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import {
@ -45,6 +55,8 @@ import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.m
import { EntityId } from '@shared/models/id/entity-id';
import { isDefinedAndNotNull } from '@core/utils';
import { parseError } from '@shared/models/error.models';
import { CompiledTbFunction, compileTbFunction } from '@shared/models/js-function.models';
import { HttpClient } from '@angular/common/http';
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
@ -163,46 +175,57 @@ type DataToValueFunction<V> = (data: any) => V;
export class DataToValueConverter<V> {
private readonly dataToValueFunction: DataToValueFunction<V>;
private readonly dataToValueFunction$: Observable<CompiledTbFunction<DataToValueFunction<V>>>;
private readonly compareToValue: any;
constructor(private settings: DataToValueSettings,
constructor(private http: HttpClient,
private settings: DataToValueSettings,
private valueType: ValueType) {
this.compareToValue = settings.compareToValue;
switch (settings.type) {
case DataToValueType.FUNCTION:
try {
this.dataToValueFunction = new Function('data', settings.dataToValueFunction) as DataToValueFunction<V>;
} catch (e) {
this.dataToValueFunction = (data) => data;
}
this.dataToValueFunction$ = compileTbFunction(this.http, settings.dataToValueFunction, 'data').pipe(
catchError(() => {
return of(new CompiledTbFunction((data: any) => data, []));
}),
share({
connector: () => new ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: false
})
);
break;
case DataToValueType.NONE:
break;
}
}
dataToValue(data: any): V {
let result: V;
dataToValue(data: any): Observable<V> {
let result: Observable<V>;
switch (this.settings.type) {
case DataToValueType.FUNCTION:
result = data;
try {
let input = data;
if (!!data) {
try {
input = JSON.parse(data);
} catch (_e) {}
}
result = this.dataToValueFunction(input);
} catch (_e) {}
result = this.dataToValueFunction$.pipe(
map((dataToValueFunction) => {
let input = data;
if (!!data) {
try {
input = JSON.parse(data);
} catch (_e) {}
}
return dataToValueFunction.execute(input);
}),
catchError(() => of(data))
);
break;
case DataToValueType.NONE:
result = data;
result = of(data);
break;
}
if (this.valueType === ValueType.BOOLEAN) {
result = (result === this.compareToValue) as any;
result = result.pipe(
map(val => (val === this.compareToValue) as V)
);
}
return result;
}
@ -260,17 +283,17 @@ export abstract class ValueGetter<V> extends ValueAction {
protected simulated: boolean) {
super(ctx, settings);
if (this.settings.action !== GetValueAction.DO_NOTHING && this.settings.action !== GetValueAction.GET_ALARM_STATUS) {
this.dataConverter = new DataToValueConverter<V>(settings.dataToValue, valueType);
this.dataConverter = new DataToValueConverter<V>(ctx.http, settings.dataToValue, valueType);
}
}
getValue(): Observable<V> {
const valueObservable: Observable<V> = this.doGetValue().pipe(
map((data) => {
switchMap((data) => {
if (this.dataConverter) {
return this.dataConverter.dataToValue(data);
} else {
return data;
return of(data);
}
}),
catchError(err => {
@ -308,9 +331,10 @@ type ValueToDataFunction<V> = (value: V) => any;
export class ValueToDataConverter<V> {
private readonly constantValue: any;
private readonly valueToDataFunction: ValueToDataFunction<V>;
private readonly valueToDataFunction$: Observable<CompiledTbFunction<ValueToDataFunction<V>>>;
constructor(protected settings: ValueToDataSettings) {
constructor(private http: HttpClient,
private settings: ValueToDataSettings) {
switch (settings.type) {
case ValueToDataType.VALUE:
break;
@ -318,31 +342,38 @@ export class ValueToDataConverter<V> {
this.constantValue = this.settings.constantValue;
break;
case ValueToDataType.FUNCTION:
try {
this.valueToDataFunction = new Function('value', settings.valueToDataFunction) as ValueToDataFunction<V>;
} catch (e) {
this.valueToDataFunction = (data) => data;
}
this.valueToDataFunction$ = compileTbFunction(this.http, settings.valueToDataFunction, 'value').pipe(
catchError(() => {
return of(new CompiledTbFunction((value: any) => value, []));
}),
share({
connector: () => new ReplaySubject(1),
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: false
})
);
break;
case ValueToDataType.NONE:
break;
}
}
valueToData(value: V): any {
valueToData(value: V): Observable<any> {
switch (this.settings.type) {
case ValueToDataType.VALUE:
return value;
return of(value);
case ValueToDataType.CONSTANT:
return this.constantValue;
return of(this.constantValue);
case ValueToDataType.FUNCTION:
let result = value;
try {
result = this.valueToDataFunction(value);
} catch (e) {}
return result;
return this.valueToDataFunction$.pipe(
map((valueToDataFunction) => {
return valueToDataFunction.execute(value);
}),
catchError(() => of(value))
);
case ValueToDataType.NONE:
return null;
return of(null);
}
}
}
@ -368,14 +399,15 @@ export abstract class ValueSetter<V> extends ValueAction {
protected settings: SetValueSettings,
protected simulated: boolean) {
super(ctx, settings);
this.valueToDataConverter = new ValueToDataConverter<V>(settings.valueToData);
this.valueToDataConverter = new ValueToDataConverter<V>(ctx.http, settings.valueToData);
}
setValue(value: V): Observable<any> {
if (this.simulated) {
return of(null).pipe(delay(500));
} else {
return this.doSetValue(this.valueToDataConverter.valueToData(value)).pipe(
return this.valueToDataConverter.valueToData(value).pipe(
switchMap(data => this.doSetValue(data)),
catchError(err => {
throw this.handleError(err);
})

1
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.html

@ -138,6 +138,7 @@
</div>
<tb-js-func *ngIf="getValueSettingsFormGroup.get('dataToValue').get('type').value === dataToValueType.FUNCTION"
formControlName="dataToValueFunction"
withModules
required
[globalVariables]="functionScopeVariables"
[functionArgs]="['data']"

1
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings-panel.component.html

@ -114,6 +114,7 @@
</tb-value-input>
<tb-js-func *ngIf="setValueSettingsFormGroup.get('valueToData').get('type').value === valueToDataType.FUNCTION"
formControlName="valueToDataFunction"
withModules
required
[globalVariables]="functionScopeVariables"
[functionArgs]="['value']"

3
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts

@ -57,6 +57,7 @@ import {
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-behaviors.component';
import { IAliasController } from '@core/api/widget-api.models';
import { WidgetActionCallbacks } from '@home/components/widget/action/manage-widget-actions.component.models';
import { isNotEmptyTbFunction } from '@shared/models/js-function.models';
export const behaviorValid = (behavior: ScadaSymbolBehavior): boolean => {
if (!behavior.id || !behavior.name || !behavior.type) {
@ -77,7 +78,7 @@ export const behaviorValid = (behavior: ScadaSymbolBehavior): boolean => {
return false;
}
if (behavior.defaultSetValueSettings.valueToData?.type === ValueToDataType.FUNCTION
&& isUndefinedOrNull(behavior.defaultSetValueSettings.valueToData?.valueToDataFunction)) {
&& !isNotEmptyTbFunction(behavior.defaultSetValueSettings.valueToData?.valueToDataFunction)) {
return false;
}
break;

5
ui-ngx/src/app/shared/models/action-widget-settings.models.ts

@ -17,6 +17,7 @@
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
import { widgetType } from '@shared/models/widget.models';
import { AlarmSeverity } from '@shared/models/alarm.models';
import { TbFunction } from '@shared/models/js-function.models';
export enum GetValueAction {
DO_NOTHING = 'DO_NOTHING',
@ -79,7 +80,7 @@ export enum DataToValueType {
export interface DataToValueSettings {
type: DataToValueType;
dataToValueFunction: string;
dataToValueFunction: TbFunction;
compareToValue?: any;
}
@ -131,7 +132,7 @@ export enum ValueToDataType {
export interface ValueToDataSettings {
type: ValueToDataType;
constantValue: any;
valueToDataFunction: string;
valueToDataFunction: TbFunction;
}
export interface SetValueSettings extends ValueActionSettings {

Loading…
Cancel
Save