16073: Style io panel tabs to be symmetrical
[arvados.git] / src / views / process-panel / process-io-card.tsx
index 4b2413ce47668fd91f144c78d04e967cc74c6f44..7d4565228cca38f0032e204eb3b4f367ebf4a3bf 100644 (file)
@@ -25,7 +25,7 @@ import {
     Chip,
 } from '@material-ui/core';
 import { ArvadosTheme } from 'common/custom-theme';
-import { CloseIcon, InfoIcon, ProcessIcon } from 'components/icon/icon';
+import { CloseIcon, InfoIcon, ProcessIcon, InputIcon, OutputIcon } from 'components/icon/icon';
 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
 import {
   BooleanCommandInputParameter,
@@ -59,8 +59,9 @@ import { InputCollectionMount } from 'store/processes/processes-actions';
 import { connect } from 'react-redux';
 import { RootState } from 'store/store';
 import { ProcessOutputCollectionFiles } from './process-output-collection-files';
+import { Process } from 'store/processes/process';
 
-type CssRules = 'card' | 'content' | 'title' | 'header' | 'avatar' | 'iconHeader' | 'tableWrapper' | 'tableRoot' | 'paramValue' | 'keepLink' | 'imagePreview' | 'valArray' | 'emptyValue';
+type CssRules = 'card' | 'content' | 'title' | 'header' | 'avatar' | 'iconHeader' | 'tableWrapper' | 'tableRoot' | 'paramValue' | 'keepLink' | 'imagePreview' | 'valArray' | 'emptyValue' | 'symmetricTabs';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     card: {
@@ -94,6 +95,10 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     },
     tableRoot: {
         width: '100%',
+        '& thead th': {
+            verticalAlign: 'bottom',
+            paddingBottom: '10px',
+        }
     },
     paramValue: {
         display: 'flex',
@@ -122,6 +127,11 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     emptyValue: {
         color: theme.customs.colors.grey500,
     },
+    symmetricTabs: {
+        '& button': {
+            flexBasis: '0',
+        }
+    },
 });
 
 export enum ProcessIOCardType {
@@ -129,6 +139,7 @@ export enum ProcessIOCardType {
     OUTPUT = 'Outputs',
 }
 export interface ProcessIOCardDataProps {
+    process: Process;
     label: ProcessIOCardType;
     params: ProcessIOParameter[];
     raw?: any;
@@ -139,12 +150,14 @@ export interface ProcessIOCardDataProps {
 type ProcessIOCardProps = ProcessIOCardDataProps & WithStyles<CssRules> & MPVPanelProps;
 
 export const ProcessIOCard = withStyles(styles)(
-    ({ classes, label, params, raw, mounts, outputUuid, doHidePanel, panelName }: ProcessIOCardProps) => {
-        const [tabState, setTabState] = useState(0);
-        const handleChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
-            setTabState(value);
+    ({ classes, label, params, raw, mounts, outputUuid, doHidePanel, panelName, process }: ProcessIOCardProps) => {
+        const [mainProcTabState, setMainProcTabState] = useState(0);
+        const handleMainProcTabChange = (event: React.MouseEvent<HTMLElement>, value: number) => {
+            setMainProcTabState(value);
         }
 
+        const PanelIcon = label == ProcessIOCardType.INPUT ? InputIcon : OutputIcon;
+
         return <Card className={classes.card} data-cy="process-io-card">
             <CardHeader
                 className={classes.header}
@@ -152,7 +165,7 @@ export const ProcessIOCard = withStyles(styles)(
                     content: classes.title,
                     avatar: classes.avatar,
                 }}
-                avatar={<ProcessIcon className={classes.iconHeader} />}
+                avatar={<PanelIcon className={classes.iconHeader} />}
                 title={
                     <Typography noWrap variant='h6' color='inherit'>
                         {label}
@@ -168,30 +181,38 @@ export const ProcessIOCard = withStyles(styles)(
                 } />
             <CardContent className={classes.content}>
                 <div>
-                    <Tabs value={tabState} onChange={handleChange} variant="fullWidth">
-                        <Tab label="Preview" />
-                        <Tab label="Raw" />
-                        {label === ProcessIOCardType.INPUT && <Tab label="Input Mounts" />}
-                        {label === ProcessIOCardType.OUTPUT && <Tab label="Output Collection" />}
-                    </Tabs>
-                    {tabState === 0 && <div className={classes.tableWrapper}>
-                        {params.length ?
-                            <ProcessIOPreview data={params} /> :
-                            <Grid container item alignItems='center' justify='center'>
-                                <DefaultView messages={["No parameters found"]} icon={InfoIcon} />
-                            </Grid>}
-                        </div>}
-                    {tabState === 1 && <div className={classes.tableWrapper}>
-                        {params.length ?
-                            <ProcessIORaw data={raw || params} /> :
-                            <Grid container item alignItems='center' justify='center'>
-                                <DefaultView messages={["No parameters found"]} icon={InfoIcon} />
-                            </Grid>}
-                        </div>}
-                    {tabState === 2 && <div className={classes.tableWrapper}>
-                        {label === ProcessIOCardType.INPUT && <ProcessInputMounts mounts={mounts || []} />}
-                        {label === ProcessIOCardType.OUTPUT && <ProcessOutputCollectionFiles isWritable={false} currentItemUuid={outputUuid} />}
-                        </div>}
+                    {!process.containerRequest.requestingContainerUuid ?
+                        (<>
+                            <Tabs value={mainProcTabState} onChange={handleMainProcTabChange} variant="fullWidth" className={classes.symmetricTabs}>
+                                <Tab label="Parameters" />
+                                <Tab label="JSON" />
+                            </Tabs>
+                            {mainProcTabState === 0 && <div className={classes.tableWrapper}>
+                                {params.length ?
+                                    <ProcessIOPreview data={params} /> :
+                                    <Grid container item alignItems='center' justify='center'>
+                                        <DefaultView messages={["No parameters found"]} icon={InfoIcon} />
+                                    </Grid>}
+                                </div>}
+                            {mainProcTabState === 1 && <div className={classes.tableWrapper}>
+                                {params.length ?
+                                    <ProcessIORaw data={raw || params} /> :
+                                    <Grid container item alignItems='center' justify='center'>
+                                        <DefaultView messages={["No parameters found"]} icon={InfoIcon} />
+                                    </Grid>}
+                                </div>}
+                        </>) :
+                        (<>
+                            <Tabs value={0} variant="fullWidth" className={classes.symmetricTabs}>
+                                {label === ProcessIOCardType.INPUT && <Tab label="Collections" />}
+                                {label === ProcessIOCardType.OUTPUT && <Tab label="Collection" />}
+                            </Tabs>
+                            <div className={classes.tableWrapper}>
+                                {label === ProcessIOCardType.INPUT && <ProcessInputMounts mounts={mounts || []} />}
+                                {label === ProcessIOCardType.OUTPUT && <ProcessOutputCollectionFiles isWritable={false} currentItemUuid={outputUuid} />}
+                            </div>
+                        </>)
+                    }
                 </div>
             </CardContent>
         </Card>;
@@ -426,7 +447,7 @@ const KeepUrlBase = withStyles(styles)(({auth, res, pdh, classes}: KeepUrlProps
     // Passing a pdh always returns a relative wb2 collection url
     const pdhWbPath = getNavUrl(pdhUrl.replace('keep:', ''), auth);
     return pdhUrl && pdhWbPath ?
-        <RouterLink to={pdhWbPath} className={classes.keepLink}>{pdhUrl}</RouterLink> :
+        <Tooltip title={"View collection in Workbench"}><RouterLink to={pdhWbPath} className={classes.keepLink}>{pdhUrl}</RouterLink></Tooltip> :
         <></>;
 });
 
@@ -437,8 +458,9 @@ const KeepUrlPath = withStyles(styles)(({auth, res, pdh, classes}: KeepUrlProps
 
     const keepUrlPathNav = getKeepNavUrl(auth, res, pdh);
     return keepUrlPath && keepUrlPathNav ?
-        <MuiLink className={classes.keepLink} onClick={() => handleClick(keepUrlPathNav)}>{keepUrlPath}</MuiLink> :
-        <></>;
+        <Tooltip title={"View in keep-web"}><MuiLink className={classes.keepLink} onClick={() => handleClick(keepUrlPathNav)}>{keepUrlPath}</MuiLink></Tooltip> :
+        // Show No value for root collection io that lacks path part
+        <EmptyValue />;
 });
 
 const getKeepNavUrl = (auth: AuthState, file: File | Directory, pdh?: string): string => {