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