diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 2c96464dda..93fd6d1fd6 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -36,6 +36,7 @@ import { EntityDebugSettingsPanelComponent } from '@home/components/entity/debug import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { + ArgumentType, CalculatedField, CalculatedFieldEventArguments, CalculatedFieldDebugDialogData, @@ -122,7 +123,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig true, onAction: (_, entity) => this.openDebugEventsDialog(entity), }, @@ -260,7 +261,10 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig { const resultArguments = Object.keys(calculatedField.configuration.arguments).reduce((acc, key) => { - acc[key] = isObject(argumentsObj) && argumentsObj.hasOwnProperty(key) ? argumentsObj[key] : ''; + const type = calculatedField.configuration.arguments[key].refEntityKey.type; + acc[key] = isObject(argumentsObj) && argumentsObj.hasOwnProperty(key) + ? { ...argumentsObj[key], type } + : type === ArgumentType.Rolling ? { values: [], type } : { value: '', type, ts: new Date().getTime() }; return acc; }, {}); return this.dialog.open(CalculatedFieldScriptTestDialogComponent, diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts index 3c51dc7f79..2af2e14daa 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts @@ -33,7 +33,6 @@ import { NG_VALUE_ACCESSOR, ValidationErrors, Validator, - Validators } from '@angular/forms'; import { ArgumentEntityType, @@ -50,7 +49,6 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { EntityId } from '@shared/models/id/entity-id'; import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; import { isDefinedAndNotNull } from '@core/utils'; -import { charsWithNumRegex } from '@shared/models/regex.constants'; import { TbPopoverComponent } from '@shared/components/popover.component'; @Component({ @@ -143,10 +141,10 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces buttonTitle: this.argumentsFormArray.at(index)?.value ? 'action.apply' : 'action.add', tenantId: this.tenantId, entityName: this.entityName, - usedArgumentNames: this.argumentsFormArray.value.map(({ argumentName }) => argumentName).filter(name => name !== argumentObj.argumentName), + usedArgumentNames: this.argumentsFormArray.getRawValue().map(({ argumentName }) => argumentName).filter(name => name !== argumentObj.argumentName), }; this.popoverComponent = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, CalculatedFieldArgumentPanelComponent, 'left', false, null, + this.viewContainerRef, CalculatedFieldArgumentPanelComponent, index ? 'left' : 'right', false, null, ctx, {}, {}, {}, true); @@ -201,7 +199,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces private getArgumentFormGroup(value: CalculatedFieldArgumentValue): FormGroup { return this.fb.group({ ...value, - argumentName: [value.argumentName, [Validators.required, Validators.maxLength(255), Validators.pattern(charsWithNumRegex)]], + argumentName: [{ value: value.argumentName, disabled: true }], ...(value.refEntityId ? { refEntityId: this.fb.group({ entityType: [{ value: value.refEntityId.entityType, disabled: true }], diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.html index eea3523d00..9131af966a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.html @@ -19,16 +19,38 @@
{{ 'calculated-fields.arguments' | translate }}
-
{{ 'calculated-fields.argument-name' | translate }}
-
{{ 'common.value' | translate }}
+
{{ 'common.name' | translate }}
+
{{ 'common.type' | translate }}
+
{{ 'common.data' | translate }}
@for (group of argumentsFormArray.controls; track group) {
- + - + + + + {{ ArgumentTypeTranslations.get(group.get('type').value) | translate }} + + + +
+ @if (group.get('type').value === ArgumentType.Rolling) { + + + + } @else { + + + + + } + +
}
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.scss index 1b2c8670c1..19046fa254 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.scss +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.scss @@ -15,14 +15,18 @@ */ @use '../../../../../../../scss/constants' as constants; +:host { + .tb-form-table { + min-width: 700px; + } +} + :host::ng-deep { .tb-form-table-row { .argument-value { .tb-value-type.row { - @media #{constants.$mat-lt-sm} { - width: 100px; - min-width: 100px; - } + width: 120px; + min-width: 120px; } } } diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.ts index c8c9f4e778..e16850008f 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component.ts @@ -26,6 +26,22 @@ import { } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { entityTypeTranslations } from '@shared/models/entity-type.models'; +import { + ArgumentType, + ArgumentTypeTranslations, + CalculatedFieldArgumentEventValue, + CalculatedFieldRollingTelemetryArgumentValue, + CalculatedFieldSingleArgumentValue, + CalculatedFieldEventArguments, + CalculatedFieldType +} from '@shared/models/calculated-field.models'; +import { + JsonObjectEditDialogComponent, + JsonObjectEditDialogData +} from '@shared/components/dialog/json-object-edit-dialog.component'; +import { filter } from 'rxjs/operators'; +import { MatDialog } from '@angular/material/dialog'; @Component({ selector: 'tb-calculated-field-test-arguments', @@ -49,29 +65,35 @@ export class CalculatedFieldTestArgumentsComponent extends PageComponent impleme argumentsFormArray = this.fb.array([]); - private propagateChange: (value: { argumentName: string; value: unknown }) => void; + readonly entityTypeTranslations = entityTypeTranslations; + readonly ArgumentTypeTranslations = ArgumentTypeTranslations; + readonly ArgumentType = ArgumentType; + readonly CalculatedFieldType = CalculatedFieldType; + + private propagateChange: (value: CalculatedFieldEventArguments) => void; - constructor(private fb: FormBuilder) { + constructor(private fb: FormBuilder, private dialog: MatDialog) { super(); this.argumentsFormArray.valueChanges .pipe(takeUntilDestroyed()) .subscribe(() => this.propagateChange(this.getValue())); } - registerOnChange(propagateChange: (value: { argumentName: string; value: unknown }) => void): void { + registerOnChange(propagateChange: (value: CalculatedFieldEventArguments) => void): void { this.propagateChange = propagateChange; } registerOnTouched(_): void { } - writeValue(argumentsObj: Record): void { + writeValue(argumentsObj: CalculatedFieldEventArguments): void { this.argumentsFormArray.clear(); Object.keys(argumentsObj).forEach(key => { - this.argumentsFormArray.push(this.fb.group({ - argumentName: [{ value: key, disabled: true}], - value: [argumentsObj[key]] - }) as FormGroup, {emitEvent: false}); + const value = { ...argumentsObj[key], argumentName: key } as CalculatedFieldArgumentEventValue; + this.argumentsFormArray.push((value).type === ArgumentType.Rolling + ? this.getRollingArgumentFormGroup(value as CalculatedFieldRollingTelemetryArgumentValue) + : this.getSimpleArgumentFormGroup(value as CalculatedFieldSingleArgumentValue), + {emitEvent: false}); }); } @@ -79,11 +101,44 @@ export class CalculatedFieldTestArgumentsComponent extends PageComponent impleme return this.argumentsFormArray.valid ? null : { arguments: { valid: false } }; } - private getValue(): { argumentName: string; value: unknown } { + private getSimpleArgumentFormGroup({ argumentName, type, ts, value }: CalculatedFieldSingleArgumentValue): FormGroup { + return this.fb.group({ + argumentName: [{ value: argumentName, disabled: true}], + type: [{ value: type , disabled: true }], + ts: [ts], + value: [value] + }) as FormGroup; + } + + private getRollingArgumentFormGroup({ argumentName, type, timewindow, values }: CalculatedFieldRollingTelemetryArgumentValue): FormGroup { + return this.fb.group({ + ...timewindow ?? {}, + argumentName: [{ value: argumentName, disabled: true }], + type: [{ value: type , disabled: true }], + values: [values] + }) as FormGroup; + } + + openEditJSONDialog(group: FormGroup): void { + this.dialog.open(JsonObjectEditDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog', 'tb-dialog-min-w-700', 'tb-dialog-h-fill'], + data: { + jsonValue: group.value, + required: true + } + }).afterClosed() + .pipe(filter(Boolean)) + .subscribe(result => group.get('type').value === ArgumentType.Rolling + ? group.patchValue({ timewindow: (result as CalculatedFieldRollingTelemetryArgumentValue).timewindow, values: (result as CalculatedFieldRollingTelemetryArgumentValue).values }) + : group.patchValue({ ts: (result as CalculatedFieldSingleArgumentValue).ts, value: (result as CalculatedFieldSingleArgumentValue).value }) ); + } + + private getValue(): CalculatedFieldEventArguments { return this.argumentsFormArray.getRawValue().reduce((acc, rowItem) => { - const { argumentName, value } = rowItem; - acc[argumentName] = value; + const { argumentName, type, ...value } = rowItem; + acc[argumentName] = { ...value }; return acc; - }, {}) as { argumentName: string; value: unknown }; + }, {}); } } diff --git a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html index 9cce511a6b..9fcb3a496a 100644 --- a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+

{{ title }}

@@ -28,10 +28,11 @@
-
-
+
+
diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index 3f5417c2d0..b1744038c3 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -184,7 +184,7 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal this.updateFunctionArgsString(); this.updateFunctionLabel(); } - if (changes.editorCompleter) { + if (changes.editorCompleter?.previousValue) { this.updateCompleters(); } } diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.html b/ui-ngx/src/app/shared/components/json-object-edit.component.html index 0aa28474d5..bd6e2c06bb 100644 --- a/ui-ngx/src/app/shared/components/json-object-edit.component.html +++ b/ui-ngx/src/app/shared/components/json-object-edit.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
diff --git a/ui-ngx/src/app/shared/components/value-input.component.html b/ui-ngx/src/app/shared/components/value-input.component.html index a7108f9174..57aed608c5 100644 --- a/ui-ngx/src/app/shared/components/value-input.component.html +++ b/ui-ngx/src/app/shared/components/value-input.component.html @@ -93,7 +93,7 @@ warning -
diff --git a/ui-ngx/src/app/shared/components/value-input.component.ts b/ui-ngx/src/app/shared/components/value-input.component.ts index 93a5a6c8bf..3065dd17c4 100644 --- a/ui-ngx/src/app/shared/components/value-input.component.ts +++ b/ui-ngx/src/app/shared/components/value-input.component.ts @@ -85,6 +85,10 @@ export class ValueInputComponent implements OnInit, OnDestroy, OnChanges, Contro @coerceBoolean() required = true; + @Input() + @coerceBoolean() + hideJsonEdit = false; + @Input() layout: ValueInputLayout | Layout = 'row'; diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index a718b236bf..5bcc0a4a2a 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -154,7 +154,7 @@ export interface CalculatedFieldTestScriptInputParams { } export interface CalculatedFieldTestScriptDialogData extends CalculatedFieldTestScriptInputParams { - argumentsEditorCompleter: TbEditorCompleter + argumentsEditorCompleter: TbEditorCompleter; openCalculatedFieldEdit?: boolean; } @@ -189,17 +189,22 @@ export const getCalculatedFieldCurrentEntityFilter = (entityName: string, entity } } -export interface CalculatedFieldAttributeArgumentValue { +export interface CalculatedFieldArgumentValueBase { + argumentName: string; + type: ArgumentType; +} + +export interface CalculatedFieldAttributeArgumentValue extends CalculatedFieldArgumentValueBase { ts: number; value: ValueType; } -export interface CalculatedFieldLatestTelemetryArgumentValue { +export interface CalculatedFieldLatestTelemetryArgumentValue extends CalculatedFieldArgumentValueBase { ts: number; value: ValueType; } -export interface CalculatedFieldRollingTelemetryArgumentValue { +export interface CalculatedFieldRollingTelemetryArgumentValue extends CalculatedFieldArgumentValueBase { timewindow: { startTs: number; endTs: number; limit: number }; values: CalculatedFieldSingleArgumentValue[]; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 4822d23387..4d19432fe7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1100,6 +1100,7 @@ "general": "General", "username": "Username", "password": "Password", + "data": "Data", "enter-username": "Enter username", "enter-password": "Enter password", "enter-search": "Enter search", diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index dbc69fb9dd..4f38160c0b 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -1058,6 +1058,19 @@ pre.tb-highlight { display: block; } } + + @for $i from 1 through 10 { + &-min-w-#{$i * 100} { + + @media screen and (min-width: #{$i * 100}px) { + --mat-dialog-container-min-width: #{$i * 100}px; + } + } + } + + &-h-fill { + height: 65vh; + } } .tb-fullscreen-dialog-gt-xs {