From 96b809b9d84ccded495d2a5fa475f9ce91d09753 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Wed, 2 Sep 2026 20:56:08 +0100 Subject: [PATCH] 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. --- assets/stylesheets/App.css | 251 +++++- src/components/Dashboard/Finance/Invoices.jsx | 29 +- .../Dashboard/Finance/PaymentPolicies.jsx | 29 +- src/components/Dashboard/Finance/Payments.jsx | 29 +- .../Dashboard/Finance/TaxRecords.jsx | 29 +- .../Dashboard/Inventory/FilamentStocks.jsx | 29 +- .../Dashboard/Inventory/OrderItems.jsx | 29 +- .../Dashboard/Inventory/PartStocks.jsx | 29 +- .../Dashboard/Inventory/ProductStocks.jsx | 29 +- .../Dashboard/Inventory/PurchaseOrders.jsx | 29 +- .../Dashboard/Inventory/Shipments.jsx | 29 +- .../Dashboard/Inventory/StockAudits.jsx | 29 +- .../Dashboard/Inventory/StockEvents.jsx | 29 +- .../Dashboard/Inventory/StockLocations.jsx | 29 +- .../Dashboard/Inventory/StockTransfers.jsx | 29 +- .../Dashboard/Management/AppPasswords.jsx | 29 +- .../Dashboard/Management/AuditLogs.jsx | 28 +- .../Dashboard/Management/CourierServices.jsx | 29 +- .../Dashboard/Management/Couriers.jsx | 29 +- .../Dashboard/Management/DocumentJobs.jsx | 29 +- .../Dashboard/Management/DocumentPrinters.jsx | 29 +- .../Dashboard/Management/DocumentSizes.jsx | 29 +- .../Management/DocumentTemplates.jsx | 29 +- .../Dashboard/Management/FilamentSkus.jsx | 29 +- .../Dashboard/Management/Filaments.jsx | 29 +- src/components/Dashboard/Management/Files.jsx | 29 +- src/components/Dashboard/Management/Hosts.jsx | 29 +- .../Dashboard/Management/Materials.jsx | 29 +- .../Dashboard/Management/NoteTypes.jsx | 29 +- .../Dashboard/Management/PartSkus.jsx | 29 +- src/components/Dashboard/Management/Parts.jsx | 29 +- .../Management/PermissionSettings.jsx | 29 +- .../Management/ProductCategories.jsx | 29 +- .../Dashboard/Management/ProductSkus.jsx | 29 +- .../Dashboard/Management/Products.jsx | 29 +- .../Dashboard/Management/StockAuditLevels.jsx | 29 +- .../Dashboard/Management/TaxRates.jsx | 29 +- .../Dashboard/Management/UserGroups.jsx | 29 +- src/components/Dashboard/Management/Users.jsx | 28 +- .../Dashboard/Management/Vendors.jsx | 81 +- .../Dashboard/Production/FilamentProfiles.jsx | 29 +- .../Dashboard/Production/GCodeFiles.jsx | 29 +- src/components/Dashboard/Production/Jobs.jsx | 30 +- .../Dashboard/Production/PrinterProfiles.jsx | 29 +- .../Dashboard/Production/Printers.jsx | 29 +- .../Dashboard/Production/SubJobs.jsx | 30 +- src/components/Dashboard/Sales/Clients.jsx | 29 +- .../Dashboard/Sales/FulfillmentPolicies.jsx | 29 +- .../Dashboard/Sales/ListingVarients.jsx | 29 +- src/components/Dashboard/Sales/Listings.jsx | 29 +- .../Dashboard/Sales/Marketplaces.jsx | 29 +- .../Dashboard/Sales/ReturnPolicies.jsx | 29 +- .../Dashboard/Sales/SalesOrders.jsx | 29 +- .../Dashboard/common/ColorSelector.jsx | 31 +- .../Dashboard/common/FilterInput.jsx | 3 +- .../Dashboard/common/ListViewEditButtons.jsx | 38 + .../Dashboard/common/ListViewTabs.jsx | 308 +++++++ .../Dashboard/common/ObjectTable.jsx | 171 +++- .../Dashboard/common/PropertyChanges.jsx | 2 + src/components/Dashboard/common/ScrollBox.jsx | 26 +- .../Dashboard/common/SegmentedNav.jsx | 431 +++++++++ .../Dashboard/common/StateDisplay.jsx | 9 +- src/components/Dashboard/common/StateTag.jsx | 23 +- .../Dashboard/context/ApiServerContext.jsx | 49 ++ .../context/ObjectListViewContext.jsx | 826 ++++++++++++++++++ .../Dashboard/context/TableStateContext.jsx | 25 + .../Dashboard/context/ThemeContext.jsx | 16 + src/database/models/DocumentPrinter.js | 36 +- 68 files changed, 3421 insertions(+), 384 deletions(-) create mode 100644 src/components/Dashboard/common/ListViewEditButtons.jsx create mode 100644 src/components/Dashboard/common/ListViewTabs.jsx create mode 100644 src/components/Dashboard/common/SegmentedNav.jsx create mode 100644 src/components/Dashboard/context/ObjectListViewContext.jsx diff --git a/assets/stylesheets/App.css b/assets/stylesheets/App.css index 542ed12d..bf683abc 100644 --- a/assets/stylesheets/App.css +++ b/assets/stylesheets/App.css @@ -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; +} diff --git a/src/components/Dashboard/Finance/Invoices.jsx b/src/components/Dashboard/Finance/Invoices.jsx index 908d1b34..657a28ff 100644 --- a/src/components/Dashboard/Finance/Invoices.jsx +++ b/src/components/Dashboard/Finance/Invoices.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const Invoices = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Finance/PaymentPolicies.jsx b/src/components/Dashboard/Finance/PaymentPolicies.jsx index 8276751a..ceae4f43 100644 --- a/src/components/Dashboard/Finance/PaymentPolicies.jsx +++ b/src/components/Dashboard/Finance/PaymentPolicies.jsx @@ -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 ( - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -51,10 +65,11 @@ const PaymentPolicies = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> ) diff --git a/src/components/Dashboard/Finance/Payments.jsx b/src/components/Dashboard/Finance/Payments.jsx index 5e78da00..10d06935 100644 --- a/src/components/Dashboard/Finance/Payments.jsx +++ b/src/components/Dashboard/Finance/Payments.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const Payments = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Finance/TaxRecords.jsx b/src/components/Dashboard/Finance/TaxRecords.jsx index 914d794e..a103315d 100644 --- a/src/components/Dashboard/Finance/TaxRecords.jsx +++ b/src/components/Dashboard/Finance/TaxRecords.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const TaxRecords = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/FilamentStocks.jsx b/src/components/Dashboard/Inventory/FilamentStocks.jsx index ae822377..8b3079ad 100644 --- a/src/components/Dashboard/Inventory/FilamentStocks.jsx +++ b/src/components/Dashboard/Inventory/FilamentStocks.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -62,10 +76,11 @@ const FilamentStocks = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/OrderItems.jsx b/src/components/Dashboard/Inventory/OrderItems.jsx index ec7e12bb..23efe527 100644 --- a/src/components/Dashboard/Inventory/OrderItems.jsx +++ b/src/components/Dashboard/Inventory/OrderItems.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const OrderItems = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/PartStocks.jsx b/src/components/Dashboard/Inventory/PartStocks.jsx index 836ddeec..4a4f2f3d 100644 --- a/src/components/Dashboard/Inventory/PartStocks.jsx +++ b/src/components/Dashboard/Inventory/PartStocks.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -62,10 +76,11 @@ const PartStocks = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/ProductStocks.jsx b/src/components/Dashboard/Inventory/ProductStocks.jsx index 8a92d938..d2797fd9 100644 --- a/src/components/Dashboard/Inventory/ProductStocks.jsx +++ b/src/components/Dashboard/Inventory/ProductStocks.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -63,10 +77,11 @@ const ProductStocks = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/PurchaseOrders.jsx b/src/components/Dashboard/Inventory/PurchaseOrders.jsx index d937f23d..470e3e81 100644 --- a/src/components/Dashboard/Inventory/PurchaseOrders.jsx +++ b/src/components/Dashboard/Inventory/PurchaseOrders.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const PurchaseOrders = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/Shipments.jsx b/src/components/Dashboard/Inventory/Shipments.jsx index 64ccc1ae..b18a5879 100644 --- a/src/components/Dashboard/Inventory/Shipments.jsx +++ b/src/components/Dashboard/Inventory/Shipments.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const Shipments = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/StockAudits.jsx b/src/components/Dashboard/Inventory/StockAudits.jsx index d5a42d9f..1dbeafff 100644 --- a/src/components/Dashboard/Inventory/StockAudits.jsx +++ b/src/components/Dashboard/Inventory/StockAudits.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -62,10 +76,11 @@ const StockAudits = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/StockEvents.jsx b/src/components/Dashboard/Inventory/StockEvents.jsx index bc26c236..73ea5123 100644 --- a/src/components/Dashboard/Inventory/StockEvents.jsx +++ b/src/components/Dashboard/Inventory/StockEvents.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const StockEvents = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/StockLocations.jsx b/src/components/Dashboard/Inventory/StockLocations.jsx index f1fae7ac..0abf31a1 100644 --- a/src/components/Dashboard/Inventory/StockLocations.jsx +++ b/src/components/Dashboard/Inventory/StockLocations.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -60,10 +74,11 @@ const StockLocations = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Inventory/StockTransfers.jsx b/src/components/Dashboard/Inventory/StockTransfers.jsx index b499b6cd..f3ccbfe0 100644 --- a/src/components/Dashboard/Inventory/StockTransfers.jsx +++ b/src/components/Dashboard/Inventory/StockTransfers.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -60,10 +74,11 @@ const StockTransfers = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/AppPasswords.jsx b/src/components/Dashboard/Management/AppPasswords.jsx index 614da466..c034566a 100644 --- a/src/components/Dashboard/Management/AppPasswords.jsx +++ b/src/components/Dashboard/Management/AppPasswords.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const AppPasswords = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/AuditLogs.jsx b/src/components/Dashboard/Management/AuditLogs.jsx index e4847c48..55481a62 100644 --- a/src/components/Dashboard/Management/AuditLogs.jsx +++ b/src/components/Dashboard/Management/AuditLogs.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -51,8 +65,10 @@ const AuditLogs = () => { active={showFilterSidebar} onClick={() => setShowFilterSidebar(!showFilterSidebar)} /> + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/CourierServices.jsx b/src/components/Dashboard/Management/CourierServices.jsx index 9db59fd3..3b72b435 100644 --- a/src/components/Dashboard/Management/CourierServices.jsx +++ b/src/components/Dashboard/Management/CourierServices.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const CourierServices = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Couriers.jsx b/src/components/Dashboard/Management/Couriers.jsx index 97a85d12..9b48f6bb 100644 --- a/src/components/Dashboard/Management/Couriers.jsx +++ b/src/components/Dashboard/Management/Couriers.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const Couriers = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/DocumentJobs.jsx b/src/components/Dashboard/Management/DocumentJobs.jsx index 21547110..6be2968d 100644 --- a/src/components/Dashboard/Management/DocumentJobs.jsx +++ b/src/components/Dashboard/Management/DocumentJobs.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const DocumentJobs = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/DocumentPrinters.jsx b/src/components/Dashboard/Management/DocumentPrinters.jsx index 5a295ab5..f43859d6 100644 --- a/src/components/Dashboard/Management/DocumentPrinters.jsx +++ b/src/components/Dashboard/Management/DocumentPrinters.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const DocumentPrinters = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/DocumentSizes.jsx b/src/components/Dashboard/Management/DocumentSizes.jsx index 7400c3a6..111cdf3f 100644 --- a/src/components/Dashboard/Management/DocumentSizes.jsx +++ b/src/components/Dashboard/Management/DocumentSizes.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -55,10 +69,11 @@ const DocumentSizes = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/DocumentTemplates.jsx b/src/components/Dashboard/Management/DocumentTemplates.jsx index 484fc12f..0c7a04c7 100644 --- a/src/components/Dashboard/Management/DocumentTemplates.jsx +++ b/src/components/Dashboard/Management/DocumentTemplates.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const DocumentTemplates = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/FilamentSkus.jsx b/src/components/Dashboard/Management/FilamentSkus.jsx index d93e6825..a6c2dc54 100644 --- a/src/components/Dashboard/Management/FilamentSkus.jsx +++ b/src/components/Dashboard/Management/FilamentSkus.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -60,10 +74,11 @@ const FilamentSkus = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Filaments.jsx b/src/components/Dashboard/Management/Filaments.jsx index 0a0b7a77..b03a78b8 100644 --- a/src/components/Dashboard/Management/Filaments.jsx +++ b/src/components/Dashboard/Management/Filaments.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -62,10 +76,11 @@ const Filaments = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Files.jsx b/src/components/Dashboard/Management/Files.jsx index f5cf2ee2..62fafe18 100644 --- a/src/components/Dashboard/Management/Files.jsx +++ b/src/components/Dashboard/Management/Files.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const Files = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Hosts.jsx b/src/components/Dashboard/Management/Hosts.jsx index da5c5fce..aadd78bb 100644 --- a/src/components/Dashboard/Management/Hosts.jsx +++ b/src/components/Dashboard/Management/Hosts.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -61,10 +75,11 @@ const Hosts = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Materials.jsx b/src/components/Dashboard/Management/Materials.jsx index 587802eb..2037eeec 100644 --- a/src/components/Dashboard/Management/Materials.jsx +++ b/src/components/Dashboard/Management/Materials.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -59,10 +73,11 @@ const Materials = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/NoteTypes.jsx b/src/components/Dashboard/Management/NoteTypes.jsx index 645d0874..e4a44e5e 100644 --- a/src/components/Dashboard/Management/NoteTypes.jsx +++ b/src/components/Dashboard/Management/NoteTypes.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const NoteTypes = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/PartSkus.jsx b/src/components/Dashboard/Management/PartSkus.jsx index 5b6b51b3..bf254942 100644 --- a/src/components/Dashboard/Management/PartSkus.jsx +++ b/src/components/Dashboard/Management/PartSkus.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -59,10 +73,11 @@ const PartSkus = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Parts.jsx b/src/components/Dashboard/Management/Parts.jsx index 6cc40e11..5235ca22 100644 --- a/src/components/Dashboard/Management/Parts.jsx +++ b/src/components/Dashboard/Management/Parts.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -61,10 +75,11 @@ const Parts = (filter) => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/PermissionSettings.jsx b/src/components/Dashboard/Management/PermissionSettings.jsx index 8f53e1c8..04a694da 100644 --- a/src/components/Dashboard/Management/PermissionSettings.jsx +++ b/src/components/Dashboard/Management/PermissionSettings.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const PermissionSettingsList = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/ProductCategories.jsx b/src/components/Dashboard/Management/ProductCategories.jsx index 7a1f9a75..6fdd1a97 100644 --- a/src/components/Dashboard/Management/ProductCategories.jsx +++ b/src/components/Dashboard/Management/ProductCategories.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -59,10 +73,11 @@ const ProductCategories = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/ProductSkus.jsx b/src/components/Dashboard/Management/ProductSkus.jsx index 9b43121b..30d7ad8a 100644 --- a/src/components/Dashboard/Management/ProductSkus.jsx +++ b/src/components/Dashboard/Management/ProductSkus.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -60,10 +74,11 @@ const ProductSkus = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Products.jsx b/src/components/Dashboard/Management/Products.jsx index bf53f1cf..85f09524 100644 --- a/src/components/Dashboard/Management/Products.jsx +++ b/src/components/Dashboard/Management/Products.jsx @@ -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 ( <> - - + + + { - + + setShowSortSidebar(!showSortSidebar)} @@ -332,10 +346,11 @@ const Products = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/StockAuditLevels.jsx b/src/components/Dashboard/Management/StockAuditLevels.jsx index b01b9b7d..2eec44f4 100644 --- a/src/components/Dashboard/Management/StockAuditLevels.jsx +++ b/src/components/Dashboard/Management/StockAuditLevels.jsx @@ -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 ( - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -55,10 +69,11 @@ const StockAuditLevels = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> ) diff --git a/src/components/Dashboard/Management/TaxRates.jsx b/src/components/Dashboard/Management/TaxRates.jsx index 720562ca..68d8a8d7 100644 --- a/src/components/Dashboard/Management/TaxRates.jsx +++ b/src/components/Dashboard/Management/TaxRates.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const TaxRates = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/UserGroups.jsx b/src/components/Dashboard/Management/UserGroups.jsx index 9a7a513f..c04c112a 100644 --- a/src/components/Dashboard/Management/UserGroups.jsx +++ b/src/components/Dashboard/Management/UserGroups.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const UserGroups = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Management/Users.jsx b/src/components/Dashboard/Management/Users.jsx index 6f6e6252..000b78c6 100644 --- a/src/components/Dashboard/Management/Users.jsx +++ b/src/components/Dashboard/Management/Users.jsx @@ -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 ( - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,8 +70,10 @@ const Users = () => { viewMode={viewMode} setViewMode={setViewMode} /> + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> ) diff --git a/src/components/Dashboard/Management/Vendors.jsx b/src/components/Dashboard/Management/Vendors.jsx index c477f133..66170460 100644 --- a/src/components/Dashboard/Management/Vendors.jsx +++ b/src/components/Dashboard/Management/Vendors.jsx @@ -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 ( <> - - - tableRef.current?.reload()} - /> - - - - - setShowSortSidebar(!showSortSidebar)} - /> - setShowFilterSidebar(!showFilterSidebar)} - /> - - - + + + + tableRef.current?.reload()} + /> + + + + + + setShowSortSidebar(!showSortSidebar)} + /> + setShowFilterSidebar(!showFilterSidebar)} + /> + + + + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Production/FilamentProfiles.jsx b/src/components/Dashboard/Production/FilamentProfiles.jsx index e44b19f8..431e6d0b 100644 --- a/src/components/Dashboard/Production/FilamentProfiles.jsx +++ b/src/components/Dashboard/Production/FilamentProfiles.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -53,10 +67,11 @@ const FilamentProfiles = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Production/GCodeFiles.jsx b/src/components/Dashboard/Production/GCodeFiles.jsx index da34da10..79484e9a 100644 --- a/src/components/Dashboard/Production/GCodeFiles.jsx +++ b/src/components/Dashboard/Production/GCodeFiles.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -59,10 +73,11 @@ const GCodeFiles = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Production/Jobs.jsx b/src/components/Dashboard/Production/Jobs.jsx index e8ad2728..2c656d16 100644 --- a/src/components/Dashboard/Production/Jobs.jsx +++ b/src/components/Dashboard/Production/Jobs.jsx @@ -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 ( <> - - + + + { /> - - + + setShowSortSidebar(!showSortSidebar)} @@ -58,10 +71,11 @@ const Jobs = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Production/PrinterProfiles.jsx b/src/components/Dashboard/Production/PrinterProfiles.jsx index 8a27d878..2c1f31bc 100644 --- a/src/components/Dashboard/Production/PrinterProfiles.jsx +++ b/src/components/Dashboard/Production/PrinterProfiles.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -52,10 +66,11 @@ const PrinterProfiles = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Production/Printers.jsx b/src/components/Dashboard/Production/Printers.jsx index 1bda5f81..4ab4cf19 100644 --- a/src/components/Dashboard/Production/Printers.jsx +++ b/src/components/Dashboard/Production/Printers.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -62,10 +76,11 @@ const Printers = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Production/SubJobs.jsx b/src/components/Dashboard/Production/SubJobs.jsx index a0a5cce7..2967e09b 100644 --- a/src/components/Dashboard/Production/SubJobs.jsx +++ b/src/components/Dashboard/Production/SubJobs.jsx @@ -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 ( <> - - + + + { /> - - + + setShowSortSidebar(!showSortSidebar)} @@ -58,10 +71,11 @@ const SubJobs = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Sales/Clients.jsx b/src/components/Dashboard/Sales/Clients.jsx index 1f759581..6b2ef043 100644 --- a/src/components/Dashboard/Sales/Clients.jsx +++ b/src/components/Dashboard/Sales/Clients.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -56,10 +70,11 @@ const Clients = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Sales/FulfillmentPolicies.jsx b/src/components/Dashboard/Sales/FulfillmentPolicies.jsx index a9c152f8..05af093b 100644 --- a/src/components/Dashboard/Sales/FulfillmentPolicies.jsx +++ b/src/components/Dashboard/Sales/FulfillmentPolicies.jsx @@ -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 ( - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -51,10 +65,11 @@ const FulfillmentPolicies = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> ) diff --git a/src/components/Dashboard/Sales/ListingVarients.jsx b/src/components/Dashboard/Sales/ListingVarients.jsx index e1e8a82e..dc80e2ee 100644 --- a/src/components/Dashboard/Sales/ListingVarients.jsx +++ b/src/components/Dashboard/Sales/ListingVarients.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const ListingVarients = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Sales/Listings.jsx b/src/components/Dashboard/Sales/Listings.jsx index 7970321e..e7bb520d 100644 --- a/src/components/Dashboard/Sales/Listings.jsx +++ b/src/components/Dashboard/Sales/Listings.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const Listings = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Sales/Marketplaces.jsx b/src/components/Dashboard/Sales/Marketplaces.jsx index 5fb300bd..e6ecbb73 100644 --- a/src/components/Dashboard/Sales/Marketplaces.jsx +++ b/src/components/Dashboard/Sales/Marketplaces.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const Marketplaces = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/Sales/ReturnPolicies.jsx b/src/components/Dashboard/Sales/ReturnPolicies.jsx index 954c4508..3d673e37 100644 --- a/src/components/Dashboard/Sales/ReturnPolicies.jsx +++ b/src/components/Dashboard/Sales/ReturnPolicies.jsx @@ -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 ( - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -50,10 +64,11 @@ const ReturnPolicies = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> ) diff --git a/src/components/Dashboard/Sales/SalesOrders.jsx b/src/components/Dashboard/Sales/SalesOrders.jsx index cad6c4b5..393a36e2 100644 --- a/src/components/Dashboard/Sales/SalesOrders.jsx +++ b/src/components/Dashboard/Sales/SalesOrders.jsx @@ -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 ( <> - - + + + { /> - + + setShowSortSidebar(!showSortSidebar)} @@ -57,10 +71,11 @@ const SalesOrders = () => { + - + + { saveSortInUrl={true} useSortInSession={true} useSortInUrl={true} + activeObjectView={viewState.activeView} + onObjectViewFilterSortChange={viewState.handleFilterSortChange} /> diff --git a/src/components/Dashboard/common/ColorSelector.jsx b/src/components/Dashboard/common/ColorSelector.jsx index fab7d860..6f87111f 100644 --- a/src/components/Dashboard/common/ColorSelector.jsx +++ b/src/components/Dashboard/common/ColorSelector.jsx @@ -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 ( - + {!required && ( { + const { isEditing, saving, saveEdits, cancelEdits, startEditing } = + useObjectListView() + + if (!isEditing) { + return null + } + + return ( + + {showStartingDivider && ( + + )} + { + await saveEdits() + }} + cancelEditing={cancelEdits} + startEditing={startEditing} + formValid={true} + loading={saving} + requirePermission={false} + /> + + ) +} + +ListViewEditButtons.propTypes = { + showStartingDivider: PropTypes.bool +} + +export default ListViewEditButtons diff --git a/src/components/Dashboard/common/ListViewTabs.jsx b/src/components/Dashboard/common/ListViewTabs.jsx new file mode 100644 index 00000000..3a054216 --- /dev/null +++ b/src/components/Dashboard/common/ListViewTabs.jsx @@ -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 }) => ( + +) + +ViewColorDot.propTypes = { + color: PropTypes.string +} + +const ViewOptionsDropdown = ({ view, isEditing, onChange, onDelete }) => { + const menu = { + items: [ + { + key: 'delete', + label: 'Delete', + icon: , + 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 ( + ( +
+ {React.cloneElement(menu, { style: menuStyle })} + + onChange({ private: event.target.checked })} + onClick={(event) => event.stopPropagation()} + > + Private + + +
+ )} + > + + ) + })} + + + + ) +} + +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 diff --git a/src/components/Dashboard/common/StateDisplay.jsx b/src/components/Dashboard/common/StateDisplay.jsx index 5b400b99..532e4fe8 100644 --- a/src/components/Dashboard/common/StateDisplay.jsx +++ b/src/components/Dashboard/common/StateDisplay.jsx @@ -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 ( <> {showState && ( - + )} + {showProgress && loadingProgressTypes.includes(currentState.type) && currentState?.progress && diff --git a/src/components/Dashboard/common/StateTag.jsx b/src/components/Dashboard/common/StateTag.jsx index b7635737..10cef8e0 100644 --- a/src/components/Dashboard/common/StateTag.jsx +++ b/src/components/Dashboard/common/StateTag.jsx @@ -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 } + const showLoading = loading && showBadge + + const padding = showLoading ? '0 6px' : '0 8px' + return ( - + - {showBadge && } + {showBadge && !loading && } + {showLoading && ( + + )} {badgeText} @@ -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 diff --git a/src/components/Dashboard/context/ApiServerContext.jsx b/src/components/Dashboard/context/ApiServerContext.jsx index 46429e1f..102d7cb6 100644 --- a/src/components/Dashboard/context/ApiServerContext.jsx +++ b/src/components/Dashboard/context/ApiServerContext.jsx @@ -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, diff --git a/src/components/Dashboard/context/ObjectListViewContext.jsx b/src/components/Dashboard/context/ObjectListViewContext.jsx new file mode 100644 index 00000000..75d1ba2a --- /dev/null +++ b/src/components/Dashboard/context/ObjectListViewContext.jsx @@ -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 ( + + {children} + + ) +} + +// 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 diff --git a/src/components/Dashboard/context/TableStateContext.jsx b/src/components/Dashboard/context/TableStateContext.jsx index c5c7b3df..6abcd3eb 100644 --- a/src/components/Dashboard/context/TableStateContext.jsx +++ b/src/components/Dashboard/context/TableStateContext.jsx @@ -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, diff --git a/src/components/Dashboard/context/ThemeContext.jsx b/src/components/Dashboard/context/ThemeContext.jsx index f7164588..baffc82a 100644 --- a/src/components/Dashboard/context/ThemeContext.jsx +++ b/src/components/Dashboard/context/ThemeContext.jsx @@ -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 = { diff --git a/src/database/models/DocumentPrinter.js b/src/database/models/DocumentPrinter.js index 28e059a4..416ff45c 100644 --- a/src/database/models/DocumentPrinter.js +++ b/src/database/models/DocumentPrinter.js @@ -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',