Compare commits

..

No commits in common. "dcbf308988d0083295c918e1b50e63df2695ccfe" and "41f844b49dc267166b9b62e4e05801a591bf9ce7" have entirely different histories.

59 changed files with 479 additions and 1028 deletions

View File

@ -575,7 +575,7 @@ body {
.markdown p { .markdown p {
font-size: 14px; font-size: 14px;
margin: 10px 0; margin: 10px 0;
line-height: 1.6; line-height: 1;
} }
.markdown h1 { .markdown h1 {
@ -598,10 +598,6 @@ body {
width: 100%; width: 100%;
} }
.property-changes .markdown {
width: unset;
}
.markdown ul, .markdown ul,
.markdown ol { .markdown ol {
padding-left: 20px; padding-left: 20px;

View File

@ -31,16 +31,16 @@ const ApiContextDebug = () => {
connecting, connecting,
connected, connected,
fetchLoading, fetchLoading,
setObjectActivity, lockObject,
clearObjectActivity, unlockObject,
fetchObjectActivities, fetchObjectLock,
updateObject, updateObject,
createObject, createObject,
deleteObject, deleteObject,
subscribeToObjectUpdates, subscribeToObjectUpdates,
subscribeToObjectEvent, subscribeToObjectEvent,
subscribeToObjectTypeUpdates, subscribeToObjectTypeUpdates,
subscribeToObjectActivity, subscribeToObjectLock,
fetchObject, fetchObject,
fetchObjects, fetchObjects,
fetchObjectsByProperty, fetchObjectsByProperty,
@ -169,40 +169,40 @@ const ApiContextDebug = () => {
} }
} }
const testSetObjectActivity = () => { const testLockObject = () => {
try { try {
setObjectActivity(testInputs.objectId, testInputs.objectType, 'viewing') lockObject(testInputs.objectId, testInputs.objectType)
msgApi.success('setActivity command sent') msgApi.success('Lock command sent')
} catch (err) { } catch (err) {
msgApi.error('setActivity command failed') msgApi.error('Lock command failed')
logger.error('setActivity error:', err) logger.error('Lock error:', err)
} }
} }
const testClearObjectActivity = () => { const testUnlockObject = () => {
try { try {
clearObjectActivity(testInputs.objectId, testInputs.objectType) unlockObject(testInputs.objectId, testInputs.objectType)
msgApi.success('clearActivity command sent') msgApi.success('Unlock command sent')
} catch (err) { } catch (err) {
msgApi.error('clearActivity command failed') msgApi.error('Unlock command failed')
logger.error('clearActivity error:', err) logger.error('Unlock error:', err)
} }
} }
const testFetchObjectActivities = async () => { const testFetchObjectLock = async () => {
try { try {
msgApi.loading('Testing fetchObjectActivities...', 0) msgApi.loading('Testing fetchObjectLock...', 0)
const result = await fetchObjectActivities( const result = await fetchObjectLock(
testInputs.objectId, testInputs.objectId,
testInputs.objectType testInputs.objectType
) )
msgApi.destroy() msgApi.destroy()
msgApi.success('fetchObjectActivities test completed') msgApi.success('fetchObjectLock test completed')
logger.debug('fetchObjectActivities test completed', result) logger.debug('fetchObjectLock test completed', result)
} catch (err) { } catch (err) {
msgApi.destroy() msgApi.destroy()
msgApi.error('fetchObjectActivities test failed') msgApi.error('fetchObjectLock test failed')
logger.error('fetchObjectActivities error:', err) logger.error('fetchObjectLock error:', err)
} }
} }
@ -477,27 +477,28 @@ const ApiContextDebug = () => {
} }
} }
const testSubscribeToObjectActivity = () => { const testSubscribeToObjectLock = () => {
try { try {
const callback = (activity) => { const callback = (lockData) => {
logger.debug('Object activity update received:', activity) logger.debug('Object lock update received:', lockData)
} }
const unsubscribe = subscribeToObjectActivity( const unsubscribe = subscribeToObjectLock(
testInputs.objectId, testInputs.objectId,
testInputs.objectType, testInputs.objectType,
callback callback
) )
msgApi.success('Subscribed to object activity updates') msgApi.success('Subscribed to object lock updates')
logger.debug('Subscribed to object activity updates for test-id') logger.debug('Subscribed to object lock updates for test-id')
// Store unsubscribe function for cleanup
setTimeout(() => { setTimeout(() => {
if (unsubscribe) { if (unsubscribe) {
unsubscribe() unsubscribe()
logger.debug('Unsubscribed from object activity updates') logger.debug('Unsubscribed from object lock updates')
} }
}, 10000) }, 10000) // Auto-unsubscribe after 10 seconds
} catch (err) { } catch (err) {
msgApi.error('Subscribe to object activity updates failed') msgApi.error('Subscribe to object lock updates failed')
logger.error('Subscribe error:', err) logger.error('Subscribe error:', err)
} }
} }
@ -718,8 +719,8 @@ const ApiContextDebug = () => {
<Button onClick={testFetchObjects} block> <Button onClick={testFetchObjects} block>
Test fetchObjects Test fetchObjects
</Button> </Button>
<Button onClick={testFetchObjectActivities} block> <Button onClick={testFetchObjectLock} block>
Test fetchObjectActivities Test fetchObjectLock
</Button> </Button>
<Button onClick={testFetchObjectsByProperty} block> <Button onClick={testFetchObjectsByProperty} block>
Test fetchObjectsByProperty Test fetchObjectsByProperty
@ -745,11 +746,11 @@ const ApiContextDebug = () => {
collapseKey='crudTests' collapseKey='crudTests'
> >
<Space direction='vertical' style={{ width: '100%' }}> <Space direction='vertical' style={{ width: '100%' }}>
<Button onClick={testSetObjectActivity} block> <Button onClick={testLockObject} block>
Test Set Activity Test Lock Object
</Button> </Button>
<Button onClick={testClearObjectActivity} block> <Button onClick={testUnlockObject} block>
Test Clear Activity Test Unlock Object
</Button> </Button>
<Button onClick={testUpdateObject} block> <Button onClick={testUpdateObject} block>
Test updateObject Test updateObject
@ -802,8 +803,8 @@ const ApiContextDebug = () => {
<Button onClick={testSubscribeToObjectTypeUpdates} block> <Button onClick={testSubscribeToObjectTypeUpdates} block>
Test Subscribe Object Type Updates Test Subscribe Object Type Updates
</Button> </Button>
<Button onClick={testSubscribeToObjectActivity} block> <Button onClick={testSubscribeToObjectLock} block>
Test Subscribe Object Activity Test Subscribe Object Lock
</Button> </Button>
</Space> </Space>
</InfoCollapse> </InfoCollapse>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -16,7 +16,7 @@ import PaymentIcon from '../../../Icons/PaymentIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -110,7 +110,7 @@ const InvoiceInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='invoice' type='invoice'
@ -142,10 +142,7 @@ const InvoiceInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -162,7 +159,7 @@ const InvoiceInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -106,7 +106,7 @@ const PaymentInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='payment' type='payment'
@ -135,10 +135,7 @@ const PaymentInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -155,7 +152,7 @@ const PaymentInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -74,7 +74,7 @@ const TaxRecordInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='taxRecord' type='taxRecord'
@ -103,10 +103,7 @@ const TaxRecordInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -122,7 +119,7 @@ const TaxRecordInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import ObjectInfo from '../../common/ObjectInfo' import ObjectInfo from '../../common/ObjectInfo'
@ -11,7 +11,7 @@ import EditButtons from '../../common/EditButtons'
import ActionHandler from '../../common/ActionHandler' import ActionHandler from '../../common/ActionHandler'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import ActivityIndicator from '../../common/ActivityIndicator' import LockIndicator from '../../common/LockIndicator'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon' import InfoCircleIcon from '../../../Icons/InfoCircleIcon'
import FilamentStockIcon from '../../../Icons/FilamentStockIcon' import FilamentStockIcon from '../../../Icons/FilamentStockIcon'
import NoteIcon from '../../../Icons/NoteIcon' import NoteIcon from '../../../Icons/NoteIcon'
@ -69,7 +69,7 @@ const FilamentStockInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filamentStock' type='filamentStock'
@ -99,10 +99,7 @@ const FilamentStockInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -78,7 +78,7 @@ const OrderItemInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='orderItem' type='orderItem'
@ -102,10 +102,7 @@ const OrderItemInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -121,7 +118,7 @@ const OrderItemInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -45,7 +45,7 @@ const PartStockInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -76,7 +76,7 @@ const PartStockInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='partStock' type='partStock'
@ -105,10 +105,7 @@ const PartStockInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -124,7 +121,7 @@ const PartStockInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -21,7 +21,7 @@ import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import PartStockIcon from '../../../Icons/PartStockIcon.jsx' import PartStockIcon from '../../../Icons/PartStockIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -55,7 +55,7 @@ const ProductStockInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -99,7 +99,7 @@ const ProductStockInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productStock' type='productStock'
@ -129,10 +129,7 @@ const ProductStockInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -149,7 +146,7 @@ const ProductStockInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -136,7 +136,7 @@ const PurchaseOrderInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='purchaseOrder' type='purchaseOrder'
@ -169,10 +169,7 @@ const PurchaseOrderInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -189,7 +186,7 @@ const PurchaseOrderInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -112,7 +112,7 @@ const PurchaseOrderInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='purchaseOrder' type='purchaseOrder'
@ -138,10 +138,7 @@ const PurchaseOrderInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -157,7 +154,7 @@ const PurchaseOrderInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -98,7 +98,7 @@ const ShipmentInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='shipment' type='shipment'
@ -127,10 +127,7 @@ const ShipmentInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -146,7 +143,7 @@ const ShipmentInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -45,7 +45,7 @@ const StockAuditInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -76,7 +76,7 @@ const StockAuditInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockAudit' type='stockAudit'
@ -105,10 +105,7 @@ const StockAuditInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -124,7 +121,7 @@ const StockAuditInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -46,7 +46,7 @@ const StockLocationInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -77,7 +77,7 @@ const StockLocationInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockLocation' type='stockLocation'
@ -106,10 +106,7 @@ const StockLocationInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -125,7 +122,7 @@ const StockLocationInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState.jsx' import useCollapseState from '../../hooks/useCollapseState.jsx'
import NotesPanel from '../../common/NotesPanel.jsx' import NotesPanel from '../../common/NotesPanel.jsx'
@ -19,7 +19,7 @@ import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import StockTransferIcon from '../../../Icons/StockTransferIcon.jsx' import StockTransferIcon from '../../../Icons/StockTransferIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -50,7 +50,7 @@ const StockTransferInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -94,7 +94,7 @@ const StockTransferInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockTransfer' type='stockTransfer'
@ -124,10 +124,7 @@ const StockTransferInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -144,7 +141,7 @@ const StockTransferInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState, useContext } from 'react' import { useRef, useState, useContext } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Flex, Modal, Space } from 'antd' import { Space, Flex, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -10,7 +10,7 @@ import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -78,7 +78,7 @@ const AppPasswordInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='appPassword' type='appPassword'
@ -106,10 +106,7 @@ const AppPasswordInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -126,7 +123,7 @@ const AppPasswordInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -76,7 +76,7 @@ const CourierServiceInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='courierService' type='courierService'
@ -105,10 +105,7 @@ const CourierServiceInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -124,7 +121,7 @@ const CourierServiceInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -72,7 +72,7 @@ const CourierInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='courier' type='courier'
@ -101,10 +101,7 @@ const CourierInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -120,7 +117,7 @@ const CourierInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -73,7 +73,7 @@ const DocumentJobInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentJob' type='documentJob'
@ -102,10 +102,7 @@ const DocumentJobInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -121,7 +118,7 @@ const DocumentJobInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -47,7 +47,7 @@ const DocumentPrinterInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -78,7 +78,7 @@ const DocumentPrinterInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentPrinter' type='documentPrinter'
@ -110,10 +110,7 @@ const DocumentPrinterInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -129,7 +126,7 @@ const DocumentPrinterInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -73,7 +73,7 @@ const DocumentSizeInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentSize' type='documentSize'
@ -102,10 +102,7 @@ const DocumentSizeInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -121,7 +118,7 @@ const DocumentSizeInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -10,7 +10,7 @@ import ViewButton from '../../common/ViewButton.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
@ -41,7 +41,7 @@ const DocumentTemplateDesign = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -97,7 +97,7 @@ const DocumentTemplateDesign = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<ActivityIndicator activities={objectFormState.activities} /> <LockIndicator lock={objectFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -113,7 +113,7 @@ const DocumentTemplateDesign = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -47,7 +47,7 @@ const DocumentTemplateInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -78,7 +78,7 @@ const DocumentTemplateInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentTemplate' type='documentTemplate'
@ -107,10 +107,7 @@ const DocumentTemplateInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -126,7 +123,7 @@ const DocumentTemplateInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,7 +8,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
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'
@ -71,7 +71,7 @@ const FilamentSkuInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filamentSku' type='filamentSku'
@ -100,10 +100,7 @@ const FilamentSkuInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -119,7 +116,7 @@ const FilamentSkuInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler' import ActionHandler from '../../common/ActionHandler'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -90,7 +90,7 @@ const FilamentInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filament' type='filament'
@ -121,10 +121,7 @@ const FilamentInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -140,7 +137,7 @@ const FilamentInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useContext, useRef, useState } from 'react' import { useContext, useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
import useCollapseState from '../../hooks/useCollapseState.jsx' import useCollapseState from '../../hooks/useCollapseState.jsx'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -82,7 +82,7 @@ const FileInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='file' type='file'
@ -112,10 +112,7 @@ const FileInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -131,7 +128,7 @@ const FileInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -47,7 +47,7 @@ const HostInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -86,7 +86,7 @@ const HostInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='host' type='host'
@ -117,10 +117,7 @@ const HostInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -136,7 +133,7 @@ const HostInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -74,7 +74,7 @@ const MaterialInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='material' type='material'
@ -103,10 +103,7 @@ const MaterialInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -122,7 +119,7 @@ const MaterialInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Flex, Space } from 'antd' import { Space, Flex } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -10,7 +10,7 @@ import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -63,7 +63,7 @@ const NoteTypeInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='noteType' type='noteType'
@ -91,10 +91,7 @@ const NoteTypeInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -110,7 +107,7 @@ const NoteTypeInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -16,7 +16,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -76,7 +76,7 @@ const NoteInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='note' type='note'
@ -106,10 +106,7 @@ const NoteInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -125,7 +122,7 @@ const NoteInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,7 +8,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
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'
@ -66,7 +66,7 @@ const PartSkuInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='partSku' type='partSku'
@ -95,10 +95,7 @@ const PartSkuInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -114,7 +111,7 @@ const PartSkuInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,7 +8,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
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'
@ -71,7 +71,7 @@ const PartInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='part' type='part'
@ -101,10 +101,7 @@ const PartInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -120,7 +117,7 @@ const PartInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -11,7 +11,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -71,7 +71,7 @@ const ProductCategoryInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productCategory' type='productCategory'
@ -100,10 +100,7 @@ const ProductCategoryInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -119,7 +116,7 @@ const ProductCategoryInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,7 +8,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
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'
@ -73,7 +73,7 @@ const ProductSkuInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productSku' type='productSku'
@ -103,10 +103,7 @@ const ProductSkuInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -122,7 +119,7 @@ const ProductSkuInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,7 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { Modal } from 'antd'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,7 +9,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
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'
@ -71,7 +72,7 @@ const ProductInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='product' type='product'
@ -101,10 +102,7 @@ const ProductInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -120,7 +118,7 @@ const ProductInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -71,7 +71,7 @@ const TaxRateInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='taxRate' type='taxRate'
@ -100,10 +100,7 @@ const TaxRateInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -119,7 +116,7 @@ const TaxRateInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
@ -13,7 +13,7 @@ import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import AppPasswordIcon from '../../../Icons/AppPasswordIcon.jsx' import AppPasswordIcon from '../../../Icons/AppPasswordIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler' import ActionHandler from '../../common/ActionHandler'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -76,7 +76,7 @@ const UserInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='user' type='user'
@ -106,10 +106,7 @@ const UserInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -125,7 +122,7 @@ const UserInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -71,7 +71,7 @@ const VendorInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='vendor' type='vendor'
@ -100,10 +100,7 @@ const VendorInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -119,7 +116,7 @@ const VendorInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -12,7 +12,7 @@ import HotEndIcon from '../../../Icons/HotEndIcon'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon' import InfoCircleIcon from '../../../Icons/InfoCircleIcon'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
import ActivityIndicator from '../../common/ActivityIndicator' import LockIndicator from '../../common/LockIndicator'
import MultiMotionIcon from '../../../Icons/MultiMotionIcon' import MultiMotionIcon from '../../../Icons/MultiMotionIcon'
import NoteIcon from '../../../Icons/NoteIcon' import NoteIcon from '../../../Icons/NoteIcon'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
@ -108,7 +108,7 @@ const FilamentProfileInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify='space-between'> <Flex justify='space-between'>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filamentProfile' type='filamentProfile'
@ -150,10 +150,7 @@ const FilamentProfileInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<EditButtons <EditButtons
isEditing={objectFormState.isEditing} isEditing={objectFormState.isEditing}
@ -164,7 +161,7 @@ const FilamentProfileInfo = () => {
startEditing={() => actionHandlerRef.current.callAction('edit')} startEditing={() => actionHandlerRef.current.callAction('edit')}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Flex> </Flex>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -15,7 +15,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -48,7 +48,7 @@ const GCodeFileInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -79,7 +79,7 @@ const GCodeFileInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='gcodeFile' type='gcodeFile'
@ -109,10 +109,7 @@ const GCodeFileInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -128,7 +125,7 @@ const GCodeFileInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -10,7 +10,7 @@ import ViewButton from '../../common/ViewButton.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import EyeIcon from '../../../Icons/EyeIcon.jsx' import EyeIcon from '../../../Icons/EyeIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import FilePreview from '../../common/FilePreview.jsx' import FilePreview from '../../common/FilePreview.jsx'
@ -79,7 +79,7 @@ const GCodeFilePreview = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator activities={objectFormState.activities} /> <LockIndicator lock={objectFormState.lock} />
</Space> </Space>
</Flex> </Flex>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -47,7 +47,7 @@ const JobInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: { objectData: {
_id: jobId _id: jobId
@ -89,7 +89,7 @@ const JobInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='job' type='job'
@ -119,10 +119,7 @@ const JobInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -139,7 +136,7 @@ const JobInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -13,7 +13,7 @@ import PictureIcon from '../../../Icons/PictureIcon'
import RulerIcon from '../../../Icons/RulerIcon' import RulerIcon from '../../../Icons/RulerIcon'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
import ActivityIndicator from '../../common/ActivityIndicator' import LockIndicator from '../../common/LockIndicator'
import NoteIcon from '../../../Icons/NoteIcon' import NoteIcon from '../../../Icons/NoteIcon'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import ObjectActions from '../../common/ObjectActions' import ObjectActions from '../../common/ObjectActions'
@ -87,7 +87,7 @@ const PrinterProfileInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify='space-between'> <Flex justify='space-between'>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='printerProfile' type='printerProfile'
@ -123,10 +123,7 @@ const PrinterProfileInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<EditButtons <EditButtons
isEditing={objectFormState.isEditing} isEditing={objectFormState.isEditing}
@ -137,7 +134,7 @@ const PrinterProfileInfo = () => {
startEditing={() => actionHandlerRef.current.callAction('edit')} startEditing={() => actionHandlerRef.current.callAction('edit')}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Flex> </Flex>

View File

@ -79,7 +79,7 @@ const ControlPrinter = ({ slicerIntegration = false }) => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import NewPrinterProfile from '../PrinterProfiles/NewPrinterProfile' import NewPrinterProfile from '../PrinterProfiles/NewPrinterProfile'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
@ -15,7 +15,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -45,7 +45,7 @@ const PrinterInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -81,7 +81,7 @@ const PrinterInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='printer' type='printer'
@ -111,10 +111,7 @@ const PrinterInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -130,7 +127,7 @@ const PrinterInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -34,7 +34,7 @@ const SlicerIntegration = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: { objectData: {
pendingSlicerUploads: [] pendingSlicerUploads: []

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } 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 useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
@ -12,7 +12,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler' import ActionHandler from '../../common/ActionHandler'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -64,7 +64,7 @@ const SubJobInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='subJob' type='subJob'
@ -93,10 +93,7 @@ const SubJobInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -71,7 +71,7 @@ const ClientInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='client' type='client'
@ -100,10 +100,7 @@ const ClientInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -119,7 +116,7 @@ const ClientInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Modal } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -23,6 +23,7 @@ import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import PublishListingVarient from './PublishListingVarient.jsx' import PublishListingVarient from './PublishListingVarient.jsx'
import UnpublishListingVarient from './UnpublishListingVarient.jsx' import UnpublishListingVarient from './UnpublishListingVarient.jsx'
import { Card } from 'antd'
const log = loglevel.getLogger('ListingVarientInfo') const log = loglevel.getLogger('ListingVarientInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -88,7 +89,7 @@ const ListingVarientInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='listingVarient' type='listingVarient'
@ -117,10 +118,7 @@ const ListingVarientInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -136,7 +134,7 @@ const ListingVarientInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Modal } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -14,7 +14,7 @@ import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ListingVarientIcon from '../../../Icons/ListingVarientIcon.jsx' import ListingVarientIcon from '../../../Icons/ListingVarientIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -25,6 +25,7 @@ import ScrollBox from '../../common/ScrollBox.jsx'
import NewListingVarient from '../ListingVarients/NewListingVarient.jsx' import NewListingVarient from '../ListingVarients/NewListingVarient.jsx'
import PublishListing from './PublishListing.jsx' import PublishListing from './PublishListing.jsx'
import UnpublishListing from './UnpublishListing.jsx' import UnpublishListing from './UnpublishListing.jsx'
import { Card } from 'antd'
const log = loglevel.getLogger('ListingInfo') const log = loglevel.getLogger('ListingInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -92,7 +93,7 @@ const ListingInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='listing' type='listing'
@ -122,10 +123,7 @@ const ListingInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -141,7 +139,7 @@ const ListingInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useContext, useRef, useState } from 'react' import { useContext, useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, message, Modal, Space } from 'antd' import { Space, Flex, Modal, message } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,7 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -21,6 +21,7 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx' import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import { Card } from 'antd'
import SyncListings from './SyncListings.jsx' import SyncListings from './SyncListings.jsx'
import SyncOrders from './SyncOrders.jsx' import SyncOrders from './SyncOrders.jsx'
import ConfigureMarketplace from './ConfigureMarketplace.jsx' import ConfigureMarketplace from './ConfigureMarketplace.jsx'
@ -161,7 +162,7 @@ const MarketplaceInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='marketplace' type='marketplace'
@ -190,10 +191,7 @@ const MarketplaceInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -209,7 +207,7 @@ const MarketplaceInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -14,7 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.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'
@ -133,7 +133,7 @@ const SalesOrderInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='salesOrder' type='salesOrder'
@ -166,10 +166,7 @@ const SalesOrderInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -186,7 +183,7 @@ const SalesOrderInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }

View File

@ -1,255 +0,0 @@
import { useState, useEffect, useContext, useRef, memo } from 'react'
import { Flex, Card, Popover, Divider } from 'antd'
import { UserOutlined } from '@ant-design/icons'
import PropTypes from 'prop-types'
import EditIcon from '../../Icons/EditIcon'
import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext'
import SpotlightTooltip from './SpotlightTooltip'
import { useNavigate } from 'react-router-dom'
import { getModelByName } from '../../../database/ObjectModels'
const getUserId = (user) => user?._id || user
const getProfileImageId = (user) => {
const profileImage = user?.profileImage
return (
profileImage?._id ||
(typeof profileImage === 'string' ? profileImage : null)
)
}
const getDisplayName = (user) =>
user?.name ||
[user?.firstName, user?.lastName].filter(Boolean).join(' ') ||
user?.username ||
'User'
const avatarImageStyle = {
width: 32,
height: 32,
borderRadius: '12px',
objectFit: 'cover',
border: '1px solid rgb(128, 128, 128, 0.4)'
}
const avatarCardStyle = { borderRadius: '12px', width: 32, height: 32 }
const UserProfileImage = memo(function UserProfileImage({
profileImageId,
displayName
}) {
const { fetchFileContent } = useContext(ApiServerContext)
const fetchFileContentRef = useRef(fetchFileContent)
fetchFileContentRef.current = fetchFileContent
const [profileImageUrl, setProfileImageUrl] = useState(null)
const profileImageUrlRef = useRef(null)
const loadedImageIdRef = useRef(null)
useEffect(() => {
if (!profileImageId) {
if (profileImageUrlRef.current) {
URL.revokeObjectURL(profileImageUrlRef.current)
profileImageUrlRef.current = null
}
loadedImageIdRef.current = null
setProfileImageUrl(null)
return
}
if (
loadedImageIdRef.current === profileImageId &&
profileImageUrlRef.current
) {
return
}
let cancelled = false
const file = { _id: profileImageId, name: '', extension: '' }
const loadProfileImage = async () => {
try {
const fileURL = await fetchFileContentRef.current(file, false)
if (!cancelled) {
if (profileImageUrlRef.current) {
URL.revokeObjectURL(profileImageUrlRef.current)
}
profileImageUrlRef.current = fileURL || null
loadedImageIdRef.current = profileImageId
setProfileImageUrl(fileURL || null)
} else if (fileURL) {
URL.revokeObjectURL(fileURL)
}
} catch {
if (!cancelled) {
setProfileImageUrl(null)
}
}
}
loadProfileImage()
return () => {
cancelled = true
}
}, [profileImageId])
useEffect(() => {
return () => {
if (profileImageUrlRef.current) {
URL.revokeObjectURL(profileImageUrlRef.current)
profileImageUrlRef.current = null
}
loadedImageIdRef.current = null
}
}, [])
if (profileImageUrl) {
return (
<img src={profileImageUrl} alt={displayName} style={avatarImageStyle} />
)
}
return (
<Card
style={avatarCardStyle}
styles={{ body: { padding: 0, height: '100%' } }}
>
<Flex justify='center' align='center' style={{ height: '100%' }}>
<UserOutlined
style={{
fontSize: 14,
color: 'var(--color-text-secondary)'
}}
/>
</Flex>
</Card>
)
})
UserProfileImage.propTypes = {
profileImageId: PropTypes.string,
displayName: PropTypes.string.isRequired
}
const UserActivityAvatar = memo(
function UserActivityAvatar({ user, mode }) {
const profileImageId = getProfileImageId(user)
const displayName = getDisplayName(user)
const navigate = useNavigate()
const model = getModelByName('user')
// Get hyperlink URL from model's default actions
var hyperlink = null
const defaultModelActions =
model.actions?.filter((action) => action.default == true) || []
if (defaultModelActions.length >= 1 && getUserId(user)) {
hyperlink = defaultModelActions[0].url(getUserId(user))
}
return (
<Popover
content={<SpotlightTooltip query={`USR:${user?._id}`} type='user' />}
placement='bottomLeft'
arrow={false}
style={{ padding: 0 }}
>
<div
style={{
position: 'relative',
width: 32,
height: 32,
cursor: 'pointer',
borderRadius: '12px'
}}
onClick={() => {
navigate(hyperlink)
}}
>
<UserProfileImage
profileImageId={profileImageId}
displayName={displayName}
/>
{mode === 'editing' && (
<div
style={{
position: 'absolute',
right: -4,
bottom: -4,
width: 14,
height: 14,
borderRadius: '50%',
background: 'var(--color-warning)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 0 0 1px var(--color-border)'
}}
>
<EditIcon style={{ fontSize: 8, color: '#ffffff' }} />
</div>
)}
</div>
</Popover>
)
},
(prevProps, nextProps) => {
return (
prevProps.mode === nextProps.mode &&
getUserId(prevProps.user) === getUserId(nextProps.user) &&
getProfileImageId(prevProps.user) === getProfileImageId(nextProps.user)
)
}
)
UserActivityAvatar.propTypes = {
user: PropTypes.object,
mode: PropTypes.string
}
const ActivityIndicator = ({
activities = [],
showStartingDivider = false
}) => {
const { userProfile } = useContext(AuthContext)
const currentUserId = userProfile?._id
const otherActivities = activities.filter((activity) => {
if (!activity?.mode) return false
const userId = getUserId(activity.user)
return userId && userId !== currentUserId
})
if (otherActivities.length === 0) {
return null
}
return (
<Flex gap='small' align='center'>
{showStartingDivider && otherActivities.length >= 1 && (
<Divider type='vertical' style={{ margin: '0 4px', height: '18px' }} />
)}
{otherActivities.map((activity) => {
const userId = getUserId(activity.user)
return (
<UserActivityAvatar
key={userId}
user={activity.user}
mode={activity.mode}
/>
)
})}
</Flex>
)
}
ActivityIndicator.propTypes = {
activities: PropTypes.array,
showStartingDivider: PropTypes.bool
}
export default ActivityIndicator

View File

@ -0,0 +1,27 @@
import { Flex, Tag } from 'antd'
import IdDisplay from './IdDisplay'
import LockIcon from '../../Icons/LockIcon'
import PropTypes from 'prop-types'
const LockIndicator = ({ lock }) => {
if (!lock?.locked || lock?.locked == false) {
return
}
return (
<Flex gap={'small'} align='center'>
<Tag icon={<LockIcon />} style={{ margin: 0 }} color={'orange'} />
<IdDisplay
id={lock?.user}
type={'user'}
longId={false}
showCopy={false}
/>
</Flex>
)
}
LockIndicator.propTypes = {
lock: PropTypes.object
}
export default LockIndicator

View File

@ -170,7 +170,7 @@ const NoteItem = ({
<PersonIcon /> <PersonIcon />
<Text style={{ whiteSpace: 'nowrap' }}>{note.user.name}:</Text> <Text style={{ whiteSpace: 'nowrap' }}>{note.user.name}:</Text>
</Space> </Space>
<div style={{ marginTop: '1px' }}> <div style={{ marginTop: '4px' }}>
<MarkdownDisplay content={note.content} /> <MarkdownDisplay content={note.content} />
</div> </div>
</Flex> </Flex>

View File

@ -11,13 +11,13 @@ import { Form } from 'antd'
import { ApiServerContext } from '../context/ApiServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext' import { AuthContext } from '../context/AuthContext'
import { useMessageContext } from '../context/MessageContext' import { useMessageContext } from '../context/MessageContext'
import PropTypes from 'prop-types'
import DeleteObjectModal from './DeleteObjectModal' import DeleteObjectModal from './DeleteObjectModal'
import merge from 'lodash/merge' import merge from 'lodash/merge'
import mergeWith from 'lodash/mergeWith' import mergeWith from 'lodash/mergeWith'
import set from 'lodash/set' import set from 'lodash/set'
import { getModelByName } from '../../../database/ObjectModels' import { getModelByName } from '../../../database/ObjectModels'
import { useLocation, useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import PropTypes from 'prop-types'
const arrayReplaceCustomizer = (objValue, srcValue) => { const arrayReplaceCustomizer = (objValue, srcValue) => {
if (Array.isArray(srcValue)) { if (Array.isArray(srcValue)) {
@ -25,45 +25,6 @@ const arrayReplaceCustomizer = (objValue, srcValue) => {
} }
} }
const getUserId = (user) => user?._id || user
const getBeingEditedByOther = (activities, currentUserId) =>
activities.some(
(activity) =>
activity?.mode === 'editing' &&
getUserId(activity.user) &&
getUserId(activity.user) !== currentUserId
)
const isUserEditing = (activities, currentUserId) =>
activities.some(
(activity) =>
activity?.mode === 'editing' && getUserId(activity.user) === currentUserId
)
const applyActivityUpdate = (activities, activity) => {
const userId = getUserId(activity?.user)
if (!userId) {
return activities
}
if (!activity?.mode) {
return activities.filter((item) => getUserId(item.user) !== userId)
}
const existingIndex = activities.findIndex(
(item) => getUserId(item.user) === userId
)
if (existingIndex >= 0) {
const next = [...activities]
next[existingIndex] = { ...activities[existingIndex], ...activity }
return next
}
return [...activities, activity]
}
const buildObjectFromEntries = (entries = []) => { const buildObjectFromEntries = (entries = []) => {
return entries.reduce((acc, entry) => { return entries.reduce((acc, entry) => {
const { namePath, value } = entry || {} const { namePath, value } = entry || {}
@ -94,7 +55,7 @@ const ObjectForm = forwardRef(
const onStateChangeRef = useRef(onStateChange) 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 [activities, setActivities] = 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 isEditingRef = useRef(false) const isEditingRef = useRef(false)
@ -109,49 +70,20 @@ const ObjectForm = forwardRef(
fetchObject, fetchObject,
updateObject, updateObject,
deleteObject, deleteObject,
setObjectActivity, lockObject,
clearObjectActivity, unlockObject,
fetchObjectActivities, fetchObjectLock,
showError, showError,
connected, connected,
subscribeToObjectUpdates, subscribeToObjectUpdates,
subscribeToObjectActivity, subscribeToObjectLock,
flushFile flushFile
} = useContext(ApiServerContext) } = useContext(ApiServerContext)
const { token, userProfile } = useContext(AuthContext) const { token } = useContext(AuthContext)
const location = useLocation()
const navigate = useNavigate() const navigate = useNavigate()
const clearAction = useCallback(
(actionParam = 'action') => {
const searchParams = new URLSearchParams(location.search)
searchParams.delete(actionParam)
const newSearch = searchParams.toString()
console.log('newSearch', newSearch)
console.log('location.pathname', location.pathname)
const newPath = location.pathname + (newSearch ? `?${newSearch}` : '')
navigate(newPath, { replace: true })
},
[location.pathname, location.search, navigate]
)
// Get the model definition for this object type // Get the model definition for this object type
const model = getModelByName(type) const model = getModelByName(type)
const notifyActivityState = useCallback(
(nextActivities) => {
onStateChangeRef.current({
activities: nextActivities,
beingEditedByOther: getBeingEditedByOther(
nextActivities,
userProfile?._id
)
})
},
[userProfile?._id]
)
// Check if the model has properties with type 'file' or 'fileList' // Check if the model has properties with type 'file' or 'fileList'
const hasFileProperties = useCallback(() => { const hasFileProperties = useCallback(() => {
if (!model || !model.properties) return false if (!model || !model.properties) return false
@ -190,8 +122,7 @@ const ObjectForm = forwardRef(
const currentIdRef = useRef(id) const currentIdRef = useRef(id)
const currentTypeRef = useRef(type) const currentTypeRef = useRef(type)
const currentIsEditingRef = useRef(isEditing) const currentIsEditingRef = useRef(isEditing)
const currentSetObjectActivityRef = useRef(setObjectActivity) const currentUnlockObjectRef = useRef(unlockObject)
const currentClearObjectActivityRef = useRef(clearObjectActivity)
const currentHasFilePropertiesRef = useRef(hasFileProperties) const currentHasFilePropertiesRef = useRef(hasFileProperties)
const currentFlushOrphanFilesRef = useRef(flushOrphanFiles) const currentFlushOrphanFilesRef = useRef(flushOrphanFiles)
@ -200,8 +131,7 @@ const ObjectForm = forwardRef(
currentIdRef.current = id currentIdRef.current = id
currentTypeRef.current = type currentTypeRef.current = type
currentIsEditingRef.current = isEditing currentIsEditingRef.current = isEditing
currentSetObjectActivityRef.current = setObjectActivity currentUnlockObjectRef.current = unlockObject
currentClearObjectActivityRef.current = clearObjectActivity
currentHasFilePropertiesRef.current = hasFileProperties currentHasFilePropertiesRef.current = hasFileProperties
currentFlushOrphanFilesRef.current = flushOrphanFiles currentFlushOrphanFilesRef.current = flushOrphanFiles
}) })
@ -303,67 +233,6 @@ const ObjectForm = forwardRef(
[] []
) )
const releaseEditingState = useCallback(
(options = {}) => {
const { notifyParent = true } = options
if (serverObjectData.current) {
const computedEntries = calculateComputedValues(
serverObjectData.current,
model
)
const computedValuesObject = buildObjectFromEntries(computedEntries)
const resetFormData = merge(
{},
serverObjectData.current,
computedValuesObject
)
setIsEditing(false)
isEditingRef.current = false
form.setFieldsValue(resetFormData)
setObjectData({ ...resetFormData, _isEditing: false })
} else {
setIsEditing(false)
isEditingRef.current = false
}
if (notifyParent) {
onStateChangeRef.current({ isEditing: false })
}
},
[calculateComputedValues, form, model]
)
const handleEditingConflict = useCallback(
(nextActivities) => {
const currentUserId = userProfile?._id
if (
!isEditingRef.current ||
!getBeingEditedByOther(nextActivities, currentUserId)
) {
return
}
if (isUserEditing(nextActivities, currentUserId)) {
setObjectActivity(id, type, 'editing')
return
}
releaseEditingState()
clearAction()
showMessageError('Another user is already editing this item')
},
[
id,
type,
userProfile?._id,
setObjectActivity,
releaseEditingState,
clearAction,
showMessageError
]
)
// 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(() => {
@ -399,7 +268,7 @@ const ObjectForm = forwardRef(
useEffect(() => { useEffect(() => {
return () => { return () => {
if (currentIdRef.current) { if (currentIdRef.current) {
currentClearObjectActivityRef.current( currentUnlockObjectRef.current(
currentIdRef.current, currentIdRef.current,
currentTypeRef.current currentTypeRef.current
) )
@ -420,16 +289,9 @@ const ObjectForm = forwardRef(
setFetchLoading(true) setFetchLoading(true)
onStateChangeRef.current({ loading: true }) onStateChangeRef.current({ loading: true })
const data = await fetchObject(id, type) const data = await fetchObject(id, type)
const initialActivities = await fetchObjectActivities(id, type) const lockEvent = await fetchObjectLock(id, type)
setActivities(initialActivities) setLock(lockEvent)
notifyActivityState(initialActivities) onStateChangeRef.current({ lock: lockEvent })
if (
isEditingRef.current &&
getBeingEditedByOther(initialActivities, userProfile?._id)
) {
releaseEditingState()
}
serverObjectData.current = data serverObjectData.current = data
@ -451,17 +313,14 @@ const ObjectForm = forwardRef(
} }
}, [ }, [
fetchObject, fetchObject,
fetchObjectActivities, fetchObjectLock,
notifyActivityState,
id, id,
type, type,
form, form,
showMessageError, showMessageError,
showError, showError,
calculateComputedValues, calculateComputedValues,
model, model
userProfile?._id,
releaseEditingState
]) ])
// Update event handler // Update event handler
@ -472,19 +331,12 @@ const ObjectForm = forwardRef(
}, []) }, [])
// Update event handler // Update event handler
const updateActivityEventHandler = useCallback( const updateLockEventHandler = useCallback((value) => {
(activity, activities) => { setLock((prev) => {
setActivities((prev) => { onStateChangeRef.current({ lock: { ...prev, ...value } })
const next = Array.isArray(activities) return { ...prev, ...value }
? activities
: applyActivityUpdate(prev, activity)
notifyActivityState(next)
handleEditingConflict(next)
return next
}) })
}, }, [])
[notifyActivityState, handleEditingConflict]
)
useEffect(() => { useEffect(() => {
if (connected == true && initialized == false && id && token != null) { if (connected == true && initialized == false && id && token != null) {
@ -495,37 +347,29 @@ const ObjectForm = forwardRef(
useEffect(() => { useEffect(() => {
if (id && connected) { if (id && connected) {
currentSetObjectActivityRef.current(
id,
type,
isEditingRef.current == true ? 'editing' : 'viewing'
)
const objectUpdatesUnsubscribe = subscribeToObjectUpdates( const objectUpdatesUnsubscribe = subscribeToObjectUpdates(
id, id,
type, type,
updateObjectEventHandler updateObjectEventHandler
) )
const activityUnsubscribe = subscribeToObjectActivity( const lockUnsubscribe = subscribeToObjectLock(
id, id,
type, type,
updateActivityEventHandler updateLockEventHandler
) )
return () => { return () => {
if (objectUpdatesUnsubscribe) objectUpdatesUnsubscribe() if (objectUpdatesUnsubscribe) objectUpdatesUnsubscribe()
if (activityUnsubscribe) activityUnsubscribe() if (lockUnsubscribe) lockUnsubscribe()
currentClearObjectActivityRef.current(id, type)
} }
} }
}, [ }, [
id, id,
type, type,
connected,
subscribeToObjectUpdates, subscribeToObjectUpdates,
subscribeToObjectActivity, subscribeToObjectLock,
updateObjectEventHandler, updateObjectEventHandler,
updateActivityEventHandler connected,
updateLockEventHandler
]) ])
// Debounce objectData updates sent to parent to limit re-renders // Debounce objectData updates sent to parent to limit re-renders
@ -536,52 +380,51 @@ const ObjectForm = forwardRef(
return () => clearTimeout(timeoutId) return () => clearTimeout(timeoutId)
}, [objectData]) }, [objectData])
const startEditing = async () => { const startEditing = () => {
try {
const latestActivities = await fetchObjectActivities(id, type)
setActivities(latestActivities)
notifyActivityState(latestActivities)
if (getBeingEditedByOther(latestActivities, userProfile?._id)) {
clearAction()
showMessageError('Another user is already editing this item')
return
}
const activityResult = await setObjectActivity(id, type, 'editing')
if (activityResult?.success === false) {
clearAction()
showMessageError('Another user is already editing this item')
return
}
isEditingRef.current = true
setIsEditing(true) setIsEditing(true)
isEditingRef.current = true
const computedEntries = calculateComputedValues(objectData, model) const computedEntries = calculateComputedValues(objectData, model)
const computedValuesObject = buildObjectFromEntries(computedEntries) const computedValuesObject = buildObjectFromEntries(computedEntries)
setObjectData((prev) => ({ setObjectData((prev) => ({
...prev, ...prev,
...computedValuesObject, ...computedValuesObject,
_isEditing: true _isEditing: isEditingRef.current
})) }))
onStateChangeRef.current({ onStateChangeRef.current({
isEditing: true, isEditing: true,
objectData: { objectData: {
...objectData, ...objectData,
...computedValuesObject, ...computedValuesObject,
_isEditing: true _isEditing: isEditingRef.current
} }
}) })
} catch (err) { lockObject(id, type)
console.error(err)
showMessageError('Failed to start editing')
}
} }
const cancelEditing = () => { const cancelEditing = () => {
releaseEditingState() console.log('cancelEditing')
setObjectActivity(id, type, 'viewing')
if (serverObjectData.current) {
// Recalculate computed values when canceling
const computedEntries = calculateComputedValues(
serverObjectData.current,
model
)
const computedValuesObject = buildObjectFromEntries(computedEntries)
const resetFormData = merge(
{},
serverObjectData.current,
computedValuesObject
)
setIsEditing(false)
isEditingRef.current = false
form.setFieldsValue(resetFormData)
console.log('resetFormData', resetFormData)
setObjectData({ ...resetFormData, _isEditing: isEditingRef.current })
}
onStateChangeRef.current({ isEditing: isEditingRef.current })
unlockObject(id, type)
} }
const handleUpdate = async () => { const handleUpdate = async () => {
@ -603,7 +446,6 @@ const ObjectForm = forwardRef(
...currentFormData, ...currentFormData,
_isEditing: isEditingRef.current _isEditing: isEditingRef.current
}) })
setObjectActivity(id, type, 'viewing')
showSuccess('Information updated successfully') showSuccess('Information updated successfully')
} catch (err) { } catch (err) {
console.error(err) console.error(err)
@ -657,7 +499,7 @@ const ObjectForm = forwardRef(
fetchLoading, fetchLoading,
isEditing, isEditing,
objectData, objectData,
activities lock
})) }))
return ( return (
@ -745,7 +587,7 @@ const ObjectForm = forwardRef(
setIsEditing, setIsEditing,
setObjectData, setObjectData,
editLoading, editLoading,
activities, lock,
handleFetchObject, handleFetchObject,
handleDelete handleDelete
})} })}

View File

@ -125,8 +125,8 @@ const ObjectTable = forwardRef(
subscribeToObjectUpdates, subscribeToObjectUpdates,
subscribeToObjectTypeUpdates, subscribeToObjectTypeUpdates,
updateMultipleObjects, updateMultipleObjects,
setObjectActivity, lockObject,
clearObjectActivity unlockObject
} = useContext(ApiServerContext) } = useContext(ApiServerContext)
const isMobile = useMediaQuery({ maxWidth: 768 }) const isMobile = useMediaQuery({ maxWidth: 768 })
const navigate = useNavigate() const navigate = useNavigate()
@ -532,19 +532,19 @@ const ObjectTable = forwardRef(
setIsEditing(true) setIsEditing(true)
tableData.forEach((item) => { tableData.forEach((item) => {
if (!item.isSkeleton) { if (!item.isSkeleton) {
setObjectActivity(item._id, type, 'editing') lockObject(item._id, type)
} }
}) })
}, [tableData, setObjectActivity, type]) }, [tableData, lockObject, type])
const cancelEditing = useCallback(() => { const cancelEditing = useCallback(() => {
setIsEditing(false) setIsEditing(false)
tableData.forEach((item) => { tableData.forEach((item) => {
if (!item.isSkeleton) { if (!item.isSkeleton) {
clearObjectActivity(item._id, type) unlockObject(item._id, type)
} }
}) })
}, [tableData, clearObjectActivity, type]) }, [tableData, unlockObject, type])
const handleUpdate = useCallback(async () => { const handleUpdate = useCallback(async () => {
setEditLoading(true) setEditLoading(true)
@ -560,7 +560,7 @@ const ObjectTable = forwardRef(
reload() reload()
tableData.forEach((item) => { tableData.forEach((item) => {
if (!item.isSkeleton) { if (!item.isSkeleton) {
clearObjectActivity(item._id, type) unlockObject(item._id, type)
} }
}) })
} catch (err) { } catch (err) {
@ -568,7 +568,7 @@ const ObjectTable = forwardRef(
} finally { } finally {
setEditLoading(false) setEditLoading(false)
} }
}, [type, updateMultipleObjects, reload, tableData, clearObjectActivity]) }, [type, updateMultipleObjects, reload, tableData, unlockObject])
// Update event handler for real-time updates // Update event handler for real-time updates
const updateEventHandler = useCallback((id, updatedData) => { const updateEventHandler = useCallback((id, updatedData) => {

View File

@ -53,11 +53,7 @@ const PropertyChanges = ({ type, value }) => {
} }
return ( return (
<Descriptions.Item key={key} label={changeProperty.label}> <Descriptions.Item key={key} label={changeProperty.label}>
<Flex <Flex gap={'small'} style={{ minWidth: 0, width: '100%' }}>
gap={'small'}
style={{ minWidth: 0, width: '100%' }}
className='property-changes'
>
{value?.old ? ( {value?.old ? (
<ObjectProperty <ObjectProperty
{...changeProperty} {...changeProperty}

View File

@ -104,44 +104,45 @@ const ApiServerProvider = ({ children }) => {
const [userSettings, setUserSettings] = useState(createEmptyUserSettings) const [userSettings, setUserSettings] = useState(createEmptyUserSettings)
const [userSettingsLoaded, setUserSettingsLoaded] = useState(false) const [userSettingsLoaded, setUserSettingsLoaded] = useState(false)
const subscribedCallbacksRef = useRef(new Map()) const subscribedCallbacksRef = useRef(new Map())
const subscribedActivityCallbacksRef = useRef(new Map()) const subscribedLockCallbacksRef = useRef(new Map())
const notificationListenersRef = useRef(new Set()) const notificationListenersRef = useRef(new Set())
const completedLaunchSessionsRef = useRef(new Set()) const completedLaunchSessionsRef = useRef(new Set())
const handleActivityUpdate = useCallback(async (data) => { const handleLockUpdate = useCallback(
logger.debug('Notifying activity update:', data) async (lockData) => {
const objectId = data._id || data.id logger.debug('Notifying lock update:', lockData)
const objectType = data.objectType const objectId = lockData._id || lockData.id
const activity = data.activity
const activities = data.activities
const callbacksRefKey = `${objectType}:${objectId}`
if ( if (
objectId && objectId &&
objectType && subscribedLockCallbacksRef.current.has(objectId) &&
activity && lockData.user != userProfile?._id
subscribedActivityCallbacksRef.current.has(callbacksRefKey)
) { ) {
const callbacks = subscribedActivityCallbacksRef.current.get( const callbacks = subscribedLockCallbacksRef.current.get(objectId)
callbacksRefKey
)
logger.debug( logger.debug(
`Calling ${callbacks.length} activity callbacks for object:`, `Calling ${callbacks.length} lock callbacks for object:`,
objectId objectId
) )
callbacks.forEach((callback) => { callbacks.forEach((callback) => {
try { try {
callback(activity, activities) callback(lockData)
} catch (error) { } catch (error) {
logger.error('Error in activity update callback:', error) logger.error('Error in lock update callback:', error)
} }
}) })
} else {
logger.debug(
`No lock callbacks found for object: ${objectId}, subscribed lock callbacks:`,
Array.from(subscribedLockCallbacksRef.current.keys())
)
} }
}, []) },
[userProfile?._id]
)
const clearSubscriptions = useCallback(() => { const clearSubscriptions = useCallback(() => {
subscribedCallbacksRef.current.clear() subscribedCallbacksRef.current.clear()
subscribedActivityCallbacksRef.current.clear() subscribedLockCallbacksRef.current.clear()
notificationListenersRef.current.clear() notificationListenersRef.current.clear()
}, []) }, [])
@ -254,7 +255,7 @@ const ApiServerProvider = ({ children }) => {
newSocket.on('objectEvent', handleObjectEvent) newSocket.on('objectEvent', handleObjectEvent)
newSocket.on('objectNew', handleObjectNew) newSocket.on('objectNew', handleObjectNew)
newSocket.on('objectDelete', handleObjectDelete) newSocket.on('objectDelete', handleObjectDelete)
newSocket.on('activityUpdate', handleActivityUpdate) newSocket.on('lockUpdate', handleLockUpdate)
newSocket.on('modelStats', handleModelStats) newSocket.on('modelStats', handleModelStats)
newSocket.on('notification', (data) => { newSocket.on('notification', (data) => {
let notification let notification
@ -305,7 +306,7 @@ const ApiServerProvider = ({ children }) => {
token, token,
authenticated, authenticated,
messageApi, messageApi,
handleActivityUpdate, handleLockUpdate,
clearSubscriptions, clearSubscriptions,
getUserSettings getUserSettings
]) ])
@ -331,49 +332,44 @@ const ApiServerProvider = ({ children }) => {
} }
}, [token, authenticated, connectToServer]) }, [token, authenticated, connectToServer])
const setObjectActivity = (id, type, mode) => { const lockObject = (id, type) => {
logger.debug('Setting activity for', id, mode) logger.debug('Locking ' + id)
if (socketRef.current && socketRef.current.connected) { if (socketRef.current && socketRef.current.connected) {
return new Promise((resolve) => { socketRef.current.emit('lock', { _id: id, type: type })
socketRef.current.emit( logger.debug('Sent lock command for object:', id)
'setActivity',
{ _id: id, type, mode },
(result) => {
logger.debug('Received setActivity result for object:', id, result)
resolve(result || { success: true })
}
)
})
}
return Promise.resolve({ success: false, error: 'not_connected' })
}
const clearObjectActivity = (id, type) => {
logger.debug('Clearing activity for', id)
if (socketRef.current && socketRef.current.connected == true) {
socketRef.current.emit('clearActivity', { _id: id, type })
logger.debug('Sent clearActivity command for object:', id)
} }
} }
const fetchObjectActivities = async (id, type) => { const unlockObject = (id, type) => {
logger.debug('Unlocking ' + id)
if (socketRef.current && socketRef.current.connected == true) { if (socketRef.current && socketRef.current.connected == true) {
logger.debug('Fetching activities for ' + id) socketRef.current.emit('unlock', { _id: id, type: type })
logger.debug('Sent unlock command for object:', id)
}
}
const fetchObjectLock = async (id, type) => {
if (socketRef.current && socketRef.current.connected == true) {
logger.debug('Fetching lock status for ' + id)
return new Promise((resolve) => { return new Promise((resolve) => {
socketRef.current.emit( socketRef.current.emit(
'getActivities', 'getLock',
{ {
_id: id, _id: id,
type: type type: type
}, },
(result) => { (lockEvent) => {
logger.debug('Received activities for object:', id, result) logger.debug('Received lock status for object:', id, lockEvent)
resolve(result?.activities || []) if (lockEvent.user != userProfile?._id) {
resolve(lockEvent)
} else {
resolve(null)
}
} }
) )
logger.debug('Sent fetch lock command for object:', id)
}) })
} }
return []
} }
const handleObjectUpdate = async (data) => { const handleObjectUpdate = async (data) => {
@ -681,25 +677,21 @@ const ApiServerProvider = ({ children }) => {
[offObjectTypeUpdatesEvent] [offObjectTypeUpdatesEvent]
) )
const offActivityEvent = useCallback((id, objectType, callback) => { const offLockEvent = useCallback((id, callback) => {
if (socketRef.current && socketRef.current.connected == true) { if (socketRef.current && socketRef.current.connected == true) {
const callbacksRefKey = `${objectType}:${id}` // Remove callback from the subscribed lock callbacks map
if (subscribedActivityCallbacksRef.current.has(callbacksRefKey)) { if (subscribedLockCallbacksRef.current.has(id)) {
const callbacks = subscribedActivityCallbacksRef.current const callbacks = subscribedLockCallbacksRef.current
.get(callbacksRefKey) .get(id)
.filter((cb) => cb !== callback) .filter((cb) => cb !== callback)
if (callbacks.length === 0) { if (callbacks.length === 0) {
subscribedActivityCallbacksRef.current.delete(callbacksRefKey) subscribedLockCallbacksRef.current.delete(id)
socketRef.current.emit('unsubscribeObjectActivity', {
_id: id,
objectType
})
} else { } else {
subscribedActivityCallbacksRef.current.set(callbacksRefKey, callbacks) subscribedLockCallbacksRef.current.set(id, callbacks)
} }
} }
logger.debug('Removed activity event listener for object:', id) logger.debug('Removed lock event listener for object:', id)
} }
}, []) }, [])
@ -843,41 +835,27 @@ const ApiServerProvider = ({ children }) => {
[offModelStats] [offModelStats]
) )
const subscribeToObjectActivity = useCallback( const subscribeToObjectLock = useCallback(
(id, type, callback) => { (id, type, callback) => {
logger.debug('Subscribing to activity for object:', id, 'type:', type) logger.debug('Subscribing to lock for object:', id, 'type:', type)
if (socketRef.current && socketRef.current.connected == true) { if (socketRef.current && socketRef.current.connected == true) {
const callbacksRefKey = `${type}:${id}` // Add callback to the subscribed lock callbacks map immediately
if (!subscribedActivityCallbacksRef.current.has(callbacksRefKey)) { if (!subscribedLockCallbacksRef.current.has(id)) {
subscribedActivityCallbacksRef.current.set(callbacksRefKey, []) subscribedLockCallbacksRef.current.set(id, [])
}
const callbacksLength =
subscribedActivityCallbacksRef.current.get(callbacksRefKey).length
subscribedActivityCallbacksRef.current
.get(callbacksRefKey)
.push(callback)
if (callbacksLength <= 0) {
socketRef.current.emit(
'subscribeToObjectActivity',
{ _id: id, objectType: type },
(result) => {
if (result?.success && Array.isArray(result.activities)) {
result.activities.forEach((activity) => {
callback(activity)
})
}
} }
subscribedLockCallbacksRef.current.get(id).push(callback)
logger.debug(
`Added lock callback for object ${id}, total lock callbacks: ${subscribedLockCallbacksRef.current.get(id).length}`
) )
}
logger.debug('Registered activity event listener for object:', id) socketRef.current.emit('subscribe_lock', { _id: id, objectType: type })
logger.debug('Registered lock event listener for object:', id)
return () => offActivityEvent(id, type, callback) // Return cleanup function
return () => offLockEvent(id, callback)
} }
}, },
[offActivityEvent] [offLockEvent]
) )
const showError = useCallback( const showError = useCallback(
@ -1993,9 +1971,9 @@ const ApiServerProvider = ({ children }) => {
userSettingsLoaded, userSettingsLoaded,
getUserSettings, getUserSettings,
updateUserSettings, updateUserSettings,
setObjectActivity, lockObject,
clearObjectActivity, unlockObject,
fetchObjectActivities, fetchObjectLock,
updateObject, updateObject,
updateMultipleObjects, updateMultipleObjects,
createObject, createObject,
@ -2005,7 +1983,7 @@ const ApiServerProvider = ({ children }) => {
subscribeToObjectUpdates, subscribeToObjectUpdates,
subscribeToObjectEvent, subscribeToObjectEvent,
subscribeToObjectTypeUpdates, subscribeToObjectTypeUpdates,
subscribeToObjectActivity, subscribeToObjectLock,
subscribeToModelStats, subscribeToModelStats,
fetchObject, fetchObject,
fetchObjects, fetchObjects,