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 021bd15c58..f6b82dd954 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
@@ -99,7 +99,7 @@
{{ 'calculated-fields.no-arguments' | translate }}
}
- @if (errorText) {
+ @if (errorText && this.argumentsFormArray.dirty) {
}
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 657b20abb4..7357912bdc 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
@@ -50,7 +50,7 @@ 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 { noLeadTrailSpacesRegex } from '@shared/models/regex.constants';
+import { charNumRegex } from '@shared/models/regex.constants';
@Component({
selector: 'tb-calculated-field-arguments-table',
@@ -98,7 +98,11 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
this.argumentsFormArray.valueChanges.pipe(takeUntilDestroyed()).subscribe(() => {
this.propagateChange(this.getArgumentsObject());
});
- effect(() => this.calculatedFieldType() && this.argumentsFormArray.updateValueAndValidity());
+ effect(() => {
+ if (this.calculatedFieldType() && this.argumentsFormArray.dirty) {
+ this.argumentsFormArray.updateValueAndValidity();
+ }
+ });
}
registerOnChange(fn: (argumentsObj: Record) => void): void {
@@ -183,7 +187,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
private populateArgumentsFormArray(argumentsObj: Record): void {
Object.keys(argumentsObj).forEach(key => {
this.argumentsFormArray.push(this.fb.group({
- argumentName: [key, [Validators.required, Validators.maxLength(255), Validators.pattern(noLeadTrailSpacesRegex)]],
+ argumentName: [key, [Validators.required, Validators.maxLength(255), Validators.pattern(charNumRegex)]],
...argumentsObj[key],
...(argumentsObj[key].refEntityId ? {
refEntityId: this.fb.group({
@@ -202,7 +206,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
private getArgumentFormGroup(value: CalculatedFieldArgumentValue): AbstractControl {
return this.fb.group({
...value,
- argumentName: [value.argumentName, [Validators.required, Validators.maxLength(255), Validators.pattern(noLeadTrailSpacesRegex)]],
+ argumentName: [value.argumentName, [Validators.required, Validators.maxLength(255), Validators.pattern(charNumRegex)]],
...(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/dialog/calculated-field-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts
index 71fea36959..d30a90e954 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts
@@ -110,7 +110,7 @@ export class CalculatedFieldDialogComponent extends DialogComponent
{{ 'calculated-fields.server-attributes' | translate }}
- @if ((keyEntityType$ | async) === EntityType.DEVICE) {
+ @if (entityType === ArgumentEntityType.Device
+ || entityType === ArgumentEntityType.Current && entityId.entityType === EntityType.DEVICE) {
{{ 'calculated-fields.client-attributes' | translate }}
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 79f34d7c20..2949ffdaee 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
@@ -18,7 +18,7 @@ import { ChangeDetectorRef, Component, ElementRef, Input, OnInit, output, ViewCh
import { TbPopoverComponent } from '@shared/components/popover.component';
import { PageComponent } from '@shared/components/page.component';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
-import { noLeadTrailSpacesRegex } from '@shared/models/regex.constants';
+import { charNumRegex, noLeadTrailSpacesRegex } from '@shared/models/regex.constants';
import {
ArgumentEntityType,
ArgumentEntityTypeTranslations,
@@ -27,7 +27,7 @@ import {
CalculatedFieldArgumentValue,
CalculatedFieldType
} from '@shared/models/calculated-field.models';
-import { delay, distinctUntilChanged, filter, map, startWith, throttleTime } from 'rxjs/operators';
+import { delay, distinctUntilChanged, filter, throttleTime } 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';
@@ -57,7 +57,7 @@ export class CalculatedFieldArgumentPanelComponent extends PageComponent impleme
argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>();
argumentFormGroup = this.fb.group({
- argumentName: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex), Validators.maxLength(255)]],
+ argumentName: ['', [Validators.required, Validators.pattern(charNumRegex), Validators.maxLength(255)]],
refEntityId: this.fb.group({
entityType: [ArgumentEntityType.Current],
id: ['']
@@ -74,11 +74,6 @@ export class CalculatedFieldArgumentPanelComponent extends PageComponent impleme
argumentTypes: ArgumentType[];
entityFilter: EntityFilter;
- keyEntityType$ = this.refEntityIdFormGroup.get('entityType').valueChanges
- .pipe(
- startWith(this.refEntityIdFormGroup.get('entityType').value),
- map(type => type === ArgumentEntityType.Current ? this.entityId.entityType : type)
- );
readonly argumentEntityTypes = Object.values(ArgumentEntityType) as ArgumentEntityType[];
readonly ArgumentEntityTypeTranslations = ArgumentEntityTypeTranslations;
@@ -140,7 +135,7 @@ export class CalculatedFieldArgumentPanelComponent extends PageComponent impleme
this.argumentFormGroup.get('defaultValue')[isRolling? 'disable' : 'enable']({ emitEvent: false });
}
- private updateEntityFilter(entityType: ArgumentEntityType, onInit = false): void {
+ private updateEntityFilter(entityType: ArgumentEntityType = ArgumentEntityType.Current, onInit = false): void {
let entityId: EntityId;
switch (entityType) {
case ArgumentEntityType.Current:
diff --git a/ui-ngx/src/app/shared/models/regex.constants.ts b/ui-ngx/src/app/shared/models/regex.constants.ts
index 55742cefd4..60bf154423 100644
--- a/ui-ngx/src/app/shared/models/regex.constants.ts
+++ b/ui-ngx/src/app/shared/models/regex.constants.ts
@@ -15,3 +15,5 @@
///
export const noLeadTrailSpacesRegex = /^\S+(?: \S+)*$/;
+
+export const charNumRegex = /^[a-zA-Z0-9]+$/;
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 be31b4f70b..ab696e226c 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -1030,7 +1030,7 @@
"timeseries-key": "Time series key",
"device-name": "Device name",
"latest-telemetry": "Latest telemetry",
- "rolling": "Rolling",
+ "rolling": "Time series rolling",
"attribute-scope": "Attribute scope",
"server-attributes": "Server attributes",
"client-attributes": "Client attributes",