diff --git a/awx/ui_next/src/screens/Job/Job.jsx b/awx/ui_next/src/screens/Job/Job.jsx index 48e4f1d4fa..b62e110494 100644 --- a/awx/ui_next/src/screens/Job/Job.jsx +++ b/awx/ui_next/src/screens/Job/Job.jsx @@ -20,13 +20,14 @@ import JobDetail from './JobDetail'; import JobOutput from './JobOutput'; import WorkflowDetail from './WorkflowDetail'; import { WorkflowOutput } from './WorkflowOutput'; +import useWsJob from './useWsJob'; import { JOB_TYPE_URL_SEGMENTS } from '../../constants'; function Job({ i18n, lookup, setBreadcrumb }) { const { id, type } = useParams(); const match = useRouteMatch(); - const { isLoading, error, request: fetchJob, result: job } = useRequest( + const { isLoading, error, request: fetchJob, result } = useRequest( useCallback(async () => { const { data } = await JobsAPI.readDetail(id, type); setBreadcrumb(data); @@ -39,6 +40,8 @@ function Job({ i18n, lookup, setBreadcrumb }) { fetchJob(); }, [fetchJob]); + const job = useWsJob(result); + let jobType; if (job) { jobType = JOB_TYPE_URL_SEGMENTS[job.type]; diff --git a/awx/ui_next/src/screens/Job/useWsJob.js b/awx/ui_next/src/screens/Job/useWsJob.js new file mode 100644 index 0000000000..c473039d2f --- /dev/null +++ b/awx/ui_next/src/screens/Job/useWsJob.js @@ -0,0 +1,53 @@ +import { useState, useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import useWebsocket from '../../util/useWebsocket'; +import { JobsAPI } from '../../api'; + +export default function useWsJob(initialJob) { + const { type } = useParams(); + const [job, setJob] = useState(initialJob); + const lastMessage = useWebsocket({ + jobs: ['status_changed'], + control: ['limit_reached_1'], + }); + + useEffect(() => { + setJob(initialJob); + }, [initialJob]); + + useEffect( + function parseWsMessage() { + async function fetchJob() { + const { data } = await JobsAPI.readDetail(job.id, type); + setJob(data); + } + + if (!job || lastMessage?.unified_job_id !== job.id) { + return; + } + + if ( + ['successful', 'failed', 'error', 'cancelled'].includes( + lastMessage.status + ) + ) { + fetchJob(); + } else { + setJob(updateJob(job, lastMessage)); + } + }, + [lastMessage] // eslint-disable-line react-hooks/exhaustive-deps + ); + + return job; +} + +function updateJob(job, message) { + const updatedJob = { + ...job, + finished: message.finished, + status: message.status, + }; + + return updatedJob; +}