Refactor Dashboard Components to Integrate ListView Functionality

- Updated multiple dashboard components (Invoices, PaymentPolicies, Payments, TaxRecords, FilamentStocks, OrderItems, PartStocks, ProductStocks, PurchaseOrders, Shipments, StockAudits, StockEvents, StockLocations, StockTransfers, AppPasswords, AuditLogs) to incorporate ListViewTabs and ListViewEditButtons for enhanced user interaction.
- Introduced ObjectListViewProvider to manage view state and filter/sort changes across components, improving maintainability and user experience.
- Added state management for active views and filter/sort handling to streamline component functionality.
This commit is contained in:
Tom Butcher 2026-09-02 20:56:08 +01:00
parent 088ef79b11
commit 96b809b9d8
68 changed files with 3421 additions and 384 deletions

View File

@ -22,7 +22,7 @@
.ant-form-item-control-input,
.ant-input,
.ant-input-number .ant-input-number-input,
.ant-segmented-item-label,
.segmented-nav-item-label,
.ant-badge-status-text,
.ant-tree-title,
.ant-select,
@ -665,6 +665,11 @@ body {
bottom: 8px;
}
.scrollbox-horizontal > [data-simplebar],
.scrollbox-horizontal .simplebar-wrapper {
width: 100%;
}
.simplebar-scrollbar:before {
background: #78787854 !important;
}
@ -2544,3 +2549,247 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
height: 0;
pointer-events: none;
}
.list-view-tabs {
flex: 1;
min-width: 0;
}
.list-view-tabs .ant-input-sm {
border-radius: 0;
}
.list-view-tabs-spin {
flex: 1;
min-width: 0;
}
.list-view-tabs-spin > .ant-spin-container {
display: flex;
flex: 1;
min-width: 0;
}
.list-view-tabs-segmented-wrap {
flex: 1;
min-width: 0;
}
.list-view-tabs-segmented-wrap .simplebar-track.simplebar-vertical {
display: none;
}
.list-view-tabs-segmented-inner {
width: max-content;
}
.segmented-nav {
display: inline-flex;
width: max-content;
flex-shrink: 0;
padding: 0;
}
.segmented-nav-group {
position: relative;
display: flex;
align-items: center;
gap: 8px;
}
.segmented-nav-thumb {
position: absolute;
top: 0;
left: 0;
z-index: 0;
border-radius: 12px;
background: var(--color-button-background);
pointer-events: none;
will-change: transform, width;
transition:
transform 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
height 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.segmented-nav-item {
position: relative;
z-index: 1;
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
border: 1px solid var(--color-list-view-tabs-border);
border-radius: 12px;
background: transparent;
cursor: pointer;
font-family: inherit;
font-size: inherit;
line-height: inherit;
color: inherit;
box-shadow: none;
outline: none;
transition:
background 0.2s ease,
border 0.2s ease;
}
.segmented-nav-item-label {
position: relative;
z-index: 1;
display: flex;
align-items: center;
min-height: 30px;
line-height: 30px;
padding-inline: 12px;
}
.segmented-nav-item-icon {
padding-inline: 8px;
}
.segmented-nav-item-icon-contents {
position: relative;
z-index: 1;
display: flex;
align-items: center;
min-height: 30px;
line-height: 30px;
}
.segmented-nav-item:focus-visible {
outline: 2px solid
color-mix(in srgb, var(--color-primary, #1677ff) 45%, transparent);
outline-offset: 2px;
}
.segmented-nav-item-selected,
.segmented-nav-item:not(.segmented-nav-item-disabled):hover {
background: var(--color-button-background);
border: 1px solid var(--color-button-border);
}
.segmented-nav-item-disabled {
cursor: not-allowed;
opacity: 0.45;
}
.segmented-nav-disabled .segmented-nav-item {
cursor: not-allowed;
}
.list-view-tabs-label {
height: 30px;
}
.list-view-tabs-label-editing .ant-input {
font-size: inherit;
}
.list-view-tabs-label-editing {
margin: 0px -8px;
max-width: none;
min-width: 0;
}
.list-view-tabs-label-editing .list-view-tabs-name-input-wrap {
flex: 0 0 auto;
width: auto;
}
.list-view-tabs-name-input-wrap {
display: inline-block;
position: relative;
vertical-align: top;
min-width: 0;
}
.list-view-tabs-name-input-sizer {
visibility: hidden;
white-space: pre;
font-size: inherit;
line-height: inherit;
font-family: inherit;
min-height: 1em;
}
.list-view-tabs-label-editing .list-view-tabs-name-input {
position: absolute;
inset: 0;
width: 100%;
min-width: 0;
padding-inline: 0;
}
.list-view-tabs-color-dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
.list-view-tabs-editing
.segmented-nav-item
.ant-color-picker-trigger.ant-color-picker-sm {
border-radius: 8px;
}
.list-view-tabs-privacy-button,
.list-view-tabs-options-button {
padding-inline: 4px;
min-width: 20px;
}
.list-view-tabs-options-dropdown {
display: flex;
flex-direction: column;
}
.list-view-tabs-options-dropdown-privacy {
margin: 3px 12px 8px;
}
.segmented-nav-drag-handle {
flex-shrink: 0;
}
.segmented-nav-item-dragging {
opacity: 0.4;
}
.segmented-nav-item-drop-before::before,
.segmented-nav-item-drop-after::after {
content: '';
position: absolute;
top: 4px;
bottom: 4px;
width: 2px;
border-radius: 1px;
background: var(--color-primary, #1677ff);
pointer-events: none;
}
.segmented-nav-item-drop-before::before {
left: -5px;
}
.segmented-nav-item-drop-after::after {
right: -5px;
}
.segmented-nav-reordering
.segmented-nav-item:not(.segmented-nav-item-dragging) {
cursor: default;
}
.list-view-tabs-add-button {
padding-inline: 4px;
min-width: 20px;
}
.state-tag-loading svg path {
stroke: currentColor;
stroke-width: 12px;
}

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Invoices = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('invoices')
@ -30,8 +38,13 @@ const Invoices = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='invoice'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='invoice'
pageName='list'
@ -45,7 +58,8 @@ const Invoices = () => {
/>
<ExportListButton objectType='invoice' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const Invoices = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const Invoices = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PaymentPolicies = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('paymentPolicy')
const [columnVisibility, setColumnVisibility] =
useColumnVisibility('paymentPolicy')
@ -24,8 +32,13 @@ const PaymentPolicies = () => {
return (
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='paymentPolicy'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='paymentPolicy'
pageName='list'
@ -39,7 +52,8 @@ const PaymentPolicies = () => {
/>
<ExportListButton objectType='paymentPolicy' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -51,10 +65,11 @@ const PaymentPolicies = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -71,6 +86,8 @@ const PaymentPolicies = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
)

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Payments = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('payments')
@ -30,8 +38,13 @@ const Payments = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='payment'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='payment'
pageName='list'
@ -45,7 +58,8 @@ const Payments = () => {
/>
<ExportListButton objectType='payment' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const Payments = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const Payments = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const TaxRecords = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('taxRecord')
@ -30,8 +38,13 @@ const TaxRecords = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='taxRecord'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='taxRecord'
pageName='list'
@ -45,7 +58,8 @@ const TaxRecords = () => {
/>
<ExportListButton objectType='taxRecord' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const TaxRecords = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const TaxRecords = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/filamentStocks.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -15,9 +15,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FilamentStocks = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('filamentStocks')
@ -35,8 +43,13 @@ const FilamentStocks = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='filamentStock'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='filamentStock'
pageName='list'
@ -50,7 +63,8 @@ const FilamentStocks = () => {
/>
<ExportListButton objectType='filamentStock' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -62,10 +76,11 @@ const FilamentStocks = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -83,6 +98,8 @@ const FilamentStocks = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const OrderItems = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('orderItems')
@ -30,8 +38,13 @@ const OrderItems = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='orderItem'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='orderItem'
pageName='list'
@ -45,7 +58,8 @@ const OrderItems = () => {
/>
<ExportListButton objectType='orderItem' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const OrderItems = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const OrderItems = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/partStocks.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -15,9 +15,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PartStocks = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('partStocks')
@ -35,8 +43,13 @@ const PartStocks = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='partStock'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='partStock'
pageName='list'
@ -50,7 +63,8 @@ const PartStocks = () => {
/>
<ExportListButton objectType='partStock' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -62,10 +76,11 @@ const PartStocks = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -83,6 +98,8 @@ const PartStocks = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,7 +1,7 @@
// src/components/Dashboard/Inventory/ProductStocks.jsx
// ProductStocks - tracks assembled products consisting of part stocks
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -16,9 +16,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductStocks = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('productStocks')
@ -36,8 +44,13 @@ const ProductStocks = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='productStock'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='productStock'
pageName='list'
@ -51,7 +64,8 @@ const ProductStocks = () => {
/>
<ExportListButton objectType='productStock' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -63,10 +77,11 @@ const ProductStocks = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -84,6 +99,8 @@ const ProductStocks = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PurchaseOrders = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('purchaseOrders')
@ -30,8 +38,13 @@ const PurchaseOrders = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='purchaseOrder'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='purchaseOrder'
pageName='list'
@ -45,7 +58,8 @@ const PurchaseOrders = () => {
/>
<ExportListButton objectType='purchaseOrder' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const PurchaseOrders = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const PurchaseOrders = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Shipments = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('shipments')
@ -30,8 +38,13 @@ const Shipments = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='shipment'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='shipment'
pageName='list'
@ -45,7 +58,8 @@ const Shipments = () => {
/>
<ExportListButton objectType='shipment' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const Shipments = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const Shipments = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/stockAudits.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -15,9 +15,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockAudits = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockAudits')
@ -35,8 +43,13 @@ const StockAudits = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='stockAudit'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='stockAudit'
pageName='list'
@ -50,7 +63,8 @@ const StockAudits = () => {
/>
<ExportListButton objectType='stockAudit' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -62,10 +76,11 @@ const StockAudits = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -83,6 +98,8 @@ const StockAudits = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTable from '../common/ObjectTable'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockEvents = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockEvents')
const [columnVisibility, setColumnVisibility] =
@ -29,8 +37,13 @@ const StockEvents = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='stockEvent'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='stockEvent'
pageName='list'
@ -44,7 +57,8 @@ const StockEvents = () => {
/>
<ExportListButton objectType='stockEvent' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,10 +70,11 @@ const StockEvents = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -77,6 +92,8 @@ const StockEvents = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,9 +13,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockLocations = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockLocations')
@ -33,8 +41,13 @@ const StockLocations = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='stockLocation'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='stockLocation'
pageName='list'
@ -48,7 +61,8 @@ const StockLocations = () => {
/>
<ExportListButton objectType='stockLocation' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -60,10 +74,11 @@ const StockLocations = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -81,6 +96,8 @@ const StockLocations = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,9 +13,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockTransfers = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockTransfers')
@ -33,8 +41,13 @@ const StockTransfers = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='stockTransfer'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='stockTransfer'
pageName='list'
@ -48,7 +61,8 @@ const StockTransfers = () => {
/>
<ExportListButton objectType='stockTransfer' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -60,10 +74,11 @@ const StockTransfers = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -81,6 +96,8 @@ const StockTransfers = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
@ -11,9 +11,17 @@ import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const AppPasswords = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('appPassword')
const [columnVisibility, setColumnVisibility] =
@ -29,8 +37,13 @@ const AppPasswords = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='appPassword'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='appPassword'
pageName='list'
@ -44,7 +57,8 @@ const AppPasswords = () => {
/>
<ExportListButton objectType='appPassword' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,10 +70,11 @@ const AppPasswords = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -77,6 +92,8 @@ const AppPasswords = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility'
@ -10,9 +10,17 @@ import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const AuditLogs = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [columnVisibility, updateColumnVisibility] =
useColumnVisibility('auditLog')
@ -27,8 +35,13 @@ const AuditLogs = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='auditLog'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='auditLog'
pageName='list'
@ -42,7 +55,8 @@ const AuditLogs = () => {
/>
<ExportListButton objectType='auditLog' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -51,8 +65,10 @@ const AuditLogs = () => {
active={showFilterSidebar}
onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -69,6 +85,8 @@ const AuditLogs = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const CourierServices = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('courierService')
@ -30,8 +38,13 @@ const CourierServices = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='courierService'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='courierService'
pageName='list'
@ -45,7 +58,8 @@ const CourierServices = () => {
/>
<ExportListButton objectType='courierService' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const CourierServices = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const CourierServices = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Couriers = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('courier')
@ -29,8 +37,13 @@ const Couriers = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='courier'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='courier'
pageName='list'
@ -44,7 +57,8 @@ const Couriers = () => {
/>
<ExportListButton objectType='courier' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,10 +70,11 @@ const Couriers = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -76,6 +91,8 @@ const Couriers = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentJobs = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentJob')
@ -30,8 +38,13 @@ const DocumentJobs = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='documentJob'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='documentJob'
pageName='list'
@ -45,7 +58,8 @@ const DocumentJobs = () => {
/>
<ExportListButton objectType='documentJob' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const DocumentJobs = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const DocumentJobs = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentPrinters = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentPrinter')
const [columnVisibility, setColumnVisibility] =
@ -29,8 +37,13 @@ const DocumentPrinters = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='documentPrinter'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='documentPrinter'
pageName='list'
@ -44,7 +57,8 @@ const DocumentPrinters = () => {
/>
<ExportListButton objectType='documentPrinter' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,10 +70,11 @@ const DocumentPrinters = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -76,6 +91,8 @@ const DocumentPrinters = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentSizes = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentSize')
const [columnVisibility, setColumnVisibility] =
useColumnVisibility('documentSize')
@ -28,8 +36,13 @@ const DocumentSizes = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='documentSize'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='documentSize'
pageName='list'
@ -43,7 +56,8 @@ const DocumentSizes = () => {
/>
<ExportListButton objectType='documentSize' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -55,10 +69,11 @@ const DocumentSizes = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -75,6 +90,8 @@ const DocumentSizes = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentTemplates = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('documentTemplate')
@ -30,8 +38,13 @@ const DocumentTemplates = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='documentTemplate'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='documentTemplate'
pageName='list'
@ -45,7 +58,8 @@ const DocumentTemplates = () => {
/>
<ExportListButton objectType='documentTemplate' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const DocumentTemplates = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const DocumentTemplates = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,9 +13,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FilamentSkus = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('filamentSkus')
@ -33,8 +41,13 @@ const FilamentSkus = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='filamentSku'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='filamentSku'
pageName='list'
@ -48,7 +61,8 @@ const FilamentSkus = () => {
/>
<ExportListButton objectType='filamentSku' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -60,10 +74,11 @@ const FilamentSkus = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -81,6 +96,8 @@ const FilamentSkus = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/filaments.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,11 +13,19 @@ import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
const Filaments = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
// View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('filament')
@ -35,8 +43,13 @@ const Filaments = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='filament'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='filament'
pageName='list'
@ -50,7 +63,8 @@ const Filaments = () => {
/>
<ExportListButton objectType='filament' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -62,10 +76,11 @@ const Filaments = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -83,6 +98,8 @@ const Filaments = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>

View File

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

View File

@ -1,12 +1,15 @@
// src/hosts.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
import useViewMode from '../hooks/useViewMode'
@ -18,6 +21,11 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
const Hosts = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
// View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('host')
@ -34,8 +42,13 @@ const Hosts = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='host'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='host'
pageName='list'
@ -49,7 +62,8 @@ const Hosts = () => {
/>
<ExportListButton objectType='host' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -61,10 +75,11 @@ const Hosts = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -82,6 +97,8 @@ const Hosts = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,9 +13,17 @@ import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Materials = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('material')
@ -32,8 +40,13 @@ const Materials = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='material'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='material'
pageName='list'
@ -47,7 +60,8 @@ const Materials = () => {
/>
<ExportListButton objectType='material' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -59,10 +73,11 @@ const Materials = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -80,6 +95,8 @@ const Materials = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const NoteTypes = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('noteType')
@ -30,8 +38,13 @@ const NoteTypes = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='noteType'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='noteType'
pageName='list'
@ -45,7 +58,8 @@ const NoteTypes = () => {
/>
<ExportListButton objectType='noteType' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const NoteTypes = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const NoteTypes = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,9 +13,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PartSkus = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('partSkus')
@ -32,8 +40,13 @@ const PartSkus = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='partSku'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='partSku'
pageName='list'
@ -47,7 +60,8 @@ const PartSkus = () => {
/>
<ExportListButton objectType='partSku' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -59,10 +73,11 @@ const PartSkus = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -80,6 +95,8 @@ const PartSkus = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/gcodefiles.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
@ -18,9 +18,17 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Parts = (filter) => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('part')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('part')
@ -34,8 +42,13 @@ const Parts = (filter) => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='part'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='part'
pageName='list'
@ -49,7 +62,8 @@ const Parts = (filter) => {
/>
<ExportListButton objectType='part' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -61,10 +75,11 @@ const Parts = (filter) => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -82,6 +97,8 @@ const Parts = (filter) => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PermissionSettingsList = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('permissionSetting')
@ -30,8 +38,13 @@ const PermissionSettingsList = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='permissionSetting'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='permissionSetting'
pageName='list'
@ -45,7 +58,8 @@ const PermissionSettingsList = () => {
/>
<ExportListButton objectType='permissionSetting' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const PermissionSettingsList = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const PermissionSettingsList = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,9 +13,17 @@ import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductCategories = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('productCategory')
@ -32,8 +40,13 @@ const ProductCategories = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='productCategory'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='productCategory'
pageName='list'
@ -47,7 +60,8 @@ const ProductCategories = () => {
/>
<ExportListButton objectType='productCategory' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -59,10 +73,11 @@ const ProductCategories = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -80,6 +95,8 @@ const ProductCategories = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
@ -13,9 +13,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductSkus = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('productSkus')
@ -33,8 +41,13 @@ const ProductSkus = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='productSku'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='productSku'
pageName='list'
@ -48,7 +61,8 @@ const ProductSkus = () => {
/>
<ExportListButton objectType='productSku' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -60,10 +74,11 @@ const ProductSkus = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -81,6 +96,8 @@ const ProductSkus = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/gcodefiles.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import {
Button,
@ -29,10 +29,18 @@ import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Products = () => {
const navigate = useNavigate()
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('Products')
@ -304,8 +312,13 @@ const Products = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='product'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='product'
pageName='list'
@ -320,7 +333,8 @@ const Products = () => {
<Button>View</Button>
</Popover>
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -332,10 +346,11 @@ const Products = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
type={'product'}
@ -351,6 +366,8 @@ const Products = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockAuditLevels = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('stockAuditLevel')
@ -28,8 +36,13 @@ const StockAuditLevels = () => {
return (
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='stockAuditLevel'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='stockAuditLevel'
pageName='list'
@ -43,7 +56,8 @@ const StockAuditLevels = () => {
/>
<ExportListButton objectType='stockAuditLevel' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -55,10 +69,11 @@ const StockAuditLevels = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -75,6 +90,8 @@ const StockAuditLevels = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
)

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const TaxRates = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('taxRate')
@ -29,8 +37,13 @@ const TaxRates = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='taxRate'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='taxRate'
pageName='list'
@ -44,7 +57,8 @@ const TaxRates = () => {
/>
<ExportListButton objectType='taxRate' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,10 +70,11 @@ const TaxRates = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -76,6 +91,8 @@ const TaxRates = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const UserGroups = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('userGroup')
@ -29,8 +37,13 @@ const UserGroups = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='userGroup'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='userGroup'
pageName='list'
@ -44,7 +57,8 @@ const UserGroups = () => {
/>
<ExportListButton objectType='userGroup' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,10 +70,11 @@ const UserGroups = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -76,6 +91,8 @@ const UserGroups = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Users = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('user')
@ -28,8 +36,13 @@ const Users = () => {
return (
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='user'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='user'
pageName='list'
@ -43,7 +56,8 @@ const Users = () => {
/>
<ExportListButton objectType='user' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,8 +70,10 @@ const Users = () => {
viewMode={viewMode}
setViewMode={setViewMode}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
type={'user'}
@ -74,6 +90,8 @@ const Users = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
)

View File

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

View File

@ -1,7 +1,10 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton'
import ObjectTable from '../common/ObjectTable'
@ -14,6 +17,11 @@ import useViewMode from '../hooks/useViewMode'
const FilamentProfiles = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('FilamentProfiles')
const [columnVisibility, setColumnVisibility] =
useColumnVisibility('filamentProfile')
@ -27,8 +35,13 @@ const FilamentProfiles = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='filamentProfile'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='filamentProfile'
pageName='list'
@ -41,7 +54,8 @@ const FilamentProfiles = () => {
/>
<ExportListButton objectType='filamentProfile' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -53,10 +67,11 @@ const FilamentProfiles = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -74,6 +89,8 @@ const FilamentProfiles = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/gcodefiles.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTable from '../common/ObjectTable'
@ -14,9 +14,17 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const GCodeFiles = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('gcodeFile')
const [columnVisibility, setColumnVisibility] =
@ -32,8 +40,13 @@ const GCodeFiles = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='gcodeFile'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='gcodeFile'
pageName='list'
@ -47,7 +60,8 @@ const GCodeFiles = () => {
/>
<ExportListButton objectType='gcodeFile' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -59,10 +73,11 @@ const GCodeFiles = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
type='gcodeFile'
@ -79,6 +94,8 @@ const GCodeFiles = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,6 +1,6 @@
// src/Jobs.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility.jsx'
import ObjectTable from '../common/ObjectTable.jsx'
@ -13,9 +13,17 @@ import ColumnViewButton from '../common/ColumnViewButton.jsx'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility.jsx'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton.jsx'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Jobs = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('job')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('job')
@ -30,8 +38,13 @@ const Jobs = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='job'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='job'
pageName='list'
@ -45,8 +58,8 @@ const Jobs = () => {
/>
<ExportListButton objectType='job' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -58,10 +71,11 @@ const Jobs = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -79,6 +93,8 @@ const Jobs = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,7 +1,10 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton'
import ObjectTable from '../common/ObjectTable'
@ -13,6 +16,11 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import useViewMode from '../hooks/useViewMode'
const PrinterProfiles = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('PrinterProfiles')
const [columnVisibility, setColumnVisibility] =
useColumnVisibility('printerProfile')
@ -26,8 +34,13 @@ const PrinterProfiles = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='printerProfile'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='printerProfile'
pageName='list'
@ -40,7 +53,8 @@ const PrinterProfiles = () => {
/>
<ExportListButton objectType='printerProfile' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -52,10 +66,11 @@ const PrinterProfiles = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -73,6 +88,8 @@ const PrinterProfiles = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,11 +1,14 @@
// src/Printers.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Space, Flex } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton'
@ -17,6 +20,11 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
const Printers = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
// View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('Printers')
@ -35,8 +43,13 @@ const Printers = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space>
<ObjectListViewProvider
objectType='printer'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space>
<ObjectActions
type='printer'
pageName='list'
@ -50,7 +63,8 @@ const Printers = () => {
/>
<ExportListButton objectType='printer' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -62,10 +76,11 @@ const Printers = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -83,6 +98,8 @@ const Printers = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>

View File

@ -1,6 +1,6 @@
// src/SubJobs.js
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility.jsx'
import ObjectTable from '../common/ObjectTable.jsx'
@ -13,9 +13,17 @@ import ColumnViewButton from '../common/ColumnViewButton.jsx'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility.jsx'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton.jsx'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const SubJobs = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('subJob')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('subJob')
@ -30,8 +38,13 @@ const SubJobs = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='subJob'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='subJob'
pageName='list'
@ -45,8 +58,8 @@ const SubJobs = () => {
/>
<ExportListButton objectType='subJob' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -58,10 +71,11 @@ const SubJobs = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
@ -79,6 +93,8 @@ const SubJobs = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Clients = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('client')
@ -29,8 +37,13 @@ const Clients = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='client'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='client'
pageName='list'
@ -44,7 +57,8 @@ const Clients = () => {
/>
<ExportListButton objectType='client' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -56,10 +70,11 @@ const Clients = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -76,6 +91,8 @@ const Clients = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FulfillmentPolicies = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('fulfillmentPolicy')
const [columnVisibility, setColumnVisibility] =
useColumnVisibility('fulfillmentPolicy')
@ -24,8 +32,13 @@ const FulfillmentPolicies = () => {
return (
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='fulfillmentPolicy'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='fulfillmentPolicy'
pageName='list'
@ -39,7 +52,8 @@ const FulfillmentPolicies = () => {
/>
<ExportListButton objectType='fulfillmentPolicy' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -51,10 +65,11 @@ const FulfillmentPolicies = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -71,6 +86,8 @@ const FulfillmentPolicies = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
)

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ListingVarients = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('listingVarients')
@ -30,8 +38,13 @@ const ListingVarients = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='listingVarient'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='listingVarient'
pageName='list'
@ -45,7 +58,8 @@ const ListingVarients = () => {
/>
<ExportListButton objectType='listingVarient' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const ListingVarients = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const ListingVarients = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Listings = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('listings')
@ -30,8 +38,13 @@ const Listings = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='listing'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='listing'
pageName='list'
@ -45,7 +58,8 @@ const Listings = () => {
/>
<ExportListButton objectType='listing' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const Listings = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const Listings = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Marketplaces = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('marketplaces')
@ -30,8 +38,13 @@ const Marketplaces = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='marketplace'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='marketplace'
pageName='list'
@ -45,7 +58,8 @@ const Marketplaces = () => {
/>
<ExportListButton objectType='marketplace' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const Marketplaces = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const Marketplaces = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ReturnPolicies = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('returnPolicy')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('returnPolicy')
const [showFilterSidebar, setShowFilterSidebar] =
@ -23,8 +31,13 @@ const ReturnPolicies = () => {
return (
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='returnPolicy'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='returnPolicy'
pageName='list'
@ -38,7 +51,8 @@ const ReturnPolicies = () => {
/>
<ExportListButton objectType='returnPolicy' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -50,10 +64,11 @@ const ReturnPolicies = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -70,6 +85,8 @@ const ReturnPolicies = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
)

View File

@ -1,4 +1,4 @@
import { useRef } from 'react'
import { useRef, useState } from 'react'
import { Flex, Space } from 'antd'
import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions'
@ -11,9 +11,17 @@ import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const SalesOrders = () => {
const tableRef = useRef()
const [viewState, setViewState] = useState({
activeView: null,
handleFilterSortChange: null
})
const [viewMode, setViewMode] = useViewMode('salesOrders')
@ -30,8 +38,13 @@ const SalesOrders = () => {
return (
<>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}>
<Space size='small'>
<ObjectListViewProvider
objectType='salesOrder'
tableRef={tableRef}
onViewStateChange={setViewState}
>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'>
<ObjectActions
type='salesOrder'
pageName='list'
@ -45,7 +58,8 @@ const SalesOrders = () => {
/>
<ExportListButton objectType='salesOrder' />
</Space>
<Space>
<ListViewTabs />
<Space>
<SortSidebarButton
active={showSortSidebar}
onClick={() => setShowSortSidebar(!showSortSidebar)}
@ -57,10 +71,11 @@ const SalesOrders = () => {
<ObjectTableViewButton
viewMode={viewMode}
setViewMode={setViewMode}
showEndingDivider={true}
/>
<ListViewEditButtons showStartingDivider={true} />
</Space>
</Flex>
</Flex>
</ObjectListViewProvider>
<ObjectTable
ref={tableRef}
visibleColumns={columnVisibility}
@ -77,6 +92,8 @@ const SalesOrders = () => {
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
activeObjectView={viewState.activeView}
onObjectViewFilterSortChange={viewState.handleFilterSortChange}
/>
</Flex>
</>

View File

@ -2,7 +2,16 @@ import { useState, useEffect } from 'react'
import { ColorPicker, Checkbox, Flex, Row, Col, Divider } from 'antd'
import PropTypes from 'prop-types'
const ColorSelector = ({ value, onChange, disabled, required = false }) => {
const ColorSelector = ({
value,
onChange,
disabled,
required = false,
size,
showText = true,
className,
onClick
}) => {
// Determine initial enabled state based on value
const [colorEnabled, setColorEnabled] = useState(!!value)
@ -97,18 +106,24 @@ const ColorSelector = ({ value, onChange, disabled, required = false }) => {
]
return (
<Flex gap={'middle'}>
<Flex gap={showText ? 'middle' : 0} align='center'>
<ColorPicker
showText
size={size}
showText={showText}
disabledAlpha
style={{ width: '100%', justifyContent: 'start' }}
style={
showText
? { width: '100%', justifyContent: 'start' }
: undefined
}
disabled={(!colorEnabled && !required) || disabled}
value={value || '#000000'}
onChange={handleColorChange}
onClick={onClick}
presets={presets}
panelRender={customPanelRender}
arrow={false}
className='ant-input-outlined'
className={className ?? (showText ? 'ant-input-outlined' : undefined)}
/>
{!required && (
<Checkbox
@ -125,7 +140,11 @@ ColorSelector.propTypes = {
value: PropTypes.string,
onChange: PropTypes.func,
disabled: PropTypes.bool,
required: PropTypes.bool
required: PropTypes.bool,
size: PropTypes.string,
showText: PropTypes.bool,
className: PropTypes.string,
onClick: PropTypes.func
}
export default ColorSelector

View File

@ -1027,7 +1027,7 @@ const FilterInput = ({
}
}, [])
const showPlaceholder = !internalValue && !focused
const showPlaceholder = Boolean(placeholder) && !internalValue
const showClear = allowClear && !!internalValue && !disabled
const affixCls = `${prefixCls}-affix-wrapper`
@ -1076,6 +1076,7 @@ const FilterInput = ({
className={classNames(prefixCls, 'filter-input-editor')}
role='textbox'
aria-multiline='false'
aria-placeholder={showPlaceholder ? placeholder : undefined}
aria-disabled={disabled || undefined}
contentEditable={!disabled}
suppressContentEditableWarning

View File

@ -0,0 +1,38 @@
import PropTypes from 'prop-types'
import { Divider, Flex } from 'antd'
import EditButtons from './EditButtons'
import { useObjectListView } from '../context/ObjectListViewContext'
const ListViewEditButtons = ({ showStartingDivider = false }) => {
const { isEditing, saving, saveEdits, cancelEdits, startEditing } =
useObjectListView()
if (!isEditing) {
return null
}
return (
<Flex align='center' gap='small'>
{showStartingDivider && (
<Divider type='vertical' style={{ margin: '0 4px', height: '18px' }} />
)}
<EditButtons
isEditing={isEditing}
handleUpdate={async () => {
await saveEdits()
}}
cancelEditing={cancelEdits}
startEditing={startEditing}
formValid={true}
loading={saving}
requirePermission={false}
/>
</Flex>
)
}
ListViewEditButtons.propTypes = {
showStartingDivider: PropTypes.bool
}
export default ListViewEditButtons

View File

@ -0,0 +1,308 @@
import PropTypes from 'prop-types'
import React, { useMemo } from 'react'
import {
Input,
Dropdown,
Checkbox,
Button,
Flex,
Typography,
Spin,
Divider,
theme
} from 'antd'
const { useToken } = theme
import SegmentedNav, { SegmentedNavDragHandle } from './SegmentedNav'
import { CaretDownFilled, LoadingOutlined } from '@ant-design/icons'
import { getModelByName } from '../../../database/ObjectModels'
import { useObjectListView } from '../context/ObjectListViewContext'
import classNames from 'classnames'
import PlusIcon from '../../Icons/PlusIcon'
import EditIcon from '../../Icons/EditIcon'
import BinIcon from '../../Icons/BinIcon'
import ScrollBox from './ScrollBox'
import ColorSelector from './ColorSelector'
const { Text } = Typography
const ViewColorDot = ({ color }) => (
<span
className='list-view-tabs-color-dot'
style={{ backgroundColor: color || '#3498DB' }}
/>
)
ViewColorDot.propTypes = {
color: PropTypes.string
}
const ViewOptionsDropdown = ({ view, isEditing, onChange, onDelete }) => {
const menu = {
items: [
{
key: 'delete',
label: 'Delete',
icon: <BinIcon />,
danger: true,
onClick: ({ domEvent }) => {
domEvent.stopPropagation()
onDelete?.()
}
}
]
}
const menuStyle = {
boxShadow: 'none'
}
const { token } = useToken()
const contentStyle = {
backgroundColor: token.colorBgElevated,
borderRadius: token.borderRadiusLG,
boxShadow: token.boxShadowSecondary
}
return (
<Dropdown
menu={menu}
trigger={['hover']}
placement='bottomLeft'
popupRender={(menu) => (
<div className='list-view-tabs-options-dropdown' style={contentStyle}>
{React.cloneElement(menu, { style: menuStyle })}
<Flex
vertical
gap='middle'
className='list-view-tabs-options-dropdown-privacy'
>
<Checkbox
checked={view.private !== false}
disabled={!isEditing}
onChange={(event) => onChange({ private: event.target.checked })}
onClick={(event) => event.stopPropagation()}
>
Private
</Checkbox>
</Flex>
</div>
)}
>
<Button
type='text'
size='small'
className='list-view-tabs-options-button'
icon={<CaretDownFilled style={{ fontSize: 14, marginTop: 4 }} />}
disabled={!isEditing}
onClick={(event) => event.stopPropagation()}
/>
</Dropdown>
)
}
ViewOptionsDropdown.propTypes = {
view: PropTypes.object.isRequired,
isEditing: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
onDelete: PropTypes.func
}
const ViewTabNameInput = ({ value, onClick, onChange }) => (
<span className='list-view-tabs-name-input-wrap'>
<span aria-hidden className='list-view-tabs-name-input-sizer'>
{value}
</span>
<Input
size='small'
variant='borderless'
className='list-view-tabs-name-input'
value={value}
onClick={onClick}
onChange={onChange}
/>
</span>
)
ViewTabNameInput.propTypes = {
value: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired
}
const ViewTabLabel = ({
view,
isEditing,
onDraftChange,
onRemove,
onSelect
}) => {
if (!isEditing) {
return (
<Flex align='center' gap={8} className='list-view-tabs-label'>
<ViewColorDot color={view.color} />
<Text ellipsis style={{ maxWidth: 160 }}>
{view.name}
</Text>
</Flex>
)
}
return (
<Flex
align='center'
gap={6}
className='list-view-tabs-label list-view-tabs-label-editing'
onFocusCapture={() => onSelect?.()}
>
<ColorSelector
size='small'
showText={false}
required
value={view.color || '#3498DB'}
onChange={(color) => onDraftChange({ color })}
onClick={(event) => event.stopPropagation()}
/>
<ViewTabNameInput
value={view.name}
onClick={(event) => event.stopPropagation()}
onChange={(event) => onDraftChange({ name: event.target.value })}
/>
<Flex align='center' gap={2}>
<ViewOptionsDropdown
view={view}
isEditing={isEditing}
onChange={onDraftChange}
onDelete={onRemove}
/>
<SegmentedNavDragHandle value={String(view._id)} />
</Flex>
</Flex>
)
}
ViewTabLabel.propTypes = {
view: PropTypes.object.isRequired,
isEditing: PropTypes.bool.isRequired,
onDraftChange: PropTypes.func.isRequired,
onRemove: PropTypes.func,
onSelect: PropTypes.func
}
const ListViewTabs = () => {
const {
objectType,
ALL_TAB_KEY,
views,
activeTabKey,
initialLoading,
isEditing,
startEditing,
selectTab,
handleTabEdit,
updateDraftView,
reorderDraftViews,
viewTabSignatures
} = useObjectListView()
const model = getModelByName(objectType)
const options = useMemo(() => {
const Icon = model?.icon
const allOption = {
value: ALL_TAB_KEY,
icon: Icon ? <Icon style={{ fontSize: 14 }} /> : null
}
const viewOptions = views.map((view) => ({
value: String(view._id),
reorderable: isEditing,
label: (
<ViewTabLabel
view={view}
isEditing={isEditing}
onDraftChange={(changes) => updateDraftView(view._id, changes)}
onRemove={
isEditing
? () => handleTabEdit(String(view._id), 'remove')
: undefined
}
onSelect={() => {
const tabKey = String(view._id)
if (activeTabKey !== tabKey) {
selectTab(tabKey)
}
}}
/>
)
}))
return [allOption, ...viewOptions]
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
ALL_TAB_KEY,
activeTabKey,
handleTabEdit,
isEditing,
model?.icon,
selectTab,
updateDraftView,
viewTabSignatures
])
return (
<Flex
align='center'
gap='small'
style={{ minHeight: 0, width: '100%', minWidth: 0 }}
>
<Divider type='vertical' style={{ margin: '0 4px', height: '18px' }} />
<Spin
spinning={initialLoading === true}
wrapperClassName='list-view-tabs-spin'
indicator={<LoadingOutlined spin />}
>
<Flex
align='center'
gap={4}
className={classNames('list-view-tabs', {
'list-view-tabs-editing': isEditing
})}
style={{ flex: 1, minWidth: 0 }}
>
<ScrollBox className='list-view-tabs-segmented-wrap' horizontal>
<Flex
align='center'
gap={8}
className='list-view-tabs-segmented-inner'
>
<SegmentedNav
className='list-view-tabs-segmented'
value={activeTabKey}
options={options}
onChange={selectTab}
onReorder={isEditing ? reorderDraftViews : undefined}
/>
<Button
type='text'
size='small'
className='list-view-tabs-add-button'
onClick={
isEditing ? () => handleTabEdit(null, 'add') : startEditing
}
icon={
isEditing ? (
<PlusIcon style={{ fontSize: 14, marginTop: 3 }} />
) : (
<EditIcon style={{ fontSize: 12, marginBottom: 5 }} />
)
}
/>
</Flex>
</ScrollBox>
</Flex>
</Spin>
</Flex>
)
}
export default ListViewTabs

View File

@ -255,6 +255,8 @@ const ObjectTable = forwardRef(
saveSortInUrl = false,
useSortInSession = false,
useSortInUrl = false,
activeObjectView = null,
onObjectViewFilterSortChange,
onRowAction
},
ref
@ -317,6 +319,15 @@ const ObjectTable = forwardRef(
const model = getModelByName(type)
const activeFilterRef = useRef({})
const tableSorterRef = useRef({})
const activeObjectViewRef = useRef(activeObjectView)
activeObjectViewRef.current = activeObjectView
const onObjectViewFilterSortChangeRef = useRef(onObjectViewFilterSortChange)
onObjectViewFilterSortChangeRef.current = onObjectViewFilterSortChange
const listViewMastersRef = useRef({ masterFilter: {}, masterSort: {} })
const [listViewMasters, setListViewMastersState] = useState({
masterFilter: {},
masterSort: {}
})
const [sidebarFilter, setSidebarFilter] = useState({})
const [tableSorter, setTableSorter] = useState({})
const [initialized, setInitialized] = useState(false)
@ -369,6 +380,33 @@ const ObjectTable = forwardRef(
)
const prevValuesRef = useRef({ type, masterFilter })
const effectiveMasterFilter = useMemo(
() => ({
...listViewMasters.masterFilter,
...masterFilter
}),
[listViewMasters.masterFilter, masterFilter]
)
const getEffectiveMasterFilter = useCallback(
() => ({
...listViewMastersRef.current.masterFilter,
...masterFilter
}),
[masterFilter]
)
const resolveSorter = useCallback((userSorter) => {
if (userSorter?.field && userSorter?.order) {
return { field: userSorter.field, order: userSorter.order }
}
const masterSort = listViewMastersRef.current.masterSort
if (masterSort?.field && masterSort?.order) {
return { field: masterSort.field, order: masterSort.order }
}
return {}
}, [])
const rowActions =
model.actions?.filter((action) => action.row == true) || []
@ -508,12 +546,19 @@ const ObjectTable = forwardRef(
return fetchObjects(type, {
page: pageNum,
limit: pageSize,
filter: { ...filter, ...masterFilter },
sorter,
filter: { ...getEffectiveMasterFilter(), ...filter },
sorter: resolveSorter(sorter),
onDataChange
})
},
[type, masterFilter, pageSize, onDataChange, fetchObjects]
[
type,
getEffectiveMasterFilter,
pageSize,
onDataChange,
fetchObjects,
resolveSorter
]
)
const skeletonsHeight = useMemo(() => {
@ -871,15 +916,15 @@ const ObjectTable = forwardRef(
Object.entries(sidebarFilter).forEach(([k, v]) => {
if (v !== '' && v !== undefined) active[k] = v
})
return { ...active, ...masterFilter }
}, [sidebarFilter, masterFilter])
return { ...effectiveMasterFilter, ...active }
}, [sidebarFilter, effectiveMasterFilter])
const tableFilterContextValue = useMemo(
() => ({
filter: getActiveFilterValues(sidebarFilter),
masterFilter
masterFilter: effectiveMasterFilter
}),
[sidebarFilter, masterFilter]
[sidebarFilter, effectiveMasterFilter]
)
newEventHandlerRef.current = newEventHandler
@ -1043,20 +1088,89 @@ const ObjectTable = forwardRef(
const filter = getPersistedFilter()
const sorter = getPersistedSorter()
const activeFilter = getActiveFilterValues(filter)
const resolvedSorter = resolveSorter(sorter)
if (Object.keys(filter).length > 0) {
setSidebarFilter(filter)
}
if (sorter.field) {
if (sorter?.field) {
tableSorterRef.current = sorter
setTableSorter(sorter)
}
loadPage(initialPage, activeFilter, sorter.field ? sorter : null)
}, [getPersistedFilter, getPersistedSorter, initialPage, loadPage])
loadPage(
initialPage,
activeFilter,
resolvedSorter.field ? resolvedSorter : null
)
}, [
getPersistedFilter,
getPersistedSorter,
initialPage,
loadPage,
resolveSorter
])
const setListViewMasters = useCallback(
({ masterFilter: nextMasterFilter = {}, masterSort: nextMasterSort = {} }) => {
listViewMastersRef.current = {
masterFilter: nextMasterFilter,
masterSort: nextMasterSort
}
setListViewMastersState({
masterFilter: nextMasterFilter,
masterSort: nextMasterSort
})
},
[]
)
const applyViewState = useCallback(
(filterState, sorterState) => {
if (filterState == null && sorterState == null) {
const filter = getPersistedFilter()
const sorter = getPersistedSorter()
const activeFilter = getActiveFilterValues(filter)
const resolvedSorter = resolveSorter(sorter)
setSidebarFilter(filter)
tableSorterRef.current = sorter?.field ? sorter : {}
setTableSorter(sorter?.field ? sorter : {})
activeFilterRef.current = activeFilter
loadPage(
initialPage,
activeFilter,
resolvedSorter.field ? resolvedSorter : null
)
return
}
const filter = filterState || {}
const sorter = sorterState?.field ? sorterState : {}
const activeFilter = getActiveFilterValues(filter)
const resolvedSorter = resolveSorter(sorter)
setSidebarFilter(filter)
tableSorterRef.current = sorter
setTableSorter(sorter)
activeFilterRef.current = activeFilter
loadPage(
initialPage,
activeFilter,
resolvedSorter.field ? resolvedSorter : null
)
},
[
getPersistedFilter,
getPersistedSorter,
initialPage,
loadPage,
resolveSorter
]
)
useImperativeHandle(ref, () => ({
reload,
applyViewState,
setListViewMasters,
setData: (newData) => {
setPages([{ pageNum: 1, items: newData }])
},
@ -1084,7 +1198,6 @@ const ObjectTable = forwardRef(
useEffect(() => {
const prevValues = prevValuesRef.current
// Deep comparison for objects, simple comparison for primitives
const hasChanged =
prevValues.type !== type ||
JSON.stringify(prevValues.masterFilter) !== JSON.stringify(masterFilter)
@ -1133,7 +1246,7 @@ const ObjectTable = forwardRef(
propertyLabel={propertyLabel}
modelType={type}
filter={sidebarFilter}
masterFilter={masterFilter}
masterFilter={effectiveMasterFilter}
/>
)
@ -1158,21 +1271,29 @@ const ObjectTable = forwardRef(
setSidebarFilter(next)
setTableSorter(nextSorter)
persistTableState(next, nextSorter)
loadPage(initialPage, getActiveFilterValues(next), nextSorter)
if (activeObjectViewRef.current) {
onObjectViewFilterSortChangeRef.current?.(next, nextSorter)
} else {
persistTableState(next, nextSorter)
}
loadPage(initialPage, getActiveFilterValues(next), resolveSorter(nextSorter))
}
const handleSidebarFilterChange = useCallback(
(newSidebarFilter) => {
setSidebarFilter(newSidebarFilter)
persistFilter(newSidebarFilter)
if (activeObjectViewRef.current) {
onObjectViewFilterSortChangeRef.current?.(newSidebarFilter, tableSorter)
} else {
persistFilter(newSidebarFilter)
}
loadPage(
initialPage,
getActiveFilterValues(newSidebarFilter),
tableSorter.field ? tableSorter : null
resolveSorter(tableSorter)
)
},
[initialPage, loadPage, persistFilter, tableSorter]
[initialPage, loadPage, persistFilter, resolveSorter, tableSorter]
)
const handleSidebarSortChange = useCallback(
@ -1183,17 +1304,21 @@ const ObjectTable = forwardRef(
isInternalSortUpdateRef.current = true
setTableSorter(nextSorter)
tableSorterRef.current = nextSorter
persistSort(nextSorter)
if (activeObjectViewRef.current) {
onObjectViewFilterSortChangeRef.current?.(sidebarFilter, nextSorter)
} else {
persistSort(nextSorter)
}
loadPage(
initialPage,
getActiveFilterValues(sidebarFilter),
nextSorter.field ? nextSorter : null
resolveSorter(nextSorter)
)
requestAnimationFrame(() => {
isInternalSortUpdateRef.current = false
})
},
[initialPage, loadPage, persistSort, sidebarFilter]
[initialPage, loadPage, persistSort, resolveSorter, sidebarFilter]
)
const modelProperties = getModelProperties(type)
@ -1315,7 +1440,7 @@ const ObjectTable = forwardRef(
}
}
if (isFilterable && !Object.keys(masterFilter).includes(prop.name)) {
if (isFilterable && !Object.keys(effectiveMasterFilter).includes(prop.name)) {
columnConfig.filterDropdown = ({
setSelectedKeys,
selectedKeys,
@ -1594,7 +1719,7 @@ const ObjectTable = forwardRef(
type={type}
filter={sidebarFilter}
onFilterChange={handleSidebarFilterChange}
masterFilter={masterFilter}
masterFilter={effectiveMasterFilter}
/>
</Flex>
)}
@ -1639,6 +1764,8 @@ ObjectTable.propTypes = {
saveSortInUrl: PropTypes.bool,
useSortInSession: PropTypes.bool,
useSortInUrl: PropTypes.bool,
activeObjectView: PropTypes.object,
onObjectViewFilterSortChange: PropTypes.func,
onRowAction: PropTypes.func
}

View File

@ -87,6 +87,7 @@ const PropertyChanges = ({ type, value }) => {
longId={false}
minimal={true}
showPreview={false}
showProgress={false}
objectData={value?.old}
maxWidth='200px'
/>
@ -102,6 +103,7 @@ const PropertyChanges = ({ type, value }) => {
longId={false}
minimal={true}
showPreview={false}
showProgress={false}
objectData={value?.new}
maxWidth='200px'
/>

View File

@ -8,21 +8,30 @@ const ScrollBox = ({
horizontalBottomPadding = 16,
verticalRightPadding = 16,
inner = false,
horizontal = false,
smallPadding = false,
className = '',
...rest
}) => {
const outerStyle = {
minHeight: '0',
minWidth: horizontal ? 0 : undefined,
'--scrollbox-vertical-right-padding': `${verticalRightPadding}px`,
'--scrollbox-horizontal-bottom-padding': `${horizontalBottomPadding}px`,
...(horizontal ? { width: '100%', height: 'auto' } : { height: '100%' })
}
const simpleBarStyle = {
...(horizontal ? { width: '100%', height: 'auto' } : { height: '100%' }),
...style
}
return (
<div
style={{
height: '100%',
minHeight: '0',
'--scrollbox-vertical-right-padding': `${verticalRightPadding}px`,
'--scrollbox-horizontal-bottom-padding': `${horizontalBottomPadding}px`
}}
className={`${inner ? 'scrollbox-inner' : ''} ${smallPadding ? 'scrollbox-inner-small-padding' : ''} ${className}`}
style={outerStyle}
className={`${inner ? 'scrollbox-inner' : ''} ${smallPadding ? 'scrollbox-inner-small-padding' : ''} ${horizontal ? 'scrollbox-horizontal' : ''} ${className}`}
>
<SimpleBar style={{ height: '100%', ...style }} {...rest}>
<SimpleBar style={simpleBarStyle} {...rest}>
{children}
</SimpleBar>
</div>
@ -35,6 +44,7 @@ ScrollBox.propTypes = {
horizontalBottomPadding: PropTypes.number,
verticalRightPadding: PropTypes.number,
inner: PropTypes.bool,
horizontal: PropTypes.bool,
smallPadding: PropTypes.bool,
className: PropTypes.string
}

View File

@ -0,0 +1,431 @@
import PropTypes from 'prop-types'
import {
createContext,
useCallback,
useContext,
useLayoutEffect,
useRef,
useState
} from 'react'
import { HolderOutlined } from '@ant-design/icons'
import classNames from 'classnames'
const SegmentedNavReorderContext = createContext(null)
const getEnabledOptions = (options, disabled) =>
options.filter((option) => !disabled && !option.disabled)
const getItemMetrics = (element) => {
if (!element) {
return null
}
return {
left: element.offsetLeft,
top: element.offsetTop,
width: element.offsetWidth,
height: element.offsetHeight
}
}
export const SegmentedNavDragHandle = ({ value }) => {
const reorder = useContext(SegmentedNavReorderContext)
const dragProps = reorder?.getDragHandleProps?.(value)
if (!dragProps) {
return null
}
return (
<span
className='segmented-nav-drag-handle overview-drag-handle'
draggable
onClick={(event) => event.stopPropagation()}
onMouseDown={(event) => event.stopPropagation()}
onDragStart={(event) => dragProps.onDragStart(event)}
onDragEnd={dragProps.onDragEnd}
>
<HolderOutlined />
</span>
)
}
SegmentedNavDragHandle.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
}
const SegmentedNav = ({
value,
options = [],
onChange,
onReorder,
className,
disabled = false
}) => {
const groupRef = useRef(null)
const thumbRef = useRef(null)
const itemRefs = useRef(new Map())
const prevValueRef = useRef(value)
const transitionGenRef = useRef(0)
const finishGenRef = useRef(0)
const [isAnimating, setIsAnimating] = useState(false)
const [thumbRect, setThumbRect] = useState(null)
const [draggedValue, setDraggedValue] = useState(null)
const [dropTarget, setDropTarget] = useState(null)
const enabledOptions = getEnabledOptions(options, disabled)
const isReordering = Boolean(onReorder && draggedValue != null)
const setItemRef = useCallback((optionValue, element) => {
if (element) {
itemRefs.current.set(optionValue, element)
} else {
itemRefs.current.delete(optionValue)
}
}, [])
useLayoutEffect(() => {
if (prevValueRef.current === value) {
return undefined
}
const fromMetrics = getItemMetrics(
itemRefs.current.get(prevValueRef.current)
)
const toMetrics = getItemMetrics(itemRefs.current.get(value))
prevValueRef.current = value
if (!fromMetrics || !toMetrics) {
return undefined
}
const transitionGen = transitionGenRef.current + 1
transitionGenRef.current = transitionGen
setIsAnimating(true)
setThumbRect(fromMetrics)
let endFrame = 0
const startFrame = requestAnimationFrame(() => {
endFrame = requestAnimationFrame(() => {
if (transitionGenRef.current === transitionGen) {
finishGenRef.current = transitionGen
setThumbRect(toMetrics)
}
})
})
return () => {
cancelAnimationFrame(startFrame)
cancelAnimationFrame(endFrame)
}
}, [value])
const finishAnimation = useCallback(() => {
setIsAnimating(false)
setThumbRect(null)
}, [])
const handleThumbTransitionEnd = useCallback(
(event) => {
if (event.target !== thumbRef.current) {
return
}
if (
(event.propertyName === 'transform' ||
event.propertyName === 'width') &&
finishGenRef.current === transitionGenRef.current
) {
finishAnimation()
}
},
[finishAnimation]
)
const clearDragState = useCallback(() => {
setDraggedValue(null)
setDropTarget(null)
}, [])
const handleDragStart = useCallback(
(event, optionValue) => {
if (!onReorder) return
event.stopPropagation()
const item = event.currentTarget.closest('.segmented-nav-item')
if (item) {
const rect = item.getBoundingClientRect()
event.dataTransfer.setDragImage(
item,
event.clientX - rect.left,
event.clientY - rect.top
)
}
setDraggedValue(optionValue)
event.dataTransfer.effectAllowed = 'move'
event.dataTransfer.setData('text/plain', String(optionValue))
},
[onReorder]
)
const handleDragEnd = useCallback(() => {
clearDragState()
}, [clearDragState])
const handleItemDragOver = useCallback(
(event, option) => {
if (!onReorder || draggedValue == null || !option.reorderable) {
return
}
if (String(option.value) === String(draggedValue)) {
return
}
event.preventDefault()
event.stopPropagation()
event.dataTransfer.dropEffect = 'move'
const rect = event.currentTarget.getBoundingClientRect()
setDropTarget({
value: option.value,
insertBefore: event.clientX < rect.left + rect.width / 2
})
},
[draggedValue, onReorder]
)
const handleItemDrop = useCallback(
(event, option) => {
if (!onReorder || draggedValue == null || !option.reorderable) {
return
}
event.preventDefault()
event.stopPropagation()
const target = dropTarget || {
value: option.value,
insertBefore: true
}
if (String(draggedValue) !== String(target.value)) {
onReorder(draggedValue, target.value, target.insertBefore)
}
clearDragState()
},
[clearDragState, draggedValue, dropTarget, onReorder]
)
const handleGroupDragOver = useCallback(
(event) => {
if (!onReorder || draggedValue == null) {
return
}
const reorderableOptions = options.filter((option) => option.reorderable)
if (reorderableOptions.length === 0) {
return
}
if (
event.target instanceof Element &&
event.target.closest('.segmented-nav-item')
) {
return
}
event.preventDefault()
event.dataTransfer.dropEffect = 'move'
const lastOption = reorderableOptions[reorderableOptions.length - 1]
setDropTarget({
value: lastOption.value,
insertBefore: false
})
},
[draggedValue, onReorder, options]
)
const handleGroupDrop = useCallback(
(event) => {
if (!onReorder || draggedValue == null) {
return
}
if (
event.target instanceof Element &&
event.target.closest('.segmented-nav-item')
) {
return
}
event.preventDefault()
event.stopPropagation()
const reorderableOptions = options.filter((option) => option.reorderable)
const lastOption = reorderableOptions[reorderableOptions.length - 1]
if (lastOption && String(draggedValue) !== String(lastOption.value)) {
onReorder(draggedValue, lastOption.value, false)
}
clearDragState()
},
[clearDragState, draggedValue, onReorder, options]
)
const getDragHandleProps = useCallback(
(optionValue) => {
const option = options.find(
(item) => String(item.value) === String(optionValue)
)
if (!onReorder || !option?.reorderable) {
return null
}
return {
onDragStart: (event) => handleDragStart(event, optionValue),
onDragEnd: handleDragEnd
}
},
[handleDragEnd, handleDragStart, onReorder, options]
)
const handleKeyDown = (event, optionIndex) => {
if (event.key !== 'ArrowRight' && event.key !== 'ArrowLeft') {
return
}
event.preventDefault()
const direction = event.key === 'ArrowRight' ? 1 : -1
const currentEnabledIndex = enabledOptions.findIndex(
(option) => option.value === value
)
const startIndex =
currentEnabledIndex === -1 ? optionIndex : currentEnabledIndex
const nextIndex =
(startIndex + direction + enabledOptions.length) % enabledOptions.length
onChange?.(enabledOptions[nextIndex].value)
}
const reorderContextValue = onReorder ? { getDragHandleProps } : null
return (
<SegmentedNavReorderContext.Provider value={reorderContextValue}>
<div
className={classNames('segmented-nav', className, {
'segmented-nav-disabled': disabled,
'segmented-nav-reordering': isReordering
})}
role='radiogroup'
>
<div
className={classNames('segmented-nav-group', {
'segmented-nav-animating': isAnimating
})}
ref={groupRef}
onDragOver={handleGroupDragOver}
onDrop={handleGroupDrop}
>
{isAnimating && thumbRect && (
<div
ref={thumbRef}
className='segmented-nav-thumb'
style={{
width: thumbRect.width,
height: thumbRect.height,
transform: `translate3d(${thumbRect.left}px, ${thumbRect.top}px, 0)`
}}
onTransitionEnd={handleThumbTransitionEnd}
aria-hidden='true'
/>
)}
{options.map((option, index) => {
const isSelected = value === option.value
const isDisabled = disabled || option.disabled
const isDragging =
draggedValue != null &&
String(draggedValue) === String(option.value)
const isDropTarget =
dropTarget != null &&
String(dropTarget.value) === String(option.value) &&
String(draggedValue) !== String(option.value)
return (
<button
key={option.value}
ref={(element) => setItemRef(option.value, element)}
type='button'
role='radio'
aria-checked={isSelected}
disabled={isDisabled}
tabIndex={isSelected ? 0 : -1}
className={classNames('segmented-nav-item', option.className, {
'segmented-nav-item-selected': isSelected,
'segmented-nav-item-disabled': isDisabled,
'segmented-nav-item-dragging': isDragging,
'segmented-nav-item-drop-before':
isDropTarget && dropTarget.insertBefore,
'segmented-nav-item-drop-after':
isDropTarget && !dropTarget.insertBefore,
'segmented-nav-item-icon': option.icon
})}
onClick={() => {
if (!isDisabled) {
onChange?.(option.value)
}
}}
onKeyDown={(event) => handleKeyDown(event, index)}
onDragOver={
option.reorderable
? (event) => handleItemDragOver(event, option)
: undefined
}
onDrop={
option.reorderable
? (event) => handleItemDrop(event, option)
: undefined
}
>
{option.icon && (
<span className='segmented-nav-item-icon-contents'>
{option.icon}
</span>
)}
{option.label && (
<span className='segmented-nav-item-label'>
{option.label}
</span>
)}
</button>
)
})}
</div>
</div>
</SegmentedNavReorderContext.Provider>
)
}
SegmentedNav.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
options: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
.isRequired,
label: PropTypes.node,
disabled: PropTypes.bool,
reorderable: PropTypes.bool,
className: PropTypes.string
})
),
onChange: PropTypes.func,
onReorder: PropTypes.func,
className: PropTypes.string,
disabled: PropTypes.bool
}
export default SegmentedNav

View File

@ -34,20 +34,27 @@ const StateDisplay = ({
'syncing'
]
const circularLoadingTypes = ['loading', 'processing', 'initializing']
const currentState = state || {
type: 'unknown',
progress: 0
}
const [showMessageModal, setShowMessageModal] = useState(false)
const progressValue = Math.round(currentState.progress * 1000) / 10
const isCircularLoading = circularLoadingTypes.includes(currentState.type)
const showCircularLoading = isCircularLoading && showProgress
return (
<>
<Flex gap='small' align={'center'}>
{showState && (
<Space>
<StateTag state={currentState.type} />
<StateTag state={currentState.type} loading={showCircularLoading} />
</Space>
)}
{showProgress &&
loadingProgressTypes.includes(currentState.type) &&
currentState?.progress &&

View File

@ -1,8 +1,15 @@
import PropTypes from 'prop-types'
import { Badge, Flex, Tag } from 'antd'
import { useMemo } from 'react'
import LoadingIcon from '../../Icons/LoadingIcon'
const StateTag = ({ state, showBadge = true, showTag = true, style = {} }) => {
const StateTag = ({
state,
showBadge = true,
showTag = true,
loading = false,
style = {}
}) => {
const { badgeStatus, badgeText } = useMemo(() => {
let status = 'default'
let text = 'Unknown'
@ -216,10 +223,17 @@ const StateTag = ({ state, showBadge = true, showTag = true, style = {} }) => {
return <Badge {...badgeProps} style={{ ...style }} />
}
const showLoading = loading && showBadge
const padding = showLoading ? '0 6px' : '0 8px'
return (
<Tag color={badgeStatus} style={{ marginRight: 0, ...style }}>
<Tag color={badgeStatus} style={{ marginRight: 0, ...style, padding }}>
<Flex gap={6}>
{showBadge && <Badge {...badgeProps} />}
{showBadge && !loading && <Badge {...badgeProps} />}
{showLoading && (
<LoadingIcon style={{ fontSize: 8 }} className='state-tag-loading' />
)}
{badgeText}
</Flex>
</Tag>
@ -230,7 +244,8 @@ StateTag.propTypes = {
state: PropTypes.string,
showBadge: PropTypes.bool,
style: PropTypes.object,
showTag: PropTypes.bool
showTag: PropTypes.bool,
loading: PropTypes.bool
}
export default StateTag

View File

@ -2532,6 +2532,51 @@ const ApiServerProvider = ({ children }) => {
}
}
const fetchObjectViews = async (objectType) => {
if (!objectType) return { data: [] }
try {
const result = await fetchObjects('objectView', {
filter: { objectType },
limit: 100
})
return result || { data: [] }
} catch (err) {
console.error(err)
showError(err, () => fetchObjectViews(objectType))
return { data: [] }
}
}
const createObjectView = async (values) => {
try {
return await createObject('objectView', values)
} catch (err) {
console.error(err)
showError(err, () => createObjectView(values))
return null
}
}
const updateObjectView = async (objectViewId, updates) => {
try {
return await updateObject(objectViewId, 'objectView', updates)
} catch (err) {
console.error(err)
showError(err, () => updateObjectView(objectViewId, updates))
return null
}
}
const deleteObjectView = async (objectViewId) => {
try {
return await deleteObject(objectViewId, 'objectView')
} catch (err) {
console.error(err)
showError(err, () => deleteObjectView(objectViewId))
return null
}
}
const fetchNotificationsApi = useCallback(async () => {
const response = await axios.get(`${config.backendUrl}/notifications`, {
params: { limit: 100, sortProperty: 'createdAt', sortOrder: 'descend' },
@ -2848,6 +2893,10 @@ const ApiServerProvider = ({ children }) => {
fetchAllUserNotifiersForObject,
toggleUserNotifier,
editUserNotifier,
fetchObjectViews,
createObjectView,
updateObjectView,
deleteObjectView,
fetchNotificationsApi,
markNotificationAsReadApi,
markAllNotificationsAsReadApi,

View File

@ -0,0 +1,826 @@
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState
} from 'react'
import { message } from 'antd'
import PropTypes from 'prop-types'
import { ApiServerContext } from './ApiServerContext'
import { AuthContext } from './AuthContext'
import { useTableState } from './TableStateContext'
const ObjectListViewContext = createContext()
const ALL_TAB_KEY = 'all'
const getPreviousTabKey = (viewList, deletedKey) => {
const index = viewList.findIndex(
(view) => String(view._id) === String(deletedKey)
)
if (index <= 0) {
return ALL_TAB_KEY
}
return String(viewList[index - 1]._id)
}
const DEFAULT_VIEW = {
name: 'New View',
color: '#3498DB',
private: true,
filter: {},
sort: {}
}
// eslint-disable-next-line react-refresh/only-export-components
export const getObjectViewKey = (view) =>
view?._reference || view?._id || null
const resolveViewFromRef = (views, viewRef) => {
if (!viewRef) return null
return (
views.find(
(view) =>
view._reference === viewRef || String(view._id) === String(viewRef)
) || null
)
}
const cloneViews = (views) =>
views.map((view) => ({
...view,
filter: view.filter ? { ...view.filter } : {},
sort: view.sort ? { ...view.sort } : {}
}))
const getViewTabSignature = (view) =>
`${view._id}:${view.name}:${view.color}:${view.private}:${view._isDraft ? 1 : 0}`
const viewStateEqual = (left, right) =>
JSON.stringify(left || {}) === JSON.stringify(right || {})
export const ObjectListViewProvider = ({
children,
objectType,
tableRef,
onViewStateChange
}) => {
const {
fetchObjectViews,
createObjectView,
updateObjectView,
deleteObjectView,
connected,
subscribeToObjectTypeUpdates,
subscribeToObjectUpdates
} = useContext(ApiServerContext)
const { token, authInitialized } = useContext(AuthContext)
const { getViewFromUrl, persistView } = useTableState()
const [views, setViews] = useState([])
const [draftViews, setDraftViews] = useState([])
const [initialLoading, setInitialLoading] = useState(true)
const [saving, setSaving] = useState(false)
const [activeTabKey, setActiveTabKey] = useState(ALL_TAB_KEY)
const [isEditing, setIsEditing] = useState(false)
const editSnapshotRef = useRef([])
const wasEditingRef = useRef(false)
const isEditingRef = useRef(isEditing)
const activeViewRef = useRef(null)
const viewsStateRef = useRef({ views, draftViews, isEditing })
const urlSyncedRef = useRef(false)
isEditingRef.current = isEditing
const apiRef = useRef({
fetchObjectViews,
createObjectView,
updateObjectView,
deleteObjectView
})
apiRef.current = {
fetchObjectViews,
createObjectView,
updateObjectView,
deleteObjectView
}
const subscribedIdsRef = useRef([])
const unsubscribesRef = useRef([])
const subscribeToObjectTypeUpdatesRef = useRef(null)
const updateEventHandlerRef = useRef()
const authReady = Boolean(token && authInitialized)
const displayedViews = isEditing ? draftViews : views
const activeView = useMemo(() => {
if (activeTabKey === ALL_TAB_KEY) return null
const view =
displayedViews.find((item) => String(item._id) === String(activeTabKey)) ||
null
if (view?._isDraft) {
return { ...view, filter: view.filter || {}, sort: view.sort || {} }
}
return view
}, [activeTabKey, displayedViews])
viewsStateRef.current = { views, draftViews, isEditing }
activeViewRef.current = activeView
const applyViewToTable = useCallback(
(tabKey) => {
if (!tableRef?.current?.applyViewState) return
const { views: savedViews, draftViews: drafts, isEditing: editing } =
viewsStateRef.current
const list = editing ? drafts : savedViews
const view =
tabKey === ALL_TAB_KEY
? null
: list.find((item) => String(item._id) === String(tabKey)) || null
if (tabKey !== ALL_TAB_KEY && !view) return
if (editing) {
tableRef.current.setListViewMasters?.({
masterFilter: {},
masterSort: {}
})
tableRef.current.applyViewState(
view?.filter || {},
view?.sort?.field ? view.sort : {}
)
return
}
tableRef.current.setListViewMasters?.({
masterFilter: view?.filter || {},
masterSort: view?.sort?.field ? view.sort : {}
})
tableRef.current.applyViewState(null, null)
},
[tableRef]
)
const loadViews = useCallback(
async (silent = false) => {
if (!authReady || !objectType) return
if (!silent) setInitialLoading(true)
try {
const { data } = await apiRef.current.fetchObjectViews(objectType)
const nextViews = data || []
setViews(nextViews)
if (!isEditingRef.current) {
setDraftViews(cloneViews(nextViews))
}
return nextViews
} catch (error) {
console.error('Error fetching object views:', error)
return []
} finally {
if (!silent) setInitialLoading(false)
}
},
[authReady, objectType]
)
const loadViewsRef = useRef(loadViews)
loadViewsRef.current = loadViews
useEffect(() => {
urlSyncedRef.current = false
setActiveTabKey(ALL_TAB_KEY)
}, [objectType])
useEffect(() => {
loadViews()
}, [loadViews])
useEffect(() => {
if (initialLoading) return
applyViewToTable(activeTabKey)
}, [activeTabKey, applyViewToTable, initialLoading, isEditing])
useEffect(() => {
if (initialLoading || urlSyncedRef.current) return
const viewRef = getViewFromUrl()
if (!viewRef) {
urlSyncedRef.current = true
return
}
const matched =
resolveViewFromRef(views, viewRef) ||
resolveViewFromRef(draftViews, viewRef)
if (matched) {
setActiveTabKey(String(matched._id))
urlSyncedRef.current = true
return
}
// Wait until views have loaded before deciding the URL reference is invalid
if (views.length === 0) return
if (!isEditing) {
persistView(null)
}
urlSyncedRef.current = true
}, [
initialLoading,
views,
draftViews,
isEditing,
getViewFromUrl,
persistView
])
const selectTab = useCallback(
(tabKey) => {
if (String(tabKey) === String(activeTabKey)) return
setActiveTabKey(tabKey)
if (tabKey === ALL_TAB_KEY) {
persistView(null)
return
}
const view = (isEditing ? draftViews : views).find(
(item) => String(item._id) === String(tabKey)
)
if (!view || view._isDraft) return
persistView(getObjectViewKey(view))
},
[activeTabKey, draftViews, isEditing, persistView, views]
)
useEffect(() => {
if (isEditing && !wasEditingRef.current) {
const snapshot = cloneViews(views)
editSnapshotRef.current = snapshot
setDraftViews(snapshot)
}
wasEditingRef.current = isEditing
}, [isEditing, views])
const startEditing = useCallback(() => {
const snapshot = cloneViews(views)
editSnapshotRef.current = snapshot
setDraftViews(snapshot)
setIsEditing(true)
}, [views])
const cancelEdits = useCallback(async () => {
const snapshot = cloneViews(editSnapshotRef.current)
setDraftViews(snapshot)
setViews(snapshot)
setIsEditing(false)
if (activeTabKey !== ALL_TAB_KEY) {
const stillExists = snapshot.some(
(view) => String(view._id) === String(activeTabKey)
)
if (!stillExists) {
setActiveTabKey(ALL_TAB_KEY)
persistView(null)
applyViewToTable(ALL_TAB_KEY)
}
}
await loadViewsRef.current(true)
}, [activeTabKey, applyViewToTable, persistView])
const saveEdits = useCallback(async () => {
setSaving(true)
try {
const originalById = new Map(views.map((view) => [String(view._id), view]))
const draftById = new Map(draftViews.map((view) => [String(view._id), view]))
let newActiveId = activeTabKey
for (const draft of draftViews) {
if (draft._isDraft) {
const created = await apiRef.current.createObjectView({
objectType,
name: draft.name,
color: draft.color,
private: draft.private !== false,
filter: draft.filter || {},
sort: draft.sort || {}
})
if (String(activeTabKey) === String(draft._id) && created?._id) {
newActiveId = created._id
}
continue
}
const original = originalById.get(String(draft._id))
if (!original) continue
const updates = {}
if (draft.name !== original.name) updates.name = draft.name
if (draft.color !== original.color) updates.color = draft.color
if (draft.private !== original.private) updates.private = draft.private
if (!viewStateEqual(draft.filter, original.filter)) {
updates.filter = draft.filter || {}
}
if (!viewStateEqual(draft.sort, original.sort)) {
updates.sort = draft.sort || {}
}
if (Object.keys(updates).length > 0) {
await apiRef.current.updateObjectView(draft._id, updates)
}
}
for (const original of views) {
if (!draftById.has(String(original._id))) {
await apiRef.current.deleteObjectView(original._id)
}
}
const refreshed = (await loadViewsRef.current(true)) || []
setDraftViews(cloneViews(refreshed))
setIsEditing(false)
let resolvedTabKey = String(activeTabKey)
if (
String(activeTabKey).startsWith('draft-') &&
newActiveId &&
String(newActiveId) !== String(activeTabKey)
) {
resolvedTabKey = String(newActiveId)
}
const savedView =
refreshed.find((view) => String(view._id) === resolvedTabKey) ||
draftViews.find((view) => String(view._id) === resolvedTabKey)
if (resolvedTabKey !== ALL_TAB_KEY && savedView && !savedView._isDraft) {
setActiveTabKey(resolvedTabKey)
persistView(getObjectViewKey(savedView))
} else if (resolvedTabKey !== ALL_TAB_KEY && !savedView) {
resolvedTabKey = ALL_TAB_KEY
setActiveTabKey(ALL_TAB_KEY)
persistView(null)
}
message.success('Views saved')
} catch (error) {
console.error('Error saving object views:', error)
message.error('Failed to save views')
} finally {
setSaving(false)
}
}, [
activeTabKey,
draftViews,
objectType,
persistView,
views
])
const handleTabEdit = useCallback(
async (targetKeyOrEvent, action) => {
if (action === 'add') {
if (isEditing) {
const tempView = {
_id: `draft-${Date.now()}`,
_isDraft: true,
objectType,
...DEFAULT_VIEW
}
setDraftViews((prev) => [...prev, tempView])
const newKey = String(tempView._id)
setActiveTabKey(newKey)
applyViewToTable(newKey)
return
}
setSaving(true)
try {
const created = await apiRef.current.createObjectView({
objectType,
...DEFAULT_VIEW
})
if (created?._id) {
const nextViews = [...views, created]
setViews(nextViews)
setDraftViews(cloneViews(nextViews))
const newKey = String(created._id)
setActiveTabKey(newKey)
applyViewToTable(newKey)
persistView(getObjectViewKey(created))
} else {
message.error('Failed to create view')
}
} catch (error) {
console.error('Error creating object view:', error)
message.error('Failed to create view')
} finally {
setSaving(false)
}
return
}
if (!isEditing) return
const targetKey =
typeof targetKeyOrEvent === 'string' ? targetKeyOrEvent : null
if (action === 'remove' && targetKey && targetKey !== ALL_TAB_KEY) {
const isActiveDeleted = String(activeTabKey) === String(targetKey)
const previousKey = isActiveDeleted
? getPreviousTabKey(draftViews, targetKey)
: null
setDraftViews((prev) =>
prev.filter((view) => String(view._id) !== String(targetKey))
)
if (isActiveDeleted) {
setActiveTabKey(previousKey)
if (previousKey === ALL_TAB_KEY) {
persistView(null)
} else {
const view = draftViews.find(
(item) => String(item._id) === String(previousKey)
)
if (view && !view._isDraft) {
persistView(getObjectViewKey(view))
}
}
applyViewToTable(previousKey)
}
}
},
[
activeTabKey,
applyViewToTable,
draftViews,
isEditing,
objectType,
persistView,
views
]
)
const updateDraftView = useCallback((viewId, changes) => {
setDraftViews((prev) =>
prev.map((view) =>
String(view._id) === String(viewId) ? { ...view, ...changes } : view
)
)
}, [])
const reorderDraftViews = useCallback((fromValue, toValue, insertBefore) => {
if (!isEditing) return
setDraftViews((prev) => {
const fromIndex = prev.findIndex(
(view) => String(view._id) === String(fromValue)
)
const toIndex = prev.findIndex(
(view) => String(view._id) === String(toValue)
)
if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {
return prev
}
let targetIndex = insertBefore ? toIndex : toIndex + 1
if (fromIndex < targetIndex) {
targetIndex -= 1
}
if (fromIndex === targetIndex) {
return prev
}
const next = [...prev]
const [moved] = next.splice(fromIndex, 1)
next.splice(targetIndex, 0, moved)
return next
})
}, [isEditing])
const mergeViewUpdate = useCallback(
(viewId, updatedData) => {
const mergeOne = (prev) =>
prev.map((view) =>
String(view._id) === String(viewId) ? { ...view, ...updatedData } : view
)
setViews(mergeOne)
if (!isEditing) {
setDraftViews(mergeOne)
}
},
[isEditing]
)
const removeView = useCallback(
(viewId) => {
const list = isEditing ? draftViews : views
const isActiveDeleted = String(activeTabKey) === String(viewId)
const previousKey = isActiveDeleted
? getPreviousTabKey(list, viewId)
: null
setViews((prev) => prev.filter((view) => String(view._id) !== String(viewId)))
if (!isEditing) {
setDraftViews((prev) =>
prev.filter((view) => String(view._id) !== String(viewId))
)
}
if (isActiveDeleted) {
setActiveTabKey(previousKey)
if (previousKey === ALL_TAB_KEY) {
persistView(null)
} else {
const view = list.find(
(item) => String(item._id) === String(previousKey)
)
if (view && !view._isDraft) {
persistView(getObjectViewKey(view))
}
}
applyViewToTable(previousKey)
}
},
[activeTabKey, applyViewToTable, draftViews, isEditing, persistView, views]
)
const handleFilterSortChange = useCallback((filter, sorter) => {
if (!isEditingRef.current) return
const view = activeViewRef.current
if (!view) return
const nextFilter = filter || {}
const nextSort = sorter || {}
const updateInList = (list) =>
list.map((item) =>
String(item._id) === String(view._id)
? { ...item, filter: nextFilter, sort: nextSort }
: item
)
activeViewRef.current = {
...view,
filter: nextFilter,
sort: nextSort
}
setDraftViews((prev) => updateInList(prev))
viewsStateRef.current = {
...viewsStateRef.current,
draftViews: updateInList(viewsStateRef.current.draftViews)
}
}, [])
const viewMatchesType = useCallback(
(view) => view?.objectType === objectType,
[objectType]
)
const updateEventHandler = useCallback(
(id, updatedData) => {
const merged = { _id: id, ...updatedData }
if (!viewMatchesType(merged)) {
removeView(id)
return
}
mergeViewUpdate(id, updatedData)
},
[mergeViewUpdate, removeView, viewMatchesType]
)
updateEventHandlerRef.current = updateEventHandler
const subscriptionFilter = useMemo(
() => ({ objectType }),
[objectType]
)
useEffect(() => {
if (connected !== true || !objectType || !authReady) return
const unsubscribe = subscribeToObjectTypeUpdates(
'objectView',
subscriptionFilter,
() => {
loadViewsRef.current(true)
}
)
subscribeToObjectTypeUpdatesRef.current = unsubscribe
return () => {
if (unsubscribe) unsubscribe()
if (subscribeToObjectTypeUpdatesRef.current === unsubscribe) {
subscribeToObjectTypeUpdatesRef.current = null
}
}
}, [
authReady,
connected,
objectType,
subscribeToObjectTypeUpdates,
subscriptionFilter
])
const subscribedViewIds = useMemo(
() => views.map((view) => view._id).filter(Boolean),
[views]
)
useEffect(() => {
if (connected !== true) return
const newViewIds = subscribedViewIds.filter(
(id) => !subscribedIdsRef.current.includes(id)
)
newViewIds.forEach((itemId) => {
const unsubscribe = subscribeToObjectUpdates(
itemId?.toLowerCase(),
'objectView',
(updateData) => updateEventHandlerRef.current(itemId, updateData)
)
subscribedIdsRef.current.push(itemId)
if (unsubscribe) {
unsubscribesRef.current.push(unsubscribe)
}
})
const viewIdsToUnsubscribe = subscribedIdsRef.current.filter(
(id) => !subscribedViewIds.includes(id)
)
viewIdsToUnsubscribe.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)
}
})
}, [connected, subscribeToObjectUpdates, subscribedViewIds])
useEffect(
() => () => {
unsubscribesRef.current.forEach((unsubscribe) => {
if (unsubscribe) unsubscribe()
})
unsubscribesRef.current = []
subscribedIdsRef.current = []
if (subscribeToObjectTypeUpdatesRef.current) {
subscribeToObjectTypeUpdatesRef.current()
subscribeToObjectTypeUpdatesRef.current = null
}
},
[]
)
const handleFilterSortChangeRef = useRef(handleFilterSortChange)
handleFilterSortChangeRef.current = handleFilterSortChange
const stableFilterSortHandlerRef = useRef((filter, sorter) => {
handleFilterSortChangeRef.current?.(filter, sorter)
})
const lastSyncedViewKeyRef = useRef(null)
const masterFilter = useMemo(() => {
if (isEditing || !activeView) return {}
return activeView.filter || {}
}, [activeView, isEditing])
const masterSort = useMemo(() => {
if (isEditing || !activeView?.sort?.field) return {}
return activeView.sort
}, [activeView, isEditing])
useEffect(() => {
const viewKey = isEditing
? `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,
masterFilter,
masterSort,
isEditing,
handleFilterSortChange: isEditing
? stableFilterSortHandlerRef.current
: null
})
}, [
activeTabKey,
activeView?._id,
isEditing,
masterFilter,
masterSort,
onViewStateChange
])
const viewTabSignatures = useMemo(
() => displayedViews.map(getViewTabSignature).join('|'),
[displayedViews]
)
const value = useMemo(
() => ({
objectType,
ALL_TAB_KEY,
views: displayedViews,
activeView,
activeTabKey,
masterFilter,
masterSort,
initialLoading,
saving,
isEditing,
selectTab,
startEditing,
saveEdits,
cancelEdits,
handleTabEdit,
updateDraftView,
reorderDraftViews,
mergeViewUpdate,
removeView,
handleFilterSortChange,
reloadViews: () => loadViewsRef.current(true),
viewTabSignatures
}),
[
objectType,
displayedViews,
activeView,
activeTabKey,
masterFilter,
masterSort,
initialLoading,
saving,
isEditing,
selectTab,
startEditing,
saveEdits,
cancelEdits,
handleTabEdit,
updateDraftView,
reorderDraftViews,
mergeViewUpdate,
removeView,
handleFilterSortChange,
viewTabSignatures
]
)
return (
<ObjectListViewContext.Provider value={value}>
{children}
</ObjectListViewContext.Provider>
)
}
// eslint-disable-next-line react-refresh/only-export-components
export const useObjectListView = () => {
const context = useContext(ObjectListViewContext)
if (!context) {
throw new Error(
'useObjectListView must be used within an ObjectListViewProvider'
)
}
return context
}
ObjectListViewProvider.propTypes = {
children: PropTypes.node.isRequired,
objectType: PropTypes.string.isRequired,
tableRef: PropTypes.object,
onViewStateChange: PropTypes.func
}
// eslint-disable-next-line react-refresh/only-export-components
export { ALL_TAB_KEY }
export default ObjectListViewContext

View File

@ -12,6 +12,7 @@ const TableStateContext = createContext()
export const FILTER_URL_PARAM = 'filter'
export const SORT_URL_PARAM = 'sort'
export const VIEW_URL_PARAM = 'view'
const getSessionFilterKey = (scope) => `tableState:${scope}:filter`
const getSessionSortKey = (scope) => `tableState:${scope}:sort`
@ -44,6 +45,8 @@ const readSortFromUrl = (searchParams) => {
return { field: parsed.field, order: parsed.order }
}
const readViewFromUrl = (searchParams) => searchParams.get(VIEW_URL_PARAM) || null
const readFilterFromSession = (scope) => {
try {
return parseJsonParam(sessionStorage.getItem(getSessionFilterKey(scope)))
@ -128,6 +131,24 @@ export const TableStateProvider = ({ children }) => {
[searchParams]
)
const getViewFromUrl = useCallback(
() => readViewFromUrl(searchParams),
[searchParams]
)
const persistView = useCallback(
(viewRef) => {
const next = new URLSearchParams(searchParams)
if (viewRef) {
next.set(VIEW_URL_PARAM, viewRef)
} else {
next.delete(VIEW_URL_PARAM)
}
setSearchParams(next, { replace: true })
},
[searchParams, setSearchParams]
)
const persistFilter = useCallback(
(
scope,
@ -256,6 +277,8 @@ export const TableStateProvider = ({ children }) => {
() => ({
getPersistedFilter,
getPersistedSorter,
getViewFromUrl,
persistView,
persistFilter,
persistSort,
persistTableState,
@ -269,6 +292,8 @@ export const TableStateProvider = ({ children }) => {
[
getPersistedFilter,
getPersistedSorter,
getViewFromUrl,
persistView,
persistFilter,
persistSort,
persistTableState,

View File

@ -171,11 +171,27 @@ export const ThemeProvider = ({ children }) => {
'--layout-modal-bg',
isDarkMode ? '#1f1f1f' : '#ffffff'
)
root.style.setProperty(
'--color-background',
isDarkMode ? '#000000' : '#ffffff'
)
root.style.setProperty('--color-text', isDarkMode ? '#ffffff' : '#000000')
root.style.setProperty(
'--color-descriptions-border',
isDarkMode ? 'rgba(253,253,253,0.12)' : 'rgba(5,5,5,0.06)'
)
root.style.setProperty(
'--color-list-view-tabs-border',
isDarkMode ? '#2a2a2a' : '#E7E7E7'
)
root.style.setProperty(
'--color-button-background',
isDarkMode ? '#141414' : '#FFFFFF'
)
root.style.setProperty(
'--color-button-border',
isDarkMode ? '#424242' : '#d9d9d9'
)
}, [isDarkMode, primaryColorOverride])
const themeConfig = {

View File

@ -110,7 +110,7 @@ export const DocumentPrinter = {
],
sorters: [
'name',
'documentSize',
'currentDocumentSize',
'connectedAt',
'connection.port',
'updatedAt',
@ -261,15 +261,47 @@ export const DocumentPrinter = {
},
columnWidth: 85
},
{
name: 'connection.username',
label: 'Username',
type: 'text',
required: false,
visible: (objectData) => objectData?.connection?.interface === 'cups',
columnWidth: 150
},
{
name: 'connection.password',
label: 'Password',
type: 'secret',
required: false,
visible: (objectData) => objectData?.connection?.interface === 'cups',
columnWidth: 150
},
{
name: 'currentDocumentSize',
label: 'Document Size',
label: 'Current Document Size',
required: false,
type: 'object',
objectType: 'documentSize',
showHyperlink: true,
columnWidth: 200
},
{
name: 'rotateOrientation',
label: 'Rotate Orientation',
required: false,
type: 'bool',
columnWidth: 150
},
{
name: 'supportedDocumentSizes',
label: 'Supported Document Sizes',
required: false,
type: 'objectList',
objectType: 'documentSize',
showHyperlink: true,
columnWidth: 260
},
{
name: 'tags',
label: 'Tags',