Merge pull request #12694 from maxunbearable/feature/calculated-fields-arguments-autocomplete
Added Calculated field arguments autocomplete
This commit is contained in:
commit
8568bb93a8
@ -37,9 +37,11 @@ import { CalculatedFieldsService } from '@core/http/calculated-fields.service';
|
|||||||
import { catchError, filter, switchMap, tap } from 'rxjs/operators';
|
import { catchError, filter, switchMap, tap } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
CalculatedField,
|
CalculatedField,
|
||||||
|
CalculatedFieldEventArguments,
|
||||||
CalculatedFieldDebugDialogData,
|
CalculatedFieldDebugDialogData,
|
||||||
CalculatedFieldDialogData,
|
CalculatedFieldDialogData,
|
||||||
CalculatedFieldTestScriptDialogData,
|
CalculatedFieldTestScriptDialogData,
|
||||||
|
getCalculatedFieldArgumentsEditorCompleter,
|
||||||
} from '@shared/models/calculated-field.models';
|
} from '@shared/models/calculated-field.models';
|
||||||
import {
|
import {
|
||||||
CalculatedFieldDebugDialogComponent,
|
CalculatedFieldDebugDialogComponent,
|
||||||
@ -58,7 +60,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
|||||||
readonly tenantId = getCurrentAuthUser(this.store).tenantId;
|
readonly tenantId = getCurrentAuthUser(this.store).tenantId;
|
||||||
additionalDebugActionConfig = {
|
additionalDebugActionConfig = {
|
||||||
title: this.translate.instant('calculated-fields.see-debug-events'),
|
title: this.translate.instant('calculated-fields.see-debug-events'),
|
||||||
action: (calculatedField: CalculatedField) => this.openDebugDialog.call(this, calculatedField),
|
action: (calculatedField: CalculatedField) => this.openDebugEventsDialog.call(this, calculatedField),
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private calculatedFieldsService: CalculatedFieldsService,
|
constructor(private calculatedFieldsService: CalculatedFieldsService,
|
||||||
@ -122,7 +124,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
|||||||
name: this.translate.instant('entity-view.events'),
|
name: this.translate.instant('entity-view.events'),
|
||||||
icon: 'history',
|
icon: 'history',
|
||||||
isEnabled: () => true,
|
isEnabled: () => true,
|
||||||
onAction: (_, entity) => this.openDebugDialog(entity),
|
onAction: (_, entity) => this.openDebugEventsDialog(entity),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '',
|
name: '',
|
||||||
@ -149,7 +151,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
|||||||
const { debugSettings = {}, id } = calculatedField;
|
const { debugSettings = {}, id } = calculatedField;
|
||||||
const additionalActionConfig = {
|
const additionalActionConfig = {
|
||||||
...this.additionalDebugActionConfig,
|
...this.additionalDebugActionConfig,
|
||||||
action: () => this.openDebugDialog(calculatedField)
|
action: () => this.openDebugEventsDialog(calculatedField)
|
||||||
};
|
};
|
||||||
const { viewContainerRef } = this.getTable();
|
const { viewContainerRef } = this.getTable();
|
||||||
if ($event) {
|
if ($event) {
|
||||||
@ -211,14 +213,14 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
|||||||
entityName: this.entityName,
|
entityName: this.entityName,
|
||||||
additionalDebugActionConfig: this.additionalDebugActionConfig,
|
additionalDebugActionConfig: this.additionalDebugActionConfig,
|
||||||
getTestScriptDialogFn: this.getTestScriptDialog.bind(this),
|
getTestScriptDialogFn: this.getTestScriptDialog.bind(this),
|
||||||
isDirty
|
isDirty,
|
||||||
},
|
},
|
||||||
enterAnimationDuration: isDirty ? 0 : null,
|
enterAnimationDuration: isDirty ? 0 : null,
|
||||||
})
|
})
|
||||||
.afterClosed();
|
.afterClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private openDebugDialog(calculatedField: CalculatedField): void {
|
private openDebugEventsDialog(calculatedField: CalculatedField): void {
|
||||||
this.dialog.open<CalculatedFieldDebugDialogComponent, CalculatedFieldDebugDialogData, null>(CalculatedFieldDebugDialogComponent, {
|
this.dialog.open<CalculatedFieldDebugDialogComponent, CalculatedFieldDebugDialogData, null>(CalculatedFieldDebugDialogComponent, {
|
||||||
disableClose: true,
|
disableClose: true,
|
||||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
@ -267,7 +269,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
|||||||
).subscribe(() => this.updateData());
|
).subscribe(() => this.updateData());
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTestScriptDialog(calculatedField: CalculatedField, argumentsObj?: Record<string, unknown>, openCalculatedFieldEdit = true): Observable<string> {
|
private getTestScriptDialog(calculatedField: CalculatedField, argumentsObj?: CalculatedFieldEventArguments, openCalculatedFieldEdit = true): Observable<string> {
|
||||||
const resultArguments = Object.keys(calculatedField.configuration.arguments).reduce((acc, key) => {
|
const resultArguments = Object.keys(calculatedField.configuration.arguments).reduce((acc, key) => {
|
||||||
acc[key] = isObject(argumentsObj) && argumentsObj.hasOwnProperty(key) ? argumentsObj[key] : '';
|
acc[key] = isObject(argumentsObj) && argumentsObj.hasOwnProperty(key) ? argumentsObj[key] : '';
|
||||||
return acc;
|
return acc;
|
||||||
@ -279,6 +281,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
|||||||
data: {
|
data: {
|
||||||
arguments: resultArguments,
|
arguments: resultArguments,
|
||||||
expression: calculatedField.configuration.expression,
|
expression: calculatedField.configuration.expression,
|
||||||
|
argumentsEditorCompleter: getCalculatedFieldArgumentsEditorCompleter(calculatedField.configuration.arguments),
|
||||||
openCalculatedFieldEdit
|
openCalculatedFieldEdit
|
||||||
}
|
}
|
||||||
}).afterClosed()
|
}).afterClosed()
|
||||||
|
|||||||
@ -99,6 +99,7 @@
|
|||||||
[functionArgs]="functionArgs$ | async"
|
[functionArgs]="functionArgs$ | async"
|
||||||
[disableUndefinedCheck]="true"
|
[disableUndefinedCheck]="true"
|
||||||
[scriptLanguage]="ScriptLanguage.TBEL"
|
[scriptLanguage]="ScriptLanguage.TBEL"
|
||||||
|
[editorCompleter]="argumentsEditorCompleter$ | async"
|
||||||
helpId="calculated-field/expression_fn"
|
helpId="calculated-field/expression_fn"
|
||||||
>
|
>
|
||||||
<button toolbarSuffixButton
|
<button toolbarSuffixButton
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import {
|
|||||||
CalculatedFieldDialogData,
|
CalculatedFieldDialogData,
|
||||||
CalculatedFieldType,
|
CalculatedFieldType,
|
||||||
CalculatedFieldTypeTranslations,
|
CalculatedFieldTypeTranslations,
|
||||||
|
getCalculatedFieldArgumentsEditorCompleter,
|
||||||
OutputType,
|
OutputType,
|
||||||
OutputTypeTranslations
|
OutputTypeTranslations
|
||||||
} from '@shared/models/calculated-field.models';
|
} from '@shared/models/calculated-field.models';
|
||||||
@ -66,6 +67,12 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
|
|||||||
map(argumentsObj => Object.keys(argumentsObj))
|
map(argumentsObj => Object.keys(argumentsObj))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
argumentsEditorCompleter$ = this.configFormGroup.get('arguments').valueChanges
|
||||||
|
.pipe(
|
||||||
|
startWith(this.data.value?.configuration?.arguments ?? {}),
|
||||||
|
map(argumentsObj => getCalculatedFieldArgumentsEditorCompleter(argumentsObj))
|
||||||
|
);
|
||||||
|
|
||||||
additionalDebugActionConfig = this.data.value?.id ? {
|
additionalDebugActionConfig = this.data.value?.id ? {
|
||||||
...this.data.additionalDebugActionConfig,
|
...this.data.additionalDebugActionConfig,
|
||||||
action: () => this.data.additionalDebugActionConfig.action({ id: this.data.value.id, ...this.fromGroupValue }),
|
action: () => this.data.additionalDebugActionConfig.action({ id: this.data.value.id, ...this.fromGroupValue }),
|
||||||
|
|||||||
@ -40,6 +40,7 @@
|
|||||||
[disableUndefinedCheck]="true"
|
[disableUndefinedCheck]="true"
|
||||||
[fillHeight]="true"
|
[fillHeight]="true"
|
||||||
[scriptLanguage]="ScriptLanguage.TBEL"
|
[scriptLanguage]="ScriptLanguage.TBEL"
|
||||||
|
[editorCompleter]="data.argumentsEditorCompleter"
|
||||||
resultType="object"
|
resultType="object"
|
||||||
helpId="calculated-field/test-expression_fn"
|
helpId="calculated-field/test-expression_fn"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -184,6 +184,9 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal
|
|||||||
this.updateFunctionArgsString();
|
this.updateFunctionArgsString();
|
||||||
this.updateFunctionLabel();
|
this.updateFunctionLabel();
|
||||||
}
|
}
|
||||||
|
if (changes.editorCompleter) {
|
||||||
|
this.updateCompleters();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
|
|||||||
import { EntityType } from '@shared/models/entity-type.models';
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
import { AliasFilterType } from '@shared/models/alias.models';
|
import { AliasFilterType } from '@shared/models/alias.models';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
import { TbEditorCompleter } from '@shared/models/ace/completion.models';
|
||||||
|
|
||||||
export interface CalculatedField extends Omit<BaseData<CalculatedFieldId>, 'label'>, HasVersion, HasTenantId, ExportableEntity<CalculatedFieldId> {
|
export interface CalculatedField extends Omit<BaseData<CalculatedFieldId>, 'label'>, HasVersion, HasTenantId, ExportableEntity<CalculatedFieldId> {
|
||||||
debugSettings?: EntityDebugSettings;
|
debugSettings?: EntityDebugSettings;
|
||||||
@ -153,6 +154,7 @@ export interface CalculatedFieldTestScriptInputParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CalculatedFieldTestScriptDialogData extends CalculatedFieldTestScriptInputParams {
|
export interface CalculatedFieldTestScriptDialogData extends CalculatedFieldTestScriptInputParams {
|
||||||
|
argumentsEditorCompleter: TbEditorCompleter
|
||||||
openCalculatedFieldEdit?: boolean;
|
openCalculatedFieldEdit?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,3 +188,112 @@ export const getCalculatedFieldCurrentEntityFilter = (entityName: string, entity
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CalculatedFieldAttributeArgumentValue<ValueType = unknown> {
|
||||||
|
ts: number;
|
||||||
|
value: ValueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalculatedFieldLatestTelemetryArgumentValue<ValueType = unknown> {
|
||||||
|
ts: number;
|
||||||
|
value: ValueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalculatedFieldRollingTelemetryArgumentValue<ValueType = unknown> {
|
||||||
|
timewindow: { startTs: number; endTs: number; limit: number };
|
||||||
|
values: CalculatedFieldSingleArgumentValue<ValueType>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CalculatedFieldSingleArgumentValue<ValueType = unknown> = CalculatedFieldAttributeArgumentValue<ValueType> & CalculatedFieldLatestTelemetryArgumentValue<ValueType>;
|
||||||
|
|
||||||
|
export type CalculatedFieldArgumentEventValue<ValueType = unknown> = CalculatedFieldAttributeArgumentValue<ValueType> | CalculatedFieldLatestTelemetryArgumentValue<ValueType> | CalculatedFieldRollingTelemetryArgumentValue<ValueType>;
|
||||||
|
|
||||||
|
export type CalculatedFieldEventArguments<ValueType = unknown> = Record<string, CalculatedFieldArgumentEventValue<ValueType>>;
|
||||||
|
|
||||||
|
export const CalculatedFieldLatestTelemetryArgumentAutocomplete = {
|
||||||
|
meta: 'object',
|
||||||
|
type: '{ ts: number; value: any; }',
|
||||||
|
description: 'Calculated field latest telemetry value argument.',
|
||||||
|
children: {
|
||||||
|
ts: {
|
||||||
|
meta: 'number',
|
||||||
|
type: 'number',
|
||||||
|
description: 'Time stamp',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
meta: 'any',
|
||||||
|
type: 'any',
|
||||||
|
description: 'Value',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CalculatedFieldAttributeValueArgumentAutocomplete = {
|
||||||
|
meta: 'object',
|
||||||
|
type: '{ ts: number; value: any; }',
|
||||||
|
description: 'Calculated field attribute value argument.',
|
||||||
|
children: {
|
||||||
|
ts: {
|
||||||
|
meta: 'number',
|
||||||
|
type: 'number',
|
||||||
|
description: 'Time stamp',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
meta: 'any',
|
||||||
|
type: 'any',
|
||||||
|
description: 'Value',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CalculatedFieldRollingValueArgumentAutocomplete = {
|
||||||
|
meta: 'object',
|
||||||
|
type: '{ values: { ts: number; value: any; }[]; timewindow: { startTs: number; endTs: number; limit: number } }; }',
|
||||||
|
description: 'Calculated field rolling value argument.',
|
||||||
|
children: {
|
||||||
|
values: {
|
||||||
|
meta: 'array',
|
||||||
|
type: '{ ts: number; value: any; }[]',
|
||||||
|
description: 'Values array',
|
||||||
|
},
|
||||||
|
timewindow: {
|
||||||
|
meta: 'object',
|
||||||
|
type: '{ startTs: number; endTs: number; limit: number }',
|
||||||
|
description: 'Time window configuration',
|
||||||
|
children: {
|
||||||
|
startTs: {
|
||||||
|
meta: 'number',
|
||||||
|
type: 'number',
|
||||||
|
description: 'Start time stamp',
|
||||||
|
},
|
||||||
|
endTs: {
|
||||||
|
meta: 'number',
|
||||||
|
type: 'number',
|
||||||
|
description: 'End time stamp',
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
meta: 'number',
|
||||||
|
type: 'number',
|
||||||
|
description: 'Limit',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCalculatedFieldArgumentsEditorCompleter = (argumentsObj: Record<string, CalculatedFieldArgument>): TbEditorCompleter => {
|
||||||
|
return new TbEditorCompleter(Object.keys(argumentsObj).reduce((acc, key) => {
|
||||||
|
switch (argumentsObj[key].refEntityKey.type) {
|
||||||
|
case ArgumentType.Attribute:
|
||||||
|
acc[key] = CalculatedFieldAttributeValueArgumentAutocomplete;
|
||||||
|
break;
|
||||||
|
case ArgumentType.LatestTelemetry:
|
||||||
|
acc[key] = CalculatedFieldLatestTelemetryArgumentAutocomplete;
|
||||||
|
break;
|
||||||
|
case ArgumentType.Rolling:
|
||||||
|
acc[key] = CalculatedFieldRollingValueArgumentAutocomplete;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {}))
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user