Refactor Dashboard Components to Remove Unused State Management

- Removed unnecessary useState hooks for view state management in multiple dashboard components (Invoices, PaymentPolicies, Payments, TaxRecords, FilamentStocks, OrderItems, PartStocks, ProductStocks, PurchaseOrders, Shipments, StockAudits, StockEvents, StockLocations, StockTransfers, AppPasswords, AuditLogs, Couriers, CourierServices, DocumentJobs, DocumentPrinters, DocumentSizes, DocumentTemplates, Filaments, FilamentSkus).
- Updated ObjectListViewProvider integration to streamline component functionality and improve maintainability.
- Adjusted CSS variables in App.css for enhanced styling consistency across components.
This commit is contained in:
Tom Butcher 2026-09-02 22:41:49 +01:00
parent 444e694593
commit 9d1a032e10
59 changed files with 1383 additions and 1271 deletions

View File

@ -47,6 +47,12 @@
font-family: 'DM Sans'; font-family: 'DM Sans';
} }
:root {
--color-list-view-tabs-border: #8282822e;
--color-button-border: #8282822e;
--color-button-background: #8282822e;
}
.ant-dropdown { .ant-dropdown {
z-index: 999; z-index: 999;
} }
@ -2754,7 +2760,7 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
} }
.list-view-tabs-options-dropdown-privacy { .list-view-tabs-options-dropdown-privacy {
margin: 3px 12px 8px; margin: 3px 12px 14px 16px;
} }
.segmented-nav-drag-handle { .segmented-nav-drag-handle {

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Invoices = () => { const Invoices = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('invoices') const [viewMode, setViewMode] = useViewMode('invoices')
@ -36,13 +31,11 @@ const Invoices = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='invoice'
<ObjectListViewProvider tableRef={tableRef}
objectType='invoice' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const Invoices = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const Invoices = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,10 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PaymentPolicies = () => { const PaymentPolicies = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('paymentPolicy') const [viewMode, setViewMode] = useViewMode('paymentPolicy')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
@ -31,12 +27,11 @@ const PaymentPolicies = () => {
useSortSidebarVisibility('PaymentPolicies') useSortSidebarVisibility('PaymentPolicies')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<ObjectListViewProvider objectType='paymentPolicy'
objectType='paymentPolicy' tableRef={tableRef}
tableRef={tableRef} >
onViewStateChange={setViewState} <Flex vertical={'true'} gap='large' className='h-100'>
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -69,7 +64,7 @@ const PaymentPolicies = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -86,10 +81,9 @@ const PaymentPolicies = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Payments = () => { const Payments = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('payments') const [viewMode, setViewMode] = useViewMode('payments')
@ -36,13 +31,11 @@ const Payments = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='payment'
<ObjectListViewProvider tableRef={tableRef}
objectType='payment' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const Payments = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const Payments = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const TaxRecords = () => { const TaxRecords = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('taxRecord') const [viewMode, setViewMode] = useViewMode('taxRecord')
@ -36,13 +31,11 @@ const TaxRecords = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='taxRecord'
<ObjectListViewProvider tableRef={tableRef}
objectType='taxRecord' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const TaxRecords = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const TaxRecords = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/filamentStocks.js // src/filamentStocks.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -21,12 +21,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FilamentStocks = () => { const FilamentStocks = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('filamentStocks') const [viewMode, setViewMode] = useViewMode('filamentStocks')
@ -41,13 +35,11 @@ const FilamentStocks = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filamentStock'
<ObjectListViewProvider tableRef={tableRef}
objectType='filamentStock' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -80,8 +72,6 @@ const FilamentStocks = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -98,11 +88,10 @@ const FilamentStocks = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const OrderItems = () => { const OrderItems = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('orderItems') const [viewMode, setViewMode] = useViewMode('orderItems')
@ -36,13 +31,11 @@ const OrderItems = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='orderItem'
<ObjectListViewProvider tableRef={tableRef}
objectType='orderItem' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const OrderItems = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const OrderItems = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/partStocks.js // src/partStocks.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -21,12 +21,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PartStocks = () => { const PartStocks = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('partStocks') const [viewMode, setViewMode] = useViewMode('partStocks')
@ -41,13 +35,11 @@ const PartStocks = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='partStock'
<ObjectListViewProvider tableRef={tableRef}
objectType='partStock' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -80,8 +72,6 @@ const PartStocks = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -98,11 +88,10 @@ const PartStocks = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,7 +1,7 @@
// src/components/Dashboard/Inventory/ProductStocks.jsx // src/components/Dashboard/Inventory/ProductStocks.jsx
// ProductStocks - tracks assembled products consisting of part stocks // ProductStocks - tracks assembled products consisting of part stocks
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -22,12 +22,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductStocks = () => { const ProductStocks = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('productStocks') const [viewMode, setViewMode] = useViewMode('productStocks')
@ -42,13 +36,11 @@ const ProductStocks = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='productStock'
<ObjectListViewProvider tableRef={tableRef}
objectType='productStock' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -81,8 +73,6 @@ const ProductStocks = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -99,11 +89,10 @@ const ProductStocks = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PurchaseOrders = () => { const PurchaseOrders = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('purchaseOrders') const [viewMode, setViewMode] = useViewMode('purchaseOrders')
@ -36,13 +31,11 @@ const PurchaseOrders = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='purchaseOrder'
<ObjectListViewProvider tableRef={tableRef}
objectType='purchaseOrder' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const PurchaseOrders = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const PurchaseOrders = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Shipments = () => { const Shipments = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('shipments') const [viewMode, setViewMode] = useViewMode('shipments')
@ -36,13 +31,11 @@ const Shipments = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='shipment'
<ObjectListViewProvider tableRef={tableRef}
objectType='shipment' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const Shipments = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const Shipments = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/stockAudits.js // src/stockAudits.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -21,12 +21,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockAudits = () => { const StockAudits = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockAudits') const [viewMode, setViewMode] = useViewMode('stockAudits')
@ -41,13 +35,11 @@ const StockAudits = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockAudit'
<ObjectListViewProvider tableRef={tableRef}
objectType='stockAudit' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -80,8 +72,6 @@ const StockAudits = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -98,11 +88,10 @@ const StockAudits = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
@ -17,10 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockEvents = () => { const StockEvents = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockEvents') const [viewMode, setViewMode] = useViewMode('stockEvents')
@ -35,13 +31,11 @@ const StockEvents = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockEvent'
<ObjectListViewProvider tableRef={tableRef}
objectType='stockEvent' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -74,8 +68,6 @@ const StockEvents = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +84,10 @@ const StockEvents = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -19,12 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockLocations = () => { const StockLocations = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockLocations') const [viewMode, setViewMode] = useViewMode('stockLocations')
@ -39,13 +33,11 @@ const StockLocations = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockLocation'
<ObjectListViewProvider tableRef={tableRef}
objectType='stockLocation' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -78,8 +70,6 @@ const StockLocations = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -96,11 +86,10 @@ const StockLocations = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -19,12 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockTransfers = () => { const StockTransfers = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockTransfers') const [viewMode, setViewMode] = useViewMode('stockTransfers')
@ -39,13 +33,11 @@ const StockTransfers = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockTransfer'
<ObjectListViewProvider tableRef={tableRef}
objectType='stockTransfer' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -78,8 +70,6 @@ const StockTransfers = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -96,11 +86,10 @@ const StockTransfers = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const AppPasswords = () => { const AppPasswords = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('appPassword') const [viewMode, setViewMode] = useViewMode('appPassword')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
@ -35,13 +30,11 @@ const AppPasswords = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='appPassword'
<ObjectListViewProvider tableRef={tableRef}
objectType='appPassword' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -74,8 +67,6 @@ const AppPasswords = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='appPassword' type='appPassword'
@ -92,12 +83,10 @@ const AppPasswords = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex> />
</> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
@ -16,11 +16,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const AuditLogs = () => { const AuditLogs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [columnVisibility, updateColumnVisibility] = const [columnVisibility, updateColumnVisibility] =
useColumnVisibility('auditLog') useColumnVisibility('auditLog')
@ -33,13 +28,11 @@ const AuditLogs = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='auditLog'
<ObjectListViewProvider tableRef={tableRef}
objectType='auditLog' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -68,8 +61,6 @@ const AuditLogs = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -85,11 +76,10 @@ const AuditLogs = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const CourierServices = () => { const CourierServices = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('courierService') const [viewMode, setViewMode] = useViewMode('courierService')
@ -36,13 +31,11 @@ const CourierServices = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='courierService'
<ObjectListViewProvider tableRef={tableRef}
objectType='courierService' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const CourierServices = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const CourierServices = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Couriers = () => { const Couriers = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('courier') const [viewMode, setViewMode] = useViewMode('courier')
@ -35,13 +30,11 @@ const Couriers = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='courier'
<ObjectListViewProvider tableRef={tableRef}
objectType='courier' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -74,7 +67,7 @@ const Couriers = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -91,11 +84,9 @@ const Couriers = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentJobs = () => { const DocumentJobs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentJob') const [viewMode, setViewMode] = useViewMode('documentJob')
@ -36,13 +31,11 @@ const DocumentJobs = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentJob'
<ObjectListViewProvider tableRef={tableRef}
objectType='documentJob' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const DocumentJobs = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const DocumentJobs = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,10 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentPrinters = () => { const DocumentPrinters = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentPrinter') const [viewMode, setViewMode] = useViewMode('documentPrinter')
@ -35,13 +31,11 @@ const DocumentPrinters = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentPrinter'
<ObjectListViewProvider tableRef={tableRef}
objectType='documentPrinter' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -74,7 +68,7 @@ const DocumentPrinters = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -91,11 +85,9 @@ const DocumentPrinters = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,10 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentSizes = () => { const DocumentSizes = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentSize') const [viewMode, setViewMode] = useViewMode('documentSize')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
@ -34,13 +30,11 @@ const DocumentSizes = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentSize'
<ObjectListViewProvider tableRef={tableRef}
objectType='documentSize' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -73,7 +67,7 @@ const DocumentSizes = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -90,11 +84,9 @@ const DocumentSizes = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentTemplates = () => { const DocumentTemplates = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentTemplate') const [viewMode, setViewMode] = useViewMode('documentTemplate')
@ -36,13 +31,11 @@ const DocumentTemplates = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentTemplate'
<ObjectListViewProvider tableRef={tableRef}
objectType='documentTemplate' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const DocumentTemplates = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const DocumentTemplates = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -19,12 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FilamentSkus = () => { const FilamentSkus = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('filamentSkus') const [viewMode, setViewMode] = useViewMode('filamentSkus')
@ -39,13 +33,11 @@ const FilamentSkus = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filamentSku'
<ObjectListViewProvider tableRef={tableRef}
objectType='filamentSku' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -78,8 +70,6 @@ const FilamentSkus = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -96,11 +86,10 @@ const FilamentSkus = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/filaments.js // src/filaments.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -21,11 +21,6 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
const Filaments = () => { const Filaments = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
// View mode state (cards/list), persisted in sessionStorage via custom hook // View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('filament') const [viewMode, setViewMode] = useViewMode('filament')
@ -41,13 +36,11 @@ const Filaments = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filament'
<ObjectListViewProvider tableRef={tableRef}
objectType='filament' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -80,8 +73,6 @@ const Filaments = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='filament' type='filament'
@ -98,12 +89,10 @@ const Filaments = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex> />
</> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Files = () => { const Files = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('file') const [viewMode, setViewMode] = useViewMode('file')
@ -33,17 +28,11 @@ const Files = () => {
const [showSortSidebar, setShowSortSidebar] = const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Files') useSortSidebarVisibility('Files')
return ( return (
<> <ObjectListViewProvider objectType='file' tableRef={tableRef}>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<ObjectListViewProvider <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
objectType='file' <Space size='small'>
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions <ObjectActions
type='file' type='file'
pageName='list' pageName='list'
@ -57,8 +46,8 @@ const Files = () => {
/> />
<ExportListButton objectType='file' /> <ExportListButton objectType='file' />
</Space> </Space>
<ListViewTabs /> <ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)} onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -73,8 +62,7 @@ const Files = () => {
/> />
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -91,11 +79,9 @@ const Files = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/hosts.js // src/hosts.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -21,11 +21,6 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
const Hosts = () => { const Hosts = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
// View mode state (cards/list), persisted in sessionStorage via custom hook // View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('host') const [viewMode, setViewMode] = useViewMode('host')
@ -40,13 +35,11 @@ const Hosts = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='host'
<ObjectListViewProvider tableRef={tableRef}
objectType='host' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -79,8 +72,6 @@ const Hosts = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='host' type='host'
@ -97,12 +88,10 @@ const Hosts = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex> />
</> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -19,11 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Materials = () => { const Materials = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('material') const [viewMode, setViewMode] = useViewMode('material')
@ -38,13 +33,11 @@ const Materials = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='material'
<ObjectListViewProvider tableRef={tableRef}
objectType='material' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -77,8 +70,6 @@ const Materials = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='material' type='material'
@ -95,12 +86,10 @@ const Materials = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex> />
</> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const NoteTypes = () => { const NoteTypes = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('noteType') const [viewMode, setViewMode] = useViewMode('noteType')
@ -36,13 +31,11 @@ const NoteTypes = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='noteType'
<ObjectListViewProvider tableRef={tableRef}
objectType='noteType' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const NoteTypes = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const NoteTypes = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -19,12 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PartSkus = () => { const PartSkus = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('partSkus') const [viewMode, setViewMode] = useViewMode('partSkus')
@ -38,13 +32,11 @@ const PartSkus = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='partSku'
<ObjectListViewProvider tableRef={tableRef}
objectType='partSku' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -77,8 +69,6 @@ const PartSkus = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -95,11 +85,10 @@ const PartSkus = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/gcodefiles.js // src/gcodefiles.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
@ -24,10 +24,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Parts = (filter) => { const Parts = (filter) => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('part') const [viewMode, setViewMode] = useViewMode('part')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('part') const [columnVisibility, setColumnVisibility] = useColumnVisibility('part')
@ -40,13 +36,11 @@ const Parts = (filter) => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='part'
<ObjectListViewProvider tableRef={tableRef}
objectType='part' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -79,7 +73,7 @@ const Parts = (filter) => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -97,11 +91,9 @@ const Parts = (filter) => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PermissionSettingsList = () => { const PermissionSettingsList = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('permissionSetting') const [viewMode, setViewMode] = useViewMode('permissionSetting')
@ -36,13 +31,11 @@ const PermissionSettingsList = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='permissionSetting'
<ObjectListViewProvider tableRef={tableRef}
objectType='permissionSetting' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const PermissionSettingsList = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const PermissionSettingsList = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -19,11 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductCategories = () => { const ProductCategories = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('productCategory') const [viewMode, setViewMode] = useViewMode('productCategory')
@ -38,13 +33,11 @@ const ProductCategories = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='productCategory'
<ObjectListViewProvider tableRef={tableRef}
objectType='productCategory' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -77,8 +70,6 @@ const ProductCategories = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='productCategory' type='productCategory'
@ -95,12 +86,10 @@ const ProductCategories = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex> />
</> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
@ -19,12 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductSkus = () => { const ProductSkus = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('productSkus') const [viewMode, setViewMode] = useViewMode('productSkus')
@ -39,13 +33,11 @@ const ProductSkus = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='productSku'
<ObjectListViewProvider tableRef={tableRef}
objectType='productSku' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -78,8 +70,6 @@ const ProductSkus = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -96,11 +86,10 @@ const ProductSkus = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/gcodefiles.js // src/gcodefiles.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { import {
Button, Button,
@ -36,11 +36,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Products = () => { const Products = () => {
const navigate = useNavigate() const navigate = useNavigate()
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('Products') const [viewMode, setViewMode] = useViewMode('Products')
@ -310,13 +305,11 @@ const Products = () => {
} }
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='product'
<ObjectListViewProvider tableRef={tableRef}
objectType='product' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -350,7 +343,7 @@ const Products = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'product'} type={'product'}
@ -366,11 +359,9 @@ const Products = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockAuditLevels = () => { const StockAuditLevels = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockAuditLevel') const [viewMode, setViewMode] = useViewMode('stockAuditLevel')
@ -35,12 +30,11 @@ const StockAuditLevels = () => {
useSortSidebarVisibility('StockAuditLevels') useSortSidebarVisibility('StockAuditLevels')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<ObjectListViewProvider objectType='stockAuditLevel'
objectType='stockAuditLevel' tableRef={tableRef}
tableRef={tableRef} >
onViewStateChange={setViewState} <Flex vertical={'true'} gap='large' className='h-100'>
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -73,7 +67,7 @@ const StockAuditLevels = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -90,10 +84,9 @@ const StockAuditLevels = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const TaxRates = () => { const TaxRates = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('taxRate') const [viewMode, setViewMode] = useViewMode('taxRate')
@ -35,13 +30,11 @@ const TaxRates = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='taxRate'
<ObjectListViewProvider tableRef={tableRef}
objectType='taxRate' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -74,7 +67,7 @@ const TaxRates = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -91,11 +84,9 @@ const TaxRates = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const UserGroups = () => { const UserGroups = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('userGroup') const [viewMode, setViewMode] = useViewMode('userGroup')
@ -35,13 +30,11 @@ const UserGroups = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='userGroup'
<ObjectListViewProvider tableRef={tableRef}
objectType='userGroup' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -74,7 +67,7 @@ const UserGroups = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -91,11 +84,9 @@ const UserGroups = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Users = () => { const Users = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('user') const [viewMode, setViewMode] = useViewMode('user')
@ -35,12 +30,11 @@ const Users = () => {
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<ObjectListViewProvider objectType='user'
objectType='user' tableRef={tableRef}
tableRef={tableRef} >
onViewStateChange={setViewState} <Flex vertical={'true'} gap='large' className='h-100'>
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -73,7 +67,7 @@ const Users = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'user'} type={'user'}
@ -90,10 +84,9 @@ const Users = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,10 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Vendors = () => { const Vendors = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('vendor') const [viewMode, setViewMode] = useViewMode('vendor')
@ -33,46 +29,40 @@ const Vendors = () => {
useSortSidebarVisibility('Vendors') useSortSidebarVisibility('Vendors')
return ( return (
<> <ObjectListViewProvider objectType='vendor' tableRef={tableRef}>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<ObjectListViewProvider <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
objectType='vendor' <Space size='small'>
tableRef={tableRef} <ObjectActions
onViewStateChange={setViewState} type='vendor'
> pageName='list'
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> onReload={() => tableRef.current?.reload()}
<Space size='small'> />
<ObjectActions <ColumnViewButton
type='vendor' type='vendor'
pageName='list' loading={false}
onReload={() => tableRef.current?.reload()} visibleState={columnVisibility}
/> updateVisibleState={setColumnVisibility}
<ColumnViewButton />
type='vendor' <ExportListButton objectType='vendor' />
loading={false} </Space>
visibleState={columnVisibility} <ListViewTabs />
updateVisibleState={setColumnVisibility} <Space>
/> <SortSidebarButton
<ExportListButton objectType='vendor' /> active={showSortSidebar}
</Space> onClick={() => setShowSortSidebar(!showSortSidebar)}
<ListViewTabs /> />
<Space> <FilterSidebarButton
<SortSidebarButton active={showFilterSidebar}
active={showSortSidebar} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
onClick={() => setShowSortSidebar(!showSortSidebar)} />
/> <ObjectTableViewButton
<FilterSidebarButton viewMode={viewMode}
active={showFilterSidebar} setViewMode={setViewMode}
onClick={() => setShowFilterSidebar(!showFilterSidebar)} />
/> <ListViewEditButtons showStartingDivider={true} />
<ObjectTableViewButton </Space>
viewMode={viewMode} </Flex>
setViewMode={setViewMode}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -89,11 +79,9 @@ const Vendors = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
@ -17,10 +17,6 @@ import useViewMode from '../hooks/useViewMode'
const FilamentProfiles = () => { const FilamentProfiles = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('FilamentProfiles') const [viewMode, setViewMode] = useViewMode('FilamentProfiles')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
@ -33,13 +29,11 @@ const FilamentProfiles = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filamentProfile'
<ObjectListViewProvider tableRef={tableRef}
objectType='filamentProfile' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -71,8 +65,6 @@ const FilamentProfiles = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='filamentProfile' type='filamentProfile'
@ -89,11 +81,10 @@ const FilamentProfiles = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/gcodefiles.js // src/gcodefiles.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
@ -20,10 +20,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const GCodeFiles = () => { const GCodeFiles = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('gcodeFile') const [viewMode, setViewMode] = useViewMode('gcodeFile')
@ -38,13 +34,11 @@ const GCodeFiles = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='gcodeFile'
<ObjectListViewProvider tableRef={tableRef}
objectType='gcodeFile' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -77,7 +71,7 @@ const GCodeFiles = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='gcodeFile' type='gcodeFile'
@ -94,11 +88,9 @@ const GCodeFiles = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/Jobs.js // src/Jobs.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility.jsx' import useColumnVisibility from '../hooks/useColumnVisibility.jsx'
import ObjectTable from '../common/ObjectTable.jsx' import ObjectTable from '../common/ObjectTable.jsx'
@ -19,10 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Jobs = () => { const Jobs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('job') const [viewMode, setViewMode] = useViewMode('job')
@ -36,13 +32,11 @@ const Jobs = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='job'
<ObjectListViewProvider tableRef={tableRef}
objectType='job' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,8 +69,6 @@ const Jobs = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'job'} type={'job'}
@ -93,11 +85,10 @@ const Jobs = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
@ -16,10 +16,6 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import useViewMode from '../hooks/useViewMode' import useViewMode from '../hooks/useViewMode'
const PrinterProfiles = () => { const PrinterProfiles = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('PrinterProfiles') const [viewMode, setViewMode] = useViewMode('PrinterProfiles')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
@ -32,13 +28,11 @@ const PrinterProfiles = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='printerProfile'
<ObjectListViewProvider tableRef={tableRef}
objectType='printerProfile' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -70,8 +64,6 @@ const PrinterProfiles = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='printerProfile' type='printerProfile'
@ -88,11 +80,10 @@ const PrinterProfiles = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/Printers.js // src/Printers.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Space, Flex } from 'antd' import { Space, Flex } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -20,11 +20,6 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
const Printers = () => { const Printers = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
// View mode state (cards/list), persisted in sessionStorage via custom hook // View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('Printers') const [viewMode, setViewMode] = useViewMode('Printers')
@ -41,13 +36,11 @@ const Printers = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='printer'
<ObjectListViewProvider tableRef={tableRef}
objectType='printer' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
@ -80,8 +73,6 @@ const Printers = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='printer' type='printer'
@ -98,12 +89,10 @@ const Printers = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex> />
</> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,6 +1,6 @@
// src/SubJobs.js // src/SubJobs.js
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility.jsx' import useColumnVisibility from '../hooks/useColumnVisibility.jsx'
import ObjectTable from '../common/ObjectTable.jsx' import ObjectTable from '../common/ObjectTable.jsx'
@ -19,10 +19,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const SubJobs = () => { const SubJobs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('subJob') const [viewMode, setViewMode] = useViewMode('subJob')
@ -36,13 +32,11 @@ const SubJobs = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='subJob'
<ObjectListViewProvider tableRef={tableRef}
objectType='subJob' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,8 +69,6 @@ const SubJobs = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'subJob'} type={'subJob'}
@ -93,11 +85,10 @@ const SubJobs = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Clients = () => { const Clients = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('client') const [viewMode, setViewMode] = useViewMode('client')
@ -35,13 +30,11 @@ const Clients = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='client'
<ObjectListViewProvider tableRef={tableRef}
objectType='client' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -74,7 +67,7 @@ const Clients = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -91,11 +84,9 @@ const Clients = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,10 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FulfillmentPolicies = () => { const FulfillmentPolicies = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('fulfillmentPolicy') const [viewMode, setViewMode] = useViewMode('fulfillmentPolicy')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
@ -31,12 +27,11 @@ const FulfillmentPolicies = () => {
useSortSidebarVisibility('FulfillmentPolicies') useSortSidebarVisibility('FulfillmentPolicies')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<ObjectListViewProvider objectType='fulfillmentPolicy'
objectType='fulfillmentPolicy' tableRef={tableRef}
tableRef={tableRef} >
onViewStateChange={setViewState} <Flex vertical={'true'} gap='large' className='h-100'>
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -69,7 +64,7 @@ const FulfillmentPolicies = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -86,10 +81,9 @@ const FulfillmentPolicies = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ListingVarients = () => { const ListingVarients = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('listingVarients') const [viewMode, setViewMode] = useViewMode('listingVarients')
@ -36,13 +31,11 @@ const ListingVarients = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='listingVarient'
<ObjectListViewProvider tableRef={tableRef}
objectType='listingVarient' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const ListingVarients = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const ListingVarients = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Listings = () => { const Listings = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('listings') const [viewMode, setViewMode] = useViewMode('listings')
@ -36,13 +31,11 @@ const Listings = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='listing'
<ObjectListViewProvider tableRef={tableRef}
objectType='listing' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const Listings = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const Listings = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Marketplaces = () => { const Marketplaces = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('marketplaces') const [viewMode, setViewMode] = useViewMode('marketplaces')
@ -36,13 +31,11 @@ const Marketplaces = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='marketplace'
<ObjectListViewProvider tableRef={tableRef}
objectType='marketplace' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const Marketplaces = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const Marketplaces = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,10 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ReturnPolicies = () => { const ReturnPolicies = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('returnPolicy') const [viewMode, setViewMode] = useViewMode('returnPolicy')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('returnPolicy') const [columnVisibility, setColumnVisibility] = useColumnVisibility('returnPolicy')
@ -30,12 +26,11 @@ const ReturnPolicies = () => {
useSortSidebarVisibility('ReturnPolicies') useSortSidebarVisibility('ReturnPolicies')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<ObjectListViewProvider objectType='returnPolicy'
objectType='returnPolicy' tableRef={tableRef}
tableRef={tableRef} >
onViewStateChange={setViewState} <Flex vertical={'true'} gap='large' className='h-100'>
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -68,7 +63,7 @@ const ReturnPolicies = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -85,10 +80,9 @@ const ReturnPolicies = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -1,4 +1,4 @@
import { useRef, useState } from 'react' import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
@ -17,11 +17,6 @@ import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const SalesOrders = () => { const SalesOrders = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('salesOrders') const [viewMode, setViewMode] = useViewMode('salesOrders')
@ -36,13 +31,11 @@ const SalesOrders = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='salesOrder'
<ObjectListViewProvider tableRef={tableRef}
objectType='salesOrder' >
tableRef={tableRef} <Flex vertical={'true'} gap='large' className='h-100'>
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
@ -75,7 +68,7 @@ const SalesOrders = () => {
<ListViewEditButtons showStartingDivider={true} /> <ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
</ObjectListViewProvider>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -92,11 +85,9 @@ const SalesOrders = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -1,5 +1,5 @@
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import React, { useMemo } from 'react' import React, { useEffect, useMemo, useState } from 'react'
import { import {
Input, Input,
Dropdown, Dropdown,
@ -46,7 +46,8 @@ const ViewOptionsDropdown = ({ view, isEditing, onChange, onDelete }) => {
domEvent.stopPropagation() domEvent.stopPropagation()
onDelete?.() onDelete?.()
} }
} },
{ type: 'divider' }
] ]
} }
@ -203,6 +204,18 @@ const ListViewTabs = () => {
viewTabSignatures viewTabSignatures
} = useObjectListView() } = useObjectListView()
const [animated, setAnimated] = useState(false)
useEffect(() => {
if (initialLoading) {
setAnimated(false)
return undefined
}
const timeoutId = setTimeout(() => setAnimated(true), 10)
return () => clearTimeout(timeoutId)
}, [initialLoading])
const model = getModelByName(objectType) const model = getModelByName(objectType)
const options = useMemo(() => { const options = useMemo(() => {
@ -286,6 +299,7 @@ const ListViewTabs = () => {
options={options} options={options}
onChange={selectTab} onChange={selectTab}
onReorder={isEditing ? reorderDraftViews : undefined} onReorder={isEditing ? reorderDraftViews : undefined}
animated={animated}
/> />
{isEditing && ( {isEditing && (
<Button <Button

View File

@ -52,11 +52,13 @@ import QuickPropertyFilters from './QuickPropertyFilters'
import FilterInput from './FilterInput' import FilterInput from './FilterInput'
import { import {
getActiveFilterValues, getActiveFilterValues,
useTableState,
useTableStatePersistence useTableStatePersistence
} from '../context/TableStateContext' } from '../context/TableStateContext'
import { hasActionPermission } from '../../../database/permissions' import { hasActionPermission } from '../../../database/permissions'
import Tooltip from './Tooltip' import Tooltip from './Tooltip'
import { ObjectTableFilterContext } from './ObjectTableFilterContext' import { ObjectTableFilterContext } from './ObjectTableFilterContext'
import ObjectListViewContext from '../context/ObjectListViewContext'
const logger = loglevel.getLogger('DasboardTable') const logger = loglevel.getLogger('DasboardTable')
logger.setLevel(config.logLevel) logger.setLevel(config.logLevel)
@ -91,6 +93,37 @@ const fromFilterExpression = (expr) => {
return [expr] return [expr]
} }
const areValuesEqual = (v1, v2) => {
const id1 = v1 && typeof v1 === 'object' && v1._id ? v1._id : v1
const id2 = v2 && typeof v2 === 'object' && v2._id ? v2._id : v2
return String(id1) === String(id2)
}
const getChangedKeys = (existing, updated) => {
if (!updated || typeof updated !== 'object') return []
return Object.keys(updated).filter((key) => {
if (key === '_id' || key === 'objectType') return false
if (!existing) return true
return !areValuesEqual(existing[key], updated[key])
})
}
const updateAffectsFilterOrSort = (
changedKeys,
filter,
masterFilter,
sorter
) => {
if (!changedKeys.length) return false
const filterKeys = new Set([
...Object.keys(filter || {}),
...Object.keys(masterFilter || {})
])
if (changedKeys.some((key) => filterKeys.has(key))) return true
if (sorter?.field && changedKeys.includes(sorter.field)) return true
return false
}
const ColumnFilterDropdown = ({ const ColumnFilterDropdown = ({
setSelectedKeys, setSelectedKeys,
selectedKeys, selectedKeys,
@ -255,8 +288,6 @@ const ObjectTable = forwardRef(
saveSortInUrl = false, saveSortInUrl = false,
useSortInSession = false, useSortInSession = false,
useSortInUrl = false, useSortInUrl = false,
activeObjectView = null,
onObjectViewFilterSortChange,
onRowAction onRowAction
}, },
ref ref
@ -264,6 +295,14 @@ const ObjectTable = forwardRef(
const { token, userProfile } = useContext(AuthContext) const { token, userProfile } = useContext(AuthContext)
const { isElectron } = useContext(ElectronContext) const { isElectron } = useContext(ElectronContext)
const { callAction } = useActions() const { callAction } = useActions()
const objectListView = useContext(ObjectListViewContext)
const listViewId = objectListView?.listViewId ?? null
const listViewFilter = objectListView?.listViewFilter ?? null
const listViewSort = objectListView?.listViewSort ?? null
const activeObjectView = objectListView?.activeObjectView ?? null
const onObjectViewFilterSortChange = objectListView?.isEditing
? objectListView.handleFilterSortChange
: null
const onStateChangeRef = useRef(onStateChange) const onStateChangeRef = useRef(onStateChange)
useEffect(() => { useEffect(() => {
onStateChangeRef.current = onStateChange onStateChangeRef.current = onStateChange
@ -271,7 +310,7 @@ const ObjectTable = forwardRef(
const { const {
fetchObjects, fetchObjects,
connected, connected,
subscribeToObjectUpdates, subscribeToAllObjectUpdates,
subscribeToObjectTypeUpdates, subscribeToObjectTypeUpdates,
updateMultipleObjects, updateMultipleObjects,
setObjectActivity, setObjectActivity,
@ -282,13 +321,19 @@ const ObjectTable = forwardRef(
const { const {
getPersistedFilter, getPersistedFilter,
getPersistedSorter, getPersistedSorter,
getAllTabPersistedFilter,
getAllTabPersistedSorter,
persistFilter, persistFilter,
persistSort, persistSort,
persistTableState, persistTableState,
persistAllTabTableState,
registerPageFilter, registerPageFilter,
registerPageSorter registerPageSorter,
registerObjectListFilter,
registerObjectListSorter
} = useTableStatePersistence({ } = useTableStatePersistence({
scope: type, scope: type,
viewId: listViewId,
pagePath: location.pathname, pagePath: location.pathname,
saveFilterInSession, saveFilterInSession,
saveFilterInUrl, saveFilterInUrl,
@ -299,6 +344,7 @@ const ObjectTable = forwardRef(
useSortInSession, useSortInSession,
useSortInUrl useSortInUrl
}) })
const { getViewFromUrl } = useTableState()
var adjustedScrollHeight = scrollHeight var adjustedScrollHeight = scrollHeight
if (isMobile) { if (isMobile) {
adjustedScrollHeight = 'calc(var(--unit-100vh) - 298px)' adjustedScrollHeight = 'calc(var(--unit-100vh) - 298px)'
@ -319,6 +365,8 @@ const ObjectTable = forwardRef(
const model = getModelByName(type) const model = getModelByName(type)
const activeFilterRef = useRef({}) const activeFilterRef = useRef({})
const tableSorterRef = useRef({}) const tableSorterRef = useRef({})
const listViewIdRef = useRef(listViewId)
const listViewFilterRef = useRef(listViewFilter)
const activeObjectViewRef = useRef(activeObjectView) const activeObjectViewRef = useRef(activeObjectView)
activeObjectViewRef.current = activeObjectView activeObjectViewRef.current = activeObjectView
const onObjectViewFilterSortChangeRef = useRef(onObjectViewFilterSortChange) const onObjectViewFilterSortChangeRef = useRef(onObjectViewFilterSortChange)
@ -327,6 +375,25 @@ const ObjectTable = forwardRef(
const [tableSorter, setTableSorter] = useState({}) const [tableSorter, setTableSorter] = useState({})
const [initialized, setInitialized] = useState(false) const [initialized, setInitialized] = useState(false)
// Keep refs in sync with props. applyViewState may update them earlier in
// the same tick; props remain the source of truth after commit.
useEffect(() => {
listViewIdRef.current = listViewId
listViewFilterRef.current = listViewFilter || {}
}, [listViewId, listViewFilter])
const lastAppliedViewKeyRef = useRef(null)
const buildEffectiveFilter = useCallback((userFilter, viewFilter = listViewFilterRef.current) => {
const active = getActiveFilterValues(userFilter)
const viewId = listViewIdRef.current
if (!viewId) return active
return {
...getActiveFilterValues(viewFilter || {}),
...active
}
}, [])
// Table state // Table state
const [pages, setPages] = useState([]) const [pages, setPages] = useState([])
const pagesRef = useRef(pages) const pagesRef = useRef(pages)
@ -362,14 +429,15 @@ const ObjectTable = forwardRef(
onStateChangeRef.current?.({ isEditing, editLoading }) onStateChangeRef.current?.({ isEditing, editLoading })
}, [isEditing, editLoading]) }, [isEditing, editLoading])
const subscribedIdsRef = useRef([])
// const [typeSubscribed, setTypeSubscribed] = useState(false)
const unsubscribesRef = useRef([])
const updateEventHandlerRef = useRef() const updateEventHandlerRef = useRef()
const subscribeToObjectTypeUpdatesRef = useRef(null) const subscribeToObjectTypeUpdatesRef = useRef(null)
const subscribedTypeRef = useRef(null) const subscribedTypeRef = useRef(null)
const subscribeToAllObjectUpdatesRef = useRef(null)
const newEventHandlerRef = useRef() const newEventHandlerRef = useRef()
const subscriptionFilterRef = useRef() const subscriptionFilterRef = useRef()
const effectiveSorterRef = useRef({})
const reloadRef = useRef(null)
const silentReloadRef = useRef(null)
const subscribeToObjectTypeUpdatesFnRef = useRef( const subscribeToObjectTypeUpdatesFnRef = useRef(
subscribeToObjectTypeUpdates subscribeToObjectTypeUpdates
) )
@ -412,16 +480,36 @@ const ObjectTable = forwardRef(
const pendingScrollAnchorRef = useRef(null) const pendingScrollAnchorRef = useRef(null)
const dataLoadGenerationRef = useRef(0) const dataLoadGenerationRef = useRef(0)
const [tableListKey, setTableListKey] = useState(0) const [tableListKey, setTableListKey] = useState(0)
const isInternalSortUpdateRef = useRef(false) // Suppress Ant Design Table onChange while we remount / set filter+sort
// programmatically. Remounting with controlled filteredValue often fires
// onChange with all-null filters (sorter intact) and would wipe the view.
const isInternalTableChangeRef = useRef(false)
const internalTableChangeClearRafRef = useRef(null)
const suppressTableChange = useCallback(() => {
isInternalTableChangeRef.current = true
if (internalTableChangeClearRafRef.current != null) {
cancelAnimationFrame(internalTableChangeClearRafRef.current)
}
// Double rAF: wait until after the remounted Table commits and any
// synchronous/mount onChange from Ant Design has run.
internalTableChangeClearRafRef.current = requestAnimationFrame(() => {
internalTableChangeClearRafRef.current = requestAnimationFrame(() => {
internalTableChangeClearRafRef.current = null
isInternalTableChangeRef.current = false
})
})
}, [])
const beginDataReload = useCallback(() => { const beginDataReload = useCallback(() => {
dataLoadGenerationRef.current += 1 dataLoadGenerationRef.current += 1
loadingPagesRef.current.clear() loadingPagesRef.current.clear()
pendingScrollAnchorRef.current = null pendingScrollAnchorRef.current = null
pagesRef.current = [] pagesRef.current = []
suppressTableChange()
setTableListKey((key) => key + 1) setTableListKey((key) => key + 1)
return dataLoadGenerationRef.current return dataLoadGenerationRef.current
}, []) }, [suppressTableChange])
const isStaleDataLoad = useCallback((generation) => { const isStaleDataLoad = useCallback((generation) => {
return generation !== dataLoadGenerationRef.current return generation !== dataLoadGenerationRef.current
@ -799,19 +887,35 @@ const ObjectTable = forwardRef(
[loadNextPage, loadPreviousPage, skeletonsHeight] [loadNextPage, loadPreviousPage, skeletonsHeight]
) )
const reload = useCallback(async () => { const reloadLoadedPages = useCallback(
setLazyLoading(true) async ({ silent = false } = {}) => {
try { if (!silent) {
const loadedPages = pagesRef.current.filter( setLazyLoading(true)
(page) => !page.isSkeletonPage
)
for (let i = 0; i < loadedPages.length; i++) {
await fetchData(loadedPages[i].pageNum)
} }
} finally { try {
setLazyLoading(false) const loadedPages = pagesRef.current.filter(
} (page) => !page.isSkeletonPage
}, [fetchData]) )
for (let i = 0; i < loadedPages.length; i++) {
await fetchData(loadedPages[i].pageNum)
}
} finally {
if (!silent) {
setLazyLoading(false)
}
}
},
[fetchData]
)
const reload = useCallback(() => reloadLoadedPages(), [reloadLoadedPages])
const silentReload = useCallback(
() => reloadLoadedPages({ silent: true }),
[reloadLoadedPages]
)
reloadRef.current = reload
silentReloadRef.current = silentReload
const startEditing = useCallback(() => { const startEditing = useCallback(() => {
setIsEditing(true) setIsEditing(true)
@ -855,138 +959,139 @@ const ObjectTable = forwardRef(
} }
}, [type, updateMultipleObjects, reload, tableData, clearObjectActivity]) }, [type, updateMultipleObjects, reload, tableData, clearObjectActivity])
// Update event handler for real-time updates const findTableItem = useCallback((id) => {
const updateEventHandler = useCallback((id, updatedData) => { for (const page of pagesRef.current) {
setPages((prevPages) => const item = page.items?.find(
prevPages.map((page) => { (entry) => String(entry._id) === String(id) && !entry.isSkeleton
const updatedItems = page.items.map((item) => { )
if (item._id === id) { if (item) return item
return { ...item, ...updatedData }
}
return item
})
return {
...page,
items: updatedItems
}
})
)
if (rowFormsRef.current[id]) {
rowFormsRef.current[id].setFieldsValue(updatedData)
} }
return null
}, []) }, [])
// Update event handler for real-time updates
const updateEventHandler = useCallback(
(id, updatedData) => {
const existingItem = findTableItem(id)
const changedKeys = getChangedKeys(existingItem, updatedData)
if (
updateAffectsFilterOrSort(
changedKeys,
subscriptionFilterRef.current,
{},
effectiveSorterRef.current
)
) {
silentReloadRef.current?.()
return
}
if (!existingItem) return
setPages((prevPages) =>
prevPages.map((page) => {
const updatedItems = page.items.map((item) => {
if (String(item._id) === String(id)) {
return { ...item, ...updatedData }
}
return item
})
return {
...page,
items: updatedItems
}
})
)
if (rowFormsRef.current[id]) {
rowFormsRef.current[id].setFieldsValue(updatedData)
}
},
[findTableItem]
)
// Store the latest updateEventHandler in a ref // Store the latest updateEventHandler in a ref
updateEventHandlerRef.current = updateEventHandler updateEventHandlerRef.current = updateEventHandler
const newEventHandler = useCallback( const newEventHandler = useCallback((params) => {
(params) => { logger.debug('New event handler:', params)
logger.debug('New event handler:', params) silentReloadRef.current?.()
reload() }, [])
},
[reload]
)
const subscriptionFilter = useMemo(() => { // Effective filter for ObjectTableFilterContext, breadcrumb, and neighbors:
const active = {} // view definition + any user-entered sidebar filters.
Object.entries(sidebarFilter).forEach(([k, v]) => { const effectiveFilter = useMemo(() => {
if (v !== '' && v !== undefined) active[k] = v const userFilter = getActiveFilterValues(sidebarFilter)
}) if (!listViewId) return userFilter
return { ...masterFilter, ...active } return {
}, [sidebarFilter, masterFilter]) ...getActiveFilterValues(listViewFilter || {}),
...userFilter
}
}, [listViewId, listViewFilter, sidebarFilter])
const effectiveSorter = useMemo(() => {
if (tableSorter?.field && tableSorter?.order) {
return { field: tableSorter.field, order: tableSorter.order }
}
if (listViewId && listViewSort?.field && listViewSort?.order) {
return { field: listViewSort.field, order: listViewSort.order }
}
return {}
}, [listViewId, listViewSort, tableSorter])
const subscriptionFilter = useMemo(
() => ({ ...masterFilter, ...effectiveFilter }),
[effectiveFilter, masterFilter]
)
const tableFilterContextValue = useMemo( const tableFilterContextValue = useMemo(
() => ({ () => ({
filter: getActiveFilterValues(sidebarFilter), filter: effectiveFilter,
masterFilter masterFilter
}), }),
[sidebarFilter, masterFilter] [effectiveFilter, masterFilter]
) )
newEventHandlerRef.current = newEventHandler newEventHandlerRef.current = newEventHandler
subscriptionFilterRef.current = subscriptionFilter subscriptionFilterRef.current = subscriptionFilter
effectiveSorterRef.current = effectiveSorter
subscribeToObjectTypeUpdatesFnRef.current = subscribeToObjectTypeUpdates subscribeToObjectTypeUpdatesFnRef.current = subscribeToObjectTypeUpdates
// Subscribe to real-time updates for all items // Cleanup subscriptions on unmount
useEffect(() => {
if (pages.length > 0 && connected == true) {
// Get all non-skeleton item IDs from all pages
const allItemIds = pages
.flatMap((page) => page.items || [])
.filter((item) => !item.isSkeleton)
.map((item) => item._id)
.filter(Boolean)
// Find new items that need subscription
const newItemIds = allItemIds.filter(
(id) => !subscribedIdsRef.current.includes(id)
)
// Subscribe to new items only
newItemIds.forEach((itemId) => {
const unsubscribe = subscribeToObjectUpdates(
itemId?.toLowerCase(),
type,
(updateData) => {
updateEventHandlerRef.current(itemId, updateData)
}
)
subscribedIdsRef.current.push(itemId)
if (unsubscribe) {
unsubscribesRef.current.push(unsubscribe)
}
})
// Clean up subscriptions for items that are no longer in the pages
const currentSubscribedIds = subscribedIdsRef.current
const itemsToUnsubscribe = currentSubscribedIds.filter(
(id) => !allItemIds.includes(id)
)
itemsToUnsubscribe.forEach((itemId) => {
const index = subscribedIdsRef.current.indexOf(itemId)
if (index > -1) {
subscribedIdsRef.current.splice(index, 1)
const unsubscribe = unsubscribesRef.current[index]
if (unsubscribe) {
unsubscribe()
}
unsubscribesRef.current.splice(index, 1)
}
})
}
}, [pages, type, subscribeToObjectUpdates, connected])
// Cleanup effect for component unmount
useEffect(() => { useEffect(() => {
return () => { return () => {
if (connected == true && unsubscribesRef.current) {
// Clean up all subscriptions when component unmounts
unsubscribesRef.current.forEach((unsubscribe) => {
if (unsubscribe) unsubscribe()
})
unsubscribesRef.current = []
subscribedIdsRef.current = []
// Clean up type subscription
}
if (connected == true && subscribeToObjectTypeUpdatesRef.current) { if (connected == true && subscribeToObjectTypeUpdatesRef.current) {
subscribeToObjectTypeUpdatesRef.current() subscribeToObjectTypeUpdatesRef.current()
subscribeToObjectTypeUpdatesRef.current = null subscribeToObjectTypeUpdatesRef.current = null
} }
if (connected == true && subscribeToAllObjectUpdatesRef.current) {
subscribeToAllObjectUpdatesRef.current()
subscribeToAllObjectUpdatesRef.current = null
}
} }
}, [connected]) }, [connected])
// Subscribe to all object updates for this type
useEffect(() => {
if (connected !== true || !type) return
const unsubscribe = subscribeToAllObjectUpdates(type, (id, updateData) => {
updateEventHandlerRef.current(id, updateData)
})
subscribeToAllObjectUpdatesRef.current = unsubscribe
return () => {
if (unsubscribe) unsubscribe()
if (subscribeToAllObjectUpdatesRef.current === unsubscribe) {
subscribeToAllObjectUpdatesRef.current = null
}
}
}, [type, connected, subscribeToAllObjectUpdates])
useEffect(() => { useEffect(() => {
if (connected !== true) return if (connected !== true) return
if (subscribedTypeRef.current === type) return if (subscribedTypeRef.current === type) return
console.log(
'subscribing to object type updates',
type,
subscriptionFilterRef.current
)
const unsubscribe = subscribeToObjectTypeUpdatesFnRef.current( const unsubscribe = subscribeToObjectTypeUpdatesFnRef.current(
type, type,
subscriptionFilterRef.current, subscriptionFilterRef.current,
@ -1047,6 +1152,8 @@ const ObjectTable = forwardRef(
} finally { } finally {
if (!isStaleDataLoad(generation)) { if (!isStaleDataLoad(generation)) {
setLoading(false) setLoading(false)
// Data/column swap can also trigger a spurious Table onChange.
suppressTableChange()
} }
} }
}, },
@ -1057,11 +1164,18 @@ const ObjectTable = forwardRef(
createSkeletonPage, createSkeletonPage,
fetchPage, fetchPage,
isStaleDataLoad, isStaleDataLoad,
setTablePages setTablePages,
suppressTableChange
] ]
) )
const loadInitialPage = useCallback(async () => { const loadInitialPage = useCallback(async () => {
// A selected view applies its own filter/sort via applyViewState.
// Do not load (or clear) filters here — that races and wipes the view.
if (getViewFromUrl() || listViewIdRef.current) {
return
}
const filter = getPersistedFilter() const filter = getPersistedFilter()
const sorter = getPersistedSorter() const sorter = getPersistedSorter()
const activeFilter = getActiveFilterValues(filter) const activeFilter = getActiveFilterValues(filter)
@ -1083,22 +1197,85 @@ const ObjectTable = forwardRef(
}, [ }, [
getPersistedFilter, getPersistedFilter,
getPersistedSorter, getPersistedSorter,
getViewFromUrl,
initialPage, initialPage,
loadPage, loadPage,
resolveSorter resolveSorter
]) ])
// When a view becomes available, apply its definition once. Skip empty
// prop-lag updates so we never clear an already-applied view filter.
useEffect(() => {
if (!listViewId || activeObjectView) {
if (!listViewId) lastAppliedViewKeyRef.current = null
return
}
const viewFilter = getActiveFilterValues(listViewFilter || {})
const viewSort =
listViewSort?.field && listViewSort?.order
? { field: listViewSort.field, order: listViewSort.order }
: {}
const viewKey = `${listViewId}:${JSON.stringify(viewFilter)}:${JSON.stringify(viewSort)}`
if (lastAppliedViewKeyRef.current === viewKey) return
// Prop lag: listViewId is set but filter/sort props are still empty.
// Never overwrite a non-empty sidebar/query with {}.
const hasViewState =
Object.keys(viewFilter).length > 0 || Boolean(viewSort.field)
if (!hasViewState) return
lastAppliedViewKeyRef.current = viewKey
setSidebarFilter(viewFilter)
setTableSorter(viewSort)
tableSorterRef.current = viewSort
activeFilterRef.current = viewFilter
loadPage(
initialPage,
viewFilter,
viewSort.field ? viewSort : null
)
}, [
activeObjectView,
initialPage,
listViewFilter,
listViewId,
listViewSort,
loadPage
])
const applyViewState = useCallback( const applyViewState = useCallback(
(filterState, sorterState) => { (filterState, sorterState, options = {}) => {
let filter
let sorter
if (filterState == null && sorterState == null) { if (filterState == null && sorterState == null) {
const filter = getPersistedFilter() // Ignore accidental All restores while a view is still selected
const sorter = getPersistedSorter() // (e.g. load race). Explicit All tab switches pass forceAll.
const activeFilter = getActiveFilterValues(filter) if (
!options.forceAll &&
(listViewIdRef.current || getViewFromUrl())
) {
return
}
listViewIdRef.current = null
listViewFilterRef.current = {}
lastAppliedViewKeyRef.current = null
filter = getAllTabPersistedFilter()
sorter = getAllTabPersistedSorter()
const resolvedSorter = resolveSorter(sorter) const resolvedSorter = resolveSorter(sorter)
const nextSorter = sorter?.field ? sorter : {}
const activeFilter = getActiveFilterValues(filter)
setSidebarFilter(filter) setSidebarFilter(filter)
tableSorterRef.current = sorter?.field ? sorter : {} tableSorterRef.current = nextSorter
setTableSorter(sorter?.field ? sorter : {}) setTableSorter(nextSorter)
activeFilterRef.current = activeFilter activeFilterRef.current = activeFilter
persistAllTabTableState(filter, nextSorter)
loadPage( loadPage(
initialPage, initialPage,
activeFilter, activeFilter,
@ -1107,14 +1284,39 @@ const ObjectTable = forwardRef(
return return
} }
const filter = filterState || {} // View tab: apply the view definition. Sidebar starts as the view
const sorter = sorterState?.field ? sorterState : {} // filter so the UI matches; All-tab user settings must not leak in.
const activeFilter = getActiveFilterValues(filter) const viewId =
options.viewId !== undefined
? options.viewId
: listViewIdRef.current
const viewFilter =
options.viewFilter !== undefined
? options.viewFilter || {}
: filterState || {}
listViewIdRef.current = viewId
listViewFilterRef.current = viewFilter
filter = viewFilter
sorter =
options.viewSort?.field
? options.viewSort
: sorterState?.field
? sorterState
: {}
const resolvedSorter = resolveSorter(sorter) const resolvedSorter = resolveSorter(sorter)
const nextSorter = sorter?.field ? sorter : {}
const activeFilter = getActiveFilterValues(filter)
lastAppliedViewKeyRef.current = `${viewId || ''}:${JSON.stringify(activeFilter)}:${JSON.stringify(nextSorter)}`
setSidebarFilter(filter) setSidebarFilter(filter)
tableSorterRef.current = sorter tableSorterRef.current = nextSorter
setTableSorter(sorter) setTableSorter(nextSorter)
activeFilterRef.current = activeFilter activeFilterRef.current = activeFilter
loadPage( loadPage(
initialPage, initialPage,
activeFilter, activeFilter,
@ -1122,10 +1324,12 @@ const ObjectTable = forwardRef(
) )
}, },
[ [
getPersistedFilter, getAllTabPersistedFilter,
getPersistedSorter, getAllTabPersistedSorter,
getViewFromUrl,
initialPage, initialPage,
loadPage, loadPage,
persistAllTabTableState,
resolveSorter resolveSorter
] ]
) )
@ -1180,14 +1384,16 @@ const ObjectTable = forwardRef(
}, [type, masterFilter, beginDataReload]) }, [type, masterFilter, beginDataReload])
useEffect(() => { useEffect(() => {
registerPageFilter(sidebarFilter) registerPageFilter(effectiveFilter)
registerObjectListFilter(effectiveFilter)
return () => registerPageFilter({}) return () => registerPageFilter({})
}, [sidebarFilter, registerPageFilter]) }, [effectiveFilter, registerPageFilter, registerObjectListFilter])
useEffect(() => { useEffect(() => {
registerPageSorter(tableSorter) registerPageSorter(effectiveSorter)
registerObjectListSorter(effectiveSorter)
return () => registerPageSorter({}) return () => registerPageSorter({})
}, [tableSorter, registerPageSorter]) }, [effectiveSorter, registerPageSorter, registerObjectListSorter])
const getFilterDropdown = ({ const getFilterDropdown = ({
setSelectedKeys, setSelectedKeys,
@ -1207,13 +1413,13 @@ const ObjectTable = forwardRef(
propertyName={propertyName} propertyName={propertyName}
propertyLabel={propertyLabel} propertyLabel={propertyLabel}
modelType={type} modelType={type}
filter={sidebarFilter} filter={effectiveFilter}
masterFilter={masterFilter} masterFilter={masterFilter}
/> />
) )
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
if (isInternalSortUpdateRef.current) return if (isInternalTableChangeRef.current) return
const next = { ...sidebarFilter } const next = { ...sidebarFilter }
@ -1233,29 +1439,42 @@ const ObjectTable = forwardRef(
setSidebarFilter(next) setSidebarFilter(next)
setTableSorter(nextSorter) setTableSorter(nextSorter)
const effective = buildEffectiveFilter(next)
activeFilterRef.current = effective
if (activeObjectViewRef.current) { if (activeObjectViewRef.current) {
// Editing a view: keep filter/sort on the draft view only
onObjectViewFilterSortChangeRef.current?.(next, nextSorter) onObjectViewFilterSortChangeRef.current?.(next, nextSorter)
} else { } else if (!listViewIdRef.current) {
// All tab: persist personal filter/sort to URL/session
persistTableState(next, nextSorter) persistTableState(next, nextSorter)
} }
loadPage(initialPage, getActiveFilterValues(next), resolveSorter(nextSorter)) loadPage(initialPage, effective, resolveSorter(nextSorter))
} }
const handleSidebarFilterChange = useCallback( const handleSidebarFilterChange = useCallback(
(newSidebarFilter) => { (newSidebarFilter) => {
setSidebarFilter(newSidebarFilter) setSidebarFilter(newSidebarFilter)
const effective = buildEffectiveFilter(newSidebarFilter)
activeFilterRef.current = effective
if (activeObjectViewRef.current) { if (activeObjectViewRef.current) {
onObjectViewFilterSortChangeRef.current?.(newSidebarFilter, tableSorter) onObjectViewFilterSortChangeRef.current?.(newSidebarFilter, tableSorter)
} else { } else if (!listViewIdRef.current) {
persistFilter(newSidebarFilter) persistFilter(newSidebarFilter)
} }
loadPage( loadPage(
initialPage, initialPage,
getActiveFilterValues(newSidebarFilter), effective,
resolveSorter(tableSorter) resolveSorter(tableSorter)
) )
}, },
[initialPage, loadPage, persistFilter, resolveSorter, tableSorter] [
buildEffectiveFilter,
initialPage,
loadPage,
persistFilter,
resolveSorter,
tableSorter
]
) )
const handleSidebarSortChange = useCallback( const handleSidebarSortChange = useCallback(
@ -1263,24 +1482,29 @@ const ObjectTable = forwardRef(
const nextSorter = newSorter?.field const nextSorter = newSorter?.field
? { field: newSorter.field, order: newSorter.order } ? { field: newSorter.field, order: newSorter.order }
: {} : {}
isInternalSortUpdateRef.current = true suppressTableChange()
setTableSorter(nextSorter) setTableSorter(nextSorter)
tableSorterRef.current = nextSorter tableSorterRef.current = nextSorter
if (activeObjectViewRef.current) { if (activeObjectViewRef.current) {
onObjectViewFilterSortChangeRef.current?.(sidebarFilter, nextSorter) onObjectViewFilterSortChangeRef.current?.(sidebarFilter, nextSorter)
} else { } else if (!listViewIdRef.current) {
persistSort(nextSorter) persistSort(nextSorter)
} }
loadPage( loadPage(
initialPage, initialPage,
getActiveFilterValues(sidebarFilter), buildEffectiveFilter(sidebarFilter),
resolveSorter(nextSorter) resolveSorter(nextSorter)
) )
requestAnimationFrame(() => {
isInternalSortUpdateRef.current = false
})
}, },
[initialPage, loadPage, persistSort, resolveSorter, sidebarFilter] [
buildEffectiveFilter,
initialPage,
loadPage,
persistSort,
resolveSorter,
sidebarFilter,
suppressTableChange
]
) )
const modelProperties = getModelProperties(type) const modelProperties = getModelProperties(type)
@ -1420,7 +1644,7 @@ const ObjectTable = forwardRef(
propertyLabel: prop.label propertyLabel: prop.label
}) })
columnConfig.filteredValue = fromFilterExpression( columnConfig.filteredValue = fromFilterExpression(
sidebarFilter[prop.name] effectiveFilter[prop.name]
) )
} }
@ -1670,7 +1894,7 @@ const ObjectTable = forwardRef(
{showSortSidebar && ( {showSortSidebar && (
<SortSidebar <SortSidebar
type={type} type={type}
sorter={tableSorter} sorter={effectiveSorter}
onSortChange={handleSidebarSortChange} onSortChange={handleSidebarSortChange}
stretchHeight={showSortSidebar && !showFilterSidebar} stretchHeight={showSortSidebar && !showFilterSidebar}
/> />
@ -1679,7 +1903,7 @@ const ObjectTable = forwardRef(
<Flex style={{ flex: 1, minHeight: 0 }}> <Flex style={{ flex: 1, minHeight: 0 }}>
<FilterSidebar <FilterSidebar
type={type} type={type}
filter={sidebarFilter} filter={effectiveFilter}
onFilterChange={handleSidebarFilterChange} onFilterChange={handleSidebarFilterChange}
masterFilter={masterFilter} masterFilter={masterFilter}
/> />
@ -1726,8 +1950,6 @@ ObjectTable.propTypes = {
saveSortInUrl: PropTypes.bool, saveSortInUrl: PropTypes.bool,
useSortInSession: PropTypes.bool, useSortInSession: PropTypes.bool,
useSortInUrl: PropTypes.bool, useSortInUrl: PropTypes.bool,
activeObjectView: PropTypes.object,
onObjectViewFilterSortChange: PropTypes.func,
onRowAction: PropTypes.func onRowAction: PropTypes.func
} }

View File

@ -7,6 +7,7 @@ import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext' import { AuthContext } from '../context/AuthContext'
import { import {
getActiveFilterValues, getActiveFilterValues,
useTableState,
useTableStatePersistence useTableStatePersistence
} from '../context/TableStateContext' } from '../context/TableStateContext'
import KeyboardShortcut from './KeyboardShortcut.jsx' import KeyboardShortcut from './KeyboardShortcut.jsx'
@ -25,6 +26,7 @@ const ObjectTableNavigationButtons = ({
const [neighbors, setNeighbors] = useState({ next: null, previous: null }) const [neighbors, setNeighbors] = useState({ next: null, previous: null })
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const { getObjectListFilter, getObjectListSorter } = useTableState()
const { getPersistedFilter, getPersistedSorter } = useTableStatePersistence({ const { getPersistedFilter, getPersistedSorter } = useTableStatePersistence({
scope: objectType, scope: objectType,
useFilterInSession: true, useFilterInSession: true,
@ -34,6 +36,12 @@ const ObjectTableNavigationButtons = ({
const getObjectNeighborsRef = useRef(getObjectNeighbors) const getObjectNeighborsRef = useRef(getObjectNeighbors)
getObjectNeighborsRef.current = getObjectNeighbors getObjectNeighborsRef.current = getObjectNeighbors
const getObjectListFilterRef = useRef(getObjectListFilter)
getObjectListFilterRef.current = getObjectListFilter
const getObjectListSorterRef = useRef(getObjectListSorter)
getObjectListSorterRef.current = getObjectListSorter
const getPersistedFilterRef = useRef(getPersistedFilter) const getPersistedFilterRef = useRef(getPersistedFilter)
getPersistedFilterRef.current = getPersistedFilter getPersistedFilterRef.current = getPersistedFilter
@ -51,8 +59,21 @@ const ObjectTableNavigationButtons = ({
const loadNeighbors = async () => { const loadNeighbors = async () => {
setLoading(true) setLoading(true)
const filter = getActiveFilterValues(getPersistedFilterRef.current()) // Prefer the effective list filter (view + user filters) when available
const sorter = getPersistedSorterRef.current() const listFilter = getActiveFilterValues(
getObjectListFilterRef.current(objectType)
)
const persistedFilter = getActiveFilterValues(
getPersistedFilterRef.current()
)
const filter =
Object.keys(listFilter).length > 0 ? listFilter : persistedFilter
const listSorter = getObjectListSorterRef.current(objectType)
const persistedSorter = getPersistedSorterRef.current()
const sorter =
listSorter?.field && listSorter?.order ? listSorter : persistedSorter
const result = await getObjectNeighborsRef.current(objectType, { const result = await getObjectNeighborsRef.current(objectType, {
id: _id, id: _id,
filter, filter,

View File

@ -60,7 +60,8 @@ const SegmentedNav = ({
onChange, onChange,
onReorder, onReorder,
className, className,
disabled = false disabled = false,
animated = true
}) => { }) => {
const groupRef = useRef(null) const groupRef = useRef(null)
const thumbRef = useRef(null) const thumbRef = useRef(null)
@ -95,6 +96,12 @@ const SegmentedNav = ({
const toMetrics = getItemMetrics(itemRefs.current.get(value)) const toMetrics = getItemMetrics(itemRefs.current.get(value))
prevValueRef.current = value prevValueRef.current = value
if (!animated) {
setIsAnimating(false)
setThumbRect(null)
return undefined
}
if (!fromMetrics || !toMetrics) { if (!fromMetrics || !toMetrics) {
return undefined return undefined
} }
@ -119,7 +126,7 @@ const SegmentedNav = ({
cancelAnimationFrame(startFrame) cancelAnimationFrame(startFrame)
cancelAnimationFrame(endFrame) cancelAnimationFrame(endFrame)
} }
}, [value]) }, [value, animated])
const finishAnimation = useCallback(() => { const finishAnimation = useCallback(() => {
setIsAnimating(false) setIsAnimating(false)
@ -425,7 +432,8 @@ SegmentedNav.propTypes = {
onChange: PropTypes.func, onChange: PropTypes.func,
onReorder: PropTypes.func, onReorder: PropTypes.func,
className: PropTypes.string, className: PropTypes.string,
disabled: PropTypes.bool disabled: PropTypes.bool,
animated: PropTypes.bool
} }
export default SegmentedNav export default SegmentedNav

View File

@ -17,6 +17,56 @@ const ObjectListViewContext = createContext()
const ALL_TAB_KEY = 'all' const ALL_TAB_KEY = 'all'
const getLastViewStorageKey = (objectType) =>
`objectListView:${objectType}:lastViewId`
const getViewsCacheKey = (objectType) =>
`objectListView:${objectType}:views`
const readLastViewId = (objectType) => {
if (!objectType) return null
try {
return sessionStorage.getItem(getLastViewStorageKey(objectType)) || null
} catch {
return null
}
}
const writeLastViewId = (objectType, viewId) => {
if (!objectType) return
try {
const key = getLastViewStorageKey(objectType)
if (viewId) {
sessionStorage.setItem(key, String(viewId))
} else {
sessionStorage.removeItem(key)
}
} catch {
// Ignore sessionStorage failures (private mode, quota, etc.)
}
}
const readCachedViews = (objectType) => {
if (!objectType) return null
try {
const raw = sessionStorage.getItem(getViewsCacheKey(objectType))
if (raw == null) return null
const parsed = JSON.parse(raw)
return Array.isArray(parsed) ? parsed : null
} catch {
return null
}
}
const writeCachedViews = (objectType, views) => {
if (!objectType) return
try {
sessionStorage.setItem(getViewsCacheKey(objectType), JSON.stringify(views))
} catch {
// Ignore sessionStorage failures (private mode, quota, etc.)
}
}
const getPreviousTabKey = (viewList, deletedKey) => { const getPreviousTabKey = (viewList, deletedKey) => {
const index = viewList.findIndex( const index = viewList.findIndex(
(view) => String(view._id) === String(deletedKey) (view) => String(view._id) === String(deletedKey)
@ -35,6 +85,9 @@ const DEFAULT_VIEW = {
sort: {} sort: {}
} }
const EMPTY_FILTER = {}
const EMPTY_SORT = {}
// eslint-disable-next-line react-refresh/only-export-components // eslint-disable-next-line react-refresh/only-export-components
export const getObjectViewKey = (view) => export const getObjectViewKey = (view) =>
view?._id != null ? String(view._id) : null view?._id != null ? String(view._id) : null
@ -62,8 +115,7 @@ const viewStateEqual = (left, right) =>
export const ObjectListViewProvider = ({ export const ObjectListViewProvider = ({
children, children,
objectType, objectType,
tableRef, tableRef
onViewStateChange
}) => { }) => {
const { const {
fetchObjectViews, fetchObjectViews,
@ -77,12 +129,21 @@ export const ObjectListViewProvider = ({
const { token, authInitialized } = useContext(AuthContext) const { token, authInitialized } = useContext(AuthContext)
const { getViewFromUrl, persistView } = useTableState() const { getViewFromUrl, persistView } = useTableState()
const [views, setViews] = useState([]) const [views, setViews] = useState(
const [draftViews, setDraftViews] = useState([]) () => readCachedViews(objectType) || []
const [initialLoading, setInitialLoading] = useState(true) )
const [draftViews, setDraftViews] = useState(() => {
const cached = readCachedViews(objectType)
return cached ? cloneViews(cached) : []
})
const [initialLoading, setInitialLoading] = useState(
() => readCachedViews(objectType) == null
)
const [viewsFetched, setViewsFetched] = useState(false)
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
const [activeTabKey, setActiveTabKey] = useState(ALL_TAB_KEY) const [activeTabKey, setActiveTabKey] = useState(ALL_TAB_KEY)
const [isEditing, setIsEditing] = useState(false) const [isEditing, setIsEditing] = useState(false)
const [viewSyncReady, setViewSyncReady] = useState(false)
const editSnapshotRef = useRef([]) const editSnapshotRef = useRef([])
const wasEditingRef = useRef(false) const wasEditingRef = useRef(false)
@ -140,15 +201,22 @@ export const ObjectListViewProvider = ({
if (tabKey !== ALL_TAB_KEY && !view) return if (tabKey !== ALL_TAB_KEY && !view) return
// "All" outside edit mode restores the user's persisted filter/sort // "All" restores the user's personal filter/sort from URL/session
if (tabKey === ALL_TAB_KEY && !editing) { if (tabKey === ALL_TAB_KEY && !editing) {
tableRef.current.applyViewState(null, null) tableRef.current.applyViewState(null, null, { forceAll: true })
return return
} }
// Views apply their own filter/sort into the table (and filter context).
// They are never written to the filter/sort URL params.
tableRef.current.applyViewState( tableRef.current.applyViewState(
view?.filter || {}, view?.filter || {},
view?.sort?.field ? view.sort : {} view?.sort?.field ? view.sort : {},
{
viewId: view?._id != null ? String(view._id) : null,
viewFilter: view?.filter || {},
viewSort: view?.sort?.field ? view.sort : {}
}
) )
}, },
[tableRef] [tableRef]
@ -157,18 +225,23 @@ export const ObjectListViewProvider = ({
const loadViews = useCallback( const loadViews = useCallback(
async (silent = false) => { async (silent = false) => {
if (!authReady || !objectType) return if (!authReady || !objectType) return
if (!silent) setInitialLoading(true) const hasCache = readCachedViews(objectType) != null
// Keep showing cached tabs while refreshing; only spin when nothing to show
if (!silent && !hasCache) setInitialLoading(true)
try { try {
const { data } = await apiRef.current.fetchObjectViews(objectType) const { data } = await apiRef.current.fetchObjectViews(objectType)
const nextViews = data || [] const nextViews = data || []
setViews(nextViews) setViews(nextViews)
writeCachedViews(objectType, nextViews)
if (!isEditingRef.current) { if (!isEditingRef.current) {
setDraftViews(cloneViews(nextViews)) setDraftViews(cloneViews(nextViews))
} }
setViewsFetched(true)
return nextViews return nextViews
} catch (error) { } catch (error) {
console.error('Error fetching object views:', error) console.error('Error fetching object views:', error)
return [] setViewsFetched(true)
return hasCache ? readCachedViews(objectType) || [] : []
} finally { } finally {
if (!silent) setInitialLoading(false) if (!silent) setInitialLoading(false)
} }
@ -179,54 +252,109 @@ export const ObjectListViewProvider = ({
const loadViewsRef = useRef(loadViews) const loadViewsRef = useRef(loadViews)
loadViewsRef.current = loadViews loadViewsRef.current = loadViews
const rememberActiveView = useCallback(
(viewId) => {
const key = viewId ? String(viewId) : null
persistView(key)
writeLastViewId(objectType, key)
},
[objectType, persistView]
)
useEffect(() => { useEffect(() => {
urlSyncedRef.current = false urlSyncedRef.current = false
setViewSyncReady(false)
setViewsFetched(false)
setActiveTabKey(ALL_TAB_KEY) setActiveTabKey(ALL_TAB_KEY)
const cached = readCachedViews(objectType)
if (cached) {
setViews(cached)
if (!isEditingRef.current) {
setDraftViews(cloneViews(cached))
}
setInitialLoading(false)
} else {
setViews([])
setDraftViews([])
setInitialLoading(true)
}
}, [objectType]) }, [objectType])
useEffect(() => { useEffect(() => {
loadViews() loadViews()
}, [loadViews]) }, [loadViews])
// Keep the local cache in sync with authoritative (non-draft) views
useEffect(() => { useEffect(() => {
if (initialLoading) return if (!objectType || initialLoading) return
writeCachedViews(objectType, views)
}, [objectType, views, initialLoading])
useEffect(() => {
if (initialLoading || !viewSyncReady) return
applyViewToTable(activeTabKey) applyViewToTable(activeTabKey)
}, [activeTabKey, applyViewToTable, initialLoading, isEditing]) }, [
activeTabKey,
applyViewToTable,
initialLoading,
isEditing,
viewSyncReady,
viewsFetched
])
useEffect(() => { useEffect(() => {
if (initialLoading || urlSyncedRef.current) return if (urlSyncedRef.current) return
const viewId = getViewFromUrl() // Allow early restore from cache; only block when we have nothing to match against yet
if (!viewId) { if (initialLoading && views.length === 0) return
const urlViewId = getViewFromUrl()
const rememberedViewId = readLastViewId(objectType)
const candidateViewId = urlViewId || rememberedViewId
if (!candidateViewId) {
urlSyncedRef.current = true urlSyncedRef.current = true
setViewSyncReady(true)
return return
} }
const matched = const matched =
resolveViewFromId(views, viewId) || resolveViewFromId(views, candidateViewId) ||
resolveViewFromId(draftViews, viewId) resolveViewFromId(draftViews, candidateViewId)
if (matched) { if (matched) {
setActiveTabKey(String(matched._id)) const matchedId = String(matched._id)
setActiveTabKey(matchedId)
writeLastViewId(objectType, matchedId)
if (!matched._isDraft) {
// Keep viewId in the URL and strip any leftover filter/sort params
persistView(matchedId)
}
urlSyncedRef.current = true urlSyncedRef.current = true
setViewSyncReady(true)
return return
} }
// Wait until views have loaded before deciding the URL viewId is invalid // Wait until views have loaded from the network before deciding the candidate is invalid
if (views.length === 0) return if (!viewsFetched) return
if (!isEditing) { if (!isEditing) {
persistView(null) rememberActiveView(null)
} }
urlSyncedRef.current = true urlSyncedRef.current = true
setViewSyncReady(true)
}, [ }, [
initialLoading, initialLoading,
viewsFetched,
views, views,
draftViews, draftViews,
isEditing, isEditing,
objectType,
getViewFromUrl, getViewFromUrl,
persistView persistView,
rememberActiveView
]) ])
const selectTab = useCallback( const selectTab = useCallback(
@ -236,7 +364,7 @@ export const ObjectListViewProvider = ({
setActiveTabKey(tabKey) setActiveTabKey(tabKey)
if (tabKey === ALL_TAB_KEY) { if (tabKey === ALL_TAB_KEY) {
persistView(null) rememberActiveView(null)
return return
} }
@ -245,9 +373,9 @@ export const ObjectListViewProvider = ({
) )
if (!view || view._isDraft) return if (!view || view._isDraft) return
persistView(getObjectViewKey(view)) rememberActiveView(getObjectViewKey(view))
}, },
[activeTabKey, draftViews, isEditing, persistView, views] [activeTabKey, draftViews, isEditing, rememberActiveView, views]
) )
useEffect(() => { useEffect(() => {
@ -278,13 +406,13 @@ export const ObjectListViewProvider = ({
) )
if (!stillExists) { if (!stillExists) {
setActiveTabKey(ALL_TAB_KEY) setActiveTabKey(ALL_TAB_KEY)
persistView(null) rememberActiveView(null)
applyViewToTable(ALL_TAB_KEY) applyViewToTable(ALL_TAB_KEY)
} }
} }
await loadViewsRef.current(true) await loadViewsRef.current(true)
}, [activeTabKey, applyViewToTable, persistView]) }, [activeTabKey, applyViewToTable, rememberActiveView])
const saveEdits = useCallback(async () => { const saveEdits = useCallback(async () => {
setSaving(true) setSaving(true)
@ -355,11 +483,11 @@ export const ObjectListViewProvider = ({
if (resolvedTabKey !== ALL_TAB_KEY && savedView && !savedView._isDraft) { if (resolvedTabKey !== ALL_TAB_KEY && savedView && !savedView._isDraft) {
setActiveTabKey(resolvedTabKey) setActiveTabKey(resolvedTabKey)
persistView(getObjectViewKey(savedView)) rememberActiveView(getObjectViewKey(savedView))
} else if (resolvedTabKey !== ALL_TAB_KEY && !savedView) { } else if (resolvedTabKey !== ALL_TAB_KEY && !savedView) {
resolvedTabKey = ALL_TAB_KEY resolvedTabKey = ALL_TAB_KEY
setActiveTabKey(ALL_TAB_KEY) setActiveTabKey(ALL_TAB_KEY)
persistView(null) rememberActiveView(null)
} }
message.success('Views saved') message.success('Views saved')
@ -373,7 +501,7 @@ export const ObjectListViewProvider = ({
activeTabKey, activeTabKey,
draftViews, draftViews,
objectType, objectType,
persistView, rememberActiveView,
views views
]) ])
@ -407,7 +535,7 @@ export const ObjectListViewProvider = ({
const newKey = String(created._id) const newKey = String(created._id)
setActiveTabKey(newKey) setActiveTabKey(newKey)
applyViewToTable(newKey) applyViewToTable(newKey)
persistView(getObjectViewKey(created)) rememberActiveView(getObjectViewKey(created))
} else { } else {
message.error('Failed to create view') message.error('Failed to create view')
} }
@ -437,13 +565,13 @@ export const ObjectListViewProvider = ({
if (isActiveDeleted) { if (isActiveDeleted) {
setActiveTabKey(previousKey) setActiveTabKey(previousKey)
if (previousKey === ALL_TAB_KEY) { if (previousKey === ALL_TAB_KEY) {
persistView(null) rememberActiveView(null)
} else { } else {
const view = draftViews.find( const view = draftViews.find(
(item) => String(item._id) === String(previousKey) (item) => String(item._id) === String(previousKey)
) )
if (view && !view._isDraft) { if (view && !view._isDraft) {
persistView(getObjectViewKey(view)) rememberActiveView(getObjectViewKey(view))
} }
} }
applyViewToTable(previousKey) applyViewToTable(previousKey)
@ -456,7 +584,7 @@ export const ObjectListViewProvider = ({
draftViews, draftViews,
isEditing, isEditing,
objectType, objectType,
persistView, rememberActiveView,
views views
] ]
) )
@ -531,19 +659,19 @@ export const ObjectListViewProvider = ({
if (isActiveDeleted) { if (isActiveDeleted) {
setActiveTabKey(previousKey) setActiveTabKey(previousKey)
if (previousKey === ALL_TAB_KEY) { if (previousKey === ALL_TAB_KEY) {
persistView(null) rememberActiveView(null)
} else { } else {
const view = list.find( const view = list.find(
(item) => String(item._id) === String(previousKey) (item) => String(item._id) === String(previousKey)
) )
if (view && !view._isDraft) { if (view && !view._isDraft) {
persistView(getObjectViewKey(view)) rememberActiveView(getObjectViewKey(view))
} }
} }
applyViewToTable(previousKey) applyViewToTable(previousKey)
} }
}, },
[activeTabKey, applyViewToTable, draftViews, isEditing, persistView, views] [activeTabKey, applyViewToTable, draftViews, isEditing, rememberActiveView, views]
) )
const handleFilterSortChange = useCallback((filter, sorter) => { const handleFilterSortChange = useCallback((filter, sorter) => {
@ -682,40 +810,17 @@ export const ObjectListViewProvider = ({
[] []
) )
const handleFilterSortChangeRef = useRef(handleFilterSortChange) const listViewId =
handleFilterSortChangeRef.current = handleFilterSortChange activeTabKey !== ALL_TAB_KEY && activeTabKey != null
? String(activeTabKey)
const stableFilterSortHandlerRef = useRef((filter, sorter) => { : null
handleFilterSortChangeRef.current?.(filter, sorter) const listViewFilter = activeView?.filter || EMPTY_FILTER
}) const listViewSort = activeView?.sort?.field
? activeView.sort
const lastSyncedViewKeyRef = useRef(null) : EMPTY_SORT
// Only expose the editable view while editing — ObjectTable uses this to
useEffect(() => { // route filter/sort changes into the draft instead of URL/session persistence.
const viewKey = isEditing const activeObjectView = isEditing ? activeView : null
? `edit:${activeView?._id ?? activeTabKey}`
: activeView?._id != null
? String(activeView._id)
: activeTabKey === ALL_TAB_KEY
? 'all'
: null
if (viewKey === lastSyncedViewKeyRef.current) return
lastSyncedViewKeyRef.current = viewKey
onViewStateChange?.({
activeView: isEditing ? activeViewRef.current : null,
isEditing,
handleFilterSortChange: isEditing
? stableFilterSortHandlerRef.current
: null
})
}, [
activeTabKey,
activeView?._id,
isEditing,
onViewStateChange
])
const viewTabSignatures = useMemo( const viewTabSignatures = useMemo(
() => displayedViews.map(getViewTabSignature).join('|'), () => displayedViews.map(getViewTabSignature).join('|'),
@ -728,7 +833,11 @@ export const ObjectListViewProvider = ({
ALL_TAB_KEY, ALL_TAB_KEY,
views: displayedViews, views: displayedViews,
activeView, activeView,
activeObjectView,
activeTabKey, activeTabKey,
listViewId,
listViewFilter,
listViewSort,
initialLoading, initialLoading,
saving, saving,
isEditing, isEditing,
@ -749,7 +858,11 @@ export const ObjectListViewProvider = ({
objectType, objectType,
displayedViews, displayedViews,
activeView, activeView,
activeObjectView,
activeTabKey, activeTabKey,
listViewId,
listViewFilter,
listViewSort,
initialLoading, initialLoading,
saving, saving,
isEditing, isEditing,
@ -788,8 +901,7 @@ export const useObjectListView = () => {
ObjectListViewProvider.propTypes = { ObjectListViewProvider.propTypes = {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
objectType: PropTypes.string.isRequired, objectType: PropTypes.string.isRequired,
tableRef: PropTypes.object, tableRef: PropTypes.object
onViewStateChange: PropTypes.func
} }
// eslint-disable-next-line react-refresh/only-export-components // eslint-disable-next-line react-refresh/only-export-components

View File

@ -3,6 +3,7 @@ import {
useCallback, useCallback,
useContext, useContext,
useMemo, useMemo,
useRef,
useState useState
} from 'react' } from 'react'
import { useSearchParams } from 'react-router-dom' import { useSearchParams } from 'react-router-dom'
@ -16,6 +17,8 @@ export const VIEW_URL_PARAM = 'viewId'
const getSessionFilterKey = (scope) => `tableState:${scope}:filter` const getSessionFilterKey = (scope) => `tableState:${scope}:filter`
const getSessionSortKey = (scope) => `tableState:${scope}:sort` const getSessionSortKey = (scope) => `tableState:${scope}:sort`
const getSessionListFilterKey = (scope) => `tableState:${scope}:listFilter`
const getSessionListSortKey = (scope) => `tableState:${scope}:listSort`
// eslint-disable-next-line react-refresh/only-export-components // eslint-disable-next-line react-refresh/only-export-components
export const getActiveFilterValues = (filterState) => { export const getActiveFilterValues = (filterState) => {
@ -89,6 +92,42 @@ const writeSortToSession = (scope, sorter) => {
} }
} }
const readListFilterFromSession = (scope) => {
try {
return parseJsonParam(sessionStorage.getItem(getSessionListFilterKey(scope)))
} catch {
return null
}
}
const readListSortFromSession = (scope) => {
try {
const parsed = parseJsonParam(sessionStorage.getItem(getSessionListSortKey(scope)))
if (!parsed?.field || !parsed?.order) return null
return { field: parsed.field, order: parsed.order }
} catch {
return null
}
}
const writeListFilterToSession = (scope, filter) => {
const key = getSessionListFilterKey(scope)
if (Object.keys(filter).length > 0) {
sessionStorage.setItem(key, JSON.stringify(filter))
} else {
sessionStorage.removeItem(key)
}
}
const writeListSortToSession = (scope, sorter) => {
const key = getSessionListSortKey(scope)
if (sorter?.field && sorter?.order) {
sessionStorage.setItem(key, JSON.stringify(sorter))
} else {
sessionStorage.removeItem(key)
}
}
const normalizeSorter = (sorter) => { const normalizeSorter = (sorter) => {
if (sorter?.field && sorter?.order) { if (sorter?.field && sorter?.order) {
return { field: sorter.field, order: sorter.order } return { field: sorter.field, order: sorter.order }
@ -100,6 +139,24 @@ export const TableStateProvider = ({ children }) => {
const [searchParams, setSearchParams] = useSearchParams() const [searchParams, setSearchParams] = useSearchParams()
const [pageFilters, setPageFilters] = useState({}) const [pageFilters, setPageFilters] = useState({})
const [pageSorters, setPageSorters] = useState({}) const [pageSorters, setPageSorters] = useState({})
// Effective list filters (view filter + user filters). Survives navigating
// from the list page to an info page so breadcrumb/neighbors keep working.
const [objectListFilters, setObjectListFilters] = useState({})
const [objectListSorters, setObjectListSorters] = useState({})
const searchParamsRef = useRef(searchParams)
searchParamsRef.current = searchParams
// Keep sequential URL writes in the same tick from clobbering each other
// (e.g. persistView then persistTableState both calling setSearchParams).
const updateSearchParams = useCallback(
(mutator) => {
const next = new URLSearchParams(searchParamsRef.current)
mutator(next)
searchParamsRef.current = next
setSearchParams(next, { replace: true })
},
[setSearchParams]
)
const getPersistedFilter = useCallback( const getPersistedFilter = useCallback(
(scope, { useFilterInUrl = false, useFilterInSession = false } = {}) => { (scope, { useFilterInUrl = false, useFilterInSession = false } = {}) => {
@ -137,18 +194,23 @@ export const TableStateProvider = ({ children }) => {
) )
const persistView = useCallback( const persistView = useCallback(
(viewId) => { (viewId, { clearFilterSort = Boolean(viewId) } = {}) => {
const next = new URLSearchParams(searchParams) updateSearchParams((next) => {
// Drop legacy `view` param that previously stored `_reference` // Drop legacy `view` param that previously stored `_reference`
next.delete('view') next.delete('view')
if (viewId) { if (viewId) {
next.set(VIEW_URL_PARAM, String(viewId)) next.set(VIEW_URL_PARAM, String(viewId))
} else { } else {
next.delete(VIEW_URL_PARAM) next.delete(VIEW_URL_PARAM)
} }
setSearchParams(next, { replace: true }) // View filter/sort live on the view object — never in the URL
if (clearFilterSort) {
next.delete(FILTER_URL_PARAM)
next.delete(SORT_URL_PARAM)
}
})
}, },
[searchParams, setSearchParams] [updateSearchParams]
) )
const persistFilter = useCallback( const persistFilter = useCallback(
@ -162,16 +224,16 @@ export const TableStateProvider = ({ children }) => {
writeFilterToSession(scope, active) writeFilterToSession(scope, active)
} }
if (saveFilterInUrl) { if (saveFilterInUrl) {
const next = new URLSearchParams(searchParams) updateSearchParams((next) => {
if (Object.keys(active).length > 0) { if (Object.keys(active).length > 0) {
next.set(FILTER_URL_PARAM, JSON.stringify(active)) next.set(FILTER_URL_PARAM, JSON.stringify(active))
} else { } else {
next.delete(FILTER_URL_PARAM) next.delete(FILTER_URL_PARAM)
} }
setSearchParams(next, { replace: true }) })
} }
}, },
[searchParams, setSearchParams] [updateSearchParams]
) )
const persistSort = useCallback( const persistSort = useCallback(
@ -185,16 +247,16 @@ export const TableStateProvider = ({ children }) => {
writeSortToSession(scope, nextSorter) writeSortToSession(scope, nextSorter)
} }
if (saveSortInUrl) { if (saveSortInUrl) {
const next = new URLSearchParams(searchParams) updateSearchParams((next) => {
if (nextSorter.field && nextSorter.order) { if (nextSorter.field && nextSorter.order) {
next.set(SORT_URL_PARAM, JSON.stringify(nextSorter)) next.set(SORT_URL_PARAM, JSON.stringify(nextSorter))
} else { } else {
next.delete(SORT_URL_PARAM) next.delete(SORT_URL_PARAM)
} }
setSearchParams(next, { replace: true }) })
} }
}, },
[searchParams, setSearchParams] [updateSearchParams]
) )
const persistTableState = useCallback( const persistTableState = useCallback(
@ -220,25 +282,25 @@ export const TableStateProvider = ({ children }) => {
} }
if (saveFilterInUrl || saveSortInUrl) { if (saveFilterInUrl || saveSortInUrl) {
const next = new URLSearchParams(searchParams) updateSearchParams((next) => {
if (saveFilterInUrl) { if (saveFilterInUrl) {
if (Object.keys(active).length > 0) { if (Object.keys(active).length > 0) {
next.set(FILTER_URL_PARAM, JSON.stringify(active)) next.set(FILTER_URL_PARAM, JSON.stringify(active))
} else { } else {
next.delete(FILTER_URL_PARAM) next.delete(FILTER_URL_PARAM)
}
} }
} if (saveSortInUrl) {
if (saveSortInUrl) { if (nextSorter.field && nextSorter.order) {
if (nextSorter.field && nextSorter.order) { next.set(SORT_URL_PARAM, JSON.stringify(nextSorter))
next.set(SORT_URL_PARAM, JSON.stringify(nextSorter)) } else {
} else { next.delete(SORT_URL_PARAM)
next.delete(SORT_URL_PARAM) }
} }
} })
setSearchParams(next, { replace: true })
} }
}, },
[searchParams, setSearchParams] [updateSearchParams]
) )
const setPageFilter = useCallback((path, filter) => { const setPageFilter = useCallback((path, filter) => {
@ -268,12 +330,71 @@ export const TableStateProvider = ({ children }) => {
}) })
}, []) }, [])
const setObjectListFilter = useCallback((objectType, filter) => {
if (!objectType) return
const active = getActiveFilterValues(filter)
writeListFilterToSession(objectType, active)
setObjectListFilters((prev) => {
const hasActive = Object.keys(active).length > 0
if (!hasActive) {
if (!(objectType in prev)) return prev
const next = { ...prev }
delete next[objectType]
return next
}
return { ...prev, [objectType]: active }
})
}, [])
const setObjectListSorter = useCallback((objectType, sorter) => {
if (!objectType) return
const nextSorter = normalizeSorter(sorter)
writeListSortToSession(objectType, nextSorter)
setObjectListSorters((prev) => {
const hasSort = nextSorter?.field && nextSorter?.order
if (!hasSort) {
if (!(objectType in prev)) return prev
const next = { ...prev }
delete next[objectType]
return next
}
return { ...prev, [objectType]: nextSorter }
})
}, [])
const getObjectListFilter = useCallback(
(objectType) => {
if (!objectType) return {}
if (objectListFilters[objectType]) {
return objectListFilters[objectType]
}
return getActiveFilterValues(readListFilterFromSession(objectType) || {})
},
[objectListFilters]
)
const getObjectListSorter = useCallback(
(objectType) => {
if (!objectType) return {}
if (objectListSorters[objectType]) {
return objectListSorters[objectType]
}
return readListSortFromSession(objectType) || {}
},
[objectListSorters]
)
const hasPageFilter = useCallback( const hasPageFilter = useCallback(
(path) => Object.keys(pageFilters[path] || {}).length > 0, (path) => Object.keys(pageFilters[path] || {}).length > 0,
[pageFilters] [pageFilters]
) )
const hasStoredFilter = useCallback((scope) => hasStoredSessionFilter(scope), []) const hasStoredFilter = useCallback((scope) => {
if (!scope) return false
if (hasStoredSessionFilter(scope)) return true
if (Object.keys(objectListFilters[scope] || {}).length > 0) return true
return Object.keys(getActiveFilterValues(readListFilterFromSession(scope) || {})).length > 0
}, [objectListFilters])
const value = useMemo( const value = useMemo(
() => ({ () => ({
@ -286,10 +407,16 @@ export const TableStateProvider = ({ children }) => {
persistTableState, persistTableState,
setPageFilter, setPageFilter,
setPageSorter, setPageSorter,
setObjectListFilter,
setObjectListSorter,
getObjectListFilter,
getObjectListSorter,
hasPageFilter, hasPageFilter,
hasStoredFilter, hasStoredFilter,
pageFilters, pageFilters,
pageSorters pageSorters,
objectListFilters,
objectListSorters
}), }),
[ [
getPersistedFilter, getPersistedFilter,
@ -301,10 +428,16 @@ export const TableStateProvider = ({ children }) => {
persistTableState, persistTableState,
setPageFilter, setPageFilter,
setPageSorter, setPageSorter,
setObjectListFilter,
setObjectListSorter,
getObjectListFilter,
getObjectListSorter,
hasPageFilter, hasPageFilter,
hasStoredFilter, hasStoredFilter,
pageFilters, pageFilters,
pageSorters pageSorters,
objectListFilters,
objectListSorters
] ]
) )
@ -327,6 +460,7 @@ export const useTableState = () => {
// eslint-disable-next-line react-refresh/only-export-components // eslint-disable-next-line react-refresh/only-export-components
export const useTableStatePersistence = ({ export const useTableStatePersistence = ({
scope, scope,
viewId = null,
pagePath, pagePath,
saveFilterInSession = false, saveFilterInSession = false,
saveFilterInUrl = false, saveFilterInUrl = false,
@ -344,15 +478,58 @@ export const useTableStatePersistence = ({
persistSort: persistSortCtx, persistSort: persistSortCtx,
persistTableState: persistTableStateCtx, persistTableState: persistTableStateCtx,
setPageFilter, setPageFilter,
setPageSorter setPageSorter,
setObjectListFilter,
setObjectListSorter
} = useTableState() } = useTableState()
// View filter/sort belong to the view object — never read/write them via
// the shared filter/sort URL or session keys used by the "All" tab.
const isViewScope = Boolean(viewId)
const readOptions = useMemo( const readOptions = useMemo(
() => ({ useFilterInUrl, useFilterInSession, useSortInUrl, useSortInSession }), () => ({
[useFilterInUrl, useFilterInSession, useSortInUrl, useSortInSession] useFilterInUrl: isViewScope ? false : useFilterInUrl,
useFilterInSession: isViewScope ? false : useFilterInSession,
useSortInUrl: isViewScope ? false : useSortInUrl,
useSortInSession: isViewScope ? false : useSortInSession
}),
[
isViewScope,
useFilterInUrl,
useFilterInSession,
useSortInUrl,
useSortInSession
]
) )
const saveOptions = useMemo( const saveOptions = useMemo(
() => ({
saveFilterInSession: isViewScope ? false : saveFilterInSession,
saveFilterInUrl: isViewScope ? false : saveFilterInUrl,
saveSortInSession: isViewScope ? false : saveSortInSession,
saveSortInUrl: isViewScope ? false : saveSortInUrl
}),
[
isViewScope,
saveFilterInSession,
saveFilterInUrl,
saveSortInSession,
saveSortInUrl
]
)
const allTabReadOptions = useMemo(
() => ({
useFilterInUrl,
useFilterInSession,
useSortInUrl,
useSortInSession
}),
[useFilterInUrl, useFilterInSession, useSortInUrl, useSortInSession]
)
const allTabSaveOptions = useMemo(
() => ({ () => ({
saveFilterInSession, saveFilterInSession,
saveFilterInUrl, saveFilterInUrl,
@ -372,6 +549,18 @@ export const useTableStatePersistence = ({
[getPersistedSorterCtx, scope, readOptions] [getPersistedSorterCtx, scope, readOptions]
) )
// Always reads the All-tab filter/sort, even while a view is still selected
// (used when switching back to All before listViewId has cleared).
const getAllTabPersistedFilter = useCallback(
() => getPersistedFilterCtx(scope, allTabReadOptions),
[getPersistedFilterCtx, scope, allTabReadOptions]
)
const getAllTabPersistedSorter = useCallback(
() => getPersistedSorterCtx(scope, allTabReadOptions),
[getPersistedSorterCtx, scope, allTabReadOptions]
)
const persistFilter = useCallback( const persistFilter = useCallback(
(filterState) => persistFilterCtx(scope, filterState, saveOptions), (filterState) => persistFilterCtx(scope, filterState, saveOptions),
[persistFilterCtx, scope, saveOptions] [persistFilterCtx, scope, saveOptions]
@ -388,6 +577,12 @@ export const useTableStatePersistence = ({
[persistTableStateCtx, scope, saveOptions] [persistTableStateCtx, scope, saveOptions]
) )
const persistAllTabTableState = useCallback(
(filterState, sorter) =>
persistTableStateCtx(scope, filterState, sorter, allTabSaveOptions),
[persistTableStateCtx, scope, allTabSaveOptions]
)
const registerPageFilter = useCallback( const registerPageFilter = useCallback(
(filterState) => { (filterState) => {
if (pagePath) { if (pagePath) {
@ -406,14 +601,38 @@ export const useTableStatePersistence = ({
[pagePath, setPageSorter] [pagePath, setPageSorter]
) )
const registerObjectListFilter = useCallback(
(filterState) => {
if (scope) {
setObjectListFilter(scope, filterState)
}
},
[scope, setObjectListFilter]
)
const registerObjectListSorter = useCallback(
(sorter) => {
if (scope) {
setObjectListSorter(scope, sorter)
}
},
[scope, setObjectListSorter]
)
return { return {
persistenceScope: scope,
getPersistedFilter, getPersistedFilter,
getPersistedSorter, getPersistedSorter,
getAllTabPersistedFilter,
getAllTabPersistedSorter,
persistFilter, persistFilter,
persistSort, persistSort,
persistTableState, persistTableState,
persistAllTabTableState,
registerPageFilter, registerPageFilter,
registerPageSorter, registerPageSorter,
registerObjectListFilter,
registerObjectListSorter,
getActiveFilterValues getActiveFilterValues
} }
} }