From a7b652c1371f8430bc4840d9f7d80b1d280f8801 Mon Sep 17 00:00:00 2001 From: Nicoleta Panaghiu Date: Tue, 22 Oct 2024 12:45:34 +0300 Subject: [PATCH] RED-10220: added support for justification technical name. --- ...d-edit-justification-dialog.component.html | 9 +++++ ...add-edit-justification-dialog.component.ts | 35 +++++++++++++++---- apps/red-ui/src/app/utils/functions.ts | 4 +-- .../lib/legal-basis/justification.model.ts | 12 +++++++ .../src/lib/legal-basis/legal-basis.ts | 1 + 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.html b/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.html index 7e58ccc7e..a8aedc290 100644 --- a/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.html @@ -17,6 +17,15 @@ type="text" /> +
+ +
{{ this.technicalName() || '-' }}
+ +
diff --git a/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts b/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts index fb62106b4..699935349 100644 --- a/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts @@ -1,11 +1,13 @@ -import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; +import { ChangeDetectionStrategy, Component, computed, Inject, untracked } from '@angular/core'; import { ReactiveFormsModule, UntypedFormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Justification } from '@red/domain'; import { JustificationsService } from '@services/entity-services/justifications.service'; -import { BaseDialogComponent, CircleButtonComponent, IconButtonComponent } from '@iqser/common-ui'; +import { BaseDialogComponent, CircleButtonComponent, HasScrollbarDirective, IconButtonComponent } from '@iqser/common-ui'; import { firstValueFrom } from 'rxjs'; import { TranslateModule } from '@ngx-translate/core'; +import { formControlToSignal } from '@utils/functions'; +import { toSignal } from '@angular/core/rxjs-interop'; interface DialogData { justification?: Justification; @@ -16,9 +18,29 @@ interface DialogData { templateUrl: './add-edit-justification-dialog.component.html', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [TranslateModule, ReactiveFormsModule, IconButtonComponent, CircleButtonComponent], + imports: [TranslateModule, ReactiveFormsModule, IconButtonComponent, CircleButtonComponent, HasScrollbarDirective], }) export class AddEditJustificationDialogComponent extends BaseDialogComponent { + readonly form = this.#getForm(); + readonly name = formControlToSignal(this.form.controls['name']); + readonly allJustifications = toSignal(this._justificationService.all$); + readonly technicalName = computed(() => { + if (this.data.justification) { + return this.data.justification.technicalName; + } + if (!this.name()) { + return null; + } + let currentTechnicalName = Justification.toTechnicalName(this.name()); + const existingTechnicalNames = untracked(this.allJustifications).map(justification => justification.technicalName); + let suffix = 1; + while (existingTechnicalNames.includes(currentTechnicalName)) { + currentTechnicalName = + currentTechnicalName === '_' ? `${currentTechnicalName}${suffix++}` : [currentTechnicalName, suffix++].join('_'); + } + return currentTechnicalName; + }); + constructor( private readonly _justificationService: JustificationsService, protected readonly _dialogRef: MatDialogRef, @@ -26,7 +48,6 @@ export class AddEditJustificationDialogComponent extends BaseDialogComponent { ) { super(_dialogRef, !!data.justification); - this.form = this._getForm(); this.initialFormValue = this.form.getRawValue(); } @@ -34,7 +55,8 @@ export class AddEditJustificationDialogComponent extends BaseDialogComponent { const dossierTemplateId = this.data.dossierTemplateId; this._loadingService.start(); try { - await firstValueFrom(this._justificationService.createOrUpdate(this.form.getRawValue() as Justification, dossierTemplateId)); + const formValue = { ...this.form.getRawValue(), technicalName: this.technicalName() }; + await firstValueFrom(this._justificationService.createOrUpdate(formValue as Justification, dossierTemplateId)); await firstValueFrom(this._justificationService.loadAll(dossierTemplateId)); this._dialogRef.close(true); } catch (error) { @@ -43,11 +65,12 @@ export class AddEditJustificationDialogComponent extends BaseDialogComponent { this._loadingService.stop(); } - private _getForm(): UntypedFormGroup { + #getForm(): UntypedFormGroup { return this._formBuilder.group({ name: [{ value: this.data.justification?.name, disabled: !!this.data.justification }, Validators.required], reason: [this.data.justification?.reason, Validators.required], description: [this.data.justification?.description, Validators.required], + technicalName: [this.data.justification?.technicalName ?? null], }); } } diff --git a/apps/red-ui/src/app/utils/functions.ts b/apps/red-ui/src/app/utils/functions.ts index 50492e03c..ea763c79a 100644 --- a/apps/red-ui/src/app/utils/functions.ts +++ b/apps/red-ui/src/app/utils/functions.ts @@ -2,7 +2,7 @@ import { ITrackable } from '@iqser/common-ui'; import type { List } from '@iqser/common-ui/lib/utils'; import type { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { Dayjs } from 'dayjs'; -import { FormControl } from '@angular/forms'; +import { AbstractControl } from '@angular/forms'; import { toSignal } from '@angular/core/rxjs-interop'; export function hexToRgb(hex: string) { @@ -146,6 +146,6 @@ export function urlFileId() { return fileId.split('?')[0]; } -export function formControlToSignal(control: FormControl) { +export function formControlToSignal(control: AbstractControl) { return toSignal(control.valueChanges, { initialValue: control.value }); } diff --git a/libs/red-domain/src/lib/legal-basis/justification.model.ts b/libs/red-domain/src/lib/legal-basis/justification.model.ts index 50fcfa71c..9b4d4c7aa 100644 --- a/libs/red-domain/src/lib/legal-basis/justification.model.ts +++ b/libs/red-domain/src/lib/legal-basis/justification.model.ts @@ -1,15 +1,18 @@ import { IListable } from '@iqser/common-ui'; import { ILegalBasis } from './legal-basis'; +import { toSnakeCase } from '@utils/functions'; export class Justification implements ILegalBasis, IListable { readonly description?: string; readonly name: string; readonly reason?: string; + readonly technicalName?: string; constructor(justification: ILegalBasis) { this.description = justification.description; this.name = justification.name; this.reason = justification.reason; + this.technicalName = justification.technicalName; } get id(): string { @@ -19,4 +22,13 @@ export class Justification implements ILegalBasis, IListable { get searchKey(): string { return this.name; } + + static toTechnicalName(value: string) { + const baseTechnicalName = toSnakeCase(value.trim()); + let technicalName = baseTechnicalName.replaceAll(/[^A-Za-z0-9_-]/g, ''); + if (!technicalName.length && baseTechnicalName.length) { + technicalName = '_'; + } + return technicalName; + } } diff --git a/libs/red-domain/src/lib/legal-basis/legal-basis.ts b/libs/red-domain/src/lib/legal-basis/legal-basis.ts index 2e750f84d..d76cb86a5 100644 --- a/libs/red-domain/src/lib/legal-basis/legal-basis.ts +++ b/libs/red-domain/src/lib/legal-basis/legal-basis.ts @@ -2,4 +2,5 @@ export interface ILegalBasis { readonly name: string; readonly description?: string; readonly reason?: string; + readonly technicalName?: string; }