--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React, { ReactNode, useEffect, useState } from "react";
+import { Tabs, Tab } from "@material-ui/core";
+import { TabsProps } from "@material-ui/core/Tabs";
+
+type TabData = {
+ show: boolean;
+ label: string;
+ content: ReactNode;
+};
+
+type ConditionalTabsProps = {
+ tabs: TabData[];
+};
+
+export const ConditionalTabs = (props: Omit<TabsProps, 'value' | 'onChange'> & ConditionalTabsProps) => {
+ const [tabState, setTabState] = useState(0);
+ const visibleTabs = props.tabs.filter(tab => tab.show);
+ const activeTab = visibleTabs[tabState];
+ const visibleTabNames = visibleTabs.map(tab => tab.label).join();
+
+ const handleTabChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
+ setTabState(value);
+ };
+
+ // Reset tab to 0 when tab visibility changes
+ // (or if tab set change causes visible set to change)
+ useEffect(() => {
+ setTabState(0);
+ }, [visibleTabNames]);
+
+ return <>
+ <Tabs
+ {...props}
+ value={tabState}
+ onChange={handleTabChange} >
+ {visibleTabs.map(tab => <Tab label={tab.label} />)}
+ </Tabs>
+ {activeTab && activeTab.content}
+ </>;
+};
//
// SPDX-License-Identifier: AGPL-3.0
-import React, { ReactElement, memo, useState } from "react";
+import React, { ReactElement, memo } from "react";
import { Dispatch } from "redux";
import {
StyleRulesCallback,
CardContent,
Tooltip,
Typography,
- Tabs,
- Tab,
Table,
TableHead,
TableBody,
import { FixedSizeList } from 'react-window';
import AutoSizer from "react-virtualized-auto-sizer";
import { LinkProps } from "@material-ui/core/Link";
+import { ConditionalTabs } from "components/conditional-tabs/conditional-tabs";
type CssRules =
| "card"
navigateTo,
forceShowParams,
}: ProcessIOCardProps) => {
- const [mainProcTabState, setMainProcTabState] = useState(0);
- const [subProcTabState, setSubProcTabState] = useState(0);
- const handleMainProcTabChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
- setMainProcTabState(value);
- };
- const handleSubProcTabChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
- setSubProcTabState(value);
- };
-
const PanelIcon = label === ProcessIOCardType.INPUT ? InputIcon : OutputIcon;
const mainProcess = !(process && process!.containerRequest.requestingContainerUuid);
const showParamTable = mainProcess || forceShowParams;
* Params when raw is provided by containerRequest properties but workflow mount is absent for preview
*/}
{!loading && (hasRaw || hasParams) && (
- <>
- <Tabs
- value={mainProcTabState}
- onChange={handleMainProcTabChange}
- variant="fullWidth"
- className={classes.symmetricTabs}
- >
- {/* params will be empty on processes without workflow definitions in mounts, so we only show raw */}
- {hasParams && <Tab label="Parameters" />}
- {!forceShowParams && <Tab label="JSON" />}
- {hasOutputCollecton && <Tab label="Collection" />}
- </Tabs>
- {mainProcTabState === 0 && params && hasParams && (
- <div className={classes.tableWrapper}>
- <ProcessIOPreview
- data={params}
- valueLabel={forceShowParams ? "Default value" : "Value"}
- />
- </div>
- )}
- {(mainProcTabState === 1 || !hasParams) && (
- <div className={classes.jsonWrapper}>
- <ProcessIORaw data={raw} />
- </div>
- )}
- {mainProcTabState === 2 && hasOutputCollecton && (
- <>
- {outputUuid && (
- <Typography className={classes.collectionLink}>
- Output Collection:{" "}
- <MuiLink
- className={classes.keepLink}
- onClick={() => {
- navigateTo(outputUuid || "");
- }}
- >
- {outputUuid}
- </MuiLink>
- </Typography>
- )}
- <ProcessOutputCollectionFiles
- isWritable={false}
- currentItemUuid={outputUuid}
- />
- </>
- )}
-
- </>
+ <ConditionalTabs
+ variant="fullWidth"
+ className={classes.symmetricTabs}
+ tabs={[
+ {
+ // params will be empty on processes without workflow definitions in mounts, so we only show raw
+ show: hasParams,
+ label: "Parameters",
+ content: <div className={classes.tableWrapper}>
+ <ProcessIOPreview
+ data={params || []}
+ valueLabel={forceShowParams ? "Default value" : "Value"}
+ />
+ </div>,
+ },
+ {
+ show: !forceShowParams,
+ label: "JSON",
+ content: <div className={classes.jsonWrapper}>
+ <ProcessIORaw data={raw} />
+ </div>,
+ },
+ {
+ show: hasOutputCollecton,
+ label: "Collection",
+ content: <ProcessOutputCollection outputUuid={outputUuid} />,
+ },
+ ]}
+ />
)}
{!loading && !hasRaw && !hasParams && (
<Grid
<CircularProgress />
</Grid>
) : !subProcessLoading && (hasInputMounts || hasOutputCollecton || isRawLoaded) ? (
- <>
- <Tabs
- value={subProcTabState}
- onChange={handleSubProcTabChange}
- variant="fullWidth"
- className={classes.symmetricTabs}
- >
- {hasInputMounts && <Tab label="Collections" />}
- {hasOutputCollecton && <Tab label="Collection" />}
- {isRawLoaded && <Tab label="JSON" />}
- </Tabs>
- {subProcTabState === 0 && hasInputMounts && <ProcessInputMounts mounts={mounts || []} />}
- {subProcTabState === 0 && hasOutputCollecton && (
- <div className={classes.tableWrapper}>
- <>
- {outputUuid && (
- <Typography className={classes.collectionLink}>
- Output Collection:{" "}
- <MuiLink
- className={classes.keepLink}
- onClick={() => {
- navigateTo(outputUuid || "");
- }}
- >
- {outputUuid}
- </MuiLink>
- </Typography>
- )}
- <ProcessOutputCollectionFiles
- isWritable={false}
- currentItemUuid={outputUuid}
- />
- </>
- </div>
- )}
- {isRawLoaded && (subProcTabState === 1 || (!hasInputMounts && !hasOutputCollecton)) && (
- <div className={classes.jsonWrapper}>
- <ProcessIORaw data={raw} />
- </div>
- )}
- </>
+ <ConditionalTabs
+ variant="fullWidth"
+ className={classes.symmetricTabs}
+ tabs={[
+ {
+ show: hasInputMounts,
+ label: "Collections",
+ content: <ProcessInputMounts mounts={mounts || []} />,
+ },
+ {
+ show: hasOutputCollecton,
+ label: "Collection",
+ content: <ProcessOutputCollection outputUuid={outputUuid} />,
+ },
+ {
+ show: isRawLoaded,
+ label: "JSON",
+ content: <div className={classes.jsonWrapper}>
+ <ProcessIORaw data={raw} />
+ </div>,
+ },
+ ]}
+ />
) : (
<Grid
container
))
);
+type ProcessOutputCollectionProps = {outputUuid: string | undefined} & WithStyles<CssRules>;
+
+const ProcessOutputCollection = withStyles(styles)(({ outputUuid, classes }: ProcessOutputCollectionProps) => (
+ <div className={classes.tableWrapper}>
+ <>
+ {outputUuid && (
+ <Typography className={classes.collectionLink}>
+ Output Collection:{" "}
+ <MuiLink
+ className={classes.keepLink}
+ onClick={() => {
+ navigateTo(outputUuid || "");
+ }}
+ >
+ {outputUuid}
+ </MuiLink>
+ </Typography>
+ )}
+ <ProcessOutputCollectionFiles
+ isWritable={false}
+ currentItemUuid={outputUuid}
+ />
+ </>
+ </div>
+));
+
type FileWithSecondaryFiles = {
secondaryFiles: File[];
};