diff --git a/optuna_dashboard/ts/components/TrialArtifactCards.tsx b/optuna_dashboard/ts/components/TrialArtifactCards.tsx new file mode 100644 index 00000000..7f9550e6 --- /dev/null +++ b/optuna_dashboard/ts/components/TrialArtifactCards.tsx @@ -0,0 +1,434 @@ +import React, { + ChangeEventHandler, + DragEventHandler, + FC, + MouseEventHandler, + useRef, + useState, +} from "react" +import { + Typography, + Box, + useTheme, + IconButton, + Card, + CardContent, + CardMedia, + CardActionArea, +} from "@mui/material" +import UploadFileIcon from "@mui/icons-material/UploadFile" +import DownloadIcon from "@mui/icons-material/Download" +import DeleteIcon from "@mui/icons-material/Delete" +import FullscreenIcon from "@mui/icons-material/Fullscreen" +import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile" + +import { actionCreator } from "../action" +import { useDeleteArtifactDialog } from "./DeleteArtifactDialog" +import { + ThreejsArtifactViewer, + useThreejsArtifactModal, +} from "./ThreejsArtifactViewer" + +export const TrialArtifactCards: FC<{ trial: Trial }> = ({ trial }) => { + const theme = useTheme() + const action = actionCreator() + const [openDeleteArtifactDialog, renderDeleteArtifactDialog] = + useDeleteArtifactDialog() + const [dragOver, setDragOver] = useState(false) + const [openThreejsArtifactModal, renderThreejsArtifactModal] = + useThreejsArtifactModal() + + const width = "200px" + const height = "150px" + + const inputRef = useRef(null) + const handleClick: MouseEventHandler = () => { + if (!inputRef || !inputRef.current) { + return + } + inputRef.current.click() + } + const handleOnChange: ChangeEventHandler = (e) => { + const files = e.target.files + if (files === null) { + return + } + action.uploadArtifact(trial.study_id, trial.trial_id, files[0]) + } + const handleDrop: DragEventHandler = (e) => { + e.stopPropagation() + e.preventDefault() + const files = e.dataTransfer.files + setDragOver(false) + for (let i = 0; i < files.length; i++) { + action.uploadArtifact(trial.study_id, trial.trial_id, files[i]) + } + } + const handleDragOver: DragEventHandler = (e) => { + e.stopPropagation() + e.preventDefault() + e.dataTransfer.dropEffect = "copy" + setDragOver(true) + } + const handleDragLeave: DragEventHandler = (e) => { + e.stopPropagation() + e.preventDefault() + e.dataTransfer.dropEffect = "copy" + setDragOver(false) + } + + return ( + <> + + Artifacts + + + {trial.artifacts.map((a) => { + const artifactUrlPath = `/artifacts/${trial.study_id}/${trial.trial_id}/${a.artifact_id}` + if (a.mimetype.startsWith("image")) { + return ( + + + + + {a.filename} + + { + openDeleteArtifactDialog( + trial.study_id, + trial.trial_id, + a + ) + }} + > + + + + + + + + ) + } else if ( + a.filename.endsWith(".stl") || + a.filename.endsWith(".3dm") + ) { + return ( + + + + + + + {a.filename} + + { + openThreejsArtifactModal(artifactUrlPath, a) + }} + > + + + { + openDeleteArtifactDialog( + trial.study_id, + trial.trial_id, + a + ) + }} + > + + + + + + + + ) + } else if (a.mimetype.startsWith("audio")) { + return ( + + + + + + + {a.filename} + + { + openDeleteArtifactDialog( + trial.study_id, + trial.trial_id, + a + ) + }} + > + + + + + + + + ) + } else { + return ( + + + + + + + {a.filename} + + { + openDeleteArtifactDialog( + trial.study_id, + trial.trial_id, + a + ) + }} + > + + + + + + + + ) + } + })} + {trial.state === "Running" || trial.state === "Waiting" ? ( + + + + + + Upload a New File + + Drag your file here or click to browse. + + + + + ) : null} + + {renderDeleteArtifactDialog()} + {renderThreejsArtifactModal()} + + ) +} diff --git a/optuna_dashboard/ts/components/TrialList.tsx b/optuna_dashboard/ts/components/TrialList.tsx index 2ce525b6..6922003a 100644 --- a/optuna_dashboard/ts/components/TrialList.tsx +++ b/optuna_dashboard/ts/components/TrialList.tsx @@ -1,13 +1,4 @@ -import React, { - ChangeEventHandler, - DragEventHandler, - FC, - MouseEventHandler, - ReactNode, - useMemo, - useRef, - useState, -} from "react" +import React, { FC, ReactNode, useMemo } from "react" import { Typography, Box, @@ -16,10 +7,6 @@ import { IconButton, Menu, MenuItem, - Card, - CardContent, - CardMedia, - CardActionArea, } from "@mui/material" import Chip from "@mui/material/Chip" import Divider from "@mui/material/Divider" @@ -31,11 +18,6 @@ import ListSubheader from "@mui/material/ListSubheader" import FilterListIcon from "@mui/icons-material/FilterList" import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank" import CheckBoxIcon from "@mui/icons-material/CheckBox" -import UploadFileIcon from "@mui/icons-material/UploadFile" -import DownloadIcon from "@mui/icons-material/Download" -import DeleteIcon from "@mui/icons-material/Delete" -import FullscreenIcon from "@mui/icons-material/Fullscreen" -import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile" import StopCircleIcon from "@mui/icons-material/StopCircle" import { TrialNote } from "./Note" @@ -44,12 +26,8 @@ import ListItemIcon from "@mui/material/ListItemIcon" import { useRecoilValue } from "recoil" import { artifactIsAvailable } from "../state" import { actionCreator } from "../action" -import { useDeleteArtifactDialog } from "./DeleteArtifactDialog" import { TrialFormWidgets } from "./TrialFormWidgets" -import { - ThreejsArtifactViewer, - useThreejsArtifactModal, -} from "./ThreejsArtifactViewer" +import { TrialArtifactCards } from "./TrialArtifactCards" const states: TrialState[] = [ "Complete", @@ -321,418 +299,11 @@ export const TrialListDetail: FC<{ value !== null ? renderInfo(key, value) : null )} - {artifactEnabled && } + {artifactEnabled && } ) } -const TrialArtifact: FC<{ trial: Trial }> = ({ trial }) => { - const theme = useTheme() - const action = actionCreator() - const [openDeleteArtifactDialog, renderDeleteArtifactDialog] = - useDeleteArtifactDialog() - const [dragOver, setDragOver] = useState(false) - const [openThreejsArtifactModal, renderThreejsArtifactModal] = - useThreejsArtifactModal() - - const width = "200px" - const height = "150px" - - const inputRef = useRef(null) - const handleClick: MouseEventHandler = () => { - if (!inputRef || !inputRef.current) { - return - } - inputRef.current.click() - } - const handleOnChange: ChangeEventHandler = (e) => { - const files = e.target.files - if (files === null) { - return - } - action.uploadArtifact(trial.study_id, trial.trial_id, files[0]) - } - const handleDrop: DragEventHandler = (e) => { - e.stopPropagation() - e.preventDefault() - const files = e.dataTransfer.files - setDragOver(false) - for (let i = 0; i < files.length; i++) { - action.uploadArtifact(trial.study_id, trial.trial_id, files[i]) - } - } - const handleDragOver: DragEventHandler = (e) => { - e.stopPropagation() - e.preventDefault() - e.dataTransfer.dropEffect = "copy" - setDragOver(true) - } - const handleDragLeave: DragEventHandler = (e) => { - e.stopPropagation() - e.preventDefault() - e.dataTransfer.dropEffect = "copy" - setDragOver(false) - } - - return ( - <> - - Artifacts - - - {trial.artifacts.map((a) => { - const artifactUrlPath = `/artifacts/${trial.study_id}/${trial.trial_id}/${a.artifact_id}` - if (a.mimetype.startsWith("image")) { - return ( - - - - - {a.filename} - - { - openDeleteArtifactDialog( - trial.study_id, - trial.trial_id, - a - ) - }} - > - - - - - - - - ) - } else if ( - a.filename.endsWith(".stl") || - a.filename.endsWith(".3dm") - ) { - return ( - - - - - - - {a.filename} - - { - openThreejsArtifactModal(artifactUrlPath, a) - }} - > - - - { - openDeleteArtifactDialog( - trial.study_id, - trial.trial_id, - a - ) - }} - > - - - - - - - - ) - } else if (a.mimetype.startsWith("audio")) { - return ( - - - - - - - {a.filename} - - { - openDeleteArtifactDialog( - trial.study_id, - trial.trial_id, - a - ) - }} - > - - - - - - - - ) - } else { - return ( - - - - - - - {a.filename} - - { - openDeleteArtifactDialog( - trial.study_id, - trial.trial_id, - a - ) - }} - > - - - - - - - - ) - } - })} - {trial.state === "Running" || trial.state === "Waiting" ? ( - - - - - - Upload a New File - - Drag your file here or click to browse. - - - - - ) : null} - - {renderDeleteArtifactDialog()} - {renderThreejsArtifactModal()} - - ) -} - const getTrialListLink = ( studyId: number, exclude: TrialState[],