-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SIMSBIOHUB-614: Fix file upload error handling. (#1366)
* Split the project/survey report/non-report attachment dialogs into 2 components. Made 2 new attachment dialogs - one for single items, one for many items. Added error handling to catch file upload errors. * Add missing JSDoc. Fix project/survey regular attachments error display (shows error in the list, not as a popup). * Add JSDoc. Add fallback catch to report upload. Fix error popup not displaying error message in body of dialog for the csv upload dialogs. --------- Co-authored-by: Macgregor Aubertin-Young <[email protected]>
- Loading branch information
1 parent
bc5663e
commit 87a60fe
Showing
14 changed files
with
530 additions
and
456 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
87 changes: 87 additions & 0 deletions
87
app/src/components/dialog/attachments/FileUploadDialog.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import Button from '@mui/material/Button'; | ||
import Dialog from '@mui/material/Dialog'; | ||
import DialogActions from '@mui/material/DialogActions'; | ||
import DialogContent from '@mui/material/DialogContent'; | ||
import DialogTitle from '@mui/material/DialogTitle'; | ||
import useTheme from '@mui/material/styles/useTheme'; | ||
import useMediaQuery from '@mui/material/useMediaQuery'; | ||
import { IDropZoneConfigProps } from 'components/file-upload/DropZone'; | ||
import FileUpload from 'components/file-upload/FileUpload'; | ||
import { IUploadHandler } from 'components/file-upload/FileUploadItem'; | ||
import { IComponentDialogProps } from '../ComponentDialog'; | ||
|
||
interface IFileUploadDialogProps extends IComponentDialogProps { | ||
/** | ||
* Set to `true` to open the dialog, `false` to close the dialog. | ||
* | ||
* @type {boolean} | ||
* @memberof IFileUploadDialogProps | ||
*/ | ||
open: boolean; | ||
/** | ||
* The title of the dialog. | ||
* | ||
* @type {string} | ||
* @memberof IFileUploadDialogProps | ||
*/ | ||
dialogTitle: string; | ||
/** | ||
* Callback fired when a file is added. | ||
* | ||
* @memberof IReportFileUploadDialogProps | ||
*/ | ||
uploadHandler: IUploadHandler; | ||
/** | ||
* Callback fired when the dialog is closed. | ||
* | ||
* This function does not need to handle any errors, as the `FileUpload` component handles errors internally. | ||
* | ||
* @memberof IFileUploadDialogProps | ||
*/ | ||
onClose: () => void; | ||
/** | ||
* Drop zone configuration properties. | ||
* | ||
* @type {IDropZoneConfigProps} | ||
* @memberof IFileUploadDialogProps | ||
*/ | ||
dropZoneProps?: IDropZoneConfigProps; | ||
} | ||
|
||
/** | ||
* Wraps the standard `FileUpload` component in a dialog. | ||
* | ||
* The wrapped `FileUpload` component allows for drag-and-drop file uploads of any number of files with any file type. | ||
* | ||
* @param {IFileUploadDialogProps} props | ||
* @return {*} | ||
*/ | ||
export const FileUploadDialog = (props: IFileUploadDialogProps) => { | ||
const { open, dialogTitle, uploadHandler, onClose, dropZoneProps } = props; | ||
|
||
const theme = useTheme(); | ||
const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); | ||
|
||
if (!open) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Dialog | ||
fullScreen={fullScreen} | ||
maxWidth="xl" | ||
open={open} | ||
aria-labelledby="file-upload-dialog-title" | ||
aria-describedby="file-upload-dialog-description"> | ||
<DialogTitle id="file-upload-dialog-title">{dialogTitle}</DialogTitle> | ||
<DialogContent> | ||
<FileUpload uploadHandler={uploadHandler} dropZoneProps={dropZoneProps} /> | ||
</DialogContent> | ||
<DialogActions> | ||
<Button onClick={onClose} color="primary" variant="outlined"> | ||
Close | ||
</Button> | ||
</DialogActions> | ||
</Dialog> | ||
); | ||
}; |
101 changes: 101 additions & 0 deletions
101
app/src/components/dialog/attachments/FileUploadSingleItemDialog.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { LoadingButton } from '@mui/lab'; | ||
import Button from '@mui/material/Button'; | ||
import Dialog from '@mui/material/Dialog'; | ||
import DialogActions from '@mui/material/DialogActions'; | ||
import DialogContent from '@mui/material/DialogContent'; | ||
import DialogTitle from '@mui/material/DialogTitle'; | ||
import useTheme from '@mui/material/styles/useTheme'; | ||
import Typography from '@mui/material/Typography'; | ||
import useMediaQuery from '@mui/material/useMediaQuery'; | ||
import { IDropZoneConfigProps } from 'components/file-upload/DropZone'; | ||
import { UploadFileStatus } from 'components/file-upload/FileUploadItem'; | ||
import { FileUploadSingleItem } from 'components/file-upload/FileUploadSingleItem'; | ||
import { useEffect, useState } from 'react'; | ||
|
||
interface IFileUploadSingleItemDialog { | ||
open: boolean; | ||
dialogTitle: string; | ||
uploadButtonLabel: string; | ||
onUpload: (file: File) => Promise<void>; | ||
onClose?: () => void; | ||
dropZoneProps: Pick<IDropZoneConfigProps, 'acceptedFileExtensions' | 'maxFileSize'>; | ||
} | ||
|
||
/** | ||
* | ||
* | ||
* @param {IFileUploadSingleItemDialog} props | ||
* @return {*} | ||
*/ | ||
export const FileUploadSingleItemDialog = (props: IFileUploadSingleItemDialog) => { | ||
const { open, dialogTitle, uploadButtonLabel, onUpload, onClose, dropZoneProps } = props; | ||
|
||
const theme = useTheme(); | ||
const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); | ||
|
||
const [currentFile, setCurrentFile] = useState<File | null>(null); | ||
const [status, setStatus] = useState<UploadFileStatus>(UploadFileStatus.STAGED); | ||
const [error, setError] = useState<string>(''); | ||
const [isUploading, setIsUploading] = useState<boolean>(false); | ||
|
||
const isDisabled = !currentFile; | ||
|
||
const handleUpload = () => { | ||
if (!currentFile) { | ||
return; | ||
} | ||
|
||
setIsUploading(true); | ||
onUpload(currentFile).finally(() => setIsUploading(false)); | ||
}; | ||
|
||
useEffect(() => { | ||
setCurrentFile(null); | ||
}, [open]); | ||
|
||
if (!open) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Dialog | ||
fullScreen={fullScreen} | ||
maxWidth="xl" | ||
open={open} | ||
aria-labelledby="file-upload-dialog-title" | ||
aria-describedby="file-upload-dialog-description"> | ||
<DialogTitle id="file-upload-dialog-title">{dialogTitle}</DialogTitle> | ||
<DialogContent> | ||
<FileUploadSingleItem | ||
file={currentFile} | ||
status={status} | ||
onStatus={(status) => setStatus(status)} | ||
onFile={(file) => { | ||
setCurrentFile(file); | ||
setError(''); | ||
}} | ||
onError={(error) => setError(error)} | ||
onCancel={() => {}} | ||
DropZoneProps={dropZoneProps} | ||
/> | ||
<Typography variant="body2" color="error"> | ||
{error} | ||
</Typography> | ||
</DialogContent> | ||
<DialogActions> | ||
<LoadingButton | ||
loading={isUploading} | ||
disabled={isDisabled} | ||
onClick={() => handleUpload()} | ||
color="primary" | ||
variant="contained" | ||
autoFocus> | ||
{uploadButtonLabel} | ||
</LoadingButton> | ||
<Button onClick={onClose} color="primary" variant="outlined" disabled={isUploading}> | ||
Close | ||
</Button> | ||
</DialogActions> | ||
</Dialog> | ||
); | ||
}; |
Oops, something went wrong.