From 328e503f5b90be37b8bd1d885adb9ee9a22b2976 Mon Sep 17 00:00:00 2001 From: mabashian Date: Tue, 18 Aug 2020 11:19:00 -0400 Subject: [PATCH] Update workflow node job status based on websocket messages --- .../components/Workflow/workflowReducer.js | 2 + .../Job/WorkflowOutput/WorkflowOutput.jsx | 7 ++ .../Job/WorkflowOutput/WorkflowOutputNode.jsx | 6 +- .../Job/WorkflowOutput/useWsWorkflowOutput.js | 65 +++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 awx/ui_next/src/screens/Job/WorkflowOutput/useWsWorkflowOutput.js diff --git a/awx/ui_next/src/components/Workflow/workflowReducer.js b/awx/ui_next/src/components/Workflow/workflowReducer.js index 1fe635c47e..eddd7dce2a 100644 --- a/awx/ui_next/src/components/Workflow/workflowReducer.js +++ b/awx/ui_next/src/components/Workflow/workflowReducer.js @@ -64,6 +64,8 @@ export default function visualizerReducer(state, action) { return { ...state, linkToDelete: action.value }; case 'SET_LINK_TO_EDIT': return { ...state, linkToEdit: action.value }; + case 'SET_NODES': + return { ...state, nodes: action.value }; case 'SET_NODE_POSITIONS': return { ...state, nodePositions: action.value }; case 'SET_NODE_TO_DELETE': diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutput.jsx b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutput.jsx index 23a87207a6..8c50bab16c 100644 --- a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutput.jsx +++ b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutput.jsx @@ -16,6 +16,7 @@ import workflowReducer, { import { WorkflowJobsAPI } from '../../../api'; import WorkflowOutputGraph from './WorkflowOutputGraph'; import WorkflowOutputToolbar from './WorkflowOutputToolbar'; +import useWsWorkflowOutput from './useWsWorkflowOutput'; const CardBody = styled(PFCardBody)` display: flex; @@ -79,6 +80,12 @@ function WorkflowOutput({ job, i18n }) { } }, [job.id, links, nodes]); + const updatedNodes = useWsWorkflowOutput(job.id, nodes); + + useEffect(() => { + dispatch({ type: 'SET_NODES', value: updatedNodes }); + }, [updatedNodes]); + if (isLoading) { return ( diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx index 4a566834ac..24f60de2a6 100644 --- a/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx +++ b/awx/ui_next/src/screens/Job/WorkflowOutput/WorkflowOutputNode.jsx @@ -110,9 +110,11 @@ function WorkflowOutputNode({ i18n, mouseEnter, mouseLeave, node }) { <> {node.job.status && } -

{node.job.name}

+

{node.job.name || node.unifiedJobTemplate.name}

- {secondsToHHMMSS(node.job.elapsed)} + {!!node?.job?.elapsed && ( + {secondsToHHMMSS(node.job.elapsed)} + )} ) : ( diff --git a/awx/ui_next/src/screens/Job/WorkflowOutput/useWsWorkflowOutput.js b/awx/ui_next/src/screens/Job/WorkflowOutput/useWsWorkflowOutput.js new file mode 100644 index 0000000000..76bd3c1e9c --- /dev/null +++ b/awx/ui_next/src/screens/Job/WorkflowOutput/useWsWorkflowOutput.js @@ -0,0 +1,65 @@ +import { useState, useEffect } from 'react'; +import useWebsocket from '../../../util/useWebsocket'; + +export default function useWsWorkflowOutput(workflowJobId, initialNodes) { + const [nodes, setNodes] = useState(initialNodes); + const lastMessage = useWebsocket({ + jobs: ['status_changed'], + control: ['limit_reached_1'], + }); + + useEffect(() => { + setNodes(initialNodes); + }, [initialNodes]); + + useEffect( + function parseWsMessage() { + if ( + !nodes || + nodes.length === 0 || + lastMessage?.workflow_job_id !== workflowJobId + ) { + return; + } + + const index = nodes.findIndex( + node => node?.originalNodeObject?.id === lastMessage.workflow_node_id + ); + + if (index > -1) { + setNodes(updateNode(nodes, index, lastMessage)); + } + }, + [lastMessage] // eslint-disable-line react-hooks/exhaustive-deps + ); + + return nodes; +} + +function updateNode(nodes, index, message) { + const node = { + ...nodes[index], + originalNodeObject: { + ...nodes[index]?.originalNodeObject, + job: message.unified_job_id, + summary_fields: { + ...nodes[index]?.originalNodeObject?.summary_fields, + job: { + ...nodes[index]?.originalNodeObject?.summary_fields?.job, + id: message.unified_job_id, + status: message.status, + type: message.type, + }, + }, + }, + job: { + ...nodes[index]?.job, + id: message.unified_job_id, + name: nodes[index]?.job?.name || nodes[index]?.unifiedJobTemplate?.name, + status: message.status, + type: message.type, + }, + }; + + return [...nodes.slice(0, index), node, ...nodes.slice(index + 1)]; +}