Skip to content

feat/AB#85638_Improve-edition-of-fields-in-ref-data #2552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: alpha
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ <h1 class="overflow-hidden whitespace-nowrap text-ellipsis mb-0">
'pages.referenceData.fields.help' | translate
}}</ui-alert>
<!-- Fields -->
<label class="block text-sm font-medium leading-6 text-gray-900">
{{ 'common.field.few' | translate }}
</label>
<kendo-grid *ngIf="!loading" [data]="valueFields" class="rounded-md">
<kendo-grid-column
field="name"
Expand Down Expand Up @@ -317,42 +320,54 @@ <h1 class="overflow-hidden whitespace-nowrap text-ellipsis mb-0">
[width]="86"
[resizable]="false"
>
<ng-template kendoGridCellTemplate let-dataItem>
<div [ngClass]="{ hidden: currEditingField === dataItem }">
<button
kendoButton
class="text-center"
icon="edit"
[look]="'flat'"
(click)="toggleInlineEditor(dataItem)"
[uiTooltip]="'common.edit' | translate"
></button>
<button
kendoButton
class="text-center"
icon="delete"
[look]="'flat'"
(click)="onRemoveField(dataItem)"
[uiTooltip]="'common.remove' | translate"
></button>
</div>
<div [ngClass]="{ hidden: currEditingField !== dataItem }">
<button
kendoButton
class="text-center"
icon="save"
[look]="'flat'"
(click)="toggleInlineEditor(null)"
[uiTooltip]="'common.save' | translate"
></button>
<button
kendoButton
class="text-center"
icon="cancel"
[look]="'flat'"
(click)="currEditingField = null"
[uiTooltip]="'common.cancel' | translate"
></button>
<ng-template kendoGridCellTemplate let-dataItem let-rowIndex="rowIndex">
<div class="flex flex-row">
<ui-icon
*ngIf="fieldsControl.controls.at(rowIndex)?.errors?.invalidField"
class="cursor-help self-center"
variant="danger"
[size]="18"
icon="info_outline"
[uiTooltip]="
'pages.referenceData.fields.noFound' | translate
"
></ui-icon>
<div class="flex flex-row" [ngClass]="{ hidden: currEditingField === dataItem }">
<button
kendoButton
class="text-center"
icon="edit"
[look]="'flat'"
(click)="toggleInlineEditor(dataItem)"
[uiTooltip]="'common.edit' | translate"
></button>
<button
kendoButton
class="text-center"
icon="delete"
[look]="'flat'"
(click)="onRemoveField(dataItem)"
[uiTooltip]="'common.remove' | translate"
></button>
</div>
<div class="flex flex-row" [ngClass]="{ hidden: currEditingField !== dataItem }">
<button
kendoButton
class="text-center"
icon="save"
[look]="'flat'"
(click)="toggleInlineEditor(null)"
[uiTooltip]="'common.save' | translate"
></button>
<button
kendoButton
class="text-center"
icon="cancel"
[look]="'flat'"
(click)="currEditingField = null"
[uiTooltip]="'common.cancel' | translate"
></button>
</div>
</div>
</ng-template>
</kendo-grid-column>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -93,7 +94,7 @@ export class ReferenceDataComponent
public apiConfigurationsQuery!: QueryRef<ApiConfigurationsQueryResponse>;
/** List of query variables */
public queryVariables: string[] = [];
/** Value fields */
/** Value fields to be displayed */
public valueFields: NonNullable<ReferenceData['fields']> = [];
/** Payload */
public payload: any;
Expand Down Expand Up @@ -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<ReferenceData['fields']> = [];
/** size style of editor */
public style: any = {};

Expand All @@ -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');
Expand Down Expand Up @@ -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 ?? '');
Expand All @@ -277,6 +289,7 @@ export class ReferenceDataComponent
const clearFields = () => {
this.payload = null;
this.valueFields = [];
this.dataFields = [];
form.get('fields')?.setValue([], { emitEvent: false });
};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 });
Expand All @@ -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();
}

/**
Expand Down Expand Up @@ -970,6 +998,7 @@ export class ReferenceDataComponent
'components.referenceData.fields.new'
),
type: 'string',
manual: true,
},
];

Expand Down
3 changes: 2 additions & 1 deletion libs/shared/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
3 changes: 2 additions & 1 deletion libs/shared/src/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
3 changes: 3 additions & 0 deletions libs/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
7 changes: 6 additions & 1 deletion libs/shared/src/lib/models/reference-data.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
21 changes: 21 additions & 0 deletions libs/shared/src/lib/utils/validators/containsFields.validator.ts
Original file line number Diff line number Diff line change
@@ -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<ReferenceData['fields']>
): 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 };
};
}
1 change: 1 addition & 0 deletions libs/shared/src/lib/utils/validators/public-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './containsFields.validator';
Loading