Enhance GCodeFile, DeployJob, NewJob, and ControlPrinter components with slicer integration support

- Updated NewGCodeFile and NewJob components to include slicerIntegration, currentStep, and onStepChange props for improved workflow management.
- Modified DeployJob to handle printer online status and added slicerIntegration support for conditional rendering of actions and steps.
- Enhanced ControlPrinter to manage visibility of actions based on slicerIntegration, improving user experience in printer control.
- Refactored form handling to pass result objects to onOk callbacks, ensuring better data handling upon submission.
This commit is contained in:
Tom Butcher 2026-07-20 02:11:01 +01:00
parent def9b9aefb
commit d7ad2208d4
4 changed files with 202 additions and 80 deletions

View File

@ -1,35 +1,49 @@
import { useMemo } from 'react'
import PropTypes from 'prop-types'
import ObjectInfo from '../../common/ObjectInfo'
import NewObjectForm from '../../common/NewObjectForm'
import WizardView from '../../common/WizardView'
const NewGCodeFile = ({ onOk, defaultValues }) => {
const NewGCodeFile = ({
onOk,
defaultValues,
slicerIntegration = false,
shouldPrint = false,
currentStep,
onStepChange
}) => {
const initialValues = useMemo(
() => ({
state: { type: 'draft' },
...defaultValues
}),
[defaultValues]
)
return (
<NewObjectForm
type={'gcodeFile'}
defaultValues={{
state: { type: 'draft' },
...defaultValues
}}
>
<NewObjectForm type={'gcodeFile'} defaultValues={initialValues}>
{({ handleSubmit, submitLoading, objectData, formValid }) => {
const steps = [
{
title: 'Upload',
key: 'upload',
content: (
<ObjectInfo
type='gcodeFile'
column={1}
bordered={false}
isEditing={true}
required={true}
objectData={objectData}
visibleProperties={{ file: true }}
showLabels={false}
/>
)
},
...(!slicerIntegration
? [
{
title: 'Upload',
key: 'upload',
content: (
<ObjectInfo
type='gcodeFile'
column={1}
bordered={false}
isEditing={true}
required={true}
objectData={objectData}
visibleProperties={{ file: true }}
showLabels={false}
/>
)
}
]
: []),
{
title: 'Required',
key: 'required',
@ -73,10 +87,13 @@ const NewGCodeFile = ({ onOk, defaultValues }) => {
loading={submitLoading}
formValid={formValid}
title='New GCode File'
showSteps={!slicerIntegration || !shouldPrint}
currentStep={currentStep}
onStepChange={onStepChange}
onSubmit={async () => {
const result = await handleSubmit()
if (result) {
onOk()
onOk(result)
}
}}
/>
@ -89,7 +106,11 @@ const NewGCodeFile = ({ onOk, defaultValues }) => {
NewGCodeFile.propTypes = {
onOk: PropTypes.func.isRequired,
reset: PropTypes.bool,
defaultValues: PropTypes.object
defaultValues: PropTypes.object,
slicerIntegration: PropTypes.bool,
currentStep: PropTypes.number,
onStepChange: PropTypes.func,
shouldPrint: PropTypes.bool
}
export default NewGCodeFile

View File

@ -2,17 +2,20 @@ import { useState, useContext, useEffect, useCallback } from 'react'
import PropTypes from 'prop-types'
import WizardView from '../../common/WizardView'
import { ApiServerContext } from '../../context/ApiServerContext'
import { Flex, Typography } from 'antd'
import { Descriptions, Flex, Typography } from 'antd'
import ObjectTable from '../../common/ObjectTable'
import ObjectSelect from '../../common/ObjectSelect'
import ObjectProperty from '../../common/ObjectProperty'
const { Text } = Typography
const DeployJob = ({ onOk, objectData = undefined }) => {
const DeployJob = ({
onOk,
objectData = undefined,
slicerIntegration = false
}) => {
const [deployLoading, setDeployLoading] = useState(false)
const [job, setJob] = useState(objectData)
const [deployedSubJobsCount, setDeployedSubJobsCount] = useState(0)
const [subJobsCount, setSubJobsCount] = useState(999)
const [allPrintersOnline, setAllPrintersOnline] = useState(false)
const { sendObjectAction, fetchObjects } = useContext(ApiServerContext)
const handleDeploy = useCallback(async () => {
@ -51,21 +54,94 @@ const DeployJob = ({ onOk, objectData = undefined }) => {
}
}, [deployedSubJobsCount, subJobsCount, deployLoading, onOk])
useEffect(() => {
if (objectData?.printers) {
if (objectData.printers.every((printer) => printer.online)) {
setAllPrintersOnline(true)
} else {
setAllPrintersOnline(false)
}
} else {
setAllPrintersOnline(false)
}
}, [objectData])
console.log(objectData)
const steps = [
{
title: 'Confirm',
key: 'confirm',
content: (
<Flex vertical gap={'middle'} style={{ width: '100%' }}>
<Flex gap={'small'} align='center' style={{ width: '100%' }}>
<Text type='secondary'>Job:</Text>
<ObjectSelect
type={'job'}
style={{ flexGrow: 1 }}
value={objectData}
onChange={(newJob) => {
setJob(newJob)
}}
<Flex gap={'middle'} align='center' style={{ width: '100%' }}>
<Descriptions
column={1}
items={[
{
label: (
<Flex
align='center'
gap={'small'}
style={{ height: '100%' }}
>
<Text type='secondary'>Job</Text>
</Flex>
),
children: (
<div
style={{
flexGrow: 1,
marginLeft: '3px',
marginBottom: '1px'
}}
>
<ObjectProperty
type={'object'}
name={'job'}
objectData={{ job: objectData }}
value={(object) => object.job}
readOnly={true}
isEditing={true}
objectType={'job'}
onChange={(newJob) => {
setJob(newJob)
}}
/>
</div>
)
},
{
label: (
<Flex
align='center'
gap={'small'}
style={{ height: '100%' }}
>
<Text type='secondary'>Printers</Text>
</Flex>
),
children: (
<div
style={{
flexGrow: 1,
marginLeft: '3px',
marginBottom: '1px'
}}
>
<ObjectProperty
type={'objectList'}
name={'printers'}
objectData={{ printers: objectData.printers }}
value={(object) => object.printers}
readOnly={true}
isEditing={true}
objectType={'printer'}
/>
</div>
)
}
]}
/>
</Flex>
@ -74,11 +150,11 @@ const DeployJob = ({ onOk, objectData = undefined }) => {
scrollHeight={'200px'}
visibleColumns={{
printer: false,
'job._id': false,
'printer._id': false
job: false
}}
masterFilter={{ 'job._id': job?._id }}
size={'small'}
showActions={!slicerIntegration}
/>
</Flex>
)
@ -89,9 +165,13 @@ const DeployJob = ({ onOk, objectData = undefined }) => {
<WizardView
steps={steps}
loading={deployLoading}
formValid={objectData != undefined}
formValid={objectData != undefined && allPrintersOnline}
title='Deploy Job'
showSteps={false}
showSkipButton={slicerIntegration}
onSkip={() => {
onOk()
}}
submitText='Deploy'
progress={(deployedSubJobsCount / subJobsCount) * 100}
onSubmit={() => {
@ -104,7 +184,8 @@ const DeployJob = ({ onOk, objectData = undefined }) => {
DeployJob.propTypes = {
onOk: PropTypes.func.isRequired,
objectData: PropTypes.object,
reset: PropTypes.bool
reset: PropTypes.bool,
slicerIntegration: PropTypes.bool
}
export default DeployJob

View File

@ -1,17 +1,26 @@
import { useMemo } from 'react'
import PropTypes from 'prop-types'
import ObjectInfo from '../../common/ObjectInfo'
import NewObjectForm from '../../common/NewObjectForm'
import WizardView from '../../common/WizardView'
const NewJob = ({ onOk, defaultValues }) => {
const NewJob = ({
onOk,
defaultValues,
slicerIntegration = false,
currentStep,
onStepChange
}) => {
const initialValues = useMemo(
() => ({
state: { type: 'draft' },
...defaultValues
}),
[defaultValues]
)
return (
<NewObjectForm
type={'job'}
defaultValues={{
state: { type: 'draft' },
...defaultValues
}}
>
<NewObjectForm type={'job'} defaultValues={initialValues}>
{({ handleSubmit, submitLoading, objectData, formValid }) => {
const steps = [
{
@ -59,10 +68,17 @@ const NewJob = ({ onOk, defaultValues }) => {
loading={submitLoading}
formValid={formValid}
title='New Job'
showSteps={!slicerIntegration}
currentStep={currentStep}
onStepChange={onStepChange}
showSkipButton={slicerIntegration}
onSkip={() => {
onOk(null)
}}
onSubmit={async () => {
const result = await handleSubmit()
if (result) {
onOk()
onOk(result)
}
}}
/>
@ -75,7 +91,10 @@ const NewJob = ({ onOk, defaultValues }) => {
NewJob.propTypes = {
onOk: PropTypes.func.isRequired,
reset: PropTypes.bool,
defaultValues: PropTypes.object
defaultValues: PropTypes.object,
slicerIntegration: PropTypes.bool,
currentStep: PropTypes.number,
onStepChange: PropTypes.func
}
export default NewJob

View File

@ -9,9 +9,9 @@ import InfoCollapse from '../../common/InfoCollapse.jsx'
import ViewButton from '../../common/ViewButton.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx'
import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx'
import PropTypes from 'prop-types'
import ObjectInfo from '../../common/ObjectInfo.jsx'
import PrinterIcon from '../../../Icons/PrinterIcon.jsx'
@ -35,7 +35,7 @@ import ScrollBox from '../../common/ScrollBox.jsx'
const log = loglevel.getLogger('ControlPrinter')
log.setLevel(config.logLevel)
const ControlPrinter = () => {
const ControlPrinter = ({ slicerIntegration = false }) => {
const location = useLocation()
const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null)
@ -226,7 +226,11 @@ const ControlPrinter = () => {
type='printer'
id={printerId}
disabled={objectFormState.loading}
visibleActions={{ edit: false }}
visibleActions={{
edit: false,
info: !slicerIntegration,
control: !slicerIntegration
}}
objectData={objectFormState.objectData}
/>
<ViewButton
@ -275,24 +279,6 @@ const ControlPrinter = () => {
/>
</Space>
</Space>
<Space>
<EditButtons
isEditing={objectFormState.isEditing}
handleUpdate={() => {
actionHandlerRef.current.callAction('finishEdit')
}}
cancelEditing={() => {
actionHandlerRef.current.callAction('cancelEdit')
}}
startEditing={() => {
actionHandlerRef.current.callAction('edit')
}}
editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid}
disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading}
/>
</Space>
</Flex>
<ScrollBox>
@ -353,11 +339,16 @@ const ControlPrinter = () => {
currentSubJob: false,
'currentSubJob._id': false,
createdAt: false,
updatedAt: false
updatedAt: false,
state: !slicerIntegration,
name: !slicerIntegration
}}
objectPropertyProps={{
showHyperlink: !slicerIntegration
}}
objectData={printerObjectData}
type='printer'
labelWidth='100px'
labelWidth='120px'
/>
)
}}
@ -386,12 +377,15 @@ const ControlPrinter = () => {
<ObjectInfo
loading={jobObjectLoading}
column={sideBarVisible ? 1 : undefined}
showHyperlink={true}
showHyperlink={!slicerIntegration}
visibleProperties={{
printers: false,
createdAt: false,
finishedAt: false
}}
objectPropertyProps={{
showHyperlink: !slicerIntegration
}}
objectData={jobObjectData}
type='job'
/>
@ -428,12 +422,15 @@ const ControlPrinter = () => {
<ObjectInfo
loading={subJobObjectLoading}
column={sideBarVisible ? 1 : undefined}
showHyperlink={true}
showHyperlink={!slicerIntegration}
visibleProperties={{
printers: false,
createdAt: false,
finishedAt: false
}}
objectPropertyProps={{
showHyperlink: !slicerIntegration
}}
objectData={subJobObjectData}
type='subJob'
/>
@ -474,7 +471,7 @@ const ControlPrinter = () => {
<ObjectInfo
loading={filamentStockObjectLoading}
column={sideBarVisible ? 1 : undefined}
showHyperlink={true}
showHyperlink={!slicerIntegration}
visibleProperties={{
updatedAt: false,
createdAt: false
@ -558,4 +555,8 @@ const ControlPrinter = () => {
)
}
ControlPrinter.propTypes = {
slicerIntegration: PropTypes.bool
}
export default ControlPrinter