diff --git a/src/features/HandleModel/HandleModelComponent/HandleModelComponent.hooks.ts b/src/features/HandleModel/HandleModelComponent/HandleModelComponent.hooks.ts index 64f1a48..fcf9a7d 100644 --- a/src/features/HandleModel/HandleModelComponent/HandleModelComponent.hooks.ts +++ b/src/features/HandleModel/HandleModelComponent/HandleModelComponent.hooks.ts @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { AnalogueModelDetail } from '../../../api/generated'; import { ErrorType, FilesProps } from './HandleModelComponent'; export const useHandleModelComponent = ( - setMetadata: React.Dispatch>, + setMetadata: (analogueModel: AnalogueModelDetail) => void, existingData?: AnalogueModelDetail, ) => { useEffect(() => { diff --git a/src/features/HandleModel/HandleModelComponent/HandleModelComponent.tsx b/src/features/HandleModel/HandleModelComponent/HandleModelComponent.tsx index b2d55a6..b1bbe65 100644 --- a/src/features/HandleModel/HandleModelComponent/HandleModelComponent.tsx +++ b/src/features/HandleModel/HandleModelComponent/HandleModelComponent.tsx @@ -18,20 +18,13 @@ import { validateValues, } from './HandleModelComponent.hooks'; import * as Styled from './HandleModelComponent.styled'; -import { - analogueModelDefault, - usePepmContextStore, -} from '../../../hooks/GlobalState'; +import { usePepmContextStore } from '../../../hooks/GlobalState'; import { readFileAsText } from '../../../utils/ReadIniFile'; import { IniFileTextField } from './HandleModelComponent.styled'; Icon.add({ error_outlined }); interface AddModelDialogProps { - confirm?: ( - file: File, - metadata: AnalogueModelDetail, - iniFile?: File, - ) => Promise; + confirm?: (file: File, iniFile?: File) => Promise; progress?: number; uploading?: boolean; isAddUploading?: boolean; @@ -72,26 +65,30 @@ export const HandleModelComponent = ({ isAddUploading, modelId, }: AddModelDialogProps) => { - const { setAnalogueModelDefault } = usePepmContextStore(); + const { setAnalogueModelDefault, analogueModel, setAnalogueModel } = + usePepmContextStore(); const [isFileDisplay, setFileDisplay] = useState(false); const [files, setFiles] = useState(defaultFiles); const [iniFileString, setIniFileString] = useState(); - const [metadata, setMetadata] = - useState(analogueModelDefault); const [submitting, setSubmitting] = useState(false); const [errors, setErrors] = useState({}); const navigate = useNavigate(); - useHandleModelComponent(setMetadata); + useHandleModelComponent(setAnalogueModel); const handleSubmit = () => { - setErrors(validateValues(metadata, files)); + setErrors(validateValues(analogueModel, files)); setSubmitting(true); }; const fileAdded = (e: React.ChangeEvent) => { if (!e.target.files) return; + if ( + !e.target.files[0].name.endsWith('.nc') && + !e.target.files[0].name.endsWith('.ini') + ) + return; const file = e.target.files[0]; const type = e.target.name; setFiles({ ...files, [type]: file }); @@ -105,15 +102,15 @@ export const HandleModelComponent = ({ const finishSubmit = () => { if (files.NC && confirm && files.INI) { - confirm(files.NC, metadata, files.INI); - } else if (files.NC && confirm) confirm(files.NC, metadata); + confirm(files.NC, files.INI); + } else if (files.NC && confirm) confirm(files.NC); cleanupStates(); }; if (Object.keys(errors).length === 0 && submitting) { finishSubmit(); } - }, [confirm, errors, files, metadata, submitting]); + }, [confirm, errors, files, analogueModel, submitting]); function toggleINIFileContent() { setFileDisplay(!isFileDisplay); @@ -154,9 +151,9 @@ export const HandleModelComponent = ({ {!isAddUploading && ( <> {errors.file && errors.file} @@ -171,7 +168,6 @@ export const HandleModelComponent = ({ )} - {uploading && (

@@ -184,7 +180,6 @@ export const HandleModelComponent = ({ {} )} - {progress === 100 && modelId && ( diff --git a/src/pages/AddModel/AddModel.tsx b/src/pages/AddModel/AddModel.tsx index 1d531ea..47e727d 100644 --- a/src/pages/AddModel/AddModel.tsx +++ b/src/pages/AddModel/AddModel.tsx @@ -7,7 +7,6 @@ import { useEffect, useState } from 'react'; import { AddAnalogueModelMetadataCommandForm, AddMetadataDto, - AnalogueModelDetail, AnalogueModelMetadataService, AnalogueModelsService, ConvertAnalogueModelCommand, @@ -23,26 +22,26 @@ import { SidePane } from '../../features/HandleModel/SidePane/SidePane'; import { ModelMetadataView } from '../../features/ModelView/ModelMetadataView/ModelMetadataView'; import * as Styled from './AddModel.styled'; import { postIniFile } from '../../api/custom/postIniFile'; +import { + analogueModelDefault, + usePepmContextStore, +} from '../../hooks/GlobalState'; enum UploadProcess { SUCCESS = 'Model successfully uploaded and is now beeing processed.', FAILED = 'File upload failed.', } -const defaultCounterValue = 1; -const defaultBeginningOfchunk = 0; export const AddModel = () => { + const { analogueModel, setAnalogueModel } = usePepmContextStore(); const [progress, setProgress] = useState(0); - const [modelId, setModelId] = useState(''); const [uploading, setUploading] = useState(false); - const [counter, setCounter] = useState(defaultCounterValue); + const [counter, setCounter] = useState(1); const [iniFile, setIniFile] = useState(); const [iniFileUploading, setIniFileUploading] = useState(false); const [iniFileSucceeded, setIniFileSucceeded] = useState(false); const [fileToBeUpload, setFileToBeUpload] = useState(); - const [beginingOfTheChunk, setBeginingOfTheChunk] = useState( - defaultBeginningOfchunk, - ); + const [beginingOfTheChunk, setBeginingOfTheChunk] = useState(0); const [endOfTheChunk, setEndOfTheChunk] = useState(); const [fileSize, setFileSize] = useState(0); const [chunkSize, setChunkSize] = useState(0); @@ -114,81 +113,105 @@ export const AddModel = () => { metadataList.push(...obj); } - async function uploadMetadata( - modelId: string, - metadata: AnalogueModelDetail, - ) { - addMetadataFields(metadata.metadata); + async function uploadMetadata(id: string) { + addMetadataFields(analogueModel.metadata); const readyMetadata: AddAnalogueModelMetadataCommandForm = { metadata: metadataList, }; await uploadModelMetadata.mutateAsync({ - id: modelId, + id: id, requestBody: readyMetadata, }); } - async function uploadModel( - file: File, - metadata: AnalogueModelDetail, - iniFile?: File, - ) { + const deleteModel = useMutation({ + mutationFn: ({ id }: { id: string }) => { + return AnalogueModelsService.deleteApiAnalogueModels(id); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['analogue-model'] }); + }, + }); + + async function uploadModel(file: File, iniFile?: File) { + if (file === undefined) return; setUploading(true); + setProgress(1); + const ModelBody: CreateAnalogueModelCommand = { - name: metadata.name ? metadata.name : '', - description: metadata.description, + name: analogueModel.name ? analogueModel.name : '', + description: analogueModel.description, sourceType: 'Deltares', }; const modelUpload = await createModel.mutateAsync(ModelBody); if (createModel.error === null && modelUpload.success) { - const id = modelUpload.data.analogueModelId; - setModelId(id); - setProgress(1); - uploadMetadata(id, metadata); - - if (counter >= chunkCount) { - setCounter(defaultCounterValue); - setBeginingOfTheChunk(defaultBeginningOfchunk); - } + setAnalogueModel({ + ...analogueModel, + analogueModelId: modelUpload.data.analogueModelId, + }); + } - if (file === undefined) return; - - const fileType = UploadFileType.NET_CDF; - const filenameExtention = file.name.split('.').pop(); - const fileExtention = '.' + filenameExtention; - - const data = { - ModelId: id, - FileSize: file.size, - FileName: file.name, - FileExtension: fileExtention, - FileType: fileType, - }; - - const createManifest = await modelManifest.mutateAsync(data); - if (modelManifest.error === null && createManifest.success) { - const uploadId = createManifest.data.uploadId; - const recivedChunkSize = createManifest.data.fileSize; - const numberOfChunks = createManifest.data.numChunks; - setUploadId(uploadId); - setChunkSize(recivedChunkSize); - setEndOfTheChunk(recivedChunkSize); - setChunkCount(numberOfChunks); - setFileToBeUpload(file); - setFileSize(file.size); - } + uploadMetadata(modelUpload.data.analogueModelId); - if (iniFile) { - setIniFile(iniFile); - } + if (counter >= chunkCount) { + setCounter(1); + setBeginingOfTheChunk(0); + } + + const fileType = UploadFileType.NET_CDF; + const filenameExtention = file.name.split('.').pop(); + const fileExtention = '.' + filenameExtention; + + const data = { + ModelId: modelUpload.data.analogueModelId, + FileSize: file.size, + FileName: file.name, + FileExtension: fileExtention, + FileType: fileType, + }; + + const createManifest = await modelManifest.mutateAsync(data); + if (modelManifest.error === null && createManifest.success) { + const uploadId = createManifest.data.uploadId; + const recivedChunkSize = createManifest.data.fileSize; + const numberOfChunks = createManifest.data.numChunks; + setUploadId(uploadId); + setChunkSize(recivedChunkSize); + setEndOfTheChunk(recivedChunkSize); + setChunkCount(numberOfChunks); + setFileToBeUpload(file); + setFileSize(file.size); + } + + if (iniFile) { + setIniFile(iniFile); } } + const resetUpload = async () => { + setUploadStatus(UploadProcess.FAILED); + setProgress(-99); + setUploading(false); + + if (analogueModel.analogueModelId !== '') { + await deleteModel.mutateAsync({ id: analogueModel.analogueModelId }); + setAnalogueModel({ + ...analogueModelDefault, + name: analogueModel.name, + description: analogueModel.description, + }); + } + }; + const fileUpload = (counter: number) => { + if (endOfTheChunk === undefined) return; + setBeginingOfTheChunk(endOfTheChunk); + setEndOfTheChunk(endOfTheChunk + chunkSize); + setCounter(counter + 1); if (counter <= chunkCount) { if (fileToBeUpload === undefined) return; @@ -200,41 +223,41 @@ export const AddModel = () => { }; const uploadChunk = async ({ Blob }: { Blob: Blob }) => { - if (modelId === '' && uploadId === '') return; + if (analogueModel.analogueModelId === '' && uploadId === '') return; const chunkData = { - ModelId: modelId, + ModelId: analogueModel.analogueModelId, UploadId: uploadId, Blob: Blob, ChunkNumber: counter, }; try { const uploadChunks = await chunkUpload.mutateAsync(chunkData); - if (chunkUpload.error === null && uploadChunks.success) { - if (endOfTheChunk === undefined) return; - setBeginingOfTheChunk(endOfTheChunk); - setEndOfTheChunk(endOfTheChunk + chunkSize); if (counter === chunkCount) { const finishBody = { - ModelId: modelId, + ModelId: analogueModel.analogueModelId, UploadId: uploadId, }; const finishedUpload = await uploadFinished.mutateAsync(finishBody); if (uploadFinished.error === null && finishedUpload.success) { - setProgress(100); - - const convert = await convertModelFile.mutateAsync({ - modelId: modelId, - }); - // eslint-disable-next-line max-depth - if (convertModelFile.error === null && convert.success) { - setUploadStatus(UploadProcess.SUCCESS); - setUploading(false); - } else { - setUploadStatus(UploadProcess.FAILED); - setProgress(-99); - setUploading(false); + try { + const convert = await convertModelFile.mutateAsync({ + modelId: analogueModel.analogueModelId, + }); + + // eslint-disable-next-line max-depth + if (convertModelFile.error === null && convert.success) { + setProgress(100); + setUploadStatus(UploadProcess.SUCCESS); + setUploading(false); + } else { + resetUpload(); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + resetUpload(); } } } else { @@ -245,6 +268,7 @@ export const AddModel = () => { } catch (error) { // eslint-disable-next-line no-console console.log('error', error); + resetUpload(); } }; @@ -266,9 +290,17 @@ export const AddModel = () => { return response; }; - if (!iniFileUploading && !iniFileSucceeded && iniFile && modelId) { + if ( + !iniFileUploading && + !iniFileSucceeded && + iniFile && + analogueModel.analogueModelId + ) { setIniFileUploading(true); - const response = uploadIniFileAsync(iniFile, modelId); + const response = uploadIniFileAsync( + iniFile, + analogueModel.analogueModelId, + ); response.then( (res) => { setIniFileSucceeded(true); @@ -278,7 +310,13 @@ export const AddModel = () => { }, ); } - }, [modelId, iniFile, iniFileUploading, iniFileSucceeded, uploadIniFile]); + }, [ + analogueModel.analogueModelId, + iniFile, + iniFileUploading, + iniFileSucceeded, + uploadIniFile, + ]); function clearStatus() { setUploadStatus(undefined); @@ -297,12 +335,12 @@ export const AddModel = () => { uploading={uploading} progress={progress} isAddUploading={progress > 0} - modelId={modelId} + modelId={analogueModel.analogueModelId} /> - {modelId !== '' && ( + {analogueModel.analogueModelId !== '' && ( <>