diff --git a/optuna_dashboard/ts/components/TrialList.tsx b/optuna_dashboard/ts/components/TrialList.tsx
index cfde6536..444fe5af 100644
--- a/optuna_dashboard/ts/components/TrialList.tsx
+++ b/optuna_dashboard/ts/components/TrialList.tsx
@@ -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 (
-
+
{trials.length} Trials
@@ -417,65 +428,91 @@ export const TrialList: FC<{ studyDetail: StudyDetail | null }> = ({
- {trials.map((trial) => {
- return (
-
- {
- 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
- }
+
+ {rowVirtualizer.getVirtualItems().map((virtualItem) => {
+ console.log(virtualItem.index, virtualItem.start, virtualItem.end)
+ const trial = trials[virtualItem.index]
+ return (
+
-
-
-
- {isBestTrial(trial.trial_id) ? (
+ {
+ 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",
+ }}
+ >
+
+
- ) : null}
-
-
-
- )
- })}
+ {isBestTrial(trial.trial_id) ? (
+
+ ) : null}
+
+
+
+ )
+ })}
+
diff --git a/package-lock.json b/package-lock.json
index 1d9a286e..11df1cdf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 9e6e59e9..5ab63bdc 100644
--- a/package.json
+++ b/package.json
@@ -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",