mirror of
https://github.com/wassname/optuna-dashboard.git
synced 2026-09-23 13:30:25 +08:00
Add mini drawer
This commit is contained in:
@@ -4,9 +4,7 @@ import { Link, useParams } from "react-router-dom"
|
||||
import MuiDrawer from "@mui/material/Drawer"
|
||||
import IconButton from "@mui/material/IconButton"
|
||||
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"
|
||||
import ClearIcon from "@mui/icons-material/Clear"
|
||||
import Divider from "@mui/material/Divider"
|
||||
import MenuIcon from "@mui/icons-material/Menu"
|
||||
import List from "@mui/material/List"
|
||||
import ListItem from "@mui/material/ListItem"
|
||||
import ListItemButton from "@mui/material/ListItemButton"
|
||||
@@ -22,21 +20,16 @@ import {
|
||||
Theme,
|
||||
CSSObject,
|
||||
styled,
|
||||
Typography,
|
||||
Toolbar,
|
||||
} from "@mui/material"
|
||||
import AutoGraphIcon from "@mui/icons-material/AutoGraph"
|
||||
import SyncIcon from "@mui/icons-material/Sync"
|
||||
import SyncDisabledIcon from "@mui/icons-material/SyncDisabled"
|
||||
import HomeIcon from "@mui/icons-material/Home"
|
||||
import Brightness4Icon from "@mui/icons-material/Brightness4"
|
||||
import Brightness7Icon from "@mui/icons-material/Brightness7"
|
||||
import TableViewIcon from "@mui/icons-material/TableView"
|
||||
import RateReviewIcon from "@mui/icons-material/RateReview"
|
||||
|
||||
import { GraphHistory } from "./GraphHistory"
|
||||
import { Note } from "./Note"
|
||||
import { actionCreator } from "../action"
|
||||
import { reloadIntervalState, studyDetailsState } from "../state"
|
||||
import { TrialTable } from "./TrialTable"
|
||||
import { StudyDetailDrawer } from "./StudyDetailDrawer"
|
||||
|
||||
interface ParamTypes {
|
||||
studyId: string
|
||||
@@ -131,219 +124,11 @@ export const StudyDetailBeta: FC<{
|
||||
<Box sx={{ display: "flex" }}>
|
||||
<StudyDetailDrawer
|
||||
studyId={studyIdNumber}
|
||||
toggleColorMode={toggleColorMode}
|
||||
page={page}
|
||||
/>
|
||||
{content}
|
||||
toggleColorMode={toggleColorMode}
|
||||
>
|
||||
{content}
|
||||
</StudyDetailDrawer>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const StudyDetailDrawer: FC<{
|
||||
studyId: number
|
||||
toggleColorMode: () => void
|
||||
page: PageId
|
||||
}> = ({ studyId, toggleColorMode, page }) => {
|
||||
const theme = useTheme()
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const drawerWidth = 240
|
||||
const [reloadInterval, updateReloadInterval] =
|
||||
useRecoilState<number>(reloadIntervalState)
|
||||
|
||||
const openedMixin = (theme: Theme): CSSObject => ({
|
||||
width: drawerWidth,
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
})
|
||||
const closedMixin = (theme: Theme): CSSObject => ({
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
width: `calc(${theme.spacing(7)} + 1px)`,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: `calc(${theme.spacing(8)} + 1px)`,
|
||||
},
|
||||
})
|
||||
const DrawerHeader = styled("div")(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
padding: theme.spacing(0, 1),
|
||||
// necessary for content to be below app bar
|
||||
...theme.mixins.toolbar,
|
||||
}))
|
||||
|
||||
const Drawer = styled(MuiDrawer, {
|
||||
shouldForwardProp: (prop) => prop !== "open",
|
||||
})(({ theme, open }) => ({
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
whiteSpace: "nowrap",
|
||||
boxSizing: "border-box",
|
||||
...(open && {
|
||||
...openedMixin(theme),
|
||||
"& .MuiDrawer-paper": openedMixin(theme),
|
||||
}),
|
||||
...(!open && {
|
||||
...closedMixin(theme),
|
||||
"& .MuiDrawer-paper": closedMixin(theme),
|
||||
}),
|
||||
}))
|
||||
|
||||
const styleListItem = {
|
||||
display: "block",
|
||||
}
|
||||
const styleListItemButton = {
|
||||
minHeight: 48,
|
||||
justifyContent: open ? "initial" : "center",
|
||||
px: 2.5,
|
||||
}
|
||||
const styleListItemIcon = {
|
||||
minWidth: 0,
|
||||
mr: open ? 3 : "auto",
|
||||
justifyContent: "center",
|
||||
}
|
||||
const styleListItemText = {
|
||||
opacity: open ? 1 : 0,
|
||||
}
|
||||
const styleSwitch = {
|
||||
display: open ? "inherit" : "none",
|
||||
}
|
||||
|
||||
return (
|
||||
<Drawer variant="permanent" anchor="left" open={open}>
|
||||
<DrawerHeader sx={open ? {} : { padding: 0, justifyContent: "center" }}>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
setOpen(!open)
|
||||
}}
|
||||
>
|
||||
{open ? <ChevronLeftIcon /> : <MenuIcon />}
|
||||
</IconButton>
|
||||
</DrawerHeader>
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem key="Top" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}/beta`}
|
||||
sx={styleListItemButton}
|
||||
selected={page === "top"}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<AutoGraphIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="History" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem key="Table" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}/trials`}
|
||||
sx={styleListItemButton}
|
||||
selected={page === "trials"}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<TableViewIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Trials" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem key="Note" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}/note`}
|
||||
sx={styleListItemButton}
|
||||
selected={page === "note"}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<RateReviewIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Note" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem key="Home" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={URL_PREFIX + "/"}
|
||||
sx={styleListItemButton}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<HomeIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Return to Home" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem key="LiveUpdate" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
sx={styleListItemButton}
|
||||
onClick={() => {
|
||||
updateReloadInterval(reloadInterval === -1 ? 10 : -1)
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
{reloadInterval === -1 ? <SyncDisabledIcon /> : <SyncIcon />}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Live Update" sx={styleListItemText} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={reloadInterval !== -1}
|
||||
sx={styleSwitch}
|
||||
inputProps={{
|
||||
"aria-labelledby": "switch-list-label-live-update",
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem key="DarkMode" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
sx={styleListItemButton}
|
||||
onClick={() => {
|
||||
toggleColorMode()
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
{theme.palette.mode === "dark" ? (
|
||||
<Brightness4Icon />
|
||||
) : (
|
||||
<Brightness7Icon />
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Dark Mode" sx={styleListItemText} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={theme.palette.mode === "dark"}
|
||||
sx={styleSwitch}
|
||||
inputProps={{
|
||||
"aria-labelledby": "switch-list-label-dark-mode",
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem key="BetaUI" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}`}
|
||||
sx={styleListItemButton}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<ClearIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Quit Beta UI" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
import React, { FC } from "react"
|
||||
import { useRecoilState } from "recoil"
|
||||
import { styled, useTheme, Theme, CSSObject } from "@mui/material/styles"
|
||||
import Box from "@mui/material/Box"
|
||||
import MuiDrawer from "@mui/material/Drawer"
|
||||
import MuiAppBar, { AppBarProps as MuiAppBarProps } from "@mui/material/AppBar"
|
||||
import Toolbar from "@mui/material/Toolbar"
|
||||
import List from "@mui/material/List"
|
||||
import Typography from "@mui/material/Typography"
|
||||
import Divider from "@mui/material/Divider"
|
||||
import IconButton from "@mui/material/IconButton"
|
||||
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight"
|
||||
import ListItem from "@mui/material/ListItem"
|
||||
import ListItemButton from "@mui/material/ListItemButton"
|
||||
import ListItemIcon from "@mui/material/ListItemIcon"
|
||||
import ListItemText from "@mui/material/ListItemText"
|
||||
import { reloadIntervalState } from "../state"
|
||||
import { Link } from "react-router-dom"
|
||||
import AutoGraphIcon from "@mui/icons-material/AutoGraph"
|
||||
import SyncIcon from "@mui/icons-material/Sync"
|
||||
import SyncDisabledIcon from "@mui/icons-material/SyncDisabled"
|
||||
import HomeIcon from "@mui/icons-material/Home"
|
||||
import Brightness4Icon from "@mui/icons-material/Brightness4"
|
||||
import Brightness7Icon from "@mui/icons-material/Brightness7"
|
||||
import TableViewIcon from "@mui/icons-material/TableView"
|
||||
import RateReviewIcon from "@mui/icons-material/RateReview"
|
||||
import ClearIcon from "@mui/icons-material/Clear"
|
||||
import MenuIcon from "@mui/icons-material/Menu"
|
||||
import { Switch } from "@mui/material"
|
||||
|
||||
const drawerWidth = 240
|
||||
|
||||
const openedMixin = (theme: Theme): CSSObject => ({
|
||||
width: drawerWidth,
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
})
|
||||
|
||||
const closedMixin = (theme: Theme): CSSObject => ({
|
||||
transition: theme.transitions.create("width", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
overflowX: "hidden",
|
||||
width: `calc(${theme.spacing(7)} + 1px)`,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: `calc(${theme.spacing(8)} + 1px)`,
|
||||
},
|
||||
})
|
||||
|
||||
const DrawerHeader = styled("div")(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
padding: theme.spacing(0, 1),
|
||||
// necessary for content to be below app bar
|
||||
...theme.mixins.toolbar,
|
||||
}))
|
||||
|
||||
interface AppBarProps extends MuiAppBarProps {
|
||||
open?: boolean
|
||||
}
|
||||
|
||||
const AppBar = styled(MuiAppBar, {
|
||||
shouldForwardProp: (prop) => prop !== "open",
|
||||
})<AppBarProps>(({ theme, open }) => ({
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
transition: theme.transitions.create(["width", "margin"], {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen,
|
||||
}),
|
||||
...(open && {
|
||||
marginLeft: drawerWidth,
|
||||
width: `calc(100% - ${drawerWidth}px)`,
|
||||
transition: theme.transitions.create(["width", "margin"], {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.enteringScreen,
|
||||
}),
|
||||
}),
|
||||
}))
|
||||
|
||||
const Drawer = styled(MuiDrawer, {
|
||||
shouldForwardProp: (prop) => prop !== "open",
|
||||
})(({ theme, open }) => ({
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
whiteSpace: "nowrap",
|
||||
boxSizing: "border-box",
|
||||
...(open && {
|
||||
...openedMixin(theme),
|
||||
"& .MuiDrawer-paper": openedMixin(theme),
|
||||
}),
|
||||
...(!open && {
|
||||
...closedMixin(theme),
|
||||
"& .MuiDrawer-paper": closedMixin(theme),
|
||||
}),
|
||||
}))
|
||||
|
||||
export const StudyDetailDrawer: FC<{
|
||||
studyId: number
|
||||
toggleColorMode: () => void
|
||||
page: "top" | "trials" | "note"
|
||||
children?: React.ReactNode
|
||||
}> = ({ studyId, toggleColorMode, page, children }) => {
|
||||
const theme = useTheme()
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const [reloadInterval, updateReloadInterval] =
|
||||
useRecoilState<number>(reloadIntervalState)
|
||||
|
||||
const styleListItem = {
|
||||
display: "block",
|
||||
}
|
||||
const styleListItemButton = {
|
||||
minHeight: 48,
|
||||
justifyContent: open ? "initial" : "center",
|
||||
px: 2.5,
|
||||
}
|
||||
const styleListItemIcon = {
|
||||
minWidth: 0,
|
||||
mr: open ? 3 : "auto",
|
||||
justifyContent: "center",
|
||||
}
|
||||
const styleListItemText = {
|
||||
opacity: open ? 1 : 0,
|
||||
}
|
||||
const styleSwitch = {
|
||||
display: open ? "inherit" : "none",
|
||||
}
|
||||
|
||||
const handleDrawerOpen = () => {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
const handleDrawerClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", width: "100%" }}>
|
||||
<AppBar position="fixed" open={open}>
|
||||
<Toolbar>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="open drawer"
|
||||
onClick={handleDrawerOpen}
|
||||
edge="start"
|
||||
sx={{
|
||||
marginRight: 5,
|
||||
...(open && { display: "none" }),
|
||||
}}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6" noWrap component="div">
|
||||
Mini variant drawer
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<Drawer variant="permanent" open={open}>
|
||||
<DrawerHeader>
|
||||
<IconButton onClick={handleDrawerClose}>
|
||||
{theme.direction === "rtl" ? (
|
||||
<ChevronRightIcon />
|
||||
) : (
|
||||
<ChevronLeftIcon />
|
||||
)}
|
||||
</IconButton>
|
||||
</DrawerHeader>
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem key="Top" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}/beta`}
|
||||
sx={styleListItemButton}
|
||||
selected={page === "top"}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<AutoGraphIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="History" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem key="Table" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}/trials`}
|
||||
sx={styleListItemButton}
|
||||
selected={page === "trials"}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<TableViewIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Trials" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem key="Note" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}/note`}
|
||||
sx={styleListItemButton}
|
||||
selected={page === "note"}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<RateReviewIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Note" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
<Box sx={{ flexGrow: 1 }} />
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem key="Home" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={URL_PREFIX + "/"}
|
||||
sx={styleListItemButton}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<HomeIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Return to Home" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem key="LiveUpdate" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
sx={styleListItemButton}
|
||||
onClick={() => {
|
||||
updateReloadInterval(reloadInterval === -1 ? 10 : -1)
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
{reloadInterval === -1 ? <SyncDisabledIcon /> : <SyncIcon />}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Live Update" sx={styleListItemText} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={reloadInterval !== -1}
|
||||
sx={styleSwitch}
|
||||
inputProps={{
|
||||
"aria-labelledby": "switch-list-label-live-update",
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem key="DarkMode" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
sx={styleListItemButton}
|
||||
onClick={() => {
|
||||
toggleColorMode()
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
{theme.palette.mode === "dark" ? (
|
||||
<Brightness4Icon />
|
||||
) : (
|
||||
<Brightness7Icon />
|
||||
)}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Dark Mode" sx={styleListItemText} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={theme.palette.mode === "dark"}
|
||||
sx={styleSwitch}
|
||||
inputProps={{
|
||||
"aria-labelledby": "switch-list-label-dark-mode",
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
<ListItem key="BetaUI" disablePadding sx={styleListItem}>
|
||||
<ListItemButton
|
||||
component={Link}
|
||||
to={`${URL_PREFIX}/studies/${studyId}`}
|
||||
sx={styleListItemButton}
|
||||
>
|
||||
<ListItemIcon sx={styleListItemIcon}>
|
||||
<ClearIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Quit Beta UI" sx={styleListItemText} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Drawer>
|
||||
<Box component="main" sx={{ flexGrow: 1 }}>
|
||||
<DrawerHeader />
|
||||
{children || null}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user