Fixed warnings and info pages.

This commit is contained in:
Tom Butcher 2025-08-23 00:53:47 +01:00
parent bb047651ae
commit 5680b067a8
18 changed files with 1567 additions and 1675 deletions

View File

@ -1,3 +1,4 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -19,6 +20,8 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
const FilamentStockInfo = () => { const FilamentStockInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const filamentStockId = new URLSearchParams(location.search).get( const filamentStockId = new URLSearchParams(location.search).get(
'filamentStockId' 'filamentStockId'
) )
@ -31,35 +34,39 @@ const FilamentStockInfo = () => {
auditLogs: true auditLogs: true
} }
) )
const [editFormState, setEditFormState] = useState({
isEditing: false,
editLoading: false,
formValid: false,
lock: null,
loading: false
})
return (
<EditObjectForm
id={filamentStockId}
type='filamentStock'
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
>
{({
loading,
isEditing,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current?.fetchObject?.()
return true
},
edit: () => {
editFormRef?.current?.startEditing?.()
return false
},
cancelEdit: () => {
editFormRef?.current?.cancelEditing?.()
return true
},
finishEdit: () => {
editFormRef?.current?.handleUpdate?.()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -67,10 +74,10 @@ const FilamentStockInfo = () => {
<ObjectActions <ObjectActions
type='filamentStock' type='filamentStock'
id={filamentStockId} id={filamentStockId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Filament Stock Information' }, { key: 'info', label: 'Filament Stock Information' },
{ key: 'events', label: 'Filament Stock Events' }, { key: 'events', label: 'Filament Stock Events' },
@ -81,57 +88,69 @@ const FilamentStockInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={true} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflow: 'auto' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Filament Stock Information' title='Filament Stock Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={filamentStockId}
type='filamentStock'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
isEditing={isEditing} isEditing={isEditing}
type='filamentStock' type='filamentStock'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Filament Stock Events' title='Filament Stock Events'
icon={<FilamentStockIcon />} icon={<FilamentStockIcon />}
active={collapseState.events} active={collapseState.events}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('events', expanded)}
updateCollapseState('events', expanded)
}
collapseKey='events' collapseKey='events'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -141,24 +160,17 @@ const FilamentStockInfo = () => {
/> />
)} )}
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel <NotesPanel _id={filamentStockId} type='filamentStock' />
_id={filamentStockId}
type='filamentStock'
/>
</Card> </Card>
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Audit Logs' title='Audit Logs'
icon={<AuditLogIcon />} icon={<AuditLogIcon />}
@ -168,7 +180,7 @@ const FilamentStockInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -181,11 +193,7 @@ const FilamentStockInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -14,9 +14,7 @@ const DocumentSizes = () => {
const [messageApi, contextHolder] = message.useMessage() const [messageApi, contextHolder] = message.useMessage()
const [newDocumentSizeOpen, setNewDocumentSizeOpen] = useState(false) const [newDocumentSizeOpen, setNewDocumentSizeOpen] = useState(false)
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentSize') const [viewMode, setViewMode] = useViewMode('documentSize')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('documentSize') useColumnVisibility('documentSize')
@ -85,7 +83,7 @@ const DocumentSizes = () => {
<NewDocumentSize <NewDocumentSize
onOk={() => { onOk={() => {
setNewDocumentSizeOpen(false) setNewDocumentSizeOpen(false)
messageApi.success('New note type created successfully.') messageApi.success('New document size created successfully.')
tableRef.current?.reload() tableRef.current?.reload()
}} }}
reset={!newDocumentSizeOpen} reset={!newDocumentSizeOpen}

View File

@ -1,3 +1,4 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
@ -24,6 +25,8 @@ log.setLevel(config.logLevel)
const DocumentSizeInfo = () => { const DocumentSizeInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const documentSizeId = new URLSearchParams(location.search).get( const documentSizeId = new URLSearchParams(location.search).get(
'documentSizeId' 'documentSizeId'
) )
@ -35,55 +38,39 @@ const DocumentSizeInfo = () => {
auditLogs: true auditLogs: true
} }
) )
const [editFormState, setEditFormState] = useState({
isEditing: false,
editLoading: false,
formValid: false,
lock: null,
loading: false
})
return (
<EditObjectForm
id={documentSizeId}
type='documentSize'
style={{ height: '100%' }}
>
{({
loading,
isEditing,
startEditing,
cancelEditing,
handleUpdate,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
// Define actions for ActionHandler
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current?.fetchObject?.()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current?.handleUpdate?.()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
height: 'calc(var(--unit-100vh) - 155px)',
minHeight: 0
}}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -91,13 +78,12 @@ const DocumentSizeInfo = () => {
<ObjectActions <ObjectActions
type='documentSize' type='documentSize'
id={documentSizeId} id={documentSizeId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Document Size Information' }, { key: 'info', label: 'Document Size Information' },
{ key: 'stocks', label: 'DocumentSize Stocks' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
]} ]}
@ -105,39 +91,51 @@ const DocumentSizeInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}>
<div style={{ height: '100%', overflowY: 'scroll' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Document Size Information' title='Document Size Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={documentSizeId}
type='documentSize'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
@ -145,22 +143,21 @@ const DocumentSizeInfo = () => {
type='documentSize' type='documentSize'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={documentSizeId} type='documentSize' /> <NotesPanel _id={documentSizeId} type='documentSize' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Audit Logs' title='Audit Logs'
icon={<AuditLogIcon />} icon={<AuditLogIcon />}
@ -170,7 +167,7 @@ const DocumentSizeInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -183,11 +180,7 @@ const DocumentSizeInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,3 +1,4 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
@ -25,6 +26,8 @@ log.setLevel(config.logLevel)
const FilamentInfo = () => { const FilamentInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const filamentId = new URLSearchParams(location.search).get('filamentId') const filamentId = new URLSearchParams(location.search).get('filamentId')
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'FilamentInfo', 'FilamentInfo',
@ -36,43 +39,35 @@ const FilamentInfo = () => {
} }
) )
return ( const [editFormState, setEditFormState] = useState({
<EditObjectForm id={filamentId} type='filament' style={{ height: '100%' }}> isEditing: false,
{({ editLoading: false,
loading, formValid: false,
isEditing, lock: null,
startEditing, loading: false
cancelEditing, })
handleUpdate,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
// Define actions for ActionHandler
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current?.fetchObject?.()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current?.handleUpdate?.()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -87,10 +82,10 @@ const FilamentInfo = () => {
<ObjectActions <ObjectActions
type='filament' type='filament'
id={filamentId} id={filamentId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Filament Information' }, { key: 'info', label: 'Filament Information' },
{ key: 'stocks', label: 'Filament Stocks' }, { key: 'stocks', label: 'Filament Stocks' },
@ -101,39 +96,53 @@ const FilamentInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflowY: 'scroll' }}> <div style={{ height: '100%', overflowY: 'scroll' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Filament Information' title='Filament Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={filamentId}
type='filament'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => {
return (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
@ -141,18 +150,20 @@ const FilamentInfo = () => {
type='filament' type='filament'
objectData={objectData} objectData={objectData}
/> />
)
}}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Filament Stocks' title='Filament Stocks'
icon={<FilamentIcon />} icon={<FilamentIcon />}
active={collapseState.stocks} active={collapseState.stocks}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('stocks', expanded)}
updateCollapseState('stocks', expanded)
}
collapseKey='stocks' collapseKey='stocks'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -171,9 +182,7 @@ const FilamentInfo = () => {
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
@ -190,7 +199,7 @@ const FilamentInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -203,11 +212,7 @@ const FilamentInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,3 +1,4 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex } from 'antd' import { Space, Flex } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
@ -17,6 +18,8 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
const NoteTypeInfo = () => { const NoteTypeInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const noteTypeId = new URLSearchParams(location.search).get('noteTypeId') const noteTypeId = new URLSearchParams(location.search).get('noteTypeId')
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'NoteTypeInfo', 'NoteTypeInfo',
@ -25,52 +28,39 @@ const NoteTypeInfo = () => {
auditLogs: true auditLogs: true
} }
) )
const [editFormState, setEditFormState] = useState({
isEditing: false,
editLoading: false,
formValid: false,
lock: null,
loading: false
})
return (
<EditObjectForm
id={noteTypeId}
type='noteType'
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
>
{({
loading,
isEditing,
startEditing,
cancelEditing,
handleUpdate,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
// Define actions for ActionHandler
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current?.fetchObject?.()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current?.handleUpdate?.()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -78,10 +68,10 @@ const NoteTypeInfo = () => {
<ObjectActions <ObjectActions
type='noteType' type='noteType'
id={noteTypeId} id={noteTypeId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Note Type Information' }, { key: 'info', label: 'Note Type Information' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
@ -90,39 +80,51 @@ const NoteTypeInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflow: 'auto' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Note Type Information' title='Note Type Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={noteTypeId}
type='noteType'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
@ -130,8 +132,10 @@ const NoteTypeInfo = () => {
type='noteType' type='noteType'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Audit Logs' title='Audit Logs'
icon={<AuditLogIcon />} icon={<AuditLogIcon />}
@ -141,7 +145,7 @@ const NoteTypeInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -154,11 +158,7 @@ const NoteTypeInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,4 +1,4 @@
import { useContext } from 'react' import { useRef, useState, useContext } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -20,66 +20,56 @@ import { ApiServerContext } from '../../context/ApiServerContext'
const PartInfo = () => { const PartInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const partId = new URLSearchParams(location.search).get('partId') const partId = new URLSearchParams(location.search).get('partId')
const { fetchObjectContent } = useContext(ApiServerContext) const { fetchObjectContent } = useContext(ApiServerContext)
const [collapseState, updateCollapseState] = useCollapseState('PartInfo', { const [collapseState, updateCollapseState] = useCollapseState('PartInfo', {
info: true, info: true,
parts: true, parts: true,
notes: true, notes: true,
auditLogs: true auditLogs: true
}) })
const [editFormState, setEditFormState] = useState({
isEditing: false,
editLoading: false,
formValid: false,
lock: null,
loading: false
})
return (
<EditObjectForm
id={partId}
type='part'
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
>
{({
loading,
isEditing,
startEditing,
cancelEditing,
handleUpdate,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current?.fetchObject?.()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current?.handleUpdate?.()
return true return true
}, },
download: () => { download: () => {
if (partId) { if (partId && editFormRef?.current?.getObjectData) {
fetchObjectContent(partId, 'part', `${objectData.name}.stl`) const objectData = editFormRef.current.getObjectData()
fetchObjectContent(partId, 'part', `${objectData?.name || 'part'}.stl`)
return true return true
} }
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -87,10 +77,10 @@ const PartInfo = () => {
<ObjectActions <ObjectActions
type='part' type='part'
id={partId} id={partId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Part Information' }, { key: 'info', label: 'Part Information' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
@ -100,61 +90,72 @@ const PartInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflow: 'auto' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Part Information' title='Part Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={partId}
type='part'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
isEditing={isEditing} isEditing={isEditing}
type='part' type='part'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={partId} type='part' /> <NotesPanel _id={partId} type='part' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Audit Logs' title='Audit Logs'
icon={<AuditLogIcon />} icon={<AuditLogIcon />}
@ -164,7 +165,7 @@ const PartInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -177,11 +178,7 @@ const PartInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,3 +1,4 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -19,6 +20,8 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
const ProductInfo = () => { const ProductInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const productId = new URLSearchParams(location.search).get('productId') const productId = new URLSearchParams(location.search).get('productId')
const [collapseState, updateCollapseState] = useCollapseState('ProductInfo', { const [collapseState, updateCollapseState] = useCollapseState('ProductInfo', {
info: true, info: true,
@ -26,50 +29,39 @@ const ProductInfo = () => {
notes: true, notes: true,
auditLogs: true auditLogs: true
}) })
const [editFormState, setEditFormState] = useState({
isEditing: false,
editLoading: false,
formValid: false,
lock: null,
loading: false
})
return (
<EditObjectForm
id={productId}
type='product'
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
>
{({
loading,
isEditing,
startEditing,
cancelEditing,
handleUpdate,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current?.fetchObject?.()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current?.handleUpdate?.()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -77,10 +69,10 @@ const ProductInfo = () => {
<ObjectActions <ObjectActions
type='product' type='product'
id={productId} id={productId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Product Information' }, { key: 'info', label: 'Product Information' },
{ key: 'parts', label: 'Product Parts' }, { key: 'parts', label: 'Product Parts' },
@ -91,54 +83,66 @@ const ProductInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflow: 'auto' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Product Information' title='Product Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={productId}
type='product'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
isEditing={isEditing} isEditing={isEditing}
type='product' type='product'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Product Parts' title='Product Parts'
icon={<ProductIcon />} icon={<ProductIcon />}
active={collapseState.parts} active={collapseState.parts}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('parts', expanded)}
updateCollapseState('parts', expanded)
}
collapseKey='parts' collapseKey='parts'
> >
<ObjectTable <ObjectTable
@ -150,21 +154,17 @@ const ProductInfo = () => {
masterFilter={{ 'product._id': productId }} masterFilter={{ 'product._id': productId }}
/> />
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={productId} type='product' /> <NotesPanel _id={productId} type='product' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Audit Logs' title='Audit Logs'
icon={<AuditLogIcon />} icon={<AuditLogIcon />}
@ -174,7 +174,7 @@ const ProductInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -187,11 +187,7 @@ const ProductInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,3 +1,4 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
@ -19,58 +20,47 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
const UserInfo = () => { const UserInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const userId = new URLSearchParams(location.search).get('userId') const userId = new URLSearchParams(location.search).get('userId')
const [collapseState, updateCollapseState] = useCollapseState('UserInfo', { const [collapseState, updateCollapseState] = useCollapseState('UserInfo', {
info: true, info: true,
notes: true, notes: true,
auditLogs: true auditLogs: true
}) })
const [editFormState, setEditFormState] = useState({
isEditing: false,
editLoading: false,
formValid: false,
lock: null,
loading: false
})
return (
<EditObjectForm
id={userId}
type='user'
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
>
{({
loading,
isEditing,
startEditing,
cancelEditing,
handleUpdate,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
// Define actions for ActionHandler
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current?.fetchObject?.()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current?.handleUpdate?.()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -78,10 +68,10 @@ const UserInfo = () => {
<ObjectActions <ObjectActions
type='user' type='user'
id={userId} id={userId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'User Information' }, { key: 'info', label: 'User Information' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
@ -91,39 +81,51 @@ const UserInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading || true} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflow: 'auto' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='User Information' title='User Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={userId}
type='user'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
@ -131,22 +133,21 @@ const UserInfo = () => {
type='user' type='user'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={userId} type='user' /> <NotesPanel _id={userId} type='user' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Audit Logs' title='Audit Logs'
icon={<AuditLogIcon />} icon={<AuditLogIcon />}
@ -156,7 +157,7 @@ const UserInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -169,11 +170,7 @@ const UserInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,3 +1,4 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
@ -23,63 +24,51 @@ log.setLevel(config.logLevel)
const VendorInfo = () => { const VendorInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const vendorId = new URLSearchParams(location.search).get('vendorId') const vendorId = new URLSearchParams(location.search).get('vendorId')
const [collapseState, updateCollapseState] = useCollapseState('VendorInfo', { const [collapseState, updateCollapseState] = useCollapseState('VendorInfo', {
info: true, info: true,
notes: true, notes: true,
auditLogs: true auditLogs: true
}) })
const [editFormState, setEditFormState] = useState({
isEditing: false,
editLoading: false,
formValid: false,
lock: null,
loading: false
})
return (
<EditObjectForm
id={vendorId}
type='vendor'
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
>
{({
loading,
isEditing,
startEditing,
cancelEditing,
handleFetchObject,
handleUpdate,
handleDelete,
formValid,
objectData,
editLoading,
lock
}) => {
// Define actions for ActionHandler
const actions = { const actions = {
reload: () => { reload: () => {
handleFetchObject() editFormRef?.current?.handleFetchObject?.()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current?.handleUpdate?.()
return true return true
}, },
delete: () => { delete: () => {
handleDelete() editFormRef?.current?.handleDelete?.()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -87,10 +76,10 @@ const VendorInfo = () => {
<ObjectActions <ObjectActions
type='vendor' type='vendor'
id={vendorId} id={vendorId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Vendor Information' }, { key: 'info', label: 'Vendor Information' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
@ -100,61 +89,72 @@ const VendorInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflow: 'auto' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Vendor Information' title='Vendor Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={vendorId}
type='vendor'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
isEditing={isEditing} isEditing={isEditing}
type='vendor' type='vendor'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={vendorId} type='vendor' /> <NotesPanel _id={vendorId} type='vendor' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='Audit Logs' title='Audit Logs'
icon={<AuditLogIcon />} icon={<AuditLogIcon />}
@ -164,7 +164,7 @@ const VendorInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -177,11 +177,7 @@ const VendorInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,97 +1,82 @@
import { useContext } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card, Typography } from 'antd' import { Space, Flex, Card, Typography } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState' import loglevel from 'loglevel'
import NotesPanel from '../../common/NotesPanel' import config from '../../../../config.js'
import InfoCollapse from '../../common/InfoCollapse' import useCollapseState from '../../hooks/useCollapseState.js'
import ObjectInfo from '../../common/ObjectInfo' import NotesPanel from '../../common/NotesPanel.jsx'
import ViewButton from '../../common/ViewButton' import InfoCollapse from '../../common/InfoCollapse.jsx'
import EditObjectForm from '../../common/EditObjectForm' import ObjectInfo from '../../common/ObjectInfo.jsx'
import EditButtons from '../../common/EditButtons' import ViewButton from '../../common/ViewButton.jsx'
import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import GCodeFileIcon from '../../../Icons/GCodeFileIcon.jsx' import EditObjectForm from '../../common/EditObjectForm.jsx'
import { ApiServerContext } from '../../context/ApiServerContext' import EditButtons from '../../common/EditButtons.jsx'
import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import EyeIcon from '../../../Icons/EyeIcon.jsx'
const { Text } = Typography const { Text } = Typography
const log = loglevel.getLogger('GCodeFileInfo')
log.setLevel(config.logLevel)
const GCodeFileInfo = () => { const GCodeFileInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const gcodeFileId = new URLSearchParams(location.search).get('gcodeFileId') const gcodeFileId = new URLSearchParams(location.search).get('gcodeFileId')
const { fetchObjectContent } = useContext(ApiServerContext)
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'gcodeFileInfo', 'GCodeFileInfo',
{ {
info: true, info: true,
preview: true, stocks: true,
notes: true, notes: true,
auditLogs: true auditLogs: true
} }
) )
return ( const [editFormState, setEditFormState] = useState({
<EditObjectForm isEditing: false,
id={gcodeFileId} editLoading: false,
type='gcodefile' formValid: false,
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }} locked: false,
> loading: false
{({ })
loading,
isEditing,
startEditing,
cancelEditing,
handleUpdate,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
// Define actions that can be triggered via URL, now with access to startEditing
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current.handleFetchObject()
return true return true
}, },
edit: () => { edit: () => {
startEditing() editFormRef?.current.startEditing()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
cancelEditing() editFormRef?.current.cancelEditing()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
handleUpdate() editFormRef?.current.handleUpdate()
return true return true
},
download: () => {
if (gcodeFileId) {
fetchObjectContent(
gcodeFileId,
'gcodeFile',
`${objectData.name}.gcode`
)
return true
}
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{
height: 'calc(var(--unit-100vh) - 155px)',
minHeight: 0
}}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
@ -99,10 +84,10 @@ const GCodeFileInfo = () => {
<ObjectActions <ObjectActions
type='gcodeFile' type='gcodeFile'
id={gcodeFileId} id={gcodeFileId}
disabled={loading} disabled={editFormState.loading}
/> />
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'GCode File Information' }, { key: 'info', label: 'GCode File Information' },
{ key: 'preview', label: 'GCode File Preview' }, { key: 'preview', label: 'GCode File Preview' },
@ -113,29 +98,47 @@ const GCodeFileInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={lock?.locked || loading} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflowY: 'scroll' }}>
<Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<EditObjectForm
id={gcodeFileId}
type='gcodeFile'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
console.log('Got edit form state change', state)
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => {
return (
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<InfoCollapse <InfoCollapse
title='GCode File Information' title='GCode File Information'
@ -150,14 +153,14 @@ const GCodeFileInfo = () => {
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
isEditing={isEditing} isEditing={isEditing}
objectData={objectData}
type='gcodeFile' type='gcodeFile'
objectData={objectData}
visibleProperties={{}}
/> />
</InfoCollapse> </InfoCollapse>
<InfoCollapse <InfoCollapse
title='GCode File Preview' title='GCode File Preview'
icon={<GCodeFileIcon />} icon={<EyeIcon />}
active={collapseState.preview} active={collapseState.preview}
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('preview', expanded) updateCollapseState('preview', expanded)
@ -176,14 +179,17 @@ const GCodeFileInfo = () => {
)} )}
</Card> </Card>
</InfoCollapse> </InfoCollapse>
</Flex>
)
}}
</EditObjectForm>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
@ -200,7 +206,7 @@ const GCodeFileInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -213,11 +219,7 @@ const GCodeFileInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -1,25 +1,33 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState' import loglevel from 'loglevel'
import NotesPanel from '../../common/NotesPanel' import config from '../../../../config.js'
import InfoCollapse from '../../common/InfoCollapse' import useCollapseState from '../../hooks/useCollapseState.js'
import ObjectInfo from '../../common/ObjectInfo' import NotesPanel from '../../common/NotesPanel.jsx'
import ViewButton from '../../common/ViewButton' import InfoCollapse from '../../common/InfoCollapse.jsx'
import EditObjectForm from '../../common/EditObjectForm' import ObjectInfo from '../../common/ObjectInfo.jsx'
import EditButtons from '../../common/EditButtons' import ViewButton from '../../common/ViewButton.jsx'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import EditObjectForm from '../../common/EditObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx'
import LockIndicator from '../../common/LockIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler' import ActionHandler from '../../common/ActionHandler.jsx'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon'
import JobIcon from '../../../Icons/JobIcon'
import AuditLogIcon from '../../../Icons/AuditLogIcon'
import NoteIcon from '../../../Icons/NoteIcon'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import JobIcon from '../../../Icons/JobIcon.jsx'
const log = loglevel.getLogger('JobInfo')
log.setLevel(config.logLevel)
const JobInfo = () => { const JobInfo = () => {
const location = useLocation() const location = useLocation()
const editFormRef = useRef(null)
const actionHandlerRef = useRef(null)
const jobId = new URLSearchParams(location.search).get('jobId') const jobId = new URLSearchParams(location.search).get('jobId')
const [collapseState, updateCollapseState] = useCollapseState('JobInfo', { const [collapseState, updateCollapseState] = useCollapseState('JobInfo', {
info: true, info: true,
@ -28,43 +36,53 @@ const JobInfo = () => {
auditLogs: true auditLogs: true
}) })
return ( const [editFormState, setEditFormState] = useState({
<EditObjectForm isEditing: false,
id={jobId} editLoading: false,
type='job' formValid: false,
style={{ height: 'calc(var(--unit-100vh) - 155px)', minHeight: 0 }} locked: false,
> loading: false
{({ })
loading,
isEditing,
formValid,
objectData,
editLoading,
lock,
fetchObject
}) => {
// Define actions that can be triggered via URL, now with access to startEditing
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() editFormRef?.current.handleFetchObject()
return true
},
edit: () => {
editFormRef?.current.startEditing()
return false
},
cancelEdit: () => {
editFormRef?.current.cancelEditing()
return true
},
finishEdit: () => {
editFormRef?.current.handleUpdate()
return true return true
} }
} }
return ( return (
<ActionHandler actions={actions} loading={loading}> <>
{({ callAction }) => (
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ height: '100%', minHeight: 0 }} style={{
height: 'calc(var(--unit-100vh) - 155px)',
minHeight: 0
}}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='middle'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions type='job' id={jobId} disabled={loading} /> <ObjectActions
type='job'
id={jobId}
disabled={editFormState.loading}
/>
<ViewButton <ViewButton
disabled={loading} disabled={editFormState.loading}
items={[ items={[
{ key: 'info', label: 'Job Information' }, { key: 'info', label: 'Job Information' },
{ key: 'subJobs', label: 'Sub Jobs' }, { key: 'subJobs', label: 'Sub Jobs' },
@ -75,39 +93,52 @@ const JobInfo = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<LockIndicator lock={lock} /> <LockIndicator lock={editFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
isEditing={isEditing} isEditing={editFormState.isEditing}
handleUpdate={() => { handleUpdate={() => {
callAction('finishEdit') actionHandlerRef.current.callAction('finishEdit')
}} }}
cancelEditing={() => { cancelEditing={() => {
callAction('cancelEdit') actionHandlerRef.current.callAction('cancelEdit')
}} }}
startEditing={() => { startEditing={() => {
callAction('edit') actionHandlerRef.current.callAction('edit')
}} }}
editLoading={editLoading} editLoading={editFormState.editLoading}
formValid={formValid} formValid={editFormState.formValid}
disabled={true} disabled={editFormState.lock?.locked || editFormState.loading}
loading={editLoading} loading={editFormState.editLoading}
/> />
</Space> </Space>
</Flex> </Flex>
<div style={{ height: '100%', overflow: 'auto' }}> <div style={{ height: '100%', overflowY: 'scroll' }}>
<Flex vertical gap={'large'}> <Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={editFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse <InfoCollapse
title='Job Information' title='Job Information'
icon={<InfoCircleIcon />} icon={<InfoCircleIcon />}
active={collapseState.info} active={collapseState.info}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('info', expanded)}
updateCollapseState('info', expanded)
}
collapseKey='info' collapseKey='info'
> >
<EditObjectForm
id={jobId}
type='job'
style={{ height: '100%' }}
ref={editFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
@ -115,15 +146,16 @@ const JobInfo = () => {
type='job' type='job'
objectData={objectData} objectData={objectData}
/> />
)}
</EditObjectForm>
</InfoCollapse> </InfoCollapse>
</ActionHandler>
<InfoCollapse <InfoCollapse
title='Sub Jobs' title='Sub Jobs'
icon={<JobIcon />} icon={<JobIcon />}
active={collapseState.subJobs} active={collapseState.subJobs}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('subJobs', expanded)}
updateCollapseState('subJobs', expanded)
}
collapseKey='subJobs' collapseKey='subJobs'
> >
<ObjectTable <ObjectTable
@ -137,9 +169,7 @@ const JobInfo = () => {
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
active={collapseState.notes} active={collapseState.notes}
onToggle={(expanded) => onToggle={(expanded) => updateCollapseState('notes', expanded)}
updateCollapseState('notes', expanded)
}
collapseKey='notes' collapseKey='notes'
> >
<Card> <Card>
@ -156,7 +186,7 @@ const JobInfo = () => {
} }
collapseKey='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {editFormState.loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
) : ( ) : (
<ObjectTable <ObjectTable
@ -169,11 +199,7 @@ const JobInfo = () => {
</Flex> </Flex>
</div> </div>
</Flex> </Flex>
)} </>
</ActionHandler>
)
}}
</EditObjectForm>
) )
} }

View File

@ -83,7 +83,7 @@ const ActionHandler = forwardRef(
ActionHandler.displayName = 'ActionHandler' ActionHandler.displayName = 'ActionHandler'
ActionHandler.propTypes = { ActionHandler.propTypes = {
children: PropTypes.func, children: PropTypes.oneOf([PropTypes.func, PropTypes.object]),
actions: PropTypes.objectOf(PropTypes.func), actions: PropTypes.objectOf(PropTypes.func),
actionParam: PropTypes.string, actionParam: PropTypes.string,
clearAfterExecute: PropTypes.bool, clearAfterExecute: PropTypes.bool,

View File

@ -1,92 +0,0 @@
// NoteTypeSelect.js
import PropTypes from 'prop-types'
import { message, Tag, Select, Space } from 'antd'
import { useEffect, useState, useContext, useCallback } from 'react'
import axios from 'axios'
import { AuthContext } from '../context/AuthContext'
import config from '../../../config'
const NoteTypeSelect = ({ onChange, disabled, value = null }) => {
const [noteTypeOptions, setNoteTypeOptions] = useState([])
const [loading, setLoading] = useState(true)
const [messageApi] = message.useMessage()
const { authenticated } = useContext(AuthContext)
const fetchNoteTypesData = useCallback(async () => {
if (!authenticated) {
return
}
setLoading(true)
try {
const response = await axios.get(
`${config.backendUrl}/notetypes?active=true`,
{
headers: {
Accept: 'application/json'
},
withCredentials: true // Important for including cookies
}
)
const data = response.data
setNoteTypeOptions(() => {
var options = []
data.map((noteType) => {
var newNoteTypeOption = {
label: (
<Space>
<Tag color={noteType?.color}>{noteType.name}</Tag>
</Space>
),
value: noteType._id
}
options.push(newNoteTypeOption)
})
return options
})
setLoading(false)
} catch (error) {
if (error.response) {
// For other errors, show a message
messageApi.error(
'Error fetching note types data:',
error.response.status
)
} else {
messageApi.error(
'An unexpected error occurred. Please try again later.'
)
}
}
}, [authenticated, messageApi])
useEffect(() => {
if (authenticated) {
fetchNoteTypesData()
}
}, [authenticated, fetchNoteTypesData])
return (
<Select
options={noteTypeOptions}
onChange={onChange}
loading={loading}
disabled={disabled}
placeholder='Select note type'
style={{ width: '100%' }}
value={value}
/>
)
}
NoteTypeSelect.propTypes = {
onChange: PropTypes.func,
disabled: PropTypes.bool,
checkable: PropTypes.bool,
value: PropTypes.object
}
export default NoteTypeSelect

View File

@ -28,10 +28,10 @@ import config from '../../../config'
import { AuthContext } from '../context/AuthContext' import { AuthContext } from '../context/AuthContext'
import { ApiServerContext } from '../context/ApiServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import InfoCircleIcon from '../../Icons/InfoCircleIcon' import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import NoteTypeSelect from './NoteTypeSelect'
import IdDisplay from './IdDisplay' import IdDisplay from './IdDisplay'
import ReloadIcon from '../../Icons/ReloadIcon' import ReloadIcon from '../../Icons/ReloadIcon'
import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon' import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon'
import ObjectProperty from './ObjectProperty'
const { Text, Title } = Typography const { Text, Title } = Typography
const { TextArea } = Input const { TextArea } = Input
@ -621,7 +621,11 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
{ required: true, message: 'Please select a note type' } { required: true, message: 'Please select a note type' }
]} ]}
> >
<NoteTypeSelect /> <ObjectProperty
type='object'
objectType='noteType'
isEditing={true}
/>
</Form.Item> </Form.Item>
</Flex> </Flex>
</Form> </Form>

View File

@ -47,7 +47,7 @@ const OperationDisplay = ({
} }
OperationDisplay.propTypes = { OperationDisplay.propTypes = {
operation: PropTypes.bool.isRequired, operation: PropTypes.string.isRequired,
showIcon: PropTypes.bool, showIcon: PropTypes.bool,
showText: PropTypes.bool, showText: PropTypes.bool,
showColor: PropTypes.bool showColor: PropTypes.bool

View File

@ -38,7 +38,7 @@ const ApiServerProvider = ({ children }) => {
const subscribedCallbacksRef = useRef(new Map()) const subscribedCallbacksRef = useRef(new Map())
const subscribedLockCallbacksRef = useRef(new Map()) const subscribedLockCallbacksRef = useRef(new Map())
const notifyLockUpdate = useCallback( const handleLockUpdate = useCallback(
async (lockData) => { async (lockData) => {
logger.debug('Notifying lock update:', lockData) logger.debug('Notifying lock update:', lockData)
const objectId = lockData._id || lockData.id const objectId = lockData._id || lockData.id
@ -94,7 +94,7 @@ const ApiServerProvider = ({ children }) => {
newSocket.on('objectUpdate', handleObjectUpdate) newSocket.on('objectUpdate', handleObjectUpdate)
newSocket.on('objectNew', handleObjectNew) newSocket.on('objectNew', handleObjectNew)
newSocket.on('notify_lock_update', notifyLockUpdate) newSocket.on('lockUpdate', handleLockUpdate)
newSocket.on('disconnect', () => { newSocket.on('disconnect', () => {
logger.debug('Api Server disconnected') logger.debug('Api Server disconnected')
@ -123,7 +123,7 @@ const ApiServerProvider = ({ children }) => {
socketRef.current = newSocket socketRef.current = newSocket
} }
}, [token, authenticated, messageApi, notificationApi, notifyLockUpdate]) }, [token, authenticated, messageApi, notificationApi, handleLockUpdate])
useEffect(() => { useEffect(() => {
if (token && authenticated == true) { if (token && authenticated == true) {

View File

@ -1,6 +1,5 @@
// src/contexts/PrintServerContext.js // src/contexts/PrintServerContext.js
import { createContext, useEffect, useState, useContext, useRef } from 'react' import { createContext, useEffect, useState, useContext, useRef } from 'react'
import io from 'socket.io-client'
import { message, notification } from 'antd' import { message, notification } from 'antd'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { AuthContext } from './AuthContext' import { AuthContext } from './AuthContext'
@ -21,47 +20,9 @@ const PrintServerProvider = ({ children }) => {
useEffect(() => { useEffect(() => {
if (token) { if (token) {
log.debug('Token is available, connecting to print server...')
const newSocket = io(config.printServerUrl, {
reconnectionAttempts: 3,
timeout: 3000,
auth: { token: token }
})
setConnecting(true)
newSocket.on('connect', () => {
log.debug('Print server connected')
setConnecting(false) setConnecting(false)
setError(null) setError(null)
}) log.debug('Token is available, connecting to print server...')
newSocket.on('disconnect', () => {
log.debug('Print server disconnected')
setError('Print server disconnected')
})
newSocket.on('connect_error', (err) => {
log.error('Print server connection error:', err)
messageApi.error('Print server connection error: ' + err.message)
setError('Print server connection error')
})
newSocket.on('bridge.notification', (data) => {
notificationApi[data.type]({
title: data.title,
message: data.message
})
})
newSocket.on('error', (err) => {
log.error('Print server error:', err)
setError('Print server error')
})
socketRef.current = newSocket
// Clean up function // Clean up function
return () => { return () => {
if (socketRef.current) { if (socketRef.current) {

View File

@ -29,6 +29,7 @@ export const FilamentStock = {
], ],
filters: ['_id'], filters: ['_id'],
sorters: ['createdAt', 'updatedAt'], sorters: ['createdAt', 'updatedAt'],
group: ['filament'],
properties: [ properties: [
{ {
name: '_id', name: '_id',