From: Stephen Smith Date: Tue, 11 Oct 2022 22:59:05 +0000 (-0400) Subject: 16073: Display process io params from props, hide preview when lacking workflow mount X-Git-Tag: 2.5.0~31^2~19 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/627132ee694565c5f3cf347fa0bbee8e514de884 16073: Display process io params from props, hide preview when lacking workflow mount Arvados-DCO-1.1-Signed-off-by: Stephen Smith --- diff --git a/src/store/process-panel/process-panel-actions.ts b/src/store/process-panel/process-panel-actions.ts index c8c0bcc7..b62a4886 100644 --- a/src/store/process-panel/process-panel-actions.ts +++ b/src/store/process-panel/process-panel-actions.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: AGPL-3.0 import { unionize, ofType, UnionOf } from "common/unionize"; -import { loadProcess } from 'store/processes/processes-actions'; +import { getRawOutputs, loadProcess } from 'store/processes/processes-actions'; import { Dispatch } from 'redux'; import { ProcessStatus } from 'store/processes/process'; import { RootState } from 'store/store'; @@ -15,6 +15,7 @@ import { showWorkflowDetails } from 'store/workflow-panel/workflow-panel-actions import { loadSubprocessPanel } from "../subprocess-panel/subprocess-panel-actions"; import { initProcessLogsPanel, processLogsPanelActions } from "store/process-logs-panel/process-logs-panel-actions"; import { CollectionFile } from "models/collection-file"; +import { ContainerRequestResource } from "models/container-request"; export const processPanelActions = unionize({ SET_PROCESS_PANEL_CONTAINER_REQUEST_UUID: ofType(), @@ -46,22 +47,30 @@ export const navigateToOutput = (uuid: string) => } }; -export const loadOutputs = (uuid: string, setOutputs) => +export const loadOutputs = (containerRequest: ContainerRequestResource, setOutputs) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { + if (!containerRequest.outputUuid) {setOutputs({}); return;}; try { - const filesPromise = services.collectionService.files(uuid); - const collectionPromise = services.collectionService.get(uuid); + const propsOutputs = getRawOutputs(containerRequest); + const filesPromise = services.collectionService.files(containerRequest.outputUuid); + const collectionPromise = services.collectionService.get(containerRequest.outputUuid); const [files, collection] = await Promise.all([filesPromise, collectionPromise]); - const outputFile = files.find((file) => file.name === 'cwl.output.json') as CollectionFile | undefined; - let outputData = outputFile ? await services.collectionService.getFileContents(outputFile) : undefined; - if ((outputData = JSON.parse(outputData)) && collection.portableDataHash) { - setOutputs({ - rawOutputs: outputData, - pdh: collection.portableDataHash, - }); + // If has propsOutput, skip fetching cwl.output.json + if (propsOutputs !== undefined) { + setOutputs({rawOutputs: propsOutputs, pdh: collection.portableDataHash}); } else { - setOutputs({}); + // Fetch outputs from keep + const outputFile = files.find((file) => file.name === 'cwl.output.json') as CollectionFile | undefined; + let outputData = outputFile ? await services.collectionService.getFileContents(outputFile) : undefined; + if ((outputData = JSON.parse(outputData)) && collection.portableDataHash) { + setOutputs({ + rawOutputs: outputData, + pdh: collection.portableDataHash, + }); + } else { + setOutputs({}); + } } } catch { setOutputs({}); diff --git a/src/store/processes/processes-actions.ts b/src/store/processes/processes-actions.ts index eb04ed67..1f672759 100644 --- a/src/store/processes/processes-actions.ts +++ b/src/store/processes/processes-actions.ts @@ -133,13 +133,22 @@ export const reRunProcess = (processUuid: string, workflowUuid: string) => } }; +/* + * Fetches raw inputs from containerRequest mounts with fallback to properties + */ export const getRawInputs = (data: any): CommandInputParameter[] | undefined => { - if (!data || !data.mounts || !data.mounts[MOUNT_PATH_CWL_INPUT]) { return undefined; } - return (data.mounts[MOUNT_PATH_CWL_INPUT].content); + if (!data) { return undefined; } + const mountInput = data.mounts?.[MOUNT_PATH_CWL_INPUT]?.content; + const propsInput = data.properties?.cwl_input; + if (!mountInput && !propsInput) { return undefined; } + return (mountInput || propsInput); } export const getInputs = (data: any): CommandInputParameter[] => { if (!data || !data.mounts || !data.mounts[MOUNT_PATH_CWL_WORKFLOW]) { return []; } + const content = getRawInputs(data) as any; + if (!content) { return []; } + const inputs = getWorkflowInputs(data.mounts[MOUNT_PATH_CWL_WORKFLOW].content); return inputs ? inputs.map( (it: any) => ( @@ -147,14 +156,22 @@ export const getInputs = (data: any): CommandInputParameter[] => { type: it.type, id: it.id, label: it.label, - default: data.mounts[MOUNT_PATH_CWL_INPUT].content[it.id], - value: data.mounts[MOUNT_PATH_CWL_INPUT].content[it.id.split('/').pop()] || [], + default: content[it.id], + value: content[it.id.split('/').pop()] || [], doc: it.doc } ) ) : []; }; +/* + * Fetches raw outputs from containerRequest properties + */ +export const getRawOutputs = (data: any): CommandInputParameter[] | undefined => { + if (!data || !data.properties || !data.properties.cwl_output) { return undefined; } + return (data.properties.cwl_output); +} + export type InputCollectionMount = { path: string; pdh: string; diff --git a/src/views/process-panel/process-io-card.tsx b/src/views/process-panel/process-io-card.tsx index 84a9ca6d..937478ef 100644 --- a/src/views/process-panel/process-io-card.tsx +++ b/src/views/process-panel/process-io-card.tsx @@ -256,23 +256,25 @@ export const ProcessIOCard = withStyles(styles)(connect(null, mapDispatchToProps {mainProcess ? (<> - {params === undefined && + {/* raw is undefined until params are loaded */} + {raw === undefined && } - {params && params.length > 0 && + {raw && Object.keys(raw).length > 0 && <> - + {/* params will be empty on processes without workflow definitions in mounts, so we only show raw */} + {(params && params.length) && } - {mainProcTabState === 0 &&
+ {(mainProcTabState === 0 && params && params.length > 0) &&
} - {mainProcTabState === 1 &&
- + {(mainProcTabState === 1 || !params || !(params.length > 0)) &&
+
} } - {params && params.length === 0 && + {raw && Object.keys(raw).length === 0 && } ) : diff --git a/src/views/process-panel/process-panel-root.tsx b/src/views/process-panel/process-panel-root.tsx index a08d8aec..248c5215 100644 --- a/src/views/process-panel/process-panel-root.tsx +++ b/src/views/process-panel/process-panel-root.tsx @@ -22,6 +22,7 @@ import { CommandInputParameter, getIOParamId } from 'models/workflow'; import { CommandOutputParameter } from 'cwlts/mappings/v1.0/CommandOutputParameter'; import { AuthState } from 'store/auth/auth-reducer'; import { ProcessCmdCard } from './process-cmd-card'; +import { ContainerRequestResource } from 'models/container-request'; type CssRules = 'root'; @@ -46,7 +47,7 @@ export interface ProcessPanelRootActionProps { onLogFilterChange: (filter: FilterOption) => void; navigateToLog: (uuid: string) => void; onCopyToClipboard: (uuid: string) => void; - fetchOutputs: (uuid: string, fetchOutputs) => void; + fetchOutputs: (containerRequest: ContainerRequestResource, fetchOutputs) => void; } export type ProcessPanelRootProps = ProcessPanelRootDataProps & ProcessPanelRootActionProps & WithStyles; @@ -77,6 +78,8 @@ export const ProcessPanelRoot = withStyles(styles)( const outputUuid = process?.containerRequest.outputUuid; const requestUuid = process?.containerRequest.uuid; + const containerRequest = process?.containerRequest; + const inputMounts = getInputCollectionMounts(process?.containerRequest); // Resets state when changing processes @@ -87,28 +90,32 @@ export const ProcessPanelRoot = withStyles(styles)( setProcessedInputs(undefined); }, [requestUuid]); + // Fetch raw output (async for fetching from keep) React.useEffect(() => { - if (outputUuid) { - fetchOutputs(outputUuid, setOutputs); + if (containerRequest) { + fetchOutputs(containerRequest, setOutputs); } - }, [outputUuid, fetchOutputs]); + }, [containerRequest, fetchOutputs]); + // Format raw output into ProcessIOParameter[] when it changes React.useEffect(() => { - if (outputDetails !== undefined && outputDetails.rawOutputs && process) { - const outputDefinitions = getOutputParameters(process.containerRequest); + if (outputDetails !== undefined && outputDetails.rawOutputs && containerRequest) { + const outputDefinitions = getOutputParameters(containerRequest); setProcessedOutputs(formatOutputData(outputDefinitions, outputDetails.rawOutputs, outputDetails.pdh, auth)); } - }, [outputDetails, auth, process]); + }, [outputDetails, auth, containerRequest]); + // Fetch raw inputs and format into ProcessIOParameter[] + // Can be sync because inputs are either already in containerRequest mounts or props React.useEffect(() => { - if (process) { - const rawInputs = getRawInputs(process.containerRequest); + if (containerRequest) { + const rawInputs = getRawInputs(containerRequest); setInputs(rawInputs); - const inputs = getInputs(process.containerRequest); + const inputs = getInputs(containerRequest); setProcessedInputs(formatInputData(inputs, auth)); } - }, [requestUuid, auth, process]); + }, [requestUuid, auth, containerRequest]); return process ? diff --git a/src/views/process-panel/process-panel.tsx b/src/views/process-panel/process-panel.tsx index 8adec3bd..75e934ab 100644 --- a/src/views/process-panel/process-panel.tsx +++ b/src/views/process-panel/process-panel.tsx @@ -54,7 +54,7 @@ const mapDispatchToProps = (dispatch: Dispatch): ProcessPanelRootActionProps => cancelProcess: (uuid) => dispatch(cancelRunningWorkflow(uuid)), onLogFilterChange: (filter) => dispatch(setProcessLogsPanelFilter(filter.value)), navigateToLog: (uuid) => dispatch(navigateToLogCollection(uuid)), - fetchOutputs: (uuid, setOutputs) => dispatch(loadOutputs(uuid, setOutputs)), + fetchOutputs: (containerRequest, setOutputs) => dispatch(loadOutputs(containerRequest, setOutputs)), }); const getFilters = (processPanel: ProcessPanelState, processes: Process[]) => {