parent
b2b347fc72
commit
2e5dd3523b
14 changed files with 401 additions and 117 deletions
@ -0,0 +1,168 @@ |
|||||||
|
import { |
||||||
|
FormEventHandler, |
||||||
|
MouseEventHandler, |
||||||
|
useEffect, |
||||||
|
useState, |
||||||
|
} from 'react'; |
||||||
|
import { Box, Button, Checkbox, checkboxClasses } from '@mui/material'; |
||||||
|
|
||||||
|
import { GREY, TEXT } from '../../lib/consts/DEFAULT_THEME'; |
||||||
|
|
||||||
|
import { BodyText } from '../Text'; |
||||||
|
import FileInfo from './FileInfo'; |
||||||
|
import fetchJSON from '../../lib/fetchers/fetchJSON'; |
||||||
|
import mainAxiosInstance from '../../lib/singletons/mainAxiosInstance'; |
||||||
|
|
||||||
|
type FileEditProps = { |
||||||
|
filesOverview: FileOverviewMetadata[]; |
||||||
|
}; |
||||||
|
|
||||||
|
type FileToEdit = FileDetailMetadata & { |
||||||
|
dataIncompleteError?: unknown; |
||||||
|
isSelected?: boolean; |
||||||
|
}; |
||||||
|
|
||||||
|
const FileEditForm = ({ filesOverview }: FileEditProps): JSX.Element => { |
||||||
|
const [filesToEdit, setFilesToEdit] = useState<FileToEdit[]>([]); |
||||||
|
|
||||||
|
const generateFileInfoChangeHandler = ( |
||||||
|
fileIndex: number, |
||||||
|
): FileInfoChangeHandler => (inputValues, { fileLocationIndex } = {}) => { |
||||||
|
if (fileLocationIndex) { |
||||||
|
filesToEdit[fileIndex].fileLocations[fileLocationIndex] = { |
||||||
|
...filesToEdit[fileIndex].fileLocations[fileLocationIndex], |
||||||
|
...inputValues, |
||||||
|
}; |
||||||
|
} else { |
||||||
|
filesToEdit[fileIndex] = { |
||||||
|
...filesToEdit[fileIndex], |
||||||
|
...inputValues, |
||||||
|
}; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const editFiles: FormEventHandler<HTMLFormElement> = (event) => { |
||||||
|
event.preventDefault(); |
||||||
|
|
||||||
|
filesToEdit.forEach(({ fileLocations, fileName, fileType, fileUUID }) => { |
||||||
|
mainAxiosInstance.put( |
||||||
|
`/files/${fileUUID}`, |
||||||
|
JSON.stringify({ |
||||||
|
fileName, |
||||||
|
fileType, |
||||||
|
fileLocations: fileLocations.map( |
||||||
|
({ fileLocationUUID, isFileLocationActive }) => ({ |
||||||
|
fileLocationUUID, |
||||||
|
isFileLocationActive, |
||||||
|
}), |
||||||
|
), |
||||||
|
}), |
||||||
|
{ |
||||||
|
headers: { 'Content-Type': 'application/json' }, |
||||||
|
}, |
||||||
|
); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const purgeFiles: MouseEventHandler<HTMLButtonElement> = () => { |
||||||
|
filesToEdit |
||||||
|
.filter(({ isSelected }) => isSelected) |
||||||
|
.forEach(({ fileUUID }) => { |
||||||
|
mainAxiosInstance.delete(`/files/${fileUUID}`); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
Promise.all( |
||||||
|
filesOverview.map(async (fileOverview: FileOverviewMetadata) => { |
||||||
|
const fileToEdit: FileToEdit = { |
||||||
|
...fileOverview, |
||||||
|
fileLocations: [], |
||||||
|
}; |
||||||
|
|
||||||
|
try { |
||||||
|
const data = await fetchJSON<string[][]>( |
||||||
|
`${process.env.NEXT_PUBLIC_API_URL?.replace( |
||||||
|
'/cgi-bin', |
||||||
|
'/api', |
||||||
|
)}/files/${fileOverview.fileUUID}`,
|
||||||
|
); |
||||||
|
|
||||||
|
fileToEdit.fileLocations = data.map( |
||||||
|
([ |
||||||
|
, |
||||||
|
, |
||||||
|
, |
||||||
|
, |
||||||
|
, |
||||||
|
fileLocationUUID, |
||||||
|
fileLocationActive, |
||||||
|
anvilUUID, |
||||||
|
anvilName, |
||||||
|
anvilDescription, |
||||||
|
]) => ({ |
||||||
|
anvilDescription, |
||||||
|
anvilName, |
||||||
|
anvilUUID, |
||||||
|
fileLocationUUID, |
||||||
|
isFileLocationActive: parseInt(fileLocationActive, 10) === 1, |
||||||
|
}), |
||||||
|
); |
||||||
|
} catch (fetchError) { |
||||||
|
fileToEdit.dataIncompleteError = fetchError; |
||||||
|
} |
||||||
|
|
||||||
|
return fileToEdit; |
||||||
|
}), |
||||||
|
).then((fetchedFilesDetail) => setFilesToEdit(fetchedFilesDetail)); |
||||||
|
}, [filesOverview]); |
||||||
|
|
||||||
|
return ( |
||||||
|
<form onSubmit={editFiles}> |
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column' }}> |
||||||
|
{filesToEdit.map( |
||||||
|
({ fileName, fileLocations, fileType, fileUUID }, fileIndex) => ( |
||||||
|
<Box |
||||||
|
key={`file-edit-${fileUUID}`} |
||||||
|
sx={{ |
||||||
|
display: 'flex', |
||||||
|
flexDirection: 'row', |
||||||
|
}} |
||||||
|
> |
||||||
|
<Checkbox |
||||||
|
onChange={({ target: { checked } }) => { |
||||||
|
filesToEdit[fileIndex].isSelected = checked; |
||||||
|
}} |
||||||
|
sx={{ |
||||||
|
color: GREY, |
||||||
|
|
||||||
|
[`&.${checkboxClasses.checked}`]: { |
||||||
|
color: TEXT, |
||||||
|
}, |
||||||
|
}} |
||||||
|
/> |
||||||
|
<FileInfo |
||||||
|
fileName={fileName} |
||||||
|
fileType={fileType} |
||||||
|
fileLocations={fileLocations} |
||||||
|
onChange={generateFileInfoChangeHandler(fileIndex)} |
||||||
|
/> |
||||||
|
</Box> |
||||||
|
), |
||||||
|
)} |
||||||
|
{filesToEdit.length > 0 && ( |
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'row' }}> |
||||||
|
<Button onClick={purgeFiles} sx={{ textTransform: 'none' }}> |
||||||
|
<BodyText text="Purge" /> |
||||||
|
</Button> |
||||||
|
<Button sx={{ textTransform: 'none' }} type="submit"> |
||||||
|
<BodyText text="Update" /> |
||||||
|
</Button> |
||||||
|
</Box> |
||||||
|
)} |
||||||
|
</Box> |
||||||
|
</form> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default FileEditForm; |
@ -1,11 +1,11 @@ |
|||||||
export const UPLOAD_FILE_TYPES_ARRAY: ReadonlyArray< |
export const UPLOAD_FILE_TYPES_ARRAY: ReadonlyArray< |
||||||
[UploadFileType, [string, string]] |
[FileType, [string, string]] |
||||||
> = [ |
> = [ |
||||||
['iso', ['application/x-cd-image', 'ISO (optical disc)']], |
['iso', ['application/x-cd-image', 'ISO (optical disc)']], |
||||||
['other', ['text/plain', 'Other file type']], |
['other', ['text/plain', 'Other file type']], |
||||||
['script', ['text/plain', 'Script (program)']], |
['script', ['text/plain', 'Script (program)']], |
||||||
]; |
]; |
||||||
export const UPLOAD_FILE_TYPES: ReadonlyMap< |
export const UPLOAD_FILE_TYPES: ReadonlyMap< |
||||||
UploadFileType, |
FileType, |
||||||
[string, string] |
[string, string] |
||||||
> = new Map(UPLOAD_FILE_TYPES_ARRAY); |
> = new Map(UPLOAD_FILE_TYPES_ARRAY); |
||||||
|
@ -0,0 +1,3 @@ |
|||||||
|
type FileDetailMetadata = FileOverviewMetadata & { |
||||||
|
fileLocations: FileLocation[]; |
||||||
|
}; |
@ -0,0 +1,4 @@ |
|||||||
|
type FileInfoChangeHandler = ( |
||||||
|
inputValues: Partial<FileDetailMetadata> | Partial<FileLocation>, |
||||||
|
options?: { fileLocationIndex?: number }, |
||||||
|
) => void; |
@ -1 +0,0 @@ |
|||||||
declare type FileInfoMetadata = Omit<FileInfoProps, 'onChange'>; |
|
@ -1,11 +0,0 @@ |
|||||||
declare type FileInfoProps = { |
|
||||||
fileName: string; |
|
||||||
fileType: UploadFileType; |
|
||||||
fileSyncAnvils: Array<{ |
|
||||||
anvilName: string; |
|
||||||
anvilDescription: string; |
|
||||||
anvilUUID: string; |
|
||||||
isSync: boolean; |
|
||||||
}>; |
|
||||||
onChange?: (inputValues: Partial<FileInfoMetadata>) => void; |
|
||||||
}; |
|
@ -0,0 +1,7 @@ |
|||||||
|
type FileLocation = { |
||||||
|
anvilName: string; |
||||||
|
anvilDescription: string; |
||||||
|
anvilUUID: string; |
||||||
|
fileLocationUUID: string; |
||||||
|
isFileLocationActive: boolean; |
||||||
|
}; |
@ -0,0 +1,7 @@ |
|||||||
|
type FileOverviewMetadata = { |
||||||
|
fileChecksum: string; |
||||||
|
fileName: string; |
||||||
|
fileSizeInBytes: number; |
||||||
|
fileType: FileType; |
||||||
|
fileUUID: string; |
||||||
|
}; |
@ -0,0 +1 @@ |
|||||||
|
declare type FileType = 'iso' | 'other' | 'script'; |
@ -1 +0,0 @@ |
|||||||
declare type UploadFileType = 'iso' | 'other' | 'script'; |
|
Loading…
Reference in new issue