15557: Add start workflow button when container request is uncommitted
authorStephen Smith <stephen@curii.com>
Mon, 9 Jan 2023 20:22:57 +0000 (15:22 -0500)
committerStephen Smith <stephen@curii.com>
Mon, 9 Jan 2023 20:22:57 +0000 (15:22 -0500)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

src/components/icon/icon.tsx
src/store/processes/processes-actions.ts
src/views/process-panel/process-details-card.tsx
src/views/process-panel/process-panel-root.tsx
src/views/process-panel/process-panel.tsx

index db220a36e9506fcd3b576314ad811254cdbd397e..48cd8bed4f4c48ddb802e3c3b41eaab4616a51af 100644 (file)
@@ -33,7 +33,7 @@ import Help from '@material-ui/icons/Help';
 import HelpOutline from '@material-ui/icons/HelpOutline';
 import History from '@material-ui/icons/History';
 import Inbox from '@material-ui/icons/Inbox';
-import Memory from '@material-ui/icons/Memory'; 
+import Memory from '@material-ui/icons/Memory';
 import MoveToInbox from '@material-ui/icons/MoveToInbox';
 import Info from '@material-ui/icons/Info';
 import Input from '@material-ui/icons/Input';
@@ -166,7 +166,7 @@ export const KeyIcon: IconType = (props) => <VpnKey {...props} />;
 export const LogIcon: IconType = (props) => <SettingsEthernet {...props} />;
 export const MailIcon: IconType = (props) => <Mail {...props} />;
 export const MaximizeIcon: IconType = (props) => <FullscreenSharp {...props} />;
-export const MemoryIcon: IconType = (props) => <Memory {...props} />; 
+export const MemoryIcon: IconType = (props) => <Memory {...props} />;
 export const UnMaximizeIcon: IconType = (props) => <FullscreenExitSharp {...props} />;
 export const MoreOptionsIcon: IconType = (props) => <MoreVert {...props} />;
 export const MoveToIcon: IconType = (props) => <Input {...props} />;
@@ -214,3 +214,4 @@ export const ActiveIcon: IconType = (props) => <CheckCircleOutline {...props} />
 export const SetupIcon: IconType = (props) => <RemoveCircleOutline {...props} />;
 export const InactiveIcon: IconType = (props) => <NotInterested {...props} />;
 export const ImageIcon: IconType = (props) => <Image {...props} />;
+export const StartIcon: IconType = (props) => <PlayArrow {...props} />;
index e4f35c1e4443741c8acf484c243a45e4867f5720..11a36e0561f722d20002c1fc7ae7f011605201e7 100644 (file)
@@ -21,6 +21,7 @@ import { CommandInputParameter, getWorkflow, getWorkflowInputs, getWorkflowOutpu
 import { ProjectResource } from "models/project";
 import { UserResource } from "models/user";
 import { CommandOutputParameter } from "cwlts/mappings/v1.0/CommandOutputParameter";
+import { ContainerRequestState } from "models/container-request";
 
 export const loadProcess = (containerRequestUuid: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<Process> => {
@@ -104,6 +105,17 @@ export const cancelRunningWorkflow = (uuid: string) =>
         }
     };
 
+export const startWorkflow = (uuid: string) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        try {
+            const process = await services.containerRequestService.update(uuid, { priority: 1, state: ContainerRequestState.COMMITTED });
+            dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Process started', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
+            return process;
+        } catch (e) {
+            throw new Error('Could not cancel the process.');
+        }
+    };
+
 export const reRunProcess = (processUuid: string, workflowUuid: string) =>
     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const process = getResource<any>(processUuid)(getState().resources);
index b09b499e1c424f3db24c9a122725b376cfb47e2f..801403b0b6b4b31ffe40e5b623330673ea70fb40 100644 (file)
@@ -15,12 +15,13 @@ import {
     Typography,
 } from '@material-ui/core';
 import { ArvadosTheme } from 'common/custom-theme';
-import { CloseIcon, MoreOptionsIcon, ProcessIcon } from 'components/icon/icon';
+import { CloseIcon, MoreOptionsIcon, ProcessIcon, StartIcon } from 'components/icon/icon';
 import { Process } from 'store/processes/process';
 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
 import { ProcessDetailsAttributes } from './process-details-attributes';
 import { ProcessStatus } from 'views-components/data-explorer/renderers';
 import { ContainerState } from 'models/container';
+import { ContainerRequestState } from 'models/container-request';
 
 type CssRules = 'card' | 'content' | 'title' | 'header' | 'cancelButton' | 'avatar' | 'iconHeader';
 
@@ -65,13 +66,14 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 export interface ProcessDetailsCardDataProps {
     process: Process;
     cancelProcess: (uuid: string) => void;
+    startProcess: (uuid: string) => void;
     onContextMenu: (event: React.MouseEvent<HTMLElement>) => void;
 }
 
 type ProcessDetailsCardProps = ProcessDetailsCardDataProps & WithStyles<CssRules> & MPVPanelProps;
 
 export const ProcessDetailsCard = withStyles(styles)(
-    ({ cancelProcess, onContextMenu, classes, process, doHidePanel, panelName }: ProcessDetailsCardProps) => {
+    ({ cancelProcess, startProcess, onContextMenu, classes, process, doHidePanel, panelName }: ProcessDetailsCardProps) => {
         return <Card className={classes.card}>
             <CardHeader
                 className={classes.header}
@@ -95,6 +97,14 @@ export const ProcessDetailsCard = withStyles(styles)(
                     </Tooltip>}
                 action={
                     <div>
+                        {process.containerRequest.state === ContainerRequestState.UNCOMMITTED &&
+                            <Tooltip title="Start Process" disableFocusListener>
+                                <IconButton
+                                    aria-label="Start Process"
+                                    onClick={event => startProcess(process.containerRequest.uuid)}>
+                                    <StartIcon />
+                                </IconButton>
+                            </Tooltip>}
                         {process.container && process.container.state === ContainerState.RUNNING &&
                             <span className={classes.cancelButton} onClick={() => cancelProcess(process.containerRequest.uuid)}>Cancel</span>}
                         <ProcessStatus uuid={process.containerRequest.uuid} />
index adb6c920746b08b73268c2a3d5b0980d9237280a..11b31ae0c97e5f4bb0d83e84718d60d32fd476f8 100644 (file)
@@ -51,6 +51,7 @@ export interface ProcessPanelRootActionProps {
     onContextMenu: (event: React.MouseEvent<HTMLElement>, process: Process) => void;
     onToggle: (status: string) => void;
     cancelProcess: (uuid: string) => void;
+    startProcess: (uuid: string) => void;
     onLogFilterChange: (filter: FilterOption) => void;
     navigateToLog: (uuid: string) => void;
     onCopyToClipboard: (uuid: string) => void;
@@ -122,6 +123,7 @@ export const ProcessPanelRoot = withStyles(styles)(
                         process={process}
                         onContextMenu={event => props.onContextMenu(event, process)}
                         cancelProcess={props.cancelProcess}
+                        startProcess={props.startProcess}
                     />
                 </MPVPanelContent>
                 <MPVPanelContent forwardProps xs="auto" data-cy="process-cmd">
index d853fd091d767b6efcc4870689073263ac9dddfa..2ad7e2a37b6cd8bb24a78c6fdd2581a105d65297 100644 (file)
@@ -25,7 +25,7 @@ import {
     updateOutputParams,
     loadNodeJson
 } from 'store/process-panel/process-panel-actions';
-import { cancelRunningWorkflow } from 'store/processes/processes-actions';
+import { cancelRunningWorkflow, startWorkflow } from 'store/processes/processes-actions';
 import { navigateToLogCollection, setProcessLogsPanelFilter } from 'store/process-logs-panel/process-logs-panel-actions';
 import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
 
@@ -62,6 +62,7 @@ const mapDispatchToProps = (dispatch: Dispatch): ProcessPanelRootActionProps =>
         dispatch<any>(toggleProcessPanelFilter(status));
     },
     cancelProcess: (uuid) => dispatch<any>(cancelRunningWorkflow(uuid)),
+    startProcess: (uuid) => dispatch<any>(startWorkflow(uuid)),
     onLogFilterChange: (filter) => dispatch(setProcessLogsPanelFilter(filter.value)),
     navigateToLog: (uuid) => dispatch<any>(navigateToLogCollection(uuid)),
     loadInputs: (containerRequest) => dispatch<any>(loadInputs(containerRequest)),