Skip to content

Commit 6f7f5cd

Browse files
authored
feat: add validation to tabular creation/modification (#3012)
Signed-off-by: Abdelsalem <[email protected]>
1 parent 5344b0e commit 6f7f5cd

File tree

10 files changed

+458
-295
lines changed

10 files changed

+458
-295
lines changed

src/components/dialogs/network-modifications/tabular-creation/tabular-creation-form.tsx

Lines changed: 72 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
99
import { FormattedMessage, useIntl } from 'react-intl';
1010
import { useFormContext, useWatch } from 'react-hook-form';
1111
import { AutocompleteInput, CustomAGGrid, ErrorInput, FieldErrorAlert, LANG_FRENCH } from '@gridsuite/commons-ui';
12-
import {
13-
CONNECTED,
14-
CREATIONS_TABLE,
15-
EQUIPMENT_ID,
16-
PARTICIPATE,
17-
REACTIVE_CAPABILITY_CURVE,
18-
TYPE,
19-
VOLTAGE_REGULATION_ON,
20-
} from 'components/utils/field-constants';
12+
import { CREATIONS_TABLE, EQUIPMENT_ID, TYPE } from 'components/utils/field-constants';
2113
import { EQUIPMENT_TYPES } from 'components/utils/equipment-types';
2214
import CsvDownloader from 'react-csv-downloader';
2315
import { Alert, Button, Grid } from '@mui/material';
@@ -27,6 +19,8 @@ import {
2719
TabularCreationField,
2820
generateCommentLines,
2921
transformIfFrenchNumber,
22+
isFieldTypeOk,
23+
setFieldTypeError,
3024
} from './tabular-creation-utils';
3125
import { BooleanNullableCellRenderer, DefaultCellRenderer } from 'components/custom-aggrid/cell-renderers';
3226
import Papa from 'papaparse';
@@ -36,6 +30,7 @@ import { useCSVPicker } from 'components/utils/inputs/input-hooks';
3630
import { AGGRID_LOCALES } from '../../../../translations/not-intl/aggrid-locales';
3731
import { useSelector } from 'react-redux';
3832
import { AppState } from '../../../../redux/reducer';
33+
import { BOOLEAN } from '../../../network/constants';
3934

4035
export interface TabularCreationFormProps {
4136
dataFetching: boolean;
@@ -53,77 +48,81 @@ export function TabularCreationForm({ dataFetching }: Readonly<TabularCreationFo
5348
(results: Papa.ParseResult<any>) => {
5449
clearErrors(CREATIONS_TABLE);
5550
let requiredFieldNameInError: string = '';
56-
5751
let requiredDependantFieldNameInError: string = '';
5852
let dependantFieldNameInError: string = '';
59-
results.data.every((result) => {
60-
Object.keys(result).every((key) => {
61-
const found = TABULAR_CREATION_FIELDS[getValues(TYPE)]?.find((field) => {
62-
return field.id === key;
63-
});
64-
// check required fields are defined
65-
if (found !== undefined && found.required && (result[key] === undefined || result[key] === null)) {
66-
requiredFieldNameInError = key;
67-
return false;
68-
}
53+
let fieldTypeInError: string = '';
54+
let expectedTypeForFieldInError: string = '';
55+
let expectedValues: string[] | undefined;
6956

70-
//check requiredIf rule
71-
if (found?.requiredIf) {
72-
const dependentValue = result[found.requiredIf.id];
73-
if (
74-
dependentValue !== undefined &&
75-
dependentValue !== null &&
76-
(result[key] === undefined || result[key] === null)
77-
) {
78-
dependantFieldNameInError = key;
79-
requiredDependantFieldNameInError = found.requiredIf.id;
80-
return false;
57+
// check if the csv contains an error
58+
if (
59+
results.data
60+
.flatMap((result) => Object.entries(result).map(([key, value]) => [result, key, value]))
61+
.some(([result, key, value]) => {
62+
const fieldDef = TABULAR_CREATION_FIELDS[getValues(TYPE)]?.find((field) => field.id === key);
63+
// check required fields are defined
64+
if (fieldDef !== undefined && fieldDef.required && (value === undefined || value === null)) {
65+
requiredFieldNameInError = key;
66+
return true; // “yes, we found an error here” → break loop
8167
}
82-
}
8368

84-
return true;
85-
});
86-
return (
87-
requiredFieldNameInError !== '' ||
88-
dependantFieldNameInError !== '' ||
89-
requiredDependantFieldNameInError !== ''
90-
);
91-
});
92-
setValue(CREATIONS_TABLE, results.data, {
93-
shouldDirty: true,
94-
});
95-
setIsFetching(false);
96-
if (requiredFieldNameInError !== '') {
97-
setError(CREATIONS_TABLE, {
98-
type: 'custom',
99-
message: intl.formatMessage(
100-
{
101-
id: 'FieldRequired',
102-
},
103-
{
104-
requiredFieldNameInError: intl.formatMessage({
105-
id: requiredFieldNameInError,
106-
}),
69+
//check requiredIf rule
70+
if (fieldDef?.requiredIf) {
71+
const dependentValue = result[fieldDef.requiredIf.id];
72+
if (
73+
dependentValue !== undefined &&
74+
dependentValue !== null &&
75+
(value === undefined || value === null)
76+
) {
77+
dependantFieldNameInError = key;
78+
requiredDependantFieldNameInError = fieldDef.requiredIf.id;
79+
return true; // “yes, we found an error here” → break loop
80+
}
10781
}
108-
),
109-
});
110-
}
111-
if (dependantFieldNameInError !== '' && requiredDependantFieldNameInError !== '') {
112-
setError(CREATIONS_TABLE, {
113-
type: 'custom',
114-
message: intl.formatMessage(
115-
{
116-
id: 'DependantFieldMissing',
117-
},
118-
{
119-
requiredField: intl.formatMessage({ id: dependantFieldNameInError }),
120-
dependantField: intl.formatMessage({
121-
id: requiredDependantFieldNameInError,
122-
}),
82+
83+
// check the field types
84+
if (!isFieldTypeOk(value, fieldDef)) {
85+
fieldTypeInError = key;
86+
expectedTypeForFieldInError = fieldDef?.type ?? '';
87+
expectedValues = fieldDef?.options;
88+
return true; // “yes, we found an error here” → break loop
12389
}
124-
),
125-
});
90+
return false; // keep looking
91+
})
92+
) {
93+
if (requiredFieldNameInError !== '') {
94+
setError(CREATIONS_TABLE, {
95+
type: 'custom',
96+
message: intl.formatMessage(
97+
{ id: 'FieldRequired' },
98+
{ requiredFieldNameInError: intl.formatMessage({ id: requiredFieldNameInError }) }
99+
),
100+
});
101+
}
102+
if (dependantFieldNameInError !== '' && requiredDependantFieldNameInError !== '') {
103+
setError(CREATIONS_TABLE, {
104+
type: 'custom',
105+
message: intl.formatMessage(
106+
{ id: 'DependantFieldMissing' },
107+
{
108+
requiredField: intl.formatMessage({ id: dependantFieldNameInError }),
109+
dependantField: intl.formatMessage({ id: requiredDependantFieldNameInError }),
110+
}
111+
),
112+
});
113+
}
114+
setIsFetching(false);
115+
setFieldTypeError(
116+
fieldTypeInError,
117+
expectedTypeForFieldInError,
118+
CREATIONS_TABLE,
119+
setError,
120+
intl,
121+
expectedValues
122+
);
126123
}
124+
setIsFetching(false);
125+
setValue(CREATIONS_TABLE, results.data, { shouldDirty: true });
127126
},
128127
[clearErrors, setValue, getValues, setError, intl]
129128
);
@@ -230,12 +229,7 @@ export function TabularCreationForm({ dataFetching }: Readonly<TabularCreationFo
230229
}
231230
columnDef.field = field.id;
232231
columnDef.headerName = intl.formatMessage({ id: field.id }) + (field.required ? ' (*)' : '');
233-
const booleanColumns = [VOLTAGE_REGULATION_ON, CONNECTED, PARTICIPATE, REACTIVE_CAPABILITY_CURVE];
234-
if (booleanColumns.includes(field.id)) {
235-
columnDef.cellRenderer = BooleanNullableCellRenderer;
236-
} else {
237-
columnDef.cellRenderer = DefaultCellRenderer;
238-
}
232+
columnDef.cellRenderer = field.type === BOOLEAN ? BooleanNullableCellRenderer : DefaultCellRenderer;
239233
return columnDef;
240234
});
241235
}, [intl, equipmentType]);

0 commit comments

Comments
 (0)