Merge pull request #12719 from maxunbearable/feature/calculated-fields-adjustments-19-02
Calculated fields adjustments
This commit is contained in:
commit
4dad2bbc53
@ -44,6 +44,7 @@ import {
|
|||||||
CalculatedFieldTestScriptDialogData,
|
CalculatedFieldTestScriptDialogData,
|
||||||
getCalculatedFieldArgumentsEditorCompleter,
|
getCalculatedFieldArgumentsEditorCompleter,
|
||||||
getCalculatedFieldArgumentsHighlights,
|
getCalculatedFieldArgumentsHighlights,
|
||||||
|
CalculatedFieldTypeTranslations,
|
||||||
} from '@shared/models/calculated-field.models';
|
} from '@shared/models/calculated-field.models';
|
||||||
import {
|
import {
|
||||||
CalculatedFieldDebugDialogComponent,
|
CalculatedFieldDebugDialogComponent,
|
||||||
@ -112,7 +113,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
|||||||
expressionColumn.sortable = false;
|
expressionColumn.sortable = false;
|
||||||
|
|
||||||
this.columns.push(new EntityTableColumn<CalculatedField>('name', 'common.name', '33%'));
|
this.columns.push(new EntityTableColumn<CalculatedField>('name', 'common.name', '33%'));
|
||||||
this.columns.push(new EntityTableColumn<CalculatedField>('type', 'common.type', '50px'));
|
this.columns.push(new EntityTableColumn<CalculatedField>('type', 'common.type', '50px', entity => this.translate.instant(CalculatedFieldTypeTranslations.get(entity.type))));
|
||||||
this.columns.push(expressionColumn);
|
this.columns.push(expressionColumn);
|
||||||
|
|
||||||
this.cellActionDescriptors.push(
|
this.cellActionDescriptors.push(
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
</mat-select>
|
</mat-select>
|
||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-chip-listbox formControlName="key" class="tb-inline-field w-1/6 xs:w-1/3">
|
<mat-chip-listbox formControlName="key" class="tb-inline-field entity-key-field w-1/6 xs:w-1/3">
|
||||||
<mat-chip>
|
<mat-chip>
|
||||||
<div tbTruncateWithTooltip>
|
<div tbTruncateWithTooltip>
|
||||||
{{ group.get('refEntityKey').get('key').value }}
|
{{ group.get('refEntityKey').get('key').value }}
|
||||||
|
|||||||
@ -16,6 +16,10 @@
|
|||||||
@use '../../../../../../../scss/constants' as constants;
|
@use '../../../../../../../scss/constants' as constants;
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
|
.entity-key-field {
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
.tb-form-table-row-cell-buttons {
|
.tb-form-table-row-cell-buttons {
|
||||||
--mat-badge-legacy-small-size-container-size: 8px;
|
--mat-badge-legacy-small-size-container-size: 8px;
|
||||||
--mat-badge-small-size-container-overlap-offset: -5px;
|
--mat-badge-small-size-container-overlap-offset: -5px;
|
||||||
|
|||||||
@ -74,10 +74,10 @@
|
|||||||
[calculatedFieldType]="fieldFormGroup.get('type').value"
|
[calculatedFieldType]="fieldFormGroup.get('type').value"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-form-panel">
|
<div class="tb-form-panel no-gap">
|
||||||
<div class="tb-form-panel-title tb-required">{{ 'calculated-fields.expression' | translate }}</div>
|
<div class="tb-form-panel-title tb-required">{{ 'calculated-fields.expression' | translate }}</div>
|
||||||
@if (fieldFormGroup.get('type').value === CalculatedFieldType.SIMPLE) {
|
@if (fieldFormGroup.get('type').value === CalculatedFieldType.SIMPLE) {
|
||||||
<mat-form-field class="mat-block" appearance="outline">
|
<mat-form-field class="mt-3" appearance="outline" subscriptSizing="dynamic">
|
||||||
<input matInput formControlName="expressionSIMPLE" maxlength="255" [placeholder]="'action.set' | translate" required>
|
<input matInput formControlName="expressionSIMPLE" maxlength="255" [placeholder]="'action.set' | translate" required>
|
||||||
@if (configFormGroup.get('expressionSIMPLE').errors && configFormGroup.get('expressionSIMPLE').touched) {
|
@if (configFormGroup.get('expressionSIMPLE').errors && configFormGroup.get('expressionSIMPLE').touched) {
|
||||||
<mat-error>
|
<mat-error>
|
||||||
@ -104,12 +104,13 @@
|
|||||||
[editorCompleter]="argumentsEditorCompleter$ | async"
|
[editorCompleter]="argumentsEditorCompleter$ | async"
|
||||||
helpId="calculated-field/expression_fn"
|
helpId="calculated-field/expression_fn"
|
||||||
>
|
>
|
||||||
|
<div toolbarPrefixButton class="tb-primary-background script-lang-chip">{{ 'api-usage.tbel' | translate }}</div>
|
||||||
<button toolbarSuffixButton
|
<button toolbarSuffixButton
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
matTooltip="{{ 'common.test-function' | translate }}"
|
matTooltip="{{ 'common.test-function' | translate }}"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
class="tb-mat-32"
|
class="tb-mat-32"
|
||||||
[disabled]="configFormGroup.get('expressionSCRIPT').invalid || configFormGroup.get('arguments').invalid"
|
[disabled]="configFormGroup.get('arguments').invalid"
|
||||||
(click)="onTestScript()">
|
(click)="onTestScript()">
|
||||||
<mat-icon class="material-icons" color="primary">bug_report</mat-icon>
|
<mat-icon class="material-icons" color="primary">bug_report</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
@ -118,7 +119,7 @@
|
|||||||
<button mat-button mat-raised-button color="primary"
|
<button mat-button mat-raised-button color="primary"
|
||||||
type="button"
|
type="button"
|
||||||
(click)="onTestScript()"
|
(click)="onTestScript()"
|
||||||
[disabled]="configFormGroup.get('expressionSCRIPT').invalid || configFormGroup.get('arguments').invalid">
|
[disabled]="configFormGroup.get('arguments').invalid">
|
||||||
{{ 'common.test-function' | translate }}
|
{{ 'common.test-function' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -19,6 +19,19 @@
|
|||||||
width: 869px;
|
width: 869px;
|
||||||
max-width: 100%;
|
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 {
|
:host ::ng-deep {
|
||||||
|
|||||||
@ -162,13 +162,13 @@
|
|||||||
<tb-timeinterval
|
<tb-timeinterval
|
||||||
subscriptSizing="dynamic"
|
subscriptSizing="dynamic"
|
||||||
appearance="outline"
|
appearance="outline"
|
||||||
class="flex-1"
|
class="time-interval-field flex-1"
|
||||||
formControlName="timeWindow"
|
formControlName="timeWindow"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-form-row">
|
<div class="tb-form-row limit-field-row">
|
||||||
<div class="fixed-title-width">{{ 'calculated-fields.limit' | translate }}</div>
|
<div class="fixed-title-width">{{ 'calculated-fields.limit' | translate }}</div>
|
||||||
<tb-datapoints-limit class="flex-1" formControlName="limit"/>
|
<tb-datapoints-limit class="w-full flex-1" formControlName="limit"/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -15,14 +15,37 @@
|
|||||||
*/
|
*/
|
||||||
@use '../../../../../../../scss/constants' as constants;
|
@use '../../../../../../../scss/constants' as constants;
|
||||||
|
|
||||||
|
$panel-width: 520px;
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 520px;
|
width: $panel-width;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
max-height: 100vh;
|
||||||
|
|
||||||
.fixed-title-width {
|
.fixed-title-width {
|
||||||
@media #{constants.$mat-lt-sm} {
|
@media #{constants.$mat-xs} {
|
||||||
min-width: 120px;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import {
|
|||||||
CalculatedFieldType,
|
CalculatedFieldType,
|
||||||
getCalculatedFieldCurrentEntityFilter
|
getCalculatedFieldCurrentEntityFilter
|
||||||
} from '@shared/models/calculated-field.models';
|
} 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 { EntityType } from '@shared/models/entity-type.models';
|
||||||
import { AttributeScope, DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
import { AttributeScope, DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||||
import { DatasourceType } from '@shared/models/widget.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 { AliasFilterType } from '@shared/models/alias.models';
|
||||||
import { merge } from 'rxjs';
|
import { merge } from 'rxjs';
|
||||||
import { MINUTE } from '@shared/models/time/time.models';
|
import { MINUTE } from '@shared/models/time/time.models';
|
||||||
|
import { TimeService } from '@core/services/time.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-calculated-field-argument-panel',
|
selector: 'tb-calculated-field-argument-panel',
|
||||||
@ -57,6 +58,8 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
|
|||||||
|
|
||||||
argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>();
|
argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>();
|
||||||
|
|
||||||
|
readonly defaultLimit = Math.max(this.timeService.getMinDatapointsLimit(), Math.floor(this.timeService.getMaxDatapointsLimit() / 10));
|
||||||
|
|
||||||
argumentFormGroup = this.fb.group({
|
argumentFormGroup = this.fb.group({
|
||||||
argumentName: ['', [Validators.required, this.uniqNameRequired(), Validators.pattern(charsWithNumRegex), Validators.maxLength(255)]],
|
argumentName: ['', [Validators.required, this.uniqNameRequired(), Validators.pattern(charsWithNumRegex), Validators.maxLength(255)]],
|
||||||
refEntityId: this.fb.group({
|
refEntityId: this.fb.group({
|
||||||
@ -69,7 +72,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
|
|||||||
scope: [{ value: AttributeScope.SERVER_SCOPE, disabled: true }, [Validators.required]],
|
scope: [{ value: AttributeScope.SERVER_SCOPE, disabled: true }, [Validators.required]],
|
||||||
}),
|
}),
|
||||||
defaultValue: ['', [Validators.pattern(noLeadTrailSpacesRegex)]],
|
defaultValue: ['', [Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||||
limit: [1000],
|
limit: [this.defaultLimit],
|
||||||
timeWindow: [MINUTE * 15],
|
timeWindow: [MINUTE * 15],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -92,11 +95,13 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
private popover: TbPopoverComponent<CalculatedFieldArgumentPanelComponent>
|
private popover: TbPopoverComponent<CalculatedFieldArgumentPanelComponent>,
|
||||||
|
private timeService: TimeService
|
||||||
) {
|
) {
|
||||||
this.observeEntityFilterChanges();
|
this.observeEntityFilterChanges();
|
||||||
this.observeEntityTypeChanges()
|
this.observeEntityTypeChanges()
|
||||||
this.observeEntityKeyChanges();
|
this.observeEntityKeyChanges();
|
||||||
|
this.observeUpdatePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
get entityType(): ArgumentEntityType {
|
get entityType(): ArgumentEntityType {
|
||||||
@ -224,4 +229,15 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
|
|||||||
typeControl.markAsTouched();
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,11 +39,11 @@
|
|||||||
<div class="flex flex-1 items-center gap-2">
|
<div class="flex flex-1 items-center gap-2">
|
||||||
@if (argumentsTypeMap.get(group.get('argumentName').value) === ArgumentType.Rolling) {
|
@if (argumentsTypeMap.get(group.get('argumentName').value) === ArgumentType.Rolling) {
|
||||||
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex-1">
|
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex-1">
|
||||||
<input matInput tb-json-to-string name="values" formControlName="values" placeholder="{{ 'value.json-value' | translate }}*"/>
|
<input matInput tb-json-to-string name="rollingJson" formControlName="rollingJson" placeholder="{{ 'value.json-value' | translate }}"/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
} @else {
|
} @else {
|
||||||
<mat-form-field appearance="outline" class="tb-inline-field w-1/3" subscriptSizing="dynamic">
|
<mat-form-field appearance="outline" class="tb-inline-field w-1/3" subscriptSizing="dynamic">
|
||||||
<input matInput formControlName="ts" type="number" placeholder="{{ 'action.set' | translate }}">
|
<input matInput formControlName="ts" type="number" placeholder="{{ 'common.timestamp' | translate }}">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<tb-value-input class="argument-value min-w-60 flex-1" [required]="false" [hideJsonEdit]="true" [shortBooleanField]="true" formControlName="value"/>
|
<tb-value-input class="argument-value min-w-60 flex-1" [required]="false" [hideJsonEdit]="true" [shortBooleanField]="true" formControlName="value"/>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,14 +110,14 @@ export class CalculatedFieldTestArgumentsComponent extends PageComponent impleme
|
|||||||
minWidth: 'min(700px, 100%)',
|
minWidth: 'min(700px, 100%)',
|
||||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
data: {
|
data: {
|
||||||
jsonValue: group.value,
|
jsonValue: this.argumentsTypeMap.get(group.get('argumentName').value) === ArgumentType.Rolling ? group.value.rollingJson : group.value,
|
||||||
required: true,
|
required: true,
|
||||||
fillHeight: true
|
fillHeight: true
|
||||||
}
|
}
|
||||||
}).afterClosed()
|
}).afterClosed()
|
||||||
.pipe(filter(Boolean))
|
.pipe(filter(Boolean))
|
||||||
.subscribe(result => this.argumentsTypeMap.get(group.get('argumentName').value) === ArgumentType.Rolling
|
.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 }) );
|
: 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 {
|
private getRollingArgumentFormGroup({ argumentName, timeWindow, values }: CalculatedFieldRollingTelemetryArgumentValue): FormGroup {
|
||||||
return this.fb.group({
|
return this.fb.group({
|
||||||
timeWindow: [timeWindow ?? {}],
|
|
||||||
argumentName: [{ value: argumentName, disabled: true }],
|
argumentName: [{ value: argumentName, disabled: true }],
|
||||||
values: [values]
|
rollingJson: [{ values: values ?? [], timeWindow: timeWindow ?? {} }]
|
||||||
}) as FormGroup;
|
}) as FormGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getValue(): CalculatedFieldEventArguments {
|
private getValue(): CalculatedFieldEventArguments {
|
||||||
return this.argumentsFormArray.getRawValue().reduce((acc, rowItem) => {
|
return this.argumentsFormArray.getRawValue().reduce((acc, rowItem) => {
|
||||||
const { argumentName, ...value } = rowItem;
|
const { argumentName, rollingJson = {}, ...value } = rowItem;
|
||||||
acc[argumentName] = value;
|
acc[argumentName] = { ...rollingJson, ...value };
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
functionName="calculate"
|
functionName="calculate"
|
||||||
class="expression-edit"
|
class="expression-edit"
|
||||||
[functionArgs]="functionArgs"
|
[functionArgs]="functionArgs"
|
||||||
|
[required]="true"
|
||||||
[disableUndefinedCheck]="true"
|
[disableUndefinedCheck]="true"
|
||||||
[fillHeight]="true"
|
[fillHeight]="true"
|
||||||
[highlightRules]="data.argumentsHighlightRules"
|
[highlightRules]="data.argumentsHighlightRules"
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import {
|
|||||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
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 { NEVER, Observable, of, switchMap } from 'rxjs';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { DialogComponent } from '@shared/components/dialog.component';
|
import { DialogComponent } from '@shared/components/dialog.component';
|
||||||
@ -62,7 +62,7 @@ export class CalculatedFieldScriptTestDialogComponent extends DialogComponent<Ca
|
|||||||
@ViewChild('expressionContent', {static: true}) expressionContent: JsonContentComponent;
|
@ViewChild('expressionContent', {static: true}) expressionContent: JsonContentComponent;
|
||||||
|
|
||||||
calculatedFieldScriptTestFormGroup = this.fb.group({
|
calculatedFieldScriptTestFormGroup = this.fb.group({
|
||||||
expression: [],
|
expression: ['', Validators.required],
|
||||||
arguments: [],
|
arguments: [],
|
||||||
output: []
|
output: []
|
||||||
});
|
});
|
||||||
|
|||||||
@ -183,6 +183,7 @@
|
|||||||
[class.lt-lg:!hidden]="column.mobileHide"
|
[class.lt-lg:!hidden]="column.mobileHide"
|
||||||
*matCellDef="let entity; let row = index"
|
*matCellDef="let entity; let row = index"
|
||||||
[matTooltip]="cellTooltip(entity, column, row)"
|
[matTooltip]="cellTooltip(entity, column, row)"
|
||||||
|
#cellMatTooltip="matTooltip"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
[style]="cellStyle(entity, column, row)">
|
[style]="cellStyle(entity, column, row)">
|
||||||
<ng-container [ngSwitch]="column.type">
|
<ng-container [ngSwitch]="column.type">
|
||||||
@ -208,6 +209,8 @@
|
|||||||
[copyText]="column.actionCell.onAction(null, entity)"
|
[copyText]="column.actionCell.onAction(null, entity)"
|
||||||
tooltipText="{{ column.actionCell.nameFunction ? column.actionCell.nameFunction(entity) : column.actionCell.name }}"
|
tooltipText="{{ column.actionCell.nameFunction ? column.actionCell.nameFunction(entity) : column.actionCell.name }}"
|
||||||
tooltipPosition="above"
|
tooltipPosition="above"
|
||||||
|
(mouseover)="cellMatTooltip.hide()"
|
||||||
|
(mouseleave)="cellMatTooltip.show()"
|
||||||
[icon]="column.actionCell.icon"
|
[icon]="column.actionCell.icon"
|
||||||
[style]="column.actionCell.style">
|
[style]="column.actionCell.style">
|
||||||
</tb-copy-button>
|
</tb-copy-button>
|
||||||
|
|||||||
@ -403,7 +403,9 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
|
|||||||
new EntityTableColumn<Event>('messageType', 'event.message-type', '100px',
|
new EntityTableColumn<Event>('messageType', 'event.message-type', '100px',
|
||||||
(entity) => entity.body.msgType ?? '-',
|
(entity) => entity.body.msgType ?? '-',
|
||||||
() => ({padding: '0 12px 0 0'}),
|
() => ({padding: '0 12px 0 0'}),
|
||||||
false
|
false,
|
||||||
|
() => ({padding: '0 12px 0 0'}),
|
||||||
|
(entity) => entity.body.msgType,
|
||||||
),
|
),
|
||||||
new EntityActionTableColumn<Event>('arguments', 'event.arguments',
|
new EntityActionTableColumn<Event>('arguments', 'event.arguments',
|
||||||
{
|
{
|
||||||
@ -539,8 +541,8 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
|
|||||||
case DebugEventType.DEBUG_CALCULATED_FIELD:
|
case DebugEventType.DEBUG_CALCULATED_FIELD:
|
||||||
this.filterColumns.push(
|
this.filterColumns.push(
|
||||||
{key: 'entityId', title: 'event.entity-id'},
|
{key: 'entityId', title: 'event.entity-id'},
|
||||||
{key: 'messageId', title: 'event.message-id'},
|
{key: 'msgId', title: 'event.message-id'},
|
||||||
{key: 'messageType', title: 'event.message-type'},
|
{key: 'msgType', title: 'event.message-type'},
|
||||||
{key: 'arguments', title: 'event.arguments'},
|
{key: 'arguments', title: 'event.arguments'},
|
||||||
{key: 'result', title: 'event.result'},
|
{key: 'result', title: 'event.result'},
|
||||||
{key: 'isError', title: 'event.error'},
|
{key: 'isError', title: 'event.error'},
|
||||||
|
|||||||
@ -31,7 +31,12 @@ import {
|
|||||||
} from '@home/components/widget/lib/scada/scada-symbol.models';
|
} from '@home/components/widget/lib/scada/scada-symbol.models';
|
||||||
import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models';
|
import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models';
|
||||||
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
|
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 { HelpLinks, ValueType } from '@shared/models/constants';
|
||||||
import { formPropertyCompletions } from '@shared/models/dynamic-form.models';
|
import { formPropertyCompletions } from '@shared/models/dynamic-form.models';
|
||||||
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
|
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 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 = {
|
const scadaSymbolCtxObjectHighlightRule: AceHighlightRule = {
|
||||||
token: 'tb.scada-symbol-ctx',
|
token: 'tb.scada-symbol-ctx',
|
||||||
regex: /\bctx\b/,
|
regex: /\bctx\b/,
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field *ngIf="valueType === valueTypeEnum.STRING" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute flex flex-1">
|
<mat-form-field *ngIf="valueType === valueTypeEnum.STRING" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute flex flex-1">
|
||||||
<input [disabled]="disabled" matInput [required]="required" name="value" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
|
<input [disabled]="disabled" matInput [required]="required" name="value" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
|
||||||
placeholder="{{ 'value.string-value' | translate }}*"/>
|
placeholder="{{ 'value.string-value' | translate }}{{ required ? '*' : ''}}"/>
|
||||||
<mat-icon matSuffix
|
<mat-icon matSuffix
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltipClass="tb-error-tooltip"
|
matTooltipClass="tb-error-tooltip"
|
||||||
@ -45,7 +45,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field *ngIf="valueType === valueTypeEnum.INTEGER" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute number flex flex-1">
|
<mat-form-field *ngIf="valueType === valueTypeEnum.INTEGER" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute number flex flex-1">
|
||||||
<input [disabled]="disabled" matInput [required]="required" name="value" type="number" step="1" pattern="^-?[0-9]+$" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
|
<input [disabled]="disabled" matInput [required]="required" name="value" type="number" step="1" pattern="^-?[0-9]+$" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
|
||||||
placeholder="{{ 'value.integer-value' | translate }}*"/>
|
placeholder="{{ 'value.integer-value' | translate }}{{ required ? '*' : ''}}"/>
|
||||||
<mat-icon matSuffix
|
<mat-icon matSuffix
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltipClass="tb-error-tooltip"
|
matTooltipClass="tb-error-tooltip"
|
||||||
@ -58,7 +58,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field *ngIf="valueType === valueTypeEnum.DOUBLE" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute number flex flex-1">
|
<mat-form-field *ngIf="valueType === valueTypeEnum.DOUBLE" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute number flex flex-1">
|
||||||
<input [disabled]="disabled" matInput [required]="required" name="value" type="number" step="any" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
|
<input [disabled]="disabled" matInput [required]="required" name="value" type="number" step="any" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
|
||||||
placeholder="{{ 'value.double-value' | translate }}*"/>
|
placeholder="{{ 'value.double-value' | translate }}{{ required ? '*' : ''}}"/>
|
||||||
<mat-icon matSuffix
|
<mat-icon matSuffix
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltipClass="tb-error-tooltip"
|
matTooltipClass="tb-error-tooltip"
|
||||||
@ -81,7 +81,7 @@
|
|||||||
<div *ngIf="valueType === valueTypeEnum.JSON" class="flex flex-1 flex-row items-center justify-start gap-2">
|
<div *ngIf="valueType === valueTypeEnum.JSON" class="flex flex-1 flex-row items-center justify-start gap-2">
|
||||||
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute flex flex-1">
|
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="tb-inline-field tb-suffix-absolute flex flex-1">
|
||||||
<input [disabled]="disabled" matInput tb-json-to-string [required]="required" name="value" #value="ngModel"
|
<input [disabled]="disabled" matInput tb-json-to-string [required]="required" name="value" #value="ngModel"
|
||||||
[(ngModel)]="modelValue" (ngModelChange)="onValueChanged()" placeholder="{{ 'value.json-value' | translate }}*"/>
|
[(ngModel)]="modelValue" (ngModelChange)="onValueChanged()" placeholder="{{ 'value.json-value' | translate }}{{ required ? '*' : ''}}"/>
|
||||||
<mat-icon matSuffix
|
<mat-icon matSuffix
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltipClass="tb-error-tooltip"
|
matTooltipClass="tb-error-tooltip"
|
||||||
|
|||||||
@ -365,5 +365,16 @@ export interface AceHighlightRule {
|
|||||||
next?: string;
|
next?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const dotOperatorHighlightRule: AceHighlightRule = {
|
||||||
|
token: 'punctuation.operator',
|
||||||
|
regex: /[.](?![.])/,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const endGroupHighlightRule: AceHighlightRule = {
|
||||||
|
regex: '',
|
||||||
|
token: 'empty',
|
||||||
|
next: 'no_regex'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,11 @@ 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';
|
import { TbEditorCompleter } from '@shared/models/ace/completion.models';
|
||||||
import { AceHighlightRules } from '@shared/models/ace/ace.models';
|
import {
|
||||||
|
AceHighlightRules,
|
||||||
|
dotOperatorHighlightRule,
|
||||||
|
endGroupHighlightRule
|
||||||
|
} from '@shared/models/ace/ace.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;
|
||||||
@ -337,6 +341,7 @@ export const getCalculatedFieldArgumentsHighlights = (
|
|||||||
|
|
||||||
const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = {
|
const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = {
|
||||||
calculatedFieldSingleArgumentValue: [
|
calculatedFieldSingleArgumentValue: [
|
||||||
|
dotOperatorHighlightRule,
|
||||||
{
|
{
|
||||||
token: 'tb.calculated-field-value',
|
token: 'tb.calculated-field-value',
|
||||||
regex: /value/,
|
regex: /value/,
|
||||||
@ -346,12 +351,14 @@ const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = {
|
|||||||
token: 'tb.calculated-field-ts',
|
token: 'tb.calculated-field-ts',
|
||||||
regex: /ts/,
|
regex: /ts/,
|
||||||
next: 'no_regex'
|
next: 'no_regex'
|
||||||
}
|
},
|
||||||
|
endGroupHighlightRule
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculatedFieldRollingArgumentValueHighlightRules: AceHighlightRules = {
|
const calculatedFieldRollingArgumentValueHighlightRules: AceHighlightRules = {
|
||||||
calculatedFieldRollingArgumentValue: [
|
calculatedFieldRollingArgumentValue: [
|
||||||
|
dotOperatorHighlightRule,
|
||||||
{
|
{
|
||||||
token: 'tb.calculated-field-values',
|
token: 'tb.calculated-field-values',
|
||||||
regex: /values/,
|
regex: /values/,
|
||||||
@ -361,12 +368,14 @@ const calculatedFieldRollingArgumentValueHighlightRules: AceHighlightRules = {
|
|||||||
token: 'tb.calculated-field-time-window',
|
token: 'tb.calculated-field-time-window',
|
||||||
regex: /timeWindow/,
|
regex: /timeWindow/,
|
||||||
next: 'calculatedFieldRollingArgumentTimeWindow'
|
next: 'calculatedFieldRollingArgumentTimeWindow'
|
||||||
}
|
},
|
||||||
|
endGroupHighlightRule
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculatedFieldTimeWindowArgumentValueHighlightRules: AceHighlightRules = {
|
const calculatedFieldTimeWindowArgumentValueHighlightRules: AceHighlightRules = {
|
||||||
calculatedFieldRollingArgumentTimeWindow: [
|
calculatedFieldRollingArgumentTimeWindow: [
|
||||||
|
dotOperatorHighlightRule,
|
||||||
{
|
{
|
||||||
token: 'tb.calculated-field-start-ts',
|
token: 'tb.calculated-field-start-ts',
|
||||||
regex: /startTs/,
|
regex: /startTs/,
|
||||||
@ -381,6 +390,7 @@ const calculatedFieldTimeWindowArgumentValueHighlightRules: AceHighlightRules =
|
|||||||
token: 'tb.calculated-field-limit',
|
token: 'tb.calculated-field-limit',
|
||||||
regex: /limit/,
|
regex: /limit/,
|
||||||
next: 'no_regex'
|
next: 'no_regex'
|
||||||
}
|
},
|
||||||
|
endGroupHighlightRule
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1101,6 +1101,7 @@
|
|||||||
"username": "Username",
|
"username": "Username",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"data": "Data",
|
"data": "Data",
|
||||||
|
"timestamp": "Timestamp",
|
||||||
"enter-username": "Enter username",
|
"enter-username": "Enter username",
|
||||||
"enter-password": "Enter password",
|
"enter-password": "Enter password",
|
||||||
"enter-search": "Enter search",
|
"enter-search": "Enter search",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user