|
|
|
@ -28,7 +28,6 @@ import { |
|
|
|
ViewContainerRef, |
|
|
|
} from '@angular/core'; |
|
|
|
import { |
|
|
|
AbstractControl, |
|
|
|
ControlValueAccessor, |
|
|
|
FormBuilder, |
|
|
|
NG_VALIDATORS, |
|
|
|
@ -50,7 +49,7 @@ import { TbPopoverService } from '@shared/components/popover.service'; |
|
|
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|
|
|
import { EntityId } from '@shared/models/id/entity-id'; |
|
|
|
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; |
|
|
|
import { getEntityDetailsPageURL, isDefined, isDefinedAndNotNull, isEqual } from '@core/utils'; |
|
|
|
import { getEntityDetailsPageURL, isEqual } from '@core/utils'; |
|
|
|
import { TbPopoverComponent } from '@shared/components/popover.component'; |
|
|
|
import { TbTableDatasource } from '@shared/components/table/table-datasource.abstract'; |
|
|
|
import { EntityService } from '@core/http/entity.service'; |
|
|
|
@ -58,8 +57,9 @@ import { MatSort } from '@angular/material/sort'; |
|
|
|
import { getCurrentAuthState } from '@core/auth/auth.selectors'; |
|
|
|
import { Store } from '@ngrx/store'; |
|
|
|
import { AppState } from '@core/core.state'; |
|
|
|
import { catchError } from 'rxjs/operators'; |
|
|
|
import { NEVER } from 'rxjs'; |
|
|
|
import { forkJoin, Observable } from 'rxjs'; |
|
|
|
import { NULL_UUID } from '@shared/models/id/has-uuid'; |
|
|
|
import { BaseData } from '@shared/models/base-data'; |
|
|
|
|
|
|
|
@Component({ |
|
|
|
selector: 'tb-calculated-field-arguments-table', |
|
|
|
@ -88,9 +88,8 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
@ViewChild(MatSort, { static: true }) sort: MatSort; |
|
|
|
|
|
|
|
errorText = ''; |
|
|
|
argumentsFormArray = this.fb.array<AbstractControl>([]); |
|
|
|
argumentsFormArray = this.fb.array<CalculatedFieldArgumentValue>([]); |
|
|
|
entityNameMap = new Map<string, string>(); |
|
|
|
entityNameErrorSet = new Set<string>(); |
|
|
|
sortOrder = { direction: 'asc', property: '' }; |
|
|
|
dataSource = new CalculatedFieldArgumentDatasource(); |
|
|
|
|
|
|
|
@ -100,6 +99,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
readonly ArgumentType = ArgumentType; |
|
|
|
readonly CalculatedFieldType = CalculatedFieldType; |
|
|
|
readonly maxArgumentsPerCF = getCurrentAuthState(this.store).maxArgumentsPerCF; |
|
|
|
readonly NULL_UUID = NULL_UUID; |
|
|
|
|
|
|
|
private popoverComponent: TbPopoverComponent<CalculatedFieldArgumentPanelComponent>; |
|
|
|
private propagateChange: (argumentsObj: Record<string, CalculatedFieldArgument>) => void = () => {}; |
|
|
|
@ -115,7 +115,6 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
private store: Store<AppState> |
|
|
|
) { |
|
|
|
this.argumentsFormArray.valueChanges.pipe(takeUntilDestroyed()).subscribe(value => { |
|
|
|
this.updateEntityNameMap(value); |
|
|
|
this.updateDataSource(value); |
|
|
|
this.propagateChange(this.getArgumentsObject(value)); |
|
|
|
}); |
|
|
|
@ -154,7 +153,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
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(); |
|
|
|
if (this.popoverComponent && !this.popoverComponent.tbHidden) { |
|
|
|
this.popoverComponent.hide(); |
|
|
|
@ -163,15 +162,16 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
if (this.popoverService.hasPopover(trigger)) { |
|
|
|
this.popoverService.hidePopover(trigger); |
|
|
|
} else { |
|
|
|
const index = this.argumentsFormArray.controls.findIndex(control => isEqual(control.value, argument)); |
|
|
|
const isExists = index !== -1; |
|
|
|
const ctx = { |
|
|
|
index, |
|
|
|
argument, |
|
|
|
entityId: this.entityId, |
|
|
|
calculatedFieldType: this.calculatedFieldType, |
|
|
|
buttonTitle: this.argumentsFormArray.at(index)?.value ? 'action.apply' : 'action.add', |
|
|
|
buttonTitle: isExists ? 'action.apply' : 'action.add', |
|
|
|
tenantId: this.tenantId, |
|
|
|
entityName: this.entityName, |
|
|
|
entityHasError: this.entityNameErrorSet.has(argument.refEntityId?.id), |
|
|
|
usedArgumentNames: this.argumentsFormArray.value.map(({ argumentName }) => argumentName).filter(name => name !== argument.argumentName), |
|
|
|
}; |
|
|
|
this.popoverComponent = this.popoverService.displayPopover({ |
|
|
|
@ -179,19 +179,20 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
renderer: this.renderer, |
|
|
|
componentType: CalculatedFieldArgumentPanelComponent, |
|
|
|
hostView: this.viewContainerRef, |
|
|
|
preferredPlacement: isDefined(index) ? 'left' : 'right', |
|
|
|
preferredPlacement: isExists ? 'left' : 'right', |
|
|
|
context: ctx, |
|
|
|
isModal: true |
|
|
|
}); |
|
|
|
this.popoverComponent.tbComponentRef.instance.argumentsDataApplied.subscribe(({ value, index }) => { |
|
|
|
this.popoverComponent.tbComponentRef.instance.argumentsDataApplied.subscribe(({ entityName, ...value }) => { |
|
|
|
this.popoverComponent.hide(); |
|
|
|
const formGroup = this.fb.group(value); |
|
|
|
if (isDefinedAndNotNull(index)) { |
|
|
|
this.argumentsFormArray.setControl(index, formGroup); |
|
|
|
if (entityName) { |
|
|
|
this.entityNameMap.set(value.refEntityId.id, entityName); |
|
|
|
} |
|
|
|
if (isExists) { |
|
|
|
this.argumentsFormArray.at(index).setValue(value); |
|
|
|
} else { |
|
|
|
this.argumentsFormArray.push(formGroup); |
|
|
|
this.argumentsFormArray.push(this.fb.control(value)); |
|
|
|
} |
|
|
|
formGroup.markAsDirty(); |
|
|
|
this.cd.markForCheck(); |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -206,7 +207,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
if (this.calculatedFieldType === CalculatedFieldType.SIMPLE |
|
|
|
&& this.argumentsFormArray.controls.some(control => control.value.refEntityKey.type === ArgumentType.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'; |
|
|
|
} else if (!this.argumentsFormArray.controls.length) { |
|
|
|
this.errorText = 'calculated-fields.hint.arguments-empty'; |
|
|
|
@ -225,7 +226,8 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
|
|
|
|
writeValue(argumentsObj: Record<string, CalculatedFieldArgument>): void { |
|
|
|
this.argumentsFormArray.clear(); |
|
|
|
this.populateArgumentsFormArray(argumentsObj) |
|
|
|
this.populateArgumentsFormArray(argumentsObj); |
|
|
|
this.updateEntityNameMap(this.argumentsFormArray.value); |
|
|
|
} |
|
|
|
|
|
|
|
getEntityDetailsPageURL(id: string, type: EntityType): string { |
|
|
|
@ -238,27 +240,48 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces |
|
|
|
...argumentsObj[key], |
|
|
|
argumentName: key |
|
|
|
}; |
|
|
|
this.argumentsFormArray.push(this.fb.group(value), { emitEvent: false }); |
|
|
|
this.argumentsFormArray.push(this.fb.control(value), { emitEvent: false }); |
|
|
|
}); |
|
|
|
this.argumentsFormArray.updateValueAndValidity(); |
|
|
|
} |
|
|
|
|
|
|
|
private updateEntityNameMap(value: CalculatedFieldArgumentValue[]): void { |
|
|
|
this.entityNameErrorSet.clear(); |
|
|
|
value.forEach(({ refEntityId = {}}) => { |
|
|
|
if (refEntityId.id && !this.entityNameMap.has(refEntityId.id)) { |
|
|
|
private updateEntityNameMap(values: CalculatedFieldArgumentValue[]): void { |
|
|
|
const entitiesByType = values.reduce((acc, { refEntityId = {}}) => { |
|
|
|
if (refEntityId.id && refEntityId.entityType !== ArgumentEntityType.Tenant) { |
|
|
|
const { id, entityType } = refEntityId as EntityId; |
|
|
|
this.entityService.getEntity(entityType as EntityType, id, { ignoreLoading: true, ignoreErrors: true }) |
|
|
|
.pipe( |
|
|
|
catchError(() => { |
|
|
|
this.entityNameErrorSet.add(id); |
|
|
|
return NEVER; |
|
|
|
}), |
|
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
|
) |
|
|
|
.subscribe(entity => this.entityNameMap.set(id, entity.name)); |
|
|
|
acc[entityType] = acc[entityType] ?? []; |
|
|
|
acc[entityType].push(id); |
|
|
|
} |
|
|
|
}); |
|
|
|
return acc; |
|
|
|
}, {} as Record<EntityType, string[]>); |
|
|
|
const tasks = Object.entries(entitiesByType).map(([entityType, ids]) => |
|
|
|
this.entityService.getEntities(entityType as EntityType, ids) |
|
|
|
); |
|
|
|
if (!tasks.length) { |
|
|
|
return; |
|
|
|
} |
|
|
|
this.fetchEntityNames(tasks, values); |
|
|
|
} |
|
|
|
|
|
|
|
private fetchEntityNames(tasks: Observable<BaseData<EntityId>[]>[], values: CalculatedFieldArgumentValue[]): void { |
|
|
|
forkJoin(tasks as Observable<BaseData<EntityId>[]>[]) |
|
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
|
.subscribe((result: Array<BaseData<EntityId>>[]) => { |
|
|
|
result.forEach((entities: BaseData<EntityId>[]) => entities.forEach((entity: BaseData<EntityId>) => this.entityNameMap.set(entity.id.id, entity.name))); |
|
|
|
let updateTable = false; |
|
|
|
values.forEach(({ refEntityId }) => { |
|
|
|
if (refEntityId?.id && !this.entityNameMap.has(refEntityId.id) && refEntityId.entityType !== ArgumentEntityType.Tenant) { |
|
|
|
updateTable = true; |
|
|
|
const control = this.argumentsFormArray.controls.find(control => control.value.refEntityId?.id === refEntityId.id); |
|
|
|
const value = control.value; |
|
|
|
value.refEntityId.id = NULL_UUID; |
|
|
|
control.setValue(value, { emitEvent: false }); |
|
|
|
} |
|
|
|
}); |
|
|
|
if (updateTable) { |
|
|
|
this.argumentsFormArray.updateValueAndValidity(); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private getSortValue(argument: CalculatedFieldArgumentValue, column: string): string { |
|
|
|
|