frontend/src/components/addDataset/AddDataset.tsx (192 lines of code) (raw):

import React, { useState, FC, useEffect } from 'react'; import { useForm, Controller } from 'react-hook-form'; import { useLocation } from 'react-router-dom'; import { Button, FormControl, InputAdornment, InputLabel, Select, Tab, Tabs, TextField, MenuItem, DialogActions, DialogTitle, DialogContent } from '@material-ui/core'; import { unwrapResult } from '@reduxjs/toolkit'; import { useAppDispatch, useTypedSelector } from '../../store'; import { addExistingDataset, uploadMediaFiles } from '../../store/media'; import { UploadPaper, UploadDescription, BucketsSelect, IFormData } from './utils'; import { UploadFiles } from './uploadImages'; import '../tasksStatuses/createTaskDialog/CreateTaskDialog.tsx'; // @todo create component for dialog and put there styles export const AddDataset: FC<any> = (props) => { const location = useLocation() as any; const dispatch = useAppDispatch(); const [files, setFiles] = useState<File[]>([]); const buckets = useTypedSelector((state) => state.data.buckets); const [submitAction, setSubmitAction] = useState(0); useEffect( () => () => { files.forEach((file: any) => URL.revokeObjectURL(file.preview)); }, [files] ); const { handleSubmit, control, register, reset, formState } = useForm< IFormData >({ mode: 'onChange', defaultValues: { bucketId: location.state?.dataset.bucket ?? '', path: location.state?.dataset.path.replace('/', '') ?? '', format: location.state?.dataset.format ?? '' } }); const resetForm = () => { reset({ path: '', bucketId: '', format: '' }); }; const AddExistingDataset = ( bucketId: string, path: string, format: string ) => { dispatch(addExistingDataset({ bucketId, path, format })) .then(unwrapResult) .then(() => { resetForm(); }) .catch(() => {}); }; const UploadImages = (bucketId: string, path: string, format: string) => { dispatch(uploadMediaFiles({ files, bucketId, path, format })) .then(unwrapResult) .then(() => { resetForm(); setFiles([]); }) .catch(() => {}); }; const onSubmit = handleSubmit(({ bucketId, path, format }) => { if (submitAction) { AddExistingDataset(bucketId, path, format); } else { UploadImages(bucketId, path, format); } }); const UploadImagesComp = Object.assign( (navProps: any) => ( <UploadFiles {...navProps} files={files} setFiles={setFiles} /> ), { displayName: 'UploadImagesComp' } ); const UploadDescriptionComp = Object.assign( () => ( <UploadDescription variant="body2"> <span> Images should be already upload to the bucket (e.g. by CyberDuck) and not to be referenced in the database yet </span> </UploadDescription> ), { displayName: 'UploadDescriptionComp' } ); const subTabs = [ { label: 'upload images', path: 'upload', component: UploadImagesComp }, { label: 'add Existing Bucket Path', path: 'add', component: UploadDescriptionComp } ]; return ( <> <DialogTitle>Add Dataset</DialogTitle> <form onSubmit={onSubmit} className="dialog-form"> <DialogContent dividers> <UploadPaper variant="outlined"> <Tabs indicatorColor="primary" textColor="primary" value={submitAction} onChange={(_, newValue: any) => setSubmitAction(newValue)} aria-label="add Dataset Example" > {subTabs.map((item) => ( <Tab label={item.label} key={item.path} /> ))} </Tabs> {subTabs.map((item, index) => submitAction === index ? <item.component /> : null )} </UploadPaper> <FormControl> <InputLabel id="upload-images-bucket-name">Bucket</InputLabel> <Controller labelId="upload-images-bucket-name" name="bucketId" control={control} rules={{ required: true }} label="Bucket" defaultValue="" as={<Select>{BucketsSelect(buckets)}</Select>} /> </FormControl> <FormControl> <InputLabel id="dataset-format">Format</InputLabel> <Controller labelId="dataset-format" name="format" control={control} rules={{ required: true }} label="Format" defaultValue="" as={ <Select> <MenuItem value="PASCAL_VOC">PASCAL VOC</MenuItem> <MenuItem value="YOLO">YOLO</MenuItem> </Select> } /> </FormControl> <TextField name="path" label="Dataset path" inputRef={register({ required: true })} InputProps={{ startAdornment: ( <InputAdornment position="start">/</InputAdornment> ) }} /> </DialogContent> <DialogActions> <Button type="button" color="primary" onClick={props.onClose}> Close </Button> <Button type="submit" color="primary" variant="contained" disabled={!formState.isValid} > {subTabs[submitAction].path} </Button> </DialogActions> </form> </> ); };