Merge pull request #12743 from maxunbearable/feature/calculated-fields-adjustments-24-02
Calculated fields adjustments
This commit is contained in:
commit
bd1e67a185
@ -16,80 +16,78 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<div class="tb-form-table">
|
<div class="tb-form-panel stroked no-padding no-gap arguments-table flex flex-col" [class.arguments-table-with-error]="errorText">
|
||||||
<div class="tb-form-table-header">
|
<table mat-table [dataSource]="dataSource" class="overflow-hidden bg-transparent" matSort
|
||||||
<div class="argument-name-field tb-form-table-header-cell w-1/6 xs:w-1/3 sm:w-1/4" tbTruncateWithTooltip>{{ 'calculated-fields.argument-name' | translate }}</div>
|
[matSortActive]="sortOrder.property" [matSortDirection]="sortOrder.direction" matSortDisableClear>
|
||||||
<div class="tb-form-table-header-cell w-1/3 xs:hidden">{{ 'calculated-fields.datasource' | translate }}</div>
|
<ng-container [matColumnDef]="'name'">
|
||||||
<div class="tb-form-table-header-cell w-1/6 lt-md:hidden">{{ 'common.type' | translate }}</div>
|
<mat-header-cell mat-sort-header *matHeaderCellDef class="!w-1/4 xs:!w-1/2">
|
||||||
<div class="tb-form-table-header-cell w-1/6 xs:w-1/3">{{ 'entity.key' | translate }}</div>
|
<div tbTruncateWithTooltip>{{ 'common.name' | translate }}</div>
|
||||||
<div class="tb-form-table-header-cell w-20 min-w-20"></div>
|
</mat-header-cell>
|
||||||
</div>
|
<mat-cell *matCellDef="let argument" class="w-1/4 xs:w-1/2">
|
||||||
<div class="tb-form-table-body">
|
<div tbTruncateWithTooltip>{{ argument.argumentName }}</div>
|
||||||
@for (group of argumentsFormArray.controls; track group) {
|
</mat-cell>
|
||||||
<div [formGroup]="group" class="tb-form-table-row">
|
|
||||||
<mat-form-field appearance="outline" class="argument-name-field tb-inline-field w-1/6 xs:w-1/3 sm:w-1/4" subscriptSizing="dynamic">
|
|
||||||
<input matInput formControlName="argumentName" placeholder="{{ 'action.set' | translate }}">
|
|
||||||
</mat-form-field>
|
|
||||||
<section class="datasource-field flex w-1/3 gap-2 xs:hidden">
|
|
||||||
@if (group.get('refEntityId')?.get('id')?.value) {
|
|
||||||
<ng-container [formGroup]="group.get('refEntityId')">
|
|
||||||
<mat-form-field appearance="outline" class="tb-inline-field w-1/2" subscriptSizing="dynamic">
|
|
||||||
<mat-select [value]="group.get('refEntityId').get('entityType').value" formControlName="entityType">
|
|
||||||
<mat-option [value]="group.get('refEntityId').get('entityType').value">
|
|
||||||
{{ entityTypeTranslations.get(group.get('refEntityId').get('entityType').value)?.type | translate }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<tb-entity-autocomplete
|
|
||||||
class="entity-field w-1/2"
|
|
||||||
formControlName="id"
|
|
||||||
[inlineField]="true"
|
|
||||||
[hideLabel]="true"
|
|
||||||
[placeholder]="'action.set' | translate"
|
|
||||||
[entityType]="group.get('refEntityId').get('entityType').value"
|
|
||||||
/>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
} @else {
|
<ng-container [matColumnDef]="'entityType'">
|
||||||
<mat-form-field appearance="outline" class="tb-inline-field flex-1" subscriptSizing="dynamic">
|
<mat-header-cell mat-sort-header *matHeaderCellDef class="entity-type-header w-1/4 xs:hidden">
|
||||||
<mat-select [value]="'current'" [disabled]="true">
|
{{ 'entity.entity-type' | translate }}
|
||||||
<mat-option [value]="'current'">
|
</mat-header-cell>
|
||||||
{{
|
<mat-cell *matCellDef="let argument" class="w-1/4 xs:hidden">
|
||||||
(group.get('refEntityId')?.get('entityType')?.value === ArgumentEntityType.Tenant
|
|
||||||
? 'calculated-fields.argument-current-tenant'
|
|
||||||
: 'calculated-fields.argument-current') | translate
|
|
||||||
}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
}
|
|
||||||
</section>
|
|
||||||
<ng-container [formGroup]="group.get('refEntityKey')">
|
|
||||||
<mat-form-field appearance="outline" class="tb-inline-field w-1/6 lt-md:hidden" subscriptSizing="dynamic">
|
|
||||||
@if (group.get('refEntityKey').get('type').value; as type) {
|
|
||||||
<mat-select [value]="type" formControlName="type">
|
|
||||||
<mat-option [value]="type">
|
|
||||||
{{ ArgumentTypeTranslations.get(type) | translate }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-chip-listbox formControlName="key" class="tb-inline-field entity-key-field w-1/6 xs:w-1/3">
|
|
||||||
<mat-chip>
|
|
||||||
<div tbTruncateWithTooltip>
|
<div tbTruncateWithTooltip>
|
||||||
{{ group.get('refEntityKey').get('key').value }}
|
@if (argument.refEntityId?.entityType === ArgumentEntityType.Tenant) {
|
||||||
|
{{ 'calculated-fields.argument-current-tenant' | translate }}
|
||||||
|
} @else if (argument.refEntityId?.id) {
|
||||||
|
{{ entityTypeTranslations.get(argument.refEntityId.entityType).type | translate }}
|
||||||
|
} @else {
|
||||||
|
{{ 'calculated-fields.argument-current' | translate }}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</mat-chip>
|
</mat-cell>
|
||||||
</mat-chip-listbox>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<ng-container [matColumnDef]="'target'">
|
||||||
|
<mat-header-cell *matHeaderCellDef class="w-1/4 xs:hidden">
|
||||||
|
{{ 'entity-view.target-entity' | translate }}
|
||||||
|
</mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let argument" class="w-1/4 xs:hidden">
|
||||||
|
<div tbTruncateWithTooltip>
|
||||||
|
@if (argument.refEntityId?.id) {
|
||||||
|
<a aria-label="Open entity details page"
|
||||||
|
[routerLink]="getEntityDetailsPageURL(argument.refEntityId.id, argument.refEntityId.entityType)">
|
||||||
|
{{ entityNameMap.get(argument.refEntityId.id) ?? '' }}
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container [matColumnDef]="'type'">
|
||||||
|
<mat-header-cell mat-sort-header *matHeaderCellDef class="w-1/4 lt-md:hidden">
|
||||||
|
{{ 'common.type' | translate }}
|
||||||
|
</mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let argument" class="w-1/4 lt-md:hidden">
|
||||||
|
<div tbTruncateWithTooltip>{{ ArgumentTypeTranslations.get(argument.refEntityKey.type) | translate }}</div>
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container [matColumnDef]="'key'">
|
||||||
|
<mat-header-cell mat-sort-header *matHeaderCellDef class="w-1/4 xs:w-1/3">
|
||||||
|
{{ 'entity.key' | translate }}
|
||||||
|
</mat-header-cell>
|
||||||
|
<mat-cell *matCellDef="let argument" class="w-1/4 xs:w-1/3">
|
||||||
|
<mat-chip>
|
||||||
|
<div tbTruncateWithTooltip class="key-text">{{ argument.refEntityKey.key }}</div>
|
||||||
|
</mat-chip>
|
||||||
|
</mat-cell>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="actions" stickyEnd>
|
||||||
|
<mat-header-cell *matHeaderCellDef class="w-20 min-w-20"/>
|
||||||
|
<mat-cell *matCellDef="let argument; let $index = index">
|
||||||
<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, $index)"
|
(click)="manageArgument($event, button, argument, $index)"
|
||||||
[matTooltip]="'action.edit' | translate"
|
[matTooltip]="'action.edit' | translate"
|
||||||
matTooltipPosition="above">
|
matTooltipPosition="above">
|
||||||
<mat-icon
|
<mat-icon
|
||||||
[matBadgeHidden]="!(group.get('refEntityKey').get('type').value === ArgumentType.Rolling
|
[matBadgeHidden]="!(argument.refEntityKey.type === ArgumentType.Rolling
|
||||||
&& calculatedFieldType === CalculatedFieldType.SIMPLE)"
|
&& calculatedFieldType === CalculatedFieldType.SIMPLE)"
|
||||||
matBadgeColor="warn"
|
matBadgeColor="warn"
|
||||||
matBadgeSize="small"
|
matBadgeSize="small"
|
||||||
@ -100,19 +98,25 @@
|
|||||||
</button>
|
</button>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
(click)="onDelete($index)"
|
(click)="onDelete($event, $index)"
|
||||||
[matTooltip]="'action.delete' | translate"
|
[matTooltip]="'action.delete' | translate"
|
||||||
matTooltipPosition="above">
|
matTooltipPosition="above">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</mat-cell>
|
||||||
} @empty {
|
</ng-container>
|
||||||
<span class="tb-prompt flex items-center justify-center">{{ 'calculated-fields.no-arguments' | translate }}</span>
|
<mat-header-row class="mat-row-select"
|
||||||
}
|
*matHeaderRowDef="['name', 'entityType', 'target', 'type', 'key', 'actions']; sticky: true"></mat-header-row>
|
||||||
|
<mat-row
|
||||||
|
*matRowDef="let argument; columns: ['name', 'entityType', 'target', 'type', 'key', 'actions']"></mat-row>
|
||||||
|
</table>
|
||||||
|
<div [class.!hidden]="(dataSource.isEmpty() | async) === false"
|
||||||
|
class="tb-prompt flex flex-1 items-end justify-center">
|
||||||
|
{{ 'calculated-fields.no-arguments' | translate }}
|
||||||
</div>
|
</div>
|
||||||
@if (errorText) {
|
@if (errorText) {
|
||||||
<tb-error noMargin [error]="errorText | translate" class="pl-3"/>
|
<tb-error noMargin [error]="errorText | translate" class="flex h-9 items-center pl-3"/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -13,11 +13,21 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
@use '../../../../../../../scss/constants' as constants;
|
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
.entity-key-field {
|
.arguments-table {
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
min-height: 108px;
|
||||||
|
|
||||||
|
&-with-error {
|
||||||
|
min-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-table {
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-text {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tb-form-table-row-cell-buttons {
|
.tb-form-table-row-cell-buttons {
|
||||||
@ -25,38 +35,24 @@
|
|||||||
--mat-badge-small-size-container-overlap-offset: -5px;
|
--mat-badge-small-size-container-overlap-offset: -5px;
|
||||||
--mat-badge-small-size-text-size: 0;
|
--mat-badge-small-size-text-size: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.argument-name-field {
|
|
||||||
@media #{constants.$mat-sm} {
|
|
||||||
min-width: 25%;
|
|
||||||
max-width: 25%;
|
|
||||||
}
|
|
||||||
@media #{constants.$mat-xs} {
|
|
||||||
min-width: 33%;
|
|
||||||
max-width: 33%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.datasource-field {
|
|
||||||
min-width: 33%;
|
|
||||||
max-width: 33%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:host ::ng-deep {
|
:host ::ng-deep {
|
||||||
.entity-field {
|
|
||||||
a {
|
|
||||||
font-size: 14px;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-mdc-standard-chip {
|
.mat-mdc-standard-chip {
|
||||||
.mdc-evolution-chip__cell--primary, .mdc-evolution-chip__action--primary, .mdc-evolution-chip__text-label {
|
.mdc-evolution-chip__cell--primary, .mdc-evolution-chip__action--primary, .mdc-evolution-chip__text-label {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arguments-table:not(.arguments-table-with-error) {
|
||||||
|
.mdc-data-table__row:last-child .mat-mdc-cell {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arguments-table {
|
||||||
|
.mat-mdc-header-row.mat-row-select .mat-mdc-header-cell.entity-type-header {
|
||||||
|
padding: 0 28px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,20 +15,22 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AfterViewInit,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
|
DestroyRef,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
Input,
|
Input,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
Renderer2,
|
Renderer2,
|
||||||
SimpleChanges,
|
SimpleChanges,
|
||||||
|
ViewChild,
|
||||||
ViewContainerRef,
|
ViewContainerRef,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {
|
import {
|
||||||
AbstractControl,
|
AbstractControl,
|
||||||
ControlValueAccessor,
|
ControlValueAccessor,
|
||||||
FormBuilder,
|
FormBuilder,
|
||||||
FormGroup,
|
|
||||||
NG_VALIDATORS,
|
NG_VALIDATORS,
|
||||||
NG_VALUE_ACCESSOR,
|
NG_VALUE_ACCESSOR,
|
||||||
ValidationErrors,
|
ValidationErrors,
|
||||||
@ -48,8 +50,11 @@ import { TbPopoverService } from '@shared/components/popover.service';
|
|||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { EntityId } from '@shared/models/id/entity-id';
|
import { EntityId } from '@shared/models/id/entity-id';
|
||||||
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models';
|
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models';
|
||||||
import { isDefined, isDefinedAndNotNull } from '@core/utils';
|
import { getEntityDetailsPageURL, isDefined, isDefinedAndNotNull } from '@core/utils';
|
||||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||||
|
import { TbTableDatasource } from '@shared/components/table/table-datasource.abstract';
|
||||||
|
import { EntityService } from '@core/http/entity.service';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-calculated-field-arguments-table',
|
selector: 'tb-calculated-field-arguments-table',
|
||||||
@ -68,19 +73,23 @@ import { TbPopoverComponent } from '@shared/components/popover.component';
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CalculatedFieldArgumentsTableComponent implements ControlValueAccessor, Validator, OnChanges {
|
export class CalculatedFieldArgumentsTableComponent implements ControlValueAccessor, Validator, OnChanges, AfterViewInit {
|
||||||
|
|
||||||
@Input() entityId: EntityId;
|
@Input() entityId: EntityId;
|
||||||
@Input() tenantId: string;
|
@Input() tenantId: string;
|
||||||
@Input() entityName: string;
|
@Input() entityName: string;
|
||||||
@Input() calculatedFieldType: CalculatedFieldType;
|
@Input() calculatedFieldType: CalculatedFieldType;
|
||||||
|
|
||||||
|
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||||
|
|
||||||
errorText = '';
|
errorText = '';
|
||||||
argumentsFormArray = this.fb.array<AbstractControl>([]);
|
argumentsFormArray = this.fb.array<AbstractControl>([]);
|
||||||
|
entityNameMap = new Map<string, string>();
|
||||||
|
sortOrder = { direction: 'asc', property: '' };
|
||||||
|
dataSource = new CalculatedFieldArgumentDatasource();
|
||||||
|
|
||||||
readonly entityTypeTranslations = entityTypeTranslations;
|
readonly entityTypeTranslations = entityTypeTranslations;
|
||||||
readonly ArgumentTypeTranslations = ArgumentTypeTranslations;
|
readonly ArgumentTypeTranslations = ArgumentTypeTranslations;
|
||||||
readonly EntityType = EntityType;
|
|
||||||
readonly ArgumentEntityType = ArgumentEntityType;
|
readonly ArgumentEntityType = ArgumentEntityType;
|
||||||
readonly ArgumentType = ArgumentType;
|
readonly ArgumentType = ArgumentType;
|
||||||
readonly CalculatedFieldType = CalculatedFieldType;
|
readonly CalculatedFieldType = CalculatedFieldType;
|
||||||
@ -93,10 +102,14 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
|||||||
private popoverService: TbPopoverService,
|
private popoverService: TbPopoverService,
|
||||||
private viewContainerRef: ViewContainerRef,
|
private viewContainerRef: ViewContainerRef,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
private renderer: Renderer2
|
private renderer: Renderer2,
|
||||||
|
private entityService: EntityService,
|
||||||
|
private destroyRef: DestroyRef,
|
||||||
) {
|
) {
|
||||||
this.argumentsFormArray.valueChanges.pipe(takeUntilDestroyed()).subscribe(() => {
|
this.argumentsFormArray.valueChanges.pipe(takeUntilDestroyed()).subscribe(value => {
|
||||||
this.propagateChange(this.getArgumentsObject());
|
this.updateEntityNameMap(value);
|
||||||
|
this.updateDataSource(value);
|
||||||
|
this.propagateChange(this.getArgumentsObject(value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,6 +120,14 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.sort.sortChange.asObservable().pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||||
|
this.sortOrder.property = this.sort.active;
|
||||||
|
this.sortOrder.direction = this.sort.direction;
|
||||||
|
this.updateDataSource(this.argumentsFormArray.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
registerOnChange(fn: (argumentsObj: Record<string, CalculatedFieldArgument>) => void): void {
|
registerOnChange(fn: (argumentsObj: Record<string, CalculatedFieldArgument>) => void): void {
|
||||||
this.propagateChange = fn;
|
this.propagateChange = fn;
|
||||||
}
|
}
|
||||||
@ -118,12 +139,13 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
|||||||
return this.errorText ? { argumentsFormArray: false } : null;
|
return this.errorText ? { argumentsFormArray: false } : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete(index: number): void {
|
onDelete($event: Event, index: number): void {
|
||||||
|
$event.stopPropagation();
|
||||||
this.argumentsFormArray.removeAt(index);
|
this.argumentsFormArray.removeAt(index);
|
||||||
this.argumentsFormArray.markAsDirty();
|
this.argumentsFormArray.markAsDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
manageArgument($event: Event, matButton: MatButton, index?: number): void {
|
manageArgument($event: Event, matButton: MatButton, argument = {} as CalculatedFieldArgumentValue, index?: number): void {
|
||||||
$event?.stopPropagation();
|
$event?.stopPropagation();
|
||||||
if (this.popoverComponent && !this.popoverComponent.tbHidden) {
|
if (this.popoverComponent && !this.popoverComponent.tbHidden) {
|
||||||
this.popoverComponent.hide();
|
this.popoverComponent.hide();
|
||||||
@ -132,16 +154,15 @@ 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 argumentObj = this.argumentsFormArray.at(index)?.getRawValue() ?? {};
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
index,
|
index,
|
||||||
argument: argumentObj,
|
argument,
|
||||||
entityId: this.entityId,
|
entityId: this.entityId,
|
||||||
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,
|
entityName: this.entityName,
|
||||||
usedArgumentNames: this.argumentsFormArray.getRawValue().map(({ argumentName }) => argumentName).filter(name => name !== argumentObj.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, isDefined(index) ? 'left' : 'right', false, null,
|
||||||
@ -150,7 +171,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
|||||||
{}, {}, true);
|
{}, {}, true);
|
||||||
this.popoverComponent.tbComponentRef.instance.argumentsDataApplied.subscribe(({ value, index }) => {
|
this.popoverComponent.tbComponentRef.instance.argumentsDataApplied.subscribe(({ value, index }) => {
|
||||||
this.popoverComponent.hide();
|
this.popoverComponent.hide();
|
||||||
const formGroup = this.getArgumentFormGroup(value);
|
const formGroup = this.fb.group(value);
|
||||||
if (isDefinedAndNotNull(index)) {
|
if (isDefinedAndNotNull(index)) {
|
||||||
this.argumentsFormArray.setControl(index, formGroup);
|
this.argumentsFormArray.setControl(index, formGroup);
|
||||||
} else {
|
} else {
|
||||||
@ -162,9 +183,14 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateDataSource(value: CalculatedFieldArgumentValue[]): void {
|
||||||
|
const sortedValue = this.sortData(value);
|
||||||
|
this.dataSource.loadData(sortedValue);
|
||||||
|
}
|
||||||
|
|
||||||
private updateErrorText(): void {
|
private updateErrorText(): void {
|
||||||
if (this.calculatedFieldType === CalculatedFieldType.SIMPLE
|
if (this.calculatedFieldType === CalculatedFieldType.SIMPLE
|
||||||
&& this.argumentsFormArray.controls.some(control => control.get('refEntityKey').get('type').value === 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.argumentsFormArray.controls.length) {
|
} else if (!this.argumentsFormArray.controls.length) {
|
||||||
this.errorText = 'calculated-fields.hint.arguments-empty';
|
this.errorText = 'calculated-fields.hint.arguments-empty';
|
||||||
@ -173,9 +199,9 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getArgumentsObject(): Record<string, CalculatedFieldArgument> {
|
private getArgumentsObject(value: CalculatedFieldArgumentValue[]): Record<string, CalculatedFieldArgument> {
|
||||||
return this.argumentsFormArray.getRawValue().reduce((acc, rawValue) => {
|
return value.reduce((acc, argumentValue) => {
|
||||||
const { argumentName, ...argument } = rawValue as CalculatedFieldArgumentValue;
|
const { argumentName, ...argument } = argumentValue as CalculatedFieldArgumentValue;
|
||||||
acc[argumentName] = argument;
|
acc[argumentName] = argument;
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as Record<string, CalculatedFieldArgument>);
|
}, {} as Record<string, CalculatedFieldArgument>);
|
||||||
@ -186,31 +212,62 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
|
|||||||
this.populateArgumentsFormArray(argumentsObj)
|
this.populateArgumentsFormArray(argumentsObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getEntityDetailsPageURL(id: string, type: EntityType): string {
|
||||||
|
return getEntityDetailsPageURL(id, type);
|
||||||
|
}
|
||||||
|
|
||||||
private populateArgumentsFormArray(argumentsObj: Record<string, CalculatedFieldArgument>): void {
|
private populateArgumentsFormArray(argumentsObj: Record<string, CalculatedFieldArgument>): void {
|
||||||
Object.keys(argumentsObj).forEach(key => {
|
Object.keys(argumentsObj).forEach(key => {
|
||||||
const value: CalculatedFieldArgumentValue = {
|
const value: CalculatedFieldArgumentValue = {
|
||||||
...argumentsObj[key],
|
...argumentsObj[key],
|
||||||
argumentName: key
|
argumentName: key
|
||||||
};
|
};
|
||||||
this.argumentsFormArray.push(this.getArgumentFormGroup(value), {emitEvent: false});
|
this.argumentsFormArray.push(this.fb.group(value), { emitEvent: false });
|
||||||
|
});
|
||||||
|
this.argumentsFormArray.updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateEntityNameMap(value: CalculatedFieldArgumentValue[]): void {
|
||||||
|
value.forEach(({ refEntityId = {}}) => {
|
||||||
|
if (refEntityId.id && !this.entityNameMap.has(refEntityId.id)) {
|
||||||
|
const { id, entityType } = refEntityId as EntityId;
|
||||||
|
this.entityService.getEntity(entityType as EntityType, id, { ignoreLoading: true, ignoreErrors: true })
|
||||||
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||||
|
.subscribe(entity => this.entityNameMap.set(id, entity.name));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getArgumentFormGroup(value: CalculatedFieldArgumentValue): FormGroup {
|
private getSortValue(argument: CalculatedFieldArgumentValue, column: string): string {
|
||||||
return this.fb.group({
|
switch (column) {
|
||||||
...value,
|
case 'entityType':
|
||||||
argumentName: [{ value: value.argumentName, disabled: true }],
|
if (argument.refEntityId?.entityType === ArgumentEntityType.Tenant) {
|
||||||
...(value.refEntityId ? {
|
return 'calculated-fields.argument-current-tenant';
|
||||||
refEntityId: this.fb.group({
|
} else if (argument.refEntityId?.id) {
|
||||||
entityType: [{ value: value.refEntityId.entityType, disabled: true }],
|
return entityTypeTranslations.get((argument.refEntityId)?.entityType as unknown as EntityType).type;
|
||||||
id: [{ value: value.refEntityId.id , disabled: true }],
|
} else {
|
||||||
}),
|
return 'calculated-fields.argument-current';
|
||||||
} : {}),
|
}
|
||||||
refEntityKey: this.fb.group({
|
case 'type':
|
||||||
...value.refEntityKey,
|
return ArgumentTypeTranslations.get(argument.refEntityKey.type);
|
||||||
type: [{ value: value.refEntityKey.type, disabled: true }],
|
case 'key':
|
||||||
key: [{ value: value.refEntityKey.key, disabled: true }],
|
return argument.refEntityKey.key;
|
||||||
}),
|
default:
|
||||||
})
|
return argument.argumentName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sortData(data: CalculatedFieldArgumentValue[]): CalculatedFieldArgumentValue[] {
|
||||||
|
return data.sort((a, b) => {
|
||||||
|
const valA = this.getSortValue(a, this.sortOrder.property) ?? '';
|
||||||
|
const valB = this.getSortValue(b, this.sortOrder.property) ?? '';
|
||||||
|
return (this.sortOrder.direction === 'asc' ? 1 : -1) * valA.localeCompare(valB);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CalculatedFieldArgumentDatasource extends TbTableDatasource<CalculatedFieldArgumentValue> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,10 +143,10 @@ export class CalculatedFieldDialogComponent extends DialogComponent<CalculatedFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private applyDialogData(): void {
|
private applyDialogData(): void {
|
||||||
const { configuration = {}, type = CalculatedFieldType.SIMPLE, ...value } = this.data.value ?? {};
|
const { configuration = {}, type = CalculatedFieldType.SIMPLE, debugSettings = { failuresEnabled: true, allEnabled: true }, ...value } = this.data.value ?? {};
|
||||||
const { expression, ...restConfig } = configuration as CalculatedFieldConfiguration;
|
const { expression, ...restConfig } = configuration as CalculatedFieldConfiguration;
|
||||||
const updatedConfig = { ...restConfig , ['expression'+type]: expression };
|
const updatedConfig = { ...restConfig , ['expression'+type]: expression };
|
||||||
this.fieldFormGroup.patchValue({ configuration: updatedConfig, type, ...value }, {emitEvent: false});
|
this.fieldFormGroup.patchValue({ configuration: updatedConfig, type, debugSettings, ...value }, {emitEvent: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
private observeTypeChanges(): void {
|
private observeTypeChanges(): void {
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AdditionalDebugActionConfig,
|
AdditionalDebugActionConfig,
|
||||||
EntityDebugSettings,
|
HasEntityDebugSettings,
|
||||||
HasTenantId,
|
HasTenantId,
|
||||||
HasVersion
|
HasVersion
|
||||||
} from '@shared/models/entity.models';
|
} from '@shared/models/entity.models';
|
||||||
@ -34,8 +34,7 @@ import {
|
|||||||
endGroupHighlightRule
|
endGroupHighlightRule
|
||||||
} from '@shared/models/ace/ace.models';
|
} from '@shared/models/ace/ace.models';
|
||||||
|
|
||||||
export interface CalculatedField extends Omit<BaseData<CalculatedFieldId>, 'label'>, HasVersion, HasTenantId, ExportableEntity<CalculatedFieldId> {
|
export interface CalculatedField extends Omit<BaseData<CalculatedFieldId>, 'label'>, HasVersion, HasEntityDebugSettings, HasTenantId, ExportableEntity<CalculatedFieldId> {
|
||||||
debugSettings?: EntityDebugSettings;
|
|
||||||
configuration: CalculatedFieldConfiguration;
|
configuration: CalculatedFieldConfiguration;
|
||||||
type: CalculatedFieldType;
|
type: CalculatedFieldType;
|
||||||
entityId: EntityId;
|
entityId: EntityId;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user