webpack/components/extensions/HostDetails/Tabs/RemoteExecutionHooks.js
import { useState, useEffect, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { propsToCamelCase } from 'foremanReact/common/helpers';
import { deleteToast } from 'foremanReact/components/ToastsList/slice';
import { startPollingJob, stopPollingJob } from './RemoteExecutionActions';
import { renderRexJobFailedToast, renderRexJobStartedToast, renderRexJobSucceededToast } from '../../../../scenes/Tasks/helpers';
export const useRexJobPolling = (initialAction, successAction = null, failureAction = null) => {
const [isPolling, setIsPolling] = useState(null);
const [succeeded, setSucceeded] = useState(null);
const [rexJobId, setRexJobId] = useState(null);
// A value that only changes when the job succeeds. Pass to TableWrapper as an additionalListener
// to reload results.
const [lastCompletedJob, setLastCompletedJob] = useState(null);
const dispatch = useDispatch();
const stopRexJobPolling = useCallback(({ jobId, statusLabel }) => {
if (statusLabel) setIsPolling(false);
if (statusLabel === 'succeeded') {
setSucceeded(true);
setLastCompletedJob(jobId);
} else {
setSucceeded(false);
}
dispatch(stopPollingJob({ key: `REX_JOB_POLLING_${jobId}` }));
dispatch(deleteToast(`REX_TOAST_${jobId}`));
}, [dispatch]);
const tick = (resp) => {
const data = resp?.data?.data || resp?.data;
const { statusLabel, id, description } = propsToCamelCase(data);
if (!id) setRexJobId(id);
if (statusLabel && statusLabel !== 'running') {
stopRexJobPolling({ jobId: id, statusLabel });
if (statusLabel === 'succeeded') {
renderRexJobSucceededToast({ id, description });
if (successAction) dispatch(typeof successAction === 'function' ? successAction() : successAction);
} else {
renderRexJobFailedToast({ id, description });
if (failureAction) dispatch(typeof failureAction === 'function' ? failureAction() : failureAction);
}
}
};
const startRexJobPolling = ({ jobId }) => {
dispatch(startPollingJob({ key: `REX_JOB_POLLING_${jobId}`, jobId, handleSuccess: tick }));
};
const pollingStarted = !!(isPolling || succeeded);
const dispatchInitialAction = (...args) => {
const originalAction = typeof initialAction === 'function' ? initialAction(...args) : initialAction;
const modifiedAction = {
...originalAction,
payload: {
...originalAction.payload,
handleSuccess: (resp) => {
const jobId = resp?.data?.id;
if (!jobId) return;
renderRexJobStartedToast({ key: `REX_TOAST_${jobId}`, ...resp.data });
startRexJobPolling({ jobId });
},
},
};
setIsPolling(true);
dispatch(modifiedAction);
};
// eslint-disable-next-line arrow-body-style
useEffect(() => {
// clean up polling when component unmounts
return function cleanupRexPolling() {
if (rexJobId) stopRexJobPolling({ jobId: rexJobId });
};
}, [rexJobId, stopRexJobPolling]);
return ({
pollingStarted,
isPolling,
succeeded,
rexJobId,
lastCompletedJob,
startRexJobPolling,
triggerJobStart: dispatchInitialAction,
});
};
export default useRexJobPolling;