From a57e7f2622a4efb8e70b24415ec75046ecd5824d Mon Sep 17 00:00:00 2001 From: Maurice Yap Date: Fri, 20 Dec 2024 16:19:01 +0000 Subject: [PATCH] Lookout UI: dark mode and visual improvements (#4107) Add dark mode to the Lookout UI and make other visual improvements: - add syntax highlighting and correct the consistency for displaying code blocks in various languages - make job sets table more responsive and use MUI table component for better styling consistency - remove the use of react-virtualized, which is no longer well-maintained (last published two years ago). I don't think a virtualised table is necessary here given the volume of rows we're likely to display - all the job sets in a queue. --- internal/lookout/ui/package.json | 12 +- internal/lookout/ui/src/App.css | 12 - internal/lookout/ui/src/App.tsx | 24 +- .../src/components/ActionableValueOnHover.tsx | 2 +- .../ui/src/components/CheckboxHeaderRow.tsx | 28 - .../lookout/ui/src/components/CheckboxRow.tsx | 67 -- .../lookout/ui/src/components/CodeBlock.tsx | 148 ++++ .../ui/src/components/CopyIconButton.tsx | 1 - internal/lookout/ui/src/components/NavBar.tsx | 90 ++- .../ui/src/components/SettingsDialog.tsx | 52 ++ .../ui/src/components/SortableHeaderCell.css | 10 - .../ui/src/components/SortableHeaderCell.tsx | 20 - .../src/components/job-sets/JobSetTable.css | 18 - .../src/components/job-sets/JobSetTable.tsx | 270 +++---- .../ui/src/components/job-sets/JobSets.tsx | 40 +- .../lookoutV2/JobsTableCell.module.css | 43 +- .../components/lookoutV2/JobsTableCell.tsx | 21 +- .../components/lookoutV2/JobsTableFilter.tsx | 3 +- .../lookoutV2/sidebar/CodeBlock.module.css | 12 - .../lookoutV2/sidebar/CodeBlock.tsx | 9 - .../sidebar/ContainerDetails.module.css | 12 - .../lookoutV2/sidebar/ContainerDetails.tsx | 3 +- .../sidebar/SidebarTabJobCommands.module.css | 11 - .../sidebar/SidebarTabJobCommands.tsx | 69 +- .../sidebar/SidebarTabJobLogs.module.css | 52 -- .../lookoutV2/sidebar/SidebarTabJobLogs.tsx | 80 +- .../lookoutV2/sidebar/SidebarTabJobResult.tsx | 22 +- .../sidebar/SidebarTabJobYaml.module.css | 29 - .../lookoutV2/sidebar/SidebarTabJobYaml.tsx | 58 +- internal/lookout/ui/src/index.tsx | 1 - .../lookoutV2/JobsTablePreferencesService.ts | 5 +- internal/lookout/ui/src/styling/spacing.ts | 8 + internal/lookout/ui/src/theme/palette.ts | 14 +- internal/lookout/ui/src/theme/theme.ts | 5 +- internal/lookout/ui/vite.config.mts | 27 +- internal/lookout/ui/yarn.lock | 707 +----------------- 36 files changed, 641 insertions(+), 1344 deletions(-) delete mode 100644 internal/lookout/ui/src/App.css delete mode 100644 internal/lookout/ui/src/components/CheckboxHeaderRow.tsx delete mode 100644 internal/lookout/ui/src/components/CheckboxRow.tsx create mode 100644 internal/lookout/ui/src/components/CodeBlock.tsx create mode 100644 internal/lookout/ui/src/components/SettingsDialog.tsx delete mode 100644 internal/lookout/ui/src/components/SortableHeaderCell.css delete mode 100644 internal/lookout/ui/src/components/SortableHeaderCell.tsx delete mode 100644 internal/lookout/ui/src/components/job-sets/JobSetTable.css delete mode 100644 internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.module.css delete mode 100644 internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.tsx delete mode 100644 internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.module.css create mode 100644 internal/lookout/ui/src/styling/spacing.ts diff --git a/internal/lookout/ui/package.json b/internal/lookout/ui/package.json index 508085cd51a..7878909b465 100644 --- a/internal/lookout/ui/package.json +++ b/internal/lookout/ui/package.json @@ -29,23 +29,22 @@ "@mui/icons-material": "^6.1.10", "@mui/lab": "^6.0.0-beta.18", "@mui/material": "^6.1.10", + "@re-dev/react-truncate": "^0.4.3", "@tanstack/react-query": "^5.62.3", "@tanstack/react-table": "^8.7.0", - "@visx/mock-data": "^1.0.0", - "@visx/stats": "^1.4.0", - "@visx/visx": "^1.4.0", "date-fns": "^2.29.3", "date-fns-tz": "^1.3.7", "js-yaml": "^4.0.0", + "lodash": "^4.17.21", "notistack": "^3.0.1", "oidc-client-ts": "^2.3.0", + "prism-react-renderer": "^2.4.1", + "prismjs": "^1.29.0", "qs": "^6.11.0", "query-string": "^6.13.7", "react": "^18", "react-dom": "^18", "react-router-dom": "6.14.2", - "react-truncate": "^2.4.0", - "react-virtualized": "^9.22.5", "semver": "6.3.1", "tough-cookie": "^4.1.3", "use-debounce": "^10.0.0", @@ -75,12 +74,11 @@ "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.14", "@types/js-yaml": "^4.0.0", + "@types/lodash": "^4.17.13", "@types/node": "^22.10.2", "@types/qs": "^6.9.17", "@types/react": "^18", "@types/react-dom": "^18", - "@types/react-truncate": "^2.3.7", - "@types/react-virtualized": "^9.22.0", "@types/uuid": "^8.3.0", "@types/validator": "^13.7.3", "@typescript-eslint/eslint-plugin": "^8.18.0", diff --git a/internal/lookout/ui/src/App.css b/internal/lookout/ui/src/App.css deleted file mode 100644 index 65f2d14bb82..00000000000 --- a/internal/lookout/ui/src/App.css +++ /dev/null @@ -1,12 +0,0 @@ -.app-container { - display: flex; - flex-direction: column; - height: 100vh; -} - -.app-content { - height: 100%; - min-height: 0; - display: flex; - flex-direction: column; -} diff --git a/internal/lookout/ui/src/App.tsx b/internal/lookout/ui/src/App.tsx index 52ed9f1840f..c7123b52699 100644 --- a/internal/lookout/ui/src/App.tsx +++ b/internal/lookout/ui/src/App.tsx @@ -1,6 +1,6 @@ import { Dispatch, ReactNode, SetStateAction, useEffect, useState } from "react" -import { ThemeProvider } from "@mui/material" +import { CssBaseline, styled, ThemeProvider } from "@mui/material" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { SnackbarProvider } from "notistack" import { UserManager, WebStorageStateStore, UserManagerSettings, User } from "oidc-client-ts" @@ -14,7 +14,18 @@ import { Services, ServicesProvider } from "./services/context" import { theme } from "./theme/theme" import { CommandSpec, OidcConfig, withRouter } from "./utils" -import "./App.css" +const AppContainer = styled("div")({ + display: "flex", + flexDirection: "column", + height: "100vh", +}) + +const AppContent = styled("div")({ + height: "100%", + minHeight: 0, + display: "flex", + flexDirection: "column", +}) export const queryClient = new QueryClient({ defaultOptions: { @@ -135,15 +146,16 @@ export function App(props: AppProps): JSX.Element { const result = ( + -
+ -
+ -
-
+ +
diff --git a/internal/lookout/ui/src/components/ActionableValueOnHover.tsx b/internal/lookout/ui/src/components/ActionableValueOnHover.tsx index 68126b84f90..1f7ba72b2e9 100644 --- a/internal/lookout/ui/src/components/ActionableValueOnHover.tsx +++ b/internal/lookout/ui/src/components/ActionableValueOnHover.tsx @@ -8,11 +8,11 @@ import { AddFilter } from "./icons" const OuterContainer = styled("div")({ display: "flex", flexDirection: "row", + alignItems: "center", gap: "0.5ch", }) const StyledIconButton = styled(IconButton)(({ hidden }) => ({ - padding: 0, visibility: hidden ? "hidden" : "unset", })) diff --git a/internal/lookout/ui/src/components/CheckboxHeaderRow.tsx b/internal/lookout/ui/src/components/CheckboxHeaderRow.tsx deleted file mode 100644 index d6b0f9e7fd9..00000000000 --- a/internal/lookout/ui/src/components/CheckboxHeaderRow.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Checkbox } from "@mui/material" -import { TableHeaderRowProps } from "react-virtualized" - -import { CHECKBOX_WIDTH } from "./CheckboxRow" - -import "./Row.css" - -export type CheckboxHeaderRowProps = { - checked: boolean - disabled: boolean - onClick: () => void -} & TableHeaderRowProps - -export default function CheckboxHeaderRow(props: CheckboxHeaderRowProps) { - return ( -
-
- -
- {props.columns} -
- ) -} diff --git a/internal/lookout/ui/src/components/CheckboxRow.tsx b/internal/lookout/ui/src/components/CheckboxRow.tsx deleted file mode 100644 index 48e5cb928ec..00000000000 --- a/internal/lookout/ui/src/components/CheckboxRow.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useState } from "react" - -import { Checkbox } from "@mui/material" -import { TableRowProps } from "react-virtualized" - -import "./Row.css" - -type CheckboxRowProps = { - isChecked: boolean - onChangeChecked: (checked: boolean) => void - onChangeCheckedShift: (checked: boolean) => void - tableKey: string -} & TableRowProps - -export const CHECKBOX_WIDTH = 70 - -const EVEN_ROW_COLOR = "#ffffff" -const ODD_ROW_COLOR = "#f5f5f5" -const SELECTED_ROW_COLOR = "#b2ebf2" -const HOVERED_ROW_COLOR = "#e0e0e0" - -export default function CheckboxRow(props: CheckboxRowProps) { - const [isHovered, setHovered] = useState(false) - - let color = EVEN_ROW_COLOR - if (props.index % 2 != 0) { - color = ODD_ROW_COLOR - } - if (isHovered) { - color = HOVERED_ROW_COLOR - } - if (props.isChecked) { - color = SELECTED_ROW_COLOR - } - return ( -
setHovered(true)} - onMouseLeave={() => setHovered(false)} - > -
- { - if (event.shiftKey) { - props.onChangeCheckedShift(!props.isChecked) - } else { - props.onChangeChecked(!props.isChecked) - } - }} - /> -
- {props.columns} -
- ) -} diff --git a/internal/lookout/ui/src/components/CodeBlock.tsx b/internal/lookout/ui/src/components/CodeBlock.tsx new file mode 100644 index 00000000000..a1d8e740743 --- /dev/null +++ b/internal/lookout/ui/src/components/CodeBlock.tsx @@ -0,0 +1,148 @@ +import { useCallback } from "react" + +import { Download } from "@mui/icons-material" +import { IconButton, styled, useColorScheme } from "@mui/material" +import { Highlight, themes } from "prism-react-renderer" +import Prism from "prismjs" +import "prismjs/components/prism-bash" +import "prismjs/components/prism-yaml" + +import { CopyIconButton } from "./CopyIconButton" + +// All langauges in this set must be imported from Prism in the form: +// import "prismjs/components/prism-{language}" +type SupportedLanguage = "bash" | "yaml" + +const DARK_PRISM_THEME = themes.oneDark +const LIGHT_PRISM_THEME = themes.oneLight + +const CodeActionsContainer = styled("div")({ + display: "flex", + position: "absolute", + top: 10, + right: 10, + opacity: 0, + transition: "opacity 300ms ease-in-out", +}) + +const CodeBlockContainer = styled("div")({ + position: "relative", + + "&:hover > .codeActionsContainer": { + opacity: 1, + }, +}) + +const StyledPre = styled("pre")(({ theme }) => ({ + lineHeight: 1.2, + fontSize: theme.typography.body2.fontSize, + overflow: "auto", + padding: 5, + borderRadius: 5, + minHeight: 50, + display: "flex", + alignItems: "center", +})) + +const Code = styled("code")({ + display: "table", + wordWrap: "break-word", +}) + +const CodeLine = styled("div")({ + display: "table-row", + counterIncrement: "line-count", +}) + +const CodeLineNumber = styled("span")({ + display: "table-cell", + textAlign: "right", + width: "1%", + position: "sticky", + left: 0, + padding: "0 12px", + overflowWrap: "normal", + + "&::before": { + content: "counter(line-count)", + opacity: 0.4, + }, +}) + +export type CodeBlockProps = { + language: SupportedLanguage | "text" + code: string + showLineNumbers: boolean +} & ( + | { + downloadable: true + downloadBlobType: string + downloadFileName: string + } + | { downloadable: false; downloadBlobType?: undefined | string; downloadFileName?: undefined | string } +) + +export const CodeBlock = ({ + language, + code, + showLineNumbers, + downloadable, + downloadBlobType, + downloadFileName, +}: CodeBlockProps) => { + const { colorScheme } = useColorScheme() + + const downloadFile = useCallback(() => { + if (!downloadable) { + return + } + + const element = document.createElement("a") + const file = new Blob([code], { + type: downloadBlobType, + }) + element.href = URL.createObjectURL(file) + element.download = downloadFileName + document.body.appendChild(element) + element.click() + }, [code, downloadable, downloadBlobType, downloadFileName]) + + return ( + + + + {downloadable && ( + + + + )} + + + {({ style, tokens, getLineProps, getTokenProps }) => ( + + + {tokens.map((line, i) => { + const lineTokens = line.map((token, key) => ) + return showLineNumbers ? ( + + + {lineTokens} + + ) : ( +
+ {lineTokens} +
+ ) + })} +
+
+ )} +
+
+ ) +} diff --git a/internal/lookout/ui/src/components/CopyIconButton.tsx b/internal/lookout/ui/src/components/CopyIconButton.tsx index 1636a617747..1fc25ad3ce0 100644 --- a/internal/lookout/ui/src/components/CopyIconButton.tsx +++ b/internal/lookout/ui/src/components/CopyIconButton.tsx @@ -6,7 +6,6 @@ import { IconButton, IconButtonProps, styled, Tooltip } from "@mui/material" const LEAVE_DELAY_MS = 1_000 const StyledIconButton = styled(IconButton)(({ hidden }) => ({ - padding: 0, visibility: hidden ? "hidden" : "unset", })) diff --git a/internal/lookout/ui/src/components/NavBar.tsx b/internal/lookout/ui/src/components/NavBar.tsx index 3607187e2df..a33828b1f2a 100644 --- a/internal/lookout/ui/src/components/NavBar.tsx +++ b/internal/lookout/ui/src/components/NavBar.tsx @@ -1,6 +1,10 @@ -import { AppBar, Tab, Tabs, Toolbar, Typography } from "@mui/material" +import { useState } from "react" + +import { Settings } from "@mui/icons-material" +import { AppBar, IconButton, Tab, Tabs, Toolbar, Typography } from "@mui/material" import { Link } from "react-router-dom" +import { SettingsDialog } from "./SettingsDialog" import { Router, withRouter } from "../utils" import "./NavBar.css" @@ -48,46 +52,56 @@ interface NavBarProps { function NavBar({ customTitle, router, username }: NavBarProps) { const currentLocation = router.location.pathname const currentValue = locationMap.has(currentLocation) ? locationMap.get(currentLocation) : 0 + const [settingsOpen, setSettingsOpen] = useState(false) + return ( - - - -
- { - const newLocation = locationFromIndex(PAGES, newIndex) - router.navigate(newLocation) - }} - textColor="inherit" - indicatorColor="secondary" - > - {PAGES.map((page, idx) => ( - - ))} - -
-
+ <> + +
- - {username ? <>Welcome, {username}! : <>Welcome!} - + + {""} + + Lookout + + {customTitle && ( + + {customTitle} + + )} + +
+
+ { + const newLocation = locationFromIndex(PAGES, newIndex) + router.navigate(newLocation) + }} + textColor="inherit" + indicatorColor="secondary" + > + {PAGES.map((page, idx) => ( + + ))} + +
+
+
+ + {username ? <>Welcome, {username}! : <>Welcome!} + +
+
+ setSettingsOpen(true)}> + + +
-
-
-
+ + + setSettingsOpen(false)} /> + ) } diff --git a/internal/lookout/ui/src/components/SettingsDialog.tsx b/internal/lookout/ui/src/components/SettingsDialog.tsx new file mode 100644 index 00000000000..7a01b7b5585 --- /dev/null +++ b/internal/lookout/ui/src/components/SettingsDialog.tsx @@ -0,0 +1,52 @@ +import { Close } from "@mui/icons-material" +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + ToggleButton, + ToggleButtonGroup, + Typography, + useColorScheme, +} from "@mui/material" + +export interface SettingsDialogProps { + open: boolean + onClose: () => void +} + +export const SettingsDialog = ({ open, onClose }: SettingsDialogProps) => { + const { mode, setMode } = useColorScheme() + + return ( + + Settings + +
+ Colour mode +
+
+ setMode(colorMode)} + fullWidth + > + Light + System + Dark + +
+
+ + + +
+ ) +} diff --git a/internal/lookout/ui/src/components/SortableHeaderCell.css b/internal/lookout/ui/src/components/SortableHeaderCell.css deleted file mode 100644 index 5adf6785dca..00000000000 --- a/internal/lookout/ui/src/components/SortableHeaderCell.css +++ /dev/null @@ -1,10 +0,0 @@ -.sortable-header-cell { - width: 100%; - padding: 0 1em 0 0; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - cursor: pointer; - text-transform: none; -} diff --git a/internal/lookout/ui/src/components/SortableHeaderCell.tsx b/internal/lookout/ui/src/components/SortableHeaderCell.tsx deleted file mode 100644 index 665aba00259..00000000000 --- a/internal/lookout/ui/src/components/SortableHeaderCell.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { ArrowDropDown, ArrowDropUp } from "@mui/icons-material" -import { TableHeaderProps } from "react-virtualized" - -import "./SortableHeaderCell.css" - -type SortableHeaderCellProps = { - descending: boolean - name: string - className: string - onOrderChange: (descending: boolean) => void -} & TableHeaderProps - -export default function SortableHeaderCell(props: SortableHeaderCellProps) { - return ( -
props.onOrderChange(!props.descending)}> -
{props.name}
-
{props.descending ? : }
-
- ) -} diff --git a/internal/lookout/ui/src/components/job-sets/JobSetTable.css b/internal/lookout/ui/src/components/job-sets/JobSetTable.css deleted file mode 100644 index a3e84cff60b..00000000000 --- a/internal/lookout/ui/src/components/job-sets/JobSetTable.css +++ /dev/null @@ -1,18 +0,0 @@ -.job-set-table-header { - text-align: center; -} - -.job-set-table-number-cell { - text-align: right; - padding-right: 1em; -} - -.job-set-submission-time-header-cell { - font-weight: 700; - text-transform: uppercase; -} - -.job-set-table-job-set-name-cell { - white-space: normal !important; - word-break: break-word !important; -} diff --git a/internal/lookout/ui/src/components/job-sets/JobSetTable.tsx b/internal/lookout/ui/src/components/job-sets/JobSetTable.tsx index 42286c80b85..59755ff4e68 100644 --- a/internal/lookout/ui/src/components/job-sets/JobSetTable.tsx +++ b/internal/lookout/ui/src/components/job-sets/JobSetTable.tsx @@ -1,19 +1,39 @@ -import { Stack } from "@mui/material" -import Truncate from "react-truncate" -import { TableCellProps, Table as VirtualizedTable, Column } from "react-virtualized" +import { useCallback, useEffect, useState } from "react" + +import { + Alert, + Box, + Checkbox, + Stack, + styled, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TableSortLabel, +} from "@mui/material" +import { visuallyHidden } from "@mui/utils" +import { Truncate } from "@re-dev/react-truncate" import { JobState, jobStateColors, jobStateIcons } from "../../models/lookoutV2Models" import { JobSet } from "../../services/JobService" import { formatJobState } from "../../utils/jobsTableFormatters" -import CheckboxHeaderRow from "../CheckboxHeaderRow" -import CheckboxRow from "../CheckboxRow" -import "./JobSetTable.css" -import SortableHeaderCell from "../SortableHeaderCell" import { JobStateCountChip } from "../lookoutV2/JobStateCountChip" +const JOB_STATES_TO_DISPLAY = [ + [JobState.Queued, "jobsQueued"], + [JobState.Pending, "jobsPending"], + [JobState.Running, "jobsRunning"], + [JobState.Succeeded, "jobsSucceeded"], + [JobState.Failed, "jobsFailed"], + [JobState.Cancelled, "jobsCancelled"], +] as const + +const MinWidthTableCell = styled(TableCell)({ width: "0%", textWrap: "nowrap" }) + interface JobSetTableProps { - height: number - width: number queue: string jobSets: JobSet[] selectedJobSets: Map @@ -26,125 +46,125 @@ interface JobSetTableProps { onJobSetStateClick(rowIndex: number, state: string): void } -function cellRendererForState(cellProps: TableCellProps, jobState: JobState, onClickFunc: () => void) { - return -} +export default function JobSetTable({ + queue, + jobSets, + selectedJobSets, + newestFirst, + onSelectJobSet, + onShiftSelectJobSet, + onDeselectAllClick, + onSelectAllClick, + onOrderChange, + onJobSetStateClick, +}: JobSetTableProps) { + const [shiftKeyPressed, setShiftKeyPressed] = useState(false) + const onKeyDown = useCallback((ev: KeyboardEvent) => { + if (ev.key === "Shift") { + setShiftKeyPressed(true) + } + }, []) + const onKeyUp = useCallback((ev: KeyboardEvent) => { + if (ev.key === "Shift") { + setShiftKeyPressed(false) + } + }, []) -function cellRendererForJobSet(cellProps: TableCellProps, width: number) { - return ( - - {cellProps.cellData} - - ) -} + useEffect(() => { + document.addEventListener("keydown", onKeyDown, false) + document.addEventListener("keyup", onKeyUp, false) + + return () => { + document.removeEventListener("keydown", onKeyDown, false) + document.removeEventListener("keyup", onKeyUp, false) + } + }, [onKeyDown, onKeyUp]) -export default function JobSetTable(props: JobSetTableProps) { - if (props.queue === "") { - return ( -
- Enter a queue name into the "Queue" field to view job sets. -
- ) + if (queue === "") { + return Enter a queue name into the "Queue" field to view job sets. } + + if (jobSets.length === 0) { + return No job sets found for this queue. + } + return ( -
- props.jobSets[index]} - rowCount={props.jobSets.length} - rowHeight={50} - headerHeight={60} - height={props.height} - width={props.width} - headerClassName="job-set-table-header" - rowRenderer={(tableRowProps) => { - return ( - props.onSelectJobSet(tableRowProps.index, selected)} - onChangeCheckedShift={(selected) => props.onShiftSelectJobSet(tableRowProps.index, selected)} - tableKey={tableRowProps.key} - {...tableRowProps} - /> - ) - }} - headerRowRenderer={(tableHeaderRowProps) => { - const jobSetsAreSelected = props.selectedJobSets.size > 0 - const noJobSetsArePresent = props.jobSets.length == 0 - return ( - props.onDeselectAllClick() : props.onSelectAllClick} - {...tableHeaderRowProps} - /> - ) - }} - > - cellProps.label} - cellRenderer={(cellProps) => cellRendererForJobSet(cellProps, 0.5 * props.width)} - className="job-set-table-job-set-name-cell" - /> - ( - - )} - /> - {( - [ - [JobState.Queued, "jobsQueued"], - [JobState.Pending, "jobsPending"], - [JobState.Running, "jobsRunning"], - [JobState.Succeeded, "jobsSucceeded"], - [JobState.Failed, "jobsFailed"], - [JobState.Cancelled, "jobsCancelled"], - ] as [JobState, keyof JobSet][] - ).map(([jobState, dataKey]) => { - const Icon = jobStateIcons[jobState] - return ( - - {formatJobState(jobState)} - - - } - className="job-set-table-number-cell" - cellRenderer={(cellProps) => - cellRendererForState(cellProps, jobState, () => props.onJobSetStateClick(cellProps.rowIndex, jobState)) - } - /> - ) - })} - -
+ + + + + + (checked ? onSelectAllClick() : onDeselectAllClick())} + /> + + Job Set + + onOrderChange(!newestFirst)} + > + Submission time + + {newestFirst ? "sorted descending" : "sorted ascending"} + + + + {JOB_STATES_TO_DISPLAY.map(([jobState]) => { + const Icon = jobStateIcons[jobState] + return ( + + + {formatJobState(jobState)} + + + + ) + })} + + + + {jobSets.map(({ jobSetId, latestSubmissionTime, ...jobSetRest }, jobSetIndex) => { + const rowSelected = selectedJobSets.has(jobSetId) + return ( + + + + shiftKeyPressed ? onShiftSelectJobSet(jobSetIndex, checked) : onSelectJobSet(jobSetIndex, checked) + } + /> + + + {jobSetId} + + {latestSubmissionTime} + {JOB_STATES_TO_DISPLAY.map(([jobState, jobSetKey]) => ( + + onJobSetStateClick(jobSetIndex, jobState)} + /> + + ))} + + ) + })} + +
+
) } diff --git a/internal/lookout/ui/src/components/job-sets/JobSets.tsx b/internal/lookout/ui/src/components/job-sets/JobSets.tsx index ad32c022dad..634e3739def 100644 --- a/internal/lookout/ui/src/components/job-sets/JobSets.tsx +++ b/internal/lookout/ui/src/components/job-sets/JobSets.tsx @@ -1,8 +1,5 @@ -import { FC } from "react" - import { Cancel, LowPriority } from "@mui/icons-material" import { Button, Container, TextField, FormControlLabel, Checkbox, Tooltip } from "@mui/material" -import { AutoSizer as _AutoSizer, AutoSizerProps } from "react-virtualized" import JobSetTable from "./JobSetTable" import { JobSet } from "../../services/JobService" @@ -12,9 +9,6 @@ import RefreshButton from "../RefreshButton" import "./JobSets.css" -// This works around a type bug in react-virtualized: https://github.com/bvaughn/react-virtualized/issues/1739 -const AutoSizer = _AutoSizer as unknown as FC - interface JobSetsProps { queue: string jobSets: JobSet[] @@ -40,23 +34,6 @@ interface JobSetsProps { } export default function JobSets(props: JobSetsProps) { - const content = (height: number, width: number) => ( - - ) - return (
@@ -125,11 +102,18 @@ export default function JobSets(props: JobSetsProps) {
- - {({ height, width }) => { - return content(height, width) - }} - +
) diff --git a/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.module.css b/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.module.css index 922a6fea4b8..cd2d81c71c4 100644 --- a/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.module.css +++ b/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.module.css @@ -1,35 +1,26 @@ .resizer { - position: relative; - right: 0; - top: 0; - height: 100%; - width: 5px; - background: rgba(0, 0, 0, 0.5); - cursor: col-resize; - user-select: none; - touch-action: none; + position: relative; + right: 0; + top: 0; + height: 100%; + width: 5px; + background: rgba(0, 0, 0, 0.5); + cursor: col-resize; + user-select: none; + touch-action: none; } .resizer.isResizing { - background: blue; - opacity: 1; + background: blue; + opacity: 1; } @media (hover: hover) { - .resizer { - opacity: 0; - } - - *:hover > .resizer { - opacity: 1; - } -} + .resizer { + opacity: 0; + } -.headerCell { - background-color: #f2f2f2; - height: 100%; -} - -.headerCell th { - height: 100%; + *:hover > .resizer { + opacity: 1; + } } diff --git a/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.tsx b/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.tsx index 703d169e405..1a9a90451db 100644 --- a/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.tsx +++ b/internal/lookout/ui/src/components/lookoutV2/JobsTableCell.tsx @@ -1,7 +1,7 @@ import { RefObject } from "react" import { KeyboardArrowRight, KeyboardArrowDown } from "@mui/icons-material" -import { TableCell, IconButton, TableSortLabel, Box } from "@mui/material" +import { TableCell, IconButton, TableSortLabel, Box, styled } from "@mui/material" import { Cell, ColumnResizeMode, flexRender, Header, Row } from "@tanstack/react-table" import styles from "./JobsTableCell.module.css" @@ -28,6 +28,13 @@ const sharedCellStyleWithOpacity = { }, } +const HeaderTableCell = styled(TableCell)(({ theme }) => ({ + backgroundColor: theme.palette.grey[200], + ...theme.applyStyles("dark", { + backgroundColor: theme.palette.grey[800], + }), +})) + export interface HeaderCellProps { header: Header columnResizeMode: ColumnResizeMode @@ -64,7 +71,7 @@ export function HeaderCell({ const match = matchForColumn(header.id, columnMatches) if (header.isPlaceholder) { return ( - ) } return ( -
- + ) } @@ -264,7 +267,7 @@ export const BodyCell = ({ cell, rowIsGroup, rowIsExpanded, onExpandedChange, on : undefined } filterAction={ - columnMetadata.filterType === undefined + rowIsGroup || !cell.getValue() || columnMetadata.filterType === undefined ? undefined : { onFilter: () => { diff --git a/internal/lookout/ui/src/components/lookoutV2/JobsTableFilter.tsx b/internal/lookout/ui/src/components/lookoutV2/JobsTableFilter.tsx index ee7c0062aa3..0416ec3720f 100644 --- a/internal/lookout/ui/src/components/lookoutV2/JobsTableFilter.tsx +++ b/internal/lookout/ui/src/components/lookoutV2/JobsTableFilter.tsx @@ -6,6 +6,7 @@ import { Checkbox, IconButton, InputAdornment, + InputLabel, ListItemIcon, ListItemText, MenuItem, @@ -130,7 +131,7 @@ const EnumFilter = ({ currentFilter, enumFilterValues, label, onFilterChange }: selected.map((s) => enumFilterValues.find((v) => v.value === s)?.displayName ?? s).join(", ") ) : ( // Approximately matches the styling for a text input's placeholder -
{label}
+ {label} ) } // Matches the styling for TextFilter component below diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.module.css b/internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.module.css deleted file mode 100644 index f1dded92758..00000000000 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.module.css +++ /dev/null @@ -1,12 +0,0 @@ -.codeBlock { - display: block; - white-space: pre; - -webkit-overflow-scrolling: touch; - overflow-x: auto; - max-width: 100%; - min-width: 100px; - padding: 5px; - background: #1b1b1b none; - color: #fff; - width: 100%; -} diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.tsx b/internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.tsx deleted file mode 100644 index dfe4aa34d80..00000000000 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/CodeBlock.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import styles from "./CodeBlock.module.css" - -export type CodeBlockProps = { - text: string -} - -export const CodeBlock = ({ text }: CodeBlockProps) => { - return
{text}
-} diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.module.css b/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.module.css index 0ac740917bf..4d543325a49 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.module.css +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.module.css @@ -8,18 +8,6 @@ justify-content: center; } -.command { - width: 100%; - white-space: pre-wrap; - font-family: monospace; - word-wrap: break-word; - background: #1b1b1b none; - color: #fff; - padding: 5px; - border-radius: 5px; - position: relative; -} - .singleContainer { padding: 0 10px 0 25px; } diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.tsx b/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.tsx index 9d86bbc835a..c6446286f34 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.tsx +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/ContainerDetails.tsx @@ -7,6 +7,7 @@ import { KeyValuePairTable } from "./KeyValuePairTable" import { useCustomSnackbar } from "../../../hooks/useCustomSnackbar" import { Job } from "../../../models/lookoutV2Models" import { useGetJobSpec } from "../../../services/lookoutV2/useGetJobSpec" +import { CodeBlock } from "../../CodeBlock" export interface ContainerData { name: string @@ -107,7 +108,7 @@ const SingleContainerDetails = ({ container, openByDefault }: { container: Conta
Command -
{entrypoint}
+
Resources diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.module.css b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.module.css deleted file mode 100644 index 845c34e93d1..00000000000 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.commandsText { - width: 100%; - white-space: pre-wrap; - font-family: monospace; - word-wrap: break-word; - background: #1b1b1b none; - color: #fff; - padding: 5px; - border-radius: 5px; - position: relative; -} diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.tsx b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.tsx index 69b5ce9681e..03cc88ef075 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.tsx +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobCommands.tsx @@ -1,14 +1,12 @@ -import { useCallback } from "react" - -import { ContentCopy } from "@mui/icons-material" -import { IconButton, Link } from "@mui/material" +import { OpenInNew } from "@mui/icons-material" +import { Link, Stack, Typography } from "@mui/material" import { template, templateSettings } from "lodash" import validator from "validator" -import styles from "./SidebarTabJobCommands.module.css" -import { useCustomSnackbar } from "../../../hooks/useCustomSnackbar" import { Job } from "../../../models/lookoutV2Models" +import { SPACING } from "../../../styling/spacing" import { CommandSpec } from "../../../utils" +import { CodeBlock } from "../../CodeBlock" export interface SidebarTabJobCommandsProps { job: Job @@ -27,40 +25,33 @@ function getCommandText(job: Job, commandSpec: CommandSpec): string { } export const SidebarTabJobCommands = ({ job, commandSpecs }: SidebarTabJobCommandsProps) => { - const openSnackbar = useCustomSnackbar() - - const copyCommand = useCallback(async (commandText: string) => { - await navigator.clipboard.writeText(commandText) - openSnackbar("Copied command to clipboard!", "info", { - autoHideDuration: 3000, - preventDuplicate: true, - }) - }, []) + if ((job.runs ?? []).length === 0) { + return null + } return ( -
- {job.runs?.length ? ( -
- {commandSpecs.map((c, i) => ( - <> -
- {i > 0 ?
: undefined} - {c.name} - copyCommand(getCommandText(job, c))}> - - -
- {validator.isURL(getCommandText(job, c)) ? ( - -
{getCommandText(job, c)}
- - ) : ( -
{getCommandText(job, c)}
- )} - - ))} -
- ) : undefined} -
+ + {commandSpecs.map((commandSpec) => { + const { name } = commandSpec + const commandText = getCommandText(job, commandSpec) + return ( +
+ + {name} + + {validator.isURL(commandText) ? ( + + +
{commandText}
+ +
+ + ) : ( + + )} +
+ ) + })} +
) } diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.module.css b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.module.css index 75da3743252..f1aac7e7509 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.module.css +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.module.css @@ -1,11 +1,3 @@ -.sidebarLogsTabContainer { - max-width: 100%; - height: 100%; - display: flex; - flex-direction: column; - overflow: auto; -} - .logsHeader { flex: 0 0 auto; max-width: 100%; @@ -20,31 +12,6 @@ padding: 0 5px 0 5px; } -.gutter { - flex: 0 0 40px; - max-width: 100%; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 5px; -} - -.errorMessage { - flex: 1 1 auto; - display: flex; - align-items: center; - justify-content: center; - height: 100%; - white-space: pre-wrap; - font-family: monospace; - word-wrap: break-word; - overflow-y: auto; - background-color: #ffcdd2; - border-radius: 5px; - padding: 0 5px 0 5px; -} - .loading { display: flex; flex-direction: row; @@ -53,20 +20,6 @@ margin: 0.5em 0 0.5em 0; } -.logView { - width: 100%; - white-space: pre-wrap; - font-family: monospace; - word-wrap: break-word; - margin-top: 5px; - background-color: #f5f5f5; - padding: 5px; - border-radius: 5px; - position: relative; - overflow-y: auto; - overflow-x: auto; -} - .emptyLogView { display: flex; align-items: center; @@ -74,11 +27,6 @@ margin: 10px 0 10px 0; } -.timestamp { - background-color: #e0e0e0; - margin-right: 10px; -} - .didNotRun { display: flex; align-items: center; diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.tsx b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.tsx index 9baac2b1c82..4b3d0025478 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.tsx +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobLogs.tsx @@ -2,6 +2,8 @@ import { useEffect, useMemo, useRef, useState, UIEvent } from "react" import { Refresh } from "@mui/icons-material" import { + Alert, + alpha, Checkbox, CircularProgress, FormControl, @@ -11,6 +13,8 @@ import { InputLabel, MenuItem, Select, + Stack, + styled, } from "@mui/material" import styles from "./SidebarTabJobLogs.module.css" @@ -19,6 +23,12 @@ import { Job, JobRun } from "../../../models/lookoutV2Models" import { LogLine } from "../../../services/lookoutV2/LogService" import { useGetJobSpec } from "../../../services/lookoutV2/useGetJobSpec" import { useGetLogs } from "../../../services/lookoutV2/useGetLogs" +import { SPACING } from "../../../styling/spacing" + +const Container = styled(Stack)({ + height: "100%", + maxWidth: "100%", +}) export interface SidebarTabJobLogsProps { job: Job @@ -121,7 +131,7 @@ export const SidebarTabJobLogs = ({ job }: SidebarTabJobLogsProps) => { } return ( -
+
{ {getLogsResult.status === "success" && ( )} -
- {getLogsResult.status === "error" && ( - <> -
{getLogsResult.error}
-
- getLogsResult.refetch()}> + {getLogsResult.status === "error" && ( +
+ getLogsResult.refetch()}> -
- - )} -
-
+ } + > + {getLogsResult.error} + +
+ )} + ) } -function LogView({ logLines, showTimestamps }: { logLines: LogLine[]; showTimestamps: boolean }) { - if (logLines.length === 0) { - return ( -
- No logs to display -
- ) - } +const LogsContainer = styled("div")(({ theme }) => ({ + width: "100%", + whiteSpace: "pre-wrap", + fontFamily: "monospace", + wordWrap: "break-word", + marginTop: 5, + backgroundColor: theme.palette.background.paper, + padding: 5, + borderRadius: 5, + position: "relative", + overflowY: "auto", + overflowX: "auto", +})) + +const Timestamp = styled("span")(({ theme }) => ({ + marginRight: 10, + backgroundColor: alpha(theme.palette.primary.light, 0.15), + ...theme.applyStyles("dark", { + backgroundColor: alpha(theme.palette.primary.main, 0.15), + }), +})) +function LogView({ logLines, showTimestamps }: { logLines: LogLine[]; showTimestamps: boolean }) { const [shouldScrollDown, setShouldScrollDown] = useState(true) const logsEndRef = useRef(null) const previousScrollTopRef = useRef() @@ -287,16 +313,24 @@ function LogView({ logLines, showTimestamps }: { logLines: LogLine[]; showTimest } } + if (logLines.length === 0) { + return ( +
+ No logs to display +
+ ) + } + return ( -
+ {logLines.map((logLine, i) => ( - {showTimestamps && {logLine.timestamp}} + {showTimestamps && {logLine.timestamp}} {logLine.line + "\n"} ))}
-
+
) } diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobResult.tsx b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobResult.tsx index 9d4e6febfd9..9a0ac0433b6 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobResult.tsx +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobResult.tsx @@ -15,7 +15,6 @@ import { Typography, } from "@mui/material" -import { CodeBlock } from "./CodeBlock" import { KeyValuePairTable } from "./KeyValuePairTable" import styles from "./SidebarTabJobResult.module.css" import { useCustomSnackbar } from "../../../hooks/useCustomSnackbar" @@ -26,6 +25,7 @@ import { IGetJobInfoService } from "../../../services/lookoutV2/GetJobInfoServic import { IGetRunInfoService } from "../../../services/lookoutV2/GetRunInfoService" import { getErrorMessage } from "../../../utils" import { formatJobRunState, formatTimeSince, formatUtcDate } from "../../../utils/jobsTableFormatters" +import { CodeBlock } from "../../CodeBlock" export interface SidebarTabJobResultProps { job: Job @@ -220,7 +220,7 @@ export const SidebarTabJobResult = ({ {topLevelError !== "" ? ( <> {topLevelErrorTitle}: - + ) : null} Runs: @@ -301,7 +301,14 @@ export const SidebarTabJobResult = ({ } aria-controls="panel1d-content" id="panel1d-header"> Error - {} + + + )} {runDebugMessageLoadingMap.has(run.runId) && runDebugMessageLoadingMap.get(run.runId) === "Loading" && ( @@ -314,7 +321,14 @@ export const SidebarTabJobResult = ({ } aria-controls="panel1d-content" id="panel1d-header"> Debug - {} + + + )} diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.module.css b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.module.css index 7b6de593b31..1597d0454a8 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.module.css +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.module.css @@ -5,32 +5,3 @@ justify-content: center; margin-bottom: 0.5em; } - -.jobYaml { - width: 100%; - white-space: pre-wrap; - font-family: monospace; - word-wrap: break-word; - background-color: #f5f5f5; - padding: 5px; - border-radius: 5px; - position: relative; -} - -.jobYamlActions { - padding: 5px; - position: absolute; - top: 0; - right: 0; -} - -@media (hover: hover) { - .jobYamlActions { - opacity: 0; - transition: opacity 300ms ease-in-out; - } - - *:hover > .jobYamlActions { - opacity: 1; - } -} diff --git a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.tsx b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.tsx index 1e87903ae13..39669e44fbb 100644 --- a/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.tsx +++ b/internal/lookout/ui/src/components/lookoutV2/sidebar/SidebarTabJobYaml.tsx @@ -1,14 +1,13 @@ -import { useCallback, useEffect, useMemo } from "react" +import { useEffect } from "react" -import { ContentCopy, Download } from "@mui/icons-material" import { CircularProgress } from "@mui/material" -import { IconButton } from "@mui/material" import yaml from "js-yaml" import styles from "./SidebarTabJobYaml.module.css" import { useCustomSnackbar } from "../../../hooks/useCustomSnackbar" import { Job } from "../../../models/lookoutV2Models" import { useGetJobSpec } from "../../../services/lookoutV2/useGetJobSpec" +import { CodeBlock } from "../../CodeBlock" export interface SidebarTabJobYamlProps { job: Job @@ -50,38 +49,6 @@ export const SidebarTabJobYaml = ({ job }: SidebarTabJobYamlProps) => { } }, [getJobSpecResult.status, getJobSpecResult.error]) - const submission = useMemo(() => { - if (getJobSpecResult.status === "success") { - return toJobSubmissionYaml(getJobSpecResult.data) - } - return undefined - }, [getJobSpecResult.status, getJobSpecResult.data]) - - const downloadYamlFile = useCallback(() => { - if (submission === undefined) { - return - } - const element = document.createElement("a") - const file = new Blob([submission], { - type: "text/plain", - }) - element.href = URL.createObjectURL(file) - element.download = `${job.jobId}.yaml` - document.body.appendChild(element) - element.click() - }, [submission, job]) - - const copyYaml = useCallback(async () => { - if (submission === undefined) { - return - } - await navigator.clipboard.writeText(submission) - openSnackbar("Copied job submission YAML to clipboard!", "info", { - autoHideDuration: 3000, - preventDuplicate: true, - }) - }, [submission, job]) - return (
{getJobSpecResult.status === "pending" && ( @@ -90,19 +57,14 @@ export const SidebarTabJobYaml = ({ job }: SidebarTabJobYamlProps) => {
)} {getJobSpecResult.status === "success" && ( -
-
-
- - - - - - -
-
- {toJobSubmissionYaml(getJobSpecResult.data)} -
+ )}
) diff --git a/internal/lookout/ui/src/index.tsx b/internal/lookout/ui/src/index.tsx index caf7421a522..5253021b3dc 100644 --- a/internal/lookout/ui/src/index.tsx +++ b/internal/lookout/ui/src/index.tsx @@ -20,7 +20,6 @@ import { FakeLogService } from "./services/lookoutV2/mocks/FakeLogService" import { getUIConfig } from "./utils" import { makeRandomJobs } from "./utils/fakeJobsUtils" -import "react-virtualized/styles.css" import "./index.css" ;(async () => { const uiConfig = await getUIConfig() diff --git a/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts b/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts index 9e69dc0c23c..b47a8ae03e0 100644 --- a/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts +++ b/internal/lookout/ui/src/services/lookoutV2/JobsTablePreferencesService.ts @@ -1,6 +1,5 @@ import { ColumnFiltersState, ExpandedStateList, VisibilityState } from "@tanstack/react-table" import qs from "qs" -import { SortDirection } from "react-virtualized" import { LookoutColumnOrder } from "../../containers/lookoutV2/JobsTableContainer" import { isValidMatch, JobId, Match } from "../../models/lookoutV2Models" @@ -100,7 +99,7 @@ export const toQueryStringSafe = (prefs: JobsTablePreferences): QueryStringPrefs }), sort: { id: prefs.order.id, - desc: String(prefs.order.direction === SortDirection.DESC), + desc: String(prefs.order.direction === "DESC"), }, e: Object.entries(prefs.expandedState) .filter(([_, expanded]) => expanded) @@ -135,7 +134,7 @@ const fromQueryStringSafe = (serializedPrefs: Partial): Partia ...(page !== undefined && { pageIndex: Number(page) }), ...(ps !== undefined && { pageSize: Number(ps) }), ...(sort && { - order: { id: sort.id, direction: sort.desc.toLowerCase() === "true" ? SortDirection.DESC : SortDirection.ASC }, + order: { id: sort.id, direction: sort.desc.toLowerCase() === "true" ? "DESC" : "ASC" }, }), ...(f && { filters: columnFiltersFromQueryStringFilters(f) }), ...(f && { columnMatches: columnMatchesFromQueryStringFilters(f) }), diff --git a/internal/lookout/ui/src/styling/spacing.ts b/internal/lookout/ui/src/styling/spacing.ts new file mode 100644 index 00000000000..0dc25da3b79 --- /dev/null +++ b/internal/lookout/ui/src/styling/spacing.ts @@ -0,0 +1,8 @@ +export const SPACING = { + xs: 0.5, + sm: 1, + md: 2, + lg: 4, + xl: 6, + xxl: 10, +} as const diff --git a/internal/lookout/ui/src/theme/palette.ts b/internal/lookout/ui/src/theme/palette.ts index e3ac24fdcaf..6e1d354eeb7 100644 --- a/internal/lookout/ui/src/theme/palette.ts +++ b/internal/lookout/ui/src/theme/palette.ts @@ -37,7 +37,19 @@ const augmentColor = (main: string): PaletteColorOptions => ({ contrastText: getContrastRatio(main, "#fff") > CONTRAST_THRESHOLD ? "#fff" : "#000", }) -export const palette: PaletteOptions = { +export const lightModePalette: PaletteOptions = { + primary: { main: LIGHT_BLUE, contrastText: "#FFF" }, + secondary: { main: ORANGE }, + statusGrey: augmentColor(STATUS_GREY), + statusBlue: augmentColor(STATUS_BLUE), + statusGreen: augmentColor(STATUS_GREEN), + statusAmber: augmentColor(STATUS_AMBER), + statusRed: augmentColor(STATUS_RED), + tonalOffset: TONAL_OFFSET, + contrastThreshold: CONTRAST_THRESHOLD, +} + +export const darkModePalette: PaletteOptions = { primary: { main: LIGHT_BLUE, contrastText: "#FFF" }, secondary: { main: ORANGE }, statusGrey: augmentColor(STATUS_GREY), diff --git a/internal/lookout/ui/src/theme/theme.ts b/internal/lookout/ui/src/theme/theme.ts index c18e2419890..7088b8257cb 100644 --- a/internal/lookout/ui/src/theme/theme.ts +++ b/internal/lookout/ui/src/theme/theme.ts @@ -1,10 +1,9 @@ import { createTheme } from "@mui/material" -import { palette } from "./palette" +import { darkModePalette, lightModePalette } from "./palette" import { typography } from "./typography" export const theme = createTheme({ - colorSchemes: { dark: false, light: true }, - palette, + colorSchemes: { dark: { palette: darkModePalette }, light: { palette: lightModePalette } }, typography, }) diff --git a/internal/lookout/ui/vite.config.mts b/internal/lookout/ui/vite.config.mts index 2070f06157e..b26dc139c63 100644 --- a/internal/lookout/ui/vite.config.mts +++ b/internal/lookout/ui/vite.config.mts @@ -1,33 +1,8 @@ import react from "@vitejs/plugin-react" import { defineConfig, ProxyOptions } from "vite" -import path from "path" -import fs from "fs" -import { createRequire } from "node:module" - -const require = createRequire(import.meta.url) - -// See https://github.com/bvaughn/react-virtualized/issues/1722 -const WRONG_CODE = `import { bpfrpt_proptype_WindowScroller } from "../WindowScroller.js";` - -const reactVirtualized = () => { - return { - name: "my:react-virtualized", - configResolved() { - const file = require - .resolve("react-virtualized") - .replace( - path.join("dist", "commonjs", "index.js"), - path.join("dist", "es", "WindowScroller", "utils", "onScroll.js"), - ) - const code = fs.readFileSync(file, "utf-8") - const modified = code.replace(WRONG_CODE, "") - fs.writeFileSync(file, modified) - }, - } -} export default defineConfig({ - plugins: [react(), reactVirtualized()], + plugins: [react()], server: { port: 3000, proxy: ["/api", "/config"].reduce>( diff --git a/internal/lookout/ui/yarn.lock b/internal/lookout/ui/yarn.lock index ebc12e72f76..0c92373beac 100644 --- a/internal/lookout/ui/yarn.lock +++ b/internal/lookout/ui/yarn.lock @@ -177,7 +177,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.25.9" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": version "7.19.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78" integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA== @@ -988,6 +988,11 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== +"@re-dev/react-truncate@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@re-dev/react-truncate/-/react-truncate-0.4.3.tgz#89ed2935a30f271a80f6af8fa66c9fe471baf742" + integrity sha512-dMtHgU/uOorC5gQNtJBjIf9Zv5+lRa11+0YSTEbfD1KCyKKb0bcCjVCEVyyKUSv0/vEmiG+twQIt2eVKETaRNA== + "@remix-run/router@1.7.2": version "1.7.2" resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.7.2.tgz#cba1cf0a04bc04cb66027c51fa600e9cbc388bc8" @@ -1206,64 +1211,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/d3-color@^1": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-1.4.2.tgz#944f281d04a0f06e134ea96adbb68303515b2784" - integrity sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA== - -"@types/d3-geo@^1.11.1": - version "1.12.3" - resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-1.12.3.tgz#512ebe735cb1cdf5f87ad59608416e2e9e868c5a" - integrity sha512-yZbPb7/5DyL/pXkeOmZ7L5ySpuGr4H48t1cuALjnJy5sXQqmSSAYBiwa6Ya/XpWKX2rJqGDDubmh3nOaopOpeA== - dependencies: - "@types/geojson" "*" - -"@types/d3-hierarchy@^1.1.6": - version "1.1.8" - resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz#50657f420d565a06c0b950a4b82eee0a369f2dea" - integrity sha512-AbStKxNyWiMDQPGDguG2Kuhlq1Sv539pZSxYbx4UZeYkutpPwXCcgyiRrlV4YH64nIOsKx7XVnOMy9O7rJsXkg== - -"@types/d3-interpolate@^1.3.1": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz#88902a205f682773a517612299a44699285eed7b" - integrity sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg== - dependencies: - "@types/d3-color" "^1" - -"@types/d3-path@^1", "@types/d3-path@^1.0.8": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.9.tgz#73526b150d14cd96e701597cbf346cfd1fd4a58c" - integrity sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ== - -"@types/d3-random@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-2.2.1.tgz#551edbb71cb317dea2cf9c76ebe059d311eefacb" - integrity sha512-5vvxn6//poNeOxt1ZwC7QU//dG9QqABjy1T7fP/xmFHY95GnaOw3yABf29hiu5SR1Oo34XcpyHFbzod+vemQjA== - -"@types/d3-scale@^3.3.0": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-3.3.2.tgz#18c94e90f4f1c6b1ee14a70f14bfca2bd1c61d06" - integrity sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ== - dependencies: - "@types/d3-time" "^2" - -"@types/d3-shape@^1.3.1", "@types/d3-shape@^1.3.2": - version "1.3.8" - resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.3.8.tgz#c3c15ec7436b4ce24e38de517586850f1fea8e89" - integrity sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg== - dependencies: - "@types/d3-path" "^1" - -"@types/d3-time@^2", "@types/d3-time@^2.0.0": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-2.1.1.tgz#743fdc821c81f86537cbfece07093ac39b4bc342" - integrity sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg== - -"@types/d3-voronoi@^1.1.9": - version "1.1.9" - resolved "https://registry.yarnpkg.com/@types/d3-voronoi/-/d3-voronoi-1.1.9.tgz#7bbc210818a3a5c5e0bafb051420df206617c9e5" - integrity sha512-DExNQkaHd1F3dFPvGA/Aw2NGyjMln6E9QzsiqOcBgnE+VInYnFBHBBySbZQts6z6xD+5jTfKCP7M4OqMyVjdwQ== - "@types/eslint-scope@^3.7.3": version "3.7.4" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" @@ -1295,11 +1242,6 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== -"@types/geojson@*": - version "7946.0.10" - resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249" - integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA== - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" @@ -1347,10 +1289,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/lodash@^4.14.146", "@types/lodash@^4.14.160": - version "4.14.186" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.186.tgz#862e5514dd7bd66ada6c70ee5fce844b06c8ee97" - integrity sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw== +"@types/lodash@^4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb" + integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg== "@types/node@*": version "22.10.1" @@ -1371,6 +1313,11 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/prismjs@^1.26.0": + version "1.26.5" + resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.26.5.tgz#72499abbb4c4ec9982446509d2f14fb8483869d6" + integrity sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ== + "@types/prop-types@*": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" @@ -1386,7 +1333,7 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.17.tgz#fc560f60946d0aeff2f914eb41679659d3310e1a" integrity sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ== -"@types/react-dom@*", "@types/react-dom@^18": +"@types/react-dom@^18": version "18.3.2" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.2.tgz#b58a9520f5f317a00bbda0271502889b71c345f0" integrity sha512-Fqp+rcvem9wEnGr3RY8dYNvSQ8PoLqjZ9HLgaPUOjJJD120uDyOxOjc/39M4Kddp9JQCxpGQbnhVQF0C0ncYVg== @@ -1400,21 +1347,6 @@ dependencies: "@types/react" "*" -"@types/react-truncate@^2.3.7": - version "2.3.7" - resolved "https://registry.yarnpkg.com/@types/react-truncate/-/react-truncate-2.3.7.tgz#8b394aa2548b5a5a6ee234972403a844451e8a4d" - integrity sha512-gWfw503eLA3Ewx+Imfq7ye1FAllkIhuor4hFQGuE4G3ZHUoc6CITqZerHN8VPBnc26O/MiaDhJKDW4WmBZovZA== - dependencies: - "@types/react" "*" - -"@types/react-virtualized@^9.22.0": - version "9.22.0" - resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.22.0.tgz#2ff9b3692fa04a429df24ffc7d181d9f33b3831d" - integrity sha512-JL/YCCFZ123za//cj10Apk54F0UGFMrjOE0QHTuXt1KBMFrzLOGv9/x6Uc/pZ0Gaf4o6w61Fostvlw0DwuPXig== - dependencies: - "@types/prop-types" "*" - "@types/react" "*" - "@types/react@*", "@types/react@^18": version "18.3.14" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.14.tgz#7ce43bbca0e15e1c4f67ad33ea3f83d75aa6756b" @@ -1576,393 +1508,6 @@ "@typescript-eslint/types" "8.18.0" eslint-visitor-keys "^4.2.0" -"@visx/annotation@1.18.1": - version "1.18.1" - resolved "https://registry.yarnpkg.com/@visx/annotation/-/annotation-1.18.1.tgz#d1d58837b9d1acb1b51d9cc0fb17b9d3f7d222c4" - integrity sha512-z6zCk6PKmmeFziKKMBhJqJG4utg3dDWOCBZdR70HWSt9rl5cTMwIfATCuhJNbE2KuW6+QvTLiMCONySFwuVR+g== - dependencies: - "@types/react" "*" - "@visx/drag" "1.18.1" - "@visx/group" "1.17.1" - "@visx/point" "1.7.0" - "@visx/shape" "1.17.1" - "@visx/text" "1.17.1" - classnames "^2.3.1" - prop-types "^15.5.10" - react-use-measure "^2.0.4" - -"@visx/axis@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/axis/-/axis-1.17.1.tgz#3241ea00c8d9ca522238282617c9ecbd7b9c8eee" - integrity sha512-3JdAY8xwA4xVnzkbXdIzCOWYCknCgw3L185lOJTXWNGO7kIgzbQ2YrLXnet37BFgD83MfxmlP6LhiHLkKVI6OQ== - dependencies: - "@types/react" "*" - "@visx/group" "1.17.1" - "@visx/point" "1.7.0" - "@visx/scale" "1.14.0" - "@visx/shape" "1.17.1" - "@visx/text" "1.17.1" - classnames "^2.3.1" - prop-types "^15.6.0" - -"@visx/bounds@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@visx/bounds/-/bounds-1.7.0.tgz#cc32aaa5aa8711771b93ec4149ff087225dc0684" - integrity sha512-ajF6PTgDoZTfwv5J0ZTx1miXY8lk3sGhMVqE3UsMubdTZBlOgeZMT4OmtTPtbCJTBTgw0FD0gd7X3gZ+3X9HgQ== - dependencies: - "@types/react" "*" - "@types/react-dom" "*" - prop-types "^15.5.10" - -"@visx/brush@1.18.1": - version "1.18.1" - resolved "https://registry.yarnpkg.com/@visx/brush/-/brush-1.18.1.tgz#0a86e0ba2501a5f84024d7ab4c49441fbd40fd8b" - integrity sha512-BSJWVVLU5GCOZGSaon1qh7BcGHrchLQ38SMuXlNhVIdH5ubiLC9J5Pj6l/NQSdQd1cYTD6eNceEiwnxa5TOWrQ== - dependencies: - "@visx/drag" "1.18.1" - "@visx/event" "1.7.0" - "@visx/group" "1.17.1" - "@visx/shape" "1.17.1" - classnames "^2.3.1" - prop-types "^15.6.1" - -"@visx/clip-path@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@visx/clip-path/-/clip-path-1.7.0.tgz#684ea6ae15c877d139c0b8f3cdfacb106c6bf4f9" - integrity sha512-PuEz/2Clmx3qb0gat4kzjoq/rLush1nhNOT1DV7ui/fipC7z+KpB53OXHeOviB4udD+u233W5kY1uSErLysPRQ== - dependencies: - "@types/react" "*" - prop-types "^15.5.10" - -"@visx/curve@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@visx/curve/-/curve-1.7.0.tgz#b8c8ae902de469ae43014c78ed9bfda8aed8137c" - integrity sha512-n0/SHM4YXjke+aEinhHFZPLMxWu3jbqtvqzfGJyibX8OmbDjavk9P+MHfGokUcw0xHy6Ch3YTuwbYuvVw5ny9A== - dependencies: - "@types/d3-shape" "^1.3.1" - d3-shape "^1.0.6" - -"@visx/drag@1.18.1": - version "1.18.1" - resolved "https://registry.yarnpkg.com/@visx/drag/-/drag-1.18.1.tgz#0a3aa7f338dcf967e75bcc99dc5f774e8ac37439" - integrity sha512-5xsgUUthG/0Nq51HFWYIe3NaHT5csxuVqx/+VfNsjkGgCHntWkcS2soPlEMh4wUT2iPKRs9z9VtRAyrpN4TtKw== - dependencies: - "@types/react" "*" - "@visx/event" "1.7.0" - prop-types "^15.5.10" - -"@visx/event@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@visx/event/-/event-1.7.0.tgz#76a1e726dfb72f33dffb957fd7e0c49488f426fe" - integrity sha512-RbAoKxvy+ildX2dVXC9/ZX94lQXPwjKgtO9jy7COc15knG4zmzsMCDYDC3uLd0+jE2o/+gSaZ/9r52p6zG5+IQ== - dependencies: - "@types/react" "*" - "@visx/point" "1.7.0" - -"@visx/geo@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/geo/-/geo-1.17.1.tgz#56a4eb559b1b2f86c340969abe0ad8d17e9dd2c9" - integrity sha512-59gDV5qQc9lrhypvVxv5kETs5rqdcTngHUOGzxslerHZb9ESQylFuhhc6q16EOWNZr7io4mSujoJzK/DcurhUw== - dependencies: - "@types/d3-geo" "^1.11.1" - "@types/geojson" "*" - "@types/react" "*" - "@visx/group" "1.17.1" - classnames "^2.3.1" - d3-geo "^1.11.3" - prop-types "^15.5.10" - -"@visx/glyph@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/glyph/-/glyph-1.17.1.tgz#9b98b1fddaf91075026acfa9caaa04145ec0f552" - integrity sha512-9KAPmO7DsH1Iq+2kZs8oTgirgYWRq7EacNyEtsq78uuHqw0gFqmOuyYV6+iHelLbulNCAzHKVAZ7Aebfy7G8ZA== - dependencies: - "@types/d3-shape" "^1.3.1" - "@types/react" "*" - "@visx/group" "1.17.1" - classnames "^2.3.1" - d3-shape "^1.2.0" - prop-types "^15.6.2" - -"@visx/gradient@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@visx/gradient/-/gradient-1.7.0.tgz#0578d27ef01204f36ce73db208141976d218adc4" - integrity sha512-KtlzpgY+1tEIxEhFwyGp7nVwDjaPs9bcLO5Wkm3uw5ehQtRMYQBC3O2N+GEKdQM2yNZVApvtSMiXQDxGTFK67g== - dependencies: - "@types/react" "*" - prop-types "^15.5.7" - -"@visx/grid@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/grid/-/grid-1.17.1.tgz#625e69dc99f9b0a5bac04bc8ad7c6fa2352d99ab" - integrity sha512-dse9q3weDqPNmeXK0lGKKPRgGiDuUjJ7Mt7NNonPUyXPctNmv6lJEWZu9HJrXEGiCAVNa8PHJ7Qkns/z+mH88Q== - dependencies: - "@types/react" "*" - "@visx/curve" "1.7.0" - "@visx/group" "1.17.1" - "@visx/point" "1.7.0" - "@visx/scale" "1.14.0" - "@visx/shape" "1.17.1" - classnames "^2.3.1" - prop-types "^15.6.2" - -"@visx/group@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/group/-/group-1.17.1.tgz#23818d3233511dc2360de4febc2a3ecd43c3c9d0" - integrity sha512-g8pSqy8TXAisiOzypnVycDynEGlBhfxtVlwDmsbYB+XSFGEjnOheQSDohDI+ia7ek54Mw9uYe05tx5kP1hRMYw== - dependencies: - "@types/react" "*" - classnames "^2.3.1" - prop-types "^15.6.2" - -"@visx/heatmap@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/heatmap/-/heatmap-1.17.1.tgz#60c8a16ffffd60bbcd2b1e4ed0fc894fcf4b96d7" - integrity sha512-pSyConA9zoK9NwO2XAyIYZJQ3K+1zjF1P5MQ4Az9DZkFeL02Kp2puXTlBg/5ohpvWMRjpUmyPxxjnE7B2paEPQ== - dependencies: - "@types/react" "*" - "@visx/group" "1.17.1" - classnames "^2.3.1" - prop-types "^15.6.1" - -"@visx/hierarchy@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/hierarchy/-/hierarchy-1.17.1.tgz#09fa16498ad6ddc4d18733accf54277b14112ece" - integrity sha512-8Z0hzKs+3Td1eGh0lvg76d3hwH1WG69OD7p5uH1qxnYezypu9v0y9Mp9qbxkDUR0kcAvyYwJ0oXXCARNP4z6ZQ== - dependencies: - "@types/d3-hierarchy" "^1.1.6" - "@types/react" "*" - "@visx/group" "1.17.1" - classnames "^2.3.1" - d3-hierarchy "^1.1.4" - prop-types "^15.6.1" - -"@visx/legend@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/legend/-/legend-1.17.1.tgz#3908321da90f3a30d3608cc572a6c13b34a3298b" - integrity sha512-vdB3EPHXYwTyS4g2MB/sVAvq6ddeyzjlTjsM6YNc6Nagwb4uTOuMeKT+t0jgLJejNMOcY7Q8eBjDDWAdiPNV1A== - dependencies: - "@types/react" "*" - "@visx/group" "1.17.1" - "@visx/scale" "1.14.0" - classnames "^2.3.1" - prop-types "^15.5.10" - -"@visx/marker@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/marker/-/marker-1.17.1.tgz#5112d94b17f742bed0ddff70b45cec137c926906" - integrity sha512-7EimyHTaKHCHmaVBbGOl+KAp22M1rooR4N9wCGd9lJX85/KD+kPpx9bsN6Qeru1fQcZcER+7Qp7ra7zhxH1Qng== - dependencies: - "@types/react" "*" - "@visx/group" "1.17.1" - "@visx/shape" "1.17.1" - classnames "^2.3.1" - prop-types "^15.6.2" - -"@visx/mock-data@1.7.0", "@visx/mock-data@^1.0.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@visx/mock-data/-/mock-data-1.7.0.tgz#b56e30604ab0e775ada741cb96e6c9c1eaaac56d" - integrity sha512-v7DGro/4q382ReSWmPCKdRR1AtNUp9ERM129omMaTcf52i8RbSYNfMdxucMaEBIbATI905vYqQKA8S6xopPupQ== - dependencies: - "@types/d3-random" "^2.2.0" - d3-random "^2.2.2" - -"@visx/network@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/network/-/network-1.17.1.tgz#4353c7e8ce89c2e1c4f61eed2669157ffbe968ad" - integrity sha512-PDoKf7DUEzAF1w2IQlWiv0/Ba02fU4XcbWvtcH+8UDsQW5jT0dcaA/fjXYWUjK/ompXUVwINZXKN18IF98/eig== - dependencies: - "@types/react" "*" - "@visx/group" "1.17.1" - classnames "^2.3.1" - prop-types "^15.6.2" - -"@visx/pattern@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/pattern/-/pattern-1.17.1.tgz#2be0b35584eaedfa0e4cdbf7fd7ae036480805ac" - integrity sha512-lPlkSHr9a/+3je6D35mIq6tNZ0BBWU5FExX0EroNRYPl9KxKtQv4C8PlAiTdmMuAXwYLnxls04y5iHwDRXH6Cw== - dependencies: - "@types/react" "*" - classnames "^2.3.1" - prop-types "^15.5.10" - -"@visx/point@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@visx/point/-/point-1.7.0.tgz#1df3c3425eae464f498473bcdda2fcae05c8ecbe" - integrity sha512-oaoY/HXYHhmpkkeKI4rBPmFtjHWtxSrIhZCVm1ipPoyQp3voJ8L6JD5eUIVmmaUCdUGUGwL1lFLnJiQ2p1Vlwg== - -"@visx/react-spring@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/react-spring/-/react-spring-1.17.1.tgz#3efcb6df4e1b1f45c86a8e407664cf444e80a755" - integrity sha512-U2+cXYpmuwN8/TNNJAiqAcXHPewKbb2vT+YmDmkIk9G20INO95EKJbHE5+homf+Jg7mRr5En31Orxjt6eIKgzA== - dependencies: - "@types/react" "*" - "@visx/axis" "1.17.1" - "@visx/grid" "1.17.1" - "@visx/scale" "1.14.0" - "@visx/text" "1.17.1" - classnames "^2.3.1" - prop-types "^15.6.2" - -"@visx/responsive@1.10.1": - version "1.10.1" - resolved "https://registry.yarnpkg.com/@visx/responsive/-/responsive-1.10.1.tgz#87c6ec030e6817aae90a588a155ea86159b098dd" - integrity sha512-7FT2BBmWFkFFqynI9C1NYfVOKT1FsNOm6MwWMqXKA7TMomdBW0wdtQNB1bHvwJvWurM/sNqxcQ/CBED6t9xujQ== - dependencies: - "@types/lodash" "^4.14.146" - "@types/react" "*" - lodash "^4.17.10" - prop-types "^15.6.1" - resize-observer-polyfill "1.5.1" - -"@visx/scale@1.14.0": - version "1.14.0" - resolved "https://registry.yarnpkg.com/@visx/scale/-/scale-1.14.0.tgz#622d274ec4f5e608de29d06cd6071892bb1e7587" - integrity sha512-ovbtEOF/d76uGMJ5UZlxdS3t2T8I6md+aIwOXBaq0HdjaCLbe7HLlMyHJKjak/sqBxLAiCGVnechTUpSkfgSQw== - dependencies: - "@types/d3-interpolate" "^1.3.1" - "@types/d3-scale" "^3.3.0" - "@types/d3-time" "^2.0.0" - d3-interpolate "^1.4.0" - d3-scale "^3.3.0" - d3-time "^2.1.1" - -"@visx/shape@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/shape/-/shape-1.17.1.tgz#c5d83b955d2e94f39002ff986550944e24ff660a" - integrity sha512-rVYFpytPCnV4s5U0za+jQ2jqFzKnmB3c8RP6fuOfF6kKosFPJcOYg9ikvewojARyMBTr1u3XvWV960Da+xyUdQ== - dependencies: - "@types/d3-path" "^1.0.8" - "@types/d3-shape" "^1.3.1" - "@types/lodash" "^4.14.146" - "@types/react" "*" - "@visx/curve" "1.7.0" - "@visx/group" "1.17.1" - "@visx/scale" "1.14.0" - classnames "^2.3.1" - d3-path "^1.0.5" - d3-shape "^1.2.0" - lodash "^4.17.15" - prop-types "^15.5.10" - -"@visx/stats@^1.4.0": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/stats/-/stats-1.17.1.tgz#f09f784bd2f26db8614fada9b04c73f6de3f4e29" - integrity sha512-MWbTr0jlFKSwjjHWrfeDA4CseHOI8lkD57OoO3Zy0q0bvL5h11GS5GMNNESWeOoxfLgNNlpK32y/k1SlUurjeg== - dependencies: - "@types/d3-shape" "^1.3.2" - "@types/react" "*" - "@visx/group" "1.17.1" - "@visx/scale" "1.14.0" - classnames "^2.3.1" - d3-shape "^1.2.0" - prop-types "^15.5.10" - -"@visx/text@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/text/-/text-1.17.1.tgz#e9ba06ab58bf4c347c9f25ecb29f78f296132045" - integrity sha512-Cx6iH0kVq3YqCfFj7U6bMiKwa/bz4Z3q0vPdxmnVGcPjGZM1ac/y61KFH263e164LJ5jFaTYpPrrFmbZoy8+Vg== - dependencies: - "@types/lodash" "^4.14.160" - "@types/react" "*" - classnames "^2.3.1" - lodash "^4.17.20" - prop-types "^15.7.2" - reduce-css-calc "^1.3.0" - -"@visx/tooltip@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/tooltip/-/tooltip-1.17.1.tgz#6023f675384d9fe70e7c13b0959b00b9c38e9a48" - integrity sha512-YfRgVtKSLTn3iW8CT5+CfTWhSXGeAp01SaPDThtdaUTx89rKv5wb4oyVgeQ5g2ScRYVC8mYj5RzY/pj3RrezFQ== - dependencies: - "@types/react" "*" - "@visx/bounds" "1.7.0" - classnames "^2.3.1" - prop-types "^15.5.10" - react-use-measure "^2.0.4" - -"@visx/visx@^1.4.0": - version "1.18.1" - resolved "https://registry.yarnpkg.com/@visx/visx/-/visx-1.18.1.tgz#86ca594af60ddf73bd69e59ba872959825799892" - integrity sha512-B6hC3l0+DMTNOxuot+D0M5rQAp972f0QjHHgU6/SwGh1S3w8/WeR+3LqYg86B7i47CrdNRgZCMRQMhgkYjfKXA== - dependencies: - "@visx/annotation" "1.18.1" - "@visx/axis" "1.17.1" - "@visx/bounds" "1.7.0" - "@visx/brush" "1.18.1" - "@visx/clip-path" "1.7.0" - "@visx/curve" "1.7.0" - "@visx/drag" "1.18.1" - "@visx/event" "1.7.0" - "@visx/geo" "1.17.1" - "@visx/glyph" "1.17.1" - "@visx/gradient" "1.7.0" - "@visx/grid" "1.17.1" - "@visx/group" "1.17.1" - "@visx/heatmap" "1.17.1" - "@visx/hierarchy" "1.17.1" - "@visx/legend" "1.17.1" - "@visx/marker" "1.17.1" - "@visx/mock-data" "1.7.0" - "@visx/network" "1.17.1" - "@visx/pattern" "1.17.1" - "@visx/point" "1.7.0" - "@visx/responsive" "1.10.1" - "@visx/scale" "1.14.0" - "@visx/shape" "1.17.1" - "@visx/text" "1.17.1" - "@visx/tooltip" "1.17.1" - "@visx/voronoi" "1.17.1" - "@visx/xychart" "1.18.1" - "@visx/zoom" "1.14.1" - -"@visx/voronoi@1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@visx/voronoi/-/voronoi-1.17.1.tgz#de8413d00b700fcd6f51117923d450184883c90b" - integrity sha512-XpgQ5siRYI9Vvw+Q82avIntDzfkSrIT3EmN2J/L/6ZnT3nTCjWksTEgQQ3G9GqoX510srbX8wL+mRqkYP+3O4Q== - dependencies: - "@types/d3-voronoi" "^1.1.9" - "@types/react" "*" - classnames "^2.3.1" - d3-voronoi "^1.1.2" - prop-types "^15.6.1" - -"@visx/xychart@1.18.1": - version "1.18.1" - resolved "https://registry.yarnpkg.com/@visx/xychart/-/xychart-1.18.1.tgz#1779b04c6e963569c3e22bff2b762991ebdacdc3" - integrity sha512-VyC7yBpLUSgzLZIWWRtf1pCP0xuYLjHEwAXl2LdCSrnyUs2pMTms7xMUNbq8uwR4e8bbBY5dbsRg/7X95tB8Yg== - dependencies: - "@types/lodash" "^4.14.146" - "@types/react" "*" - "@visx/annotation" "1.18.1" - "@visx/axis" "1.17.1" - "@visx/event" "1.7.0" - "@visx/glyph" "1.17.1" - "@visx/grid" "1.17.1" - "@visx/react-spring" "1.17.1" - "@visx/responsive" "1.10.1" - "@visx/scale" "1.14.0" - "@visx/shape" "1.17.1" - "@visx/text" "1.17.1" - "@visx/tooltip" "1.17.1" - "@visx/voronoi" "1.17.1" - classnames "^2.3.1" - d3-array "^2.6.0" - d3-interpolate-path "2.2.1" - d3-shape "^2.0.0" - lodash "^4.17.10" - mitt "^2.1.0" - prop-types "^15.6.2" - -"@visx/zoom@1.14.1": - version "1.14.1" - resolved "https://registry.yarnpkg.com/@visx/zoom/-/zoom-1.14.1.tgz#9b9a2e9258fdd97be02c7f10e7968486aa996a13" - integrity sha512-ifuN7Hhm/azlta8rrh4+t7cEhxCgvy2j+nOeEogTXPZMy8qp76t8Dz7BGIT1lx5lN1kRpKdj9ApZeVdIhzeTQQ== - dependencies: - "@types/react" "*" - "@visx/event" "1.7.0" - prop-types "^15.6.2" - "@vitejs/plugin-react@^4.3.4": version "4.3.4" resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz#c64be10b54c4640135a5b28a2432330e88ad7c20" @@ -2375,11 +1920,6 @@ babel-plugin-macros@^3.1.0: cosmiconfig "^7.0.0" resolve "^1.19.0" -balanced-match@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - integrity sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -2537,17 +2077,12 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -classnames@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" - integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== - -clsx@^1.0.4, clsx@^1.1.0: +clsx@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== -clsx@^2.1.1: +clsx@^2.0.0, clsx@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== @@ -2650,123 +2185,6 @@ csstype@^3.1.3: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -d3-array@1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" - integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== - -d3-array@2, d3-array@^2.3.0, d3-array@^2.6.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" - integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== - dependencies: - internmap "^1.0.0" - -d3-color@1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" - integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== - -"d3-color@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" - integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== - -"d3-format@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767" - integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== - -d3-geo@^1.11.3: - version "1.12.1" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f" - integrity sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg== - dependencies: - d3-array "1" - -d3-hierarchy@^1.1.4: - version "1.1.9" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83" - integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ== - -d3-interpolate-path@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/d3-interpolate-path/-/d3-interpolate-path-2.2.1.tgz#fd8ff20a90aff3f380bcd1c15305e7b531e55d07" - integrity sha512-6qLLh/KJVzls0XtMsMpcxhqMhgVEN7VIbR/6YGZe2qlS8KDgyyVB20XcmGnDyB051HcefQXM/Tppa9vcANEA4Q== - -"d3-interpolate@1.2.0 - 2": - version "2.0.1" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" - integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== - dependencies: - d3-color "1 - 2" - -d3-interpolate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987" - integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA== - dependencies: - d3-color "1" - -d3-path@1, d3-path@^1.0.5: - version "1.0.9" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" - integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== - -"d3-path@1 - 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-2.0.0.tgz#55d86ac131a0548adae241eebfb56b4582dd09d8" - integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA== - -d3-random@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-2.2.2.tgz#5eebd209ef4e45a2b362b019c1fb21c2c98cbb6e" - integrity sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw== - -d3-scale@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3" - integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ== - dependencies: - d3-array "^2.3.0" - d3-format "1 - 2" - d3-interpolate "1.2.0 - 2" - d3-time "^2.1.1" - d3-time-format "2 - 3" - -d3-shape@^1.0.6, d3-shape@^1.2.0: - version "1.3.7" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" - integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== - dependencies: - d3-path "1" - -d3-shape@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-2.1.0.tgz#3b6a82ccafbc45de55b57fcf956c584ded3b666f" - integrity sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA== - dependencies: - d3-path "1 - 2" - -"d3-time-format@2 - 3": - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6" - integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== - dependencies: - d3-time "1 - 2" - -"d3-time@1 - 2", d3-time@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682" - integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== - dependencies: - d3-array "2" - -d3-voronoi@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" - integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg== - data-urls@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" @@ -2812,11 +2230,6 @@ date-fns@^2.29.3: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== -debounce@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - debug@4, debug@^4.3.1, debug@^4.3.7: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" @@ -2916,7 +2329,7 @@ dom-accessibility-api@^0.6.3: resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz#993e925cc1d73f2c662e7d75dd5a5445259a8fd8" integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w== -dom-helpers@^5.0.1, dom-helpers@^5.1.3: +dom-helpers@^5.0.1: version "5.2.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== @@ -3861,11 +3274,6 @@ internal-slot@^1.0.7, internal-slot@^1.1.0: hasown "^2.0.2" side-channel "^1.1.0" -internmap@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" - integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== - is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -4343,7 +3751,7 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: +lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4379,11 +3787,6 @@ magic-string@^0.30.12: dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" -math-expression-evaluator@^1.2.14: - version "1.4.0" - resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz#3d66031117fbb7b9715ea6c9c68c2cd2eebd37e2" - integrity sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw== - math-intrinsics@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.0.0.tgz#4e04bf87c85aa51e90d078dac2252b4eb5260817" @@ -4443,11 +3846,6 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== -mitt@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230" - integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -4725,7 +4123,20 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prism-react-renderer@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz#ac63b7f78e56c8f2b5e76e823a976d5ede77e35f" + integrity sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig== + dependencies: + "@types/prismjs" "^1.26.0" + clsx "^2.0.0" + +prismjs@^1.29.0: + version "1.29.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" + integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== + +prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -4806,11 +4217,6 @@ react-is@^18.0.0, react-is@^18.3.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - react-refresh@^0.14.2: version "0.14.2" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" @@ -4841,30 +4247,6 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react-truncate@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/react-truncate/-/react-truncate-2.4.0.tgz#3cf5ff09ab86f93e3c078d359f4de6d75aa60510" - integrity sha512-3QW11/COYwi6iPUaunUhl06DW5NJBJD1WkmxW5YxqqUu6kvP+msB3jfoLg8WRbu57JqgebjVW8Lknw6T5/QZdA== - -react-use-measure@^2.0.4: - version "2.1.1" - resolved "https://registry.yarnpkg.com/react-use-measure/-/react-use-measure-2.1.1.tgz#5824537f4ee01c9469c45d5f7a8446177c6cc4ba" - integrity sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig== - dependencies: - debounce "^1.2.1" - -react-virtualized@^9.22.5: - version "9.22.5" - resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.5.tgz#bfb96fed519de378b50d8c0064b92994b3b91620" - integrity sha512-YqQMRzlVANBv1L/7r63OHa2b0ZsAaDp1UhVNEdUaXI8A5u6hTpA5NYtUueLH2rFuY/27mTGIBl7ZhqFKzw18YQ== - dependencies: - "@babel/runtime" "^7.7.2" - clsx "^1.0.4" - dom-helpers "^5.1.3" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-lifecycles-compat "^3.0.4" - react@^18: version "18.3.1" resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" @@ -4880,22 +4262,6 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -reduce-css-calc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" - integrity sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA== - dependencies: - balanced-match "^0.4.2" - math-expression-evaluator "^1.2.14" - reduce-function-call "^1.0.1" - -reduce-function-call@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.3.tgz#60350f7fb252c0a67eb10fd4694d16909971300f" - integrity sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ== - dependencies: - balanced-match "^1.0.0" - reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz#c58afb17a4007b4d1118c07b92c23fca422c5d82" @@ -4944,11 +4310,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -resize-observer-polyfill@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" - integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"