Enhance NewDocumentJob Component with Job Update Handling and Progress Display
Some checks reported errors
farmcontrol/farmcontrol-ui/pipeline/head Something is wrong with the build of this commit

- Integrated ProgressDisplay component to manage job deployment progress within the NewDocumentJob component.
- Added subscription to object updates for real-time job status tracking, improving user feedback during document processing.
- Refactored state management to handle job updates and deployment actions more effectively, enhancing overall functionality and user experience.
This commit is contained in:
Tom Butcher 2026-08-22 14:02:29 +01:00
parent 8035c2ba59
commit 7833b1dbce

View File

@ -3,14 +3,72 @@ import ObjectInfo from '../../common/ObjectInfo'
import NewObjectForm from '../../common/NewObjectForm' import NewObjectForm from '../../common/NewObjectForm'
import WizardView from '../../common/WizardView' import WizardView from '../../common/WizardView'
import TemplatePreview from '../../common/TemplatePreview' import TemplatePreview from '../../common/TemplatePreview'
import ProgressDisplay from '../../common/ProgressDisplay'
import { ApiServerContext } from '../../context/ApiServerContext' import { ApiServerContext } from '../../context/ApiServerContext'
import { useContext, useRef, useState } from 'react' import { useCallback, useContext, useEffect, useRef, useState } from 'react'
import { Modal } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
const NewDocumentJob = ({ onOk, defaultValues = {} }) => { const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
const { sendObjectAction, downloadTemplate, formatFileName } = const {
useContext(ApiServerContext) sendObjectAction,
downloadTemplate,
formatFileName,
subscribeToObjectUpdates,
connected
} = useContext(ApiServerContext)
const [downloading, setDownloading] = useState(false) const [downloading, setDownloading] = useState(false)
const [deployingJob, setDeployingJob] = useState(null)
const onOkRef = useRef(onOk)
const pendingJobRef = useRef(null)
const deploySentRef = useRef(false)
const sendObjectActionRef = useRef(sendObjectAction)
onOkRef.current = onOk
sendObjectActionRef.current = sendObjectAction
const deployingJobId = deployingJob?._id
? String(deployingJob._id).toLowerCase()
: null
const handleJobUpdate = useCallback((updatedJob) => {
setDeployingJob((prev) => (prev ? { ...prev, ...updatedJob } : updatedJob))
}, [])
useEffect(() => {
if (!deployingJobId || connected != true) {
return
}
const unsubscribe = subscribeToObjectUpdates(
deployingJobId,
'documentJob',
handleJobUpdate
)
if (!deploySentRef.current && pendingJobRef.current) {
deploySentRef.current = true
sendObjectActionRef.current(
pendingJobRef.current.documentPrinter._id,
'documentPrinter',
{
type: 'deploy',
data: pendingJobRef.current
}
)
}
return () => {
if (unsubscribe) unsubscribe()
}
}, [deployingJobId, connected, subscribeToObjectUpdates, handleJobUpdate])
useEffect(() => {
const stateType = deployingJob?.state?.type
if (stateType === 'queued' || stateType === 'error') {
onOkRef.current?.()
}
}, [deployingJob?.state?.type])
// Capture initial default values so later prop changes don't re-initialize the form // Capture initial default values so later prop changes don't re-initialize the form
const defaultValuesRef = useRef({ const defaultValuesRef = useRef({
@ -20,154 +78,175 @@ const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
}) })
return ( return (
<NewObjectForm <>
type={'documentJob'} <NewObjectForm
defaultValues={defaultValuesRef.current} type={'documentJob'}
> defaultValues={defaultValuesRef.current}
{({ handleSubmit, submitLoading, objectData, formValid }) => { >
const steps = [ {({ handleSubmit, submitLoading, objectData, formValid }) => {
{ const steps = [
title: 'Required', {
key: 'required', title: 'Required',
content: ( key: 'required',
<ObjectInfo content: (
type='documentJob' <ObjectInfo
column={1} type='documentJob'
visibleProperties={{ name: false }} column={1}
bordered={false} visibleProperties={{ name: false }}
labelWidth={115} bordered={false}
isEditing={true} labelWidth={115}
required={true} isEditing={true}
objectData={objectData} required={true}
/> objectData={objectData}
)
}
]
const fileName =
formatFileName(
objectData?.name + ' ' + dayjs().format('YYYY-MM-DD HH:mm:ss')
) || 'document'
return (
<WizardView
steps={steps}
submitText='Print'
title={'Print Document'}
formValid={formValid}
loading={submitLoading}
disabled={downloading}
sideBarGrow={true}
sideBar={
<div
style={{
height: 'calc(100vh - 240px)',
flexGrow: 1,
minWidth: 0
}}
>
<TemplatePreview
objectData={objectData?.object}
documentTemplate={objectData?.documentTemplate}
/> />
</div> )
} }
onSubmit={async () => { ]
const newDocumentJob = await handleSubmit() const fileName =
if (newDocumentJob) { formatFileName(
await sendObjectAction( objectData?.name + ' ' + dayjs().format('YYYY-MM-DD HH:mm:ss')
newDocumentJob.documentPrinter._id, ) || 'document'
'documentPrinter', return (
{ <WizardView
type: 'deploy', steps={steps}
data: newDocumentJob submitText='Print'
} title={'Print Document'}
) formValid={formValid}
if (onOk) { loading={submitLoading}
onOk() disabled={downloading}
sideBarGrow={true}
sideBar={
<div
style={{
height: 'calc(100vh - 240px)',
flexGrow: 1,
minWidth: 0
}}
>
<TemplatePreview
objectData={objectData?.object}
documentTemplate={objectData?.documentTemplate}
/>
</div>
}
onSubmit={async () => {
const newDocumentJob = await handleSubmit()
if (!newDocumentJob?._id) {
return
} }
}
}} pendingJobRef.current = newDocumentJob
actions={[ deploySentRef.current = false
{ setDeployingJob({
label: 'Download', ...newDocumentJob,
steps: ['required'], state: { type: 'deploying', progress: 0 }
loading: downloading == true, })
disabled: downloading == true || submitLoading == true, }}
children: [ actions={[
{ {
label: 'PDF', label: 'Download',
key: 'pdf', steps: ['required'],
onClick: () => { loading: downloading == true,
setDownloading(true) disabled: downloading == true || submitLoading == true,
downloadTemplate( children: [
objectData.documentTemplate._id, {
objectData.documentTemplate.content, label: 'PDF',
objectData.object, key: 'pdf',
fileName, onClick: () => {
'pdf', setDownloading(true)
() => { downloadTemplate(
setDownloading(false) objectData.documentTemplate._id,
} objectData.documentTemplate.content,
) objectData.object,
fileName,
'pdf',
() => {
setDownloading(false)
}
)
}
},
{
label: 'PNG',
key: 'png',
onClick: () => {
setDownloading(true)
downloadTemplate(
objectData.documentTemplate._id,
objectData.documentTemplate.content,
objectData.object,
fileName,
'png',
() => {
setDownloading(false)
}
)
}
},
{
label: 'JPEG',
key: 'jpeg',
onClick: () => {
setDownloading(true)
downloadTemplate(
objectData.documentTemplate._id,
objectData.documentTemplate.content,
objectData.object,
fileName,
'jpeg',
() => {
setDownloading(false)
}
)
}
},
{
label: 'SVG',
key: 'svg',
onClick: () => {
setDownloading(true)
downloadTemplate(
objectData.documentTemplate._id,
objectData.documentTemplate.content,
objectData.object,
fileName,
'svg',
() => {
setDownloading(false)
}
)
}
} }
}, ]
{ }
label: 'PNG', ]}
key: 'png', />
onClick: () => { )
setDownloading(true) }}
downloadTemplate( </NewObjectForm>
objectData.documentTemplate._id, <Modal
objectData.documentTemplate.content, open={Boolean(deployingJob)}
objectData.object, footer={null}
fileName, closable={false}
'png', maskClosable={false}
() => { centered
setDownloading(false) destroyOnHidden={true}
} zIndex={2000}
) width={320}
} getContainer={() => document.body}
}, >
{ <ProgressDisplay
label: 'JPEG', percent={Math.round(
key: 'jpeg', (Number(deployingJob?.state?.progress) || 0) * 100
onClick: () => { )}
setDownloading(true) status={
downloadTemplate( deployingJob?.state?.type === 'error' ? 'exception' : 'active'
objectData.documentTemplate._id, }
objectData.documentTemplate.content, >
objectData.object, Please wait...
fileName, </ProgressDisplay>
'jpeg', </Modal>
() => { </>
setDownloading(false)
}
)
}
},
{
label: 'SVG',
key: 'svg',
onClick: () => {
setDownloading(true)
downloadTemplate(
objectData.documentTemplate._id,
objectData.documentTemplate.content,
objectData.object,
fileName,
'svg',
() => {
setDownloading(false)
}
)
}
}
]
}
]}
/>
)
}}
</NewObjectForm>
) )
} }