diff --git a/.github/workflows/typescript-tests.yml b/.github/workflows/typescript-tests.yml
index 01c99470..26c98501 100644
--- a/.github/workflows/typescript-tests.yml
+++ b/.github/workflows/typescript-tests.yml
@@ -9,7 +9,14 @@ on:
- '**.tsx'
- 'optuna_dashboard/package.json'
- 'optuna_dashboard/package-lock.json'
+ - 'vscode/package.json'
+ - 'vscode/package-lock.json'
+ - 'tslib/react/package.json'
+ - 'tslib/react/package-lock.json'
+ - 'tslib/storage/package.json'
+ - 'tslib/storage/package-lock.json'
- 'optuna_dashboard/tsconfig.json'
+ - 'optuna_dashboard/tsconfig.pkg.json'
- 'optuna_dashboard/webpack.config.js'
jobs:
lint:
@@ -112,6 +119,11 @@ jobs:
npm run build:dev
npm run build:prd
+ - name: Build optuna_dashboard package (for Jupyter Lab extension)
+ working-directory: optuna_dashboard
+ run: |
+ npm run build:pkg
+
test-tslib:
name: Run tests
runs-on: ubuntu-latest
diff --git a/optuna_dashboard/.gitignore b/optuna_dashboard/.gitignore
new file mode 100644
index 00000000..c8beb626
--- /dev/null
+++ b/optuna_dashboard/.gitignore
@@ -0,0 +1,2 @@
+pkg
+types
diff --git a/optuna_dashboard/package-lock.json b/optuna_dashboard/package-lock.json
index d039bfe3..0513b6c2 100644
--- a/optuna_dashboard/package-lock.json
+++ b/optuna_dashboard/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "optuna-dashboard",
+ "name": "@optuna/optuna-dashboard",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "optuna-dashboard",
+ "name": "@optuna/optuna-dashboard",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
@@ -19,7 +19,7 @@
"@react-three/drei": "^9.96.4",
"@react-three/fiber": "^8.15.15",
"@tanstack/react-query": "^5.18.1",
- "@tanstack/react-table": "^8.16.0",
+ "@tanstack/react-table": "file:../tslib/react/node_modules/@tanstack/react-table",
"@tanstack/react-virtual": "^3.1.2",
"@types/papaparse": "^5.3.14",
"@types/three": "^0.160.0",
@@ -14278,22 +14278,8 @@
}
},
"node_modules/@tanstack/react-table": {
- "version": "8.17.3",
- "license": "MIT",
- "dependencies": {
- "@tanstack/table-core": "8.17.3"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": ">=16.8",
- "react-dom": ">=16.8"
- }
+ "resolved": "../tslib/react/node_modules/@tanstack/react-table",
+ "link": true
},
"node_modules/@tanstack/react-virtual": {
"version": "3.5.1",
@@ -14310,17 +14296,6 @@
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
- "node_modules/@tanstack/table-core": {
- "version": "8.17.3",
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- }
- },
"node_modules/@tanstack/virtual-core": {
"version": "3.5.1",
"license": "MIT",
diff --git a/optuna_dashboard/package.json b/optuna_dashboard/package.json
index 12dadc4e..6953ee7b 100644
--- a/optuna_dashboard/package.json
+++ b/optuna_dashboard/package.json
@@ -1,14 +1,16 @@
{
- "name": "optuna-dashboard",
+ "name": "@optuna/optuna-dashboard",
"private": true,
"version": "0.0.1",
"description": "Dashboard for Optuna",
- "main": "index.js",
+ "main": "pkg/pkg_index.js",
+ "types": "types/pkg_index.d.ts",
"scripts": {
"watch": "NODE_ENV=development TYPESCRIPT_LOADER=esbuild-loader webpack --watch",
"build": "webpack",
"build:dev": "NODE_ENV=development TYPESCRIPT_LOADER=esbuild-loader webpack",
"build:prd": "NODE_ENV=production webpack",
+ "build:pkg": "tsc -d --project tsconfig.pkg.json",
"type-check": "tsc --noEmit"
},
"author": "Masashi Shibata",
@@ -24,7 +26,7 @@
"@react-three/drei": "^9.96.4",
"@react-three/fiber": "^8.15.15",
"@tanstack/react-query": "^5.18.1",
- "@tanstack/react-table": "^8.16.0",
+ "@tanstack/react-table": "file:../tslib/react/node_modules/@tanstack/react-table",
"@tanstack/react-virtual": "^3.1.2",
"@types/papaparse": "^5.3.14",
"@types/three": "^0.160.0",
diff --git a/optuna_dashboard/ts/components/App.tsx b/optuna_dashboard/ts/components/App.tsx
index 1204ae8f..c915f7c7 100644
--- a/optuna_dashboard/ts/components/App.tsx
+++ b/optuna_dashboard/ts/components/App.tsx
@@ -13,14 +13,10 @@ import { BrowserRouter as Router, Route, Routes } from "react-router-dom"
import { RecoilRoot } from "recoil"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
-import { APIClientProvider } from "../apiClientProvider"
-import { AxiosClient } from "../axiosClient"
import { CompareStudies } from "./CompareStudies"
import { StudyDetail } from "./StudyDetail"
import { StudyList } from "./StudyList"
-const axiosAPIClient = new AxiosClient()
-
const queryClient = new QueryClient({
defaultOptions: {
queries: {
@@ -54,102 +50,100 @@ export const App: FC = () => {
}
return (
-
-
-
-
-
-
-
-
-
-
- }
- />
-
- }
- />
-
- }
- />
-
- }
- />
-
- }
- />
-
- }
- />
-
- }
- />
-
- }
- />
- }
- />
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+ }
+ />
+
+
+
+
+
+
+
)
}
diff --git a/optuna_dashboard/ts/components/Artifact/TableArtifactViewer.tsx b/optuna_dashboard/ts/components/Artifact/TableArtifactViewer.tsx
index bb346fe4..6fc01f02 100644
--- a/optuna_dashboard/ts/components/Artifact/TableArtifactViewer.tsx
+++ b/optuna_dashboard/ts/components/Artifact/TableArtifactViewer.tsx
@@ -1,10 +1,10 @@
import ClearIcon from "@mui/icons-material/Clear"
import { Box, Modal, useTheme } from "@mui/material"
import IconButton from "@mui/material/IconButton"
+import { DataGrid } from "@optuna/react"
import { useSnackbar } from "notistack"
import Papa from "papaparse"
import React, { useState, useEffect, ReactNode } from "react"
-import { DataGrid } from "../DataGrid"
import { Artifact } from "ts/types/optuna"
diff --git a/optuna_dashboard/ts/components/CompareStudies.tsx b/optuna_dashboard/ts/components/CompareStudies.tsx
index 8d376240..49f62b97 100644
--- a/optuna_dashboard/ts/components/CompareStudies.tsx
+++ b/optuna_dashboard/ts/components/CompareStudies.tsx
@@ -13,12 +13,12 @@ import {
import Chip from "@mui/material/Chip"
import Divider from "@mui/material/Divider"
import FormControlLabel from "@mui/material/FormControlLabel"
+import Grid from "@mui/material/Grid"
import List from "@mui/material/List"
import ListItem from "@mui/material/ListItem"
import ListItemButton from "@mui/material/ListItemButton"
import ListItemText from "@mui/material/ListItemText"
import ListSubheader from "@mui/material/ListSubheader"
-import Grid2 from "@mui/material/Unstable_Grid2"
import * as Optuna from "@optuna/types"
import { useSnackbar } from "notistack"
import React, { FC, useEffect, useMemo, useState } from "react"
@@ -336,21 +336,21 @@ const StudiesGraph: FC<{ studies: StudySummary[] }> = ({ studies }) => {
) : null}
-
+
{showStudyDetails !== null &&
showStudyDetails.length > 0 &&
showStudyDetails.every((s) => s)
? showStudyDetails[0].directions.map((d, i) => (
-
+
-
+
))
: null}
-
+
)
}
diff --git a/optuna_dashboard/ts/components/DataGrid.tsx b/optuna_dashboard/ts/components/DataGrid.tsx
deleted file mode 100644
index 607f580c..00000000
--- a/optuna_dashboard/ts/components/DataGrid.tsx
+++ /dev/null
@@ -1,383 +0,0 @@
-import CheckBoxIcon from "@mui/icons-material/CheckBox"
-import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank"
-import FilterListIcon from "@mui/icons-material/FilterList"
-import FirstPageIcon from "@mui/icons-material/FirstPage"
-import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft"
-import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight"
-import LastPageIcon from "@mui/icons-material/LastPage"
-import {
- Box,
- IconButton,
- Menu,
- MenuItem,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TablePagination,
- TableRow,
- TableSortLabel,
- TextField,
- useTheme,
-} from "@mui/material"
-import ListItemIcon from "@mui/material/ListItemIcon"
-import Paper from "@mui/material/Paper"
-import { TablePaginationActionsProps } from "@mui/material/TablePagination/TablePaginationActions"
-import { styled } from "@mui/system"
-import React from "react"
-
-import {
- ColumnDef,
- ColumnFiltersState,
- Header,
- PaginationState,
- SortingState,
- flexRender,
- getCoreRowModel,
- getFacetedRowModel,
- getFacetedUniqueValues,
- getFilteredRowModel,
- getPaginationRowModel,
- getSortedRowModel,
- useReactTable,
-} from "@tanstack/react-table"
-
-const TableHeaderCellSpan = styled("span")({
- display: "inline-flex",
-})
-
-const HiddenSpan = styled("span")({
- border: 0,
- clip: "rect(0 0 0 0)",
- height: 1,
- margin: -1,
- overflow: "hidden",
- padding: 0,
- position: "absolute",
- top: 20,
- width: 1,
-})
-
-function FilterMenu({
- header,
- filterChoices,
-}: {
- header: Header
- filterChoices: string[]
-}): React.ReactElement {
- const [filterMenuAnchorEl, setFilterMenuAnchorEl] =
- React.useState(null)
- return (
- <>
- {
- setFilterMenuAnchorEl(e.currentTarget)
- }}
- >
-
-
-
- >
- )
-}
-
-function DataGrid({
- data,
- columns,
- initialRowsPerPage,
-}: {
- data: T[]
- columns: ColumnDef[]
- initialRowsPerPage?: number
-}): React.ReactElement {
- const [sorting, setSorting] = React.useState([])
- const [columnFilters, setColumnFilters] = React.useState(
- []
- )
- const rowsPerPageOptions = [10, 50, 100, { label: "All", value: data.length }]
-
- const [pagination, setPagination] = React.useState({
- pageIndex: 0,
- pageSize:
- initialRowsPerPage && rowsPerPageOptions.includes(initialRowsPerPage)
- ? initialRowsPerPage
- : 50,
- })
-
- const table = useReactTable({
- data,
- columns,
- state: {
- columnFilters,
- sorting,
- pagination,
- },
- onColumnFiltersChange: setColumnFilters,
- onSortingChange: setSorting,
- onPaginationChange: setPagination,
- getCoreRowModel: getCoreRowModel(),
- getFacetedRowModel: getFacetedRowModel(),
- getFacetedUniqueValues: getFacetedUniqueValues(),
- getSortedRowModel: getSortedRowModel(),
- getPaginationRowModel: getPaginationRowModel(),
- getFilteredRowModel: getFilteredRowModel(),
- autoResetPageIndex: false,
- })
-
- return (
-
-
-
-
- {table.getHeaderGroups().map((headerGroup) => (
-
- {headerGroup.headers.map((header) => {
- if (
- header.column.getCanFilter() &&
- !header.column.getIsFiltered()
- ) {
- header.column.setFilterValue([])
- }
- const order = header.column.getIsSorted()
- const filterChoices = header.column.getCanFilter()
- ? Array.from(
- header.column.getFacetedUniqueValues().keys()
- ).sort()
- : null
- return (
-
- {header.isPlaceholder ? null : (
-
- {header.column.getCanSort() ? (
-
- {flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
- {order !== null ? (
-
- {order === "desc"
- ? "sorted descending"
- : "sorted ascending"}
-
- ) : null}
-
- ) : (
- flexRender(
- header.column.columnDef.header,
- header.getContext()
- )
- )}
- {filterChoices !== null ? (
-
- ) : null}
-
- )}
-
- )
- })}
-
- ))}
-
-
- {table.getRowModel().rows.map((row) => {
- return (
-
- {row.getVisibleCells().map((cell) => {
- return (
-
- {flexRender(
- cell.column.columnDef.cell,
- cell.getContext()
- )}
-
- )
- })}
-
- )
- })}
-
-
-
-
- {
- table.setPageIndex(page)
- }}
- onRowsPerPageChange={(e) => {
- const size = e.target.value ? Number(e.target.value) : 10
- table.setPageSize(size)
- }}
- ActionsComponent={TablePaginationActions}
- />
- {table.getPageCount() > 2 ? (
- table.setPageIndex(page)}
- maxPageNumber={table.getPageCount()}
- />
- ) : null}
-
-
- )
-}
-
-const TablePaginationActions = ({
- count,
- page,
- rowsPerPage,
- onPageChange,
-}: TablePaginationActionsProps) => {
- const theme = useTheme()
- const handleFirstPageButtonClick = (
- event: React.MouseEvent
- ) => {
- onPageChange(event, 0)
- }
-
- const handleBackButtonClick = (
- event: React.MouseEvent
- ) => {
- onPageChange(event, page - 1)
- }
-
- const handleNextButtonClick = (
- event: React.MouseEvent
- ) => {
- onPageChange(event, page + 1)
- }
-
- const handleLastPageButtonClick = (
- event: React.MouseEvent
- ) => {
- onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1))
- }
-
- return (
-
-
- {theme.direction === "rtl" ? : }
-
-
- {theme.direction === "rtl" ? (
-
- ) : (
-
- )}
-
- = Math.ceil(count / rowsPerPage) - 1}
- aria-label="next page"
- >
- {theme.direction === "rtl" ? (
-
- ) : (
-
- )}
-
- = Math.ceil(count / rowsPerPage) - 1}
- aria-label="last page"
- >
- {theme.direction === "rtl" ? : }
-
-
- )
-}
-
-const PaginationForm1: React.FC<{
- onPageNumberSubmit: (value: number) => void
- maxPageNumber: number
-}> = ({ onPageNumberSubmit, maxPageNumber }) => {
- // This component is separated from DataGrid to prevent `DataGrid` from re-rendering the page,
- // every time any letters are input.
- const [specifiedPageText, setSpecifiedPageText] = React.useState("")
-
- const handleSubmitPageNumber = (event: React.FormEvent) => {
- event.preventDefault()
- const newPageNumber = parseInt(specifiedPageText, 10)
- // Page is 0-indexed in `TablePagination`.
- onPageNumberSubmit(newPageNumber - 1)
- setSpecifiedPageText("") // reset the input field
- }
-
- return (
-
- )
-}
-
-export { DataGrid }
diff --git a/optuna_dashboard/ts/components/Preferential/PreferentialAnalytics.tsx b/optuna_dashboard/ts/components/Preferential/PreferentialAnalytics.tsx
index 554e6ea4..e0f1560e 100644
--- a/optuna_dashboard/ts/components/Preferential/PreferentialAnalytics.tsx
+++ b/optuna_dashboard/ts/components/Preferential/PreferentialAnalytics.tsx
@@ -6,12 +6,12 @@ import {
Typography,
useTheme,
} from "@mui/material"
-import Grid2 from "@mui/material/Unstable_Grid2"
+import Grid from "@mui/material/Grid"
+import { DataGrid } from "@optuna/react"
import * as Optuna from "@optuna/types"
import React, { FC } from "react"
import { useStudyDetailValue, useStudySummaryValue } from "../../state"
import { BestTrialsCard } from "../BestTrialsCard"
-import { DataGrid } from "../DataGrid"
import { Contour } from "../GraphContour"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
@@ -41,16 +41,16 @@ export const PreferentialAnalytics: FC<{ studyId: number }> = ({ studyId }) => {
component="div"
sx={{ display: "flex", width: "100%", flexDirection: "column" }}
>
-
-
+
+
-
-
+
+
-
-
+
+
= ({ studyId }) => {
-
-
+
+
)
}
diff --git a/optuna_dashboard/ts/components/StudyDetail.tsx b/optuna_dashboard/ts/components/StudyDetail.tsx
index 55a1332a..f49f2839 100644
--- a/optuna_dashboard/ts/components/StudyDetail.tsx
+++ b/optuna_dashboard/ts/components/StudyDetail.tsx
@@ -8,7 +8,7 @@ import {
Typography,
useTheme,
} from "@mui/material"
-import Grid2 from "@mui/material/Unstable_Grid2"
+import Grid from "@mui/material/Grid"
import React, { FC, useEffect, useMemo } from "react"
import { Link, useParams } from "react-router-dom"
import { useRecoilValue } from "recoil"
@@ -146,19 +146,19 @@ export const StudyDetail: FC<{
>
Empirical Distribution of the Objective Value
-
+
{studyDetail !== null
? studyDetail.directions.map((d, i) => (
-
+
-
+
))
: null}
-
+
)
} else if (page === "trialList") {
diff --git a/optuna_dashboard/ts/components/StudyHistory.tsx b/optuna_dashboard/ts/components/StudyHistory.tsx
index 6577f050..bcf161a4 100644
--- a/optuna_dashboard/ts/components/StudyHistory.tsx
+++ b/optuna_dashboard/ts/components/StudyHistory.tsx
@@ -8,7 +8,8 @@ import {
useTheme,
} from "@mui/material"
import FormControlLabel from "@mui/material/FormControlLabel"
-import Grid2 from "@mui/material/Unstable_Grid2"
+import Grid from "@mui/material/Grid"
+import { DataGrid } from "@optuna/react"
import * as Optuna from "@optuna/types"
import React, { FC, useState } from "react"
import { useRecoilValue } from "recoil"
@@ -21,7 +22,6 @@ import {
import { artifactIsAvailable } from "../state"
import { StudyArtifactCards } from "./Artifact/StudyArtifactCards"
import { BestTrialsCard } from "./BestTrialsCard"
-import { DataGrid } from "./DataGrid"
import { GraphHistory } from "./GraphHistory"
import { GraphHyperparameterImportance } from "./GraphHyperparameterImportances"
import { GraphIntermediateValues } from "./GraphIntermediateValues"
@@ -124,31 +124,31 @@ export const StudyHistory: FC<{ studyId: number }> = ({ studyId }) => {
/>
-
-
+
+
-
-
+
+
-
+
{studyDetail !== null &&
studyDetail.plotly_graph_objects.map((go) => (
-
+
-
+
))}
-
+
-
-
+
+
= ({ studyId }) => {
-
+
{studyDetail !== null &&
studyDetail.directions.length === 1 &&
studyDetail.has_intermediate_values ? (
-
+
-
+
) : null}
-
+
{artifactEnabled && studyDetail !== null && (
-
-
+
+
= ({ studyId }) => {
-
-
+
+
)}
)
diff --git a/optuna_dashboard/ts/components/TrialTable.tsx b/optuna_dashboard/ts/components/TrialTable.tsx
index 55fdc2e0..df62cf97 100644
--- a/optuna_dashboard/ts/components/TrialTable.tsx
+++ b/optuna_dashboard/ts/components/TrialTable.tsx
@@ -3,9 +3,10 @@ import LinkIcon from "@mui/icons-material/Link"
import { Button, IconButton, useTheme } from "@mui/material"
import React, { FC } from "react"
+import { DataGrid } from "@optuna/react"
+
import { Link } from "react-router-dom"
import { StudyDetail, Trial } from "ts/types/optuna"
-import { DataGrid } from "./DataGrid"
import {
ColumnDef,
diff --git a/optuna_dashboard/ts/index.tsx b/optuna_dashboard/ts/index.tsx
index fd63f378..9fe11370 100644
--- a/optuna_dashboard/ts/index.tsx
+++ b/optuna_dashboard/ts/index.tsx
@@ -1,9 +1,15 @@
import React from "react"
import ReactDOM from "react-dom/client"
+import { APIClientProvider } from "./apiClientProvider"
+import { AxiosClient } from "./axiosClient"
import { App } from "./components/App"
+const axiosAPIClient = new AxiosClient()
+
ReactDOM.createRoot(document.getElementById("dashboard") as HTMLElement).render(
-
+
+
+
)
diff --git a/optuna_dashboard/ts/pkg_index.tsx b/optuna_dashboard/ts/pkg_index.tsx
new file mode 100644
index 00000000..c8e04aa6
--- /dev/null
+++ b/optuna_dashboard/ts/pkg_index.tsx
@@ -0,0 +1,5 @@
+import { APIClientProvider } from "./apiClientProvider"
+import { AxiosClient } from "./axiosClient"
+import { App } from "./components/App"
+
+export { AxiosClient, APIClientProvider, App }
diff --git a/optuna_dashboard/tsconfig.pkg.json b/optuna_dashboard/tsconfig.pkg.json
new file mode 100644
index 00000000..0e65b770
--- /dev/null
+++ b/optuna_dashboard/tsconfig.pkg.json
@@ -0,0 +1,15 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "./ts",
+ "outDir": "./pkg",
+ "declaration": true,
+ "declarationDir": "./types",
+ },
+ "files": [
+ "./ts/pkg_index.tsx",
+ ],
+ "include": [
+ "./ts/types/**/*",
+ ],
+}
\ No newline at end of file
diff --git a/standalone_app/src/components/StudyDetail.tsx b/standalone_app/src/components/StudyDetail.tsx
index 7d137f5b..ff9b176c 100644
--- a/standalone_app/src/components/StudyDetail.tsx
+++ b/standalone_app/src/components/StudyDetail.tsx
@@ -12,7 +12,7 @@ import {
Typography,
useTheme,
} from "@mui/material"
-import Grid2 from "@mui/material/Unstable_Grid2"
+import Grid from "@mui/material/Grid"
import {
PlotHistory,
PlotImportance,
@@ -176,8 +176,8 @@ export const StudyDetail: FC<{
-
-
+
+
{!!study && (
@@ -185,8 +185,8 @@ export const StudyDetail: FC<{
)}
-
-
+
+
{!!study && (
@@ -198,8 +198,8 @@ export const StudyDetail: FC<{
)}
-
-
+
+
{!!study && }
diff --git a/tslib/react/src/components/DataGrid.tsx b/tslib/react/src/components/DataGrid.tsx
index 4462768b..15d55bea 100644
--- a/tslib/react/src/components/DataGrid.tsx
+++ b/tslib/react/src/components/DataGrid.tsx
@@ -1,15 +1,19 @@
-import CheckBoxIcon from "@mui/icons-material/CheckBox"
-import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank"
-import FilterListIcon from "@mui/icons-material/FilterList"
-import FirstPageIcon from "@mui/icons-material/FirstPage"
-import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft"
-import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight"
-import LastPageIcon from "@mui/icons-material/LastPage"
+import {
+ CheckBox as CheckBoxIcon,
+ CheckBoxOutlineBlank as CheckBoxOutlineBlankIcon,
+ FilterList as FilterListIcon,
+ FirstPage as FirstPageIcon,
+ KeyboardArrowLeft,
+ KeyboardArrowRight,
+ LastPage as LastPageIcon,
+} from "@mui/icons-material"
import {
Box,
IconButton,
+ ListItem as ListItemIcon,
Menu,
MenuItem,
+ Paper,
Table,
TableBody,
TableCell,
@@ -21,8 +25,6 @@ import {
TextField,
useTheme,
} from "@mui/material"
-import ListItemIcon from "@mui/material/ListItemIcon"
-import Paper from "@mui/material/Paper"
import { TablePaginationActionsProps } from "@mui/material/TablePagination/TablePaginationActions"
import { styled } from "@mui/system"
import React from "react"