From 561e80264b0a9df86f5ce1e1a5a388bb53d11bc6 Mon Sep 17 00:00:00 2001 From: Stephen Smith Date: Mon, 1 Apr 2024 21:06:33 -0400 Subject: [PATCH] 21508: Add virtual list to io panel and styles to make sizing behave Arvados-DCO-1.1-Signed-off-by: Stephen Smith --- .../views/process-panel/process-io-card.tsx | 178 ++++++++++++------ 1 file changed, 116 insertions(+), 62 deletions(-) diff --git a/services/workbench2/src/views/process-panel/process-io-card.tsx b/services/workbench2/src/views/process-panel/process-io-card.tsx index 7a39af6fe1..a12d9918da 100644 --- a/services/workbench2/src/views/process-panel/process-io-card.tsx +++ b/services/workbench2/src/views/process-panel/process-io-card.tsx @@ -67,6 +67,8 @@ import { navigateTo } from "store/navigation/navigation-action"; import classNames from "classnames"; import { DefaultCodeSnippet } from "components/default-code-snippet/default-code-snippet"; import { KEEP_URL_REGEX } from "models/resource"; +import { FixedSizeList } from 'react-window'; +import AutoSizer from "react-virtualized-auto-sizer"; type CssRules = | "card" @@ -76,22 +78,17 @@ type CssRules = | "avatar" | "iconHeader" | "tableWrapper" - | "paramValue" | "paramTableRoot" | "mountsTableRoot" + | "rowStyles" + | "valueWrapper" + | "value" | "keepLink" | "collectionLink" - | "imagePreview" - | "valArray" | "secondaryVal" - | "secondaryRow" | "emptyValue" | "noBorderRow" - | "symmetricTabs" - | "imagePlaceholder" - | "rowWithPreview" - | "labelColumn" - | "primaryRow"; + | "symmetricTabs"; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ card: { @@ -127,15 +124,44 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ height: "auto", maxHeight: `calc(100% - ${theme.spacing.unit * 3}px)`, overflow: "auto", + // Use flexbox to keep scrolling at the virtual list level + display: "flex", + flexDirection: "column", + alignItems: "start", // Prevents scroll bars at different levels in json tab }, paramTableRoot: { - width: "100%", - "& thead th": { - verticalAlign: "bottom", - paddingBottom: "10px", + display: "flex", + flexDirection: "column", + overflow: "hidden", + + "& thead tr": { + alignItems: "end", + "& th": { + padding: "4px 25px 10px", + }, }, - "& td, & th": { - paddingRight: "25px", + "& tbody": { + height: "100vh", // Must be constrained by panel maxHeight + }, + "& thead tr, & > tbody tr": { + display: "flex", + "& th, & td": { + flexGrow: 1, + flexShrink: 1, + flexBasis: 0, + overflow: "hidden", + }, + "& th:nth-last-of-type(1), & td:nth-last-of-type(1)": { + flexGrow: 2, + }, + }, + "& > tbody tr td": { + padding: "4px 25px 4px", + overflow: "auto hidden", + display: "flex", + flexDirection: "row", + alignItems: "center", + whiteSpace: "nowrap", }, }, mountsTableRoot: { @@ -148,17 +174,42 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ paddingRight: "25px", }, }, - paramValue: { + rowStyles: { + height: "40px", + "& td": { + paddingTop: "2px", + paddingBottom: "2px", + }, + }, + valueWrapper: { display: "flex", - alignItems: "flex-start", - flexDirection: "column", + alignItems: "center", + flexDirection: "row", + height: "100%", + overflow: "hidden", '& pre': { margin: 0, }, }, + value: { + display: "flex", + gap: "10px", + flexWrap: "wrap", + maxWidth: "100%", + maxHeight: "100%", + whiteSpace: "nowrap", + "& span": { + display: "inline", + }, + "& a, & pre": { + overflow: "hidden", + textOverflow: "ellipsis", + }, + }, keepLink: { color: theme.palette.primary.main, textDecoration: "none", + // Overflow wrap for mounts table overflowWrap: "break-word", cursor: "pointer", }, @@ -171,28 +222,9 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ cursor: "pointer", }, }, - imagePreview: { - maxHeight: "15em", - maxWidth: "15em", - marginBottom: theme.spacing.unit, - }, - valArray: { - display: "flex", - gap: "10px", - flexWrap: "wrap", - "& span": { - display: "inline", - }, - }, secondaryVal: { paddingLeft: "20px", }, - secondaryRow: { - height: "24px", - verticalAlign: "top", - position: "relative", - top: "-4px", - }, emptyValue: { color: theme.customs.colors.grey700, }, @@ -209,28 +241,6 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ flexBasis: "0", }, }, - imagePlaceholder: { - width: "60px", - height: "60px", - display: "flex", - alignItems: "center", - justifyContent: "center", - backgroundColor: "#cecece", - borderRadius: "10px", - }, - rowWithPreview: { - verticalAlign: "bottom", - }, - labelColumn: { - minWidth: "120px", - }, - primaryRow: { - height: "26px", - "& td": { - paddingTop: "2px", - paddingBottom: "2px", - }, - }, }); export enum ProcessIOCardType { @@ -557,6 +567,38 @@ type ProcessIOPreviewProps = ProcessIOPreviewDataProps & WithStyles; const ProcessIOPreview = memo( withStyles(styles)(({ classes, data, showImagePreview, valueLabel }: ProcessIOPreviewProps) => { const showLabel = data.some((param: ProcessIOParameter) => param.label); + + const hasMoreValues = (index: number) => ( + data[index+1] && !(data[index+1].id || data[index+1].label) + ); + + const RenderRow = ({index, style}) => { + const param = data[index]; + + const rowClasses = { + [classes.noBorderRow]: hasMoreValues(index), + [classes.rowStyles]: true, + }; + + return + {param.id} + {showLabel && {param.label}} + + + + + + + {param.value.collection} + + + + ; + }; + return ( Name - {showLabel && Label} + {showLabel && Label} {valueLabel} Collection + + {({ height, width }) => + + {RenderRow} + + } +
); @@ -583,8 +637,8 @@ interface ProcessValuePreviewProps { } const ProcessValuePreview = withStyles(styles)(({ value, showImagePreview, classes }: ProcessValuePreviewProps & WithStyles) => ( - - {value.display} + + {value.display} )); -- 2.30.2