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