From 7ea901db09f58a41fe2421706db2afe9b6b3878f Mon Sep 17 00:00:00 2001 From: Estela Silva Date: Wed, 22 May 2024 14:56:24 -0300 Subject: [PATCH] updated ref data fields edition --- .../reference-data.component.html | 87 +++++++++++-------- .../reference-data.component.ts | 53 ++++++++--- libs/shared/src/i18n/en.json | 3 +- libs/shared/src/i18n/fr.json | 3 +- libs/shared/src/index.ts | 3 + .../src/lib/models/reference-data.model.ts | 7 +- .../validators/containsFields.validator.ts | 21 +++++ .../src/lib/utils/validators/public-api.ts | 1 + 8 files changed, 127 insertions(+), 51 deletions(-) create mode 100644 libs/shared/src/lib/utils/validators/containsFields.validator.ts create mode 100644 libs/shared/src/lib/utils/validators/public-api.ts diff --git a/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.html b/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.html index 5293e6af62..9093be71c3 100644 --- a/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.html +++ b/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.html @@ -280,6 +280,9 @@

'pages.referenceData.fields.help' | translate }} + [width]="86" [resizable]="false" > - -
- - -
-
- - + +
+ +
+ + +
+
+ + +
diff --git a/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts b/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts index f5d1b00c8e..c9348a50eb 100644 --- a/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts +++ b/apps/back-office/src/app/dashboard/pages/reference-data/reference-data.component.ts @@ -27,6 +27,7 @@ import { ApiConfigurationQueryResponse, EditReferenceDataMutationResponse, paginationStrategy, + containsFieldsValidator, } from '@oort-front/shared'; import { Apollo, QueryRef } from 'apollo-angular'; import { EDIT_REFERENCE_DATA } from './graphql/mutations'; @@ -93,7 +94,7 @@ export class ReferenceDataComponent public apiConfigurationsQuery!: QueryRef; /** List of query variables */ public queryVariables: string[] = []; - /** Value fields */ + /** Value fields to be displayed */ public valueFields: NonNullable = []; /** Payload */ public payload: any; @@ -140,6 +141,8 @@ export class ReferenceDataComponent private addChipListTimeoutListener!: NodeJS.Timeout; /** Outside click listener for inline edition */ private inlineEditionOutsideClickListener!: any; + /** Saves the original fields fetched from the reference data */ + private dataFields: NonNullable = []; /** size style of editor */ public style: any = {}; @@ -148,6 +151,20 @@ export class ReferenceDataComponent return this.referenceForm.get('query') as FormControl | null; } + /** @returns the fieldsControl form control */ + get fieldsControl() { + const arrayControl = this.fb.array([]); + this.valueFields.forEach((value) => { + arrayControl.push( + this.fb.nonNullable.control( + value, + containsFieldsValidator(this.dataFields) + ) + ); + }); + return arrayControl; + } + /** @returns name of reference model */ get name(): AbstractControl | null { return this.referenceForm.get('name'); @@ -251,12 +268,7 @@ export class ReferenceDataComponent } }; - const handleQueryChange = (queryStr: string, resetFields = true) => { - // Clear the fields - if (resetFields) { - clearFields(); - } - + const handleQueryChange = (queryStr: string) => { // Update the query variables try { const query = gql(queryStr ?? ''); @@ -277,6 +289,7 @@ export class ReferenceDataComponent const clearFields = () => { this.payload = null; this.valueFields = []; + this.dataFields = []; form.get('fields')?.setValue([], { emitEvent: false }); }; @@ -332,7 +345,7 @@ export class ReferenceDataComponent .subscribe(setPaginationValidators); // Initialize the query variables - handleQueryChange(this.queryControl?.value, false); + handleQueryChange(this.queryControl?.value); }, 100); return form; @@ -390,6 +403,11 @@ export class ReferenceDataComponent ? this.referenceData?.data : []; this.referenceForm = this.getRefDataForm(); + if (!this.dataFields.length) { + this.dataFields = + this.referenceForm?.get('fields')?.value || []; + this.getFields(true); + } this.valueFields = this.referenceForm?.get('fields')?.value || []; this.loadApiConfigurations( this.referenceForm?.get('type')?.value @@ -809,8 +827,12 @@ export class ReferenceDataComponent return array.map((it) => Object.values(it).toString()).join('\n'); } - /** Uses the API Configuration to get the fields and parse their types. */ - public async getFields() { + /** + * Uses the API Configuration to get the fields and parse their types. + * + * @param init if starting component don't mark form as dirt, but get payload only + */ + public async getFields(init = false) { const apiConfID = this.referenceForm.value.apiConfiguration; const path = this.referenceForm.value.path; const query = this.referenceForm.value.query; @@ -855,10 +877,15 @@ export class ReferenceDataComponent query, type ); - this.valueFields = result.fields; + const fieldsCopy = cloneDeep(this.valueFields); + const manualFields = fieldsCopy.filter((field) => field.manual); + this.dataFields = result.fields; + this.valueFields = this.dataFields.concat(manualFields); this.payload = result.payload; this.referenceForm?.get('fields')?.setValue(this.valueFields); - this.referenceForm.get('fields')?.markAsDirty(); + if (!init) { + this.referenceForm.get('fields')?.markAsDirty(); + } } catch (e) { if (e instanceof HttpErrorResponse) { this.snackBar.openSnackBar(e.message, { error: true }); @@ -875,6 +902,7 @@ export class ReferenceDataComponent onRemoveField(field: any) { this.valueFields = this.valueFields.filter((x) => x.name !== field.name); this.referenceForm?.get('fields')?.setValue(this.valueFields); + this.setReferenceFormValue(); } /** @@ -970,6 +998,7 @@ export class ReferenceDataComponent 'components.referenceData.fields.new' ), type: 'string', + manual: true, }, ]; diff --git a/libs/shared/src/i18n/en.json b/libs/shared/src/i18n/en.json index b5a752e2aa..d3a14abc2c 100644 --- a/libs/shared/src/i18n/en.json +++ b/libs/shared/src/i18n/en.json @@ -2509,7 +2509,8 @@ "help": "The fields are calculated based on the attributes of the first item in the payload.", "missingConfig": "Can't fetch fields. Missing configuration: {{config}}", "noFields": "No fields found", - "title": "Field" + "title": "Field", + "noFound": "Field not found in the payload of the reference data." }, "graphQLFilter": "GraphQL query parameters", "pagination": { diff --git a/libs/shared/src/i18n/fr.json b/libs/shared/src/i18n/fr.json index 23dcd230d3..95db436299 100644 --- a/libs/shared/src/i18n/fr.json +++ b/libs/shared/src/i18n/fr.json @@ -2523,7 +2523,8 @@ "help": "Les champs sont calculés en fonction des attributs du premier élément dans la réponse de l'API", "missingConfig": "Impossible de récupérer les champs. Configuration manquante : {{config}}", "noFields": "Aucun champ trouvé", - "title": "Champ" + "title": "Champ", + "noFound": "Champ introuvable dans la charge utile des données de référence." }, "graphQLFilter": "Paramètres de la requête GraphQL", "pagination": { diff --git a/libs/shared/src/index.ts b/libs/shared/src/index.ts index e0573fadb0..2337f6de43 100644 --- a/libs/shared/src/index.ts +++ b/libs/shared/src/index.ts @@ -144,3 +144,6 @@ export * from './lib/const/tinymce.const'; // === ENUM === export * from './lib/components/dashboard-filter/enums/dashboard-filters.enum'; + +// === VALIDATORS === +export * from './lib/utils/validators/public-api'; diff --git a/libs/shared/src/lib/models/reference-data.model.ts b/libs/shared/src/lib/models/reference-data.model.ts index d8a39856de..781ef2adcc 100644 --- a/libs/shared/src/lib/models/reference-data.model.ts +++ b/libs/shared/src/lib/models/reference-data.model.ts @@ -26,7 +26,12 @@ export interface ReferenceData { apiConfiguration?: ApiConfiguration; graphQLTypeName?: string; query?: string; - fields?: { name: string; type: string; graphQLFieldName?: string }[]; + fields?: { + name: string; + type: string; + graphQLFieldName?: string; + manual?: boolean; + }[]; valueField?: string; path?: string; data?: any; diff --git a/libs/shared/src/lib/utils/validators/containsFields.validator.ts b/libs/shared/src/lib/utils/validators/containsFields.validator.ts new file mode 100644 index 0000000000..792d74b4fd --- /dev/null +++ b/libs/shared/src/lib/utils/validators/containsFields.validator.ts @@ -0,0 +1,21 @@ +import { AbstractControl, ValidatorFn, ValidationErrors } from '@angular/forms'; +import { ReferenceData } from '../../models/reference-data.model'; + +/** + * Checks if array of reference data fetched fields contains the field (current control value) + * + * @param fields array the all the available fields + * @returns null if the field is available, otherwise returns a validation error + */ +export function containsFieldsValidator( + fields: NonNullable +): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + if (!control.value) { + // if there is no value, it should be valid + return null; + } + const hasField = fields.some((field) => field.name === control.value.name); + return hasField ? null : { invalidField: true }; + }; +} diff --git a/libs/shared/src/lib/utils/validators/public-api.ts b/libs/shared/src/lib/utils/validators/public-api.ts new file mode 100644 index 0000000000..e933c92b64 --- /dev/null +++ b/libs/shared/src/lib/utils/validators/public-api.ts @@ -0,0 +1 @@ +export * from './containsFields.validator';