mirror of
https://github.com/wassname/optuna-dashboard.git
synced 2026-09-11 12:30:25 +08:00
Virtualize trials list.
This commit is contained in:
@@ -29,6 +29,8 @@ import { actionCreator } from "../action"
|
||||
import { TrialFormWidgets } from "./TrialFormWidgets"
|
||||
import { TrialArtifactCards } from "./TrialArtifactCards"
|
||||
|
||||
import { useVirtualizer } from "@tanstack/react-virtual"
|
||||
|
||||
const states: TrialState[] = [
|
||||
"Complete",
|
||||
"Pruned",
|
||||
@@ -344,6 +346,14 @@ export const TrialList: FC<{ studyDetail: StudyDetail | null }> = ({
|
||||
(state) => allTrials.filter((t) => t.state === state).length
|
||||
)
|
||||
}, [studyDetail?.trials])
|
||||
const listParentRef = React.useRef(null)
|
||||
|
||||
const rowVirtualizer = useVirtualizer({
|
||||
count: trials.length,
|
||||
getScrollElement: () => listParentRef.current,
|
||||
estimateSize: () => 75,
|
||||
overscan: 10,
|
||||
})
|
||||
|
||||
const trialListWidth = 200
|
||||
|
||||
@@ -353,13 +363,14 @@ export const TrialList: FC<{ studyDetail: StudyDetail | null }> = ({
|
||||
return (
|
||||
<Box sx={{ display: "flex", flexDirection: "row", width: "100%" }}>
|
||||
<Box
|
||||
ref={listParentRef}
|
||||
sx={{
|
||||
minWidth: trialListWidth,
|
||||
overflow: "auto",
|
||||
height: `calc(100vh - ${theme.spacing(8)})`,
|
||||
}}
|
||||
>
|
||||
<List>
|
||||
<List sx={{ position: "relateve" }}>
|
||||
<ListSubheader sx={{ display: "flex", flexDirection: "row" }}>
|
||||
<Typography sx={{ p: theme.spacing(1, 0) }}>
|
||||
{trials.length} Trials
|
||||
@@ -417,65 +428,91 @@ export const TrialList: FC<{ studyDetail: StudyDetail | null }> = ({
|
||||
</Menu>
|
||||
</ListSubheader>
|
||||
<Divider />
|
||||
{trials.map((trial) => {
|
||||
return (
|
||||
<ListItem key={trial.trial_id} disablePadding>
|
||||
<ListItemButton
|
||||
onClick={(e) => {
|
||||
if (e.shiftKey) {
|
||||
let next: number[]
|
||||
const selectedNumbers = selected.map((t) => t.number)
|
||||
const alreadySelected =
|
||||
selectedNumbers.findIndex((n) => n === trial.number) >=
|
||||
0
|
||||
if (alreadySelected) {
|
||||
next = selectedNumbers.filter((n) => n !== trial.number)
|
||||
} else {
|
||||
next = [...selectedNumbers, trial.number]
|
||||
}
|
||||
navigate(
|
||||
getTrialListLink(trial.study_id, excludedStates, next)
|
||||
)
|
||||
} else {
|
||||
navigate(
|
||||
getTrialListLink(trial.study_id, excludedStates, [
|
||||
trial.number,
|
||||
])
|
||||
)
|
||||
}
|
||||
}}
|
||||
selected={
|
||||
selected.findIndex((t) => t.number === trial.number) !== -1
|
||||
}
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: `${rowVirtualizer.getTotalSize()}px`,
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
{rowVirtualizer.getVirtualItems().map((virtualItem) => {
|
||||
console.log(virtualItem.index, virtualItem.start, virtualItem.end)
|
||||
const trial = trials[virtualItem.index]
|
||||
return (
|
||||
<ListItem
|
||||
key={trial.trial_id}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
transform: `translateY(${virtualItem.start}px)`,
|
||||
}}
|
||||
disablePadding
|
||||
>
|
||||
<ListItemText primary={`Trial ${trial.number}`} />
|
||||
<Box>
|
||||
<Chip
|
||||
color={getChipColor(trial.state)}
|
||||
label={trial.state}
|
||||
sx={{ margin: theme.spacing(0) }}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
{isBestTrial(trial.trial_id) ? (
|
||||
<ListItemButton
|
||||
onClick={(e) => {
|
||||
if (e.shiftKey) {
|
||||
let next: number[]
|
||||
const selectedNumbers = selected.map((t) => t.number)
|
||||
const alreadySelected =
|
||||
selectedNumbers.findIndex(
|
||||
(n) => n === trial.number
|
||||
) >= 0
|
||||
if (alreadySelected) {
|
||||
next = selectedNumbers.filter(
|
||||
(n) => n !== trial.number
|
||||
)
|
||||
} else {
|
||||
next = [...selectedNumbers, trial.number]
|
||||
}
|
||||
navigate(
|
||||
getTrialListLink(trial.study_id, excludedStates, next)
|
||||
)
|
||||
} else {
|
||||
navigate(
|
||||
getTrialListLink(trial.study_id, excludedStates, [
|
||||
trial.number,
|
||||
])
|
||||
)
|
||||
}
|
||||
}}
|
||||
selected={
|
||||
selected.findIndex((t) => t.number === trial.number) !==
|
||||
-1
|
||||
}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<ListItemText primary={`Trial ${trial.number}`} />
|
||||
<Box>
|
||||
<Chip
|
||||
label={"Best Trial"}
|
||||
color="secondary"
|
||||
sx={{ marginLeft: theme.spacing(1) }}
|
||||
color={getChipColor(trial.state)}
|
||||
label={trial.state}
|
||||
sx={{ margin: theme.spacing(0) }}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
) : null}
|
||||
</Box>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)
|
||||
})}
|
||||
{isBestTrial(trial.trial_id) ? (
|
||||
<Chip
|
||||
label={"Best Trial"}
|
||||
color="secondary"
|
||||
sx={{ marginLeft: theme.spacing(1) }}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
) : null}
|
||||
</Box>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
</List>
|
||||
</Box>
|
||||
<Divider orientation="vertical" flexItem />
|
||||
|
||||
Generated
+39
@@ -16,6 +16,7 @@
|
||||
"@mui/material": "^5.12.1",
|
||||
"@react-three/drei": "^9.80.0",
|
||||
"@react-three/fiber": "^8.13.6",
|
||||
"@tanstack/react-virtual": "^3.1.2",
|
||||
"@types/three": "^0.154.0",
|
||||
"axios": "^1.6.0",
|
||||
"elkjs": "^0.8.2",
|
||||
@@ -3810,6 +3811,31 @@
|
||||
"@sinonjs/commons": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-virtual": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.1.2.tgz",
|
||||
"integrity": "sha512-qibmxtctgOZo2I+3Rw5GR9kXgaa15U5r3/idDY1ItUKW15UK7GhCfyIfE6qYuJ1fxQF6dJDsD8SbpPyuJgpxuA==",
|
||||
"dependencies": {
|
||||
"@tanstack/virtual-core": "3.1.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/virtual-core": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.1.2.tgz",
|
||||
"integrity": "sha512-DATZJs8iejkIUqXZe6ruDAnjFo78BKnIIgqQZrc7CmEFqfLEN/TPD91n4hRfo6hpRB6xC00bwKxv7vdjFNEmOg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz",
|
||||
@@ -17926,6 +17952,19 @@
|
||||
"@sinonjs/commons": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"@tanstack/react-virtual": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.1.2.tgz",
|
||||
"integrity": "sha512-qibmxtctgOZo2I+3Rw5GR9kXgaa15U5r3/idDY1ItUKW15UK7GhCfyIfE6qYuJ1fxQF6dJDsD8SbpPyuJgpxuA==",
|
||||
"requires": {
|
||||
"@tanstack/virtual-core": "3.1.2"
|
||||
}
|
||||
},
|
||||
"@tanstack/virtual-core": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.1.2.tgz",
|
||||
"integrity": "sha512-DATZJs8iejkIUqXZe6ruDAnjFo78BKnIIgqQZrc7CmEFqfLEN/TPD91n4hRfo6hpRB6xC00bwKxv7vdjFNEmOg=="
|
||||
},
|
||||
"@testing-library/dom": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@mui/material": "^5.12.1",
|
||||
"@react-three/drei": "^9.80.0",
|
||||
"@react-three/fiber": "^8.13.6",
|
||||
"@tanstack/react-virtual": "^3.1.2",
|
||||
"@types/three": "^0.154.0",
|
||||
"axios": "^1.6.0",
|
||||
"elkjs": "^0.8.2",
|
||||
|
||||
Reference in New Issue
Block a user