From 4704e24c246f89a5b85602d3c57d015a76174f67 Mon Sep 17 00:00:00 2001 From: Marliana Lara Date: Wed, 1 Apr 2020 15:21:42 -0400 Subject: [PATCH] Fetch full resource object and replace the matching node --- .../components/PromptDetail/PromptDetail.jsx | 8 +- .../components/Workflow/workflowReducer.js | 17 +++ .../Workflow/workflowReducer.test.js | 1 + .../Modals/NodeModals/NodeViewModal.jsx | 106 ++++++++++++++---- .../Modals/NodeModals/NodeViewModal.test.jsx | 1 + 5 files changed, 108 insertions(+), 25 deletions(-) diff --git a/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx b/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx index b64cb06822..4e013c87f2 100644 --- a/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx +++ b/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx @@ -28,12 +28,16 @@ function hasPromptData(launchData) { } function formatTimeout(timeout) { - if (typeof timeout === "undefined" || timeout === null) { + if (typeof timeout === 'undefined' || timeout === null) { return null; } const minutes = Math.floor(timeout / 60); const seconds = timeout - Math.floor(timeout / 60) * 60; - return <>{minutes} min {seconds} sec; + return ( + <> + {minutes} min {seconds} sec + + ); } function PromptDetail({ i18n, resource, launchConfig = {} }) { diff --git a/awx/ui_next/src/components/Workflow/workflowReducer.js b/awx/ui_next/src/components/Workflow/workflowReducer.js index 05d8af15fb..1fe635c47e 100644 --- a/awx/ui_next/src/components/Workflow/workflowReducer.js +++ b/awx/ui_next/src/components/Workflow/workflowReducer.js @@ -17,6 +17,7 @@ export function initReducer() { nodes: [], nodeToDelete: null, nodeToEdit: null, + nodeToView: null, showDeleteAllNodesModal: false, showLegend: false, showTools: false, @@ -93,6 +94,8 @@ export default function visualizerReducer(state, action) { return updateLink(state, action.linkType); case 'UPDATE_NODE': return updateNode(state, action.node); + case 'REFRESH_NODE': + return refreshNode(state, action.node); default: throw new Error(`Unrecognized action type: ${action.type}`); } @@ -607,3 +610,17 @@ function updateNode(state, editedNode) { unsavedChanges: true, }; } + +function refreshNode(state, refreshedNode) { + const { nodeToView, nodes } = state; + const newNodes = [...nodes]; + + const matchingNode = newNodes.find(node => node.id === nodeToView.id); + matchingNode.unifiedJobTemplate = refreshedNode.nodeResource; + + return { + ...state, + nodes: newNodes, + nodeToView: matchingNode, + }; +} diff --git a/awx/ui_next/src/components/Workflow/workflowReducer.test.js b/awx/ui_next/src/components/Workflow/workflowReducer.test.js index 82aa87cf09..cab793ee5c 100644 --- a/awx/ui_next/src/components/Workflow/workflowReducer.test.js +++ b/awx/ui_next/src/components/Workflow/workflowReducer.test.js @@ -16,6 +16,7 @@ const defaultState = { nodes: [], nodeToDelete: null, nodeToEdit: null, + nodeToView: null, showDeleteAllNodesModal: false, showLegend: false, showTools: false, diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.jsx index 03bea68be7..d233adc03c 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.jsx @@ -11,44 +11,105 @@ import ContentError from '@components/ContentError'; import ContentLoading from '@components/ContentLoading'; import PromptDetail from '@components/PromptDetail'; import useRequest from '@util/useRequest'; -import { JobTemplatesAPI, WorkflowJobTemplatesAPI } from '@api'; +import { + InventorySourcesAPI, + JobTemplatesAPI, + ProjectsAPI, + WorkflowJobTemplatesAPI, +} from '@api'; + +function getNodeType(node) { + const ujtType = node.type || node.unified_job_type; + + let nodeType; + let nodeAPI; + switch (ujtType) { + case 'job_template': + case 'job': + nodeType = 'job_template'; + nodeAPI = JobTemplatesAPI; + break; + case 'project': + case 'project_update': + nodeType = 'project_sync'; + nodeAPI = ProjectsAPI; + break; + case 'inventory_source': + case 'inventory_update': + nodeType = 'inventory_source_sync'; + nodeAPI = InventorySourcesAPI; + break; + case 'workflow_job_template': + case 'workflow_job': + nodeType = 'workflow_job_template'; + nodeAPI = WorkflowJobTemplatesAPI; + break; + case 'workflow_approval_template': + case 'workflow_approval': + nodeType = 'approval'; + nodeAPI = null; + break; + default: + } + return [nodeType, nodeAPI]; +} function NodeViewModal({ i18n }) { const dispatch = useContext(WorkflowDispatchContext); const { nodeToView } = useContext(WorkflowStateContext); const { unifiedJobTemplate } = nodeToView; - const jobType = - unifiedJobTemplate.unified_job_type || unifiedJobTemplate.type; + const [nodeType, nodeAPI] = getNodeType(unifiedJobTemplate); const { result: launchConfig, - isLoading, - error, + isLoading: isLaunchConfigLoading, + error: launchConfigError, request: fetchLaunchConfig, } = useRequest( useCallback(async () => { - const readLaunch = ['workflow_job', 'workflow_job_template'].includes( - jobType - ) - ? WorkflowJobTemplatesAPI.readLaunch(unifiedJobTemplate.id) - : JobTemplatesAPI.readLaunch(unifiedJobTemplate.id); - + const readLaunch = + nodeType === 'workflow_job_template' + ? WorkflowJobTemplatesAPI.readLaunch(unifiedJobTemplate.id) + : JobTemplatesAPI.readLaunch(unifiedJobTemplate.id); const { data } = await readLaunch; - return data; - }, [jobType, unifiedJobTemplate]), + }, [nodeType, unifiedJobTemplate.id]), {} ); + const { + result: nodeDetail, + isLoading: isNodeDetailLoading, + error: nodeDetailError, + request: fetchNodeDetail, + } = useRequest( + useCallback(async () => { + const { data } = await nodeAPI?.readDetail(unifiedJobTemplate.id); + return data; + }, [nodeAPI, unifiedJobTemplate.id]), + null + ); + useEffect(() => { - if ( - ['workflow_job', 'workflow_job_template', 'job', 'job_template'].includes( - jobType - ) - ) { + if (nodeType === 'workflow_job_template' || nodeType === 'job_template') { fetchLaunchConfig(); } - }, [jobType, fetchLaunchConfig]); + + if (unifiedJobTemplate.unified_job_type && nodeType !== 'approval') { + fetchNodeDetail(); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + useEffect(() => { + if (nodeDetail) { + dispatch({ + type: 'REFRESH_NODE', + node: { + nodeResource: nodeDetail, + }, + }); + } + }, [nodeDetail]); // eslint-disable-line react-hooks/exhaustive-deps const handleEdit = () => { dispatch({ type: 'SET_NODE_TO_VIEW', value: null }); @@ -56,11 +117,10 @@ function NodeViewModal({ i18n }) { }; let Content; - - if (isLoading) { + if (isLaunchConfigLoading || isNodeDetailLoading) { Content = ; - } else if (error) { - Content = ; + } else if (launchConfigError || nodeDetailError) { + Content = ; } else { Content = ( diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.test.jsx index f0a9fc5456..9026d1f575 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.test.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeViewModal.test.jsx @@ -11,6 +11,7 @@ import NodeViewModal from './NodeViewModal'; jest.mock('@api/models/JobTemplates'); jest.mock('@api/models/WorkflowJobTemplates'); WorkflowJobTemplatesAPI.readLaunch.mockResolvedValue({}); +WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({}); JobTemplatesAPI.readLaunch.mockResolvedValue({}); const dispatch = jest.fn();