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 783ae6be5c..a0cbc8a5fe 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 @@ -44,6 +44,7 @@ import { CalculatedFieldTestScriptDialogData, getCalculatedFieldArgumentsEditorCompleter, getCalculatedFieldArgumentsHighlights, + CalculatedFieldTypeTranslations, } from '@shared/models/calculated-field.models'; import { CalculatedFieldDebugDialogComponent, @@ -112,7 +113,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig('name', 'common.name', '33%')); - this.columns.push(new EntityTableColumn('type', 'common.type', '50px')); + this.columns.push(new EntityTableColumn('type', 'common.type', '50px', entity => this.translate.instant(CalculatedFieldTypeTranslations.get(entity.type)))); this.columns.push(expressionColumn); this.cellActionDescriptors.push( diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html index a617db5d6d..d49f612ae6 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html @@ -73,7 +73,7 @@ } - +
{{ group.get('refEntityKey').get('key').value }} diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss index 321cde8dfe..febe5233d3 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss @@ -16,6 +16,10 @@ @use '../../../../../../../scss/constants' as constants; :host { + .entity-key-field { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + } + .tb-form-table-row-cell-buttons { --mat-badge-legacy-small-size-container-size: 8px; --mat-badge-small-size-container-overlap-offset: -5px; diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html index 20fba95688..34504488a5 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html @@ -74,10 +74,10 @@ [calculatedFieldType]="fieldFormGroup.get('type').value" />
-
+
{{ 'calculated-fields.expression' | translate }}
@if (fieldFormGroup.get('type').value === CalculatedFieldType.SIMPLE) { - + @if (configFormGroup.get('expressionSIMPLE').errors && configFormGroup.get('expressionSIMPLE').touched) { @@ -104,12 +104,13 @@ [editorCompleter]="argumentsEditorCompleter$ | async" helpId="calculated-field/expression_fn" > +
{{ 'api-usage.tbel' | translate }}
@@ -118,7 +119,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss index c17dbf8bb5..244051b05a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss @@ -19,6 +19,19 @@ width: 869px; max-width: 100%; } + + .script-lang-chip { + line-height: 20px; + font-size: 14px; + font-weight: 500; + color: white; + border-radius: 100px; + width: 70px; + display: flex; + justify-content: center; + margin-top: 2px; + margin-right: 4px; + } } :host ::ng-deep { diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html index 039df61fc6..5d66ae93bb 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html @@ -162,13 +162,13 @@
-
+
{{ 'calculated-fields.limit' | translate }}
- +
}
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss index 92eb5b1905..33c54f33f2 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss @@ -15,14 +15,37 @@ */ @use '../../../../../../../scss/constants' as constants; +$panel-width: 520px; + :host { display: flex; - width: 520px; + width: $panel-width; max-width: 100%; + max-height: 100vh; .fixed-title-width { - @media #{constants.$mat-lt-sm} { + @media #{constants.$mat-xs} { min-width: 120px; } } } + +:host ::ng-deep { + .limit-field-row { + @media screen and (max-width: $panel-width) { + display: flex; + flex-direction: column; + + .fixed-title-width { + align-self: flex-start; + padding-top: 8px; + } + } + } + + .time-interval-field { + .advanced-input { + flex-direction: column; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts index 66ce0aeeeb..e1ddd65014 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts @@ -28,7 +28,7 @@ import { CalculatedFieldType, getCalculatedFieldCurrentEntityFilter } from '@shared/models/calculated-field.models'; -import { debounceTime, distinctUntilChanged, filter } from 'rxjs/operators'; +import { debounceTime, delay, distinctUntilChanged, filter } from 'rxjs/operators'; import { EntityType } from '@shared/models/entity-type.models'; import { AttributeScope, DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { DatasourceType } from '@shared/models/widget.models'; @@ -38,6 +38,7 @@ import { EntityFilter } from '@shared/models/query/query.models'; import { AliasFilterType } from '@shared/models/alias.models'; import { merge } from 'rxjs'; import { MINUTE } from '@shared/models/time/time.models'; +import { TimeService } from '@core/services/time.service'; @Component({ selector: 'tb-calculated-field-argument-panel', @@ -57,6 +58,8 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit { argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>(); + readonly defaultLimit = Math.max(this.timeService.getMinDatapointsLimit(), Math.floor(this.timeService.getMaxDatapointsLimit() / 10)); + argumentFormGroup = this.fb.group({ argumentName: ['', [Validators.required, this.uniqNameRequired(), Validators.pattern(charsWithNumRegex), Validators.maxLength(255)]], refEntityId: this.fb.group({ @@ -69,7 +72,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit { scope: [{ value: AttributeScope.SERVER_SCOPE, disabled: true }, [Validators.required]], }), defaultValue: ['', [Validators.pattern(noLeadTrailSpacesRegex)]], - limit: [1000], + limit: [this.defaultLimit], timeWindow: [MINUTE * 15], }); @@ -92,11 +95,13 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit { constructor( private fb: FormBuilder, private cd: ChangeDetectorRef, - private popover: TbPopoverComponent + private popover: TbPopoverComponent, + private timeService: TimeService ) { this.observeEntityFilterChanges(); this.observeEntityTypeChanges() this.observeEntityKeyChanges(); + this.observeUpdatePosition(); } get entityType(): ArgumentEntityType { @@ -224,4 +229,15 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit { typeControl.markAsTouched(); } } + + private observeUpdatePosition(): void { + merge( + this.refEntityIdFormGroup.get('entityType').valueChanges, + this.refEntityKeyFormGroup.get('type').valueChanges, + this.argumentFormGroup.get('timeWindow').valueChanges, + this.refEntityIdFormGroup.get('id').valueChanges.pipe(filter(Boolean)), + ) + .pipe(delay(50), takeUntilDestroyed()) + .subscribe(() => this.popover.updatePosition()); + } } 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 3f5c864708..c97bdbb3b3 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 @@ -39,11 +39,11 @@
@if (argumentsTypeMap.get(group.get('argumentName').value) === ArgumentType.Rolling) { - + } @else { - + } 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 2411a7fd81..8f62e7a561 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 @@ -110,14 +110,14 @@ export class CalculatedFieldTestArgumentsComponent extends PageComponent impleme minWidth: 'min(700px, 100%)', panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - jsonValue: group.value, + jsonValue: this.argumentsTypeMap.get(group.get('argumentName').value) === ArgumentType.Rolling ? group.value.rollingJson : group.value, required: true, fillHeight: true } }).afterClosed() .pipe(filter(Boolean)) .subscribe(result => this.argumentsTypeMap.get(group.get('argumentName').value) === ArgumentType.Rolling - ? group.patchValue({ timeWindow: (result as CalculatedFieldRollingTelemetryArgumentValue).timeWindow, values: (result as CalculatedFieldRollingTelemetryArgumentValue).values }) + ? group.get('rollingJson').patchValue({ values: (result as CalculatedFieldRollingTelemetryArgumentValue).values, timeWindow: (result as CalculatedFieldRollingTelemetryArgumentValue).timeWindow }) : group.patchValue({ ts: (result as CalculatedFieldSingleArgumentValue).ts, value: (result as CalculatedFieldSingleArgumentValue).value }) ); } @@ -131,16 +131,15 @@ export class CalculatedFieldTestArgumentsComponent extends PageComponent impleme private getRollingArgumentFormGroup({ argumentName, timeWindow, values }: CalculatedFieldRollingTelemetryArgumentValue): FormGroup { return this.fb.group({ - timeWindow: [timeWindow ?? {}], argumentName: [{ value: argumentName, disabled: true }], - values: [values] + rollingJson: [{ values: values ?? [], timeWindow: timeWindow ?? {} }] }) as FormGroup; } private getValue(): CalculatedFieldEventArguments { return this.argumentsFormArray.getRawValue().reduce((acc, rowItem) => { - const { argumentName, ...value } = rowItem; - acc[argumentName] = value; + const { argumentName, rollingJson = {}, ...value } = rowItem; + acc[argumentName] = { ...rollingJson, ...value }; return acc; }, {}); } diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html index 789d290a6d..8acdc8b0ef 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html @@ -38,6 +38,7 @@ functionName="calculate" class="expression-edit" [functionArgs]="functionArgs" + [required]="true" [disableUndefinedCheck]="true" [fillHeight]="true" [highlightRules]="data.argumentsHighlightRules" diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts index 769387b3dd..28657a8d25 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts @@ -26,7 +26,7 @@ import { import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { FormBuilder } from '@angular/forms'; +import { FormBuilder, Validators } from '@angular/forms'; import { NEVER, Observable, of, switchMap } from 'rxjs'; import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; @@ -62,7 +62,7 @@ export class CalculatedFieldScriptTestDialogComponent extends DialogComponent @@ -208,6 +209,8 @@ [copyText]="column.actionCell.onAction(null, entity)" tooltipText="{{ column.actionCell.nameFunction ? column.actionCell.nameFunction(entity) : column.actionCell.name }}" tooltipPosition="above" + (mouseover)="cellMatTooltip.hide()" + (mouseleave)="cellMatTooltip.show()" [icon]="column.actionCell.icon" [style]="column.actionCell.style"> diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 1e9717d5a8..4a81e1ea0d 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -403,7 +403,9 @@ export class EventTableConfig extends EntityTableConfig { new EntityTableColumn('messageType', 'event.message-type', '100px', (entity) => entity.body.msgType ?? '-', () => ({padding: '0 12px 0 0'}), - false + false, + () => ({padding: '0 12px 0 0'}), + (entity) => entity.body.msgType, ), new EntityActionTableColumn('arguments', 'event.arguments', { @@ -539,8 +541,8 @@ export class EventTableConfig extends EntityTableConfig { case DebugEventType.DEBUG_CALCULATED_FIELD: this.filterColumns.push( {key: 'entityId', title: 'event.entity-id'}, - {key: 'messageId', title: 'event.message-id'}, - {key: 'messageType', title: 'event.message-type'}, + {key: 'msgId', title: 'event.message-id'}, + {key: 'msgType', title: 'event.message-type'}, {key: 'arguments', title: 'event.arguments'}, {key: 'result', title: 'event.result'}, {key: 'isError', title: 'event.error'}, diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts index 9fe747db0a..2e90106a9c 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts @@ -31,7 +31,12 @@ import { } from '@home/components/widget/lib/scada/scada-symbol.models'; import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; -import { AceHighlightRule, AceHighlightRules } from '@shared/models/ace/ace.models'; +import { + AceHighlightRule, + AceHighlightRules, + dotOperatorHighlightRule, + endGroupHighlightRule +} from '@shared/models/ace/ace.models'; import { HelpLinks, ValueType } from '@shared/models/constants'; import { formPropertyCompletions } from '@shared/models/dynamic-form.models'; import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; @@ -921,17 +926,6 @@ export class ScadaSymbolElement { const identifierRe = /[a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*/; -const dotOperatorHighlightRule: AceHighlightRule = { - token: 'punctuation.operator', - regex: /[.](?![.])/, -}; - -const endGroupHighlightRule: AceHighlightRule = { - regex: '', - token: 'empty', - next: 'no_regex' -}; - const scadaSymbolCtxObjectHighlightRule: AceHighlightRule = { token: 'tb.scada-symbol-ctx', regex: /\bctx\b/, 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 57aed608c5..41f2bfc942 100644 --- a/ui-ngx/src/app/shared/components/value-input.component.html +++ b/ui-ngx/src/app/shared/components/value-input.component.html @@ -33,7 +33,7 @@ + placeholder="{{ 'value.string-value' | translate }}{{ required ? '*' : ''}}"/> + placeholder="{{ 'value.integer-value' | translate }}{{ required ? '*' : ''}}"/> + placeholder="{{ 'value.double-value' | translate }}{{ required ? '*' : ''}}"/> + [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()" placeholder="{{ 'value.json-value' | translate }}{{ required ? '*' : ''}}"/> , 'label'>, HasVersion, HasTenantId, ExportableEntity { debugSettings?: EntityDebugSettings; @@ -337,6 +341,7 @@ export const getCalculatedFieldArgumentsHighlights = ( const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = { calculatedFieldSingleArgumentValue: [ + dotOperatorHighlightRule, { token: 'tb.calculated-field-value', regex: /value/, @@ -346,12 +351,14 @@ const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = { token: 'tb.calculated-field-ts', regex: /ts/, next: 'no_regex' - } + }, + endGroupHighlightRule ], } const calculatedFieldRollingArgumentValueHighlightRules: AceHighlightRules = { calculatedFieldRollingArgumentValue: [ + dotOperatorHighlightRule, { token: 'tb.calculated-field-values', regex: /values/, @@ -361,12 +368,14 @@ const calculatedFieldRollingArgumentValueHighlightRules: AceHighlightRules = { token: 'tb.calculated-field-time-window', regex: /timeWindow/, next: 'calculatedFieldRollingArgumentTimeWindow' - } + }, + endGroupHighlightRule ], } const calculatedFieldTimeWindowArgumentValueHighlightRules: AceHighlightRules = { calculatedFieldRollingArgumentTimeWindow: [ + dotOperatorHighlightRule, { token: 'tb.calculated-field-start-ts', regex: /startTs/, @@ -381,6 +390,7 @@ const calculatedFieldTimeWindowArgumentValueHighlightRules: AceHighlightRules = token: 'tb.calculated-field-limit', regex: /limit/, next: 'no_regex' - } + }, + endGroupHighlightRule ] } 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 b4b31e3d37..cf6e3ba86e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1101,6 +1101,7 @@ "username": "Username", "password": "Password", "data": "Data", + "timestamp": "Timestamp", "enter-username": "Enter username", "enter-password": "Enter password", "enter-search": "Enter search",