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