Fixes
This commit is contained in:
parent
d3216f3ee7
commit
bc835eb9d4
@ -77,12 +77,12 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
|
||||
|
||||
this.defaultSortOrder = {property: 'name', direction: Direction.DESC};
|
||||
|
||||
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>('expression', 'calculated-fields.expression', '50%', entity => entity.configuration.expression));
|
||||
const expressionColumn = new EntityTableColumn<CalculatedField>('expression', 'calculated-fields.expression', '33%', entity => entity.configuration?.expression);
|
||||
expressionColumn.sortable = false;
|
||||
|
||||
this.columns.push(new EntityTableColumn<CalculatedField>('name', 'common.name', '33%'));
|
||||
this.columns.push(new EntityTableColumn<CalculatedField>('type', 'common.type', '50px'));
|
||||
this.columns.push(expressionColumn);
|
||||
|
||||
this.cellActionDescriptors.push(
|
||||
{
|
||||
|
||||
@ -133,7 +133,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
||||
};
|
||||
this.keysPopupClosed = false;
|
||||
const argumentsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
|
||||
this.viewContainerRef, CalculatedFieldArgumentPanelComponent, 'leftBottom', false, null,
|
||||
this.viewContainerRef, CalculatedFieldArgumentPanelComponent, 'left', false, null,
|
||||
ctx,
|
||||
{},
|
||||
{}, {}, true);
|
||||
|
||||
@ -84,10 +84,7 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
|
||||
public fb: UntypedFormBuilder) {
|
||||
super(store, router, dialogRef);
|
||||
this.applyDialogData();
|
||||
this.outputFormGroup.get('type').valueChanges
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe(type => this.toggleScopeByOutputType(type));
|
||||
this.toggleScopeByOutputType(this.outputFormGroup.get('type').value);
|
||||
this.observeTypeChanges();
|
||||
}
|
||||
|
||||
get configFormGroup(): FormGroup {
|
||||
@ -113,10 +110,26 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
|
||||
private applyDialogData(): void {
|
||||
const { configuration = {}, type = CalculatedFieldType.SIMPLE, ...value } = this.data.value;
|
||||
const { expression, ...restConfig } = configuration as CalculatedFieldConfiguration;
|
||||
this.fieldFormGroup.patchValue({ configuration: { ...restConfig, ['expression'+type]: expression }, ...value });
|
||||
this.fieldFormGroup.patchValue({ configuration: { ...restConfig, ['expression'+type]: expression }, type, ...value });
|
||||
}
|
||||
|
||||
private observeTypeChanges(): void {
|
||||
this.toggleKeyByCalculatedFieldType(this.fieldFormGroup.get('type').value);
|
||||
this.toggleScopeByOutputType(this.outputFormGroup.get('type').value);
|
||||
|
||||
this.outputFormGroup.get('type').valueChanges
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe(type => this.toggleScopeByOutputType(type));
|
||||
this.fieldFormGroup.get('type').valueChanges
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe(type => this.toggleKeyByCalculatedFieldType(type));
|
||||
}
|
||||
|
||||
private toggleScopeByOutputType(type: OutputType): void {
|
||||
this.outputFormGroup.get('scope')[type === OutputType.Attribute? 'enable' : 'disable']({emitEvent: false});
|
||||
}
|
||||
|
||||
private toggleKeyByCalculatedFieldType(type: CalculatedFieldType): void {
|
||||
this.outputFormGroup.get('name')[type === CalculatedFieldType.SIMPLE? 'enable' : 'disable']({emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,33 +24,35 @@
|
||||
<div class="tb-flex no-gap">
|
||||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput name="value" formControlName="argumentName" maxlength="255" placeholder="{{ 'action.set' | translate }}"/>
|
||||
@if (argumentFormGroup.get('argumentName').touched) {
|
||||
@if (argumentFormGroup.get('argumentName').hasError('required')) {
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="'calculated-fields.hint.argument-name-required' | translate"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
} @else if (argumentFormGroup.get('argumentName').hasError('pattern')) {
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="'calculated-fields.hint.argument-name-pattern' | translate"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
} @else if (argumentFormGroup.get('argumentName').hasError('maxlength')) {
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="'calculated-fields.hint.argument-name-max-length' | translate"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
<div class="h-5 pr-2">
|
||||
@if (argumentFormGroup.get('argumentName').touched) {
|
||||
@if (argumentFormGroup.get('argumentName').hasError('required')) {
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="'calculated-fields.hint.argument-name-required' | translate"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
} @else if (argumentFormGroup.get('argumentName').hasError('pattern')) {
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="'calculated-fields.hint.argument-name-pattern' | translate"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
} @else if (argumentFormGroup.get('argumentName').hasError('maxlength')) {
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="'calculated-fields.hint.argument-name-max-length' | translate"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
@ -117,40 +119,42 @@
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
@if (refEntityKeyFormGroup.get('type').value !== ArgumentType.Attribute) {
|
||||
<div class="tb-form-row">
|
||||
<div class="fixed-title-width tb-required">{{ 'calculated-fields.timeseries-key' | translate }}</div>
|
||||
<tb-entity-key-autocomplete class="w-full" formControlName="key" [dataKeyType]="DataKeyType.timeseries" [entityFilter]="entityFilter"/>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="tb-form-row">
|
||||
<div class="fixed-title-width tb-required">{{ 'calculated-fields.attribute-scope' | translate }}</div>
|
||||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||||
<mat-select formControlName="scope" class="w-full">
|
||||
<mat-option [value]="AttributeScope.SERVER_SCOPE">
|
||||
{{ 'calculated-fields.server-attributes' | translate }}
|
||||
</mat-option>
|
||||
@if ((keyEntityType$ | async) === EntityType.DEVICE) {
|
||||
<mat-option [value]="AttributeScope.CLIENT_SCOPE">
|
||||
{{ 'calculated-fields.client-attributes' | translate }}
|
||||
@if (entityFilter.singleEntity.id || entityType === ArgumentEntityType.Current || entityType === ArgumentEntityType.Tenant) {
|
||||
@if (refEntityKeyFormGroup.get('type').value !== ArgumentType.Attribute) {
|
||||
<div class="tb-form-row">
|
||||
<div class="fixed-title-width tb-required">{{ 'calculated-fields.timeseries-key' | translate }}</div>
|
||||
<tb-entity-key-autocomplete class="w-full" formControlName="key" [dataKeyType]="DataKeyType.timeseries" [entityFilter]="entityFilter"/>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="tb-form-row">
|
||||
<div class="fixed-title-width tb-required">{{ 'calculated-fields.attribute-scope' | translate }}</div>
|
||||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||||
<mat-select formControlName="scope" class="w-full">
|
||||
<mat-option [value]="AttributeScope.SERVER_SCOPE">
|
||||
{{ 'calculated-fields.server-attributes' | translate }}
|
||||
</mat-option>
|
||||
<mat-option [value]="AttributeScope.SHARED_SCOPE">
|
||||
{{ 'calculated-fields.shared-attributes' | translate }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="tb-form-row">
|
||||
<div class="fixed-title-width tb-required">{{ 'calculated-fields.attribute-key' | translate }}</div>
|
||||
<tb-entity-key-autocomplete
|
||||
formControlName="key"
|
||||
class="w-full"
|
||||
[dataKeyType]="DataKeyType.attribute"
|
||||
[entityFilter]="entityFilter"
|
||||
[keyScopeType]="argumentFormGroup.get('refEntityKey').get('scope').value"
|
||||
/>
|
||||
</div>
|
||||
@if ((keyEntityType$ | async) === EntityType.DEVICE) {
|
||||
<mat-option [value]="AttributeScope.CLIENT_SCOPE">
|
||||
{{ 'calculated-fields.client-attributes' | translate }}
|
||||
</mat-option>
|
||||
<mat-option [value]="AttributeScope.SHARED_SCOPE">
|
||||
{{ 'calculated-fields.shared-attributes' | translate }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="tb-form-row">
|
||||
<div class="fixed-title-width tb-required">{{ 'calculated-fields.attribute-key' | translate }}</div>
|
||||
<tb-entity-key-autocomplete
|
||||
formControlName="key"
|
||||
class="w-full"
|
||||
[dataKeyType]="DataKeyType.attribute"
|
||||
[entityFilter]="entityFilter"
|
||||
[keyScopeType]="argumentFormGroup.get('refEntityKey').get('scope').value"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</ng-container>
|
||||
@if (refEntityKeyFormGroup.get('type').value !== ArgumentType.Rolling) {
|
||||
|
||||
@ -25,5 +25,9 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-form-field-infix {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, ElementRef, Input, OnInit, output, ViewChild } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, ElementRef, Input, OnInit, output, ViewChild } from '@angular/core';
|
||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||
import { PageComponent } from '@shared/components/page.component';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
@ -27,7 +27,7 @@ import {
|
||||
CalculatedFieldArgumentValue,
|
||||
CalculatedFieldType
|
||||
} from '@shared/models/calculated-field.models';
|
||||
import { debounceTime, delay, distinctUntilChanged, filter, map, startWith } from 'rxjs/operators';
|
||||
import { delay, distinctUntilChanged, filter, map, startWith, 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';
|
||||
@ -92,6 +92,7 @@ export class CalculatedFieldArgumentPanelComponent extends PageComponent impleme
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private cd: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
@ -154,22 +155,24 @@ export class CalculatedFieldArgumentPanelComponent extends PageComponent impleme
|
||||
default:
|
||||
entityId = this.argumentFormGroup.get('refEntityId').value as any;
|
||||
}
|
||||
if (onInit) {
|
||||
if (!onInit) {
|
||||
this.argumentFormGroup.get('refEntityKey').get('key').setValue('');
|
||||
}
|
||||
this.entityFilter = {
|
||||
type: AliasFilterType.singleEntity,
|
||||
singleEntity: entityId,
|
||||
};
|
||||
this.cd.markForCheck();
|
||||
}
|
||||
|
||||
private observeEntityFilterChanges(): void {
|
||||
merge(
|
||||
this.refEntityIdFormGroup.get('entityType').valueChanges,
|
||||
this.refEntityKeyFormGroup.get('type').valueChanges,
|
||||
this.refEntityIdFormGroup.get('id').valueChanges.pipe(filter(Boolean)),
|
||||
this.refEntityKeyFormGroup.get('scope').valueChanges,
|
||||
)
|
||||
.pipe(debounceTime(300), delay(50), takeUntilDestroyed())
|
||||
.pipe(throttleTime(100), delay(50), takeUntilDestroyed())
|
||||
.subscribe(() => this.updateEntityFilter(this.entityType));
|
||||
}
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
<a *ngIf="selectEntityFormGroup.get('entity').value && disabled" aria-label="Open device profile" [routerLink]=entityURL>
|
||||
{{ displayEntityFn(selectEntityFormGroup.get('entity').value) }}
|
||||
</a>
|
||||
<mat-icon *ngIf="selectEntityFormGroup.get('entity').hasError('required') && iconError"
|
||||
<mat-icon *ngIf="iconError && selectEntityFormGroup.get('entity').hasError('required') && selectEntityFormGroup.get('entity').touched"
|
||||
matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
-->
|
||||
<mat-form-field class="tb-flex no-gap !w-full" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput type="text" placeholder="{{ 'entity.key-name' | translate }}"
|
||||
<input matInput type="text" placeholder="{{ 'action.set' | translate }}"
|
||||
#keyInput
|
||||
[formControl]="keyControl"
|
||||
required
|
||||
@ -28,12 +28,22 @@
|
||||
(click)="clear()">
|
||||
<mat-icon class="material-icons">close</mat-icon>
|
||||
</button>
|
||||
} @else if (keyControl.hasError('required') && keyControl.touched) {
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="'common.hint.key-required' | translate"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
}
|
||||
<mat-autocomplete
|
||||
class="tb-autocomplete"
|
||||
#keysAutocomplete="matAutocomplete">
|
||||
@for (key of filteredKeys$ | async; track key) {
|
||||
<mat-option [value]="key"><span [innerHTML]="key | highlight: searchText"></span></mat-option>
|
||||
} @empty {
|
||||
<mat-option [value]="''">{{ 'entity.no-keys-found' | translate }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user