Compare commits
9 Commits
eba1a87664
...
8bbfe20ec4
| Author | SHA1 | Date | |
|---|---|---|---|
| 8bbfe20ec4 | |||
| d7ea87f957 | |||
| ced34b4a86 | |||
| 25743ddc2c | |||
| e688bd891d | |||
| aee3370b6d | |||
| 4d01a6a04f | |||
| 23b5300a2c | |||
| 5c69fa5fda |
25
package.json
25
package.json
@ -30,14 +30,14 @@
|
|||||||
"@tsparticles/react": "^3.0.0",
|
"@tsparticles/react": "^3.0.0",
|
||||||
"@tsparticles/slim": "^3.9.1",
|
"@tsparticles/slim": "^3.9.1",
|
||||||
"@uiw/react-codemirror": "^4.25.1",
|
"@uiw/react-codemirror": "^4.25.1",
|
||||||
"antd": "^5.27.0",
|
"antd": "^5.27.1",
|
||||||
"antd-style": "^3.7.1",
|
"antd-style": "^3.7.1",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"country-list": "^2.3.0",
|
"country-list": "^2.4.1",
|
||||||
"cross-env": "^10.0.0",
|
"cross-env": "^10.0.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.18",
|
||||||
"dotenv": "^17.2.1",
|
"dotenv": "^17.2.1",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.34.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
@ -50,13 +50,12 @@
|
|||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"prettier-eslint": "^16.4.2",
|
"prettier-eslint": "^16.4.2",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.2.0",
|
"react": "^19.1.1",
|
||||||
"react-country-flag": "^3.1.0",
|
"react-country-flag": "^3.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^19.1.1",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-responsive": "^10.0.1",
|
"react-responsive": "^10.0.1",
|
||||||
"react-router-dom": "^7.8.0",
|
"react-router-dom": "^7.8.2",
|
||||||
"react-stl-viewer": "^2.5.0",
|
|
||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
"socket.io-client": "*",
|
"socket.io-client": "*",
|
||||||
"standard": "^17.1.2",
|
"standard": "^17.1.2",
|
||||||
@ -96,12 +95,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
"@vitejs/plugin-react": "^5.0.1",
|
"@vitejs/plugin-react": "^5.0.2",
|
||||||
"concurrently": "^9.2.0",
|
"concurrently": "^9.2.1",
|
||||||
"electron": "^37.2.6",
|
"electron": "^37.4.0",
|
||||||
"electron-builder": "^26.0.12",
|
"electron-builder": "^26.0.12",
|
||||||
"electron-packager": "^17.1.2",
|
"electron-packager": "^17.1.2",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.34.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
@ -116,7 +115,7 @@
|
|||||||
"vite": "^7.1.3",
|
"vite": "^7.1.3",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-plugin-svgo": "^2.0.0",
|
"vite-plugin-svgo": "^2.0.0",
|
||||||
"vite-plugin-svgr": "^4.3.0"
|
"vite-plugin-svgr": "^4.5.0"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "com.tombutcher.farmcontrol",
|
"appId": "com.tombutcher.farmcontrol",
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
|
|||||||
|
|
||||||
const FilamentStockInfo = () => {
|
const FilamentStockInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const filamentStockId = new URLSearchParams(location.search).get(
|
const filamentStockId = new URLSearchParams(location.search).get(
|
||||||
'filamentStockId'
|
'filamentStockId'
|
||||||
@ -34,7 +34,7 @@ const FilamentStockInfo = () => {
|
|||||||
auditLogs: true
|
auditLogs: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -44,19 +44,19 @@ const FilamentStockInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.fetchObject?.()
|
objectFormRef?.current?.fetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,10 +74,10 @@ const FilamentStockInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='filamentStock'
|
type='filamentStock'
|
||||||
id={filamentStockId}
|
id={filamentStockId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Filament Stock Information' },
|
{ key: 'info', label: 'Filament Stock Information' },
|
||||||
{ key: 'events', label: 'Filament Stock Events' },
|
{ key: 'events', label: 'Filament Stock Events' },
|
||||||
@ -88,11 +88,11 @@ const FilamentStockInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -102,10 +102,10 @@ const FilamentStockInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -113,7 +113,7 @@ const FilamentStockInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -127,7 +127,7 @@ const FilamentStockInfo = () => {
|
|||||||
id={filamentStockId}
|
id={filamentStockId}
|
||||||
type='filamentStock'
|
type='filamentStock'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -150,7 +150,7 @@ const FilamentStockInfo = () => {
|
|||||||
onToggle={(expanded) => updateCollapseState('events', expanded)}
|
onToggle={(expanded) => updateCollapseState('events', expanded)}
|
||||||
collapseKey='events'
|
collapseKey='events'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
@ -180,7 +180,7 @@ const FilamentStockInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -25,7 +25,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const DocumentSizeInfo = () => {
|
const DocumentSizeInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const documentSizeId = new URLSearchParams(location.search).get(
|
const documentSizeId = new URLSearchParams(location.search).get(
|
||||||
'documentSizeId'
|
'documentSizeId'
|
||||||
@ -38,7 +38,7 @@ const DocumentSizeInfo = () => {
|
|||||||
auditLogs: true
|
auditLogs: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -48,19 +48,19 @@ const DocumentSizeInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.fetchObject?.()
|
objectFormRef?.current?.fetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,10 +78,10 @@ const DocumentSizeInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='documentSize'
|
type='documentSize'
|
||||||
id={documentSizeId}
|
id={documentSizeId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Document Size Information' },
|
{ key: 'info', label: 'Document Size Information' },
|
||||||
{ key: 'notes', label: 'Notes' },
|
{ key: 'notes', label: 'Notes' },
|
||||||
@ -91,11 +91,11 @@ const DocumentSizeInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -105,10 +105,10 @@ const DocumentSizeInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -116,7 +116,7 @@ const DocumentSizeInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -130,7 +130,7 @@ const DocumentSizeInfo = () => {
|
|||||||
id={documentSizeId}
|
id={documentSizeId}
|
||||||
type='documentSize'
|
type='documentSize'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -167,7 +167,7 @@ const DocumentSizeInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -21,7 +21,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const DocumentTemplateDesign = () => {
|
const DocumentTemplateDesign = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const documentTemplateId = new URLSearchParams(location.search).get(
|
const documentTemplateId = new URLSearchParams(location.search).get(
|
||||||
'documentTemplateId'
|
'documentTemplateId'
|
||||||
@ -36,7 +36,7 @@ const DocumentTemplateDesign = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -46,19 +46,19 @@ const DocumentTemplateDesign = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current.handleFetchObject()
|
objectFormRef?.current.handleFetchObject()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current.startEditing()
|
objectFormRef?.current.startEditing()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current.cancelEditing()
|
objectFormRef?.current.cancelEditing()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current.handleUpdate()
|
objectFormRef?.current.handleUpdate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,11 +78,11 @@ const DocumentTemplateDesign = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='documentTemplate'
|
type='documentTemplate'
|
||||||
id={documentTemplateId}
|
id={documentTemplateId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
visibleActions={{ edit: false }}
|
visibleActions={{ edit: false }}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
key: 'preview',
|
key: 'preview',
|
||||||
@ -99,11 +99,11 @@ const DocumentTemplateDesign = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -113,10 +113,10 @@ const DocumentTemplateDesign = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -125,14 +125,14 @@ const DocumentTemplateDesign = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<ObjectForm
|
<ObjectForm
|
||||||
id={documentTemplateId}
|
id={documentTemplateId}
|
||||||
type='documentTemplate'
|
type='documentTemplate'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
console.log('Got edit form state change', state)
|
console.log('Got edit form state change', state)
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
|
|||||||
@ -25,7 +25,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const DocumentTemplateInfo = () => {
|
const DocumentTemplateInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const documentTemplateId = new URLSearchParams(location.search).get(
|
const documentTemplateId = new URLSearchParams(location.search).get(
|
||||||
'documentTemplateId'
|
'documentTemplateId'
|
||||||
@ -40,7 +40,7 @@ const DocumentTemplateInfo = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -50,19 +50,19 @@ const DocumentTemplateInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current.handleFetchObject()
|
objectFormRef?.current.handleFetchObject()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current.startEditing()
|
objectFormRef?.current.startEditing()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current.cancelEditing()
|
objectFormRef?.current.cancelEditing()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current.handleUpdate()
|
objectFormRef?.current.handleUpdate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,10 +83,10 @@ const DocumentTemplateInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='documentTemplate'
|
type='documentTemplate'
|
||||||
id={documentTemplateId}
|
id={documentTemplateId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'DocumentTemplate Information' },
|
{ key: 'info', label: 'DocumentTemplate Information' },
|
||||||
{ key: 'notes', label: 'Notes' },
|
{ key: 'notes', label: 'Notes' },
|
||||||
@ -96,11 +96,11 @@ const DocumentTemplateInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -110,10 +110,10 @@ const DocumentTemplateInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -122,7 +122,7 @@ const DocumentTemplateInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -136,7 +136,7 @@ const DocumentTemplateInfo = () => {
|
|||||||
id={documentTemplateId}
|
id={documentTemplateId}
|
||||||
type='documentTemplate'
|
type='documentTemplate'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
console.log('Got edit form state change', state)
|
console.log('Got edit form state change', state)
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
@ -182,7 +182,7 @@ const DocumentTemplateInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -26,7 +26,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const FilamentInfo = () => {
|
const FilamentInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const filamentId = new URLSearchParams(location.search).get('filamentId')
|
const filamentId = new URLSearchParams(location.search).get('filamentId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
@ -39,7 +39,7 @@ const FilamentInfo = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -49,19 +49,19 @@ const FilamentInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.fetchObject?.()
|
objectFormRef?.current?.fetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,10 +82,10 @@ const FilamentInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='filament'
|
type='filament'
|
||||||
id={filamentId}
|
id={filamentId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Filament Information' },
|
{ key: 'info', label: 'Filament Information' },
|
||||||
{ key: 'stocks', label: 'Filament Stocks' },
|
{ key: 'stocks', label: 'Filament Stocks' },
|
||||||
@ -96,11 +96,11 @@ const FilamentInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -110,10 +110,10 @@ const FilamentInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -122,7 +122,7 @@ const FilamentInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -136,7 +136,7 @@ const FilamentInfo = () => {
|
|||||||
id={filamentId}
|
id={filamentId}
|
||||||
type='filament'
|
type='filament'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -163,7 +163,7 @@ const FilamentInfo = () => {
|
|||||||
onToggle={(expanded) => updateCollapseState('stocks', expanded)}
|
onToggle={(expanded) => updateCollapseState('stocks', expanded)}
|
||||||
collapseKey='stocks'
|
collapseKey='stocks'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
@ -199,7 +199,7 @@ const FilamentInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -1,19 +1,9 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useState } from 'react'
|
|
||||||
import { useMediaQuery } from 'react-responsive'
|
|
||||||
import { Typography, Flex, Steps, Divider } from 'antd'
|
|
||||||
|
|
||||||
import ObjectInfo from '../../common/ObjectInfo'
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
import NewObjectForm from '../../common/NewObjectForm'
|
import NewObjectForm from '../../common/NewObjectForm'
|
||||||
import NewObjectButtons from '../../common/NewObjectButtons'
|
import WizardView from '../../common/WizardView'
|
||||||
|
|
||||||
const { Title } = Typography
|
|
||||||
|
|
||||||
const NewFilament = ({ onOk }) => {
|
const NewFilament = ({ onOk }) => {
|
||||||
const [currentStep, setCurrentStep] = useState(0)
|
|
||||||
|
|
||||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NewObjectForm type={'filament'}>
|
<NewObjectForm type={'filament'}>
|
||||||
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
||||||
@ -66,43 +56,16 @@ const NewFilament = ({ onOk }) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
<Flex gap='middle'>
|
<WizardView
|
||||||
{!isMobile && (
|
steps={steps}
|
||||||
<div style={{ minWidth: '160px' }}>
|
loading={submitLoading}
|
||||||
<Steps
|
formValid={formValid}
|
||||||
current={currentStep}
|
title='New Filament'
|
||||||
items={steps}
|
|
||||||
direction='vertical'
|
|
||||||
style={{ width: 'fit-content' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isMobile && (
|
|
||||||
<Divider type='vertical' style={{ height: 'unset' }} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Flex vertical gap='middle' style={{ flexGrow: 1 }}>
|
|
||||||
<Title level={2} style={{ margin: 0 }}>
|
|
||||||
New Filament
|
|
||||||
</Title>
|
|
||||||
<div style={{ minHeight: '260px', marginBottom: 8 }}>
|
|
||||||
{steps[currentStep].content}
|
|
||||||
</div>
|
|
||||||
<NewObjectButtons
|
|
||||||
currentStep={currentStep}
|
|
||||||
totalSteps={steps.length}
|
|
||||||
onPrevious={() => setCurrentStep((prev) => prev - 1)}
|
|
||||||
onNext={() => setCurrentStep((prev) => prev + 1)}
|
|
||||||
onSubmit={() => {
|
onSubmit={() => {
|
||||||
handleSubmit()
|
handleSubmit()
|
||||||
onOk()
|
onOk()
|
||||||
}}
|
}}
|
||||||
formValid={formValid}
|
|
||||||
submitLoading={submitLoading}
|
|
||||||
/>
|
/>
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</NewObjectForm>
|
</NewObjectForm>
|
||||||
|
|||||||
@ -26,7 +26,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const HostInfo = () => {
|
const HostInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const hostId = new URLSearchParams(location.search).get('hostId')
|
const hostId = new URLSearchParams(location.search).get('hostId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('HostInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('HostInfo', {
|
||||||
@ -37,7 +37,7 @@ const HostInfo = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [hostOTPOpen, setHostOTPOpen] = useState(false)
|
const [hostOTPOpen, setHostOTPOpen] = useState(false)
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -47,7 +47,7 @@ const HostInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current.handleFetchObject()
|
objectFormRef?.current.handleFetchObject()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
hostOTP: () => {
|
hostOTP: () => {
|
||||||
@ -55,15 +55,15 @@ const HostInfo = () => {
|
|||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current.startEditing()
|
objectFormRef?.current.startEditing()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current.cancelEditing()
|
objectFormRef?.current.cancelEditing()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current.handleUpdate()
|
objectFormRef?.current.handleUpdate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,10 +84,10 @@ const HostInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='host'
|
type='host'
|
||||||
id={hostId}
|
id={hostId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Host Information' },
|
{ key: 'info', label: 'Host Information' },
|
||||||
{ key: 'notes', label: 'Notes' },
|
{ key: 'notes', label: 'Notes' },
|
||||||
@ -97,11 +97,11 @@ const HostInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -111,10 +111,10 @@ const HostInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -123,7 +123,7 @@ const HostInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -137,7 +137,7 @@ const HostInfo = () => {
|
|||||||
id={hostId}
|
id={hostId}
|
||||||
type='host'
|
type='host'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
console.log('Got edit form state change', state)
|
console.log('Got edit form state change', state)
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
@ -179,7 +179,7 @@ const HostInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -1,279 +1,80 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useState, useEffect } from 'react'
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
import axios from 'axios'
|
import NewObjectForm from '../../common/NewObjectForm'
|
||||||
import {
|
import WizardView from '../../common/WizardView'
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
Button,
|
|
||||||
message,
|
|
||||||
Select,
|
|
||||||
Flex,
|
|
||||||
Steps,
|
|
||||||
Divider,
|
|
||||||
Upload,
|
|
||||||
Descriptions
|
|
||||||
} from 'antd'
|
|
||||||
import { UploadOutlined } from '@ant-design/icons'
|
|
||||||
import VendorSelect from '../../common/VendorSelect'
|
|
||||||
|
|
||||||
import config from '../../../../config'
|
const NewMaterial = ({ onOk }) => {
|
||||||
|
return (
|
||||||
const initialNewMaterialForm = {
|
<NewObjectForm type={'material'}>
|
||||||
name: '',
|
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
||||||
vendor: { id: null, name: '' },
|
const steps = [
|
||||||
category: '',
|
|
||||||
image: null,
|
|
||||||
url: '',
|
|
||||||
barcode: ''
|
|
||||||
}
|
|
||||||
|
|
||||||
const NewMaterial = ({ onSuccess }) => {
|
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
|
||||||
|
|
||||||
const [newMaterialLoading, setNewMaterialLoading] = useState(false)
|
|
||||||
const [currentStep, setCurrentStep] = useState(0)
|
|
||||||
const [nextEnabled, setNextEnabled] = useState(false)
|
|
||||||
|
|
||||||
const [newMaterialForm] = Form.useForm()
|
|
||||||
const [newMaterialFormValues, setNewMaterialFormValues] = useState(
|
|
||||||
initialNewMaterialForm
|
|
||||||
)
|
|
||||||
|
|
||||||
const [imageList, setImageList] = useState([])
|
|
||||||
|
|
||||||
const newMaterialFormUpdateValues = Form.useWatch([], newMaterialForm)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
newMaterialForm
|
|
||||||
.validateFields({
|
|
||||||
validateOnly: true
|
|
||||||
})
|
|
||||||
.then(() => setNextEnabled(true))
|
|
||||||
.catch(() => setNextEnabled(false))
|
|
||||||
}, [newMaterialForm, newMaterialFormUpdateValues])
|
|
||||||
|
|
||||||
const summaryItems = [
|
|
||||||
{
|
{
|
||||||
key: 'name',
|
title: 'Required',
|
||||||
label: 'Name',
|
key: 'required',
|
||||||
children: newMaterialFormValues.name
|
content: (
|
||||||
},
|
<ObjectInfo
|
||||||
{
|
type='material'
|
||||||
key: 'vendor',
|
column={1}
|
||||||
label: 'Vendor',
|
bordered={false}
|
||||||
children: newMaterialFormValues.vendor.name
|
isEditing={true}
|
||||||
},
|
required={true}
|
||||||
{
|
objectData={objectData}
|
||||||
key: 'category',
|
|
||||||
label: 'Category',
|
|
||||||
children: newMaterialFormValues.category
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'image',
|
|
||||||
label: 'Image',
|
|
||||||
children: newMaterialFormValues.image && (
|
|
||||||
<img
|
|
||||||
src={newMaterialFormValues.image}
|
|
||||||
style={{ width: 128 }}
|
|
||||||
alt='Material'
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'url',
|
title: 'Optional',
|
||||||
label: 'URL',
|
key: 'optional',
|
||||||
children: newMaterialFormValues.url
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'barcode',
|
|
||||||
label: 'Barcode',
|
|
||||||
children: newMaterialFormValues.barcode
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const handleNewMaterial = async () => {
|
|
||||||
setNewMaterialLoading(true)
|
|
||||||
try {
|
|
||||||
await axios.post(
|
|
||||||
`${config.backendUrl}/materials`,
|
|
||||||
newMaterialFormValues,
|
|
||||||
{
|
|
||||||
withCredentials: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
messageApi.success('New material created successfully.')
|
|
||||||
onSuccess()
|
|
||||||
} catch (error) {
|
|
||||||
messageApi.error('Error creating new material: ' + error.message)
|
|
||||||
} finally {
|
|
||||||
setNewMaterialLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getBase64 = (file) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader()
|
|
||||||
reader.readAsDataURL(file)
|
|
||||||
reader.onload = () => resolve(reader.result)
|
|
||||||
reader.onerror = (error) => reject(error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleImageUpload = async ({ file, fileList }) => {
|
|
||||||
if (fileList.length === 0) {
|
|
||||||
setImageList(fileList)
|
|
||||||
newMaterialForm.setFieldsValue({ image: '' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const base64 = await getBase64(file)
|
|
||||||
setNewMaterialFormValues((prevValues) => ({
|
|
||||||
...prevValues,
|
|
||||||
image: base64
|
|
||||||
}))
|
|
||||||
fileList[0].name = 'Material Image'
|
|
||||||
setImageList(fileList)
|
|
||||||
newMaterialForm.setFieldsValue({ image: base64 })
|
|
||||||
}
|
|
||||||
|
|
||||||
const steps = [
|
|
||||||
{
|
|
||||||
title: 'Details',
|
|
||||||
key: 'details',
|
|
||||||
content: (
|
content: (
|
||||||
<>
|
<ObjectInfo
|
||||||
<Form.Item
|
type='material'
|
||||||
label='Name'
|
column={1}
|
||||||
name='name'
|
bordered={false}
|
||||||
rules={[
|
isEditing={true}
|
||||||
{
|
required={false}
|
||||||
required: true,
|
objectData={objectData}
|
||||||
message: 'Please enter a name.'
|
/>
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label='Vendor'
|
|
||||||
name='vendor'
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: 'Please select a vendor.'
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<VendorSelect />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label='Category'
|
|
||||||
name='category'
|
|
||||||
rules={[{ required: true, message: 'Please select a category' }]}
|
|
||||||
>
|
|
||||||
<Select>
|
|
||||||
<Select.Option value='Raw Material'>Raw Material</Select.Option>
|
|
||||||
<Select.Option value='Component'>Component</Select.Option>
|
|
||||||
<Select.Option value='Consumable'>Consumable</Select.Option>
|
|
||||||
<Select.Option value='Tool'>Tool</Select.Option>
|
|
||||||
<Select.Option value='Packaging'>Packaging</Select.Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Additional Info',
|
|
||||||
key: 'additional',
|
|
||||||
content: (
|
|
||||||
<>
|
|
||||||
<Form.Item label='Image' name='image'>
|
|
||||||
<Upload
|
|
||||||
listType='picture'
|
|
||||||
maxCount={1}
|
|
||||||
fileList={imageList}
|
|
||||||
onChange={handleImageUpload}
|
|
||||||
beforeUpload={() => false}
|
|
||||||
>
|
|
||||||
<Button icon={<UploadOutlined />}>Upload Image</Button>
|
|
||||||
</Upload>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label='URL' name='url'>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item label='Barcode' name='barcode'>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Summary',
|
title: 'Summary',
|
||||||
key: 'summary',
|
key: 'summary',
|
||||||
content: (
|
content: (
|
||||||
<>
|
<ObjectInfo
|
||||||
<Descriptions
|
type='material'
|
||||||
title='Material Details'
|
|
||||||
bordered
|
|
||||||
column={1}
|
column={1}
|
||||||
items={summaryItems}
|
bordered={false}
|
||||||
|
visibleProperties={{
|
||||||
|
_id: false,
|
||||||
|
createdAt: false,
|
||||||
|
updatedAt: false
|
||||||
|
}}
|
||||||
|
isEditing={false}
|
||||||
|
objectData={objectData}
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<WizardView
|
||||||
{contextHolder}
|
steps={steps}
|
||||||
<Form
|
loading={submitLoading}
|
||||||
form={newMaterialForm}
|
formValid={formValid}
|
||||||
layout='vertical'
|
title='New Material'
|
||||||
onValuesChange={(changedValues) => {
|
onSubmit={() => {
|
||||||
setNewMaterialFormValues((prevValues) => ({
|
handleSubmit()
|
||||||
...prevValues,
|
onOk()
|
||||||
...changedValues
|
|
||||||
}))
|
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<Steps
|
|
||||||
current={currentStep}
|
|
||||||
items={steps.map((item) => ({ title: item.title }))}
|
|
||||||
style={{ marginBottom: 24 }}
|
|
||||||
/>
|
/>
|
||||||
<div style={{ minHeight: 200 }}>{steps[currentStep].content}</div>
|
)
|
||||||
<Divider />
|
}}
|
||||||
<Flex justify='space-between'>
|
</NewObjectForm>
|
||||||
<Button
|
|
||||||
disabled={currentStep === 0}
|
|
||||||
onClick={() => setCurrentStep((prev) => prev - 1)}
|
|
||||||
>
|
|
||||||
Previous
|
|
||||||
</Button>
|
|
||||||
{currentStep < steps.length - 1 ? (
|
|
||||||
<Button
|
|
||||||
type='primary'
|
|
||||||
disabled={!nextEnabled}
|
|
||||||
onClick={() => setCurrentStep((prev) => prev + 1)}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
type='primary'
|
|
||||||
loading={newMaterialLoading}
|
|
||||||
onClick={handleNewMaterial}
|
|
||||||
>
|
|
||||||
Create Material
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
</Form>
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
NewMaterial.propTypes = {
|
NewMaterial.propTypes = {
|
||||||
onSuccess: PropTypes.func.isRequired
|
onOk: PropTypes.func.isRequired,
|
||||||
|
reset: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NewMaterial
|
export default NewMaterial
|
||||||
|
|||||||
@ -1,18 +1,9 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useState } from 'react'
|
|
||||||
import { useMediaQuery } from 'react-responsive'
|
|
||||||
import { Typography, Flex, Steps, Divider } from 'antd'
|
|
||||||
|
|
||||||
import ObjectInfo from '../../common/ObjectInfo'
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
import NewObjectForm from '../../common/NewObjectForm'
|
import NewObjectForm from '../../common/NewObjectForm'
|
||||||
import NewObjectButtons from '../../common/NewObjectButtons'
|
import WizardView from '../../common/WizardView'
|
||||||
|
|
||||||
const { Title } = Typography
|
|
||||||
|
|
||||||
const NewNoteType = ({ onOk }) => {
|
const NewNoteType = ({ onOk }) => {
|
||||||
const [currentStep, setCurrentStep] = useState(0)
|
|
||||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NewObjectForm
|
<NewObjectForm
|
||||||
type={'noteType'}
|
type={'noteType'}
|
||||||
@ -70,43 +61,16 @@ const NewNoteType = ({ onOk }) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
<Flex gap='middle'>
|
<WizardView
|
||||||
{!isMobile && (
|
steps={steps}
|
||||||
<div style={{ minWidth: '160px' }}>
|
loading={submitLoading}
|
||||||
<Steps
|
formValid={formValid}
|
||||||
current={currentStep}
|
title='New Note Type'
|
||||||
items={steps}
|
|
||||||
direction='vertical'
|
|
||||||
style={{ width: 'fit-content' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isMobile && (
|
|
||||||
<Divider type='vertical' style={{ height: 'unset' }} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Flex vertical gap='middle' style={{ flexGrow: 1 }}>
|
|
||||||
<Title level={2} style={{ margin: 0 }}>
|
|
||||||
New Note Type
|
|
||||||
</Title>
|
|
||||||
<div style={{ minHeight: '260px', marginBottom: 8 }}>
|
|
||||||
{steps[currentStep].content}
|
|
||||||
</div>
|
|
||||||
<NewObjectButtons
|
|
||||||
currentStep={currentStep}
|
|
||||||
totalSteps={steps.length}
|
|
||||||
onPrevious={() => setCurrentStep((prev) => prev - 1)}
|
|
||||||
onNext={() => setCurrentStep((prev) => prev + 1)}
|
|
||||||
onSubmit={() => {
|
onSubmit={() => {
|
||||||
handleSubmit()
|
handleSubmit()
|
||||||
onOk()
|
onOk()
|
||||||
}}
|
}}
|
||||||
formValid={formValid}
|
|
||||||
submitLoading={submitLoading}
|
|
||||||
/>
|
/>
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</NewObjectForm>
|
</NewObjectForm>
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
|||||||
|
|
||||||
const NoteTypeInfo = () => {
|
const NoteTypeInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const noteTypeId = new URLSearchParams(location.search).get('noteTypeId')
|
const noteTypeId = new URLSearchParams(location.search).get('noteTypeId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
@ -28,7 +28,7 @@ const NoteTypeInfo = () => {
|
|||||||
auditLogs: true
|
auditLogs: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -38,19 +38,19 @@ const NoteTypeInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.fetchObject?.()
|
objectFormRef?.current?.fetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,10 +68,10 @@ const NoteTypeInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='noteType'
|
type='noteType'
|
||||||
id={noteTypeId}
|
id={noteTypeId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Note Type Information' },
|
{ key: 'info', label: 'Note Type Information' },
|
||||||
{ key: 'auditLogs', label: 'Audit Logs' }
|
{ key: 'auditLogs', label: 'Audit Logs' }
|
||||||
@ -80,11 +80,11 @@ const NoteTypeInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -94,10 +94,10 @@ const NoteTypeInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -105,7 +105,7 @@ const NoteTypeInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -119,7 +119,7 @@ const NoteTypeInfo = () => {
|
|||||||
id={noteTypeId}
|
id={noteTypeId}
|
||||||
type='noteType'
|
type='noteType'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -145,7 +145,7 @@ const NoteTypeInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
51
src/components/Dashboard/Management/Notes/NewNote.jsx
Normal file
51
src/components/Dashboard/Management/Notes/NewNote.jsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
|
import NewObjectForm from '../../common/NewObjectForm'
|
||||||
|
import WizardView from '../../common/WizardView'
|
||||||
|
|
||||||
|
const NewNote = ({ onOk, defaultValues = {} }) => {
|
||||||
|
return (
|
||||||
|
<NewObjectForm type={'note'} defaultValues={defaultValues}>
|
||||||
|
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
title: 'Required',
|
||||||
|
key: 'required',
|
||||||
|
content: (
|
||||||
|
<ObjectInfo
|
||||||
|
type='note'
|
||||||
|
column={1}
|
||||||
|
visibleProperties={{ 'parent._id': false }}
|
||||||
|
bordered={false}
|
||||||
|
isEditing={true}
|
||||||
|
required={true}
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<WizardView
|
||||||
|
steps={steps}
|
||||||
|
showSteps={false}
|
||||||
|
loading={submitLoading}
|
||||||
|
formValid={formValid}
|
||||||
|
title='New Note'
|
||||||
|
onSubmit={() => {
|
||||||
|
handleSubmit()
|
||||||
|
onOk()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</NewObjectForm>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NewNote.propTypes = {
|
||||||
|
onOk: PropTypes.func.isRequired,
|
||||||
|
reset: PropTypes.bool,
|
||||||
|
defaultValues: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NewNote
|
||||||
184
src/components/Dashboard/Management/Notes/NoteInfo.jsx
Normal file
184
src/components/Dashboard/Management/Notes/NoteInfo.jsx
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import { useRef, useState } from 'react'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { Space, Flex, Card } from 'antd'
|
||||||
|
import loglevel from 'loglevel'
|
||||||
|
import config from '../../../../config'
|
||||||
|
import useCollapseState from '../../hooks/useCollapseState'
|
||||||
|
import NotesPanel from '../../common/NotesPanel'
|
||||||
|
import InfoCollapse from '../../common/InfoCollapse'
|
||||||
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
|
import ViewButton from '../../common/ViewButton'
|
||||||
|
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
|
||||||
|
import NoteIcon from '../../../Icons/NoteIcon.jsx'
|
||||||
|
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
|
||||||
|
import ObjectForm from '../../common/ObjectForm'
|
||||||
|
import EditButtons from '../../common/EditButtons'
|
||||||
|
import LockIndicator from '../../common/LockIndicator.jsx'
|
||||||
|
import ActionHandler from '../../common/ActionHandler.jsx'
|
||||||
|
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||||
|
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||||
|
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||||
|
|
||||||
|
const log = loglevel.getLogger('NoteInfo')
|
||||||
|
log.setLevel(config.logLevel)
|
||||||
|
|
||||||
|
const NoteInfo = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const objectFormRef = useRef(null)
|
||||||
|
const actionHandlerRef = useRef(null)
|
||||||
|
const noteId = new URLSearchParams(location.search).get('noteId')
|
||||||
|
const [collapseState, updateCollapseState] = useCollapseState('NoteInfo', {
|
||||||
|
info: true,
|
||||||
|
notes: true,
|
||||||
|
auditLogs: true
|
||||||
|
})
|
||||||
|
const [objectFormState, setEditFormState] = useState({
|
||||||
|
isEditing: false,
|
||||||
|
editLoading: false,
|
||||||
|
formValid: false,
|
||||||
|
lock: null,
|
||||||
|
loading: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
reload: () => {
|
||||||
|
objectFormRef?.current?.handleFetchObject?.()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
edit: () => {
|
||||||
|
objectFormRef?.current?.startEditing?.()
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
cancelEdit: () => {
|
||||||
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
finishEdit: () => {
|
||||||
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
delete: () => {
|
||||||
|
objectFormRef?.current?.handleDelete?.()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Flex
|
||||||
|
gap='large'
|
||||||
|
vertical='true'
|
||||||
|
style={{ maxHeight: '100%', minHeight: 0 }}
|
||||||
|
>
|
||||||
|
<Flex justify={'space-between'}>
|
||||||
|
<Space size='middle'>
|
||||||
|
<Space size='small'>
|
||||||
|
<ObjectActions
|
||||||
|
type='note'
|
||||||
|
id={noteId}
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
/>
|
||||||
|
<ViewButton
|
||||||
|
disabled={objectFormState.loading}
|
||||||
|
items={[
|
||||||
|
{ key: 'info', label: 'Note Information' },
|
||||||
|
{ key: 'notes', label: 'Notes' },
|
||||||
|
{ key: 'auditLogs', label: 'Audit Logs' }
|
||||||
|
]}
|
||||||
|
visibleState={collapseState}
|
||||||
|
updateVisibleState={updateCollapseState}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<EditButtons
|
||||||
|
isEditing={objectFormState.isEditing}
|
||||||
|
handleUpdate={() => {
|
||||||
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
|
}}
|
||||||
|
cancelEditing={() => {
|
||||||
|
actionHandlerRef.current.callAction('cancelEdit')
|
||||||
|
}}
|
||||||
|
startEditing={() => {
|
||||||
|
actionHandlerRef.current.callAction('edit')
|
||||||
|
}}
|
||||||
|
editLoading={objectFormState.editLoading}
|
||||||
|
formValid={objectFormState.formValid}
|
||||||
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
|
loading={objectFormState.editLoading}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||||
|
<Flex vertical gap={'large'}>
|
||||||
|
<ActionHandler
|
||||||
|
actions={actions}
|
||||||
|
loading={objectFormState.loading}
|
||||||
|
ref={actionHandlerRef}
|
||||||
|
>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Note Information'
|
||||||
|
icon={<InfoCircleIcon />}
|
||||||
|
active={collapseState.info}
|
||||||
|
onToggle={(expanded) => updateCollapseState('info', expanded)}
|
||||||
|
collapseKey='info'
|
||||||
|
>
|
||||||
|
<ObjectForm
|
||||||
|
id={noteId}
|
||||||
|
type='note'
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
ref={objectFormRef}
|
||||||
|
onStateChange={(state) => {
|
||||||
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ loading, isEditing, objectData }) => (
|
||||||
|
<ObjectInfo
|
||||||
|
loading={loading}
|
||||||
|
isEditing={isEditing}
|
||||||
|
type='note'
|
||||||
|
objectData={objectData}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ObjectForm>
|
||||||
|
</InfoCollapse>
|
||||||
|
</ActionHandler>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Notes'
|
||||||
|
icon={<NoteIcon />}
|
||||||
|
active={collapseState.notes}
|
||||||
|
onToggle={(expanded) => updateCollapseState('notes', expanded)}
|
||||||
|
collapseKey='notes'
|
||||||
|
>
|
||||||
|
<Card>
|
||||||
|
<NotesPanel _id={noteId} type='note' />
|
||||||
|
</Card>
|
||||||
|
</InfoCollapse>
|
||||||
|
<InfoCollapse
|
||||||
|
title='Audit Logs'
|
||||||
|
icon={<AuditLogIcon />}
|
||||||
|
active={collapseState.auditLogs}
|
||||||
|
onToggle={(expanded) =>
|
||||||
|
updateCollapseState('auditLogs', expanded)
|
||||||
|
}
|
||||||
|
collapseKey='auditLogs'
|
||||||
|
>
|
||||||
|
{objectFormState.loading ? (
|
||||||
|
<InfoCollapsePlaceholder />
|
||||||
|
) : (
|
||||||
|
<ObjectTable
|
||||||
|
type='auditLog'
|
||||||
|
masterFilter={{ 'parent._id': noteId }}
|
||||||
|
visibleColumns={{ _id: false, 'parent._id': false }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</InfoCollapse>
|
||||||
|
</Flex>
|
||||||
|
</div>
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoteInfo
|
||||||
@ -20,7 +20,7 @@ import { ApiServerContext } from '../../context/ApiServerContext'
|
|||||||
|
|
||||||
const PartInfo = () => {
|
const PartInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const partId = new URLSearchParams(location.search).get('partId')
|
const partId = new URLSearchParams(location.search).get('partId')
|
||||||
const { fetchObjectContent } = useContext(ApiServerContext)
|
const { fetchObjectContent } = useContext(ApiServerContext)
|
||||||
@ -30,7 +30,7 @@ const PartInfo = () => {
|
|||||||
notes: true,
|
notes: true,
|
||||||
auditLogs: true
|
auditLogs: true
|
||||||
})
|
})
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -40,24 +40,24 @@ const PartInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.fetchObject?.()
|
objectFormRef?.current?.fetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
download: () => {
|
download: () => {
|
||||||
if (partId && editFormRef?.current?.getObjectData) {
|
if (partId && objectFormRef?.current?.getObjectData) {
|
||||||
const objectData = editFormRef.current.getObjectData()
|
const objectData = objectFormRef.current.getObjectData()
|
||||||
fetchObjectContent(partId, 'part', `${objectData?.name || 'part'}.stl`)
|
fetchObjectContent(partId, 'part', `${objectData?.name || 'part'}.stl`)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -77,10 +77,10 @@ const PartInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='part'
|
type='part'
|
||||||
id={partId}
|
id={partId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Part Information' },
|
{ key: 'info', label: 'Part Information' },
|
||||||
{ key: 'notes', label: 'Notes' },
|
{ key: 'notes', label: 'Notes' },
|
||||||
@ -90,11 +90,11 @@ const PartInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -104,10 +104,10 @@ const PartInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -115,7 +115,7 @@ const PartInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -129,7 +129,7 @@ const PartInfo = () => {
|
|||||||
id={partId}
|
id={partId}
|
||||||
type='part'
|
type='part'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -165,7 +165,7 @@ const PartInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import {
|
|||||||
import { DeleteOutlined, EyeOutlined } from '@ant-design/icons'
|
import { DeleteOutlined, EyeOutlined } from '@ant-design/icons'
|
||||||
import { AuthContext } from '../../context/AuthContext'
|
import { AuthContext } from '../../context/AuthContext'
|
||||||
import PartIcon from '../../../Icons/PartIcon'
|
import PartIcon from '../../../Icons/PartIcon'
|
||||||
import { StlViewer } from 'react-stl-viewer'
|
|
||||||
import VendorSelect from '../../common/VendorSelect'
|
import VendorSelect from '../../common/VendorSelect'
|
||||||
|
|
||||||
import config from '../../../../config'
|
import config from '../../../../config'
|
||||||
@ -482,15 +481,7 @@ const NewProduct = ({ onOk, reset }) => {
|
|||||||
>
|
>
|
||||||
<Flex style={{ minWidth: '100%', minHeight: '80vh' }}>
|
<Flex style={{ minWidth: '100%', minHeight: '80vh' }}>
|
||||||
{previewFile && !isPreviewLoading ? (
|
{previewFile && !isPreviewLoading ? (
|
||||||
<div style={{ flexGrow: 1 }}>
|
<div style={{ flexGrow: 1 }}></div>
|
||||||
<StlViewer
|
|
||||||
url={fileUrls[previewFile.uid]}
|
|
||||||
orbitControls
|
|
||||||
shadows
|
|
||||||
style={{ height: '80vh', width: '100%' }}
|
|
||||||
modelProps={{ color: '#008675' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
|||||||
|
|
||||||
const ProductInfo = () => {
|
const ProductInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const productId = new URLSearchParams(location.search).get('productId')
|
const productId = new URLSearchParams(location.search).get('productId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('ProductInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('ProductInfo', {
|
||||||
@ -29,7 +29,7 @@ const ProductInfo = () => {
|
|||||||
notes: true,
|
notes: true,
|
||||||
auditLogs: true
|
auditLogs: true
|
||||||
})
|
})
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -39,19 +39,19 @@ const ProductInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.fetchObject?.()
|
objectFormRef?.current?.fetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,10 +69,10 @@ const ProductInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='product'
|
type='product'
|
||||||
id={productId}
|
id={productId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Product Information' },
|
{ key: 'info', label: 'Product Information' },
|
||||||
{ key: 'parts', label: 'Product Parts' },
|
{ key: 'parts', label: 'Product Parts' },
|
||||||
@ -83,11 +83,11 @@ const ProductInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -97,10 +97,10 @@ const ProductInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -108,7 +108,7 @@ const ProductInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -122,7 +122,7 @@ const ProductInfo = () => {
|
|||||||
id={productId}
|
id={productId}
|
||||||
type='product'
|
type='product'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -174,7 +174,7 @@ const ProductInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
|||||||
|
|
||||||
const UserInfo = () => {
|
const UserInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const userId = new URLSearchParams(location.search).get('userId')
|
const userId = new URLSearchParams(location.search).get('userId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('UserInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('UserInfo', {
|
||||||
@ -28,7 +28,7 @@ const UserInfo = () => {
|
|||||||
notes: true,
|
notes: true,
|
||||||
auditLogs: true
|
auditLogs: true
|
||||||
})
|
})
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -38,19 +38,19 @@ const UserInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.fetchObject?.()
|
objectFormRef?.current?.fetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,10 +68,10 @@ const UserInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='user'
|
type='user'
|
||||||
id={userId}
|
id={userId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'User Information' },
|
{ key: 'info', label: 'User Information' },
|
||||||
{ key: 'notes', label: 'Notes' },
|
{ key: 'notes', label: 'Notes' },
|
||||||
@ -81,11 +81,11 @@ const UserInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -95,10 +95,10 @@ const UserInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -106,7 +106,7 @@ const UserInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -120,7 +120,7 @@ const UserInfo = () => {
|
|||||||
id={userId}
|
id={userId}
|
||||||
type='user'
|
type='user'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -157,7 +157,7 @@ const UserInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -1,18 +1,9 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useState } from 'react'
|
|
||||||
import { useMediaQuery } from 'react-responsive'
|
|
||||||
import { Typography, Flex, Steps, Divider } from 'antd'
|
|
||||||
|
|
||||||
import ObjectInfo from '../../common/ObjectInfo'
|
import ObjectInfo from '../../common/ObjectInfo'
|
||||||
import NewObjectForm from '../../common/NewObjectForm'
|
import NewObjectForm from '../../common/NewObjectForm'
|
||||||
import NewObjectButtons from '../../common/NewObjectButtons'
|
import WizardView from '../../common/WizardView'
|
||||||
|
|
||||||
const { Title } = Typography
|
|
||||||
|
|
||||||
const NewVendor = ({ onOk }) => {
|
const NewVendor = ({ onOk }) => {
|
||||||
const [currentStep, setCurrentStep] = useState(0)
|
|
||||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NewObjectForm type={'vendor'}>
|
<NewObjectForm type={'vendor'}>
|
||||||
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
||||||
@ -65,43 +56,16 @@ const NewVendor = ({ onOk }) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
<Flex gap='middle'>
|
<WizardView
|
||||||
{!isMobile && (
|
steps={steps}
|
||||||
<div style={{ minWidth: '160px' }}>
|
loading={submitLoading}
|
||||||
<Steps
|
formValid={formValid}
|
||||||
current={currentStep}
|
title='New Vendor'
|
||||||
items={steps}
|
|
||||||
direction='vertical'
|
|
||||||
style={{ width: 'fit-content' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isMobile && (
|
|
||||||
<Divider type='vertical' style={{ height: 'unset' }} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Flex vertical gap='middle' style={{ flexGrow: 1 }}>
|
|
||||||
<Title level={2} style={{ margin: 0 }}>
|
|
||||||
New Vendor
|
|
||||||
</Title>
|
|
||||||
<div style={{ minHeight: '260px', marginBottom: 8 }}>
|
|
||||||
{steps[currentStep].content}
|
|
||||||
</div>
|
|
||||||
<NewObjectButtons
|
|
||||||
currentStep={currentStep}
|
|
||||||
totalSteps={steps.length}
|
|
||||||
onPrevious={() => setCurrentStep((prev) => prev - 1)}
|
|
||||||
onNext={() => setCurrentStep((prev) => prev + 1)}
|
|
||||||
onSubmit={() => {
|
onSubmit={() => {
|
||||||
handleSubmit()
|
handleSubmit()
|
||||||
onOk()
|
onOk()
|
||||||
}}
|
}}
|
||||||
formValid={formValid}
|
|
||||||
submitLoading={submitLoading}
|
|
||||||
/>
|
/>
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</NewObjectForm>
|
</NewObjectForm>
|
||||||
|
|||||||
@ -24,7 +24,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const VendorInfo = () => {
|
const VendorInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const vendorId = new URLSearchParams(location.search).get('vendorId')
|
const vendorId = new URLSearchParams(location.search).get('vendorId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('VendorInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('VendorInfo', {
|
||||||
@ -32,7 +32,7 @@ const VendorInfo = () => {
|
|||||||
notes: true,
|
notes: true,
|
||||||
auditLogs: true
|
auditLogs: true
|
||||||
})
|
})
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -42,23 +42,23 @@ const VendorInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current?.handleFetchObject?.()
|
objectFormRef?.current?.handleFetchObject?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current?.startEditing?.()
|
objectFormRef?.current?.startEditing?.()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current?.cancelEditing?.()
|
objectFormRef?.current?.cancelEditing?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current?.handleUpdate?.()
|
objectFormRef?.current?.handleUpdate?.()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
delete: () => {
|
delete: () => {
|
||||||
editFormRef?.current?.handleDelete?.()
|
objectFormRef?.current?.handleDelete?.()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,10 +76,10 @@ const VendorInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='vendor'
|
type='vendor'
|
||||||
id={vendorId}
|
id={vendorId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Vendor Information' },
|
{ key: 'info', label: 'Vendor Information' },
|
||||||
{ key: 'notes', label: 'Notes' },
|
{ key: 'notes', label: 'Notes' },
|
||||||
@ -89,11 +89,11 @@ const VendorInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -103,10 +103,10 @@ const VendorInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -114,7 +114,7 @@ const VendorInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -128,7 +128,7 @@ const VendorInfo = () => {
|
|||||||
id={vendorId}
|
id={vendorId}
|
||||||
type='vendor'
|
type='vendor'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -164,7 +164,7 @@ const VendorInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -28,7 +28,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const GCodeFileInfo = () => {
|
const GCodeFileInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const gcodeFileId = new URLSearchParams(location.search).get('gcodeFileId')
|
const gcodeFileId = new URLSearchParams(location.search).get('gcodeFileId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState(
|
const [collapseState, updateCollapseState] = useCollapseState(
|
||||||
@ -41,7 +41,7 @@ const GCodeFileInfo = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -51,19 +51,19 @@ const GCodeFileInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current.handleFetchObject()
|
objectFormRef?.current.handleFetchObject()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current.startEditing()
|
objectFormRef?.current.startEditing()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current.cancelEditing()
|
objectFormRef?.current.cancelEditing()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current.handleUpdate()
|
objectFormRef?.current.handleUpdate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,10 +84,10 @@ const GCodeFileInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='gcodeFile'
|
type='gcodeFile'
|
||||||
id={gcodeFileId}
|
id={gcodeFileId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'GCode File Information' },
|
{ key: 'info', label: 'GCode File Information' },
|
||||||
{ key: 'preview', label: 'GCode File Preview' },
|
{ key: 'preview', label: 'GCode File Preview' },
|
||||||
@ -98,11 +98,11 @@ const GCodeFileInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -112,10 +112,10 @@ const GCodeFileInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -124,14 +124,14 @@ const GCodeFileInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<ObjectForm
|
<ObjectForm
|
||||||
id={gcodeFileId}
|
id={gcodeFileId}
|
||||||
type='gcodeFile'
|
type='gcodeFile'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
console.log('Got edit form state change', state)
|
console.log('Got edit form state change', state)
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
@ -206,7 +206,7 @@ const GCodeFileInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -26,7 +26,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const JobInfo = () => {
|
const JobInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const jobId = new URLSearchParams(location.search).get('jobId')
|
const jobId = new URLSearchParams(location.search).get('jobId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('JobInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('JobInfo', {
|
||||||
@ -36,7 +36,7 @@ const JobInfo = () => {
|
|||||||
auditLogs: true
|
auditLogs: true
|
||||||
})
|
})
|
||||||
|
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -46,19 +46,19 @@ const JobInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current.handleFetchObject()
|
objectFormRef?.current.handleFetchObject()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current.startEditing()
|
objectFormRef?.current.startEditing()
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current.cancelEditing()
|
objectFormRef?.current.cancelEditing()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current.handleUpdate()
|
objectFormRef?.current.handleUpdate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,10 +79,10 @@ const JobInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='job'
|
type='job'
|
||||||
id={jobId}
|
id={jobId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Job Information' },
|
{ key: 'info', label: 'Job Information' },
|
||||||
{ key: 'subJobs', label: 'Sub Jobs' },
|
{ key: 'subJobs', label: 'Sub Jobs' },
|
||||||
@ -93,11 +93,11 @@ const JobInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -107,10 +107,10 @@ const JobInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -119,7 +119,7 @@ const JobInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -133,7 +133,7 @@ const JobInfo = () => {
|
|||||||
id={jobId}
|
id={jobId}
|
||||||
type='job'
|
type='job'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
}}
|
}}
|
||||||
@ -186,7 +186,7 @@ const JobInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@ log.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const PrinterInfo = () => {
|
const PrinterInfo = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const editFormRef = useRef(null)
|
const objectFormRef = useRef(null)
|
||||||
const actionHandlerRef = useRef(null)
|
const actionHandlerRef = useRef(null)
|
||||||
const printerId = new URLSearchParams(location.search).get('printerId')
|
const printerId = new URLSearchParams(location.search).get('printerId')
|
||||||
const [collapseState, updateCollapseState] = useCollapseState('PrinterInfo', {
|
const [collapseState, updateCollapseState] = useCollapseState('PrinterInfo', {
|
||||||
@ -35,7 +35,7 @@ const PrinterInfo = () => {
|
|||||||
auditLogs: true
|
auditLogs: true
|
||||||
})
|
})
|
||||||
|
|
||||||
const [editFormState, setEditFormState] = useState({
|
const [objectFormState, setEditFormState] = useState({
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
editLoading: false,
|
editLoading: false,
|
||||||
formValid: false,
|
formValid: false,
|
||||||
@ -45,20 +45,20 @@ const PrinterInfo = () => {
|
|||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
reload: () => {
|
reload: () => {
|
||||||
editFormRef?.current.handleFetchObject()
|
objectFormRef?.current.handleFetchObject()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
edit: () => {
|
edit: () => {
|
||||||
editFormRef?.current.startEditing()
|
objectFormRef?.current.startEditing()
|
||||||
console.log('CALLING START EDITING')
|
console.log('CALLING START EDITING')
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
cancelEdit: () => {
|
cancelEdit: () => {
|
||||||
editFormRef?.current.cancelEditing()
|
objectFormRef?.current.cancelEditing()
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
finishEdit: () => {
|
finishEdit: () => {
|
||||||
editFormRef?.current.handleUpdate()
|
objectFormRef?.current.handleUpdate()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,10 +79,10 @@ const PrinterInfo = () => {
|
|||||||
<ObjectActions
|
<ObjectActions
|
||||||
type='printer'
|
type='printer'
|
||||||
id={printerId}
|
id={printerId}
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
/>
|
/>
|
||||||
<ViewButton
|
<ViewButton
|
||||||
disabled={editFormState.loading}
|
disabled={objectFormState.loading}
|
||||||
items={[
|
items={[
|
||||||
{ key: 'info', label: 'Printer Information' },
|
{ key: 'info', label: 'Printer Information' },
|
||||||
{ key: 'notes', label: 'Notes' },
|
{ key: 'notes', label: 'Notes' },
|
||||||
@ -92,11 +92,11 @@ const PrinterInfo = () => {
|
|||||||
updateVisibleState={updateCollapseState}
|
updateVisibleState={updateCollapseState}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
<LockIndicator lock={editFormState.lock} />
|
<LockIndicator lock={objectFormState.lock} />
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<EditButtons
|
<EditButtons
|
||||||
isEditing={editFormState.isEditing}
|
isEditing={objectFormState.isEditing}
|
||||||
handleUpdate={() => {
|
handleUpdate={() => {
|
||||||
actionHandlerRef.current.callAction('finishEdit')
|
actionHandlerRef.current.callAction('finishEdit')
|
||||||
}}
|
}}
|
||||||
@ -106,10 +106,10 @@ const PrinterInfo = () => {
|
|||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
actionHandlerRef.current.callAction('edit')
|
actionHandlerRef.current.callAction('edit')
|
||||||
}}
|
}}
|
||||||
editLoading={editFormState.editLoading}
|
editLoading={objectFormState.editLoading}
|
||||||
formValid={editFormState.formValid}
|
formValid={objectFormState.formValid}
|
||||||
disabled={editFormState.lock?.locked || editFormState.loading}
|
disabled={objectFormState.lock?.locked || objectFormState.loading}
|
||||||
loading={editFormState.editLoading}
|
loading={objectFormState.editLoading}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -118,7 +118,7 @@ const PrinterInfo = () => {
|
|||||||
<Flex vertical gap={'large'}>
|
<Flex vertical gap={'large'}>
|
||||||
<ActionHandler
|
<ActionHandler
|
||||||
actions={actions}
|
actions={actions}
|
||||||
loading={editFormState.loading}
|
loading={objectFormState.loading}
|
||||||
ref={actionHandlerRef}
|
ref={actionHandlerRef}
|
||||||
>
|
>
|
||||||
<InfoCollapse
|
<InfoCollapse
|
||||||
@ -132,7 +132,7 @@ const PrinterInfo = () => {
|
|||||||
id={printerId}
|
id={printerId}
|
||||||
type='printer'
|
type='printer'
|
||||||
style={{ height: '100%' }}
|
style={{ height: '100%' }}
|
||||||
ref={editFormRef}
|
ref={objectFormRef}
|
||||||
onStateChange={(state) => {
|
onStateChange={(state) => {
|
||||||
console.log('Got edit form state change', state)
|
console.log('Got edit form state change', state)
|
||||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||||
@ -174,7 +174,7 @@ const PrinterInfo = () => {
|
|||||||
}
|
}
|
||||||
collapseKey='auditLogs'
|
collapseKey='auditLogs'
|
||||||
>
|
>
|
||||||
{editFormState.loading ? (
|
{objectFormState.loading ? (
|
||||||
<InfoCollapsePlaceholder />
|
<InfoCollapsePlaceholder />
|
||||||
) : (
|
) : (
|
||||||
<ObjectTable
|
<ObjectTable
|
||||||
|
|||||||
@ -12,7 +12,8 @@ const breadcrumbNameMap = {
|
|||||||
developer: 'Developer',
|
developer: 'Developer',
|
||||||
overview: 'Overview',
|
overview: 'Overview',
|
||||||
info: 'Info',
|
info: 'Info',
|
||||||
design: 'Design'
|
design: 'Design',
|
||||||
|
control: 'Control'
|
||||||
}
|
}
|
||||||
|
|
||||||
const mainSections = ['production', 'inventory', 'management', 'developer']
|
const mainSections = ['production', 'inventory', 'management', 'developer']
|
||||||
|
|||||||
32
src/components/Dashboard/common/MarkdownInput.jsx
Normal file
32
src/components/Dashboard/common/MarkdownInput.jsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Card, Splitter } from 'antd'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import CodeBlockEditor from './CodeBlockEditor'
|
||||||
|
import MarkdownDisplay from './MarkdownDisplay'
|
||||||
|
|
||||||
|
const MarkdownInput = ({ value, onChange }) => {
|
||||||
|
return (
|
||||||
|
<Splitter className={'farmcontrol-splitter'} style={{ height: '100%' }}>
|
||||||
|
<Splitter.Panel>
|
||||||
|
<Card>
|
||||||
|
<CodeBlockEditor
|
||||||
|
code={value}
|
||||||
|
onChange={onChange}
|
||||||
|
language='markdown'
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Splitter.Panel>
|
||||||
|
<Splitter.Panel>
|
||||||
|
<Card style={{ height: '100%' }}>
|
||||||
|
<MarkdownDisplay content={value} />
|
||||||
|
</Card>
|
||||||
|
</Splitter.Panel>
|
||||||
|
</Splitter>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownInput.propTypes = {
|
||||||
|
value: PropTypes.string.isRequired,
|
||||||
|
onChange: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MarkdownInput
|
||||||
29
src/components/Dashboard/common/MissingPlaceholder.jsx
Normal file
29
src/components/Dashboard/common/MissingPlaceholder.jsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Card, Flex, Typography } from 'antd'
|
||||||
|
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
const { Text } = Typography
|
||||||
|
|
||||||
|
const MissingPlaceholder = ({ message }) => {
|
||||||
|
return (
|
||||||
|
<Card size='small'>
|
||||||
|
<Flex
|
||||||
|
justify='center'
|
||||||
|
gap={'small'}
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
align='center'
|
||||||
|
>
|
||||||
|
<Text type='secondary'>
|
||||||
|
<InfoCircleIcon />
|
||||||
|
</Text>
|
||||||
|
<Text type='secondary'>{message}</Text>
|
||||||
|
</Flex>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
MissingPlaceholder.propTypes = {
|
||||||
|
message: PropTypes.string.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MissingPlaceholder
|
||||||
@ -13,6 +13,7 @@ const NewObjectButtons = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Flex justify='end'>
|
<Flex justify='end'>
|
||||||
|
{totalSteps > 1 ? (
|
||||||
<Button
|
<Button
|
||||||
style={{ margin: '0 8px' }}
|
style={{ margin: '0 8px' }}
|
||||||
onClick={onPrevious}
|
onClick={onPrevious}
|
||||||
@ -20,6 +21,7 @@ const NewObjectButtons = ({
|
|||||||
>
|
>
|
||||||
Previous
|
Previous
|
||||||
</Button>
|
</Button>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{currentStep < totalSteps - 1 ? (
|
{currentStep < totalSteps - 1 ? (
|
||||||
<Button type='primary' disabled={!formValid} onClick={onNext}>
|
<Button type='primary' disabled={!formValid} onClick={onNext}>
|
||||||
|
|||||||
313
src/components/Dashboard/common/NoteItem.jsx
Normal file
313
src/components/Dashboard/common/NoteItem.jsx
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
import { useState, useContext, useCallback, useEffect, useRef } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
Button,
|
||||||
|
Space,
|
||||||
|
Typography,
|
||||||
|
Flex,
|
||||||
|
Tag,
|
||||||
|
Dropdown,
|
||||||
|
Divider,
|
||||||
|
Modal
|
||||||
|
} from 'antd'
|
||||||
|
import { CaretLeftFilled, LoadingOutlined } from '@ant-design/icons'
|
||||||
|
import PlusIcon from '../../Icons/PlusIcon'
|
||||||
|
import BinIcon from '../../Icons/BinIcon'
|
||||||
|
import PersonIcon from '../../Icons/PersonIcon'
|
||||||
|
import TimeDisplay from './TimeDisplay'
|
||||||
|
import MarkdownDisplay from './MarkdownDisplay'
|
||||||
|
import IdDisplay from './IdDisplay'
|
||||||
|
import MissingPlaceholder from './MissingPlaceholder'
|
||||||
|
import NewNote from '../Management/Notes/NewNote'
|
||||||
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
|
import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon'
|
||||||
|
import { AuthContext } from '../context/AuthContext'
|
||||||
|
import { getModelByName } from '../../../database/ObjectModels'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
|
const { Text } = Typography
|
||||||
|
|
||||||
|
const NoteItem = ({ note }) => {
|
||||||
|
const [childNotes, setChildNotes] = useState([])
|
||||||
|
const noteModel = getModelByName('note')
|
||||||
|
const infoAction = noteModel.actions.filter(
|
||||||
|
(action) => action.name == 'info'
|
||||||
|
)[0]
|
||||||
|
const InfoIcon = infoAction.icon
|
||||||
|
const [newNoteOpen, setNewNoteOpen] = useState(false)
|
||||||
|
const [deleteNoteOpen, setDeleteNoteOpen] = useState(false)
|
||||||
|
const [deleteNoteLoading, setDeleteNoteLoading] = useState(false)
|
||||||
|
const [childNotesLoading, setChildNotesLoading] = useState(false)
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false)
|
||||||
|
const subscribeToObjectTypeUpdatesRef = useRef(null)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const {
|
||||||
|
deleteObject,
|
||||||
|
fetchObjects,
|
||||||
|
subscribeToObjectTypeUpdates,
|
||||||
|
connected
|
||||||
|
} = useContext(ApiServerContext)
|
||||||
|
const { userProfile, token } = useContext(AuthContext)
|
||||||
|
|
||||||
|
let transformValue = 'rotate(0deg)'
|
||||||
|
if (isExpanded) {
|
||||||
|
transformValue = 'rotate(-90deg)'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleNoteExpand = useCallback(async () => {
|
||||||
|
setChildNotesLoading(true)
|
||||||
|
try {
|
||||||
|
const childNotesData = await fetchObjects('note', {
|
||||||
|
filter: { 'parent._id': note._id }
|
||||||
|
})
|
||||||
|
setChildNotes(childNotesData.data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching child notes:', error)
|
||||||
|
} finally {
|
||||||
|
setChildNotesLoading(false)
|
||||||
|
}
|
||||||
|
}, [note._id, fetchObjects])
|
||||||
|
|
||||||
|
const toggleExpand = async () => {
|
||||||
|
if (isExpanded == false) {
|
||||||
|
await handleNoteExpand()
|
||||||
|
setIsExpanded(true)
|
||||||
|
} else {
|
||||||
|
setChildNotes([])
|
||||||
|
setIsExpanded(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteNote = async () => {
|
||||||
|
if (token != null) {
|
||||||
|
setDeleteNoteLoading(true)
|
||||||
|
await deleteObject(note._id, 'note')
|
||||||
|
setDeleteNoteOpen(false)
|
||||||
|
setDeleteNoteLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (connected == true && subscribeToObjectTypeUpdatesRef.current == null) {
|
||||||
|
if (isExpanded == true) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = subscribeToObjectTypeUpdates(
|
||||||
|
'note',
|
||||||
|
(noteData) => {
|
||||||
|
if (noteData.parent._id == note._id) {
|
||||||
|
console.log(
|
||||||
|
'Note note added to parent:',
|
||||||
|
note._id,
|
||||||
|
'isExpanded:',
|
||||||
|
isExpanded
|
||||||
|
)
|
||||||
|
if (isExpanded == true) {
|
||||||
|
handleNoteExpand()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if (subscribeToObjectTypeUpdatesRef.current) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current()
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (connected == true && subscribeToObjectTypeUpdatesRef.current) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current()
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
subscribeToObjectTypeUpdates,
|
||||||
|
connected,
|
||||||
|
handleNoteExpand,
|
||||||
|
isExpanded,
|
||||||
|
note._id
|
||||||
|
])
|
||||||
|
|
||||||
|
// Check if the current user can delete this note
|
||||||
|
const canDeleteNote = userProfile && userProfile._id === note.user._id
|
||||||
|
|
||||||
|
const dropdownItems = [
|
||||||
|
{
|
||||||
|
key: 'new',
|
||||||
|
icon: <PlusIcon />,
|
||||||
|
label: 'New Note',
|
||||||
|
onClick: () => {
|
||||||
|
setNewNoteOpen(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// Only add delete option if user owns the note
|
||||||
|
if (canDeleteNote) {
|
||||||
|
dropdownItems.push({
|
||||||
|
key: 'delete',
|
||||||
|
label: 'Delete Note',
|
||||||
|
icon: <BinIcon />,
|
||||||
|
onClick: () => {
|
||||||
|
setDeleteNoteOpen(true)
|
||||||
|
},
|
||||||
|
danger: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
key={note._id}
|
||||||
|
size='small'
|
||||||
|
style={{
|
||||||
|
backgroundColor: note.noteType.color + '26',
|
||||||
|
textAlign: 'left'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex vertical gap={'small'}>
|
||||||
|
<Flex gap={'middle'} align='start'>
|
||||||
|
<Space>
|
||||||
|
<PersonIcon />
|
||||||
|
<Text style={{ whiteSpace: 'nowrap' }}>{note.user.name}:</Text>
|
||||||
|
</Space>
|
||||||
|
<div style={{ marginBottom: '4px' }}>
|
||||||
|
<MarkdownDisplay content={note.content} />
|
||||||
|
</div>
|
||||||
|
</Flex>
|
||||||
|
<Divider style={{ margin: 0 }} />
|
||||||
|
<Flex wrap gap={'small'}>
|
||||||
|
<Dropdown
|
||||||
|
menu={{ items: dropdownItems }}
|
||||||
|
trigger={['hover']}
|
||||||
|
placement='bottomLeft'
|
||||||
|
>
|
||||||
|
<Button size='small'>Actions</Button>
|
||||||
|
</Dropdown>
|
||||||
|
<Space size={'small'} style={{ marginRight: 8 }}>
|
||||||
|
<Text type='secondary'>Type:</Text>
|
||||||
|
<Tag color={note.noteType.color} style={{ margin: 0 }}>
|
||||||
|
{note.noteType.name}
|
||||||
|
</Tag>
|
||||||
|
</Space>
|
||||||
|
<Space size={'small'} style={{ marginRight: 8 }}>
|
||||||
|
<Text type='secondary'>User ID:</Text>
|
||||||
|
<IdDisplay
|
||||||
|
longId={false}
|
||||||
|
id={note.user._id}
|
||||||
|
type={'user'}
|
||||||
|
showHyperlink={true}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
<Space size={'small'} style={{ marginRight: 8 }}>
|
||||||
|
<Text type='secondary'>Created At:</Text>
|
||||||
|
<TimeDisplay dateTime={note.createdAt} showSince={true} />
|
||||||
|
</Space>
|
||||||
|
<Flex style={{ flexGrow: 1 }} justify='end'>
|
||||||
|
<Space size={'small'}>
|
||||||
|
<Button
|
||||||
|
icon={<InfoIcon />}
|
||||||
|
type='text'
|
||||||
|
size='small'
|
||||||
|
onClick={() => {
|
||||||
|
navigate(infoAction.url(note._id))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={
|
||||||
|
childNotesLoading ? <LoadingOutlined /> : <CaretLeftFilled />
|
||||||
|
}
|
||||||
|
size='small'
|
||||||
|
type='text'
|
||||||
|
loading={childNotesLoading}
|
||||||
|
disabled={childNotesLoading}
|
||||||
|
style={{
|
||||||
|
transform: transformValue,
|
||||||
|
transition: 'transform 0.2s ease'
|
||||||
|
}}
|
||||||
|
onClick={toggleExpand}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
{isExpanded && (
|
||||||
|
<Flex vertical gap={'small'} style={{ flexGrow: 1 }}>
|
||||||
|
{childNotes.length > 0 ? (
|
||||||
|
childNotes.map((childNote) => (
|
||||||
|
<NoteItem key={childNote._id} note={childNote} />
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<MissingPlaceholder message={'No child notes.'} />
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
<Flex vertical gap={'middle'}></Flex>
|
||||||
|
</Flex>
|
||||||
|
<Modal
|
||||||
|
open={newNoteOpen}
|
||||||
|
onCancel={() => {
|
||||||
|
setNewNoteOpen(false)
|
||||||
|
}}
|
||||||
|
width={800}
|
||||||
|
closeIcon={false}
|
||||||
|
destroyOnHidden={true}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<NewNote
|
||||||
|
onOk={() => {
|
||||||
|
setNewNoteOpen(false)
|
||||||
|
}}
|
||||||
|
defaultValues={{
|
||||||
|
parent: { _id: note._id },
|
||||||
|
parentType: 'note'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={deleteNoteOpen}
|
||||||
|
title={
|
||||||
|
<Space size={'middle'}>
|
||||||
|
<ExclamationOctagonIcon />
|
||||||
|
Confirm Delete
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
okText='Delete'
|
||||||
|
cancelText='Cancel'
|
||||||
|
okType='danger'
|
||||||
|
closable={false}
|
||||||
|
centered
|
||||||
|
maskClosable={false}
|
||||||
|
footer={[
|
||||||
|
<Button
|
||||||
|
key='cancel'
|
||||||
|
onClick={() => {
|
||||||
|
setDeleteNoteOpen(false)
|
||||||
|
}}
|
||||||
|
disabled={deleteNoteLoading}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
key='delete'
|
||||||
|
type='primary'
|
||||||
|
danger
|
||||||
|
onClick={handleDeleteNote}
|
||||||
|
loading={deleteNoteLoading}
|
||||||
|
disabled={deleteNoteLoading}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Text>Are you sure you want to delete this note?</Text>
|
||||||
|
</Modal>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NoteItem.propTypes = {
|
||||||
|
note: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoteItem
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useContext, useEffect, useState } from 'react'
|
import { useCallback, useContext, useEffect, useState, useRef } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
@ -7,292 +7,35 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
Flex,
|
Flex,
|
||||||
Modal,
|
Modal,
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
Switch,
|
|
||||||
Spin,
|
Spin,
|
||||||
Alert,
|
Alert,
|
||||||
message,
|
message,
|
||||||
Divider,
|
|
||||||
Tag,
|
|
||||||
Dropdown
|
Dropdown
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { CaretLeftFilled, LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
import PlusIcon from '../../Icons/PlusIcon'
|
import PlusIcon from '../../Icons/PlusIcon'
|
||||||
import BinIcon from '../../Icons/BinIcon'
|
|
||||||
import PersonIcon from '../../Icons/PersonIcon'
|
|
||||||
import TimeDisplay from './TimeDisplay'
|
|
||||||
import MarkdownDisplay from './MarkdownDisplay'
|
|
||||||
import axios from 'axios'
|
|
||||||
import config from '../../../config'
|
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import { ApiServerContext } from '../context/ApiServerContext'
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||||
import IdDisplay from './IdDisplay'
|
|
||||||
import ReloadIcon from '../../Icons/ReloadIcon'
|
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||||
import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon'
|
import NewNote from '../Management/Notes/NewNote'
|
||||||
import ObjectProperty from './ObjectProperty'
|
import NoteItem from './NoteItem'
|
||||||
|
|
||||||
const { Text, Title } = Typography
|
const { Text } = Typography
|
||||||
const { TextArea } = Input
|
|
||||||
|
|
||||||
const NoteItem = ({
|
const NotesPanel = ({ _id, type }) => {
|
||||||
note,
|
|
||||||
expandedNotes,
|
|
||||||
setExpandedNotes,
|
|
||||||
fetchData,
|
|
||||||
onNewNote,
|
|
||||||
onDeleteNote,
|
|
||||||
userProfile,
|
|
||||||
onChildNoteAdded
|
|
||||||
}) => {
|
|
||||||
const [childNotes, setChildNotes] = useState({})
|
|
||||||
const [loadingChildNotes, setLoadingChildNotes] = useState(null)
|
|
||||||
|
|
||||||
const isExpanded = expandedNotes[note._id]
|
|
||||||
const hasChildNotes = childNotes[note._id] && childNotes[note._id].length > 0
|
|
||||||
const isThisNoteLoading = loadingChildNotes === note._id
|
|
||||||
|
|
||||||
let transformValue = 'rotate(0deg)'
|
|
||||||
if (isExpanded) {
|
|
||||||
transformValue = 'rotate(-90deg)'
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleNoteExpand = async (noteId) => {
|
|
||||||
const newExpandedState = !expandedNotes[noteId]
|
|
||||||
|
|
||||||
setExpandedNotes((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[noteId]: newExpandedState
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (newExpandedState && !childNotes[noteId]) {
|
|
||||||
setLoadingChildNotes(noteId)
|
|
||||||
try {
|
|
||||||
const childNotesData = await fetchData(noteId)
|
|
||||||
setChildNotes((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[noteId]: childNotesData
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching child notes:', error)
|
|
||||||
} finally {
|
|
||||||
setLoadingChildNotes(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleNewChildNote = () => {
|
|
||||||
if (onNewNote) {
|
|
||||||
onNewNote(note._id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeleteNote = () => {
|
|
||||||
if (onDeleteNote) {
|
|
||||||
onDeleteNote(note._id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload child notes when a new child note is added
|
|
||||||
const reloadChildNotes = useCallback(async () => {
|
|
||||||
// Always fetch child notes when this function is called
|
|
||||||
// This ensures child notes are loaded even if the parent wasn't expanded before
|
|
||||||
setLoadingChildNotes(note._id)
|
|
||||||
try {
|
|
||||||
const childNotesData = await fetchData(note._id)
|
|
||||||
setChildNotes((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[note._id]: childNotesData
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching child notes:', error)
|
|
||||||
} finally {
|
|
||||||
setLoadingChildNotes(null)
|
|
||||||
}
|
|
||||||
}, [fetchData, note._id])
|
|
||||||
|
|
||||||
// Listen for child note additions
|
|
||||||
useEffect(() => {
|
|
||||||
if (onChildNoteAdded) {
|
|
||||||
onChildNoteAdded(note._id, reloadChildNotes)
|
|
||||||
}
|
|
||||||
}, [note._id, onChildNoteAdded, reloadChildNotes])
|
|
||||||
|
|
||||||
// Check if the current user can delete this note
|
|
||||||
const canDeleteNote = userProfile && userProfile._id === note.user._id
|
|
||||||
|
|
||||||
const dropdownItems = [
|
|
||||||
{
|
|
||||||
key: 'new',
|
|
||||||
icon: <PlusIcon />,
|
|
||||||
label: 'New Note',
|
|
||||||
onClick: handleNewChildNote
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// Only add delete option if user owns the note
|
|
||||||
if (canDeleteNote) {
|
|
||||||
dropdownItems.push({
|
|
||||||
key: 'delete',
|
|
||||||
label: 'Delete Note',
|
|
||||||
icon: <BinIcon />,
|
|
||||||
onClick: handleDeleteNote,
|
|
||||||
danger: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
key={note._id}
|
|
||||||
size='small'
|
|
||||||
style={{
|
|
||||||
backgroundColor: note.noteType.color + '26',
|
|
||||||
textAlign: 'left'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Flex vertical gap={'small'}>
|
|
||||||
<Flex gap={'middle'} align='start'>
|
|
||||||
<Space>
|
|
||||||
<PersonIcon />
|
|
||||||
<Text style={{ whiteSpace: 'nowrap' }}>{note.user.name}:</Text>
|
|
||||||
</Space>
|
|
||||||
<div style={{ marginBottom: '4px' }}>
|
|
||||||
<MarkdownDisplay content={note.content} />
|
|
||||||
</div>
|
|
||||||
</Flex>
|
|
||||||
<Divider style={{ margin: 0 }} />
|
|
||||||
<Flex wrap gap={'small'}>
|
|
||||||
<Dropdown
|
|
||||||
menu={{ items: dropdownItems }}
|
|
||||||
trigger={['hover']}
|
|
||||||
placement='bottomLeft'
|
|
||||||
>
|
|
||||||
<Button size='small'>Actions</Button>
|
|
||||||
</Dropdown>
|
|
||||||
<Space size={'small'} style={{ marginRight: 8 }}>
|
|
||||||
<Text type='secondary'>Type:</Text>
|
|
||||||
<Tag color={note.noteType.color} style={{ margin: 0 }}>
|
|
||||||
{note.noteType.name}
|
|
||||||
</Tag>
|
|
||||||
</Space>
|
|
||||||
<Space size={'small'} style={{ marginRight: 8 }}>
|
|
||||||
<Text type='secondary'>User ID:</Text>
|
|
||||||
<IdDisplay
|
|
||||||
longId={false}
|
|
||||||
id={note.user._id}
|
|
||||||
type={'user'}
|
|
||||||
showHyperlink={true}
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
<Space size={'small'} style={{ marginRight: 8 }}>
|
|
||||||
<Text type='secondary'>Created At:</Text>
|
|
||||||
<TimeDisplay dateTime={note.createdAt} showSince={true} />
|
|
||||||
</Space>
|
|
||||||
<Flex style={{ flexGrow: 1 }} justify='end'>
|
|
||||||
<Space size={'small'}>
|
|
||||||
<Button
|
|
||||||
icon={
|
|
||||||
isThisNoteLoading ? <LoadingOutlined /> : <CaretLeftFilled />
|
|
||||||
}
|
|
||||||
size='small'
|
|
||||||
type='text'
|
|
||||||
loading={isThisNoteLoading}
|
|
||||||
disabled={isThisNoteLoading}
|
|
||||||
style={{
|
|
||||||
transform: transformValue,
|
|
||||||
transition: 'transform 0.2s ease'
|
|
||||||
}}
|
|
||||||
onClick={() => handleNoteExpand(note._id)}
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
{isExpanded && (
|
|
||||||
<>
|
|
||||||
<Flex vertical gap={'small'} style={{ flexGrow: 1 }}>
|
|
||||||
{hasChildNotes ? (
|
|
||||||
childNotes[note._id].map((childNote) => (
|
|
||||||
<NoteItem
|
|
||||||
key={childNote._id}
|
|
||||||
note={childNote}
|
|
||||||
expandedNotes={expandedNotes}
|
|
||||||
setExpandedNotes={setExpandedNotes}
|
|
||||||
fetchData={fetchData}
|
|
||||||
onNewNote={onNewNote}
|
|
||||||
onDeleteNote={onDeleteNote}
|
|
||||||
userProfile={userProfile}
|
|
||||||
onChildNoteAdded={onChildNoteAdded}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
) : !isThisNoteLoading ? (
|
|
||||||
<Card size='small'>
|
|
||||||
<Flex
|
|
||||||
justify='center'
|
|
||||||
gap={'small'}
|
|
||||||
style={{ height: '100%' }}
|
|
||||||
align='center'
|
|
||||||
>
|
|
||||||
<Text type='secondary'>
|
|
||||||
<InfoCircleIcon />
|
|
||||||
</Text>
|
|
||||||
<Text type='secondary'>No child notes.</Text>
|
|
||||||
</Flex>
|
|
||||||
</Card>
|
|
||||||
) : null}
|
|
||||||
</Flex>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Flex vertical gap={'middle'}></Flex>
|
|
||||||
</Flex>
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
NoteItem.propTypes = {
|
|
||||||
note: PropTypes.object.isRequired,
|
|
||||||
expandedNotes: PropTypes.object.isRequired,
|
|
||||||
setExpandedNotes: PropTypes.func.isRequired,
|
|
||||||
fetchData: PropTypes.func.isRequired,
|
|
||||||
onNewNote: PropTypes.func,
|
|
||||||
onDeleteNote: PropTypes.func,
|
|
||||||
userProfile: PropTypes.object,
|
|
||||||
onChildNoteAdded: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
const NotesPanel = ({ _id, onNewNote, type }) => {
|
|
||||||
const [newNoteOpen, setNewNoteOpen] = useState(false)
|
const [newNoteOpen, setNewNoteOpen] = useState(false)
|
||||||
const [showMarkdown, setShowMarkdown] = useState(false)
|
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [initialized, setInitialized] = useState(false)
|
const [initialized, setInitialized] = useState(false)
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const [newNoteFormLoading, setNewNoteFormLoading] = useState(false)
|
|
||||||
const [newNoteFormValues, setNewNoteFormValues] = useState({})
|
|
||||||
const [deleteNoteLoading, setDeleteNoteLoading] = useState(false)
|
|
||||||
const [doneEnabled, setDoneEnabled] = useState(false)
|
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
const [notes, setNotes] = useState(null)
|
const [notes, setNotes] = useState(null)
|
||||||
const [expandedNotes, setExpandedNotes] = useState({})
|
const [expandedNotes, setExpandedNotes] = useState({})
|
||||||
const [newNoteForm] = Form.useForm()
|
const subscribeToObjectTypeUpdatesRef = useRef(null)
|
||||||
const [selectedParentId, setSelectedParentId] = useState(null)
|
|
||||||
const [selectedParentType, setSelectedParentType] = useState(null)
|
|
||||||
const [childNoteCallbacks, setChildNoteCallbacks] = useState({})
|
|
||||||
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false)
|
|
||||||
const [noteToDelete, setNoteToDelete] = useState(null)
|
|
||||||
|
|
||||||
const newNoteFormUpdateValues = Form.useWatch([], newNoteForm)
|
const { token } = useContext(AuthContext)
|
||||||
|
const { fetchNotes, connected, subscribeToObjectTypeUpdates } =
|
||||||
useEffect(() => {
|
useContext(ApiServerContext)
|
||||||
newNoteForm
|
|
||||||
.validateFields({
|
|
||||||
validateOnly: true
|
|
||||||
})
|
|
||||||
.then(() => setDoneEnabled(true))
|
|
||||||
.catch(() => setDoneEnabled(false))
|
|
||||||
}, [newNoteForm, newNoteFormUpdateValues])
|
|
||||||
|
|
||||||
const { token, userProfile } = useContext(AuthContext)
|
|
||||||
const { fetchNotes } = useContext(ApiServerContext)
|
|
||||||
|
|
||||||
const fetchData = useCallback(
|
const fetchData = useCallback(
|
||||||
async (id) => {
|
async (id) => {
|
||||||
@ -307,17 +50,6 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
[fetchNotes]
|
[fetchNotes]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleNewChildNote = useCallback(
|
|
||||||
(parentId) => {
|
|
||||||
setSelectedParentId(parentId)
|
|
||||||
setSelectedParentType('note')
|
|
||||||
setNewNoteOpen(true)
|
|
||||||
newNoteForm.resetFields()
|
|
||||||
setNewNoteFormValues({})
|
|
||||||
},
|
|
||||||
[newNoteForm]
|
|
||||||
)
|
|
||||||
|
|
||||||
const generateNotes = useCallback(
|
const generateNotes = useCallback(
|
||||||
async (id) => {
|
async (id) => {
|
||||||
const notesData = await fetchData(id)
|
const notesData = await fetchData(id)
|
||||||
@ -351,114 +83,37 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
note={note}
|
note={note}
|
||||||
expandedNotes={expandedNotes}
|
expandedNotes={expandedNotes}
|
||||||
setExpandedNotes={setExpandedNotes}
|
setExpandedNotes={setExpandedNotes}
|
||||||
fetchData={fetchData}
|
|
||||||
onNewNote={handleNewChildNote}
|
|
||||||
onDeleteNote={handleDeleteNote}
|
|
||||||
userProfile={userProfile}
|
|
||||||
onChildNoteAdded={(noteId, callback) => {
|
|
||||||
setChildNoteCallbacks((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[noteId]: callback
|
|
||||||
}))
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
[fetchData, expandedNotes, userProfile, handleNewChildNote]
|
[fetchData, expandedNotes]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleNewNote = async () => {
|
|
||||||
setNewNoteFormLoading(true)
|
|
||||||
try {
|
|
||||||
await axios.post(
|
|
||||||
`${config.backendUrl}/notes`,
|
|
||||||
{
|
|
||||||
...newNoteFormValues,
|
|
||||||
parent: selectedParentId,
|
|
||||||
parentType: selectedParentType
|
|
||||||
},
|
|
||||||
{
|
|
||||||
withCredentials: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
setNewNoteOpen(false)
|
|
||||||
messageApi.success('Added a new note.')
|
|
||||||
|
|
||||||
// If this is a child note, expand the parent and reload child notes
|
|
||||||
if (selectedParentId) {
|
|
||||||
// Ensure parent is expanded
|
|
||||||
setExpandedNotes((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[selectedParentId]: true
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Add a small delay to ensure state update has taken effect
|
|
||||||
setTimeout(() => {
|
|
||||||
// Reload child notes for the parent
|
|
||||||
if (childNoteCallbacks[selectedParentId]) {
|
|
||||||
childNoteCallbacks[selectedParentId]()
|
|
||||||
}
|
|
||||||
}, 100)
|
|
||||||
} else {
|
|
||||||
// If it's a top-level note, reload all notes
|
|
||||||
setLoading(true)
|
|
||||||
handleReloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelectedParentId(null)
|
|
||||||
} catch (error) {
|
|
||||||
messageApi.error('Error creating new note: ' + error.message)
|
|
||||||
} finally {
|
|
||||||
setNewNoteFormLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeleteNote = async (noteId) => {
|
|
||||||
setNoteToDelete(noteId)
|
|
||||||
setDeleteConfirmOpen(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmDeleteNote = async () => {
|
|
||||||
if (!noteToDelete) return
|
|
||||||
setDeleteNoteLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await axios.delete(`${config.backendUrl}/notes/${noteToDelete}`, {
|
|
||||||
withCredentials: true
|
|
||||||
})
|
|
||||||
messageApi.success('Note deleted successfully.')
|
|
||||||
|
|
||||||
// Reload all top-level notes
|
|
||||||
setLoading(true)
|
|
||||||
handleReloadData()
|
|
||||||
|
|
||||||
// Reload child notes for all expanded parents to ensure UI stays in sync
|
|
||||||
const expandedNoteIds = Object.keys(expandedNotes).filter(
|
|
||||||
(id) => expandedNotes[id]
|
|
||||||
)
|
|
||||||
for (const parentId of expandedNoteIds) {
|
|
||||||
if (childNoteCallbacks[parentId]) {
|
|
||||||
childNoteCallbacks[parentId]()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
messageApi.error('Error deleting note: ' + error.message)
|
|
||||||
} finally {
|
|
||||||
setDeleteNoteLoading(false)
|
|
||||||
setDeleteConfirmOpen(false)
|
|
||||||
setNoteToDelete(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cancelDeleteNote = () => {
|
|
||||||
setDeleteConfirmOpen(false)
|
|
||||||
setNoteToDelete(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleReloadData = useCallback(async () => {
|
const handleReloadData = useCallback(async () => {
|
||||||
|
console.log('GOT RELOAD DATA')
|
||||||
setNotes(await generateNotes(_id))
|
setNotes(await generateNotes(_id))
|
||||||
}, [_id, generateNotes])
|
}, [_id, generateNotes])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (connected == true && subscribeToObjectTypeUpdatesRef.current == null) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = subscribeToObjectTypeUpdates(
|
||||||
|
'note',
|
||||||
|
(noteData) => {
|
||||||
|
if (noteData.parent._id == _id) {
|
||||||
|
console.log('Note note added to parent:', _id)
|
||||||
|
handleReloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
if (connected == true && subscribeToObjectTypeUpdatesRef.current) {
|
||||||
|
subscribeToObjectTypeUpdatesRef.current()
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [_id, subscribeToObjectTypeUpdates, connected, handleReloadData])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token != null && !initialized) {
|
if (token != null && !initialized) {
|
||||||
handleReloadData()
|
handleReloadData()
|
||||||
@ -466,25 +121,6 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
}
|
}
|
||||||
}, [token, handleReloadData, initialized])
|
}, [token, handleReloadData, initialized])
|
||||||
|
|
||||||
const handleModalOk = async () => {
|
|
||||||
try {
|
|
||||||
const values = await newNoteForm.validateFields()
|
|
||||||
onNewNote(values)
|
|
||||||
newNoteForm.resetFields()
|
|
||||||
setNewNoteOpen(false)
|
|
||||||
setShowMarkdown(false)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Validation failed:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleModalCancel = () => {
|
|
||||||
newNoteForm.resetFields()
|
|
||||||
setNewNoteOpen(false)
|
|
||||||
setShowMarkdown(false)
|
|
||||||
setSelectedParentId(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
const actionItems = {
|
const actionItems = {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
@ -504,11 +140,7 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
setLoading(true)
|
setLoading(true)
|
||||||
handleReloadData()
|
handleReloadData()
|
||||||
} else if (key === 'newNote') {
|
} else if (key === 'newNote') {
|
||||||
setSelectedParentId(_id)
|
|
||||||
setSelectedParentType(type)
|
|
||||||
setNewNoteOpen(true)
|
setNewNoteOpen(true)
|
||||||
newNoteForm.resetFields()
|
|
||||||
setNewNoteFormValues({})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -528,11 +160,7 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
icon={<PlusIcon />}
|
icon={<PlusIcon />}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedParentId(_id)
|
|
||||||
setSelectedParentType(type)
|
|
||||||
setNewNoteOpen(true)
|
setNewNoteOpen(true)
|
||||||
newNoteForm.resetFields()
|
|
||||||
setNewNoteFormValues({})
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
@ -552,146 +180,24 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
open={newNoteOpen}
|
open={newNoteOpen}
|
||||||
onOk={handleModalOk}
|
|
||||||
onCancel={handleModalCancel}
|
|
||||||
width={800}
|
width={800}
|
||||||
closeIcon={false}
|
|
||||||
destroyOnHidden={true}
|
destroyOnHidden={true}
|
||||||
footer={false}
|
footer={null}
|
||||||
>
|
onCancel={() => {
|
||||||
<Flex vertical gap='large'>
|
|
||||||
<Flex vertical gap='middle'>
|
|
||||||
<Flex align='center' justify='space-between'>
|
|
||||||
<Title level={2} style={{ marginTop: 0, marginBottom: 4 }}>
|
|
||||||
New Note
|
|
||||||
</Title>
|
|
||||||
<Space gap={'small'}>
|
|
||||||
<Text type='secondary'>Markdown:</Text>
|
|
||||||
<Switch onChange={setShowMarkdown} size='small' />
|
|
||||||
</Space>
|
|
||||||
</Flex>
|
|
||||||
<Form
|
|
||||||
form={newNoteForm}
|
|
||||||
layout='vertical'
|
|
||||||
onFinish={handleNewNote}
|
|
||||||
initialValues={{ content: '' }}
|
|
||||||
onValuesChange={(changedValues) =>
|
|
||||||
setNewNoteFormValues((prevValues) => ({
|
|
||||||
...prevValues,
|
|
||||||
...changedValues
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Flex vertical gap={'large'}>
|
|
||||||
<Flex gap='middle' wrap>
|
|
||||||
<Form.Item
|
|
||||||
name='content'
|
|
||||||
rules={[{ required: true, message: '' }]}
|
|
||||||
style={{ margin: 0, flexGrow: 1, minWidth: '300px' }}
|
|
||||||
>
|
|
||||||
<TextArea
|
|
||||||
rows={6}
|
|
||||||
placeholder='Enter note content'
|
|
||||||
style={{ resize: 'none' }}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{showMarkdown && (
|
|
||||||
<Card
|
|
||||||
style={{
|
|
||||||
flexGrow: 1,
|
|
||||||
minWidth: '300px',
|
|
||||||
backgroundColor: () => {
|
|
||||||
if (newNoteFormValues?.noteType?.color) {
|
|
||||||
return newNoteFormValues.noteType.color + '26'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MarkdownDisplay
|
|
||||||
content={newNoteForm.getFieldValue('content') || ''}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
<Form.Item
|
|
||||||
name='noteType'
|
|
||||||
style={{ margin: 0 }}
|
|
||||||
rules={[
|
|
||||||
{ required: true, message: 'Please select a note type' }
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<ObjectProperty
|
|
||||||
type='object'
|
|
||||||
objectType='noteType'
|
|
||||||
isEditing={true}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Flex>
|
|
||||||
</Form>
|
|
||||||
</Flex>
|
|
||||||
<Flex justify='end'>
|
|
||||||
<Button
|
|
||||||
style={{ margin: '0 8px' }}
|
|
||||||
disabled={newNoteFormLoading}
|
|
||||||
onClick={() => {
|
|
||||||
setNewNoteOpen(false)
|
setNewNoteOpen(false)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Cancel
|
<NewNote
|
||||||
</Button>
|
onOk={() => {
|
||||||
|
setNewNoteOpen(false)
|
||||||
<Button
|
messageApi.success('New note added.')
|
||||||
type='primary'
|
|
||||||
loading={newNoteFormLoading}
|
|
||||||
onClick={() => {
|
|
||||||
newNoteForm.submit()
|
|
||||||
}}
|
}}
|
||||||
disabled={newNoteFormLoading || !doneEnabled}
|
reset={newNoteOpen}
|
||||||
>
|
defaultValues={{
|
||||||
Done
|
parent: { _id },
|
||||||
</Button>
|
parentType: type
|
||||||
</Flex>
|
}}
|
||||||
</Flex>
|
/>
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Modal
|
|
||||||
open={deleteConfirmOpen}
|
|
||||||
title={
|
|
||||||
<Space size={'middle'}>
|
|
||||||
<ExclamationOctagonIcon />
|
|
||||||
Confirm Delete
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
onOk={confirmDeleteNote}
|
|
||||||
onCancel={cancelDeleteNote}
|
|
||||||
okText='Delete'
|
|
||||||
cancelText='Cancel'
|
|
||||||
okType='danger'
|
|
||||||
closable={false}
|
|
||||||
centered
|
|
||||||
maskClosable={false}
|
|
||||||
footer={[
|
|
||||||
<Button
|
|
||||||
key='cancel'
|
|
||||||
onClick={cancelDeleteNote}
|
|
||||||
disabled={deleteNoteLoading}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</Button>,
|
|
||||||
<Button
|
|
||||||
key='delete'
|
|
||||||
type='primary'
|
|
||||||
danger
|
|
||||||
onClick={confirmDeleteNote}
|
|
||||||
loading={deleteNoteLoading}
|
|
||||||
disabled={deleteNoteLoading}
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</Button>
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Text>Are you sure you want to delete this note?</Text>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Typography, Flex } from 'antd'
|
import { Typography, Flex, Badge } from 'antd'
|
||||||
import { useState, useEffect, useContext, useCallback } from 'react'
|
import { useState, useEffect, useContext, useCallback } from 'react'
|
||||||
import { getModelByName } from '../../../database/ObjectModels'
|
import { getModelByName } from '../../../database/ObjectModels'
|
||||||
import { ApiServerContext } from '../context/ApiServerContext'
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
@ -52,9 +52,10 @@ const ObjectDisplay = ({ object, objectType }) => {
|
|||||||
const model = getModelByName(objectType)
|
const model = getModelByName(objectType)
|
||||||
const Icon = model.icon
|
const Icon = model.icon
|
||||||
return (
|
return (
|
||||||
<Flex gap={'small'}>
|
<Flex gap={'small'} align='center'>
|
||||||
<Icon />
|
<Icon />
|
||||||
<Text>{objectData?.name ? objectData.name : null}</Text>
|
{objectData?.color ? <Badge color={objectData?.color} /> : null}
|
||||||
|
<Text ellipsis>{objectData?.name ? objectData.name : null}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,21 @@ const ObjectInfo = ({
|
|||||||
loading = false,
|
loading = false,
|
||||||
isEditing = false,
|
isEditing = false,
|
||||||
type = 'unknown',
|
type = 'unknown',
|
||||||
|
showHyperlink,
|
||||||
|
showLabels = true,
|
||||||
objectData = null,
|
objectData = null,
|
||||||
properties = [],
|
properties = [],
|
||||||
required = undefined,
|
required = undefined,
|
||||||
visibleProperties = {},
|
visibleProperties = {},
|
||||||
objectPropertyProps = {},
|
objectPropertyProps = {},
|
||||||
|
column = {
|
||||||
|
xs: 1,
|
||||||
|
sm: 1,
|
||||||
|
md: 1,
|
||||||
|
lg: 2,
|
||||||
|
xl: 2,
|
||||||
|
xxl: 2
|
||||||
|
},
|
||||||
...rest
|
...rest
|
||||||
}) => {
|
}) => {
|
||||||
const allItems = getModelProperties(type)
|
const allItems = getModelProperties(type)
|
||||||
@ -47,33 +57,29 @@ const ObjectInfo = ({
|
|||||||
const key = item.name || item.label || idx
|
const key = item.name || item.label || idx
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
label: (
|
label:
|
||||||
|
showLabels == true ? (
|
||||||
<Flex vertical style={{ height: '100%' }} justify='center'>
|
<Flex vertical style={{ height: '100%' }} justify='center'>
|
||||||
{item.label}
|
{item.label}
|
||||||
</Flex>
|
</Flex>
|
||||||
),
|
) : null,
|
||||||
children: (
|
children: (
|
||||||
<ObjectProperty
|
<ObjectProperty
|
||||||
{...item}
|
{...item}
|
||||||
{...objectPropertyProps}
|
{...objectPropertyProps}
|
||||||
|
showHyperlink={showHyperlink}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
objectData={objectData}
|
objectData={objectData}
|
||||||
/>
|
/>
|
||||||
)
|
),
|
||||||
|
span: item?.span || undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Spin spinning={loading} indicator={<LoadingOutlined />}>
|
<Spin spinning={loading} indicator={<LoadingOutlined />}>
|
||||||
<Descriptions
|
<Descriptions
|
||||||
column={{
|
column={column}
|
||||||
xs: 1,
|
|
||||||
sm: 1,
|
|
||||||
md: 1,
|
|
||||||
lg: 2,
|
|
||||||
xl: 2,
|
|
||||||
xxl: 2
|
|
||||||
}}
|
|
||||||
bordered={true}
|
bordered={true}
|
||||||
{...rest}
|
{...rest}
|
||||||
items={descriptionItems}
|
items={descriptionItems}
|
||||||
@ -84,6 +90,9 @@ const ObjectInfo = ({
|
|||||||
|
|
||||||
ObjectInfo.propTypes = {
|
ObjectInfo.propTypes = {
|
||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool,
|
||||||
|
column: PropTypes.object,
|
||||||
|
showHyperlink: PropTypes.bool,
|
||||||
|
showLabels: PropTypes.bool,
|
||||||
indicator: PropTypes.node,
|
indicator: PropTypes.node,
|
||||||
properties: PropTypes.array,
|
properties: PropTypes.array,
|
||||||
bordered: PropTypes.bool,
|
bordered: PropTypes.bool,
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import ObjectList from './ObjectList'
|
|||||||
import VarianceDisplay from './VarianceDisplay'
|
import VarianceDisplay from './VarianceDisplay'
|
||||||
import OperationDisplay from './OperationDisplay'
|
import OperationDisplay from './OperationDisplay'
|
||||||
import MarkdownDisplay from './MarkdownDisplay'
|
import MarkdownDisplay from './MarkdownDisplay'
|
||||||
|
import MarkdownInput from './MarkdownInput'
|
||||||
import ObjectSelect from './ObjectSelect'
|
import ObjectSelect from './ObjectSelect'
|
||||||
import ObjectDisplay from './ObjectDisplay'
|
import ObjectDisplay from './ObjectDisplay'
|
||||||
import ObjectTypeSelect from './ObjectTypeSelect'
|
import ObjectTypeSelect from './ObjectTypeSelect'
|
||||||
@ -603,6 +604,12 @@ const ObjectProperty = ({
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
|
case 'markdown':
|
||||||
|
return (
|
||||||
|
<Form.Item name={formItemName} {...mergedFormItemProps}>
|
||||||
|
<MarkdownInput value={value} />
|
||||||
|
</Form.Item>
|
||||||
|
)
|
||||||
case 'material':
|
case 'material':
|
||||||
return (
|
return (
|
||||||
<Form.Item name={formItemName} {...mergedFormItemProps}>
|
<Form.Item name={formItemName} {...mergedFormItemProps}>
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import CheckIcon from '../../Icons/CheckIcon'
|
|||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
||||||
import { AuthContext } from '../context/AuthContext'
|
import { AuthContext } from '../context/AuthContext'
|
||||||
import merge from 'lodash/merge'
|
import unionBy from 'lodash/unionBy'
|
||||||
const logger = loglevel.getLogger('DasboardTable')
|
const logger = loglevel.getLogger('DasboardTable')
|
||||||
logger.setLevel(config.logLevel)
|
logger.setLevel(config.logLevel)
|
||||||
|
|
||||||
@ -88,9 +88,10 @@ const ObjectTable = forwardRef(
|
|||||||
const [lazyLoading, setLazyLoading] = useState(false)
|
const [lazyLoading, setLazyLoading] = useState(false)
|
||||||
|
|
||||||
const subscribedIdsRef = useRef([])
|
const subscribedIdsRef = useRef([])
|
||||||
const [typeSubscribed, setTypeSubscribed] = useState(false)
|
// const [typeSubscribed, setTypeSubscribed] = useState(false)
|
||||||
const unsubscribesRef = useRef([])
|
const unsubscribesRef = useRef([])
|
||||||
const updateEventHandlerRef = useRef()
|
const updateEventHandlerRef = useRef()
|
||||||
|
const subscribeToObjectTypeUpdatesRef = useRef(null)
|
||||||
|
|
||||||
const rowActions =
|
const rowActions =
|
||||||
model.actions?.filter((action) => action.row == true) || []
|
model.actions?.filter((action) => action.row == true) || []
|
||||||
@ -291,12 +292,17 @@ const ObjectTable = forwardRef(
|
|||||||
const updateEventHandler = useCallback((id, updatedData) => {
|
const updateEventHandler = useCallback((id, updatedData) => {
|
||||||
console.log('GOT UPDATE FOR', id)
|
console.log('GOT UPDATE FOR', id)
|
||||||
setPages((prevPages) =>
|
setPages((prevPages) =>
|
||||||
prevPages.map((page) => ({
|
prevPages.map((page) => {
|
||||||
|
const updatedItems = unionBy(
|
||||||
|
[{ ...updatedData, _id: id }],
|
||||||
|
page.items,
|
||||||
|
'_id'
|
||||||
|
)
|
||||||
|
return {
|
||||||
...page,
|
...page,
|
||||||
items: page.items.map((item) => {
|
items: updatedItems
|
||||||
return item._id === id ? merge({}, item, updatedData) : item
|
}
|
||||||
})
|
})
|
||||||
}))
|
|
||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -363,6 +369,9 @@ const ObjectTable = forwardRef(
|
|||||||
// Cleanup effect for component unmount
|
// Cleanup effect for component unmount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
console.log('API: Call unsub', connected)
|
||||||
|
if (connected == true && unsubscribesRef.current) {
|
||||||
|
console.log('API: Got object unsub')
|
||||||
// Clean up all subscriptions when component unmounts
|
// Clean up all subscriptions when component unmounts
|
||||||
unsubscribesRef.current.forEach((unsubscribe) => {
|
unsubscribesRef.current.forEach((unsubscribe) => {
|
||||||
console.log('CALLING UNSUB on unmount')
|
console.log('CALLING UNSUB on unmount')
|
||||||
@ -370,26 +379,33 @@ const ObjectTable = forwardRef(
|
|||||||
})
|
})
|
||||||
unsubscribesRef.current = []
|
unsubscribesRef.current = []
|
||||||
subscribedIdsRef.current = []
|
subscribedIdsRef.current = []
|
||||||
|
|
||||||
|
// Clean up type subscription
|
||||||
}
|
}
|
||||||
}, [])
|
if (connected == true && subscribeToObjectTypeUpdatesRef.current) {
|
||||||
|
console.log('UNSUBBING type subscription on unmount')
|
||||||
|
console.log('API: Got type unsub')
|
||||||
|
subscribeToObjectTypeUpdatesRef.current()
|
||||||
|
subscribeToObjectTypeUpdatesRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [connected])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (connected == true && typeSubscribed == false) {
|
if (
|
||||||
const unsubscribe = subscribeToObjectTypeUpdates(type, newEventHandler)
|
connected == true &&
|
||||||
setTypeSubscribed(true)
|
subscribeToObjectTypeUpdatesRef.current == null
|
||||||
return () => {
|
) {
|
||||||
if (unsubscribe && typeSubscribed == true) {
|
console.log(
|
||||||
unsubscribe()
|
'API: Subbing to updates',
|
||||||
}
|
subscribeToObjectTypeUpdatesRef.current
|
||||||
}
|
)
|
||||||
}
|
subscribeToObjectTypeUpdatesRef.current = subscribeToObjectTypeUpdates(
|
||||||
}, [
|
|
||||||
type,
|
type,
|
||||||
subscribeToObjectTypeUpdates,
|
newEventHandler
|
||||||
connected,
|
)
|
||||||
newEventHandler,
|
}
|
||||||
typeSubscribed
|
}, [type, subscribeToObjectTypeUpdates, connected, newEventHandler])
|
||||||
])
|
|
||||||
|
|
||||||
const updateData = useCallback(
|
const updateData = useCallback(
|
||||||
(_id, updatedData) => {
|
(_id, updatedData) => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// PrinterTemperaturePanel.js
|
// PrinterTemperaturePanel.js
|
||||||
import { useContext, useState, useEffect, useCallback } from 'react'
|
import { useContext, useState, useEffect } from 'react'
|
||||||
import {
|
import {
|
||||||
Progress,
|
Progress,
|
||||||
Typography,
|
Typography,
|
||||||
@ -11,9 +11,10 @@ import {
|
|||||||
Button
|
Button
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
import { LoadingOutlined, CaretLeftOutlined } from '@ant-design/icons'
|
||||||
import { PrintServerContext } from '../context/PrintServerContext'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { ApiServerContext } from '../context/ApiServerContext'
|
||||||
|
import merge from 'lodash/merge'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
const { Panel } = Collapse
|
const { Panel } = Collapse
|
||||||
@ -30,91 +31,70 @@ const CustomCollapse = styled(Collapse)`
|
|||||||
`
|
`
|
||||||
|
|
||||||
const PrinterTemperaturePanel = ({
|
const PrinterTemperaturePanel = ({
|
||||||
printerId,
|
id,
|
||||||
showHotEndControls = true,
|
showExtruderControls = true,
|
||||||
showHeatedBedControls = true,
|
showBedControls = true,
|
||||||
showHotEnd = true,
|
showExtruder = true,
|
||||||
showHeatedBed = true,
|
showBed = true,
|
||||||
showMoreInfo = true,
|
showMoreInfo = true
|
||||||
shouldUnsubscribe = true
|
|
||||||
}) => {
|
}) => {
|
||||||
const [temperatureData, setTemperatureData] = useState({
|
const [temperatureData, setTemperatureData] = useState({
|
||||||
hotEnd: {},
|
extruder: {
|
||||||
heatedBed: {}
|
current: 0,
|
||||||
|
target: 0,
|
||||||
|
power: 0
|
||||||
|
},
|
||||||
|
bed: {
|
||||||
|
current: 0,
|
||||||
|
target: 0,
|
||||||
|
power: 0
|
||||||
|
},
|
||||||
|
pinda: 0,
|
||||||
|
ambiant: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
const [hotEndTemperature, setHotEndTemperature] = useState(
|
const { subscribeToObjectEvent, connected } = useContext(ApiServerContext)
|
||||||
temperatureData?.hotEnd?.target || 0
|
|
||||||
)
|
|
||||||
const [heatedBedTemperature, setHeatedBedTemperature] = useState(
|
|
||||||
temperatureData?.heatedBed?.target || 0
|
|
||||||
)
|
|
||||||
const { printServer } = useContext(PrintServerContext)
|
|
||||||
|
|
||||||
const notifyTemperatureStatusUpdate = useCallback((statusUpdate) => {
|
// Sync input values with actual temperature targets
|
||||||
setTemperatureData((prev) => {
|
useEffect(() => {
|
||||||
const temperatureObject = {
|
if (temperatureData.extruder?.target !== undefined) {
|
||||||
...prev
|
setExtruderTarget(temperatureData.extruder.target)
|
||||||
}
|
}
|
||||||
if (statusUpdate?.extruder?.temperature !== undefined) {
|
}, [temperatureData.extruder?.target])
|
||||||
temperatureObject.hotEnd.current = statusUpdate?.extruder?.temperature
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusUpdate?.heater_bed?.temperature !== undefined) {
|
|
||||||
temperatureObject.heatedBed.current =
|
|
||||||
statusUpdate?.heater_bed?.temperature
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusUpdate?.extruder?.target !== undefined) {
|
|
||||||
temperatureObject.hotEnd.target = statusUpdate?.extruder?.target
|
|
||||||
setHotEndTemperature(statusUpdate?.extruder?.target)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusUpdate?.heater_bed?.target !== undefined) {
|
|
||||||
temperatureObject.heatedBed.target = statusUpdate?.heater_bed?.target
|
|
||||||
setHeatedBedTemperature(statusUpdate?.heater_bed?.target)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusUpdate?.extruder?.power !== undefined) {
|
|
||||||
temperatureObject.hotEnd.power = statusUpdate?.extruder?.power
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusUpdate?.heater_bed?.power !== undefined) {
|
|
||||||
temperatureObject.heatedBed.power = statusUpdate?.heater_bed?.power
|
|
||||||
}
|
|
||||||
|
|
||||||
return temperatureObject
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const params = {
|
if (temperatureData.bed?.target !== undefined) {
|
||||||
printerId,
|
setBedTarget(temperatureData.bed.target)
|
||||||
objects: {
|
|
||||||
extruder: null,
|
|
||||||
heater_bed: null // eslint-disable-line
|
|
||||||
}
|
}
|
||||||
}
|
}, [temperatureData.bed?.target])
|
||||||
if (printServer?.connected == true) {
|
|
||||||
printServer.emit('printer.objects.subscribe', params)
|
|
||||||
printServer.emit('printer.objects.query', params)
|
|
||||||
printServer.on('notify_status_update', notifyTemperatureStatusUpdate)
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
if (printServer && shouldUnsubscribe == true) {
|
|
||||||
printServer.off('notify_status_update', notifyTemperatureStatusUpdate)
|
|
||||||
printServer.emit('printer.objects.unsubscribe', params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [printServer, printerId, notifyTemperatureStatusUpdate, shouldUnsubscribe])
|
|
||||||
|
|
||||||
const handleSetTemperatureClick = (target, value) => {
|
useEffect(() => {
|
||||||
if (printServer) {
|
if (id && connected) {
|
||||||
printServer.emit('printer.gcode.script', {
|
const temperatureEventUnsubscribe = subscribeToObjectEvent(
|
||||||
printerId,
|
id,
|
||||||
script: `SET_HEATER_TEMPERATURE HEATER=${target} TARGET=${value}`
|
'printer',
|
||||||
|
'temperature',
|
||||||
|
(event) => {
|
||||||
|
setTemperatureData((prev) => {
|
||||||
|
const merged = merge({}, prev, event.data)
|
||||||
|
return merged
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
return () => {
|
||||||
|
if (temperatureEventUnsubscribe) temperatureEventUnsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [id, connected])
|
||||||
|
|
||||||
|
const [extruderTarget, setExtruderTarget] = useState(0)
|
||||||
|
const [bedTarget, setBedTarget] = useState(0)
|
||||||
|
|
||||||
|
const handleSetTemperature = (data) => {
|
||||||
|
if (id && connected == true) {
|
||||||
|
console.log(data)
|
||||||
|
//sendObjectAction(id, 'printer', { type: 'setTemperature', data })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const moreInfoItems = [
|
const moreInfoItems = [
|
||||||
@ -126,33 +106,32 @@ const PrinterTemperaturePanel = ({
|
|||||||
<Flex vertical gap={0}>
|
<Flex vertical gap={0}>
|
||||||
<Text>
|
<Text>
|
||||||
Hot End Power:{' '}
|
Hot End Power:{' '}
|
||||||
{Math.round((temperatureData.hotEnd.power || 0) * 100)}%
|
{Math.round((temperatureData.extruder.power || 0) * 100)}%
|
||||||
</Text>
|
</Text>
|
||||||
<Progress
|
<Progress
|
||||||
percent={(temperatureData.hotEnd.power || 0) * 100}
|
percent={(temperatureData.extruder.power || 0) * 100}
|
||||||
showInfo={false}
|
showInfo={false}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex vertical gap={0}>
|
<Flex vertical gap={0}>
|
||||||
<Text>
|
<Text>
|
||||||
Bed Power:{' '}
|
Bed Power: {Math.round((temperatureData.bed.power || 0) * 100)}%
|
||||||
{Math.round((temperatureData.heatedBed.power || 0) * 100)}%
|
|
||||||
</Text>
|
</Text>
|
||||||
<Progress
|
<Progress
|
||||||
percent={(temperatureData.heatedBed.power || 0) * 100}
|
percent={(temperatureData.bed.power || 0) * 100}
|
||||||
showInfo={false}
|
showInfo={false}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Panel>
|
<Panel>
|
||||||
{typeof temperatureData.pindaTemp !== 'undefined' && (
|
{typeof temperatureData.pinda !== 'undefined' && (
|
||||||
<Flex vertical gap={0}>
|
<Flex vertical gap={0}>
|
||||||
<Text>Pinda Temp: {temperatureData.pindaTemp}°C</Text>
|
<Text>Pinda Temp: {temperatureData.pindaTemp}°C</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{typeof temperatureData.ambiantActual !== 'undefined' && (
|
{typeof temperatureData.ambiant !== 'undefined' && (
|
||||||
<Flex vertical gap={0}>
|
<Flex vertical gap={0}>
|
||||||
<Text>Ambient Actual: {temperatureData.ambiantActual}°C</Text>
|
<Text>Ambient Actual: {temperatureData.ambiant}°C</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Panel>
|
</Panel>
|
||||||
@ -165,41 +144,41 @@ const PrinterTemperaturePanel = ({
|
|||||||
<div style={{ minWidth: 190 }}>
|
<div style={{ minWidth: 190 }}>
|
||||||
{temperatureData ? (
|
{temperatureData ? (
|
||||||
<Flex vertical gap='middle'>
|
<Flex vertical gap='middle'>
|
||||||
{temperatureData.hotEnd && showHotEnd && (
|
{temperatureData.extruder && showExtruder && (
|
||||||
<Flex vertical gap={0}>
|
<Flex vertical gap={0}>
|
||||||
<Text>
|
<Text>
|
||||||
Hot End: {temperatureData.hotEnd.current}°C /{' '}
|
Hot End: {temperatureData.extruder.current}°C /{' '}
|
||||||
{temperatureData.hotEnd.target}°C
|
{temperatureData.extruder.target}°C
|
||||||
</Text>
|
</Text>
|
||||||
<Progress
|
<Progress
|
||||||
percent={(temperatureData.hotEnd.target / 300) * 100}
|
percent={(temperatureData.extruder.target / 300) * 100}
|
||||||
strokeColor='#FF392F1D'
|
strokeColor='#FF392F1D'
|
||||||
success={{
|
success={{
|
||||||
percent: (temperatureData.hotEnd.current / 300) * 100,
|
percent: (temperatureData.extruder.current / 300) * 100,
|
||||||
strokeColor: '#FF3B2F'
|
strokeColor: '#FF3B2F'
|
||||||
}}
|
}}
|
||||||
showInfo={false}
|
showInfo={false}
|
||||||
/>
|
/>
|
||||||
{showHotEndControls && (
|
{showExtruderControls && (
|
||||||
<Space direction='horizontal' style={{ marginTop: 5 }}>
|
<Space direction='horizontal' style={{ marginTop: 5 }}>
|
||||||
<Space.Compact block size='small'>
|
<Space.Compact block size='small'>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
value={hotEndTemperature}
|
value={extruderTarget}
|
||||||
min={0}
|
min={0}
|
||||||
max={300}
|
max={300}
|
||||||
style={{ width: '120px' }}
|
style={{ width: '120px' }}
|
||||||
addonAfter='°C'
|
addonAfter='°C'
|
||||||
onChange={(value) => setHotEndTemperature(value)}
|
onChange={(value) => setExtruderTarget(value || 0)}
|
||||||
onPressEnter={() =>
|
onPressEnter={handleSetTemperature({
|
||||||
handleSetTemperatureClick('extruder', hotEndTemperature)
|
extruder: { target: extruderTarget }
|
||||||
}
|
})}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type='default'
|
type='default'
|
||||||
style={{ width: 40 }}
|
style={{ width: 40 }}
|
||||||
onClick={() =>
|
onClick={handleSetTemperature({
|
||||||
handleSetTemperatureClick('extruder', hotEndTemperature)
|
extruder: { target: extruderTarget }
|
||||||
}
|
})}
|
||||||
>
|
>
|
||||||
Set
|
Set
|
||||||
</Button>
|
</Button>
|
||||||
@ -208,7 +187,9 @@ const PrinterTemperaturePanel = ({
|
|||||||
type='default'
|
type='default'
|
||||||
size='small'
|
size='small'
|
||||||
style={{ width: 40 }}
|
style={{ width: 40 }}
|
||||||
onClick={() => handleSetTemperatureClick('extruder', 0)}
|
onClick={() =>
|
||||||
|
handleSetTemperature({ extruder: { target: 0 } })
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Off
|
Off
|
||||||
</Button>
|
</Button>
|
||||||
@ -217,50 +198,44 @@ const PrinterTemperaturePanel = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{temperatureData.heatedBed && showHeatedBed && (
|
{temperatureData.bed && showBed && (
|
||||||
<Flex vertical gap={0}>
|
<Flex vertical gap={0}>
|
||||||
<Text>
|
<Text>
|
||||||
Heated Bed: {temperatureData.heatedBed.current}°C /{' '}
|
Heated Bed: {temperatureData.bed.current}°C /{' '}
|
||||||
{temperatureData.heatedBed.target}°C
|
{temperatureData.bed.target}°C
|
||||||
</Text>
|
</Text>
|
||||||
<Progress
|
<Progress
|
||||||
percent={(temperatureData.heatedBed.target / 300) * 100}
|
percent={(temperatureData.bed.target / 300) * 100}
|
||||||
strokeColor='#FF392F1D'
|
strokeColor='#FF392F1D'
|
||||||
success={{
|
success={{
|
||||||
percent: (temperatureData.heatedBed.current / 300) * 100,
|
percent: (temperatureData.bed.current / 300) * 100,
|
||||||
strokeColor: '#FF3B2F'
|
strokeColor: '#FF3B2F'
|
||||||
}}
|
}}
|
||||||
showInfo={false}
|
showInfo={false}
|
||||||
/>
|
/>
|
||||||
{showHeatedBedControls && (
|
{showBedControls && (
|
||||||
<Space
|
<Space
|
||||||
direction='horizontal'
|
direction='horizontal'
|
||||||
style={{ marginTop: 5, height: '21px' }}
|
style={{ marginTop: 5, height: '21px' }}
|
||||||
>
|
>
|
||||||
<Space.Compact block size='small'>
|
<Space.Compact block size='small'>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
value={heatedBedTemperature}
|
value={bedTarget}
|
||||||
min={0}
|
min={0}
|
||||||
max={300}
|
max={300}
|
||||||
style={{ width: '120px' }}
|
style={{ width: '120px' }}
|
||||||
addonAfter='°C'
|
addonAfter='°C'
|
||||||
onChange={(value) => setHeatedBedTemperature(value)}
|
onChange={(value) => setBedTarget(value || 0)}
|
||||||
onPressEnter={() =>
|
onPressEnter={handleSetTemperature({
|
||||||
handleSetTemperatureClick(
|
bed: { target: bedTarget }
|
||||||
'heater_bed',
|
})}
|
||||||
heatedBedTemperature
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type='default'
|
type='default'
|
||||||
style={{ width: 40 }}
|
style={{ width: 40 }}
|
||||||
onClick={() =>
|
onClick={handleSetTemperature({
|
||||||
handleSetTemperatureClick(
|
bed: { target: bedTarget }
|
||||||
'heater_bed',
|
})}
|
||||||
heatedBedTemperature
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
Set
|
Set
|
||||||
</Button>
|
</Button>
|
||||||
@ -269,7 +244,11 @@ const PrinterTemperaturePanel = ({
|
|||||||
type='default'
|
type='default'
|
||||||
size='small'
|
size='small'
|
||||||
style={{ width: 40 }}
|
style={{ width: 40 }}
|
||||||
onClick={() => handleSetTemperatureClick('heater_bed', 0)}
|
onClick={() =>
|
||||||
|
handleSetTemperature({
|
||||||
|
bed: { target: 0 }
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Off
|
Off
|
||||||
</Button>
|
</Button>
|
||||||
@ -298,11 +277,11 @@ const PrinterTemperaturePanel = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
PrinterTemperaturePanel.propTypes = {
|
PrinterTemperaturePanel.propTypes = {
|
||||||
printerId: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
showHotEndControls: PropTypes.bool,
|
showExtruderControls: PropTypes.bool,
|
||||||
showHeatedBedControls: PropTypes.bool,
|
showBedControls: PropTypes.bool,
|
||||||
showHotEnd: PropTypes.bool,
|
showExtruder: PropTypes.bool,
|
||||||
showHeatedBed: PropTypes.bool,
|
showBed: PropTypes.bool,
|
||||||
showMoreInfo: PropTypes.bool,
|
showMoreInfo: PropTypes.bool,
|
||||||
shouldUnsubscribe: PropTypes.bool
|
shouldUnsubscribe: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|||||||
67
src/components/Dashboard/common/WizardView.jsx
Normal file
67
src/components/Dashboard/common/WizardView.jsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useMediaQuery } from 'react-responsive'
|
||||||
|
import { Typography, Flex, Steps, Divider } from 'antd'
|
||||||
|
import NewObjectButtons from './NewObjectButtons'
|
||||||
|
|
||||||
|
const { Title } = Typography
|
||||||
|
|
||||||
|
const WizardView = ({
|
||||||
|
showSteps = true,
|
||||||
|
steps,
|
||||||
|
title = 'Wizard View',
|
||||||
|
onSubmit,
|
||||||
|
formValid,
|
||||||
|
loading
|
||||||
|
}) => {
|
||||||
|
const [currentStep, setCurrentStep] = useState(0)
|
||||||
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex gap='middle'>
|
||||||
|
{!isMobile && showSteps == true ? (
|
||||||
|
<div style={{ minWidth: '160px' }}>
|
||||||
|
<Steps
|
||||||
|
current={currentStep}
|
||||||
|
items={steps}
|
||||||
|
direction='vertical'
|
||||||
|
style={{ width: 'fit-content' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{!isMobile && showSteps == true ? (
|
||||||
|
<Divider type='vertical' style={{ height: 'unset' }} />
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<Flex vertical gap='middle' style={{ flexGrow: 1 }}>
|
||||||
|
<Title level={2} style={{ margin: 0 }}>
|
||||||
|
{title}
|
||||||
|
</Title>
|
||||||
|
<div style={{ minHeight: '260px', marginBottom: 8 }}>
|
||||||
|
{steps[currentStep].content}
|
||||||
|
</div>
|
||||||
|
<NewObjectButtons
|
||||||
|
currentStep={currentStep}
|
||||||
|
totalSteps={steps.length}
|
||||||
|
onPrevious={() => setCurrentStep((prev) => prev - 1)}
|
||||||
|
onNext={() => setCurrentStep((prev) => prev + 1)}
|
||||||
|
onSubmit={onSubmit}
|
||||||
|
formValid={formValid}
|
||||||
|
submitLoading={loading}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
WizardView.propTypes = {
|
||||||
|
onSubmit: PropTypes.func.isRequired,
|
||||||
|
formValid: PropTypes.bool.isRequired,
|
||||||
|
steps: PropTypes.array.isRequired,
|
||||||
|
showSteps: PropTypes.bool,
|
||||||
|
title: PropTypes.string,
|
||||||
|
loading: PropTypes.bool
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WizardView
|
||||||
@ -93,7 +93,9 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
newSocket.on('objectUpdate', handleObjectUpdate)
|
newSocket.on('objectUpdate', handleObjectUpdate)
|
||||||
|
newSocket.on('objectEvent', handleObjectEvent)
|
||||||
newSocket.on('objectNew', handleObjectNew)
|
newSocket.on('objectNew', handleObjectNew)
|
||||||
|
newSocket.on('objectDelete', handleObjectDelete)
|
||||||
newSocket.on('lockUpdate', handleLockUpdate)
|
newSocket.on('lockUpdate', handleLockUpdate)
|
||||||
|
|
||||||
newSocket.on('disconnect', () => {
|
newSocket.on('disconnect', () => {
|
||||||
@ -216,6 +218,37 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleObjectEvent = async (data) => {
|
||||||
|
const id = data._id
|
||||||
|
const objectType = data.objectType
|
||||||
|
|
||||||
|
const callbacksRefKey = `${objectType}:${id}:events:${data.event.type}`
|
||||||
|
logger.debug('Notifying object event:', data)
|
||||||
|
if (
|
||||||
|
id &&
|
||||||
|
objectType &&
|
||||||
|
subscribedCallbacksRef.current.has(callbacksRefKey)
|
||||||
|
) {
|
||||||
|
const callbacks = subscribedCallbacksRef.current.get(callbacksRefKey)
|
||||||
|
logger.debug(
|
||||||
|
`Calling ${callbacks.length} callbacks for object:`,
|
||||||
|
callbacksRefKey
|
||||||
|
)
|
||||||
|
callbacks.forEach((callback) => {
|
||||||
|
try {
|
||||||
|
callback(data.event)
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error in object event callback:', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
`No callbacks found for object: ${callbacksRefKey}, subscribed callbacks:`,
|
||||||
|
Array.from(subscribedCallbacksRef.current.keys())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleObjectNew = async (data) => {
|
const handleObjectNew = async (data) => {
|
||||||
logger.debug('Notifying object new:', data)
|
logger.debug('Notifying object new:', data)
|
||||||
const objectType = data.objectType || 'unknown'
|
const objectType = data.objectType || 'unknown'
|
||||||
@ -241,6 +274,31 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleObjectDelete = async (data) => {
|
||||||
|
logger.debug('Notifying object delete:', data)
|
||||||
|
const objectType = data.objectType || 'unknown'
|
||||||
|
|
||||||
|
if (objectType && subscribedCallbacksRef.current.has(objectType)) {
|
||||||
|
const callbacks = subscribedCallbacksRef.current.get(objectType)
|
||||||
|
logger.debug(
|
||||||
|
`Calling ${callbacks.length} callbacks for type:`,
|
||||||
|
objectType
|
||||||
|
)
|
||||||
|
callbacks.forEach((callback) => {
|
||||||
|
try {
|
||||||
|
callback(data.object)
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error in object new callback:', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
`No callbacks found for object: ${objectType}, subscribed callbacks:`,
|
||||||
|
Array.from(subscribedCallbacksRef.current.keys())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const offObjectUpdatesEvent = useCallback((id, objectType, callback) => {
|
const offObjectUpdatesEvent = useCallback((id, objectType, callback) => {
|
||||||
if (socketRef.current && socketRef.current.connected == true) {
|
if (socketRef.current && socketRef.current.connected == true) {
|
||||||
const callbacksRefKey = `${objectType}:${id}`
|
const callbacksRefKey = `${objectType}:${id}`
|
||||||
@ -251,7 +309,10 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
.filter((cb) => cb !== callback)
|
.filter((cb) => cb !== callback)
|
||||||
if (callbacks.length === 0) {
|
if (callbacks.length === 0) {
|
||||||
subscribedCallbacksRef.current.delete(callbacksRefKey)
|
subscribedCallbacksRef.current.delete(callbacksRefKey)
|
||||||
socketRef.current.emit('unsubscribe', { id: id, type: objectType })
|
socketRef.current.emit('unsubscribeObjectUpdate', {
|
||||||
|
id: id,
|
||||||
|
objectType: objectType
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
subscribedCallbacksRef.current.set(callbacksRefKey, callbacks)
|
subscribedCallbacksRef.current.set(callbacksRefKey, callbacks)
|
||||||
}
|
}
|
||||||
@ -262,14 +323,22 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
const offObjectTypeUpdatesEvent = useCallback((objectType, callback) => {
|
const offObjectTypeUpdatesEvent = useCallback((objectType, callback) => {
|
||||||
if (socketRef.current && socketRef.current.connected == true) {
|
if (socketRef.current && socketRef.current.connected == true) {
|
||||||
// Remove callback from the subscribed callbacks map
|
// Remove callback from the subscribed callbacks map
|
||||||
console.log('Unsubscribing from type')
|
console.log(
|
||||||
|
'Unsubscribing from type',
|
||||||
|
objectType,
|
||||||
|
subscribedCallbacksRef.current.has(objectType)
|
||||||
|
)
|
||||||
if (subscribedCallbacksRef.current.has(objectType)) {
|
if (subscribedCallbacksRef.current.has(objectType)) {
|
||||||
const callbacks = subscribedCallbacksRef.current
|
const callbacks = subscribedCallbacksRef.current
|
||||||
.get(objectType)
|
.get(objectType)
|
||||||
.filter((cb) => cb !== callback)
|
.filter((cb) => cb !== callback)
|
||||||
|
console.log('API: CALLBACKS', callbacks)
|
||||||
|
|
||||||
if (callbacks.length === 0) {
|
if (callbacks.length === 0) {
|
||||||
subscribedCallbacksRef.current.delete(objectType)
|
subscribedCallbacksRef.current.delete(objectType)
|
||||||
socketRef.current.emit('unsubscribe', { objectType: objectType })
|
socketRef.current.emit('unsubscribeObjectTypeUpdate', {
|
||||||
|
objectType: objectType
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
subscribedCallbacksRef.current.set(objectType, callbacks)
|
subscribedCallbacksRef.current.set(objectType, callbacks)
|
||||||
}
|
}
|
||||||
@ -342,7 +411,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
logger.debug('Registered update event listener for object:', objectType)
|
logger.debug('Registered type event listener for object:', objectType)
|
||||||
|
|
||||||
// Return cleanup function
|
// Return cleanup function
|
||||||
return () => offObjectTypeUpdatesEvent(objectType, callback)
|
return () => offObjectTypeUpdatesEvent(objectType, callback)
|
||||||
@ -369,6 +438,84 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const offObjectEventEvent = useCallback(
|
||||||
|
(id, objectType, eventType, callback) => {
|
||||||
|
if (socketRef.current && socketRef.current.connected == true) {
|
||||||
|
const callbacksRefKey = `${objectType}:${id}:events:${eventType}`
|
||||||
|
// Remove callback from the subscribed callbacks map
|
||||||
|
if (subscribedCallbacksRef.current.has(callbacksRefKey)) {
|
||||||
|
const callbacks = subscribedCallbacksRef.current
|
||||||
|
.get(callbacksRefKey)
|
||||||
|
.filter((cb) => cb !== callback)
|
||||||
|
if (callbacks.length === 0) {
|
||||||
|
subscribedCallbacksRef.current.delete(callbacksRefKey)
|
||||||
|
socketRef.current.emit('unsubscribeObjectEvent', {
|
||||||
|
_id: id,
|
||||||
|
objectType,
|
||||||
|
eventType
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
subscribedCallbacksRef.current.set(callbacksRefKey, callbacks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
|
const subscribeToObjectEvent = useCallback(
|
||||||
|
(id, objectType, eventType, callback) => {
|
||||||
|
if (socketRef.current && socketRef.current.connected == true) {
|
||||||
|
const callbacksRefKey = `${objectType}:${id}:events:${eventType}`
|
||||||
|
// Add callback to the subscribed callbacks map immediately
|
||||||
|
if (!subscribedCallbacksRef.current.has(callbacksRefKey)) {
|
||||||
|
subscribedCallbacksRef.current.set(callbacksRefKey, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const callbacksLength =
|
||||||
|
subscribedCallbacksRef.current.get(callbacksRefKey).length
|
||||||
|
|
||||||
|
if (callbacksLength <= 0) {
|
||||||
|
socketRef.current.emit(
|
||||||
|
'subscribeToObjectEvent',
|
||||||
|
{
|
||||||
|
_id: id,
|
||||||
|
objectType: objectType,
|
||||||
|
eventType: eventType
|
||||||
|
},
|
||||||
|
(result) => {
|
||||||
|
if (result.success) {
|
||||||
|
logger.info(
|
||||||
|
'Subscribed to event id:',
|
||||||
|
id,
|
||||||
|
'objectType:',
|
||||||
|
objectType,
|
||||||
|
'eventType:',
|
||||||
|
eventType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
logger.info(
|
||||||
|
'Adding event callback id:',
|
||||||
|
id,
|
||||||
|
'objectType:',
|
||||||
|
objectType,
|
||||||
|
'eventType:',
|
||||||
|
eventType,
|
||||||
|
'callbacks length:',
|
||||||
|
callbacksLength + 1
|
||||||
|
)
|
||||||
|
subscribedCallbacksRef.current.get(callbacksRefKey).push(callback)
|
||||||
|
|
||||||
|
// Return cleanup function
|
||||||
|
return () => offObjectEventEvent(id, objectType, eventType, callback)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[offObjectUpdatesEvent]
|
||||||
|
)
|
||||||
|
|
||||||
const subscribeToObjectLock = useCallback(
|
const subscribeToObjectLock = useCallback(
|
||||||
(id, type, callback) => {
|
(id, type, callback) => {
|
||||||
logger.debug('Subscribing to lock for object:', id, 'type:', type)
|
logger.debug('Subscribing to lock for object:', id, 'type:', type)
|
||||||
@ -548,13 +695,6 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
logger.debug('Object updated successfully')
|
logger.debug('Object updated successfully')
|
||||||
if (socketRef.current && socketRef.current.connected == true) {
|
|
||||||
await socketRef.current.emit('update', {
|
|
||||||
_id: id,
|
|
||||||
type: type,
|
|
||||||
updatedAt: response.data.updatedAt
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return response.data
|
return response.data
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
@ -577,13 +717,6 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
logger.debug('Object deleted successfully')
|
logger.debug('Object deleted successfully')
|
||||||
if (socketRef.current && socketRef.current.connected == true) {
|
|
||||||
await socketRef.current.emit('update', {
|
|
||||||
_id: id,
|
|
||||||
type: type,
|
|
||||||
updatedAt: response.data.updatedAt
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return response.data
|
return response.data
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
@ -649,7 +782,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
try {
|
try {
|
||||||
const response = await axios.get(`${config.backendUrl}/notes`, {
|
const response = await axios.get(`${config.backendUrl}/notes`, {
|
||||||
params: {
|
params: {
|
||||||
parent: parentId,
|
'parent._id': parentId,
|
||||||
sort: 'createdAt',
|
sort: 'createdAt',
|
||||||
order: 'ascend'
|
order: 'ascend'
|
||||||
},
|
},
|
||||||
@ -755,6 +888,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
createObject,
|
createObject,
|
||||||
deleteObject,
|
deleteObject,
|
||||||
subscribeToObjectUpdates,
|
subscribeToObjectUpdates,
|
||||||
|
subscribeToObjectEvent,
|
||||||
subscribeToObjectTypeUpdates,
|
subscribeToObjectTypeUpdates,
|
||||||
subscribeToObjectLock,
|
subscribeToObjectLock,
|
||||||
fetchObject,
|
fetchObject,
|
||||||
|
|||||||
@ -30,13 +30,6 @@ export const Note = {
|
|||||||
type: 'dateTime',
|
type: 'dateTime',
|
||||||
readOnly: true
|
readOnly: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'noteType',
|
|
||||||
label: 'Note Type',
|
|
||||||
type: 'object',
|
|
||||||
objectType: 'noteType',
|
|
||||||
showHyperlink: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'parent._id',
|
name: 'parent._id',
|
||||||
label: 'Parent ID',
|
label: 'Parent ID',
|
||||||
@ -44,7 +37,23 @@ export const Note = {
|
|||||||
objectType: (objectData) => {
|
objectType: (objectData) => {
|
||||||
return objectData.parentType
|
return objectData.parentType
|
||||||
},
|
},
|
||||||
showHyperlink: true
|
showHyperlink: true,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'content',
|
||||||
|
label: 'Content',
|
||||||
|
type: 'markdown',
|
||||||
|
required: true,
|
||||||
|
span: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'noteType',
|
||||||
|
label: 'Note Type',
|
||||||
|
type: 'object',
|
||||||
|
objectType: 'noteType',
|
||||||
|
showHyperlink: true,
|
||||||
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'noteType._id',
|
name: 'noteType._id',
|
||||||
@ -58,11 +67,6 @@ export const Note = {
|
|||||||
type: 'id',
|
type: 'id',
|
||||||
objectType: 'user'
|
objectType: 'user'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'content',
|
|
||||||
label: 'Content',
|
|
||||||
type: 'markdown'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'updatedAt',
|
name: 'updatedAt',
|
||||||
label: 'Updated At',
|
label: 'Updated At',
|
||||||
|
|||||||
@ -143,6 +143,21 @@ export const Printer = {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
required: false,
|
required: false,
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'currentFilamentStock',
|
||||||
|
label: 'Filament Stock',
|
||||||
|
type: 'object',
|
||||||
|
objectType: 'filamentStock',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'currentFilamentStock._id',
|
||||||
|
label: 'Filament Stock ID',
|
||||||
|
type: 'id',
|
||||||
|
objectType: 'filamentStock',
|
||||||
|
showHyperlink: true,
|
||||||
|
readOnly: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import Settings from '../components/Dashboard/Management/Settings'
|
|||||||
import AuditLogs from '../components/Dashboard/Management/AuditLogs.jsx'
|
import AuditLogs from '../components/Dashboard/Management/AuditLogs.jsx'
|
||||||
import NoteTypes from '../components/Dashboard/Management/NoteTypes.jsx'
|
import NoteTypes from '../components/Dashboard/Management/NoteTypes.jsx'
|
||||||
import NoteTypeInfo from '../components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx'
|
import NoteTypeInfo from '../components/Dashboard/Management/NoteTypes/NoteTypeInfo.jsx'
|
||||||
|
import NoteInfo from '../components/Dashboard/Management/Notes/NoteInfo.jsx'
|
||||||
import Users from '../components/Dashboard/Management/Users.jsx'
|
import Users from '../components/Dashboard/Management/Users.jsx'
|
||||||
import UserInfo from '../components/Dashboard/Management/Users/UserInfo.jsx'
|
import UserInfo from '../components/Dashboard/Management/Users/UserInfo.jsx'
|
||||||
import Hosts from '../components/Dashboard/Management/Hosts.jsx'
|
import Hosts from '../components/Dashboard/Management/Hosts.jsx'
|
||||||
@ -68,6 +69,7 @@ const ManagementRoutes = [
|
|||||||
path='management/notetypes/info'
|
path='management/notetypes/info'
|
||||||
element={<NoteTypeInfo />}
|
element={<NoteTypeInfo />}
|
||||||
/>,
|
/>,
|
||||||
|
<Route key='note-info' path='management/notes/info' element={<NoteInfo />} />,
|
||||||
<Route
|
<Route
|
||||||
key='documentsizes'
|
key='documentsizes'
|
||||||
path='management/documentsizes'
|
path='management/documentsizes'
|
||||||
|
|||||||
364
yarn.lock
364
yarn.lock
@ -724,7 +724,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.27.1"
|
"@babel/helper-plugin-utils" "^7.27.1"
|
||||||
|
|
||||||
"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.1", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.6", "@babel/runtime@^7.25.7", "@babel/runtime@^7.26.0":
|
"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.1", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.6", "@babel/runtime@^7.25.7", "@babel/runtime@^7.26.0":
|
||||||
version "7.28.3"
|
version "7.28.3"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.3.tgz#75c5034b55ba868121668be5d5bb31cc64e6e61a"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.3.tgz#75c5034b55ba868121668be5d5bb31cc64e6e61a"
|
||||||
integrity sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==
|
integrity sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==
|
||||||
@ -759,33 +759,6 @@
|
|||||||
"@babel/helper-string-parser" "^7.27.1"
|
"@babel/helper-string-parser" "^7.27.1"
|
||||||
"@babel/helper-validator-identifier" "^7.27.1"
|
"@babel/helper-validator-identifier" "^7.27.1"
|
||||||
|
|
||||||
"@chevrotain/cst-dts-gen@10.5.0":
|
|
||||||
version "10.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.5.0.tgz#922ebd8cc59d97241bb01b1b17561a5c1ae0124e"
|
|
||||||
integrity sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==
|
|
||||||
dependencies:
|
|
||||||
"@chevrotain/gast" "10.5.0"
|
|
||||||
"@chevrotain/types" "10.5.0"
|
|
||||||
lodash "4.17.21"
|
|
||||||
|
|
||||||
"@chevrotain/gast@10.5.0":
|
|
||||||
version "10.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@chevrotain/gast/-/gast-10.5.0.tgz#e4e614bc46d17a8892742f38e56cd33f1f3ad162"
|
|
||||||
integrity sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==
|
|
||||||
dependencies:
|
|
||||||
"@chevrotain/types" "10.5.0"
|
|
||||||
lodash "4.17.21"
|
|
||||||
|
|
||||||
"@chevrotain/types@10.5.0":
|
|
||||||
version "10.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-10.5.0.tgz#52a97d74a8cfbc197f054636d93ecd8912d33d21"
|
|
||||||
integrity sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==
|
|
||||||
|
|
||||||
"@chevrotain/utils@10.5.0":
|
|
||||||
version "10.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-10.5.0.tgz#0ee36f65b49b447fbac71b9e5af5c5c6c98ac057"
|
|
||||||
integrity sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==
|
|
||||||
|
|
||||||
"@codemirror/autocomplete@^6.0.0", "@codemirror/autocomplete@^6.3.2", "@codemirror/autocomplete@^6.7.1":
|
"@codemirror/autocomplete@^6.0.0", "@codemirror/autocomplete@^6.3.2", "@codemirror/autocomplete@^6.7.1":
|
||||||
version "6.18.6"
|
version "6.18.6"
|
||||||
resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz#de26e864a1ec8192a1b241eb86addbb612964ddb"
|
resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz#de26e864a1ec8192a1b241eb86addbb612964ddb"
|
||||||
@ -1918,27 +1891,10 @@
|
|||||||
rc-resize-observer "^1.3.1"
|
rc-resize-observer "^1.3.1"
|
||||||
rc-util "^5.44.0"
|
rc-util "^5.44.0"
|
||||||
|
|
||||||
"@react-three/fiber@^8.15.5":
|
"@rolldown/pluginutils@1.0.0-beta.34":
|
||||||
version "8.18.0"
|
version "1.0.0-beta.34"
|
||||||
resolved "https://registry.yarnpkg.com/@react-three/fiber/-/fiber-8.18.0.tgz#73bfa12c82dabf889b572f9dfeefb10485532dd1"
|
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz#4421645c676926faa4574940d72fa7ce0ec7d419"
|
||||||
integrity sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==
|
integrity sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.17.8"
|
|
||||||
"@types/react-reconciler" "^0.26.7"
|
|
||||||
"@types/webxr" "*"
|
|
||||||
base64-js "^1.5.1"
|
|
||||||
buffer "^6.0.3"
|
|
||||||
its-fine "^1.0.6"
|
|
||||||
react-reconciler "^0.27.0"
|
|
||||||
react-use-measure "^2.1.7"
|
|
||||||
scheduler "^0.21.0"
|
|
||||||
suspend-react "^0.1.3"
|
|
||||||
zustand "^3.7.1"
|
|
||||||
|
|
||||||
"@rolldown/pluginutils@1.0.0-beta.32":
|
|
||||||
version "1.0.0-beta.32"
|
|
||||||
resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.32.tgz#40a51db68a3c967183a9d58c5f5179adf6214cce"
|
|
||||||
integrity sha512-QReCdvxiUZAPkvp1xpAg62IeNzykOFA6syH2CnClif4YmALN1XKpB39XneL80008UbtMShthSVDKmrx05N1q/g==
|
|
||||||
|
|
||||||
"@rollup/pluginutils@^4.2.1":
|
"@rollup/pluginutils@^4.2.1":
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
@ -1948,7 +1904,7 @@
|
|||||||
estree-walker "^2.0.1"
|
estree-walker "^2.0.1"
|
||||||
picomatch "^2.2.2"
|
picomatch "^2.2.2"
|
||||||
|
|
||||||
"@rollup/pluginutils@^5.1.3":
|
"@rollup/pluginutils@^5.2.0":
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.2.0.tgz#eac25ca5b0bdda4ba735ddaca5fbf26bd435f602"
|
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.2.0.tgz#eac25ca5b0bdda4ba735ddaca5fbf26bd435f602"
|
||||||
integrity sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==
|
integrity sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==
|
||||||
@ -2792,11 +2748,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types "~6.21.0"
|
undici-types "~6.21.0"
|
||||||
|
|
||||||
"@types/offscreencanvas@^2019.6.4":
|
|
||||||
version "2019.7.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz#90267db13f64d6e9ccb5ae3eac92786a7c77a516"
|
|
||||||
integrity sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==
|
|
||||||
|
|
||||||
"@types/parse-json@^4.0.0":
|
"@types/parse-json@^4.0.0":
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
|
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
|
||||||
@ -2810,25 +2761,6 @@
|
|||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
xmlbuilder ">=11.0.1"
|
xmlbuilder ">=11.0.1"
|
||||||
|
|
||||||
"@types/react-reconciler@^0.26.7":
|
|
||||||
version "0.26.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.26.7.tgz#0c4643f30821ae057e401b0d9037e03e8e9b2a36"
|
|
||||||
integrity sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==
|
|
||||||
dependencies:
|
|
||||||
"@types/react" "*"
|
|
||||||
|
|
||||||
"@types/react-reconciler@^0.28.0":
|
|
||||||
version "0.28.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.28.9.tgz#d24b4864c384e770c83275b3fe73fba00269c83b"
|
|
||||||
integrity sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==
|
|
||||||
|
|
||||||
"@types/react@*":
|
|
||||||
version "19.1.11"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.11.tgz#a64d8ec1769fc861d22f54e6e9f360ed67b54dc8"
|
|
||||||
integrity sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==
|
|
||||||
dependencies:
|
|
||||||
csstype "^3.0.2"
|
|
||||||
|
|
||||||
"@types/responselike@^1.0.0":
|
"@types/responselike@^1.0.0":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
|
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
|
||||||
@ -2856,11 +2788,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.11.tgz#d3d6b418978c8aa202d41e5bb3483227b6ecc1bb"
|
resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.11.tgz#d3d6b418978c8aa202d41e5bb3483227b6ecc1bb"
|
||||||
integrity sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==
|
integrity sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==
|
||||||
|
|
||||||
"@types/webxr@*":
|
|
||||||
version "0.5.22"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.22.tgz#d8a14c12bbfaaa4a13de21ec2d4a8197b3e1b532"
|
|
||||||
integrity sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==
|
|
||||||
|
|
||||||
"@types/yauzl@^2.9.1":
|
"@types/yauzl@^2.9.1":
|
||||||
version "2.10.3"
|
version "2.10.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999"
|
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999"
|
||||||
@ -2944,23 +2871,18 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8"
|
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8"
|
||||||
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
|
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
|
||||||
|
|
||||||
"@vitejs/plugin-react@^5.0.1":
|
"@vitejs/plugin-react@^5.0.2":
|
||||||
version "5.0.1"
|
version "5.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.0.1.tgz#02c074f3fd9a82e4676c51e0fe9603a26ca614a3"
|
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.0.2.tgz#3b5d73fc0e4370a0fafe27154d2c208e2bca8f71"
|
||||||
integrity sha512-DE4UNaBXwtVoDJ0ccBdLVjFTWL70NRuWNCxEieTI3lrq9ORB9aOCQEKstwDXBl87NvFdbqh/p7eINGyj0BthJA==
|
integrity sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/core" "^7.28.3"
|
"@babel/core" "^7.28.3"
|
||||||
"@babel/plugin-transform-react-jsx-self" "^7.27.1"
|
"@babel/plugin-transform-react-jsx-self" "^7.27.1"
|
||||||
"@babel/plugin-transform-react-jsx-source" "^7.27.1"
|
"@babel/plugin-transform-react-jsx-source" "^7.27.1"
|
||||||
"@rolldown/pluginutils" "1.0.0-beta.32"
|
"@rolldown/pluginutils" "1.0.0-beta.34"
|
||||||
"@types/babel__core" "^7.20.5"
|
"@types/babel__core" "^7.20.5"
|
||||||
react-refresh "^0.17.0"
|
react-refresh "^0.17.0"
|
||||||
|
|
||||||
"@webgpu/glslang@^0.0.15":
|
|
||||||
version "0.0.15"
|
|
||||||
resolved "https://registry.yarnpkg.com/@webgpu/glslang/-/glslang-0.0.15.tgz#f5ccaf6015241e6175f4b90906b053f88483d1f2"
|
|
||||||
integrity sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==
|
|
||||||
|
|
||||||
"@xmldom/xmldom@^0.8.8":
|
"@xmldom/xmldom@^0.8.8":
|
||||||
version "0.8.11"
|
version "0.8.11"
|
||||||
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608"
|
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608"
|
||||||
@ -3112,7 +3034,7 @@ antd-style@^3.7.1:
|
|||||||
"@emotion/utils" "^1.2.1"
|
"@emotion/utils" "^1.2.1"
|
||||||
use-merge-value "^1.2.0"
|
use-merge-value "^1.2.0"
|
||||||
|
|
||||||
antd@^5.27.0:
|
antd@^5.27.1:
|
||||||
version "5.27.1"
|
version "5.27.1"
|
||||||
resolved "https://registry.yarnpkg.com/antd/-/antd-5.27.1.tgz#5378fc017cb4057ffefe2a670f20e54b924d897d"
|
resolved "https://registry.yarnpkg.com/antd/-/antd-5.27.1.tgz#5378fc017cb4057ffefe2a670f20e54b924d897d"
|
||||||
integrity sha512-jGMSdBN7hAMvPV27B4RhzZfL6n6yu8yDbo7oXrlJasaOqB7bSDPcjdEy1kXy3JPsny/Qazb1ykzRI4EfcByAPQ==
|
integrity sha512-jGMSdBN7hAMvPV27B4RhzZfL6n6yu8yDbo7oXrlJasaOqB7bSDPcjdEy1kXy3JPsny/Qazb1ykzRI4EfcByAPQ==
|
||||||
@ -3515,14 +3437,6 @@ buffer@^5.1.0, buffer@^5.5.0:
|
|||||||
base64-js "^1.3.1"
|
base64-js "^1.3.1"
|
||||||
ieee754 "^1.1.13"
|
ieee754 "^1.1.13"
|
||||||
|
|
||||||
buffer@^6.0.3:
|
|
||||||
version "6.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
|
|
||||||
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
|
|
||||||
dependencies:
|
|
||||||
base64-js "^1.3.1"
|
|
||||||
ieee754 "^1.2.1"
|
|
||||||
|
|
||||||
builder-util-runtime@9.3.1:
|
builder-util-runtime@9.3.1:
|
||||||
version "9.3.1"
|
version "9.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
|
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
|
||||||
@ -3676,6 +3590,14 @@ chalk-template@0.4.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
chalk "^4.1.2"
|
chalk "^4.1.2"
|
||||||
|
|
||||||
|
chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
||||||
|
version "4.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||||
|
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||||
|
dependencies:
|
||||||
|
ansi-styles "^4.1.0"
|
||||||
|
supports-color "^7.1.0"
|
||||||
|
|
||||||
chalk@5.0.1:
|
chalk@5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6"
|
||||||
@ -3692,14 +3614,6 @@ chalk@^1.1.3:
|
|||||||
strip-ansi "^3.0.0"
|
strip-ansi "^3.0.0"
|
||||||
supports-color "^2.0.0"
|
supports-color "^2.0.0"
|
||||||
|
|
||||||
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
|
|
||||||
version "4.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
|
||||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^4.1.0"
|
|
||||||
supports-color "^7.1.0"
|
|
||||||
|
|
||||||
chalk@^5.0.1:
|
chalk@^5.0.1:
|
||||||
version "5.6.0"
|
version "5.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.0.tgz#a1a8d294ea3526dbb77660f12649a08490e33ab8"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.0.tgz#a1a8d294ea3526dbb77660f12649a08490e33ab8"
|
||||||
@ -3725,18 +3639,6 @@ character-reference-invalid@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9"
|
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9"
|
||||||
integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==
|
integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==
|
||||||
|
|
||||||
chevrotain@^10.1.2:
|
|
||||||
version "10.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-10.5.0.tgz#9c1dc62ef0753bb562dbe521b5f72d041bad624e"
|
|
||||||
integrity sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==
|
|
||||||
dependencies:
|
|
||||||
"@chevrotain/cst-dts-gen" "10.5.0"
|
|
||||||
"@chevrotain/gast" "10.5.0"
|
|
||||||
"@chevrotain/types" "10.5.0"
|
|
||||||
"@chevrotain/utils" "10.5.0"
|
|
||||||
lodash "4.17.21"
|
|
||||||
regexp-to-ast "0.5.0"
|
|
||||||
|
|
||||||
chownr@^2.0.0:
|
chownr@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
|
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
|
||||||
@ -3922,18 +3824,17 @@ concat-map@0.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||||
|
|
||||||
concurrently@^9.2.0:
|
concurrently@^9.2.1:
|
||||||
version "9.2.0"
|
version "9.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.2.0.tgz#233e3892ceb0b5db9fd49e9c8c739737a7b638b5"
|
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.2.1.tgz#248ea21b95754947be2dad9c3e4b60f18ca4e44f"
|
||||||
integrity sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==
|
integrity sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk "^4.1.2"
|
chalk "4.1.2"
|
||||||
lodash "^4.17.21"
|
rxjs "7.8.2"
|
||||||
rxjs "^7.8.1"
|
shell-quote "1.8.3"
|
||||||
shell-quote "^1.8.1"
|
supports-color "8.1.1"
|
||||||
supports-color "^8.1.1"
|
tree-kill "1.2.2"
|
||||||
tree-kill "^1.2.2"
|
yargs "17.7.2"
|
||||||
yargs "^17.7.2"
|
|
||||||
|
|
||||||
config-file-ts@0.2.8-rc1:
|
config-file-ts@0.2.8-rc1:
|
||||||
version "0.2.8-rc1"
|
version "0.2.8-rc1"
|
||||||
@ -4018,7 +3919,7 @@ cosmiconfig@^8.1.3:
|
|||||||
parse-json "^5.2.0"
|
parse-json "^5.2.0"
|
||||||
path-type "^4.0.0"
|
path-type "^4.0.0"
|
||||||
|
|
||||||
country-list@^2.3.0:
|
country-list@^2.4.1:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/country-list/-/country-list-2.4.1.tgz#468b60a91004533133352a629de07a3a9d459899"
|
resolved "https://registry.yarnpkg.com/country-list/-/country-list-2.4.1.tgz#468b60a91004533133352a629de07a3a9d459899"
|
||||||
integrity sha512-KhVV/UfUV3dSNpsWIqHTQxLpYDKPKz1UwkRjadt+YbX2PRhyCEihEoS5XgB7J7AMXpkicvl+tRHvkNI5wbji/g==
|
integrity sha512-KhVV/UfUV3dSNpsWIqHTQxLpYDKPKz1UwkRjadt+YbX2PRhyCEihEoS5XgB7J7AMXpkicvl+tRHvkNI5wbji/g==
|
||||||
@ -4333,11 +4234,16 @@ data-view-byte-offset@^1.0.1:
|
|||||||
es-errors "^1.3.0"
|
es-errors "^1.3.0"
|
||||||
is-data-view "^1.0.1"
|
is-data-view "^1.0.1"
|
||||||
|
|
||||||
dayjs@^1.11.11, dayjs@^1.11.13:
|
dayjs@^1.11.11:
|
||||||
version "1.11.13"
|
version "1.11.13"
|
||||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
|
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
|
||||||
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
|
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
|
||||||
|
|
||||||
|
dayjs@^1.11.18:
|
||||||
|
version "1.11.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.18.tgz#835fa712aac52ab9dec8b1494098774ed7070a11"
|
||||||
|
integrity sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==
|
||||||
|
|
||||||
debug@2.6.9, debug@^2.2.0:
|
debug@2.6.9, debug@^2.2.0:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
@ -4577,11 +4483,6 @@ dotenv@^17.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.2.1.tgz#6f32e10faf014883515538dc922a0fb8765d9b32"
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.2.1.tgz#6f32e10faf014883515538dc922a0fb8765d9b32"
|
||||||
integrity sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==
|
integrity sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==
|
||||||
|
|
||||||
draco3d@^1.4.1:
|
|
||||||
version "1.5.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/draco3d/-/draco3d-1.5.7.tgz#94f9bce293eb8920c159dc91a4ce9124a9e899e0"
|
|
||||||
integrity sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==
|
|
||||||
|
|
||||||
dunder-proto@^1.0.0, dunder-proto@^1.0.1:
|
dunder-proto@^1.0.0, dunder-proto@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
|
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
|
||||||
@ -4668,10 +4569,10 @@ electron-to-chromium@^1.5.204:
|
|||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.208.tgz#609c29502fd7257b4d721e3446f3ae391a0ca1b3"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.208.tgz#609c29502fd7257b4d721e3446f3ae391a0ca1b3"
|
||||||
integrity sha512-ozZyibehoe7tOhNaf16lKmljVf+3npZcJIEbJRVftVsmAg5TeA1mGS9dVCZzOwr2xT7xK15V0p7+GZqSPgkuPg==
|
integrity sha512-ozZyibehoe7tOhNaf16lKmljVf+3npZcJIEbJRVftVsmAg5TeA1mGS9dVCZzOwr2xT7xK15V0p7+GZqSPgkuPg==
|
||||||
|
|
||||||
electron@^37.2.6:
|
electron@^37.4.0:
|
||||||
version "37.3.1"
|
version "37.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-37.3.1.tgz#92d0299593c4302dcdf3305af917c60dad69719f"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-37.4.0.tgz#08b2eff9d6250fac7b298f17f93946ecd586f38e"
|
||||||
integrity sha512-7DhktRLqhe6OJh/Bo75bTI0puUYEmIwSzMinocgO63mx3MVjtIn2tYMzLmAleNIlud2htkjpsMG2zT4PiTCloA==
|
integrity sha512-HhsSdWowE5ODOeWNc/323Ug2C52mq/TqNBG+4uMeOA3G2dMXNc/nfyi0RYu1rJEgiaJLEjtHveeZZaYRYFsFCQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^2.0.0"
|
"@electron/get" "^2.0.0"
|
||||||
"@types/node" "^22.7.7"
|
"@types/node" "^22.7.7"
|
||||||
@ -5150,7 +5051,7 @@ eslint@^8.41.0, eslint@^8.57.1:
|
|||||||
strip-ansi "^6.0.1"
|
strip-ansi "^6.0.1"
|
||||||
text-table "^0.2.0"
|
text-table "^0.2.0"
|
||||||
|
|
||||||
eslint@^9.33.0:
|
eslint@^9.34.0:
|
||||||
version "9.34.0"
|
version "9.34.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.34.0.tgz#0ea1f2c1b5d1671db8f01aa6b8ce722302016f7b"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.34.0.tgz#0ea1f2c1b5d1671db8f01aa6b8ce722302016f7b"
|
||||||
integrity sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==
|
integrity sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==
|
||||||
@ -5382,11 +5283,6 @@ fecha@^4.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd"
|
resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd"
|
||||||
integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==
|
integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==
|
||||||
|
|
||||||
fflate@^0.6.9:
|
|
||||||
version "0.6.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.6.10.tgz#5f40f9659205936a2d18abf88b2e7781662b6d43"
|
|
||||||
integrity sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==
|
|
||||||
|
|
||||||
file-entry-cache@^6.0.1:
|
file-entry-cache@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
||||||
@ -6035,7 +5931,7 @@ iconv-lite@0.6, iconv-lite@0.6.3, iconv-lite@^0.6.2, iconv-lite@^0.6.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||||
|
|
||||||
ieee754@^1.1.13, ieee754@^1.2.1:
|
ieee754@^1.1.13:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||||
@ -6431,13 +6327,6 @@ iterator.prototype@^1.1.4:
|
|||||||
has-symbols "^1.1.0"
|
has-symbols "^1.1.0"
|
||||||
set-function-name "^2.0.2"
|
set-function-name "^2.0.2"
|
||||||
|
|
||||||
its-fine@^1.0.6:
|
|
||||||
version "1.2.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-1.2.5.tgz#5466c287f86a0a73e772c8d8d515626c97195dc9"
|
|
||||||
integrity sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==
|
|
||||||
dependencies:
|
|
||||||
"@types/react-reconciler" "^0.28.0"
|
|
||||||
|
|
||||||
jackspeak@^3.1.2:
|
jackspeak@^3.1.2:
|
||||||
version "3.4.3"
|
version "3.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
|
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
|
||||||
@ -6570,11 +6459,6 @@ keyv@^4.0.0, keyv@^4.5.3, keyv@^4.5.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
json-buffer "3.0.1"
|
json-buffer "3.0.1"
|
||||||
|
|
||||||
ktx-parse@^0.4.5:
|
|
||||||
version "0.4.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/ktx-parse/-/ktx-parse-0.4.5.tgz#79905e22281a9d3e602b2ff522df1ee7d1813aa6"
|
|
||||||
integrity sha512-MK3FOody4TXbFf8Yqv7EBbySw7aPvEcPX++Ipt6Sox+/YMFvR5xaTyhfNSk1AEmMy+RYIw81ctN4IMxCB8OAlg==
|
|
||||||
|
|
||||||
lazy-val@^1.0.5:
|
lazy-val@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.5.tgz#6cf3b9f5bc31cee7ee3e369c0832b7583dcd923d"
|
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.5.tgz#6cf3b9f5bc31cee7ee3e369c0832b7583dcd923d"
|
||||||
@ -6652,7 +6536,7 @@ lodash.merge@^4.6.2:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||||
|
|
||||||
lodash@4.17.21, lodash@^4.17.15, lodash@^4.17.21:
|
lodash@^4.17.15, lodash@^4.17.21:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
@ -6683,7 +6567,7 @@ longest-streak@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
|
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
|
||||||
integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
|
integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==
|
||||||
|
|
||||||
loose-envify@^1.1.0, loose-envify@^1.4.0:
|
loose-envify@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
@ -7464,11 +7348,6 @@ ml-matrix@^6.10.4:
|
|||||||
is-any-array "^2.0.1"
|
is-any-array "^2.0.1"
|
||||||
ml-array-rescale "^1.3.7"
|
ml-array-rescale "^1.3.7"
|
||||||
|
|
||||||
mmd-parser@^1.0.4:
|
|
||||||
version "1.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/mmd-parser/-/mmd-parser-1.0.4.tgz#87cc05782cb5974ca854f0303fc5147bc9d690e7"
|
|
||||||
integrity sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==
|
|
||||||
|
|
||||||
moment@^2.30.1:
|
moment@^2.30.1:
|
||||||
version "2.30.1"
|
version "2.30.1"
|
||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
|
||||||
@ -7669,14 +7548,6 @@ onetime@^5.1.0, onetime@^5.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn "^2.1.0"
|
mimic-fn "^2.1.0"
|
||||||
|
|
||||||
opentype.js@^1.3.3:
|
|
||||||
version "1.3.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/opentype.js/-/opentype.js-1.3.4.tgz#1c0e72e46288473cc4a4c6a2dc60fd7fe6020d77"
|
|
||||||
integrity sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==
|
|
||||||
dependencies:
|
|
||||||
string.prototype.codepointat "^0.2.1"
|
|
||||||
tiny-inflate "^1.0.3"
|
|
||||||
|
|
||||||
optionator@^0.9.3:
|
optionator@^0.9.3:
|
||||||
version "0.9.4"
|
version "0.9.4"
|
||||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734"
|
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734"
|
||||||
@ -7984,11 +7855,6 @@ postcss@^8.5.6:
|
|||||||
picocolors "^1.1.1"
|
picocolors "^1.1.1"
|
||||||
source-map-js "^1.2.1"
|
source-map-js "^1.2.1"
|
||||||
|
|
||||||
potpack@^1.0.1:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14"
|
|
||||||
integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==
|
|
||||||
|
|
||||||
prelude-ls@^1.2.1:
|
prelude-ls@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||||
@ -8518,13 +8384,12 @@ react-country-flag@^3.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-country-flag/-/react-country-flag-3.1.0.tgz#f0c4c332934a77d3e894ba4800634f7a887e53d4"
|
resolved "https://registry.yarnpkg.com/react-country-flag/-/react-country-flag-3.1.0.tgz#f0c4c332934a77d3e894ba4800634f7a887e53d4"
|
||||||
integrity sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g==
|
integrity sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g==
|
||||||
|
|
||||||
react-dom@^18.2.0:
|
react-dom@^19.1.1:
|
||||||
version "18.3.1"
|
version "19.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.1.tgz#2daa9ff7f3ae384aeb30e76d5ee38c046dc89893"
|
||||||
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify "^1.1.0"
|
scheduler "^0.26.0"
|
||||||
scheduler "^0.23.2"
|
|
||||||
|
|
||||||
react-is@^16.13.1, react-is@^16.7.0:
|
react-is@^16.13.1, react-is@^16.7.0:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
@ -8553,14 +8418,6 @@ react-markdown@^10.1.0:
|
|||||||
unist-util-visit "^5.0.0"
|
unist-util-visit "^5.0.0"
|
||||||
vfile "^6.0.0"
|
vfile "^6.0.0"
|
||||||
|
|
||||||
react-reconciler@^0.27.0:
|
|
||||||
version "0.27.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.27.0.tgz#360124fdf2d76447c7491ee5f0e04503ed9acf5b"
|
|
||||||
integrity sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
scheduler "^0.21.0"
|
|
||||||
|
|
||||||
react-refresh@^0.17.0:
|
react-refresh@^0.17.0:
|
||||||
version "0.17.0"
|
version "0.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53"
|
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53"
|
||||||
@ -8576,7 +8433,7 @@ react-responsive@^10.0.1:
|
|||||||
prop-types "^15.6.1"
|
prop-types "^15.6.1"
|
||||||
shallow-equal "^3.1.0"
|
shallow-equal "^3.1.0"
|
||||||
|
|
||||||
react-router-dom@^7.8.0:
|
react-router-dom@^7.8.2:
|
||||||
version "7.8.2"
|
version "7.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.8.2.tgz#25a8fc36588189baf3bbb5e360c8ffffbd2beabc"
|
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.8.2.tgz#25a8fc36588189baf3bbb5e360c8ffffbd2beabc"
|
||||||
integrity sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==
|
integrity sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==
|
||||||
@ -8591,25 +8448,10 @@ react-router@7.8.2:
|
|||||||
cookie "^1.0.1"
|
cookie "^1.0.1"
|
||||||
set-cookie-parser "^2.6.0"
|
set-cookie-parser "^2.6.0"
|
||||||
|
|
||||||
react-stl-viewer@^2.5.0:
|
react@^19.1.1:
|
||||||
version "2.5.0"
|
version "19.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-stl-viewer/-/react-stl-viewer-2.5.0.tgz#c6478b5926b8a3cd2bd366101483818d891f04c9"
|
resolved "https://registry.yarnpkg.com/react/-/react-19.1.1.tgz#06d9149ec5e083a67f9a1e39ce97b06a03b644af"
|
||||||
integrity sha512-jlYId05N0P9rKVEdOfLO1bPsS9SYfMRxjnKvhks6T/c4HU0BxnNcZpRr4gfpJU0nFL6HHgmVKhKTh1LCHNcZuA==
|
integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==
|
||||||
dependencies:
|
|
||||||
"@react-three/fiber" "^8.15.5"
|
|
||||||
three-stdlib "2.17.2"
|
|
||||||
|
|
||||||
react-use-measure@^2.1.7:
|
|
||||||
version "2.1.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-use-measure/-/react-use-measure-2.1.7.tgz#36b8a2e7fd2fa58109ab851b3addcb0aad66ad1d"
|
|
||||||
integrity sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==
|
|
||||||
|
|
||||||
react@^18.2.0:
|
|
||||||
version "18.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
|
||||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
|
|
||||||
read-binary-file-arch@^1.0.6:
|
read-binary-file-arch@^1.0.6:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
@ -8658,11 +8500,6 @@ reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9:
|
|||||||
get-proto "^1.0.1"
|
get-proto "^1.0.1"
|
||||||
which-builtin-type "^1.2.1"
|
which-builtin-type "^1.2.1"
|
||||||
|
|
||||||
regexp-to-ast@0.5.0:
|
|
||||||
version "0.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz#56c73856bee5e1fef7f73a00f1473452ab712a24"
|
|
||||||
integrity sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==
|
|
||||||
|
|
||||||
regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4:
|
regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4:
|
||||||
version "1.5.4"
|
version "1.5.4"
|
||||||
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19"
|
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19"
|
||||||
@ -8895,7 +8732,7 @@ rw@1:
|
|||||||
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
|
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
|
||||||
integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
|
integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
|
||||||
|
|
||||||
rxjs@^7.8.1:
|
rxjs@7.8.2:
|
||||||
version "7.8.2"
|
version "7.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b"
|
||||||
integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==
|
integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==
|
||||||
@ -8957,19 +8794,10 @@ sax@^1.2.4, sax@^1.4.1:
|
|||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
|
||||||
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
|
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
|
||||||
|
|
||||||
scheduler@^0.21.0:
|
scheduler@^0.26.0:
|
||||||
version "0.21.0"
|
version "0.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0.tgz#6fd2532ff5a6d877b6edb12f00d8ab7e8f308820"
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337"
|
||||||
integrity sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==
|
integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
|
|
||||||
scheduler@^0.23.2:
|
|
||||||
version "0.23.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
|
|
||||||
integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
|
|
||||||
scroll-into-view-if-needed@^3.1.0:
|
scroll-into-view-if-needed@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
@ -9125,7 +8953,7 @@ shebang-regex@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||||
|
|
||||||
shell-quote@^1.8.1:
|
shell-quote@1.8.3:
|
||||||
version "1.8.3"
|
version "1.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.3.tgz#55e40ef33cf5c689902353a3d8cd1a6725f08b4b"
|
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.3.tgz#55e40ef33cf5c689902353a3d8cd1a6725f08b4b"
|
||||||
integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==
|
integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==
|
||||||
@ -9402,11 +9230,6 @@ string-width@^5.0.1, string-width@^5.1.2:
|
|||||||
emoji-regex "^9.2.2"
|
emoji-regex "^9.2.2"
|
||||||
strip-ansi "^7.0.1"
|
strip-ansi "^7.0.1"
|
||||||
|
|
||||||
string.prototype.codepointat@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc"
|
|
||||||
integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==
|
|
||||||
|
|
||||||
string.prototype.matchall@^4.0.12:
|
string.prototype.matchall@^4.0.12:
|
||||||
version "4.0.12"
|
version "4.0.12"
|
||||||
resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0"
|
resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0"
|
||||||
@ -9592,6 +9415,13 @@ sumchecker@^3.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
|
|
||||||
|
supports-color@8.1.1:
|
||||||
|
version "8.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
|
||||||
|
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
|
||||||
|
dependencies:
|
||||||
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
supports-color@^2.0.0:
|
supports-color@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||||
@ -9604,23 +9434,11 @@ supports-color@^7.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^4.0.0"
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
supports-color@^8.1.1:
|
|
||||||
version "8.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
|
|
||||||
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
|
|
||||||
dependencies:
|
|
||||||
has-flag "^4.0.0"
|
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@^1.0.0:
|
supports-preserve-symlinks-flag@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||||
|
|
||||||
suspend-react@^0.1.3:
|
|
||||||
version "0.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/suspend-react/-/suspend-react-0.1.3.tgz#a52f49d21cfae9a2fb70bd0c68413d3f9d90768e"
|
|
||||||
integrity sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==
|
|
||||||
|
|
||||||
svg-parser@^2.0.4:
|
svg-parser@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5"
|
resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5"
|
||||||
@ -9696,23 +9514,6 @@ text-table@^0.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
||||||
|
|
||||||
three-stdlib@2.17.2:
|
|
||||||
version "2.17.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/three-stdlib/-/three-stdlib-2.17.2.tgz#9c2a2914a16123853531612dac8870e6e242685b"
|
|
||||||
integrity sha512-7ZLCJJogtn1D1MlUi7q0iLUbrxj7K++YxjHIIz5AZ4wX4E137BgiiTmhH4XhAuvXGRk9ph3ZtoHTfJBXhqDX3w==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.16.7"
|
|
||||||
"@types/offscreencanvas" "^2019.6.4"
|
|
||||||
"@webgpu/glslang" "^0.0.15"
|
|
||||||
chevrotain "^10.1.2"
|
|
||||||
draco3d "^1.4.1"
|
|
||||||
fflate "^0.6.9"
|
|
||||||
ktx-parse "^0.4.5"
|
|
||||||
mmd-parser "^1.0.4"
|
|
||||||
opentype.js "^1.3.3"
|
|
||||||
potpack "^1.0.1"
|
|
||||||
zstddec "^0.0.2"
|
|
||||||
|
|
||||||
three@^0.159.0:
|
three@^0.159.0:
|
||||||
version "0.159.0"
|
version "0.159.0"
|
||||||
resolved "https://registry.yarnpkg.com/three/-/three-0.159.0.tgz#6576b1210805b14f0765bac41fd0e4ec18e43b2e"
|
resolved "https://registry.yarnpkg.com/three/-/three-0.159.0.tgz#6576b1210805b14f0765bac41fd0e4ec18e43b2e"
|
||||||
@ -9735,11 +9536,6 @@ tiny-async-pool@1.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
semver "^5.5.0"
|
semver "^5.5.0"
|
||||||
|
|
||||||
tiny-inflate@^1.0.3:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4"
|
|
||||||
integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==
|
|
||||||
|
|
||||||
tinyglobby@^0.2.14:
|
tinyglobby@^0.2.14:
|
||||||
version "0.2.14"
|
version "0.2.14"
|
||||||
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d"
|
||||||
@ -9777,7 +9573,7 @@ toidentifier@1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||||
|
|
||||||
tree-kill@^1.2.2:
|
tree-kill@1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
|
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
|
||||||
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
|
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
|
||||||
@ -10133,12 +9929,12 @@ vite-plugin-svgo@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
svgo "3.3.2"
|
svgo "3.3.2"
|
||||||
|
|
||||||
vite-plugin-svgr@^4.3.0:
|
vite-plugin-svgr@^4.5.0:
|
||||||
version "4.3.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-4.3.0.tgz#742f16f11375996306c696ec323e4d23f6005075"
|
resolved "https://registry.yarnpkg.com/vite-plugin-svgr/-/vite-plugin-svgr-4.5.0.tgz#253e4c703d1f0b30935c285ca8621f4857952338"
|
||||||
integrity sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==
|
integrity sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@rollup/pluginutils" "^5.1.3"
|
"@rollup/pluginutils" "^5.2.0"
|
||||||
"@svgr/core" "^8.1.0"
|
"@svgr/core" "^8.1.0"
|
||||||
"@svgr/plugin-jsx" "^8.1.0"
|
"@svgr/plugin-jsx" "^8.1.0"
|
||||||
|
|
||||||
@ -10335,7 +10131,7 @@ yargs-parser@^21.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
|
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
|
||||||
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
|
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
|
||||||
|
|
||||||
yargs@^17.0.1, yargs@^17.6.2, yargs@^17.7.2:
|
yargs@17.7.2, yargs@^17.0.1, yargs@^17.6.2:
|
||||||
version "17.7.2"
|
version "17.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
|
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
|
||||||
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
|
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
|
||||||
@ -10361,16 +10157,6 @@ yocto-queue@^0.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||||
|
|
||||||
zstddec@^0.0.2:
|
|
||||||
version "0.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/zstddec/-/zstddec-0.0.2.tgz#57e2f28dd1ff56b750e07d158a43f0611ad9eeb4"
|
|
||||||
integrity sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==
|
|
||||||
|
|
||||||
zustand@^3.7.1:
|
|
||||||
version "3.7.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d"
|
|
||||||
integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==
|
|
||||||
|
|
||||||
zwitch@^2.0.0:
|
zwitch@^2.0.0:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"
|
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user