16073: Show loading indicator when process io params are not loaded
[arvados.git] / src / views / process-panel / process-io-card.tsx
index 0a1ec9e22c0174d88cad4fe327b10cb947821d45..7284159ebf7193310e41c9836c140b4c37af0fb5 100644 (file)
@@ -24,6 +24,7 @@ import {
     Paper,
     Grid,
     Chip,
+    CircularProgress,
 } from '@material-ui/core';
 import { ArvadosTheme } from 'common/custom-theme';
 import { CloseIcon, ImageIcon, InputIcon, ImageOffIcon, OutputIcon, MaximizeIcon } from 'components/icon/icon';
@@ -63,7 +64,25 @@ import { ProcessOutputCollectionFiles } from './process-output-collection-files'
 import { Process } from 'store/processes/process';
 import { navigateTo } from 'store/navigation/navigation-action';
 
-type CssRules = 'card' | 'content' | 'title' | 'header' | 'avatar' | 'iconHeader' | 'tableWrapper' | 'tableRoot' | 'paramValue' | 'keepLink' | 'collectionLink' | 'imagePreview' | 'valArray' | 'emptyValue' | 'halfRow' | 'symmetricTabs' | 'imagePlaceholder' | 'rowWithPreview';
+type CssRules =
+  | "card"
+  | "content"
+  | "title"
+  | "header"
+  | "avatar"
+  | "iconHeader"
+  | "tableWrapper"
+  | "tableRoot"
+  | "paramValue"
+  | "keepLink"
+  | "collectionLink"
+  | "imagePreview"
+  | "valArray"
+  | "emptyValue"
+  | "halfRow"
+  | "symmetricTabs"
+  | "imagePlaceholder"
+  | "rowWithPreview";
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     card: {
@@ -102,6 +121,9 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         '& thead th': {
             verticalAlign: 'bottom',
             paddingBottom: '10px',
+        },
+        '& td, & th': {
+            paddingRight: '25px',
         }
     },
     paramValue: {
@@ -171,7 +193,7 @@ export enum ProcessIOCardType {
 export interface ProcessIOCardDataProps {
     process: Process;
     label: ProcessIOCardType;
-    params: ProcessIOParameter[];
+    params?: ProcessIOParameter[];
     raw?: any;
     mounts?: InputCollectionMount[];
     outputUuid?: string;
@@ -230,7 +252,10 @@ export const ProcessIOCard = withStyles(styles)(connect(null, mapDispatchToProps
             <CardContent className={classes.content}>
                 {mainProcess ?
                     (<>
-                        {params.length ?
+                        {params === undefined && <Grid container item alignItems='center' justify='center'>
+                            <CircularProgress />
+                        </Grid>}
+                        {params && params.length > 0 &&
                             <>
                                 <Tabs value={mainProcTabState} onChange={handleMainProcTabChange} variant="fullWidth" className={classes.symmetricTabs}>
                                     <Tab label="Parameters" />
@@ -242,12 +267,12 @@ export const ProcessIOCard = withStyles(styles)(connect(null, mapDispatchToProps
                                 {mainProcTabState === 1 && <div className={classes.tableWrapper}>
                                         <ProcessIORaw data={raw || params} />
                                     </div>}
-                            </> :
-                            <Grid container item alignItems='center' justify='center'>
-                                <DefaultView messages={["No parameters found"]} />
-                            </Grid>
-                        }
+                            </>}
+                        {params && params.length === 0 && <Grid container item alignItems='center' justify='center'>
+                            <DefaultView messages={["No parameters found"]} />
+                        </Grid>}
                     </>) :
+                    // Subprocess
                     (<>
                         {((mounts && mounts.length) || outputUuid) ?
                             <>
@@ -532,9 +557,14 @@ export const getIOParamDisplayValue = (auth: AuthState, input: CommandInputParam
     }
 };
 
+/*
+ * @returns keep url without keep: prefix
+ */
 const getKeepUrl = (file: File | Directory, pdh?: string): string => {
     const isKeepUrl = file.location?.startsWith('keep:') || false;
-    const keepUrl = isKeepUrl ? file.location : pdh ? `keep:${pdh}/${file.location}` : file.location;
+    const keepUrl = isKeepUrl ?
+                        file.location?.replace('keep:', '') :
+                        pdh ? `${pdh}/${file.location}` : file.location;
     return keepUrl || '';
 };
 
@@ -548,7 +578,7 @@ const KeepUrlBase = withStyles(styles)(({auth, res, pdh, classes}: KeepUrlProps
     const keepUrl = getKeepUrl(res, pdh);
     const pdhUrl = keepUrl ? keepUrl.split('/').slice(0, 1)[0] : '';
     // Passing a pdh always returns a relative wb2 collection url
-    const pdhWbPath = getNavUrl(pdhUrl.replace('keep:', ''), auth);
+    const pdhWbPath = getNavUrl(pdhUrl, auth);
     return pdhUrl && pdhWbPath ?
         <Tooltip title={"View collection in Workbench"}><RouterLink to={pdhWbPath} className={classes.keepLink}>{pdhUrl}</RouterLink></Tooltip> :
         <></>;
@@ -561,18 +591,18 @@ const KeepUrlPath = withStyles(styles)(({auth, res, pdh, classes}: KeepUrlProps
 
     const keepUrlPathNav = getKeepNavUrl(auth, res, pdh);
     return keepUrlPath && keepUrlPathNav ?
-        <Tooltip title={"View in keep-web"}><MuiLink className={classes.keepLink} onClick={() => handleClick(keepUrlPathNav)}>{keepUrlPath}</MuiLink></Tooltip> :
+        <Tooltip title={"View in keep-web"}><a className={classes.keepLink} href={keepUrlPathNav} target="_blank">{keepUrlPath}</a></Tooltip> :
         // Show No value for root collection io that lacks path part
         <EmptyValue />;
 });
 
 const getKeepNavUrl = (auth: AuthState, file: File | Directory, pdh?: string): string => {
-    let keepUrl = getKeepUrl(file, pdh).replace('keep:', '');
+    let keepUrl = getKeepUrl(file, pdh);
     return (getInlineFileUrl(`${auth.config.keepWebServiceUrl}/c=${keepUrl}?api_token=${auth.apiToken}`, auth.config.keepWebServiceUrl, auth.config.keepWebInlineServiceUrl));
 };
 
 const getImageUrl = (auth: AuthState, file: File, pdh?: string): string => {
-    const keepUrl = getKeepUrl(file, pdh).replace('keep:', '');
+    const keepUrl = getKeepUrl(file, pdh);
     return getInlineFileUrl(`${auth.config.keepWebServiceUrl}/c=${keepUrl}?api_token=${auth.apiToken}`, auth.config.keepWebServiceUrl, auth.config.keepWebInlineServiceUrl);
 };