Implemented DocumentPrinters and DocumentJobs

This commit is contained in:
Tom Butcher 2025-11-29 01:24:57 +00:00
parent 0594cf82cd
commit df85d99aaf
8 changed files with 165 additions and 55 deletions

View File

@ -68,12 +68,14 @@ const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
} }
onSubmit={async () => { onSubmit={async () => {
const newDocumentJob = await handleSubmit() const newDocumentJob = await handleSubmit()
if (newDocumentJob.sendToFile == true) { await sendObjectAction(
sendObjectAction(newDocumentJob._id, 'documentJob', { newDocumentJob.documentPrinter._id,
type: 'print', 'documentPrinter',
{
type: 'deploy',
data: newDocumentJob data: newDocumentJob
})
} }
)
if (onOk) { if (onOk) {
onOk() onOk()
} }

View File

@ -22,6 +22,7 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import HostOTP from './HostOtp.jsx' import HostOTP from './HostOtp.jsx'
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx' import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import PrinterIcon from '../../../Icons/PrinterIcon.jsx' import PrinterIcon from '../../../Icons/PrinterIcon.jsx'
import DocumentPrinterIcon from '../../../Icons/DocumentPrinterIcon.jsx'
const log = loglevel.getLogger('HostInfo') const log = loglevel.getLogger('HostInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -34,6 +35,7 @@ const HostInfo = () => {
const [collapseState, updateCollapseState] = useCollapseState('HostInfo', { const [collapseState, updateCollapseState] = useCollapseState('HostInfo', {
info: true, info: true,
printers: true, printers: true,
documentPrinters: true,
notes: true, notes: true,
auditLogs: true auditLogs: true
}) })
@ -95,6 +97,7 @@ const HostInfo = () => {
items={[ items={[
{ key: 'info', label: 'Host Information' }, { key: 'info', label: 'Host Information' },
{ key: 'printers', label: 'Printers' }, { key: 'printers', label: 'Printers' },
{ key: 'documentPrinters', label: 'Document Printers' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
]} ]}
@ -149,7 +152,6 @@ const HostInfo = () => {
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
onStateChange={(state) => { onStateChange={(state) => {
console.log('Got edit form state change', state)
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
> >
@ -188,6 +190,28 @@ const HostInfo = () => {
/> />
)} )}
</InfoCollapse> </InfoCollapse>
<InfoCollapse
title='Document Printers'
icon={<DocumentPrinterIcon />}
active={collapseState.documentPrinters}
onToggle={(expanded) =>
updateCollapseState('documentPrinters', expanded)
}
collapseKey='documentPrinters'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='documentPrinter'
masterFilter={{ 'host._id': hostId }}
visibleColumns={{
host: false,
'host._id': false
}}
/>
)}
</InfoCollapse>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'

View File

@ -37,6 +37,7 @@ import ObjectDisplay from './ObjectDisplay'
import ObjectTypeSelect from './ObjectTypeSelect' import ObjectTypeSelect from './ObjectTypeSelect'
import ObjectTypeDisplay from './ObjectTypeDisplay' import ObjectTypeDisplay from './ObjectTypeDisplay'
import CodeBlockEditor from './CodeBlockEditor' import CodeBlockEditor from './CodeBlockEditor'
import CustomSelect from './CustomSelect'
import StateDisplay from './StateDisplay' import StateDisplay from './StateDisplay'
import AlertsDisplay from './AlertsDisplay' import AlertsDisplay from './AlertsDisplay'
import FileUpload from './FileUpload' import FileUpload from './FileUpload'
@ -84,6 +85,7 @@ const ObjectProperty = ({
options = [], options = [],
roundNumber = false, roundNumber = false,
showHyperlink, showHyperlink,
showSince,
...rest ...rest
}) => { }) => {
if (value && typeof value == 'function' && objectData) { if (value && typeof value == 'function' && objectData) {
@ -117,6 +119,9 @@ const ObjectProperty = ({
if (masterFilter && typeof masterFilter == 'function' && objectData) { if (masterFilter && typeof masterFilter == 'function' && objectData) {
masterFilter = masterFilter(objectData) masterFilter = masterFilter(objectData)
} }
if (options && typeof options == 'function' && objectData) {
options = options(objectData)
}
if (!value) { if (!value) {
value = getPropertyValue(objectData, name) value = getPropertyValue(objectData, name)
@ -169,8 +174,9 @@ const ObjectProperty = ({
) )
} }
case 'select': { case 'select': {
const selectValue = options.find((option) => option.value === value) if (options && Array.isArray(options)) {
if (selectValue) { const selectValue =
options.find((option) => option.value === value) || 'n/a'
return <Text {...textParams}>{selectValue.label}</Text> return <Text {...textParams}>{selectValue.label}</Text>
} else { } else {
return ( return (
@ -206,7 +212,9 @@ const ObjectProperty = ({
} }
case 'dateTime': { case 'dateTime': {
if (value != null) { if (value != null) {
return <TimeDisplay dateTime={value} {...rest} /> return (
<TimeDisplay dateTime={value} showSince={showSince} {...rest} />
)
} else { } else {
return ( return (
<Text type='secondary' {...textParams}> <Text type='secondary' {...textParams}>
@ -249,7 +257,7 @@ const ObjectProperty = ({
) )
} else { } else {
var roundedValue = value var roundedValue = value
if (roundNumber != false) { if (roundNumber != false && typeof value === 'number') {
roundedValue = value.toFixed(roundNumber) roundedValue = value.toFixed(roundNumber)
} }
@ -508,7 +516,10 @@ const ObjectProperty = ({
// Editable mode: wrap in Form.Item // Editable mode: wrap in Form.Item
// Merge required rule if needed // Merge required rule if needed
let mergedFormItemProps = { ...formItemProps, style: { flexGrow: 1 } } let mergedFormItemProps = {
...formItemProps,
style: { flexGrow: 1, width: '100%' }
}
if (required && disabled == false) { if (required && disabled == false) {
let rules let rules
if (mergedFormItemProps.rules) { if (mergedFormItemProps.rules) {
@ -575,11 +586,10 @@ const ObjectProperty = ({
case 'select': case 'select':
return ( return (
<Form.Item name={formItemName} {...mergedFormItemProps}> <Form.Item name={formItemName} {...mergedFormItemProps}>
<Select <CustomSelect
defaultValue={value}
placeholder={'Select a ' + label.toLowerCase() + '...'} placeholder={'Select a ' + label.toLowerCase() + '...'}
disabled={disabled} disabled={disabled}
options={options} options={Array.isArray(options) ? options : []}
/> />
</Form.Item> </Form.Item>
) )
@ -804,7 +814,8 @@ ObjectProperty.propTypes = {
previewOpen: PropTypes.bool, previewOpen: PropTypes.bool,
showPreview: PropTypes.bool, showPreview: PropTypes.bool,
showHyperlink: PropTypes.bool, showHyperlink: PropTypes.bool,
options: PropTypes.array options: PropTypes.array,
showSince: PropTypes.bool
} }
export default ObjectProperty export default ObjectProperty

View File

@ -1,9 +1,18 @@
// PrinterSelect.js // PrinterSelect.js
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Progress, Flex, Space } from 'antd' import { Progress, Flex, Space, Modal, Button, Typography } from 'antd'
import StateTag from './StateTag' import StateTag from './StateTag'
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import { useState } from 'react'
const StateDisplay = ({ state, showProgress = true, showState = true }) => { const { Text } = Typography
const StateDisplay = ({
state,
showProgress = true,
showState = true,
showMessage = true
}) => {
const loadingProgressTypes = [ const loadingProgressTypes = [
'loading', 'loading',
'processing', 'processing',
@ -15,8 +24,9 @@ const StateDisplay = ({ state, showProgress = true, showState = true }) => {
type: 'unknown', type: 'unknown',
progress: 0 progress: 0
} }
const [showMessageModal, setShowMessageModal] = useState(false)
return ( return (
<>
<Flex gap='small' align={'center'}> <Flex gap='small' align={'center'}>
{showState && ( {showState && (
<Space> <Space>
@ -34,14 +44,34 @@ const StateDisplay = ({ state, showProgress = true, showState = true }) => {
style={{ width: '150px', marginBottom: '2px' }} style={{ width: '150px', marginBottom: '2px' }}
/> />
) : null} ) : null}
{showMessage && currentState?.message && (
<Button
type='text'
size='small'
style={{ padding: '4px' }}
onClick={() => setShowMessageModal(true)}
>
<InfoCircleIcon />
</Button>
)}
</Flex> </Flex>
<Modal
open={showMessageModal}
onCancel={() => setShowMessageModal(false)}
footer={null}
>
<Text>{currentState.message}</Text>
</Modal>
</>
) )
} }
StateDisplay.propTypes = { StateDisplay.propTypes = {
state: PropTypes.object, state: PropTypes.object,
showProgress: PropTypes.bool, showProgress: PropTypes.bool,
showState: PropTypes.bool showState: PropTypes.bool,
showMessage: PropTypes.bool
} }
export default StateDisplay export default StateDisplay

View File

@ -32,6 +32,14 @@ const StateTag = ({ state, showBadge = true, style = {} }) => {
status = 'warning' status = 'warning'
text = 'Initializing' text = 'Initializing'
break break
case 'connecting':
status = 'warning'
text = 'Connecting'
break
case 'deploying':
status = 'warning'
text = 'Deploying'
break
case 'printing': case 'printing':
status = 'processing' status = 'processing'
text = 'Printing' text = 'Printing'

View File

@ -337,8 +337,6 @@ const ApiServerProvider = ({ children }) => {
const callbacks = subscribedCallbacksRef.current const callbacks = subscribedCallbacksRef.current
.get(objectType) .get(objectType)
.filter((cb) => cb !== callback) .filter((cb) => cb !== callback)
console.log('API: CALLBACKS', callbacks)
if (callbacks.length === 0) { if (callbacks.length === 0) {
subscribedCallbacksRef.current.delete(objectType) subscribedCallbacksRef.current.delete(objectType)
socketRef.current.emit('unsubscribeObjectTypeUpdate', { socketRef.current.emit('unsubscribeObjectTypeUpdate', {

View File

@ -84,10 +84,10 @@ export const DocumentPrinter = {
readOnly: true readOnly: true
}, },
{ {
name: 'active', name: 'connectedAt',
label: 'Active', label: 'Connected At',
type: 'bool', type: 'dateTime',
required: true readOnly: true
}, },
{ {
name: 'online', name: 'online',
@ -95,6 +95,12 @@ export const DocumentPrinter = {
type: 'bool', type: 'bool',
readOnly: true readOnly: true
}, },
{
name: 'active',
label: 'Active',
type: 'bool',
required: true
},
{ {
name: 'host', name: 'host',
label: 'Host', label: 'Host',
@ -111,16 +117,6 @@ export const DocumentPrinter = {
showCopy: true, showCopy: true,
showHyperlink: true showHyperlink: true
}, },
{
name: 'connection.mode',
label: 'Mode',
type: 'select',
options: [
{ label: 'Network', value: 'network' },
{ label: 'Serial', value: 'serial' }
],
required: true
},
{ {
name: 'connection.interface', name: 'connection.interface',
label: 'Interface', label: 'Interface',
@ -132,12 +128,43 @@ export const DocumentPrinter = {
], ],
required: true required: true
}, },
{
name: 'connection.protocol',
label: 'Protocol',
type: 'select',
options: (objectData) => {
if (objectData?.connection?.interface == 'cups') {
return [
{ label: 'IPP', value: 'ipp' },
{ label: 'HTTP', value: 'http' }
]
}
return [
{ label: 'TCP', value: 'tcp' },
{ label: 'Serial', value: 'serial' },
{ label: 'System', value: 'system' }
]
},
required: true
},
{ {
name: 'connection.host', name: 'connection.host',
label: 'Connection String', label: 'Host Name',
type: 'text', type: 'text',
required: true required: true
}, },
{
name: 'connection.port',
label: 'Port',
type: 'number',
required: false,
disabled: (objectData) => {
return (
objectData?.connection?.protocol == 'system' ||
objectData?.connection?.protocol == 'serial'
)
}
},
{ {
name: 'currentDocumentSize', name: 'currentDocumentSize',
label: 'Current Document Size', label: 'Current Document Size',

View File

@ -95,7 +95,17 @@ export const DocumentSize = {
required: true, required: true,
columnWidth: 150, columnWidth: 150,
type: 'number', type: 'number',
suffix: 'mm' suffix: 'mm',
disabled: (objectData) => {
return objectData.infiniteHeight
}
},
{
name: 'infiniteHeight',
label: 'Infinite Height',
required: true,
columnWidth: 150,
type: 'bool'
} }
] ]
} }