Skip to content

Commit 6579b0d

Browse files
committed
front: support any type of files in importTrainSchedules
Signed-off-by: Clara Ni <[email protected]>
1 parent 33346f1 commit 6579b0d

File tree

5 files changed

+42
-113
lines changed

5 files changed

+42
-113
lines changed

front/public/locales/en/operationalStudies/importTrainSchedule.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@
99
"error": "An error has occurred",
1010
"errorEmptyFile": "Empty file",
1111
"errorImport": "Unable to convert data to TrainSchedule",
12-
"errorInvalidJSONFormat": "Invalid JSON format",
13-
"errorInvalidXMLFormat": "Invalid XML format",
1412
"errorNoDate": "You must enter a date.",
1513
"errorNoFrom": "You must fill in an origin.",
1614
"errorNoTo": "You must fill in a destination.",
1715
"errorSameFromTo": "Origin and destination must be different",
18-
"errorUnsupportedFileType": "Unsupported file type"
16+
"errorInvalidFile": "Invalid file"
1917
},
2018
"failure": "Operation failed",
2119
"from": "Origin",

front/public/locales/fr/operationalStudies/importTrainSchedule.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@
99
"error": "Une erreur est survenue",
1010
"errorEmptyFile": "Fichier vide",
1111
"errorImport": "Impossible de convertir les données en TrainSchedule",
12-
"errorInvalidJSONFormat": "Format JSON invalide",
13-
"errorInvalidXMLFormat": "Format XML invalide",
1412
"errorNoDate": "Vous devez renseigner une date.",
1513
"errorNoFrom": "Vous devez renseigner une origine.",
1614
"errorNoTo": "Vous devez renseigner une destination.",
1715
"errorSameFromTo": "L'origine et la destination doivent être différentes.",
18-
"errorUnsupportedFileType": "Type de fichier non supporté"
16+
"errorInvalidFile": "Fichier invalide"
1917
},
2018
"failure": "Opération échouée",
2119
"from": "Origine",

front/src/common/uploadFileModal.tsx

+4-54
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useContext, useState } from 'react';
1+
import { useContext, useState } from 'react';
22

33
import { Download } from '@osrd-project/ui-icons';
44
import { isNil } from 'lodash';
@@ -16,50 +16,6 @@ const UploadFileModal = ({ handleSubmit }: UploadFileModalProps) => {
1616
const { t } = useTranslation(['operationalStudies/importTrainSchedule']);
1717
const { closeModal } = useContext(ModalContext);
1818
const [selectedFile, setSelectedFile] = useState<File | undefined>(undefined);
19-
const [isValid, setIsValid] = useState<string | undefined>(undefined);
20-
21-
const parseXML = (xmlString: string) => {
22-
try {
23-
const parser = new DOMParser();
24-
const xmlDoc = parser.parseFromString(xmlString, 'application/xml');
25-
const parserError = xmlDoc.getElementsByTagName('parsererror');
26-
if (parserError.length > 0) {
27-
throw new Error('Invalid XML');
28-
}
29-
return undefined;
30-
} catch (error) {
31-
return t('errorMessages.errorInvalidXMLFormat').toString();
32-
}
33-
};
34-
// TODO : create the translation keys
35-
const validateFile = useCallback(
36-
async (fileToValidate: File): Promise<string | undefined> => {
37-
if (fileToValidate.size === 0) {
38-
return t('errorMessages.errorEmptyFile').toString();
39-
}
40-
if (fileToValidate.type === 'application/json') {
41-
try {
42-
JSON.parse(await fileToValidate.text());
43-
} catch (e) {
44-
return t('errorMessages.errorInvalidJSONFormat').toString();
45-
}
46-
} else if (
47-
fileToValidate.type === 'application/railml' ||
48-
fileToValidate.name.endsWith('.railml')
49-
) {
50-
const fileContent = await fileToValidate.text();
51-
const xmlError = parseXML(fileContent);
52-
if (xmlError) {
53-
return xmlError;
54-
}
55-
} else {
56-
return t('errorMessages.errorUnsupportedFileType').toString();
57-
}
58-
59-
return undefined;
60-
},
61-
[t]
62-
);
6319

6420
return (
6521
<>
@@ -73,21 +29,15 @@ const UploadFileModal = ({ handleSubmit }: UploadFileModalProps) => {
7329
<input
7430
type="file"
7531
name="file"
76-
accept=".json,.xml,.railml"
32+
accept=".json,.txt,.xml,.railml"
7733
onChange={async (e) => {
7834
if (e.target.files && e.target.files.length > 0) {
79-
const error = await validateFile(e.target.files[0]);
80-
setIsValid(error);
81-
if (isNil(error)) {
82-
setSelectedFile(e.target.files[0]);
83-
}
35+
setSelectedFile(e.target.files[0]);
8436
} else {
8537
setSelectedFile(undefined);
86-
setIsValid(undefined);
8738
}
8839
}}
8940
/>
90-
{!isNil(isValid) && <div className="text-danger">{isValid}</div>}
9141
</>
9242
</ModalBodySNCF>
9343
<ModalFooterSNCF>
@@ -105,7 +55,7 @@ const UploadFileModal = ({ handleSubmit }: UploadFileModalProps) => {
10555
<div className="col-6">
10656
<button
10757
type="button"
108-
disabled={isNil(selectedFile) || !isNil(isValid)}
58+
disabled={isNil(selectedFile)}
10959
className="btn btn-block btn-sm btn-primary"
11060
onClick={() => {
11161
if (selectedFile) handleSubmit(selectedFile);

front/src/modules/trainschedule/components/ImportTrainSchedule/ImportTrainScheduleConfig.tsx

+23-10
Original file line numberDiff line numberDiff line change
@@ -320,22 +320,35 @@ const ImportTrainScheduleConfig = ({
320320
closeModal();
321321
setTrainsList([]);
322322

323-
const fileName = file.name.toLowerCase();
324-
const fileExtension = fileName.split('.').pop();
323+
let fileContent: string;
324+
try {
325+
fileContent = await file.text();
326+
} catch (error) {
327+
handleFileReadingError(error as Error);
328+
return;
329+
}
325330

326331
try {
327-
const fileContent = await file.text();
332+
processJsonFile(fileContent, setTrainsJsonData);
333+
} catch {
334+
// if file was json, display error message immidiately and return
335+
if (file.type === 'application/json') {
336+
dispatch(
337+
setFailure({
338+
name: t('errorMessages.error'),
339+
message: t('errorMessages.errorInvalidFile'),
340+
})
341+
);
342+
return;
343+
}
328344

329-
if (fileExtension === 'json') {
330-
processJsonFile(fileContent, setTrainsJsonData, dispatch);
331-
} else if (fileExtension === 'xml' || fileExtension === 'railml') {
332-
processXmlFile(fileContent, parseRailML, updateTrainSchedules, dispatch);
333-
} else {
345+
try {
346+
await processXmlFile(fileContent, parseRailML, updateTrainSchedules);
347+
} catch {
334348
handleUnsupportedFileType(dispatch);
335349
}
336-
} catch (error) {
337-
handleFileReadingError(error as Error);
338350
}
351+
339352
};
340353
return (
341354
<>

front/src/modules/trainschedule/components/ManageTrainSchedule/helpers/handleParseFiles.ts

+13-43
Original file line numberDiff line numberDiff line change
@@ -9,62 +9,32 @@ export const handleFileReadingError = (error: Error) => {
99
console.error('File reading error:', error);
1010
};
1111

12-
export const handleJsonParsingError = (error: Error, dispatch: Dispatch) => {
13-
console.error('Error parsing JSON:', error);
14-
dispatch(
15-
setFailure({
16-
name: t('errorMessages.error'),
17-
message: t('errorMessages.errorInvalidJSONFormat'),
18-
})
19-
);
20-
};
21-
22-
export const handleXmlParsingError = (error: Error, dispatch: Dispatch) => {
23-
console.error('Error parsing XML/RailML:', error);
24-
dispatch(
25-
setFailure({
26-
name: t('errorMessages.error'),
27-
message: t('errorMessages.errorInvalidXMLFormat'),
28-
})
29-
);
30-
};
31-
3212
export const processJsonFile = (
3313
fileContent: string,
34-
setTrainsJsonData: (data: TrainScheduleBase[]) => void,
35-
dispatch: Dispatch
14+
setTrainsJsonData: (data: TrainScheduleBase[]) => void
3615
) => {
37-
try {
38-
const importedTrainSchedules: TrainScheduleBase[] = JSON.parse(fileContent);
39-
if (importedTrainSchedules && importedTrainSchedules.length > 0) {
40-
setTrainsJsonData(importedTrainSchedules);
41-
}
42-
} catch (error) {
43-
handleJsonParsingError(error as Error, dispatch);
16+
const importedTrainSchedules: TrainScheduleBase[] = JSON.parse(fileContent);
17+
if (importedTrainSchedules && importedTrainSchedules.length > 0) {
18+
setTrainsJsonData(importedTrainSchedules);
4419
}
4520
};
4621

4722
export const processXmlFile = async (
4823
fileContent: string,
4924
parseRailML: (xmlDoc: Document) => Promise<ImportedTrainSchedule[]>,
5025
updateTrainSchedules: (schedules: ImportedTrainSchedule[]) => void,
51-
dispatch: Dispatch
5226
) => {
53-
try {
54-
const parser = new DOMParser();
55-
const xmlDoc = parser.parseFromString(fileContent, 'application/xml');
56-
const parserError = xmlDoc.getElementsByTagName('parsererror');
27+
const parser = new DOMParser();
28+
const xmlDoc = parser.parseFromString(fileContent, 'application/xml');
29+
const parserError = xmlDoc.getElementsByTagName('parsererror');
5730

58-
if (parserError.length > 0) {
59-
throw new Error('Invalid XML');
60-
}
31+
if (parserError.length > 0) {
32+
throw new Error('Invalid XML');
33+
}
6134

62-
const importedTrainSchedules = await parseRailML(xmlDoc);
63-
if (importedTrainSchedules && importedTrainSchedules.length > 0) {
64-
updateTrainSchedules(importedTrainSchedules);
65-
}
66-
} catch (error) {
67-
handleXmlParsingError(error as Error, dispatch);
35+
const importedTrainSchedules = await parseRailML(xmlDoc);
36+
if (importedTrainSchedules && importedTrainSchedules.length > 0) {
37+
updateTrainSchedules(importedTrainSchedules);
6838
}
6939
};
7040

0 commit comments

Comments
 (0)