Compare commits

..

No commits in common. "97f0c816adc96a4e9d0a19d632730942a20ac4fe" and "1e7697f1d590b997c4d7ea294215ce1723f4ab48" have entirely different histories.

18 changed files with 120 additions and 361 deletions

View File

@ -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;
}

View File

@ -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()
} }

View File

@ -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'

View File

@ -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

View File

@ -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 })
} }
} }

View File

@ -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

View File

@ -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

View File

@ -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,54 +15,33 @@ const StateDisplay = ({
type: 'unknown', type: 'unknown',
progress: 0 progress: 0
} }
const [showMessageModal, setShowMessageModal] = useState(false)
return (
<>
<Flex gap='small' align={'center'}>
{showState && (
<Space>
<StateTag state={currentState.type} />
</Space>
)}
{showProgress &&
loadingProgressTypes.includes(currentState.type) &&
currentState?.progress &&
currentState?.progress > 0 ? (
<Progress
percent={Math.round(currentState.progress * 100)}
status={currentState.type === 'used' ? '' : 'active'}
strokeColor={currentState.type === 'used' ? 'orange' : ''}
style={{ width: '150px', marginBottom: '2px' }}
/>
) : null}
{showMessage && currentState?.message && ( return (
<Button <Flex gap='small' align={'center'}>
type='text' {showState && (
size='small' <Space>
style={{ padding: '4px' }} <StateTag state={currentState.type} />
onClick={() => setShowMessageModal(true)} </Space>
> )}
<InfoCircleIcon /> {showProgress &&
</Button> loadingProgressTypes.includes(currentState.type) &&
)} currentState?.progress &&
</Flex> currentState?.progress > 0 ? (
<Modal <Progress
open={showMessageModal} percent={Math.round(currentState.progress * 100)}
onCancel={() => setShowMessageModal(false)} status={currentState.type === 'used' ? '' : 'active'}
footer={null} strokeColor={currentState.type === 'used' ? 'orange' : ''}
> style={{ width: '150px', marginBottom: '2px' }}
<Text>{currentState.message}</Text> />
</Modal> ) : null}
</> </Flex>
) )
} }
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,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'

View File

@ -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', {

View File

@ -613,7 +613,7 @@ const AuthProvider = ({ children }) => {
<Button <Button
key='submit' key='submit'
onClick={() => { onClick={() => {
setShowAuthErrorModal(false) showAuthErrorModal(false)
loginWithSSO() loginWithSSO()
}} }}
> >

View File

@ -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( params: params,
`${config.backendUrl}/spotlight/${prefix}`, headers: {
Accept: 'application/json'
},
withCredentials: true
})
} else {
// For other modes (:, ^), use the original behavior
response = await axios.get(
`${config.backendUrl}/spotlight/${encodeURIComponent(searchQuery.trim())}`,
{ {
params: params,
headers: { headers: {
Accept: 'application/json', Accept: 'application/json'
Authorization: `Bearer ${token}` },
} 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}

View File

@ -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: {

View File

@ -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',

View File

@ -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',

View File

@ -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'
} }
] ]
} }

View File

@ -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

View File

@ -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',