Merge branch 'main' into 19069-workflow-launching
authorPeter Amstutz <peter.amstutz@curii.com>
Mon, 23 May 2022 15:00:15 +0000 (11:00 -0400)
committerPeter Amstutz <peter.amstutz@curii.com>
Mon, 23 May 2022 15:00:15 +0000 (11:00 -0400)
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>

13 files changed:
cypress/integration/create-workflow.spec.js
cypress/integration/favorites.spec.js
cypress/integration/side-panel.spec.js
src/models/workflow.ts
src/store/context-menu/context-menu-actions.ts
src/store/run-process-panel/run-process-panel-actions.test.ts
src/store/run-process-panel/run-process-panel-actions.ts
src/store/side-panel-tree/side-panel-tree-actions.ts
src/views-components/side-panel-button/side-panel-button.tsx
src/views/process-panel/process-details-attributes.tsx
src/views/run-process-panel/run-process-panel-root.tsx
src/views/run-process-panel/run-process-second-step.tsx
src/views/workflow-panel/workflow-description-card.tsx

index b1ea5dbf7e297d373911d728379869ed92ffff57..709db76e41e5059258d11ccc3a20a783b50db75c 100644 (file)
@@ -148,14 +148,14 @@ describe('Multi-file deletion tests', function () {
 
                 cy.get('[data-cy=side-panel-button]').click();
 
-                cy.get('#aside-menu-list').contains('Run a process').click();
+                cy.get('#aside-menu-list').contains('Run a workflow').click();
 
                 cy.get('@testWorkflow')
                     .then((testWorkflow) => {
                         cy.get('main').contains(testWorkflow.name).click();
                         cy.get('[data-cy=run-process-next-button]').click();
 
-                        cy.get('label').contains('#main/foo').parent('div').find('input').click();
+                        cy.get('label').contains('foo').parent('div').find('input').click();
                         cy.get('div[role=dialog]')
                             .within(() => {
                                 cy.get('p').contains('Projects').closest('div[role=button]')
@@ -174,7 +174,7 @@ describe('Multi-file deletion tests', function () {
                                 cy.get('[data-cy=ok-button]').click();
                             });
 
-                        cy.get('label').contains('#main/bar').parent('div').find('input').click();
+                        cy.get('label').contains('bar').parent('div').find('input').click();
                         cy.get('div[role=dialog]')
                             .within(() => {
                                 cy.get('p').contains('Projects').closest('div[role=button]')
@@ -193,13 +193,13 @@ describe('Multi-file deletion tests', function () {
                             });
                     });
 
-                cy.get('label').contains('#main/foo').parent('div')
+                cy.get('label').contains('foo').parent('div')
                     .within(() => {
                         cy.contains('baz');
                         cy.contains('bar');
                     });
 
-                cy.get('label').contains('#main/bar').parent('div')
+                cy.get('label').contains('bar').parent('div')
                     .within(() => {
                         cy.contains(testCollection.name);
                         cy.contains(testCollection2.name);
index 9bc90ebdee4c9fda24b91a2c9c15312965d3fd46..7b0a4392a446bb162551cae85815af4f7c192b4d 100644 (file)
@@ -219,7 +219,7 @@ describe('Favorites tests', function () {
 
                 cy.get('[data-cy=side-panel-button]').click();
 
-                cy.get('#aside-menu-list').contains('Run a process').click();
+                cy.get('#aside-menu-list').contains('Run a workflow').click();
 
                 cy.get('@testWorkflow')
                     .then((testWorkflow) => {
index 4c824d3275f5d83bf53a04da7dc1abf41312a9d1..fc2052cc13afb11311512589185c9ac60f5eed45 100644 (file)
@@ -62,7 +62,7 @@ describe('Side panel tests', function() {
             {url: '/shared-with-me', label: 'Shared with me'},
             {url: '/public-favorites', label: 'Public Favorites'},
             {url: '/favorites', label: 'My Favorites'},
-            {url: '/workflows', label: 'Workflows'},
+            // {url: '/workflows', label: 'Workflows'},
             {url: '/all_processes', label: 'All Processes'},
             {url: '/trash', label: 'Trash'},
         ].map(function(section) {
index ad84bd9e891a95fcfff02a1cb001a72e226e0f45..6d21dbc766381831a1e048529913e77f51784a38 100644 (file)
@@ -139,7 +139,7 @@ export const parseWorkflowDefinition = (workflow: WorkflowResource): WorkflowRes
 
 export const getWorkflow = (workflowDefinition: WorkflowResourceDefinition) => {
     if (!workflowDefinition.$graph) { return undefined; }
-    const mainWorkflow = workflowDefinition.$graph.find(item => item.class === 'Workflow' && item.id === '#main');
+    const mainWorkflow = workflowDefinition.$graph.find(item => item.id === '#main');
     return mainWorkflow
         ? mainWorkflow
         : undefined;
@@ -153,7 +153,7 @@ export const getWorkflowInputs = (workflowDefinition: WorkflowResourceDefinition
 };
 
 export const getInputLabel = (input: CommandInputParameter) => {
-    return `${input.label || input.id}`;
+    return `${input.label || input.id.split('/').pop()}`;
 };
 
 export const isRequiredInput = ({ type }: CommandInputParameter) => {
index 1116949a6f31f769dfcf0fbb3ed56e147e7166c2..bc7f94b0a8bfc06c24b75d86ad4643f5cdb64103 100644 (file)
@@ -189,7 +189,7 @@ export const openProcessContextMenu = (event: React.MouseEvent<HTMLElement>, pro
                 name: res.name,
                 description: res.description,
                 outputUuid: res.outputUuid || '',
-                workflowUuid: res.properties.workflowUuid || '',
+                workflowUuid: res.properties.template_uuid || '',
                 menuKind: ContextMenuKind.PROCESS_RESOURCE
             }));
         }
index 745be88fb5f66a1c6d0c9d1a3f13f047b841b50e..3137583e35dd89c34810a0d1b514db623e68cd1f 100644 (file)
@@ -116,13 +116,13 @@ describe("run-process-panel-actions", () => {
                 description: "basicFormTestDescription",
                 mounts: undefined,
                 name: "basicFormTestName",
-                outputName: undefined,
+                outputName: "Output from basicFormTestName",
                 outputPath: "/var/spool/cwl",
                 ownerUuid: "ce8i5-tpzed-yid70bw31f51234",
                 priority: 1,
                 properties: {
                     workflowName: "revsort.cwl",
-                    workflowUuid: "ce8i5-7fd4e-2tlnerdkxnl4fjt",
+                    template_uuid: "ce8i5-7fd4e-2tlnerdkxnl4fjt",
                 },
                 runtimeConstraints: {
                     API: true,
index adb5ade7c2bb87eb0dce96ae5769eacb10632af5..61597bb776a760e4cf499d0226944428e4b56f95 100644 (file)
@@ -103,11 +103,13 @@ export const setWorkflow = (workflow: WorkflowResource, isWorkflowChanged = true
             dispatch(runProcessPanelActions.SET_STEP_CHANGED(false));
             dispatch(runProcessPanelActions.SET_SELECTED_WORKFLOW(workflow));
             dispatch<any>(loadPresets(workflow.uuid));
+            dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name: workflow.name }));
             dispatch(initialize(RUN_PROCESS_ADVANCED_FORM, advancedFormValues));
         }
         if (!isWorkflowChanged) {
             dispatch(runProcessPanelActions.SET_SELECTED_WORKFLOW(workflow));
             dispatch<any>(loadPresets(workflow.uuid));
+            dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name: workflow.name }));
             dispatch(initialize(RUN_PROCESS_ADVANCED_FORM, advancedFormValues));
         }
     };
@@ -173,9 +175,9 @@ export const runProcess = async (dispatch: Dispatch<any>, getState: () => RootSt
             ],
             outputPath: '/var/spool/cwl',
             priority: 1,
-            outputName: advancedForm[OUTPUT_FIELD] ? advancedForm[OUTPUT_FIELD] : undefined,
+            outputName: advancedForm[OUTPUT_FIELD] ? advancedForm[OUTPUT_FIELD] : `Output from ${basicForm.name}`,
             properties: {
-                workflowUuid: selectedWorkflow.uuid,
+                template_uuid: selectedWorkflow.uuid,
                 workflowName: selectedWorkflow.name
             },
             useExisting: false
index 895fe79c0bdc9011bcb0c7b26c42c6ac3b68ea8e..58f7d82d956546644532767679547e39023d87c5 100644 (file)
@@ -52,7 +52,7 @@ let SIDE_PANEL_CATEGORIES: string[] = [
     SidePanelTreeCategory.SHARED_WITH_ME,
     SidePanelTreeCategory.PUBLIC_FAVORITES,
     SidePanelTreeCategory.FAVORITES,
-    SidePanelTreeCategory.WORKFLOWS,
+    //    SidePanelTreeCategory.WORKFLOWS,
     SidePanelTreeCategory.GROUPS,
     SidePanelTreeCategory.ALL_PROCESSES,
     SidePanelTreeCategory.TRASH
index a219e55a26d768b47d0e8b97e28ed9abb87b7868..c813efb0a373f4080fe177b1234ce0222f5f5a1d 100644 (file)
@@ -107,7 +107,7 @@ export const SidePanelButton = withStyles(styles)(
                         <CollectionIcon className={classes.icon} /> New collection
                     </MenuItem>
                     <MenuItem data-cy='side-panel-run-process' className={classes.menuItem} onClick={this.handleRunProcessClick}>
-                        <ProcessIcon className={classes.icon} /> Run a process
+                        <ProcessIcon className={classes.icon} /> Run a workflow
                     </MenuItem>
                     <MenuItem data-cy='side-panel-new-project' className={classes.menuItem} onClick={this.handleNewProjectClick}>
                         <ProjectIcon className={classes.icon} /> New project
index d0e593d50aec3a1639886c159f62b05ca474b4f4..99a4404c87e90fbca886d39b872415857c06c007 100644 (file)
@@ -74,7 +74,7 @@ export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })(
                 </Grid>
                 <Grid item xs={12} md={mdSize}>
                     <DetailsAttribute label='Docker Image locator'
-                    linkToUuid={containerRequest.containerImage} value={containerRequest.containerImage} />
+                        linkToUuid={containerRequest.containerImage} value={containerRequest.containerImage} />
                 </Grid>
                 <Grid item xs={12} md={mdSize}>
                     <DetailsAttribute
@@ -85,7 +85,7 @@ export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })(
                     <DetailsAttribute label='Container UUID' value={containerRequest.containerUuid} />
                 </Grid>
                 {!props.hideProcessPanelRedundantFields && <Grid item xs={12} md={mdSize}>
-                    <DetailsAttribute label='Status' value={getProcessStatus({containerRequest, container})} />
+                    <DetailsAttribute label='Status' value={getProcessStatus({ containerRequest, container })} />
                 </Grid>}
                 <Grid item xs={12} md={mdSize}>
                     <DetailsAttribute label='Created at' value={formatDate(containerRequest.createdAt)} />
@@ -112,13 +112,13 @@ export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })(
                         <DetailsAttribute classLabel={classes.link} label='Inputs' />
                     </span>
                 </Grid>
-                {containerRequest.properties.workflowUuid &&
-                <Grid item xs={12} md={mdSize}>
-                    <span onClick={() => props.openWorkflow(containerRequest.properties.workflowUuid)}>
-                        <DetailsAttribute classValue={classes.link}
-                            label='Workflow' value={containerRequest.properties.workflowName} />
-                    </span>
-                </Grid>}
+                {containerRequest.properties.template_uuid &&
+                    <Grid item xs={12} md={mdSize}>
+                        <span onClick={() => props.openWorkflow(containerRequest.properties.template_uuid)}>
+                            <DetailsAttribute classValue={classes.link}
+                                label='Workflow' value={containerRequest.properties.workflowName} />
+                        </span>
+                    </Grid>}
                 <Grid item xs={12} md={mdSize}>
                     <DetailsAttribute label='Priority' value={containerRequest.priority} />
                 </Grid>
@@ -128,13 +128,13 @@ export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })(
                 */}
                 <Grid item xs={12} md={12}>
                     <DetailsAttribute label='Properties' />
-                    { Object.keys(containerRequest.properties).length > 0
+                    {Object.keys(containerRequest.properties).length > 0
                         ? Object.keys(containerRequest.properties).map(k =>
-                                Array.isArray(containerRequest.properties[k])
+                            Array.isArray(containerRequest.properties[k])
                                 ? containerRequest.properties[k].map((v: string) =>
                                     getPropertyChip(k, v, undefined, classes.propertyTag))
                                 : getPropertyChip(k, containerRequest.properties[k], undefined, classes.propertyTag))
-                        : <div>No properties</div> }
+                        : <div>No properties</div>}
                 </Grid>
             </Grid>;
         }
index 3c42437a674344e257b504caa6288b91166a0224..9dd5aa3fd0d98cd79b08a95315a9761b6c9c42e9 100644 (file)
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from 'react';
-import { Stepper, Step, StepLabel, StepContent } from '@material-ui/core';
+import { Stepper, Step, StepLabel, StepContent, StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core';
 import { RunProcessFirstStepDataProps, RunProcessFirstStepActionProps, RunProcessFirstStep } from 'views/run-process-panel/run-process-first-step';
 import { RunProcessSecondStepForm } from './run-process-second-step';
 
@@ -17,25 +17,34 @@ export type RunProcessPanelRootActionProps = RunProcessFirstStepActionProps & {
 
 type RunProcessPanelRootProps = RunProcessPanelRootDataProps & RunProcessPanelRootActionProps;
 
-export const RunProcessPanelRoot = ({ runProcess, currentStep, onSearch, onSetStep, onSetWorkflow, workflows, selectedWorkflow }: RunProcessPanelRootProps) =>
-    <Stepper activeStep={currentStep} orientation="vertical" elevation={2}>
-        <Step>
-            <StepLabel>Choose a workflow</StepLabel>
-            <StepContent>
-                <RunProcessFirstStep
-                    workflows={workflows}
-                    selectedWorkflow={selectedWorkflow}
-                    onSearch={onSearch}
-                    onSetStep={onSetStep} 
-                    onSetWorkflow={onSetWorkflow} />
-            </StepContent>
-        </Step>
-        <Step>
-            <StepLabel>Select inputs</StepLabel>
-            <StepContent>
-                <RunProcessSecondStepForm
-                    goBack={() => onSetStep(0)}
-                    runProcess={runProcess} />
-            </StepContent>
-        </Step>
-    </Stepper>;
\ No newline at end of file
+type CssRules = 'stepper';
+
+const styles: StyleRulesCallback<CssRules> = theme => ({
+    stepper: {
+        overflow: "scroll",
+    }
+});
+
+export const RunProcessPanelRoot = withStyles(styles)(
+    ({ runProcess, currentStep, onSearch, onSetStep, onSetWorkflow, workflows, selectedWorkflow, classes }: WithStyles<CssRules> & RunProcessPanelRootProps) =>
+        <Stepper activeStep={currentStep} orientation="vertical" elevation={2} className={classes.stepper}>
+            <Step>
+                <StepLabel>Choose a workflow</StepLabel>
+                <StepContent>
+                    <RunProcessFirstStep
+                        workflows={workflows}
+                        selectedWorkflow={selectedWorkflow}
+                        onSearch={onSearch}
+                        onSetStep={onSetStep}
+                        onSetWorkflow={onSetWorkflow} />
+                </StepContent>
+            </Step>
+            <Step>
+                <StepLabel>Select inputs</StepLabel>
+                <StepContent>
+                    <RunProcessSecondStepForm
+                        goBack={() => onSetStep(0)}
+                        runProcess={runProcess} />
+                </StepContent>
+            </Step>
+        </Stepper>);
index 08cf4e6caf43955ddc39750aaa5c6d9bc8e8f8e4..ca30ce5fe2b8129f6cea1d704ed7e58ae1689720 100644 (file)
@@ -58,14 +58,14 @@ export const RunProcessSecondStepForm = connect(mapStateToProps, { onPresetChang
     ({ inputs, workflow, selectedPreset, presets, onPresetChange, valid, goBack, runProcess }: RunProcessSecondStepFormProps) =>
         <Grid container spacing={16} data-cy="new-process-panel">
             <Grid item xs={12}>
-                <Grid container spacing={32}>
+                {/* <Grid container spacing={32}>
                     <Grid item xs={12} md={6}>
-                        {workflow && selectedPreset && presets &&
-                            < WorkflowPresetSelect
-                                {...{ workflow, selectedPreset, presets, onChange: onPresetChange }} />
-                        }
+                    {workflow && selectedPreset && presets &&
+                    < WorkflowPresetSelect
+                    {...{ workflow, selectedPreset, presets, onChange: onPresetChange }} />
+                    }
                     </Grid>
-                </Grid>
+                    </Grid> */}
                 <RunProcessBasicForm />
                 <RunProcessInputsForm inputs={inputs} />
                 <RunProcessAdvancedForm />
index 9c1d81c3ed21ecc712a154fb1abe44b779f9467f..b9e89c7631a192801c0c7b6e0bef9e6e770a013a 100644 (file)
@@ -14,13 +14,17 @@ import {
     TableHead,
     TableCell,
     TableBody,
-    TableRow
+    TableRow,
+    Grid,
 } from '@material-ui/core';
 import { ArvadosTheme } from 'common/custom-theme';
 import { WorkflowIcon } from 'components/icon/icon';
 import { DataTableDefaultView } from 'components/data-table-default-view/data-table-default-view';
 import { WorkflowResource, parseWorkflowDefinition, getWorkflowInputs, getInputLabel, stringifyInputType } from 'models/workflow';
-import { WorkflowGraph } from "views/workflow-panel/workflow-graph";
+// import { WorkflowGraph } from "views/workflow-panel/workflow-graph";
+import { DetailsAttribute } from 'components/details-attribute/details-attribute';
+import { ResourceOwnerWithName } from 'views-components/data-explorer/renderers';
+import { formatDate } from "common/formatters";
 
 export type CssRules = 'root' | 'tab' | 'inputTab' | 'graphTab' | 'graphTabWithChosenWorkflow' | 'descriptionTab' | 'inputsTable';
 
@@ -77,16 +81,17 @@ export const WorkflowDetailsCard = withStyles(styles)(
                 <Tabs value={value} onChange={this.handleChange} centered={true}>
                     <Tab className={classes.tab} label="Description" />
                     <Tab className={classes.tab} label="Inputs" />
-                    <Tab className={classes.tab} label="Graph" />
+                    <Tab className={classes.tab} label="Details" />
+                    {/* <Tab className={classes.tab} label="Graph" /> */}
                 </Tabs>
                 {value === 0 && <CardContent className={classes.descriptionTab}>
                     {workflow ? <div>
                         {workflow.description}
                     </div> : (
-                            <DataTableDefaultView
-                                icon={WorkflowIcon}
-                                messages={['Please select a workflow to see its description.']} />
-                        )}
+                        <DataTableDefaultView
+                            icon={WorkflowIcon}
+                            messages={['Please select a workflow to see its description.']} />
+                    )}
                 </CardContent>}
                 {value === 1 && <CardContent className={classes.inputTab}>
                     {workflow
@@ -96,12 +101,20 @@ export const WorkflowDetailsCard = withStyles(styles)(
                             messages={['Please select a workflow to see its inputs.']} />
                     }
                 </CardContent>}
-                {value === 2 && <CardContent className={workflow ? classes.graphTabWithChosenWorkflow : classes.graphTab}>
+                {/* {value === 2 && <CardContent className={workflow ? classes.graphTabWithChosenWorkflow : classes.graphTab}>
+                    {workflow
+                    ? <WorkflowGraph workflow={workflow} />
+                    : <DataTableDefaultView
+                    icon={WorkflowIcon}
+                    messages={['Please select a workflow to see its visualisation.']} />
+                    }
+                    </CardContent>} */}
+                {value === 2 && <CardContent className={classes.descriptionTab}>
                     {workflow
-                        ? <WorkflowGraph workflow={workflow} />
+                        ? <WorkflowDetailsAttributes workflow={workflow} />
                         : <DataTableDefaultView
                             icon={WorkflowIcon}
-                            messages={['Please select a workflow to see its visualisation.']} />
+                            messages={['Please select a workflow to see its details.']} />
                     }
                 </CardContent>}
             </div>;
@@ -137,3 +150,29 @@ export const WorkflowDetailsCard = withStyles(styles)(
             </Table>;
         }
     });
+
+export const WorkflowDetailsAttributes = ({ workflow }: WorkflowDetailsCardDataProps) => {
+    return <Grid container>
+        <Grid item xs={12} >
+            <DetailsAttribute
+                label={"Workflow UUID"}
+                linkToUuid={workflow?.uuid} />
+        </Grid>
+        <Grid item xs={12} >
+            <DetailsAttribute
+                label='Owner' linkToUuid={workflow?.ownerUuid}
+                uuidEnhancer={(uuid: string) => <ResourceOwnerWithName uuid={uuid} />} />
+        </Grid>
+        <Grid item xs={12}>
+            <DetailsAttribute label='Created at' value={formatDate(workflow?.createdAt)} />
+        </Grid>
+        <Grid item xs={12}>
+            <DetailsAttribute label='Last modified' value={formatDate(workflow?.modifiedAt)} />
+        </Grid>
+        <Grid item xs={12} >
+            <DetailsAttribute
+                label='Last modified by user' linkToUuid={workflow?.modifiedByUserUuid}
+                uuidEnhancer={(uuid: string) => <ResourceOwnerWithName uuid={uuid} />} />
+        </Grid>
+    </Grid >;
+};