Browse Source

Fixed Calculated fields creation of arguments with same name and adjustments

pull/13042/head
mpetrov 2 years ago
parent
commit
609ba690f5
  1. 2
      ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts
  2. 6
      ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html
  3. 36
      ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts
  4. 11
      ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts
  5. 2
      ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.html

2
ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts

@ -160,7 +160,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
private getExpressionLabel(entity: CalculatedField): string { private getExpressionLabel(entity: CalculatedField): string {
if (entity.type === CalculatedFieldType.SCRIPT) { if (entity.type === CalculatedFieldType.SCRIPT) {
return 'function calculate(' + Object.keys(entity.configuration.arguments).join(', ') + ')'; return 'function calculate(ctx, ' + Object.keys(entity.configuration.arguments).join(', ') + ')';
} else { } else {
return entity.configuration.expression; return entity.configuration.expression;
} }

6
ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html

@ -87,17 +87,17 @@
</ng-container> </ng-container>
<ng-container matColumnDef="actions" stickyEnd> <ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef class="w-20 min-w-20"/> <mat-header-cell *matHeaderCellDef class="w-20 min-w-20"/>
<mat-cell *matCellDef="let argument; let $index = index"> <mat-cell *matCellDef="let argument;">
<div class="tb-form-table-row-cell-buttons flex w-20 min-w-20"> <div class="tb-form-table-row-cell-buttons flex w-20 min-w-20">
<button type="button" <button type="button"
mat-icon-button mat-icon-button
#button #button
(click)="manageArgument($event, button, argument, $index)" (click)="manageArgument($event, button, argument)"
[matTooltip]="'action.edit' | translate" [matTooltip]="'action.edit' | translate"
matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon <mat-icon
[matBadgeHidden]="!(argument.refEntityKey.type === ArgumentType.Rolling [matBadgeHidden]="!(argument.refEntityKey.type === ArgumentType.Rolling
&& calculatedFieldType === CalculatedFieldType.SIMPLE) && !entityNameErrorSet.has(argument.refEntityId?.id)" && calculatedFieldType === CalculatedFieldType.SIMPLE) && argument.refEntityId?.id !== NULL_UUID"
matBadgeColor="warn" matBadgeColor="warn"
matBadgeSize="small" matBadgeSize="small"
matBadge="*" matBadge="*"

36
ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts

@ -28,7 +28,6 @@ import {
ViewContainerRef, ViewContainerRef,
} from '@angular/core'; } from '@angular/core';
import { import {
AbstractControl,
ControlValueAccessor, ControlValueAccessor,
FormBuilder, FormBuilder,
NG_VALIDATORS, NG_VALIDATORS,
@ -60,6 +59,7 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
import { NEVER } from 'rxjs'; import { NEVER } from 'rxjs';
import { NULL_UUID } from '@shared/models/id/has-uuid';
@Component({ @Component({
selector: 'tb-calculated-field-arguments-table', selector: 'tb-calculated-field-arguments-table',
@ -88,9 +88,8 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
@ViewChild(MatSort, { static: true }) sort: MatSort; @ViewChild(MatSort, { static: true }) sort: MatSort;
errorText = ''; errorText = '';
argumentsFormArray = this.fb.array<AbstractControl>([]); argumentsFormArray = this.fb.array<CalculatedFieldArgumentValue>([]);
entityNameMap = new Map<string, string>(); entityNameMap = new Map<string, string>([[NULL_UUID, '']]);
entityNameErrorSet = new Set<string>();
sortOrder = { direction: 'asc', property: '' }; sortOrder = { direction: 'asc', property: '' };
dataSource = new CalculatedFieldArgumentDatasource(); dataSource = new CalculatedFieldArgumentDatasource();
@ -100,6 +99,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
readonly ArgumentType = ArgumentType; readonly ArgumentType = ArgumentType;
readonly CalculatedFieldType = CalculatedFieldType; readonly CalculatedFieldType = CalculatedFieldType;
readonly maxArgumentsPerCF = getCurrentAuthState(this.store).maxArgumentsPerCF; readonly maxArgumentsPerCF = getCurrentAuthState(this.store).maxArgumentsPerCF;
readonly NULL_UUID = NULL_UUID;
private popoverComponent: TbPopoverComponent<CalculatedFieldArgumentPanelComponent>; private popoverComponent: TbPopoverComponent<CalculatedFieldArgumentPanelComponent>;
private propagateChange: (argumentsObj: Record<string, CalculatedFieldArgument>) => void = () => {}; private propagateChange: (argumentsObj: Record<string, CalculatedFieldArgument>) => void = () => {};
@ -154,7 +154,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
this.argumentsFormArray.markAsDirty(); this.argumentsFormArray.markAsDirty();
} }
manageArgument($event: Event, matButton: MatButton, argument = {} as CalculatedFieldArgumentValue, index?: number): void { manageArgument($event: Event, matButton: MatButton, argument = {} as CalculatedFieldArgumentValue): void {
$event?.stopPropagation(); $event?.stopPropagation();
if (this.popoverComponent && !this.popoverComponent.tbHidden) { if (this.popoverComponent && !this.popoverComponent.tbHidden) {
this.popoverComponent.hide(); this.popoverComponent.hide();
@ -163,31 +163,30 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
if (this.popoverService.hasPopover(trigger)) { if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger); this.popoverService.hidePopover(trigger);
} else { } else {
const index = this.argumentsFormArray.controls.findIndex(control => isEqual(control.value, argument));
const isExists = index !== -1;
const ctx = { const ctx = {
index, index,
argument, argument,
entityId: this.entityId, entityId: this.entityId,
calculatedFieldType: this.calculatedFieldType, calculatedFieldType: this.calculatedFieldType,
buttonTitle: this.argumentsFormArray.at(index)?.value ? 'action.apply' : 'action.add', buttonTitle: isExists ? 'action.apply' : 'action.add',
tenantId: this.tenantId, tenantId: this.tenantId,
entityName: this.entityName, entityName: this.entityName,
entityHasError: this.entityNameErrorSet.has(argument.refEntityId?.id),
usedArgumentNames: this.argumentsFormArray.value.map(({ argumentName }) => argumentName).filter(name => name !== argument.argumentName), usedArgumentNames: this.argumentsFormArray.value.map(({ argumentName }) => argumentName).filter(name => name !== argument.argumentName),
}; };
this.popoverComponent = this.popoverService.displayPopover(trigger, this.renderer, this.popoverComponent = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, CalculatedFieldArgumentPanelComponent, isDefined(index) ? 'left' : 'right', false, null, this.viewContainerRef, CalculatedFieldArgumentPanelComponent, isExists ? 'left' : 'right', false, null,
ctx, ctx,
{}, {},
{}, {}, true); {}, {}, true);
this.popoverComponent.tbComponentRef.instance.argumentsDataApplied.subscribe(({ value, index }) => { this.popoverComponent.tbComponentRef.instance.argumentsDataApplied.subscribe((value ) => {
this.popoverComponent.hide(); this.popoverComponent.hide();
const formGroup = this.fb.group(value); if (isExists) {
if (isDefinedAndNotNull(index)) { this.argumentsFormArray.at(index).setValue(value);
this.argumentsFormArray.setControl(index, formGroup);
} else { } else {
this.argumentsFormArray.push(formGroup); this.argumentsFormArray.push(this.fb.control(value));
} }
formGroup.markAsDirty();
this.cd.markForCheck(); this.cd.markForCheck();
}); });
} }
@ -202,7 +201,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
if (this.calculatedFieldType === CalculatedFieldType.SIMPLE if (this.calculatedFieldType === CalculatedFieldType.SIMPLE
&& this.argumentsFormArray.controls.some(control => control.value.refEntityKey.type === ArgumentType.Rolling)) { && this.argumentsFormArray.controls.some(control => control.value.refEntityKey.type === ArgumentType.Rolling)) {
this.errorText = 'calculated-fields.hint.arguments-simple-with-rolling'; this.errorText = 'calculated-fields.hint.arguments-simple-with-rolling';
} else if (this.entityNameErrorSet.size) { } else if (this.argumentsFormArray.controls.some(control => control.value.refEntityId?.id === NULL_UUID)) {
this.errorText = 'calculated-fields.hint.arguments-entity-not-found'; this.errorText = 'calculated-fields.hint.arguments-entity-not-found';
} else if (!this.argumentsFormArray.controls.length) { } else if (!this.argumentsFormArray.controls.length) {
this.errorText = 'calculated-fields.hint.arguments-empty'; this.errorText = 'calculated-fields.hint.arguments-empty';
@ -234,20 +233,21 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
...argumentsObj[key], ...argumentsObj[key],
argumentName: key argumentName: key
}; };
this.argumentsFormArray.push(this.fb.group(value), { emitEvent: false }); this.argumentsFormArray.push(this.fb.control(value), { emitEvent: false });
}); });
this.argumentsFormArray.updateValueAndValidity(); this.argumentsFormArray.updateValueAndValidity();
} }
private updateEntityNameMap(value: CalculatedFieldArgumentValue[]): void { private updateEntityNameMap(value: CalculatedFieldArgumentValue[]): void {
this.entityNameErrorSet.clear();
value.forEach(({ refEntityId = {}}) => { value.forEach(({ refEntityId = {}}) => {
if (refEntityId.id && !this.entityNameMap.has(refEntityId.id)) { if (refEntityId.id && !this.entityNameMap.has(refEntityId.id)) {
const { id, entityType } = refEntityId as EntityId; const { id, entityType } = refEntityId as EntityId;
this.entityService.getEntity(entityType as EntityType, id, { ignoreLoading: true, ignoreErrors: true }) this.entityService.getEntity(entityType as EntityType, id, { ignoreLoading: true, ignoreErrors: true })
.pipe( .pipe(
catchError(() => { catchError(() => {
this.entityNameErrorSet.add(id); const control = this.argumentsFormArray.controls.find(control => control.value.refEntityId?.id === id);
control.setValue({ ...control.value, refEntityId: { ...control.value.refEntityId, id: NULL_UUID } });
return NEVER; return NEVER;
}), }),
takeUntilDestroyed(this.destroyRef) takeUntilDestroyed(this.destroyRef)

11
ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts

@ -42,6 +42,7 @@ import { getCurrentAuthState } from '@core/auth/auth.selectors';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { EntityAutocompleteComponent } from '@shared/components/entity/entity-autocomplete.component'; import { EntityAutocompleteComponent } from '@shared/components/entity/entity-autocomplete.component';
import { NULL_UUID } from '@shared/models/id/has-uuid';
@Component({ @Component({
selector: 'tb-calculated-field-argument-panel', selector: 'tb-calculated-field-argument-panel',
@ -51,18 +52,16 @@ import { EntityAutocompleteComponent } from '@shared/components/entity/entity-au
export class CalculatedFieldArgumentPanelComponent implements OnInit, AfterViewInit { export class CalculatedFieldArgumentPanelComponent implements OnInit, AfterViewInit {
@Input() buttonTitle: string; @Input() buttonTitle: string;
@Input() index: number;
@Input() argument: CalculatedFieldArgumentValue; @Input() argument: CalculatedFieldArgumentValue;
@Input() entityId: EntityId; @Input() entityId: EntityId;
@Input() tenantId: string; @Input() tenantId: string;
@Input() entityName: string; @Input() entityName: string;
@Input() entityHasError: boolean;
@Input() calculatedFieldType: CalculatedFieldType; @Input() calculatedFieldType: CalculatedFieldType;
@Input() usedArgumentNames: string[]; @Input() usedArgumentNames: string[];
@ViewChild('entityAutocomplete') entityAutocomplete: EntityAutocompleteComponent; @ViewChild('entityAutocomplete') entityAutocomplete: EntityAutocompleteComponent;
argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>(); argumentsDataApplied = output<CalculatedFieldArgumentValue>();
readonly maxDataPointsPerRollingArg = getCurrentAuthState(this.store).maxDataPointsPerRollingArg; readonly maxDataPointsPerRollingArg = getCurrentAuthState(this.store).maxDataPointsPerRollingArg;
readonly defaultLimit = Math.floor(this.maxDataPointsPerRollingArg / 10); readonly defaultLimit = Math.floor(this.maxDataPointsPerRollingArg / 10);
@ -106,7 +105,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit, AfterViewI
private store: Store<AppState> private store: Store<AppState>
) { ) {
this.observeEntityFilterChanges(); this.observeEntityFilterChanges();
this.observeEntityTypeChanges() this.observeEntityTypeChanges();
this.observeEntityKeyChanges(); this.observeEntityKeyChanges();
this.observeUpdatePosition(); this.observeUpdatePosition();
} }
@ -141,7 +140,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit, AfterViewI
} }
ngAfterViewInit(): void { ngAfterViewInit(): void {
if (this.entityHasError) { if (this.argument.refEntityId.id === NULL_UUID) {
this.entityAutocomplete.selectEntityFormGroup.get('entity').markAsTouched(); this.entityAutocomplete.selectEntityFormGroup.get('entity').markAsTouched();
} }
} }
@ -156,7 +155,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit, AfterViewI
value.defaultValue = value.defaultValue.trim(); value.defaultValue = value.defaultValue.trim();
} }
value.refEntityKey.key = value.refEntityKey.key.trim(); value.refEntityKey.key = value.refEntityKey.key.trim();
this.argumentsDataApplied.emit({ value, index: this.index }); this.argumentsDataApplied.emit(value);
} }
cancel(): void { cancel(): void {

2
ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.html

@ -53,7 +53,7 @@
color="primary" color="primary"
type="button" type="button"
(click)="onCancel(); additionalActionConfig.action()"> (click)="onCancel(); additionalActionConfig.action()">
{{ additionalActionConfig.title | translate }} {{ additionalActionConfig.title }}
</button> </button>
} }
</div> </div>

Loading…
Cancel
Save