Virtualize trials list.

This commit is contained in:
y0z
2024-02-21 17:38:05 +09:00
parent 2197e7966a
commit 8106f1edd2
3 changed files with 127 additions and 50 deletions
+87 -50
View File
@@ -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 />
+39
View File
@@ -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",
+1
View File
@@ -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",