Compare commits

..

3 Commits

Author SHA1 Message Date
2a18f3d697 Refactoring 2025-07-14 22:59:47 +01:00
4788b76363 Added delete functionality 2025-07-14 22:58:12 +01:00
528d8d1259 Fixed ID Display 2025-07-14 22:57:20 +01:00
19 changed files with 194 additions and 168 deletions

View File

@ -36,6 +36,15 @@
.ant-typography .id-text { .ant-typography .id-text {
font-family: 'DM Mono'; font-family: 'DM Mono';
font-size: 11.9px; font-size: 11.9px;
vertical-align: top !important;
}
.ant-typography-ellipsis-single-line {
vertical-align: middle !important;
}
.ant-typography-ellipsis-single-line >code {
vertical-align: top !important;
} }
.flag { .flag {

View File

@ -113,7 +113,7 @@ const FilamentStockInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -130,7 +130,7 @@ const FilamentStockInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('events', expanded) updateCollapseState('events', expanded)
} }
key='events' collapseKey='events'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
@ -150,10 +150,13 @@ const FilamentStockInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={filamentStockId} /> <NotesPanel
_id={filamentStockId}
type='filamentStock'
/>
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -164,7 +167,7 @@ const FilamentStockInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -133,7 +133,7 @@ const FilamentInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -151,7 +151,7 @@ const FilamentInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('stocks', expanded) updateCollapseState('stocks', expanded)
} }
key='stocks' collapseKey='stocks'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
@ -175,10 +175,10 @@ const FilamentInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={filamentId} /> <NotesPanel _id={filamentId} type='filament' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -189,7 +189,7 @@ const FilamentInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -1,6 +1,5 @@
import React, { useState, useContext, useRef } from 'react' import React, { useState, useRef } from 'react'
import { Button, Flex, Space, Modal, Dropdown, message } from 'antd' import { Button, Flex, Space, Modal, Dropdown, message } from 'antd'
import { AuthContext } from '../context/AuthContext'
import NewNoteType from './NoteTypes/NewNoteType' import NewNoteType from './NoteTypes/NewNoteType'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import PlusIcon from '../../Icons/PlusIcon' import PlusIcon from '../../Icons/PlusIcon'
@ -15,7 +14,7 @@ const NoteTypes = () => {
const [messageApi, contextHolder] = message.useMessage() const [messageApi, contextHolder] = message.useMessage()
const [newNoteTypeOpen, setNewNoteTypeOpen] = useState(false) const [newNoteTypeOpen, setNewNoteTypeOpen] = useState(false)
const tableRef = useRef() const tableRef = useRef()
const { authenticated } = useContext(AuthContext)
const [viewMode, setViewMode] = useViewMode('noteType') const [viewMode, setViewMode] = useViewMode('noteType')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
@ -73,7 +72,6 @@ const NoteTypes = () => {
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='noteType' type='noteType'
authenticated={authenticated}
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
/> />
</Flex> </Flex>

View File

@ -122,7 +122,7 @@ const NoteTypeInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -140,7 +140,7 @@ const NoteTypeInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -131,7 +131,7 @@ const PartInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -148,10 +148,10 @@ const PartInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={partId} /> <NotesPanel _id={partId} type='part' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -162,7 +162,7 @@ const PartInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -1,6 +1,6 @@
// src/gcodefiles.js // src/gcodefiles.js
import React, { useState, useContext, useRef } from 'react' import React, { useState, useRef } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { import {
Button, Button,
@ -15,8 +15,6 @@ import {
Input Input
} from 'antd' } from 'antd'
import { DownloadOutlined } from '@ant-design/icons' import { DownloadOutlined } from '@ant-design/icons'
import { AuthContext } from '../context/AuthContext'
import IdDisplay from '../common/IdDisplay' import IdDisplay from '../common/IdDisplay'
import TimeDisplay from '../common/TimeDisplay' import TimeDisplay from '../common/TimeDisplay'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
@ -37,7 +35,7 @@ const Products = () => {
const navigate = useNavigate() const navigate = useNavigate()
const [newProductOpen, setNewProductOpen] = useState(false) const [newProductOpen, setNewProductOpen] = useState(false)
const tableRef = useRef() const tableRef = useRef()
const { authenticated } = useContext(AuthContext)
const [viewMode, setViewMode] = useViewMode('Products') const [viewMode, setViewMode] = useViewMode('Products')
const getProductActionItems = (id) => { const getProductActionItems = (id) => {
@ -350,7 +348,6 @@ const Products = () => {
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'product'} type={'product'}
authenticated={authenticated}
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
/> />
</Flex> </Flex>

View File

@ -123,7 +123,7 @@ const ProductInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -140,7 +140,7 @@ const ProductInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('parts', expanded) updateCollapseState('parts', expanded)
} }
key='parts' collapseKey='parts'
> >
<ObjectTable <ObjectTable
type='part' type='part'
@ -159,10 +159,10 @@ const ProductInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={productId} /> <NotesPanel _id={productId} type='product' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -173,7 +173,7 @@ const ProductInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -1,6 +1,5 @@
import React, { useContext, useRef } from 'react' import React, { useRef } from 'react'
import { Button, Flex, Space, Dropdown } from 'antd' import { Button, Flex, Space, Dropdown } from 'antd'
import { AuthContext } from '../context/AuthContext'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ReloadIcon from '../../Icons/ReloadIcon' import ReloadIcon from '../../Icons/ReloadIcon'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
@ -11,7 +10,7 @@ import ColumnViewButton from '../common/ColumnViewButton'
const Users = () => { const Users = () => {
const tableRef = useRef() const tableRef = useRef()
const { authenticated } = useContext(AuthContext)
const [viewMode, setViewMode] = useViewMode('user') const [viewMode, setViewMode] = useViewMode('user')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('user') const [columnVisibility, setColumnVisibility] = useColumnVisibility('user')
@ -56,7 +55,6 @@ const Users = () => {
ref={tableRef} ref={tableRef}
type={'user'} type={'user'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
authenticated={authenticated}
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
/> />
</Flex> </Flex>

View File

@ -123,7 +123,7 @@ const UserInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -141,10 +141,10 @@ const UserInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={userId} /> <NotesPanel _id={userId} type='user' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -155,7 +155,7 @@ const UserInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -1,6 +1,5 @@
import React, { useState, useContext, useRef } from 'react' import React, { useState, useRef } from 'react'
import { Button, Flex, Space, Modal, Dropdown, message } from 'antd' import { Button, Flex, Space, Modal, Dropdown, message } from 'antd'
import { AuthContext } from '../context/AuthContext'
import NewVendor from './Vendors/NewVendor' import NewVendor from './Vendors/NewVendor'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import PlusIcon from '../../Icons/PlusIcon' import PlusIcon from '../../Icons/PlusIcon'
@ -15,7 +14,7 @@ const Vendors = () => {
const [messageApi, contextHolder] = message.useMessage() const [messageApi, contextHolder] = message.useMessage()
const [newVendorOpen, setNewVendorOpen] = useState(false) const [newVendorOpen, setNewVendorOpen] = useState(false)
const tableRef = useRef() const tableRef = useRef()
const { authenticated } = useContext(AuthContext)
const [viewMode, setViewMode] = useViewMode('vendor') const [viewMode, setViewMode] = useViewMode('vendor')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('vendor') const [columnVisibility, setColumnVisibility] = useColumnVisibility('vendor')
@ -72,7 +71,6 @@ const Vendors = () => {
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='vendor' type='vendor'
authenticated={authenticated}
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
/> />
</Flex> </Flex>

View File

@ -42,17 +42,18 @@ const VendorInfo = () => {
isEditing, isEditing,
startEditing, startEditing,
cancelEditing, cancelEditing,
handleFetchObject,
handleUpdate, handleUpdate,
handleDelete,
formValid, formValid,
objectData, objectData,
editLoading, editLoading,
lock, lock
fetchObject
}) => { }) => {
// Define actions for ActionHandler // Define actions for ActionHandler
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() handleFetchObject()
return true return true
}, },
edit: () => { edit: () => {
@ -66,6 +67,10 @@ const VendorInfo = () => {
finishEdit: () => { finishEdit: () => {
handleUpdate() handleUpdate()
return true return true
},
delete: () => {
handleDelete()
return true
} }
} }
@ -127,7 +132,7 @@ const VendorInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -144,10 +149,10 @@ const VendorInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={vendorId} /> <NotesPanel _id={vendorId} type='vendor' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -158,7 +163,7 @@ const VendorInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -144,7 +144,7 @@ const GCodeFileInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -162,7 +162,7 @@ const GCodeFileInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('preview', expanded) updateCollapseState('preview', expanded)
} }
key='preview' collapseKey='preview'
> >
<Card> <Card>
{objectData?.gcodeFileInfo?.thumbnail ? ( {objectData?.gcodeFileInfo?.thumbnail ? (
@ -184,10 +184,10 @@ const GCodeFileInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={gcodeFileId} /> <NotesPanel _id={gcodeFileId} type='gcodeFile' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -198,7 +198,7 @@ const GCodeFileInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -1,9 +1,7 @@
// src/Jobs.js // src/Jobs.js
import React, { useState, useContext, useRef } from 'react' import React, { useState, useRef } from 'react'
import { Button, Flex, Space, Modal, Dropdown, message } from 'antd' import { Button, Flex, Space, Modal, Dropdown, message } from 'antd'
import { AuthContext } from '../context/AuthContext.js'
import NewJob from './Jobs/NewJob.jsx' import NewJob from './Jobs/NewJob.jsx'
import useColumnVisibility from '../hooks/useColumnVisibility.js' import useColumnVisibility from '../hooks/useColumnVisibility.js'
import PlusIcon from '../../Icons/PlusIcon.jsx' import PlusIcon from '../../Icons/PlusIcon.jsx'
@ -19,7 +17,6 @@ const Jobs = () => {
const [newJobOpen, setNewJobOpen] = useState(false) const [newJobOpen, setNewJobOpen] = useState(false)
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('job') const [viewMode, setViewMode] = useViewMode('job')
const { authenticated } = useContext(AuthContext)
const [columnVisibility, setColumnVisibility] = useColumnVisibility('job') const [columnVisibility, setColumnVisibility] = useColumnVisibility('job')
@ -81,7 +78,6 @@ const Jobs = () => {
ref={tableRef} ref={tableRef}
type={'job'} type={'job'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
authenticated={authenticated}
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
/> />
</Flex> </Flex>

View File

@ -1,4 +1,4 @@
import React, { useContext } from 'react' import React from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Space, Flex, Card } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
@ -17,14 +17,12 @@ import JobIcon from '../../../Icons/JobIcon'
import AuditLogIcon from '../../../Icons/AuditLogIcon' import AuditLogIcon from '../../../Icons/AuditLogIcon'
import NoteIcon from '../../../Icons/NoteIcon' import NoteIcon from '../../../Icons/NoteIcon'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import { ApiServerContext } from '../../context/ApiServerContext'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
const JobInfo = () => { const JobInfo = () => {
const location = useLocation() const location = useLocation()
const jobId = new URLSearchParams(location.search).get('jobId') const jobId = new URLSearchParams(location.search).get('jobId')
const { fetchObjectContent } = useContext(ApiServerContext)
const [collapseState, updateCollapseState] = useCollapseState('JobInfo', { const [collapseState, updateCollapseState] = useCollapseState('JobInfo', {
info: true, info: true,
subJobs: true, subJobs: true,
@ -41,9 +39,6 @@ const JobInfo = () => {
{({ {({
loading, loading,
isEditing, isEditing,
startEditing,
cancelEditing,
handleUpdate,
formValid, formValid,
objectData, objectData,
editLoading, editLoading,
@ -55,28 +50,6 @@ const JobInfo = () => {
reload: () => { reload: () => {
fetchObject() fetchObject()
return true return true
},
edit: () => {
startEditing()
return false
},
cancelEdit: () => {
cancelEditing()
return true
},
finishEdit: () => {
handleUpdate()
return true
},
download: () => {
if (jobId) {
fetchObjectContent(
jobId,
'job',
`${objectData.name || 'job'}.json`
)
return true
}
} }
} }
@ -135,7 +108,7 @@ const JobInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -153,7 +126,7 @@ const JobInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('subJobs', expanded) updateCollapseState('subJobs', expanded)
} }
key='subJobs' collapseKey='subJobs'
> >
<SubJobsTree jobData={objectData} loading={loading} /> <SubJobsTree jobData={objectData} loading={loading} />
</InfoCollapse> </InfoCollapse>
@ -165,10 +138,10 @@ const JobInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={jobId} /> <NotesPanel _id={jobId} type='job' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -179,7 +152,7 @@ const JobInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -135,7 +135,7 @@ const PrinterInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -153,7 +153,7 @@ const PrinterInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('jobs', expanded) updateCollapseState('jobs', expanded)
} }
key='jobs' collapseKey='jobs'
> >
<PrinterJobsTree <PrinterJobsTree
subJobs={objectData?.subJobs} subJobs={objectData?.subJobs}
@ -168,10 +168,10 @@ const PrinterInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={printerId} /> <NotesPanel _id={printerId} type='printer' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -182,7 +182,7 @@ const PrinterInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogsParent', expanded) updateCollapseState('auditLogsParent', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />
@ -201,7 +201,7 @@ const PrinterInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogsOwner', expanded) updateCollapseState('auditLogsOwner', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -1,9 +1,7 @@
// src/SubJobs.js // src/SubJobs.js
import React, { useContext, useRef } from 'react' import React, { useRef } from 'react'
import { Button, Flex, Space, Dropdown } from 'antd' import { Button, Flex, Space, Dropdown } from 'antd'
import { AuthContext } from '../context/AuthContext.js'
import useColumnVisibility from '../hooks/useColumnVisibility.js' import useColumnVisibility from '../hooks/useColumnVisibility.js'
import ReloadIcon from '../../Icons/ReloadIcon.jsx' import ReloadIcon from '../../Icons/ReloadIcon.jsx'
import ObjectTable from '../common/ObjectTable.jsx' import ObjectTable from '../common/ObjectTable.jsx'
@ -15,7 +13,6 @@ import ColumnViewButton from '../common/ColumnViewButton.jsx'
const SubJobs = () => { const SubJobs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('subJob') const [viewMode, setViewMode] = useViewMode('subJob')
const { authenticated } = useContext(AuthContext)
const [columnVisibility, setColumnVisibility] = useColumnVisibility('subJob') const [columnVisibility, setColumnVisibility] = useColumnVisibility('subJob')
@ -64,7 +61,6 @@ const SubJobs = () => {
ref={tableRef} ref={tableRef}
type={'subJob'} type={'subJob'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
authenticated={authenticated}
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
/> />
</Flex> </Flex>

View File

@ -1,7 +1,9 @@
import React, { useState, useEffect, useContext, useCallback } from 'react' import React, { useState, useEffect, useContext, useCallback } from 'react'
import { Form, message } from 'antd' import { Form, message } from 'antd'
import { ApiServerContext } from '../context/ApiServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import DeleteObjectModal from './DeleteObjectModal'
/** /**
* EditObjectForm is a reusable form component for editing any object type. * EditObjectForm is a reusable form component for editing any object type.
@ -27,17 +29,21 @@ const EditObjectForm = ({ id, type, style, children }) => {
const [form] = Form.useForm() const [form] = Form.useForm()
const formUpdateValues = Form.useWatch([], form) const formUpdateValues = Form.useWatch([], form)
const [messageApi, contextHolder] = message.useMessage() const [messageApi, contextHolder] = message.useMessage()
const [deleteModalOpen, setDeleteModalOpen] = useState(false)
const [deleteLoading, setDeleteLoading] = useState(false)
const { const {
fetchObjectInfo, fetchObject,
updateObjectInfo, updateObject,
deleteObject,
lockObject, lockObject,
unlockObject, unlockObject,
onLockEvent,
onUpdateEvent,
fetchObjectLock, fetchObjectLock,
showError showError,
connected,
subscribeToObject,
subscribeToLock
} = useContext(ApiServerContext) } = useContext(ApiServerContext)
const { authenticated } = useContext(AuthContext)
// Validate form on change // Validate form on change
useEffect(() => { useEffect(() => {
form form
@ -46,11 +52,6 @@ const EditObjectForm = ({ id, type, style, children }) => {
.catch(() => setFormValid(false)) .catch(() => setFormValid(false))
}, [form, formUpdateValues]) }, [form, formUpdateValues])
// Lock event handler
const lockEventHandler = useCallback((lockEvent) => {
setLock(lockEvent)
}, [])
// Cleanup on unmount // Cleanup on unmount
useEffect(() => { useEffect(() => {
return () => { return () => {
@ -60,10 +61,10 @@ const EditObjectForm = ({ id, type, style, children }) => {
} }
}, [id, type, unlockObject]) }, [id, type, unlockObject])
const fetchObject = useCallback(async () => { const handleFetchObject = useCallback(async () => {
try { try {
setFetchLoading(true) setFetchLoading(true)
const data = await fetchObjectInfo(id, type) const data = await fetchObject(id, type)
const lockEvent = await fetchObjectLock(id, type) const lockEvent = await fetchObjectLock(id, type)
setLock(lockEvent) setLock(lockEvent)
setObjectData(data) setObjectData(data)
@ -77,38 +78,47 @@ const EditObjectForm = ({ id, type, style, children }) => {
fetchObject fetchObject
) )
} }
}, [fetchObjectInfo, fetchObjectLock, id, type, form, messageApi, showError]) }, [fetchObject, fetchObjectLock, id, type, form, messageApi, showError])
const updateObject = async () => {
const values = form.getFieldsValue()
await updateObjectInfo(id, type, values)
}
// Update event handler // Update event handler
const updateEventHandler = useCallback(() => { const updateObjectEventHandler = useCallback((value) => {
fetchObject() setObjectData((prev) => ({ ...prev, ...value }))
}, [fetchObject]) }, [])
// Update event handler
const updateLockEventHandler = useCallback((value) => {
setLock((prev) => ({ ...prev, ...value }))
}, [])
useEffect(() => { useEffect(() => {
if (!initialized && id) { if (!initialized && id && authenticated == true) {
setInitialized(true) setInitialized(true)
fetchObject() handleFetchObject()
} }
}, [id, initialized, fetchObject]) }, [id, initialized, handleFetchObject, authenticated])
useEffect(() => { useEffect(() => {
if (id) { if (id && connected) {
const cleanup = onLockEvent(id, lockEventHandler) const objectUnsubscribe = subscribeToObject(
return cleanup id,
type,
updateObjectEventHandler
)
const lockUnsubscribe = subscribeToLock(id, type, updateLockEventHandler)
return () => {
if (objectUnsubscribe) objectUnsubscribe()
if (lockUnsubscribe) lockUnsubscribe()
} }
}, [id, onLockEvent, lockEventHandler])
useEffect(() => {
if (id) {
const cleanup = onUpdateEvent(id, updateEventHandler)
return cleanup
} }
}, [id, onUpdateEvent, updateEventHandler]) }, [
id,
type,
subscribeToObject,
subscribeToLock,
updateObjectEventHandler,
connected,
updateLockEventHandler
])
const startEditing = () => { const startEditing = () => {
setIsEditing(true) setIsEditing(true)
@ -126,10 +136,10 @@ const EditObjectForm = ({ id, type, style, children }) => {
const handleUpdate = async () => { const handleUpdate = async () => {
try { try {
const values = await form.validateFields() const value = await form.validateFields()
setEditLoading(true) setEditLoading(true)
await updateObject() await updateObject(id, type, value)
setObjectData({ ...objectData, ...values }) setObjectData({ ...objectData, ...value })
setIsEditing(false) setIsEditing(false)
messageApi.success('Information updated successfully') messageApi.success('Information updated successfully')
} catch (err) { } catch (err) {
@ -142,12 +152,43 @@ const EditObjectForm = ({ id, type, style, children }) => {
() => handleUpdate() () => handleUpdate()
) )
} finally { } finally {
fetchObject() handleFetchObject()
setEditLoading(false) setEditLoading(false)
} }
} }
const handleDelete = () => {
setDeleteModalOpen(true)
}
const confirmDelete = async () => {
setDeleteLoading(true)
try {
await deleteObject(id, type)
setDeleteModalOpen(false)
messageApi.success('Deleted successfully')
// Optionally: trigger a callback to parent to remove this object from view
} catch (err) {
messageApi.error('Failed to delete')
showError(
`Failed to delete. Message: ${err.message}. Code: ${err.code}`,
confirmDelete
)
} finally {
setDeleteLoading(false)
}
}
return ( return (
<>
<DeleteObjectModal
open={deleteModalOpen}
onOk={confirmDelete}
onCancel={() => setDeleteModalOpen(false)}
loading={deleteLoading}
objectType={type}
objectName={objectData?.name || objectData?.label || ''}
/>
<Form <Form
form={form} form={form}
layout='vertical' layout='vertical'
@ -170,9 +211,11 @@ const EditObjectForm = ({ id, type, style, children }) => {
setObjectData, setObjectData,
editLoading, editLoading,
lock, lock,
fetchObject handleFetchObject,
handleDelete
})} })}
</Form> </Form>
</>
) )
} }

View File

@ -2,6 +2,7 @@ import VendorIcon from '../../components/Icons/VendorIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon' import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon' import EditIcon from '../../components/Icons/EditIcon'
import ReloadIcon from '../../components/Icons/ReloadIcon' import ReloadIcon from '../../components/Icons/ReloadIcon'
import BinIcon from '../../components/Icons/BinIcon'
export const Vendor = { export const Vendor = {
name: 'vendor', name: 'vendor',
@ -31,6 +32,15 @@ export const Vendor = {
icon: EditIcon, icon: EditIcon,
url: (_id) => url: (_id) =>
`/dashboard/management/vendors/info?vendorId=${_id}&action=edit` `/dashboard/management/vendors/info?vendorId=${_id}&action=edit`
},
{ type: 'divider' },
{
name: 'delete',
label: 'Delete',
icon: BinIcon,
danger: true,
url: (_id) =>
`/dashboard/management/vendors/info?vendorId=${_id}&action=delete`
} }
], ],
url: (id) => `/dashboard/management/vendors/info?vendorId=${id}`, url: (id) => `/dashboard/management/vendors/info?vendorId=${id}`,