Calculated fields adjustments, improvements and fixes
This commit is contained in:
		
							parent
							
								
									145789882e
								
							
						
					
					
						commit
						eb3f6b137f
					
				@ -54,7 +54,8 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
 | 
			
		||||
              private durationLeft: DurationLeftPipe,
 | 
			
		||||
              private popoverService: TbPopoverService,
 | 
			
		||||
              private destroyRef: DestroyRef,
 | 
			
		||||
              private renderer: Renderer2
 | 
			
		||||
              private renderer: Renderer2,
 | 
			
		||||
              public entityName: string
 | 
			
		||||
  ) {
 | 
			
		||||
    super();
 | 
			
		||||
    this.tableTitle = this.translate.instant('entity.type-calculated-fields');
 | 
			
		||||
@ -159,6 +160,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
 | 
			
		||||
        entityId: this.entityId,
 | 
			
		||||
        debugLimitsConfiguration: this.calculatedFieldsDebugPerTenantLimitsConfiguration,
 | 
			
		||||
        tenantId: this.tenantId,
 | 
			
		||||
        entityName: this.entityName,
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
      .afterClosed();
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,7 @@ export class CalculatedFieldsTableComponent {
 | 
			
		||||
 | 
			
		||||
  active = input<boolean>();
 | 
			
		||||
  entityId = input<EntityId>();
 | 
			
		||||
  entityName = input<string>();
 | 
			
		||||
 | 
			
		||||
  calculatedFieldsTableConfig: CalculatedFieldsTableConfig;
 | 
			
		||||
 | 
			
		||||
@ -71,7 +72,8 @@ export class CalculatedFieldsTableComponent {
 | 
			
		||||
          this.durationLeft,
 | 
			
		||||
          this.popoverService,
 | 
			
		||||
          this.destroyRef,
 | 
			
		||||
          this.renderer
 | 
			
		||||
          this.renderer,
 | 
			
		||||
          this.entityName()
 | 
			
		||||
        );
 | 
			
		||||
        this.cd.markForCheck();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -80,21 +80,26 @@
 | 
			
		||||
                            </mat-chip>
 | 
			
		||||
                        </mat-chip-listbox>
 | 
			
		||||
                    </ng-container>
 | 
			
		||||
                    <div class="flex opacity-55">
 | 
			
		||||
                    <div class="flex">
 | 
			
		||||
                        <button type="button"
 | 
			
		||||
                                mat-icon-button
 | 
			
		||||
                                #button
 | 
			
		||||
                                (click)="manageArgument($event, button, $index)"
 | 
			
		||||
                                [matTooltip]="'action.edit' | translate"
 | 
			
		||||
                                matTooltipPosition="above">
 | 
			
		||||
                            <mat-icon>edit</mat-icon>
 | 
			
		||||
                            <mat-icon class="opacity-55">edit</mat-icon>
 | 
			
		||||
                            @if (argumentsFormArray.dirty
 | 
			
		||||
                            && group.get('refEntityKey').get('type').value === ArgumentType.Rolling
 | 
			
		||||
                            && calculatedFieldType() === CalculatedFieldType.SIMPLE) {
 | 
			
		||||
                              <tb-error class="edit-hint absolute right-0 top-0" [error]="'*'"/>
 | 
			
		||||
                            }
 | 
			
		||||
                        </button>
 | 
			
		||||
                        <button type="button"
 | 
			
		||||
                                mat-icon-button
 | 
			
		||||
                                (click)="onDelete($index)"
 | 
			
		||||
                                [matTooltip]="'action.delete' | translate"
 | 
			
		||||
                                matTooltipPosition="above">
 | 
			
		||||
                            <mat-icon>delete</mat-icon>
 | 
			
		||||
                            <mat-icon class="opacity-55">delete</mat-icon>
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
@ -19,4 +19,9 @@
 | 
			
		||||
      font-size: 14px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .edit-hint {
 | 
			
		||||
    .mat-mdc-form-field-error {
 | 
			
		||||
      font-size: 16px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,9 @@ import {
 | 
			
		||||
  forwardRef,
 | 
			
		||||
  input,
 | 
			
		||||
  Input,
 | 
			
		||||
  OnChanges,
 | 
			
		||||
  Renderer2,
 | 
			
		||||
  SimpleChanges,
 | 
			
		||||
  ViewContainerRef,
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import {
 | 
			
		||||
@ -70,10 +72,11 @@ import { TbPopoverComponent } from '@shared/components/popover.component';
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
})
 | 
			
		||||
export class CalculatedFieldArgumentsTableComponent implements ControlValueAccessor, Validator {
 | 
			
		||||
export class CalculatedFieldArgumentsTableComponent implements ControlValueAccessor, Validator, OnChanges {
 | 
			
		||||
 | 
			
		||||
  @Input() entityId: EntityId;
 | 
			
		||||
  @Input() tenantId: string;
 | 
			
		||||
  @Input() entityName: string;
 | 
			
		||||
 | 
			
		||||
  calculatedFieldType = input<CalculatedFieldType>()
 | 
			
		||||
 | 
			
		||||
@ -84,6 +87,8 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
 | 
			
		||||
  readonly ArgumentTypeTranslations = ArgumentTypeTranslations;
 | 
			
		||||
  readonly EntityType = EntityType;
 | 
			
		||||
  readonly ArgumentEntityType = ArgumentEntityType;
 | 
			
		||||
  readonly ArgumentType = ArgumentType;
 | 
			
		||||
  readonly CalculatedFieldType = CalculatedFieldType;
 | 
			
		||||
 | 
			
		||||
  private popoverComponent: TbPopoverComponent<CalculatedFieldArgumentPanelComponent>;
 | 
			
		||||
  private propagateChange: (argumentsObj: Record<string, CalculatedFieldArgument>) => void = () => {};
 | 
			
		||||
@ -105,6 +110,13 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnChanges(changes: SimpleChanges): void {
 | 
			
		||||
    if (changes.calculatedFieldType?.previousValue
 | 
			
		||||
      && changes.calculatedFieldType.currentValue !== changes.calculatedFieldType.previousValue) {
 | 
			
		||||
      this.argumentsFormArray.markAsDirty();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  registerOnChange(fn: (argumentsObj: Record<string, CalculatedFieldArgument>) => void): void {
 | 
			
		||||
    this.propagateChange = fn;
 | 
			
		||||
  }
 | 
			
		||||
@ -137,6 +149,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
 | 
			
		||||
        calculatedFieldType: this.calculatedFieldType(),
 | 
			
		||||
        buttonTitle: this.argumentsFormArray.at(index)?.value ? 'action.apply' : 'action.add',
 | 
			
		||||
        tenantId: this.tenantId,
 | 
			
		||||
        entityName: this.entityName,
 | 
			
		||||
      };
 | 
			
		||||
      this.popoverComponent = this.popoverService.displayPopover(trigger, this.renderer,
 | 
			
		||||
        this.viewContainerRef, CalculatedFieldArgumentPanelComponent, 'left', false, null,
 | 
			
		||||
@ -202,6 +215,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
 | 
			
		||||
        }),
 | 
			
		||||
      } : {}),
 | 
			
		||||
      refEntityKey: this.fb.group({
 | 
			
		||||
        ...value.refEntityKey,
 | 
			
		||||
        type: [{ value: value.refEntityKey.type, disabled: true }],
 | 
			
		||||
        key: [{ value: value.refEntityKey.key, disabled: true }],
 | 
			
		||||
      }),
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,7 @@
 | 
			
		||||
            formControlName="arguments"
 | 
			
		||||
            [entityId]="data.entityId"
 | 
			
		||||
            [tenantId]="data.tenantId"
 | 
			
		||||
            [entityName]="data.entityName"
 | 
			
		||||
            [calculatedFieldType]="fieldFormGroup.get('type').value"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
@ -114,7 +115,7 @@
 | 
			
		||||
            </mat-form-field>
 | 
			
		||||
            @if (outputFormGroup.get('type').value === OutputType.Attribute) {
 | 
			
		||||
              <mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
                <mat-label>{{ 'calculated-fields.output-type' | translate }}</mat-label>
 | 
			
		||||
                <mat-label>{{ 'calculated-fields.attribute-scope' | translate }}</mat-label>
 | 
			
		||||
                <mat-select formControlName="scope" class="w-full">
 | 
			
		||||
                  <mat-option [value]="AttributeScope.SERVER_SCOPE">
 | 
			
		||||
                    {{ 'calculated-fields.server-attributes' | translate }}
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,7 @@ import { EntityType } from '@shared/models/entity-type.models';
 | 
			
		||||
import { map, startWith } from 'rxjs/operators';
 | 
			
		||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
 | 
			
		||||
import { ScriptLanguage } from '@shared/models/rule-node.models';
 | 
			
		||||
import { merge } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-calculated-field-dialog',
 | 
			
		||||
@ -59,10 +60,10 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
 | 
			
		||||
    }),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  functionArgs$ = this.configFormGroup.valueChanges
 | 
			
		||||
  functionArgs$ = merge(this.configFormGroup.get('arguments').valueChanges, this.fieldFormGroup.get('type').valueChanges)
 | 
			
		||||
    .pipe(
 | 
			
		||||
      startWith(this.data.value?.configuration ?? {}),
 | 
			
		||||
      map(configuration => Object.keys(configuration.arguments))
 | 
			
		||||
      startWith(null),
 | 
			
		||||
      map(() => Object.keys(this.configFormGroup.get('arguments').value ?? this.data.value.configuration.arguments))
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  readonly OutputTypeTranslations = OutputTypeTranslations;
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@
 | 
			
		||||
            }
 | 
			
		||||
          </mat-form-field>
 | 
			
		||||
        </div>
 | 
			
		||||
        @if (entityFilter.singleEntity.id || entityType === ArgumentEntityType.Current || entityType === ArgumentEntityType.Tenant) {
 | 
			
		||||
        @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>
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
 | 
			
		||||
  @Input() argument: CalculatedFieldArgumentValue;
 | 
			
		||||
  @Input() entityId: EntityId;
 | 
			
		||||
  @Input() tenantId: string;
 | 
			
		||||
  @Input() entityName: string;
 | 
			
		||||
  @Input() calculatedFieldType: CalculatedFieldType;
 | 
			
		||||
 | 
			
		||||
  argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>();
 | 
			
		||||
@ -83,6 +84,8 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
 | 
			
		||||
  readonly ArgumentEntityType = ArgumentEntityType;
 | 
			
		||||
  readonly ArgumentEntityTypeParamsMap = ArgumentEntityTypeParamsMap;
 | 
			
		||||
 | 
			
		||||
  private currentEntityFilter: EntityFilter;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private fb: FormBuilder,
 | 
			
		||||
    private cd: ChangeDetectorRef,
 | 
			
		||||
@ -107,6 +110,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.argumentFormGroup.patchValue(this.argument, {emitEvent: false});
 | 
			
		||||
    this.currentEntityFilter = this.getCurrentEntityFilter();
 | 
			
		||||
    this.updateEntityFilter(this.argument.refEntityId?.entityType, true);
 | 
			
		||||
    this.toggleByEntityKeyType(this.argument.refEntityKey?.type);
 | 
			
		||||
    this.setInitialEntityKeyType();
 | 
			
		||||
@ -138,30 +142,53 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateEntityFilter(entityType: ArgumentEntityType = ArgumentEntityType.Current, onInit = false): void {
 | 
			
		||||
    let entityId: EntityId;
 | 
			
		||||
    let entityFilter: EntityFilter;
 | 
			
		||||
    switch (entityType) {
 | 
			
		||||
      case ArgumentEntityType.Current:
 | 
			
		||||
        entityId = this.entityId
 | 
			
		||||
        entityFilter = this.currentEntityFilter;
 | 
			
		||||
        break;
 | 
			
		||||
      case ArgumentEntityType.Tenant:
 | 
			
		||||
        entityId = {
 | 
			
		||||
          id: this.tenantId,
 | 
			
		||||
          entityType: EntityType.TENANT
 | 
			
		||||
        entityFilter = {
 | 
			
		||||
          type: AliasFilterType.singleEntity,
 | 
			
		||||
          singleEntity: {
 | 
			
		||||
            id: this.tenantId,
 | 
			
		||||
            entityType: EntityType.TENANT
 | 
			
		||||
          },
 | 
			
		||||
        };
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        entityId = this.argumentFormGroup.get('refEntityId').value as unknown as EntityId;
 | 
			
		||||
        entityFilter = {
 | 
			
		||||
          type: AliasFilterType.singleEntity,
 | 
			
		||||
          singleEntity: this.argumentFormGroup.get('refEntityId').value as unknown as EntityId,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    if (!onInit) {
 | 
			
		||||
      this.argumentFormGroup.get('refEntityKey').get('key').setValue('');
 | 
			
		||||
    }
 | 
			
		||||
    this.entityFilter = {
 | 
			
		||||
      type: AliasFilterType.singleEntity,
 | 
			
		||||
      singleEntity: entityId,
 | 
			
		||||
    };
 | 
			
		||||
    this.entityFilter = entityFilter;
 | 
			
		||||
    this.cd.markForCheck();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getCurrentEntityFilter(): EntityFilter {
 | 
			
		||||
    switch (this.entityId.entityType) {
 | 
			
		||||
      case EntityType.ASSET_PROFILE:
 | 
			
		||||
        return {
 | 
			
		||||
          deviceTypes: [this.entityName],
 | 
			
		||||
          type: AliasFilterType.assetType
 | 
			
		||||
        };
 | 
			
		||||
      case EntityType.DEVICE_PROFILE:
 | 
			
		||||
        return {
 | 
			
		||||
          deviceTypes: [this.entityName],
 | 
			
		||||
          type: AliasFilterType.deviceType
 | 
			
		||||
        };
 | 
			
		||||
      default:
 | 
			
		||||
        return {
 | 
			
		||||
          type: AliasFilterType.singleEntity,
 | 
			
		||||
          singleEntity: this.entityId,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private observeEntityFilterChanges(): void {
 | 
			
		||||
    merge(
 | 
			
		||||
      this.refEntityIdFormGroup.get('entityType').valueChanges,
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,10 @@
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN && !isEdit"
 | 
			
		||||
         label="{{ 'entity.type-calculated-fields' | translate }}" #calculatedFieldsTab="matTab">
 | 
			
		||||
  <tb-calculated-fields-table [active]="calculatedFieldsTab.isActive" [entityId]="entity.id" [entityName]="entity.name"/>
 | 
			
		||||
</mat-tab>
 | 
			
		||||
<mat-tab *ngIf="entity && !isEdit" #auditLogsTab="matTab"
 | 
			
		||||
         label="{{ 'audit-log.audit-logs' | translate }}">
 | 
			
		||||
  <tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table>
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,10 @@
 | 
			
		||||
                      [entityName]="entity.name">
 | 
			
		||||
  </tb-attribute-table>
 | 
			
		||||
</mat-tab>
 | 
			
		||||
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
 | 
			
		||||
         label="{{ 'entity.type-calculated-fields' | translate }}" #calculatedFieldsTab="matTab">
 | 
			
		||||
  <tb-calculated-fields-table [active]="calculatedFieldsTab.isActive" [entityId]="entity.id"/>
 | 
			
		||||
</mat-tab>
 | 
			
		||||
<mat-tab *ngIf="entity"
 | 
			
		||||
         label="{{ 'alarm.alarms' | translate }}" #alarmsTab="matTab">
 | 
			
		||||
  <tb-alarm-table [active]="alarmsTab.isActive" [entityId]="entity.id"></tb-alarm-table>
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,10 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</mat-tab>
 | 
			
		||||
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN && !isEdit"
 | 
			
		||||
         label="{{ 'entity.type-calculated-fields' | translate }}" #calculatedFieldsTab="matTab">
 | 
			
		||||
  <tb-calculated-fields-table [active]="calculatedFieldsTab.isActive" [entityId]="entity.id" [entityName]="entity.name"/>
 | 
			
		||||
</mat-tab>
 | 
			
		||||
<mat-tab *ngIf="entity && !isEdit" #auditLogsTab="matTab"
 | 
			
		||||
         label="{{ 'audit-log.audit-logs' | translate }}">
 | 
			
		||||
  <tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table>
 | 
			
		||||
 | 
			
		||||
@ -120,6 +120,7 @@ export interface CalculatedFieldDialogData {
 | 
			
		||||
  entityId: EntityId;
 | 
			
		||||
  debugLimitsConfiguration: string;
 | 
			
		||||
  tenantId: string;
 | 
			
		||||
  entityName?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ArgumentEntityTypeParams {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user