Compare commits
No commits in common. "97f0c816adc96a4e9d0a19d632730942a20ac4fe" and "1e7697f1d590b997c4d7ea294215ce1723f4ab48" have entirely different histories.
97f0c816ad
...
1e7697f1d5
@ -314,7 +314,3 @@ body {
|
|||||||
.ant-select-selection-item .ant-tag {
|
.ant-select-selection-item .ant-tag {
|
||||||
margin-left: 1px !important;
|
margin-left: 1px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-badge.ant-badge-status {
|
|
||||||
line-height: 18.5px;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -68,14 +68,12 @@ const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
|
|||||||
}
|
}
|
||||||
onSubmit={async () => {
|
onSubmit={async () => {
|
||||||
const newDocumentJob = await handleSubmit()
|
const newDocumentJob = await handleSubmit()
|
||||||
await sendObjectAction(
|
if (newDocumentJob.sendToFile == true) {
|
||||||
newDocumentJob.documentPrinter._id,
|
sendObjectAction(newDocumentJob._id, 'documentJob', {
|
||||||
'documentPrinter',
|
type: 'print',
|
||||||
{
|
|
||||||
type: 'deploy',
|
|
||||||
data: newDocumentJob
|
data: newDocumentJob
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
|
||||||
if (onOk) {
|
if (onOk) {
|
||||||
onOk()
|
onOk()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ 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)
|
||||||
@ -35,7 +34,6 @@ 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
|
||||||
})
|
})
|
||||||
@ -97,7 +95,6 @@ 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' }
|
||||||
]}
|
]}
|
||||||
@ -152,6 +149,7 @@ 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 }))
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -190,28 +188,6 @@ 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'
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
import { useEffect, useRef } from 'react'
|
|
||||||
import { Select } from 'antd'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const CustomSelect = ({
|
|
||||||
placeholder,
|
|
||||||
disabled,
|
|
||||||
options = [],
|
|
||||||
value,
|
|
||||||
onChange,
|
|
||||||
...rest
|
|
||||||
}) => {
|
|
||||||
const prevOptionsRef = useRef(options)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Check if options have changed
|
|
||||||
const optionsChanged =
|
|
||||||
JSON.stringify(prevOptionsRef.current) !== JSON.stringify(options)
|
|
||||||
|
|
||||||
if (optionsChanged && value !== undefined && value !== null) {
|
|
||||||
// Check if current value exists in new options
|
|
||||||
const valueExists =
|
|
||||||
Array.isArray(options) &&
|
|
||||||
options.some((option) => option.value === value)
|
|
||||||
|
|
||||||
// If value doesn't exist in new options, clear it
|
|
||||||
if (!valueExists && onChange) {
|
|
||||||
onChange(undefined)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the ref with current options
|
|
||||||
prevOptionsRef.current = options
|
|
||||||
}, [options, value, onChange])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
placeholder={placeholder}
|
|
||||||
disabled={disabled}
|
|
||||||
options={Array.isArray(options) ? options : []}
|
|
||||||
value={value}
|
|
||||||
onChange={onChange}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomSelect.propTypes = {
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
options: PropTypes.array,
|
|
||||||
value: PropTypes.any,
|
|
||||||
onChange: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CustomSelect
|
|
||||||
@ -30,15 +30,13 @@ import { getModelByName } from '../../../database/ObjectModels'
|
|||||||
const ObjectForm = forwardRef(
|
const ObjectForm = forwardRef(
|
||||||
({ id, type, style, children, onEdit, onStateChange }, ref) => {
|
({ id, type, style, children, onEdit, onStateChange }, ref) => {
|
||||||
const [objectData, setObjectData] = useState(null)
|
const [objectData, setObjectData] = useState(null)
|
||||||
const serverObjectData = useRef(null)
|
const [serverObjectData, setServerObjectData] = useState(null)
|
||||||
const onStateChangeRef = useRef(onStateChange)
|
|
||||||
const [fetchLoading, setFetchLoading] = useState(true)
|
const [fetchLoading, setFetchLoading] = useState(true)
|
||||||
const [editLoading, setEditLoading] = useState(false)
|
const [editLoading, setEditLoading] = useState(false)
|
||||||
const [lock, setLock] = useState({})
|
const [lock, setLock] = useState({})
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const [isEditing, setIsEditing] = useState(false)
|
const [isEditing, setIsEditing] = useState(false)
|
||||||
const [formValid, setFormValid] = useState(false)
|
const [formValid, setFormValid] = useState(false)
|
||||||
|
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
const formUpdateValues = Form.useWatch([], form)
|
const formUpdateValues = Form.useWatch([], form)
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
@ -143,32 +141,26 @@ const ObjectForm = forwardRef(
|
|||||||
// Validate form on change (debounced to avoid heavy work on every keystroke)
|
// Validate form on change (debounced to avoid heavy work on every keystroke)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
const currentFormValues = form.getFieldsValue()
|
|
||||||
const mergedObjectData = {
|
|
||||||
...serverObjectData.current,
|
|
||||||
...currentFormValues
|
|
||||||
}
|
|
||||||
|
|
||||||
form
|
form
|
||||||
.validateFields({ validateOnly: true })
|
.validateFields({ validateOnly: true })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setFormValid(true)
|
setFormValid(true)
|
||||||
onStateChangeRef.current({
|
onStateChange({
|
||||||
formValid: true,
|
formValid: true,
|
||||||
objectData: mergedObjectData
|
objectData: { ...serverObjectData, ...form.getFieldsValue() }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setFormValid(false)
|
setFormValid(false)
|
||||||
onStateChangeRef.current({
|
onStateChange({
|
||||||
formValid: false,
|
formValid: false,
|
||||||
objectData: mergedObjectData
|
objectData: { ...serverObjectData, ...form.getFieldsValue() }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, 150)
|
}, 150)
|
||||||
|
|
||||||
return () => clearTimeout(timeoutId)
|
return () => clearTimeout(timeoutId)
|
||||||
}, [form, formUpdateValues])
|
}, [form, formUpdateValues, onStateChange, serverObjectData])
|
||||||
|
|
||||||
// Cleanup on unmount
|
// Cleanup on unmount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -193,13 +185,13 @@ const ObjectForm = forwardRef(
|
|||||||
const handleFetchObject = useCallback(async () => {
|
const handleFetchObject = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setFetchLoading(true)
|
setFetchLoading(true)
|
||||||
onStateChangeRef.current({ loading: true })
|
onStateChange({ loading: true })
|
||||||
const data = await fetchObject(id, type)
|
const data = await fetchObject(id, type)
|
||||||
const lockEvent = await fetchObjectLock(id, type)
|
const lockEvent = await fetchObjectLock(id, type)
|
||||||
setLock(lockEvent)
|
setLock(lockEvent)
|
||||||
onStateChangeRef.current({ lock: lockEvent })
|
onStateChange({ lock: lockEvent })
|
||||||
setObjectData(data)
|
setObjectData(data)
|
||||||
serverObjectData.current = data
|
setServerObjectData(data)
|
||||||
|
|
||||||
// Calculate and set computed values on initial load
|
// Calculate and set computed values on initial load
|
||||||
const computedValues = calculateComputedValues(data, model)
|
const computedValues = calculateComputedValues(data, model)
|
||||||
@ -207,7 +199,7 @@ const ObjectForm = forwardRef(
|
|||||||
|
|
||||||
form.setFieldsValue(initialFormData)
|
form.setFieldsValue(initialFormData)
|
||||||
setFetchLoading(false)
|
setFetchLoading(false)
|
||||||
onStateChangeRef.current({ loading: false })
|
onStateChange({ loading: false })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
messageApi.error('Failed to fetch object info')
|
messageApi.error('Failed to fetch object info')
|
||||||
@ -226,7 +218,7 @@ const ObjectForm = forwardRef(
|
|||||||
// Update event handler
|
// Update event handler
|
||||||
const updateLockEventHandler = useCallback((value) => {
|
const updateLockEventHandler = useCallback((value) => {
|
||||||
setLock((prev) => {
|
setLock((prev) => {
|
||||||
onStateChangeRef.current({ lock: { ...prev, ...value } })
|
onStateChange({ lock: { ...prev, ...value } })
|
||||||
return { ...prev, ...value }
|
return { ...prev, ...value }
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
@ -268,31 +260,29 @@ const ObjectForm = forwardRef(
|
|||||||
// Debounce objectData updates sent to parent to limit re-renders
|
// Debounce objectData updates sent to parent to limit re-renders
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
onStateChangeRef.current({ objectData })
|
onStateChange({ objectData })
|
||||||
}, 150)
|
}, 150)
|
||||||
|
|
||||||
return () => clearTimeout(timeoutId)
|
return () => clearTimeout(timeoutId)
|
||||||
}, [objectData])
|
}, [objectData, onStateChange])
|
||||||
|
|
||||||
const startEditing = () => {
|
const startEditing = () => {
|
||||||
setIsEditing(true)
|
setIsEditing(true)
|
||||||
onStateChangeRef.current({ isEditing: true })
|
onStateChange({ isEditing: true })
|
||||||
lockObject(id, type)
|
lockObject(id, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancelEditing = () => {
|
const cancelEditing = () => {
|
||||||
if (serverObjectData.current) {
|
if (serverObjectData) {
|
||||||
// Recalculate computed values when canceling
|
// Recalculate computed values when canceling
|
||||||
const computedValues = calculateComputedValues(
|
const computedValues = calculateComputedValues(serverObjectData, model)
|
||||||
serverObjectData.current,
|
const resetFormData = { ...serverObjectData, ...computedValues }
|
||||||
model
|
|
||||||
)
|
|
||||||
const resetFormData = { ...serverObjectData.current, ...computedValues }
|
|
||||||
|
|
||||||
form.setFieldsValue(resetFormData)
|
form.setFieldsValue(resetFormData)
|
||||||
setObjectData(resetFormData)
|
setObjectData(resetFormData)
|
||||||
}
|
}
|
||||||
setIsEditing(false)
|
setIsEditing(false)
|
||||||
onStateChangeRef.current({ isEditing: false })
|
onStateChange({ isEditing: false })
|
||||||
unlockObject(id, type)
|
unlockObject(id, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,11 +290,11 @@ const ObjectForm = forwardRef(
|
|||||||
try {
|
try {
|
||||||
const value = await form.validateFields()
|
const value = await form.validateFields()
|
||||||
setEditLoading(true)
|
setEditLoading(true)
|
||||||
onStateChangeRef.current({ editLoading: true })
|
onStateChange({ editLoading: true })
|
||||||
await updateObject(id, type, value)
|
await updateObject(id, type, value)
|
||||||
setObjectData({ ...objectData, ...value })
|
setObjectData({ ...objectData, ...value })
|
||||||
setIsEditing(false)
|
setIsEditing(false)
|
||||||
onStateChangeRef.current({ isEditing: false })
|
onStateChange({ isEditing: false })
|
||||||
messageApi.success('Information updated successfully')
|
messageApi.success('Information updated successfully')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
@ -319,7 +309,7 @@ const ObjectForm = forwardRef(
|
|||||||
} finally {
|
} finally {
|
||||||
handleFetchObject()
|
handleFetchObject()
|
||||||
setEditLoading(false)
|
setEditLoading(false)
|
||||||
onStateChangeRef.current({ editLoading: false })
|
onStateChange({ editLoading: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { Spin, Descriptions, Flex } from 'antd'
|
import { Spin, Descriptions, Flex } from 'antd'
|
||||||
import { useState, useEffect } from 'react'
|
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import ObjectProperty from './ObjectProperty'
|
import ObjectProperty from './ObjectProperty'
|
||||||
import { getModelProperties } from '../../../database/ObjectModels'
|
import { getModelProperties } from '../../../database/ObjectModels'
|
||||||
import merge from 'lodash/merge'
|
|
||||||
|
|
||||||
const ObjectInfo = ({
|
const ObjectInfo = ({
|
||||||
loading = false,
|
loading = false,
|
||||||
@ -29,12 +27,6 @@ const ObjectInfo = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const allItems = getModelProperties(type)
|
const allItems = getModelProperties(type)
|
||||||
|
|
||||||
const [combinedObjectData, setCombinedObjectData] = useState(objectData)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCombinedObjectData((prev) => merge({}, prev, objectData))
|
|
||||||
}, [objectData])
|
|
||||||
|
|
||||||
// If properties array is empty, show all properties
|
// If properties array is empty, show all properties
|
||||||
// Otherwise, filter and order by the properties array
|
// Otherwise, filter and order by the properties array
|
||||||
let items
|
let items
|
||||||
@ -90,8 +82,7 @@ const ObjectInfo = ({
|
|||||||
{...item}
|
{...item}
|
||||||
{...objectPropertyProps}
|
{...objectPropertyProps}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
objectData={combinedObjectData}
|
objectData={objectData}
|
||||||
showSince={true}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
span: item?.span || undefined
|
span: item?.span || undefined
|
||||||
|
|||||||
@ -37,7 +37,6 @@ 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'
|
||||||
@ -85,7 +84,6 @@ 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) {
|
||||||
@ -119,9 +117,6 @@ 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)
|
||||||
@ -174,9 +169,8 @@ const ObjectProperty = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'select': {
|
case 'select': {
|
||||||
if (options && Array.isArray(options)) {
|
const selectValue = options.find((option) => option.value === value)
|
||||||
const selectValue =
|
if (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 (
|
||||||
@ -212,9 +206,7 @@ const ObjectProperty = ({
|
|||||||
}
|
}
|
||||||
case 'dateTime': {
|
case 'dateTime': {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
return (
|
return <TimeDisplay dateTime={value} {...rest} />
|
||||||
<TimeDisplay dateTime={value} showSince={showSince} {...rest} />
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Text type='secondary' {...textParams}>
|
<Text type='secondary' {...textParams}>
|
||||||
@ -257,7 +249,7 @@ const ObjectProperty = ({
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
var roundedValue = value
|
var roundedValue = value
|
||||||
if (roundNumber != false && typeof value === 'number') {
|
if (roundNumber != false) {
|
||||||
roundedValue = value.toFixed(roundNumber)
|
roundedValue = value.toFixed(roundNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,10 +508,7 @@ 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 = {
|
let mergedFormItemProps = { ...formItemProps, style: { flexGrow: 1 } }
|
||||||
...formItemProps,
|
|
||||||
style: { flexGrow: 1, width: '100%' }
|
|
||||||
}
|
|
||||||
if (required && disabled == false) {
|
if (required && disabled == false) {
|
||||||
let rules
|
let rules
|
||||||
if (mergedFormItemProps.rules) {
|
if (mergedFormItemProps.rules) {
|
||||||
@ -586,10 +575,11 @@ const ObjectProperty = ({
|
|||||||
case 'select':
|
case 'select':
|
||||||
return (
|
return (
|
||||||
<Form.Item name={formItemName} {...mergedFormItemProps}>
|
<Form.Item name={formItemName} {...mergedFormItemProps}>
|
||||||
<CustomSelect
|
<Select
|
||||||
|
defaultValue={value}
|
||||||
placeholder={'Select a ' + label.toLowerCase() + '...'}
|
placeholder={'Select a ' + label.toLowerCase() + '...'}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
options={Array.isArray(options) ? options : []}
|
options={options}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
@ -814,8 +804,7 @@ 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
|
||||||
|
|||||||
@ -1,18 +1,9 @@
|
|||||||
// PrinterSelect.js
|
// PrinterSelect.js
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Progress, Flex, Space, Modal, Button, Typography } from 'antd'
|
import { Progress, Flex, Space } from 'antd'
|
||||||
import StateTag from './StateTag'
|
import StateTag from './StateTag'
|
||||||
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
|
||||||
import { useState } from 'react'
|
|
||||||
|
|
||||||
const { Text } = Typography
|
const StateDisplay = ({ state, showProgress = true, showState = true }) => {
|
||||||
|
|
||||||
const StateDisplay = ({
|
|
||||||
state,
|
|
||||||
showProgress = true,
|
|
||||||
showState = true,
|
|
||||||
showMessage = true
|
|
||||||
}) => {
|
|
||||||
const loadingProgressTypes = [
|
const loadingProgressTypes = [
|
||||||
'loading',
|
'loading',
|
||||||
'processing',
|
'processing',
|
||||||
@ -24,9 +15,8 @@ const StateDisplay = ({
|
|||||||
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>
|
||||||
@ -44,34 +34,14 @@ const StateDisplay = ({
|
|||||||
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
|
||||||
|
|||||||
@ -32,14 +32,6 @@ 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'
|
||||||
|
|||||||
@ -337,6 +337,8 @@ 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', {
|
||||||
|
|||||||
@ -613,7 +613,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
<Button
|
<Button
|
||||||
key='submit'
|
key='submit'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowAuthErrorModal(false)
|
showAuthErrorModal(false)
|
||||||
loginWithSSO()
|
loginWithSSO()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -14,8 +14,7 @@ import {
|
|||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
useRef,
|
useRef,
|
||||||
createElement,
|
createElement
|
||||||
useContext
|
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
@ -30,8 +29,6 @@ import {
|
|||||||
getModelByPrefix
|
getModelByPrefix
|
||||||
} from '../../../database/ObjectModels'
|
} from '../../../database/ObjectModels'
|
||||||
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||||
import { ApiServerContext } from './ApiServerContext'
|
|
||||||
import { AuthContext } from './AuthContext'
|
|
||||||
|
|
||||||
const SpotlightContext = createContext()
|
const SpotlightContext = createContext()
|
||||||
|
|
||||||
@ -44,8 +41,6 @@ const SpotlightProvider = ({ children }) => {
|
|||||||
const [listData, setListData] = useState([])
|
const [listData, setListData] = useState([])
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const [inputPrefix, setInputPrefix] = useState({ prefix: '', mode: null })
|
const [inputPrefix, setInputPrefix] = useState({ prefix: '', mode: null })
|
||||||
const { fetchSpotlightData } = useContext(ApiServerContext)
|
|
||||||
const { token } = useContext(AuthContext)
|
|
||||||
|
|
||||||
// Refs for throttling/debouncing
|
// Refs for throttling/debouncing
|
||||||
const lastFetchTime = useRef(0)
|
const lastFetchTime = useRef(0)
|
||||||
@ -121,7 +116,7 @@ const SpotlightProvider = ({ children }) => {
|
|||||||
setLoading(true)
|
setLoading(true)
|
||||||
setListData([])
|
setListData([])
|
||||||
|
|
||||||
let data
|
let response
|
||||||
|
|
||||||
// Check if we have a prefix with ? mode (filter mode)
|
// Check if we have a prefix with ? mode (filter mode)
|
||||||
if (inputPrefix && inputPrefix.mode === '?') {
|
if (inputPrefix && inputPrefix.mode === '?') {
|
||||||
@ -133,34 +128,37 @@ const SpotlightProvider = ({ children }) => {
|
|||||||
// Parse the query parameters
|
// Parse the query parameters
|
||||||
const params = new URLSearchParams(queryParams)
|
const params = new URLSearchParams(queryParams)
|
||||||
|
|
||||||
// For ? mode, use axios directly with query params
|
response = await axios.get(`${config.backendUrl}/spotlight/${prefix}`, {
|
||||||
const response = await axios.get(
|
|
||||||
`${config.backendUrl}/spotlight/${prefix}`,
|
|
||||||
{
|
|
||||||
params: params,
|
params: params,
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json'
|
||||||
Authorization: `Bearer ${token}`
|
},
|
||||||
}
|
withCredentials: true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// For other modes (:, ^), use the original behavior
|
||||||
|
response = await axios.get(
|
||||||
|
`${config.backendUrl}/spotlight/${encodeURIComponent(searchQuery.trim())}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json'
|
||||||
|
},
|
||||||
|
withCredentials: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
data = response.data
|
|
||||||
} else {
|
|
||||||
// For other modes (:, ^), use fetchSpotlightData from ApiServerContext
|
|
||||||
data = await fetchSpotlightData(searchQuery.trim())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
// If the query contains a prefix mode character, and the response is an object, wrap it in an array
|
// If the query contains a prefix mode character, and the response is an object, wrap it in an array
|
||||||
if (
|
if (
|
||||||
/[:?^]/.test(searchQuery) &&
|
/[:?^]/.test(searchQuery) &&
|
||||||
data &&
|
response.data &&
|
||||||
!Array.isArray(data) &&
|
!Array.isArray(response.data) &&
|
||||||
typeof data === 'object'
|
typeof response.data === 'object'
|
||||||
) {
|
) {
|
||||||
setListData([data])
|
setListData([response.data])
|
||||||
} else {
|
} else {
|
||||||
setListData(data)
|
setListData(response.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there's a pending query after this fetch completes
|
// Check if there's a pending query after this fetch completes
|
||||||
@ -466,22 +464,11 @@ const SpotlightProvider = ({ children }) => {
|
|||||||
align='center'
|
align='center'
|
||||||
justify='space-between'
|
justify='space-between'
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex gap={'small'} align='center'>
|
||||||
gap={'small'}
|
|
||||||
align='center'
|
|
||||||
style={{ flexGrow: 1 }}
|
|
||||||
>
|
|
||||||
{Icon ? <Icon style={{ fontSize: '20px' }} /> : null}
|
{Icon ? <Icon style={{ fontSize: '20px' }} /> : null}
|
||||||
|
|
||||||
{item.name ? (
|
{item.name ? (
|
||||||
<Text
|
<Text ellipsis style={{ maxWidth: 170 }}>
|
||||||
ellipsis
|
|
||||||
style={{
|
|
||||||
maxWidth: 170,
|
|
||||||
flexGrow: 1,
|
|
||||||
width: '100%'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.name}
|
{item.name}
|
||||||
</Text>
|
</Text>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -90,7 +90,7 @@ export const ThemeProvider = ({ children }) => {
|
|||||||
colorWarning: '#FF9F0A',
|
colorWarning: '#FF9F0A',
|
||||||
colorInfo: '#0A84FF',
|
colorInfo: '#0A84FF',
|
||||||
colorLink: '#5AC8F5',
|
colorLink: '#5AC8F5',
|
||||||
borderRadius: '12px'
|
borderRadius: '10px'
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Layout: {
|
Layout: {
|
||||||
|
|||||||
@ -36,9 +36,9 @@ export const DocumentJob = {
|
|||||||
`/dashboard/management/documentjobs/info?documentJobId=${_id}&action=edit`
|
`/dashboard/management/documentjobs/info?documentJobId=${_id}&action=edit`
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
columns: ['name', '_id', 'state', 'createdAt', 'updatedAt'],
|
columns: ['name', '_id', 'width', 'height', 'createdAt', 'updatedAt'],
|
||||||
filters: ['name', '_id', 'state'],
|
filters: ['name', '_id', 'width', 'height'],
|
||||||
sorters: ['name', 'state', 'createdAt', 'updatedAt'],
|
sorters: ['name', 'width', 'height', 'createdAt', 'updatedAt'],
|
||||||
properties: [
|
properties: [
|
||||||
{
|
{
|
||||||
name: '_id',
|
name: '_id',
|
||||||
|
|||||||
@ -38,15 +38,13 @@ export const DocumentPrinter = {
|
|||||||
columns: [
|
columns: [
|
||||||
'name',
|
'name',
|
||||||
'_id',
|
'_id',
|
||||||
'state',
|
'documentSize',
|
||||||
'host',
|
'documentSize._id',
|
||||||
'host._id',
|
'createdAt',
|
||||||
'tags',
|
|
||||||
'connectedAt',
|
|
||||||
'updatedAt'
|
'updatedAt'
|
||||||
],
|
],
|
||||||
filters: ['name', '_id'],
|
filters: ['name', '_id'],
|
||||||
sorters: ['name', 'documentSize', 'connectedAt', 'updatedAt'],
|
sorters: ['name', 'documentSize', 'createdAt', 'updatedAt'],
|
||||||
properties: [
|
properties: [
|
||||||
{
|
{
|
||||||
name: '_id',
|
name: '_id',
|
||||||
@ -84,10 +82,10 @@ export const DocumentPrinter = {
|
|||||||
readOnly: true
|
readOnly: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'connectedAt',
|
name: 'active',
|
||||||
label: 'Connected At',
|
label: 'Active',
|
||||||
type: 'dateTime',
|
type: 'bool',
|
||||||
readOnly: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'online',
|
name: 'online',
|
||||||
@ -95,12 +93,6 @@ 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',
|
||||||
@ -117,6 +109,16 @@ 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',
|
||||||
@ -128,43 +130,12 @@ 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: 'Host Name',
|
label: 'Connection String',
|
||||||
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',
|
||||||
|
|||||||
@ -35,24 +35,9 @@ export const DocumentSize = {
|
|||||||
`/dashboard/management/documentsizes/info?documentSizeId=${_id}&action=edit`
|
`/dashboard/management/documentsizes/info?documentSizeId=${_id}&action=edit`
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
columns: [
|
columns: ['name', '_id', 'width', 'height', 'createdAt', 'updatedAt'],
|
||||||
'name',
|
filters: ['name', '_id', 'width', 'height'],
|
||||||
'_id',
|
sorters: ['name', 'width', 'height', 'createdAt', 'updatedAt'],
|
||||||
'width',
|
|
||||||
'height',
|
|
||||||
'infiniteHeight',
|
|
||||||
'createdAt',
|
|
||||||
'updatedAt'
|
|
||||||
],
|
|
||||||
filters: ['name', '_id', 'width', 'height', 'infiniteHeight'],
|
|
||||||
sorters: [
|
|
||||||
'name',
|
|
||||||
'width',
|
|
||||||
'height',
|
|
||||||
'infiniteHeight',
|
|
||||||
'createdAt',
|
|
||||||
'updatedAt'
|
|
||||||
],
|
|
||||||
properties: [
|
properties: [
|
||||||
{
|
{
|
||||||
name: '_id',
|
name: '_id',
|
||||||
@ -95,17 +80,7 @@ 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'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,7 +96,6 @@ export const File = {
|
|||||||
label: 'Size',
|
label: 'Size',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
roundNumber: 2,
|
|
||||||
required: true,
|
required: true,
|
||||||
suffix: (objectData) => {
|
suffix: (objectData) => {
|
||||||
const size = objectData?.size || 0
|
const size = objectData?.size || 0
|
||||||
|
|||||||
@ -167,16 +167,7 @@ export const Printer = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
columns: [
|
columns: ['name', '_id', 'state', 'tags', 'connectedAt'],
|
||||||
'name',
|
|
||||||
'_id',
|
|
||||||
'state',
|
|
||||||
'host',
|
|
||||||
'host._id',
|
|
||||||
'tags',
|
|
||||||
'connectedAt',
|
|
||||||
'updatedAt'
|
|
||||||
],
|
|
||||||
filters: ['name', '_id', 'state', 'tags'],
|
filters: ['name', '_id', 'state', 'tags'],
|
||||||
sorters: ['name', 'state', 'connectedAt'],
|
sorters: ['name', 'state', 'connectedAt'],
|
||||||
group: ['tags'],
|
group: ['tags'],
|
||||||
@ -189,8 +180,8 @@ export const Printer = {
|
|||||||
showCopy: true
|
showCopy: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'createdAt',
|
name: 'connectedAt',
|
||||||
label: 'Created At',
|
label: 'Connected At',
|
||||||
type: 'dateTime',
|
type: 'dateTime',
|
||||||
readOnly: true
|
readOnly: true
|
||||||
},
|
},
|
||||||
@ -202,12 +193,6 @@ export const Printer = {
|
|||||||
columnWidth: 200,
|
columnWidth: 200,
|
||||||
columnFixed: 'left'
|
columnFixed: 'left'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'updatedAt',
|
|
||||||
label: 'Updated At',
|
|
||||||
type: 'dateTime',
|
|
||||||
readOnly: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'state',
|
name: 'state',
|
||||||
label: 'Status',
|
label: 'Status',
|
||||||
@ -217,10 +202,10 @@ export const Printer = {
|
|||||||
readOnly: true
|
readOnly: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'connectedAt',
|
name: 'active',
|
||||||
label: 'Connected At',
|
label: 'Active',
|
||||||
type: 'dateTime',
|
type: 'bool',
|
||||||
readOnly: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'online',
|
name: 'online',
|
||||||
@ -228,12 +213,6 @@ export const Printer = {
|
|||||||
type: 'bool',
|
type: 'bool',
|
||||||
readOnly: true
|
readOnly: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'active',
|
|
||||||
label: 'Active',
|
|
||||||
type: 'bool',
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'vendor',
|
name: 'vendor',
|
||||||
label: 'Vendor',
|
label: 'Vendor',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user