CircularProgress,
} from "@material-ui/core";
import { ArvadosTheme } from "common/custom-theme";
-import { CloseIcon, ImageIcon, InputIcon, ImageOffIcon, OutputIcon, MaximizeIcon, UnMaximizeIcon, InfoIcon } from "components/icon/icon";
+import { CloseIcon, InputIcon, OutputIcon, MaximizeIcon, UnMaximizeIcon, InfoIcon } from "components/icon/icon";
import { MPVPanelProps } from "components/multi-panel-view/multi-panel-view";
import {
BooleanCommandInputParameter,
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"
| "paramTableRoot"
| "paramTableCellText"
| "mountsTableRoot"
+ | "jsonWrapper"
| "keepLink"
| "collectionLink"
| "secondaryVal"
| "emptyValue"
| "noBorderRow"
- | "symmetricTabs";
+ | "symmetricTabs"
+ | "wrapTooltip";
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
card: {
color: theme.customs.colors.greyD,
fontSize: "1.875rem",
},
- // Applies to each tab's content
+ // Applies to table tab and collection table content
tableWrapper: {
height: "auto",
maxHeight: `calc(100% - ${theme.spacing.unit * 6}px)`,
// 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
+ alignItems: "stretch", // Stretches output collection to full width
+
},
// Param table virtual list styles
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,
},
paddingRight: "25px",
},
},
+ // JSON tab wrapper
+ jsonWrapper: {
+ height: `calc(100% - ${theme.spacing.unit * 6}px)`,
+ },
keepLink: {
color: theme.palette.primary.main,
textDecoration: "none",
flexBasis: "0",
},
},
+ wrapTooltip: {
+ maxWidth: "600px",
+ wordWrap: "break-word",
+ },
});
export enum ProcessIOCardType {
</div>
)}
{(mainProcTabState === 1 || !hasParams) && (
- <div className={classes.tableWrapper}>
+ <div className={classes.jsonWrapper}>
<ProcessIORaw data={raw} />
</div>
)}
{hasOutputCollecton && <Tab label="Collection" />}
{isRawLoaded && <Tab label="JSON" />}
</Tabs>
- <div className={classes.tableWrapper}>
- {subProcTabState === 0 && hasInputMounts && <ProcessInputMounts mounts={mounts || []} />}
- {subProcTabState === 0 && hasOutputCollecton && (
+ {subProcTabState === 0 && hasInputMounts && <ProcessInputMounts mounts={mounts || []} />}
+ {subProcTabState === 0 && hasOutputCollecton && (
+ <div className={classes.tableWrapper}>
<>
{outputUuid && (
<Typography className={classes.collectionLink}>
currentItemUuid={outputUuid}
/>
</>
- )}
- {isRawLoaded && (subProcTabState === 1 || (!hasInputMounts && !hasOutputCollecton)) && (
- <div className={classes.tableWrapper}>
- <ProcessIORaw data={raw} />
- </div>
- )}
- </div>
+ </div>
+ )}
+ {isRawLoaded && (subProcTabState === 1 || (!hasInputMounts && !hasOutputCollecton)) && (
+ <div className={classes.jsonWrapper}>
+ <ProcessIORaw data={raw} />
+ </div>
+ )}
</>
) : (
<Grid
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}) => {
[classes.noBorderRow]: hasMoreValues(index),
};
- return <TableRow style={style} className={classNames(rowClasses)}>
+ return <TableRow
+ style={style}
+ className={classNames(rowClasses)}
+ data-cy={isMainRow(param) ? "process-io-param" : ""}>
<TableCell>
<Tooltip title={param.id}>
<Typography className={classes.paramTableCellText}>
}
const ProcessIORaw = withStyles(styles)(({ data }: ProcessIORawDataProps) => (
- <Paper elevation={0} style={{minWidth: "100%"}}>
- <DefaultCodeSnippet
- lines={[JSON.stringify(data, null, 2)]}
+ <Paper elevation={0} style={{minWidth: "100%", height: "100%"}}>
+ <DefaultVirtualCodeSnippet
+ lines={JSON.stringify(data, null, 2).split('\n')}
linked
/>
</Paper>
// Passing a pdh always returns a relative wb2 collection url
const pdhWbPath = getNavUrl(pdhUrl, auth);
return pdhUrl && pdhWbPath ? (
- <Tooltip title={"View collection in Workbench"}>
+ <Tooltip title={<>View collection in Workbench<br />{pdhUrl}</>}>
<RouterLink
to={pdhWbPath}
className={classes.keepLink}
const keepUrlPathNav = getKeepNavUrl(auth, res, pdh);
return keepUrlPathNav ? (
- <Tooltip title={"View in keep-web"}>
+ <Tooltip classes={{tooltip: classes.wrapTooltip}} title={<>View in keep-web<br />{keepUrlPath || "/"}</>}>
<a
className={classes.keepLink}
href={keepUrlPathNav}
target="_blank"
- rel="noopener"
+ rel="noopener noreferrer"
>
{keepUrlPath || "/"}
</a>
};
};
+type MuiLinkWithTooltipProps = WithStyles<CssRules> & React.PropsWithChildren<LinkProps>;
+
+const MuiLinkWithTooltip = withStyles(styles)((props: MuiLinkWithTooltipProps) => (
+ <Tooltip title={props.title} classes={{tooltip: props.classes.wrapTooltip}}>
+ <MuiLink {...props}>
+ {props.children}
+ </MuiLink>
+ </Tooltip>
+));
+
const fileToProcessIOValue = (file: File, secondary: boolean, auth: AuthState, pdh: string | undefined, mainFilePdh: string): ProcessIOValue => {
if (isExternalValue(file)) {
return { display: <UnsupportedValue /> };
if (isFileUrl(file.location)) {
return {
display: (
- <MuiLink
+ <MuiLinkWithTooltip
href={file.location}
target="_blank"
rel="noopener"
+ title={file.location}
>
{file.location}
- </MuiLink>
+ </MuiLinkWithTooltip>
),
secondary,
};