X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/1f8dc0fa14b8095203638f27d36d548c8568152b..9a72938d7fa4786aed241f619476490570933f15:/services/workbench2/src/views/process-panel/process-io-card.tsx 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 a6086c6c57..8df4a5e678 100644 --- a/services/workbench2/src/views/process-panel/process-io-card.tsx +++ b/services/workbench2/src/views/process-panel/process-io-card.tsx @@ -65,10 +65,11 @@ import { ProcessOutputCollectionFiles } from "./process-output-collection-files" import { Process } from "store/processes/process"; import { navigateTo } from "store/navigation/navigation-action"; import classNames from "classnames"; -import { DefaultCodeSnippet } from "components/default-code-snippet/default-code-snippet"; +import { DefaultVirtualCodeSnippet } from "components/default-code-snippet/default-virtual-code-snippet"; import { KEEP_URL_REGEX } from "models/resource"; import { FixedSizeList } from 'react-window'; import AutoSizer from "react-virtualized-auto-sizer"; +import { LinkProps } from "@material-ui/core/Link"; type CssRules = | "card" @@ -79,14 +80,16 @@ type CssRules = | "iconHeader" | "tableWrapper" | "paramTableRoot" + | "paramTableCellText" | "mountsTableRoot" - | "value" + | "jsonWrapper" | "keepLink" | "collectionLink" | "secondaryVal" | "emptyValue" | "noBorderRow" - | "symmetricTabs"; + | "symmetricTabs" + | "wrapTooltip"; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ card: { @@ -106,7 +109,7 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ }, // Card content content: { - height: `calc(100% - ${theme.spacing.unit * 7}px - ${theme.spacing.unit * 1.5}px)`, + height: `calc(100% - ${theme.spacing.unit * 6}px)`, padding: theme.spacing.unit * 1.0, paddingTop: 0, "&:last-child": { @@ -120,10 +123,10 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ color: theme.customs.colors.greyD, fontSize: "1.875rem", }, - // Applies to each tab's content + // Applies to table tab's content tableWrapper: { height: "auto", - maxHeight: `calc(100% - ${theme.spacing.unit * 3}px)`, + maxHeight: `calc(100% - ${theme.spacing.unit * 6}px)`, overflow: "auto", // Use flexbox to keep scrolling at the virtual list level display: "flex", @@ -157,6 +160,9 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ overflow: "hidden", }, // Column width overrides + "& th:nth-of-type(1), & td:nth-of-type(1)": { + flexGrow: 0.7, + }, "& th:nth-last-of-type(1), & td:nth-last-of-type(1)": { flexGrow: 2, }, @@ -172,14 +178,25 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ flexDirection: "row", alignItems: "center", whiteSpace: "nowrap", - '& pre': { - margin: 0, - overflow: "hidden", - textOverflow: "ellipsis", - }, }, }, }, + // Param value cell typography styles + paramTableCellText: { + overflow: "hidden", + display: "flex", + // Every cell contents requires a wrapper for the ellipsis + // since adding ellipses to an anchor element parent results in misaligned tooltip + "& a, & span": { + overflow: "hidden", + textOverflow: "ellipsis", + }, + '& pre': { + margin: 0, + overflow: "hidden", + textOverflow: "ellipsis", + }, + }, mountsTableRoot: { width: "100%", "& thead th": { @@ -190,12 +207,9 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ paddingRight: "25px", }, }, - // Cell typography styles - value: { - maxWidth: "100%", - whiteSpace: "nowrap", - overflow: "hidden", - textOverflow: "ellipsis", + // JSON tab wrapper + jsonWrapper: { + height: `calc(100% - ${theme.spacing.unit * 6}px)`, }, keepLink: { color: theme.palette.primary.main, @@ -233,6 +247,10 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ flexBasis: "0", }, }, + wrapTooltip: { + maxWidth: "600px", + wordWrap: "break-word", + }, }); export enum ProcessIOCardType { @@ -405,7 +423,7 @@ export const ProcessIOCard = withStyles(styles)( )} {(mainProcTabState === 1 || !hasParams) && ( -
+
)} @@ -492,7 +510,7 @@ export const ProcessIOCard = withStyles(styles)( )} {isRawLoaded && (subProcTabState === 1 || (!hasInputMounts && !hasOutputCollecton)) && ( -
+
)} @@ -542,7 +560,13 @@ const ProcessIOPreview = memo( const showLabel = data.some((param: ProcessIOParameter) => param.label); const hasMoreValues = (index: number) => ( - data[index+1] && !(data[index+1].id || data[index+1].label) + data[index+1] && !isMainRow(data[index+1]) + ); + + const isMainRow = (param: ProcessIOParameter) => ( + param && + ((param.id || param.label) && + !param.value.secondary) ); const RenderRow = ({index, style}) => { @@ -552,16 +576,27 @@ const ProcessIOPreview = memo( [classes.noBorderRow]: hasMoreValues(index), }; - return + return - - {param.id} - + + + + {param.id} + + + {showLabel && - - {param.label} - + + + + {param.label} + + + } - + + {/** Collection is an anchor so doesn't require wrapper element */} {param.value.collection} @@ -613,7 +649,7 @@ interface ProcessValuePreviewProps { } const ProcessValuePreview = withStyles(styles)(({ value, classes }: ProcessValuePreviewProps & WithStyles) => ( - + {value.display} )); @@ -623,9 +659,9 @@ interface ProcessIORawDataProps { } const ProcessIORaw = withStyles(styles)(({ data }: ProcessIORawDataProps) => ( - - + @@ -681,7 +717,7 @@ export const getIOParamDisplayValue = (auth: AuthState, input: CommandInputParam case isPrimitiveOfType(input, CWLType.BOOLEAN): const boolValue = (input as BooleanCommandInputParameter).value; return boolValue !== undefined && !(Array.isArray(boolValue) && boolValue.length === 0) - ? [{ display: renderPrimitiveValue(boolValue, false) }] + ? [{ display: {renderPrimitiveValue(boolValue, false)} }] : [{ display: }]; case isPrimitiveOfType(input, CWLType.INT): @@ -690,20 +726,20 @@ export const getIOParamDisplayValue = (auth: AuthState, input: CommandInputParam return intValue !== undefined && // Missing values are empty array !(Array.isArray(intValue) && intValue.length === 0) - ? [{ display: renderPrimitiveValue(intValue, false) }] + ? [{ display: {renderPrimitiveValue(intValue, false)} }] : [{ display: }]; case isPrimitiveOfType(input, CWLType.FLOAT): case isPrimitiveOfType(input, CWLType.DOUBLE): const floatValue = (input as FloatCommandInputParameter).value; return floatValue !== undefined && !(Array.isArray(floatValue) && floatValue.length === 0) - ? [{ display: renderPrimitiveValue(floatValue, false) }] + ? [{ display: {renderPrimitiveValue(floatValue, false)} }] : [{ display: }]; case isPrimitiveOfType(input, CWLType.STRING): const stringValue = (input as StringCommandInputParameter).value || undefined; return stringValue !== undefined && !(Array.isArray(stringValue) && stringValue.length === 0) - ? [{ display: renderPrimitiveValue(stringValue, false) }] + ? [{ display: {renderPrimitiveValue(stringValue, false)} }] : [{ display: }]; case isPrimitiveOfType(input, CWLType.FILE): @@ -724,21 +760,21 @@ export const getIOParamDisplayValue = (auth: AuthState, input: CommandInputParam case getEnumType(input) !== null: const enumValue = (input as EnumCommandInputParameter).value; - return enumValue !== undefined && enumValue ? [{ display:
{enumValue}
}] : [{ display: }]; + return enumValue !== undefined && enumValue ? [{ display: {enumValue} }] : [{ display: }]; case isArrayOfType(input, CWLType.STRING): const strArray = (input as StringArrayCommandInputParameter).value || []; - return strArray.length ? [{ display: <>{strArray.map(val => renderPrimitiveValue(val, true))} }] : [{ display: }]; + return strArray.length ? [{ display: {strArray.map(val => renderPrimitiveValue(val, true))} }] : [{ display: }]; case isArrayOfType(input, CWLType.INT): case isArrayOfType(input, CWLType.LONG): const intArray = (input as IntArrayCommandInputParameter).value || []; - return intArray.length ? [{ display: <>{intArray.map(val => renderPrimitiveValue(val, true))} }] : [{ display: }]; + return intArray.length ? [{ display: {intArray.map(val => renderPrimitiveValue(val, true))} }] : [{ display: }]; case isArrayOfType(input, CWLType.FLOAT): case isArrayOfType(input, CWLType.DOUBLE): const floatArray = (input as FloatArrayCommandInputParameter).value || []; - return floatArray.length ? [{ display: <>{floatArray.map(val => renderPrimitiveValue(val, true))} }] : [{ display: }]; + return floatArray.length ? [{ display: {floatArray.map(val => renderPrimitiveValue(val, true))} }] : [{ display: }]; case isArrayOfType(input, CWLType.FILE): const fileArrayMainFiles = (input as FileArrayCommandInputParameter).value || []; @@ -766,6 +802,27 @@ export const getIOParamDisplayValue = (auth: AuthState, input: CommandInputParam } }; +interface PrimitiveTooltipProps { + data: boolean | number | string; +} + +const PrimitiveTooltip = (props: React.PropsWithChildren) => ( + +
{props.children}
+
+); + +interface PrimitiveArrayTooltipProps { + data: string[]; +} + +const PrimitiveArrayTooltip = (props: React.PropsWithChildren) => ( + + {props.children} + +); + + const renderPrimitiveValue = (value: any, asChip: boolean) => { const isObject = typeof value === "object"; if (!isObject) { @@ -776,7 +833,7 @@ const renderPrimitiveValue = (value: any, asChip: boolean) => { style={{marginRight: "10px"}} /> ) : ( -
{String(value)}
+ <>{String(value)} ); } else { return asChip ? : ; @@ -808,7 +865,7 @@ const KeepUrlBase = withStyles(styles)(({ auth, res, pdh, classes }: KeepUrlProp // Passing a pdh always returns a relative wb2 collection url const pdhWbPath = getNavUrl(pdhUrl, auth); return pdhUrl && pdhWbPath ? ( - + View collection in Workbench
{pdhUrl}}> + View in keep-web
{keepUrlPath || "/"}}> & React.PropsWithChildren; + +const MuiLinkWithTooltip = withStyles(styles)((props: MuiLinkWithTooltipProps) => ( + + + {props.children} + + +)); + const fileToProcessIOValue = (file: File, secondary: boolean, auth: AuthState, pdh: string | undefined, mainFilePdh: string): ProcessIOValue => { if (isExternalValue(file)) { return { display: }; @@ -910,13 +977,14 @@ const fileToProcessIOValue = (file: File, secondary: boolean, auth: AuthState, p if (isFileUrl(file.location)) { return { display: ( - {file.location} - + ), secondary, };