From d46ec7b02f914c30b7ee1885d5db03b1b2c1cf78 Mon Sep 17 00:00:00 2001 From: Tsu-ba-me Date: Thu, 13 Jan 2022 22:22:31 -0500 Subject: [PATCH] fix(striker-ui): split file upload and edit; make file info reusable --- striker-ui/components/Files/FileInfo.tsx | 101 ++++++------------ .../components/Files/FileUploadInfo.tsx | 96 +++++++++++++++++ striker-ui/components/Files/Files.tsx | 14 +-- striker-ui/lib/consts/UPLOAD_FILE_TYPES.ts | 11 ++ striker-ui/types/UploadFileTypes.d.ts | 1 + 5 files changed, 149 insertions(+), 74 deletions(-) create mode 100644 striker-ui/components/Files/FileUploadInfo.tsx create mode 100644 striker-ui/lib/consts/UPLOAD_FILE_TYPES.ts create mode 100644 striker-ui/types/UploadFileTypes.d.ts diff --git a/striker-ui/components/Files/FileInfo.tsx b/striker-ui/components/Files/FileInfo.tsx index bb989f35..4768472e 100644 --- a/striker-ui/components/Files/FileInfo.tsx +++ b/striker-ui/components/Files/FileInfo.tsx @@ -1,96 +1,63 @@ -import { useEffect, useRef } from 'react'; import { - Box, - Button, Checkbox, + FormControl, FormControlLabel, - Input, - InputLabel, MenuItem, Select, TextField, } from '@mui/material'; -import { BodyText } from '../Text'; + +import { UPLOAD_FILE_TYPES_ARRAY } from '../../lib/consts/UPLOAD_FILE_TYPES'; type FileInfoProps = { - anvilList: { + fileName: string; + fileType: string; + fileSyncAnvilList: { anvilName: string; anvilDescription: string; anvilUUID: string; + isSync: boolean; }[]; - isShowSelectFileOnStart?: boolean; -}; - -const FILE_TYPE_LIST = { - iso: 'ISO (optical disc)', - other: 'Other file type', - script: 'Script (program)', }; -// Used to solve react/require-default-params AND ensure linting works within the function component. -const FILE_INFO_DEFAULT_PROPS = { isShowSelectFileOnStart: false }; - const FileInfo = ({ - anvilList, - isShowSelectFileOnStart = FILE_INFO_DEFAULT_PROPS.isShowSelectFileOnStart, + fileName, + fileType, + fileSyncAnvilList, }: FileInfoProps): JSX.Element => { - const selectFileRef = useRef(); - - const openFilePicker = () => { - selectFileRef.current?.click(); - }; - - useEffect(() => { - if (isShowSelectFileOnStart) { - openFilePicker(); - } - }, [isShowSelectFileOnStart]); - return ( -
- - - - - - - - - - {anvilList.map(({ anvilName, anvilDescription, anvilUUID }) => { + + + + {fileSyncAnvilList.map( + ({ anvilName, anvilDescription, anvilUUID, isSync }) => { return ( } + control={} key={anvilUUID} label={`${anvilName}: ${anvilDescription}`} value={`${anvilUUID}-sync`} /> ); - })} - -
+ }, + )} + ); }; -FileInfo.defaultProps = FILE_INFO_DEFAULT_PROPS; - export default FileInfo; diff --git a/striker-ui/components/Files/FileUploadInfo.tsx b/striker-ui/components/Files/FileUploadInfo.tsx new file mode 100644 index 00000000..e133aa53 --- /dev/null +++ b/striker-ui/components/Files/FileUploadInfo.tsx @@ -0,0 +1,96 @@ +import { ChangeEventHandler, useEffect, useRef, useState } from 'react'; +import { Box, Button, Input, InputLabel } from '@mui/material'; +import EventEmitter from 'events'; + +import { UPLOAD_FILE_TYPES } from '../../lib/consts/UPLOAD_FILE_TYPES'; + +import FileInfo from './FileInfo'; +import { BodyText } from '../Text'; + +type FileUploadInfoProps = { + openFilePickerEventEmitter?: EventEmitter; +}; + +const FILE_UPLOAD_INFO_DEFAULT_PROPS = { + openFilePickerEventEmitter: undefined, +}; + +const FileUploadInfo = ({ + openFilePickerEventEmitter, +}: FileUploadInfoProps = FILE_UPLOAD_INFO_DEFAULT_PROPS): JSX.Element => { + const selectFileRef = useRef(); + + const [selectedFileList, setSelectedFileList] = useState([]); + + const convertMIMETypeToFileTypeKey = ( + fileMIMEType: string, + ): UploadFileTypes => { + const fileTypesIterator = UPLOAD_FILE_TYPES.entries(); + + let fileType: UploadFileTypes | undefined; + + do { + const fileTypesResult = fileTypesIterator.next(); + + if (fileTypesResult.value) { + const [fileTypeKey, [mimeTypeToUse]] = fileTypesResult.value; + + if (fileMIMEType === mimeTypeToUse) { + fileType = fileTypeKey; + } + } else { + fileType = 'other'; + } + } while (!fileType); + + return fileType; + }; + + const autocompleteAfterSelectFile: ChangeEventHandler = ({ + target: { files }, + }) => { + if (files) { + setSelectedFileList(Array.from(files)); + } + }; + + useEffect(() => { + openFilePickerEventEmitter?.addListener('open', () => { + selectFileRef.current?.click(); + }); + }, [openFilePickerEventEmitter]); + + return ( +
+ + + + + {selectedFileList.map((file: File) => ( + + ))} + {selectedFileList.length > 0 && ( + + )} + +
+ ); +}; + +FileUploadInfo.defaultProps = FILE_UPLOAD_INFO_DEFAULT_PROPS; + +export default FileUploadInfo; diff --git a/striker-ui/components/Files/Files.tsx b/striker-ui/components/Files/Files.tsx index 8209a8fa..17673460 100644 --- a/striker-ui/components/Files/Files.tsx +++ b/striker-ui/components/Files/Files.tsx @@ -1,7 +1,7 @@ -import { useState } from 'react'; import { Box, IconButton } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import { styled } from '@mui/material/styles'; +import EventEmitter from 'events'; import ICON_BUTTON_STYLE from '../../lib/consts/ICON_BUTTON_STYLE'; @@ -9,8 +9,8 @@ import { Panel } from '../Panels'; import PeriodicFetch from '../../lib/fetchers/periodicFetch'; import Spinner from '../Spinner'; import { HeaderText } from '../Text'; -import FileInfo from './FileInfo'; import FileList from './FileList'; +import FileUploadInfo from './FileUploadInfo'; const PREFIX = 'Files'; @@ -28,14 +28,14 @@ const StyledDiv = styled('div')(() => ({ })); const Files = (): JSX.Element => { - const [isShowUploadForm, setIsShowUploadForm] = useState(false); + const openFilePickerEventEmitter: EventEmitter = new EventEmitter(); const { data: fileList, isLoading } = PeriodicFetch( `${process.env.NEXT_PUBLIC_API_URL?.replace('/cgi-bin', '/api')}/files`, ); const onAddFileButtonClick = () => { - setIsShowUploadForm(!isShowUploadForm); + openFilePickerEventEmitter.emit('open'); }; return ( @@ -54,9 +54,9 @@ const Files = (): JSX.Element => { - {isShowUploadForm && ( - - )} + {isLoading ? : } diff --git a/striker-ui/lib/consts/UPLOAD_FILE_TYPES.ts b/striker-ui/lib/consts/UPLOAD_FILE_TYPES.ts new file mode 100644 index 00000000..5fa3d4b0 --- /dev/null +++ b/striker-ui/lib/consts/UPLOAD_FILE_TYPES.ts @@ -0,0 +1,11 @@ +export const UPLOAD_FILE_TYPES_ARRAY: ReadonlyArray< + [UploadFileTypes, [string, string]] +> = [ + ['iso', ['application/x-cd-image', 'ISO (optical disc)']], + ['other', ['text/plain', 'Other file type']], + ['script', ['text/plain', 'Script (program)']], +]; +export const UPLOAD_FILE_TYPES: ReadonlyMap< + UploadFileTypes, + [string, string] +> = new Map(UPLOAD_FILE_TYPES_ARRAY); diff --git a/striker-ui/types/UploadFileTypes.d.ts b/striker-ui/types/UploadFileTypes.d.ts new file mode 100644 index 00000000..c6978890 --- /dev/null +++ b/striker-ui/types/UploadFileTypes.d.ts @@ -0,0 +1 @@ +declare type UploadFileTypes = 'iso' | 'other' | 'script';