Compare commits

...

11 Commits

Author SHA1 Message Date
1466fe0f62 Enhance ObjectKanban and ObjectTable with Silent Loading Options
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Updated ObjectKanban and ObjectTable components to support silent loading, allowing for smoother user experience during data fetching without disrupting the UI.
- Refactored load functions to accept an options parameter, enabling conditional loading states based on the silent flag.
- Improved loading state management in ObjectKanbanColumn to maintain visual consistency during filter and sort updates.
- Adjusted loading behavior in ObjectTable to prevent unnecessary loading indicators when silent loading is enabled.
2026-09-03 03:17:38 +01:00
26d8c80d54 Enhance ObjectKanban with Skeleton Loading and Responsive Layout
- Introduced a skeleton loading state in the ObjectKanban component to improve user experience during data fetching.
- Updated CSS styles for the ObjectKanban and related components to ensure a responsive layout, accommodating various screen sizes.
- Refactored ObjectKanbanHeader to conditionally render skeletons based on loading state, enhancing visual feedback.
- Improved filter and sorter handling in ObjectKanbanColumn for better data management during loading.
2026-09-03 02:58:29 +01:00
0eae922a9e Enhance ObjectTableViewButton with View Mode Cycling and Typography Updates
- Refactored ObjectTableViewButton to include a cycling feature for view modes, allowing users to switch between list, cards, and kanban views seamlessly.
- Updated the component to utilize Ant Design's Typography for improved text styling and consistency.
- Removed icons from view mode options to streamline the interface and focused on text labels.
- Adjusted button properties to enhance user interaction and accessibility.
2026-09-03 01:42:33 +01:00
ab7919122a Add Kanban and Timeline Icons, Enhance Kanban Component Styles
- Introduced new SVG icons for Kanban and Timeline to enhance visual representation in the dashboard.
- Expanded App.css with new styles for the Kanban component, improving layout and responsiveness.
- Updated various dashboard components to integrate the new ObjectListViewPageContent for better view management and consistency across the application.
2026-09-03 01:30:44 +01:00
9b344b6a3d Enhance Dashboard Breadcrumb and ObjectListView Context with View Management
- Updated DashboardBreadcrumb to display a more informative name by incorporating the view name alongside the model label, improving user navigation clarity.
- Enhanced ObjectListViewProvider to synchronize the active view name with the dashboard breadcrumb, ensuring consistent view representation across components.
- Introduced session management for object list views in TableStateContext, allowing for persistent view states across user sessions.
2026-09-02 22:56:51 +01:00
9d1a032e10 Refactor Dashboard Components to Remove Unused State Management
- Removed unnecessary useState hooks for view state management in multiple dashboard components (Invoices, PaymentPolicies, Payments, TaxRecords, FilamentStocks, OrderItems, PartStocks, ProductStocks, PurchaseOrders, Shipments, StockAudits, StockEvents, StockLocations, StockTransfers, AppPasswords, AuditLogs, Couriers, CourierServices, DocumentJobs, DocumentPrinters, DocumentSizes, DocumentTemplates, Filaments, FilamentSkus).
- Updated ObjectListViewProvider integration to streamline component functionality and improve maintainability.
- Adjusted CSS variables in App.css for enhanced styling consistency across components.
2026-09-02 22:41:49 +01:00
444e694593 Update getModelByPluralName to use replaceAll for whitespace handling
- Modified the getModelByPluralName function to utilize replaceAll instead of replace for improved whitespace removal in formatted names, enhancing consistency in model name formatting.
2026-09-02 21:41:29 +01:00
b6834fecc6 Refactor ObjectTable and ObjectListViewContext for Simplified Filter Management
- Removed unnecessary state management for masterFilter and masterSort in ObjectTable, streamlining filter handling.
- Updated ObjectListViewContext to simplify view state restoration logic, enhancing clarity and maintainability.
- Adjusted references to masterFilter throughout ObjectTable to ensure consistent filter application.
2026-09-02 21:35:56 +01:00
73de7ac8ee Enhance Dashboard Components with Loading State and Styling Improvements
- Updated ListViewEditButtons to disable actions during initial loading, improving user experience.
- Refactored ListViewTabs to adjust icon styles based on loading state and removed unnecessary imports for cleaner code.
- Modified ObjectListViewContext to use viewId instead of view reference for better clarity and consistency.
- Updated TableStateContext to reflect changes in view parameter naming, enhancing code maintainability.
- Adjusted App.css for improved styling of segmented navigation items and loading indicators.
2026-09-02 21:26:39 +01:00
96b809b9d8 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.
2026-09-02 20:56:08 +01:00
088ef79b11 Add LoadingIcon Component with SVG Animation
- Introduced a new LoadingIcon component that utilizes an SVG for a rotating loading animation.
- Added loadingicon.svg file to assets/icons for the visual representation of the loading state.
- Integrated the LoadingIcon component into the project for enhanced user experience during loading processes.
2026-09-02 19:02:30 +01:00
82 changed files with 5824 additions and 1057 deletions

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.779032,0,0,0.779032,3.073021,9.025537)">
<path d="M22.587,55.452L29.317,55.452L29.317,3.541L22.587,3.541L22.587,55.452ZM44.947,55.452L51.677,55.452L51.677,3.541L44.947,3.541L44.947,55.452ZM10.588,58.962L63.676,58.962C70.606,58.962 74.264,55.326 74.264,48.481L74.264,10.522C74.264,3.667 70.606,0.02 63.676,0.02L10.588,0.02C3.679,0.02 0,3.667 0,10.522L0,48.481C0,55.326 3.679,58.962 10.588,58.962ZM11.167,52.003C8.429,52.003 6.959,50.615 6.959,47.743L6.959,11.251C6.959,8.378 8.429,6.979 11.167,6.979L63.097,6.979C65.813,6.979 67.305,8.378 67.305,11.251L67.305,47.743C67.305,50.615 65.813,52.003 63.097,52.003L11.167,52.003Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<svg
width="100%"
height="100%"
viewBox="0 0 64 64"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve"
class="th-icon"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"
>
<g>
<path
d="M32,5.131C46.829,5.131 58.869,17.171 58.869,32"
style="fill:none;"
/>
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
from="0 32 32"
to="360 32 32"
dur="1s"
repeatCount="indefinite"
/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 774 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0,-0.777065,0.777065,0,9.038886,69.94022)">
<path d="M75.315,48.595C75.315,55.44 71.658,59.097 64.728,59.097L21.503,59.097C14.606,59.097 10.906,55.461 10.906,48.595L10.906,36.765L17.865,36.765L17.865,48.26C17.865,50.888 19.229,52.138 21.722,52.138L64.499,52.138C66.981,52.138 68.356,50.888 68.356,48.26L68.356,36.765L75.315,36.765L75.315,48.595ZM75.315,10.657L75.315,22.436L68.356,22.436L68.356,10.982C68.356,8.354 66.981,7.114 64.499,7.114L21.722,7.114C19.229,7.114 17.865,8.354 17.865,10.982L17.865,22.436L10.906,22.436L10.906,10.657C10.906,3.781 14.606,0.155 21.503,0.155L64.728,0.155C71.658,0.155 75.315,3.802 75.315,10.657Z" style="fill-rule:nonzero;"/>
<path d="M88.562,55.043C88.562,57.276 86.765,59.094 84.532,59.094C82.3,59.094 80.481,57.276 80.481,55.043C80.481,52.81 82.3,51.013 84.532,51.013C86.765,51.013 88.562,52.81 88.562,55.043Z" style="fill-rule:nonzero;"/>
<path d="M88.562,42.32C88.562,44.553 86.765,46.34 84.532,46.34C82.3,46.34 80.481,44.553 80.481,42.32C80.481,40.066 82.3,38.269 84.532,38.269C86.765,38.269 88.562,40.066 88.562,42.32Z" style="fill-rule:nonzero;"/>
<path d="M88.562,16.774C88.562,19.007 86.765,20.825 84.532,20.825C82.3,20.825 80.481,19.007 80.481,16.774C80.481,14.541 82.3,12.744 84.532,12.744C86.765,12.744 88.562,14.541 88.562,16.774Z" style="fill-rule:nonzero;"/>
<path d="M88.562,4.02C88.562,6.284 86.765,8.071 84.532,8.071C82.3,8.071 80.481,6.284 80.481,4.02C80.481,1.787 82.3,0 84.532,0C86.765,0 88.562,1.787 88.562,4.02Z" style="fill-rule:nonzero;"/>
<path d="M84.582,34.107C87.085,34.107 89.11,32.082 89.11,29.579C89.11,27.076 87.085,25.041 84.582,25.041C82.961,25.041 81.507,25.903 80.707,27.224L10.916,27.224C9.558,27.224 8.54,28.242 8.54,29.6C8.54,30.958 9.558,31.998 10.916,31.998L80.75,31.998C81.55,33.276 82.961,34.107 84.582,34.107Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -22,7 +22,7 @@
.ant-form-item-control-input, .ant-form-item-control-input,
.ant-input, .ant-input,
.ant-input-number .ant-input-number-input, .ant-input-number .ant-input-number-input,
.ant-segmented-item-label, .segmented-nav-item-label,
.ant-badge-status-text, .ant-badge-status-text,
.ant-tree-title, .ant-tree-title,
.ant-select, .ant-select,
@ -47,6 +47,12 @@
font-family: 'DM Sans'; font-family: 'DM Sans';
} }
:root {
--color-list-view-tabs-border: #8282822e;
--color-button-border: #8282822e;
--color-button-background: #8282822e;
}
.ant-dropdown { .ant-dropdown {
z-index: 999; z-index: 999;
} }
@ -665,6 +671,11 @@ body {
bottom: 8px; bottom: 8px;
} }
.scrollbox-horizontal > [data-simplebar],
.scrollbox-horizontal .simplebar-wrapper {
width: 100%;
}
.simplebar-scrollbar:before { .simplebar-scrollbar:before {
background: #78787854 !important; background: #78787854 !important;
} }
@ -1361,16 +1372,193 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
width: 100%; width: 100%;
height: 100%; height: 100%;
min-width: 0; min-width: 0;
min-height: 0;
display: flex;
flex-direction: column;
} }
.objectTableCardsContainer > .ant-spin-nested-loading,
.objectTableCardsContainer > .ant-spin-nested-loading > .ant-spin-container,
.objectTableCardsContainer .ant-spin-nested-loading { .objectTableCardsContainer .ant-spin-nested-loading {
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: 0;
flex: 1;
display: flex;
flex-direction: column;
} }
.objectTableCardsContainer .ant-spin-container { .objectTableCardsContainer .ant-spin-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: 0;
flex: 1;
display: flex;
flex-direction: column;
}
.objectKanbanContainerWrapper {
position: relative;
width: 100%;
height: 100%;
min-width: 0;
min-height: 0;
display: flex;
flex-direction: column;
}
.objectKanbanContainerWrapper > .ant-spin-nested-loading,
.objectKanbanContainerWrapper > .ant-spin-nested-loading > .ant-spin-container {
height: 100%;
min-height: 0;
flex: 1;
display: flex;
flex-direction: column;
}
.objectKanbanContainerSkeletons {
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
min-height: 0;
}
.objectKanbanKanbanBody {
position: relative;
flex: 1;
min-width: 0;
min-height: 0;
}
.objectKanbanContainer {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
min-width: 0;
min-height: 0;
z-index: 1;
pointer-events: auto;
}
.objectKanbanWrap {
width: 100%;
height: 100%;
min-width: 0;
min-height: 0;
}
.objectKanbanWrap > .ant-spin-nested-loading,
.objectKanbanWrap > .ant-spin-nested-loading > .ant-spin-container {
height: 100%;
min-height: 0;
}
.objectKanbanScroll {
flex: 1;
width: 100%;
min-width: 0;
min-height: 0;
}
.objectKanbanScroll .simplebar-content-wrapper {
height: 100%;
}
.objectKanbanScroll .simplebar-content {
min-height: 100%;
}
.objectKanbanHeader {
flex-shrink: 0;
width: 100%;
min-width: 0;
overflow: hidden;
}
.objectKanbanHeaderTrack {
width: max-content;
min-width: 100%;
will-change: transform;
}
.objectKanbanHeaderRow {
width: max-content;
min-width: 100%;
align-items: flex-start;
}
.objectKanbanHeaderCell {
flex: 0 0 360px;
min-width: 360px;
flex-shrink: 0;
padding: 8px 8px;
border: 1px solid var(--ant-color-border-secondary);
border-bottom: 1px solid var(--color-descriptions-border);
border-radius: 12px 12px 0 0;
background-color: var(--layout-header-bg);
}
.objectKanban {
width: max-content;
min-width: 100%;
height: 100%;
min-height: 100%;
align-items: stretch;
padding-bottom: 4px;
}
.objectKanbanSkeletonColumns {
position: absolute;
inset: 0;
z-index: 0;
overflow: hidden;
pointer-events: none;
}
.objectKanbanSkeletonTrack {
width: max-content;
min-width: 100%;
height: 100%;
will-change: transform;
}
.objectKanbanSkeletonRow {
width: max-content;
min-width: 100%;
height: 100%;
align-items: stretch;
}
.objectKanbanColumn,
.objectKanbanColumnSkeleton {
flex: 0 0 360px;
min-width: 360px;
min-height: 0;
border-top: none;
border-radius: 0 0 12px 12px;
}
.objectKanbanColumnSkeleton {
border-radius: 0 0 12px 12px;
overflow: hidden;
}
.objectKanbanColumnCards {
flex: 1;
border-radius: 0 0 12px 12px;
height: 100%;
}
.objectKanbanColumnSkeleton .objectKanbanColumnCards {
background-color: var(--layout-header-bg);
}
.objectKanbanColumnCardsInner {
padding: 16px;
} }
.electron-body .ant-modal-wrap, .electron-body .ant-modal-wrap,
@ -2544,3 +2732,253 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
height: 0; height: 0;
pointer-events: none; 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;
min-width: 32px;
}
.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
color-mix(
in srgb,
var(--color-button-border) 40%,
var(--color-button-background)
);
}
.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 14px 16px;
}
.segmented-nav-drag-handle {
flex-shrink: 0;
}
.segmented-nav-item-dragging {
opacity: 0.4;
}
.segmented-nav-item-drop-before::before,
.segmented-nav-item-drop-after::after {
content: '';
position: absolute;
top: 4px;
bottom: 4px;
width: 2px;
border-radius: 1px;
background: var(--color-primary, #1677ff);
pointer-events: none;
}
.segmented-nav-item-drop-before::before {
left: -5px;
}
.segmented-nav-item-drop-after::after {
right: -5px;
}
.segmented-nav-reordering
.segmented-nav-item:not(.segmented-nav-item-dragging) {
cursor: default;
}
.list-view-tabs-add-button {
padding-inline: 4px;
min-width: 20px;
}
.state-tag-loading svg path {
stroke: currentColor;
stroke-width: 12px;
}

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Invoices = () => { const Invoices = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('invoices')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('invoices') useColumnVisibility('invoices')
@ -28,9 +28,12 @@ const Invoices = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='invoice'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='invoice' type='invoice'
@ -45,6 +48,7 @@ const Invoices = () => {
/> />
<ExportListButton objectType='invoice' /> <ExportListButton objectType='invoice' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const Invoices = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='invoice'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='invoice' type='invoice'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const Invoices = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,15 +6,16 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PaymentPolicies = () => { const PaymentPolicies = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('paymentPolicy')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('paymentPolicy') useColumnVisibility('paymentPolicy')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -23,8 +24,12 @@ const PaymentPolicies = () => {
useSortSidebarVisibility('PaymentPolicies') useSortSidebarVisibility('PaymentPolicies')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<Flex justify={'space-between'} style={{ minHeight: 0 }}> objectType='paymentPolicy'
tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='paymentPolicy' type='paymentPolicy'
@ -39,6 +44,7 @@ const PaymentPolicies = () => {
/> />
<ExportListButton objectType='paymentPolicy' /> <ExportListButton objectType='paymentPolicy' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -49,17 +55,16 @@ const PaymentPolicies = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='paymentPolicy'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='paymentPolicy' type='paymentPolicy'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -73,6 +78,7 @@ const PaymentPolicies = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Payments = () => { const Payments = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('payments')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('payments') useColumnVisibility('payments')
@ -28,9 +28,12 @@ const Payments = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='payment'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='payment' type='payment'
@ -45,6 +48,7 @@ const Payments = () => {
/> />
<ExportListButton objectType='payment' /> <ExportListButton objectType='payment' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const Payments = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='payment'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='payment' type='payment'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const Payments = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const TaxRecords = () => { const TaxRecords = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('taxRecord')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('taxRecord') useColumnVisibility('taxRecord')
@ -28,9 +28,12 @@ const TaxRecords = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='taxRecord'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='taxRecord' type='taxRecord'
@ -45,6 +48,7 @@ const TaxRecords = () => {
/> />
<ExportListButton objectType='taxRecord' /> <ExportListButton objectType='taxRecord' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const TaxRecords = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='taxRecord'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='taxRecord' type='taxRecord'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const TaxRecords = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -10,18 +10,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FilamentStocks = () => { const FilamentStocks = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('filamentStocks')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('filamentStocks') useColumnVisibility('filamentStocks')
@ -33,9 +32,12 @@ const FilamentStocks = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filamentStock'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filamentStock' type='filamentStock'
@ -50,6 +52,7 @@ const FilamentStocks = () => {
/> />
<ExportListButton objectType='filamentStock' /> <ExportListButton objectType='filamentStock' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -60,18 +63,15 @@ const FilamentStocks = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='filamentStock'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='filamentStock' type='filamentStock'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -83,9 +83,10 @@ const FilamentStocks = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const OrderItems = () => { const OrderItems = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('orderItems')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('orderItems') useColumnVisibility('orderItems')
@ -28,9 +28,12 @@ const OrderItems = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='orderItem'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='orderItem' type='orderItem'
@ -45,6 +48,7 @@ const OrderItems = () => {
/> />
<ExportListButton objectType='orderItem' /> <ExportListButton objectType='orderItem' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const OrderItems = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='orderItem'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='orderItem' type='orderItem'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const OrderItems = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -10,18 +10,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PartStocks = () => { const PartStocks = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('partStocks')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('partStocks') useColumnVisibility('partStocks')
@ -33,9 +32,12 @@ const PartStocks = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='partStock'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='partStock' type='partStock'
@ -50,6 +52,7 @@ const PartStocks = () => {
/> />
<ExportListButton objectType='partStock' /> <ExportListButton objectType='partStock' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -60,18 +63,15 @@ const PartStocks = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='partStock'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='partStock' type='partStock'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -83,9 +83,10 @@ const PartStocks = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -11,18 +11,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductStocks = () => { const ProductStocks = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('productStocks')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('productStock') useColumnVisibility('productStock')
@ -34,9 +33,12 @@ const ProductStocks = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='productStock'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productStock' type='productStock'
@ -51,6 +53,7 @@ const ProductStocks = () => {
/> />
<ExportListButton objectType='productStock' /> <ExportListButton objectType='productStock' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -61,18 +64,15 @@ const ProductStocks = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='productStock'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='productStock' type='productStock'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -84,9 +84,10 @@ const ProductStocks = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PurchaseOrders = () => { const PurchaseOrders = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('purchaseOrders')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('purchaseOrders') useColumnVisibility('purchaseOrders')
@ -28,9 +28,12 @@ const PurchaseOrders = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='purchaseOrder'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='purchaseOrder' type='purchaseOrder'
@ -45,6 +48,7 @@ const PurchaseOrders = () => {
/> />
<ExportListButton objectType='purchaseOrder' /> <ExportListButton objectType='purchaseOrder' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const PurchaseOrders = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='purchaseOrder'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='purchaseOrder' type='purchaseOrder'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const PurchaseOrders = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Shipments = () => { const Shipments = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('shipments')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('shipments') useColumnVisibility('shipments')
@ -28,9 +28,12 @@ const Shipments = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='shipment'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='shipment' type='shipment'
@ -45,6 +48,7 @@ const Shipments = () => {
/> />
<ExportListButton objectType='shipment' /> <ExportListButton objectType='shipment' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const Shipments = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='shipment'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='shipment' type='shipment'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const Shipments = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -10,18 +10,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockAudits = () => { const StockAudits = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('stockAudits')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('stockAudits') useColumnVisibility('stockAudits')
@ -33,9 +32,12 @@ const StockAudits = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockAudit'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockAudit' type='stockAudit'
@ -50,6 +52,7 @@ const StockAudits = () => {
/> />
<ExportListButton objectType='stockAudit' /> <ExportListButton objectType='stockAudit' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -60,18 +63,15 @@ const StockAudits = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='stockAudit'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='stockAudit' type='stockAudit'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -83,9 +83,10 @@ const StockAudits = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,15 +6,16 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockEvents = () => { const StockEvents = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('stockEvents')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('stockEvent') useColumnVisibility('stockEvent')
@ -27,9 +28,12 @@ const StockEvents = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockEvent'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockEvent' type='stockEvent'
@ -44,6 +48,7 @@ const StockEvents = () => {
/> />
<ExportListButton objectType='stockEvent' /> <ExportListButton objectType='stockEvent' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,18 +59,15 @@ const StockEvents = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='stockEvent'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='stockEvent' type='stockEvent'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -77,9 +79,10 @@ const StockEvents = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -8,18 +8,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockLocations = () => { const StockLocations = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('stockLocations')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('stockLocation') useColumnVisibility('stockLocation')
@ -31,9 +30,12 @@ const StockLocations = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockLocation'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockLocation' type='stockLocation'
@ -48,6 +50,7 @@ const StockLocations = () => {
/> />
<ExportListButton objectType='stockLocation' /> <ExportListButton objectType='stockLocation' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -58,18 +61,15 @@ const StockLocations = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='stockLocation'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='stockLocation' type='stockLocation'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -81,9 +81,10 @@ const StockLocations = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -8,18 +8,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockTransfers = () => { const StockTransfers = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('stockTransfers')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('stockTransfer') useColumnVisibility('stockTransfer')
@ -31,9 +30,12 @@ const StockTransfers = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='stockTransfer'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockTransfer' type='stockTransfer'
@ -48,6 +50,7 @@ const StockTransfers = () => {
/> />
<ExportListButton objectType='stockTransfer' /> <ExportListButton objectType='stockTransfer' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -58,18 +61,15 @@ const StockTransfers = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='stockTransfer'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='stockTransfer' type='stockTransfer'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -81,9 +81,10 @@ const StockTransfers = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -7,15 +7,15 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const AppPasswords = () => { const AppPasswords = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('appPassword')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('appPassword') useColumnVisibility('appPassword')
@ -27,9 +27,12 @@ const AppPasswords = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='appPassword'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='appPassword' type='appPassword'
@ -44,6 +47,7 @@ const AppPasswords = () => {
/> />
<ExportListButton objectType='appPassword' /> <ExportListButton objectType='appPassword' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +58,14 @@ const AppPasswords = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='appPassword'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='appPassword' type='appPassword'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -77,10 +78,10 @@ const AppPasswords = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/>
/>
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -10,6 +10,9 @@ import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const AuditLogs = () => { const AuditLogs = () => {
const tableRef = useRef() const tableRef = useRef()
@ -25,9 +28,12 @@ const AuditLogs = () => {
return ( return (
<> <ObjectListViewProvider
objectType='auditLog'
tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='auditLog' type='auditLog'
@ -42,6 +48,7 @@ const AuditLogs = () => {
/> />
<ExportListButton objectType='auditLog' /> <ExportListButton objectType='auditLog' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -51,9 +58,9 @@ const AuditLogs = () => {
active={showFilterSidebar} active={showFilterSidebar}
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
@ -69,9 +76,10 @@ const AuditLogs = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const CourierServices = () => { const CourierServices = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('courierService')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('courierService') useColumnVisibility('courierService')
@ -28,9 +28,12 @@ const CourierServices = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='courierService'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='courierService' type='courierService'
@ -45,6 +48,7 @@ const CourierServices = () => {
/> />
<ExportListButton objectType='courierService' /> <ExportListButton objectType='courierService' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const CourierServices = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='courierService'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='courierService' type='courierService'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const CourierServices = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Couriers = () => { const Couriers = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('courier')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('courier') const [columnVisibility, setColumnVisibility] = useColumnVisibility('courier')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -27,9 +27,12 @@ const Couriers = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='courier'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='courier' type='courier'
@ -44,6 +47,7 @@ const Couriers = () => {
/> />
<ExportListButton objectType='courier' /> <ExportListButton objectType='courier' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +58,16 @@ const Couriers = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='courier'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='courier' type='courier'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -78,7 +81,7 @@ const Couriers = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentJobs = () => { const DocumentJobs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentJob')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('documentJob') useColumnVisibility('documentJob')
@ -28,9 +28,12 @@ const DocumentJobs = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentJob'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentJob' type='documentJob'
@ -45,6 +48,7 @@ const DocumentJobs = () => {
/> />
<ExportListButton objectType='documentJob' /> <ExportListButton objectType='documentJob' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const DocumentJobs = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='documentJob'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='documentJob' type='documentJob'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const DocumentJobs = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,15 +6,16 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentPrinters = () => { const DocumentPrinters = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentPrinter')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('documentPrinter') useColumnVisibility('documentPrinter')
@ -27,9 +28,12 @@ const DocumentPrinters = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentPrinter'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentPrinter' type='documentPrinter'
@ -44,6 +48,7 @@ const DocumentPrinters = () => {
/> />
<ExportListButton objectType='documentPrinter' /> <ExportListButton objectType='documentPrinter' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +59,16 @@ const DocumentPrinters = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='documentPrinter'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='documentPrinter' type='documentPrinter'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -78,7 +82,7 @@ const DocumentPrinters = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,15 +6,16 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentSizes = () => { const DocumentSizes = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentSize')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('documentSize') useColumnVisibility('documentSize')
@ -26,9 +27,12 @@ const DocumentSizes = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentSize'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentSize' type='documentSize'
@ -43,6 +47,7 @@ const DocumentSizes = () => {
/> />
<ExportListButton objectType='documentSize' /> <ExportListButton objectType='documentSize' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -53,17 +58,16 @@ const DocumentSizes = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='documentSize'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='documentSize' type='documentSize'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -77,7 +81,7 @@ const DocumentSizes = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const DocumentTemplates = () => { const DocumentTemplates = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('documentTemplate')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('documentTemplate') useColumnVisibility('documentTemplate')
@ -28,9 +28,12 @@ const DocumentTemplates = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='documentTemplate'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentTemplate' type='documentTemplate'
@ -45,6 +48,7 @@ const DocumentTemplates = () => {
/> />
<ExportListButton objectType='documentTemplate' /> <ExportListButton objectType='documentTemplate' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const DocumentTemplates = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='documentTemplate'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='documentTemplate' type='documentTemplate'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const DocumentTemplates = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -8,18 +8,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FilamentSkus = () => { const FilamentSkus = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('filamentSkus')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('filamentSku') useColumnVisibility('filamentSku')
@ -31,9 +30,12 @@ const FilamentSkus = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filamentSku'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filamentSku' type='filamentSku'
@ -48,6 +50,7 @@ const FilamentSkus = () => {
/> />
<ExportListButton objectType='filamentSku' /> <ExportListButton objectType='filamentSku' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -58,18 +61,15 @@ const FilamentSkus = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='filamentSku'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='filamentSku' type='filamentSku'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -81,9 +81,10 @@ const FilamentSkus = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -8,11 +8,13 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
import useViewMode from '../hooks/useViewMode'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import ExportListButton from '../common/ExportListButton' 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 useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
@ -20,7 +22,6 @@ const Filaments = () => {
const tableRef = useRef() const tableRef = useRef()
// View mode state (cards/list), persisted in sessionStorage via custom hook // View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('filament')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('filament') useColumnVisibility('filament')
@ -33,9 +34,12 @@ const Filaments = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filament'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='filament' type='filament'
@ -50,6 +54,7 @@ const Filaments = () => {
/> />
<ExportListButton objectType='filament' /> <ExportListButton objectType='filament' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -60,17 +65,14 @@ const Filaments = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='filament'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='filament' type='filament'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -83,10 +85,10 @@ const Filaments = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/>
/>
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Files = () => { const Files = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('file')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('file') const [columnVisibility, setColumnVisibility] = useColumnVisibility('file')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -25,11 +25,13 @@ const Files = () => {
const [showSortSidebar, setShowSortSidebar] = const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Files') useSortSidebarVisibility('Files')
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='file'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='file' type='file'
@ -44,6 +46,7 @@ const Files = () => {
/> />
<ExportListButton objectType='file' /> <ExportListButton objectType='file' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +57,15 @@ const Files = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='file'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='file' type='file'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -78,7 +79,7 @@ const Files = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -7,9 +7,11 @@ import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' 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 ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
import useViewMode from '../hooks/useViewMode'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
@ -20,7 +22,6 @@ const Hosts = () => {
const tableRef = useRef() const tableRef = useRef()
// View mode state (cards/list), persisted in sessionStorage via custom hook // View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('host')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('host') const [columnVisibility, setColumnVisibility] = useColumnVisibility('host')
@ -32,9 +33,12 @@ const Hosts = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='host'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='host' type='host'
@ -49,6 +53,7 @@ const Hosts = () => {
/> />
<ExportListButton objectType='host' /> <ExportListButton objectType='host' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -59,17 +64,14 @@ const Hosts = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='host'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='host' type='host'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -82,10 +84,10 @@ const Hosts = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/>
/>
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -9,16 +9,16 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Materials = () => { const Materials = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('material')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('material') useColumnVisibility('material')
@ -30,9 +30,12 @@ const Materials = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='material'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='material' type='material'
@ -47,6 +50,7 @@ const Materials = () => {
/> />
<ExportListButton objectType='material' /> <ExportListButton objectType='material' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -57,17 +61,14 @@ const Materials = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='material'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='material' type='material'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -80,10 +81,10 @@ const Materials = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/>
/>
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const NoteTypes = () => { const NoteTypes = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('noteType')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('noteType') useColumnVisibility('noteType')
@ -28,9 +28,12 @@ const NoteTypes = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='noteType'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='noteType' type='noteType'
@ -45,6 +48,7 @@ const NoteTypes = () => {
/> />
<ExportListButton objectType='noteType' /> <ExportListButton objectType='noteType' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const NoteTypes = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='noteType'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='noteType' type='noteType'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const NoteTypes = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -8,18 +8,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PartSkus = () => { const PartSkus = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('partSkus')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('partSku') const [columnVisibility, setColumnVisibility] = useColumnVisibility('partSku')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -30,9 +29,12 @@ const PartSkus = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='partSku'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='partSku' type='partSku'
@ -47,6 +49,7 @@ const PartSkus = () => {
/> />
<ExportListButton objectType='partSku' /> <ExportListButton objectType='partSku' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -57,18 +60,15 @@ const PartSkus = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='partSku'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='partSku' type='partSku'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -80,9 +80,10 @@ const PartSkus = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -9,7 +9,6 @@ import ObjectActions from '../common/ObjectActions'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import useViewMode from '../hooks/useViewMode'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
@ -18,10 +17,12 @@ import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Parts = (filter) => { const Parts = (filter) => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('part')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('part') const [columnVisibility, setColumnVisibility] = useColumnVisibility('part')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -32,9 +33,12 @@ const Parts = (filter) => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='part'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='part' type='part'
@ -49,6 +53,7 @@ const Parts = (filter) => {
/> />
<ExportListButton objectType='part' /> <ExportListButton objectType='part' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -59,17 +64,16 @@ const Parts = (filter) => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='part'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='part' type='part'
cards={viewMode === 'cards'}
filter={filter} filter={filter}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -84,7 +88,7 @@ const Parts = (filter) => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const PermissionSettingsList = () => { const PermissionSettingsList = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('permissionSetting')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('permissionSetting') useColumnVisibility('permissionSetting')
@ -28,9 +28,12 @@ const PermissionSettingsList = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='permissionSetting'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='permissionSetting' type='permissionSetting'
@ -45,6 +48,7 @@ const PermissionSettingsList = () => {
/> />
<ExportListButton objectType='permissionSetting' /> <ExportListButton objectType='permissionSetting' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const PermissionSettingsList = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='permissionSetting'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='permissionSetting' type='permissionSetting'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const PermissionSettingsList = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -9,16 +9,16 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductCategories = () => { const ProductCategories = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('productCategory')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('productCategory') useColumnVisibility('productCategory')
@ -30,9 +30,12 @@ const ProductCategories = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='productCategory'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='productCategory' type='productCategory'
@ -47,6 +50,7 @@ const ProductCategories = () => {
/> />
<ExportListButton objectType='productCategory' /> <ExportListButton objectType='productCategory' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -57,17 +61,14 @@ const ProductCategories = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='productCategory'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='productCategory' type='productCategory'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -80,10 +81,10 @@ const ProductCategories = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/>
/>
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -8,18 +8,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ProductSkus = () => { const ProductSkus = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('productSkus')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('productSku') useColumnVisibility('productSku')
@ -31,9 +30,12 @@ const ProductSkus = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='productSku'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productSku' type='productSku'
@ -48,6 +50,7 @@ const ProductSkus = () => {
/> />
<ExportListButton objectType='productSku' /> <ExportListButton objectType='productSku' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -58,18 +61,15 @@ const ProductSkus = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='productSku'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='productSku' type='productSku'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -81,9 +81,10 @@ const ProductSkus = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -25,17 +25,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Products = () => { const Products = () => {
const navigate = useNavigate() const navigate = useNavigate()
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('Products')
const getProductActionItems = (id) => { const getProductActionItems = (id) => {
return { return {
items: [ items: [
@ -302,9 +302,12 @@ const Products = () => {
} }
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='product'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='product' type='product'
@ -320,6 +323,7 @@ const Products = () => {
<Button>View</Button> <Button>View</Button>
</Popover> </Popover>
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -330,16 +334,15 @@ const Products = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='product'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'product'} type={'product'}
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -353,7 +356,7 @@ const Products = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const StockAuditLevels = () => { const StockAuditLevels = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('stockAuditLevel')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('stockAuditLevel') useColumnVisibility('stockAuditLevel')
@ -27,8 +27,12 @@ const StockAuditLevels = () => {
useSortSidebarVisibility('StockAuditLevels') useSortSidebarVisibility('StockAuditLevels')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<Flex justify={'space-between'} style={{ minHeight: 0 }}> objectType='stockAuditLevel'
tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockAuditLevel' type='stockAuditLevel'
@ -43,6 +47,7 @@ const StockAuditLevels = () => {
/> />
<ExportListButton objectType='stockAuditLevel' /> <ExportListButton objectType='stockAuditLevel' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -53,17 +58,16 @@ const StockAuditLevels = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='stockAuditLevel'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='stockAuditLevel' type='stockAuditLevel'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -77,6 +81,7 @@ const StockAuditLevels = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const TaxRates = () => { const TaxRates = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('taxRate')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('taxRate') const [columnVisibility, setColumnVisibility] = useColumnVisibility('taxRate')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -27,9 +27,12 @@ const TaxRates = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='taxRate'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='taxRate' type='taxRate'
@ -44,6 +47,7 @@ const TaxRates = () => {
/> />
<ExportListButton objectType='taxRate' /> <ExportListButton objectType='taxRate' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +58,16 @@ const TaxRates = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='taxRate'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='taxRate' type='taxRate'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -78,7 +81,7 @@ const TaxRates = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const UserGroups = () => { const UserGroups = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('userGroup')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('userGroup') const [columnVisibility, setColumnVisibility] = useColumnVisibility('userGroup')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -27,9 +27,12 @@ const UserGroups = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='userGroup'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='userGroup' type='userGroup'
@ -44,6 +47,7 @@ const UserGroups = () => {
/> />
<ExportListButton objectType='userGroup' /> <ExportListButton objectType='userGroup' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +58,16 @@ const UserGroups = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='userGroup'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='userGroup' type='userGroup'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -78,7 +81,7 @@ const UserGroups = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Users = () => { const Users = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('user')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('user') const [columnVisibility, setColumnVisibility] = useColumnVisibility('user')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -27,8 +27,12 @@ const Users = () => {
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<Flex justify={'space-between'} style={{ minHeight: 0 }}> objectType='user'
tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='user' type='user'
@ -43,6 +47,7 @@ const Users = () => {
/> />
<ExportListButton objectType='user' /> <ExportListButton objectType='user' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -53,16 +58,16 @@ const Users = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='user'
setViewMode={setViewMode}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'user'} type={'user'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -76,6 +81,7 @@ const Users = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Vendors = () => { const Vendors = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('vendor')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('vendor') const [columnVisibility, setColumnVisibility] = useColumnVisibility('vendor')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -25,11 +25,13 @@ const Vendors = () => {
const [showSortSidebar, setShowSortSidebar] = const [showSortSidebar, setShowSortSidebar] =
useSortSidebarVisibility('Vendors') useSortSidebarVisibility('Vendors')
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='vendor'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='vendor' type='vendor'
@ -44,6 +46,7 @@ const Vendors = () => {
/> />
<ExportListButton objectType='vendor' /> <ExportListButton objectType='vendor' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +57,15 @@ const Vendors = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='vendor'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='vendor' type='vendor'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -78,7 +79,7 @@ const Vendors = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -2,6 +2,9 @@ import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
@ -10,11 +13,9 @@ import ObjectTableViewButton from '../common/ObjectTableViewButton'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import useViewMode from '../hooks/useViewMode'
const FilamentProfiles = () => { const FilamentProfiles = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('FilamentProfiles')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('filamentProfile') useColumnVisibility('filamentProfile')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -25,9 +26,12 @@ const FilamentProfiles = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='filamentProfile'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='filamentProfile' type='filamentProfile'
@ -41,6 +45,7 @@ const FilamentProfiles = () => {
/> />
<ExportListButton objectType='filamentProfile' /> <ExportListButton objectType='filamentProfile' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -51,17 +56,14 @@ const FilamentProfiles = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='filamentProfile'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='filamentProfile' type='filamentProfile'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -74,9 +76,10 @@ const FilamentProfiles = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -8,16 +8,17 @@ import ObjectActions from '../common/ObjectActions'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const GCodeFiles = () => { const GCodeFiles = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('gcodeFile')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('gcodeFile') useColumnVisibility('gcodeFile')
@ -30,9 +31,12 @@ const GCodeFiles = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='gcodeFile'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='gcodeFile' type='gcodeFile'
@ -47,6 +51,7 @@ const GCodeFiles = () => {
/> />
<ExportListButton objectType='gcodeFile' /> <ExportListButton objectType='gcodeFile' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -57,16 +62,15 @@ const GCodeFiles = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='gcodeFile'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='gcodeFile' type='gcodeFile'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -81,7 +85,7 @@ const GCodeFiles = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -5,7 +5,6 @@ import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility.jsx' import useColumnVisibility from '../hooks/useColumnVisibility.jsx'
import ObjectTable from '../common/ObjectTable.jsx' import ObjectTable from '../common/ObjectTable.jsx'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
import useViewMode from '../hooks/useViewMode.jsx'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
@ -13,10 +12,12 @@ import ColumnViewButton from '../common/ColumnViewButton.jsx'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility.jsx' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility.jsx'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton.jsx' import ExportListButton from '../common/ExportListButton.jsx'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Jobs = () => { const Jobs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('job')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('job') const [columnVisibility, setColumnVisibility] = useColumnVisibility('job')
@ -28,9 +29,12 @@ const Jobs = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='job'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='job' type='job'
@ -45,7 +49,7 @@ const Jobs = () => {
/> />
<ExportListButton objectType='job' /> <ExportListButton objectType='job' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -56,18 +60,15 @@ const Jobs = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='job'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'job'} type={'job'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,9 +80,10 @@ const Jobs = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -2,6 +2,9 @@ import { useRef } from 'react'
import { Flex, Space } from 'antd' import { Flex, Space } from 'antd'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import ObjectTable from '../common/ObjectTable' import ObjectTable from '../common/ObjectTable'
@ -10,10 +13,8 @@ import ObjectTableViewButton from '../common/ObjectTableViewButton'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import useViewMode from '../hooks/useViewMode'
const PrinterProfiles = () => { const PrinterProfiles = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('PrinterProfiles')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('printerProfile') useColumnVisibility('printerProfile')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -24,9 +25,12 @@ const PrinterProfiles = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='printerProfile'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='printerProfile' type='printerProfile'
@ -40,6 +44,7 @@ const PrinterProfiles = () => {
/> />
<ExportListButton objectType='printerProfile' /> <ExportListButton objectType='printerProfile' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -50,17 +55,14 @@ const PrinterProfiles = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='printerProfile'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='printerProfile' type='printerProfile'
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
@ -73,9 +75,10 @@ const PrinterProfiles = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,11 +6,13 @@ import ObjectTable from '../common/ObjectTable'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' 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 ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useColumnVisibility from '../hooks/useColumnVisibility' import useColumnVisibility from '../hooks/useColumnVisibility'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
@ -19,7 +21,6 @@ const Printers = () => {
const tableRef = useRef() const tableRef = useRef()
// View mode state (cards/list), persisted in sessionStorage via custom hook // View mode state (cards/list), persisted in sessionStorage via custom hook
const [viewMode, setViewMode] = useViewMode('Printers')
// Column visibility state, persisted in sessionStorage via custom hook // Column visibility state, persisted in sessionStorage via custom hook
const [columnVisibility, setColumnVisibility] = useColumnVisibility('printer') const [columnVisibility, setColumnVisibility] = useColumnVisibility('printer')
@ -33,9 +34,12 @@ const Printers = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='printer'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space> <Space>
<ObjectActions <ObjectActions
type='printer' type='printer'
@ -50,6 +54,7 @@ const Printers = () => {
/> />
<ExportListButton objectType='printer' /> <ExportListButton objectType='printer' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -60,19 +65,16 @@ const Printers = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='printer'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type='printer' type='printer'
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
expandHeight={true} expandHeight={true}
saveFilterInSession={true} saveFilterInSession={true}
@ -83,10 +85,10 @@ const Printers = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/>
/>
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -5,7 +5,6 @@ import { Flex, Space } from 'antd'
import useColumnVisibility from '../hooks/useColumnVisibility.jsx' import useColumnVisibility from '../hooks/useColumnVisibility.jsx'
import ObjectTable from '../common/ObjectTable.jsx' import ObjectTable from '../common/ObjectTable.jsx'
import ObjectActions from '../common/ObjectActions' import ObjectActions from '../common/ObjectActions'
import useViewMode from '../hooks/useViewMode.jsx'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
@ -13,10 +12,12 @@ import ColumnViewButton from '../common/ColumnViewButton.jsx'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility.jsx' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility.jsx'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ExportListButton from '../common/ExportListButton.jsx' import ExportListButton from '../common/ExportListButton.jsx'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const SubJobs = () => { const SubJobs = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('subJob')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('subJob') const [columnVisibility, setColumnVisibility] = useColumnVisibility('subJob')
@ -28,9 +29,12 @@ const SubJobs = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='subJob'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='subJob' type='subJob'
@ -45,7 +49,7 @@ const SubJobs = () => {
/> />
<ExportListButton objectType='subJob' /> <ExportListButton objectType='subJob' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -56,18 +60,15 @@ const SubJobs = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='subJob'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
type={'subJob'} type={'subJob'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,9 +80,10 @@ const SubJobs = () => {
saveSortInUrl={true} saveSortInUrl={true}
useSortInSession={true} useSortInSession={true}
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Clients = () => { const Clients = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('client')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('client') const [columnVisibility, setColumnVisibility] = useColumnVisibility('client')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -27,9 +27,12 @@ const Clients = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='client'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='client' type='client'
@ -44,6 +47,7 @@ const Clients = () => {
/> />
<ExportListButton objectType='client' /> <ExportListButton objectType='client' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -54,17 +58,16 @@ const Clients = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='client'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='client' type='client'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -78,7 +81,7 @@ const Clients = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,15 +6,16 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const FulfillmentPolicies = () => { const FulfillmentPolicies = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('fulfillmentPolicy')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('fulfillmentPolicy') useColumnVisibility('fulfillmentPolicy')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
@ -23,8 +24,12 @@ const FulfillmentPolicies = () => {
useSortSidebarVisibility('FulfillmentPolicies') useSortSidebarVisibility('FulfillmentPolicies')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<Flex justify={'space-between'} style={{ minHeight: 0 }}> objectType='fulfillmentPolicy'
tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='fulfillmentPolicy' type='fulfillmentPolicy'
@ -39,6 +44,7 @@ const FulfillmentPolicies = () => {
/> />
<ExportListButton objectType='fulfillmentPolicy' /> <ExportListButton objectType='fulfillmentPolicy' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -49,17 +55,16 @@ const FulfillmentPolicies = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='fulfillmentPolicy'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='fulfillmentPolicy' type='fulfillmentPolicy'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -73,6 +78,7 @@ const FulfillmentPolicies = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ListingVarients = () => { const ListingVarients = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('listingVarients')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('listingVarients') useColumnVisibility('listingVarients')
@ -28,9 +28,12 @@ const ListingVarients = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='listingVarient'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='listingVarient' type='listingVarient'
@ -45,6 +48,7 @@ const ListingVarients = () => {
/> />
<ExportListButton objectType='listingVarient' /> <ExportListButton objectType='listingVarient' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const ListingVarients = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='listingVarient'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='listingVarient' type='listingVarient'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const ListingVarients = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Listings = () => { const Listings = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('listings')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('listings') useColumnVisibility('listings')
@ -28,9 +28,12 @@ const Listings = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='listing'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='listing' type='listing'
@ -45,6 +48,7 @@ const Listings = () => {
/> />
<ExportListButton objectType='listing' /> <ExportListButton objectType='listing' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const Listings = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='listing'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='listing' type='listing'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const Listings = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const Marketplaces = () => { const Marketplaces = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('marketplaces')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('marketplaces') useColumnVisibility('marketplaces')
@ -28,9 +28,12 @@ const Marketplaces = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='marketplace'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='marketplace' type='marketplace'
@ -45,6 +48,7 @@ const Marketplaces = () => {
/> />
<ExportListButton objectType='marketplace' /> <ExportListButton objectType='marketplace' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const Marketplaces = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='marketplace'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='marketplace' type='marketplace'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const Marketplaces = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

@ -6,15 +6,16 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const ReturnPolicies = () => { const ReturnPolicies = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('returnPolicy')
const [columnVisibility, setColumnVisibility] = useColumnVisibility('returnPolicy') const [columnVisibility, setColumnVisibility] = useColumnVisibility('returnPolicy')
const [showFilterSidebar, setShowFilterSidebar] = const [showFilterSidebar, setShowFilterSidebar] =
useFilterSidebarVisibility('ReturnPolicies') useFilterSidebarVisibility('ReturnPolicies')
@ -22,8 +23,12 @@ const ReturnPolicies = () => {
useSortSidebarVisibility('ReturnPolicies') useSortSidebarVisibility('ReturnPolicies')
return ( return (
<Flex vertical={'true'} gap='large' className='h-100'> <ObjectListViewProvider
<Flex justify={'space-between'} style={{ minHeight: 0 }}> objectType='returnPolicy'
tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='returnPolicy' type='returnPolicy'
@ -38,6 +43,7 @@ const ReturnPolicies = () => {
/> />
<ExportListButton objectType='returnPolicy' /> <ExportListButton objectType='returnPolicy' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -48,17 +54,16 @@ const ReturnPolicies = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='returnPolicy'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='returnPolicy' type='returnPolicy'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -72,6 +77,7 @@ const ReturnPolicies = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</ObjectListViewProvider>
) )
} }

View File

@ -6,17 +6,17 @@ import useColumnVisibility from '../hooks/useColumnVisibility'
import ObjectTableViewButton from '../common/ObjectTableViewButton' import ObjectTableViewButton from '../common/ObjectTableViewButton'
import FilterSidebarButton from '../common/FilterSidebarButton' import FilterSidebarButton from '../common/FilterSidebarButton'
import SortSidebarButton from '../common/SortSidebarButton' import SortSidebarButton from '../common/SortSidebarButton'
import useViewMode from '../hooks/useViewMode'
import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility' import useFilterSidebarVisibility from '../hooks/useFilterSidebarVisibility'
import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility' import useSortSidebarVisibility from '../hooks/useSortSidebarVisibility'
import ColumnViewButton from '../common/ColumnViewButton' import ColumnViewButton from '../common/ColumnViewButton'
import ExportListButton from '../common/ExportListButton' import ExportListButton from '../common/ExportListButton'
import ListViewTabs from '../common/ListViewTabs'
import ListViewEditButtons from '../common/ListViewEditButtons'
import { ObjectListViewProvider } from '../context/ObjectListViewContext'
const SalesOrders = () => { const SalesOrders = () => {
const tableRef = useRef() const tableRef = useRef()
const [viewMode, setViewMode] = useViewMode('salesOrders')
const [columnVisibility, setColumnVisibility] = const [columnVisibility, setColumnVisibility] =
useColumnVisibility('salesOrders') useColumnVisibility('salesOrders')
@ -28,9 +28,12 @@ const SalesOrders = () => {
return ( return (
<> <ObjectListViewProvider
<Flex vertical={'true'} gap='large' className='h-100'> objectType='salesOrder'
<Flex justify={'space-between'} style={{ minHeight: 0 }}> tableRef={tableRef}
>
<Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify='space-between' style={{ minHeight: 0 }} gap='small'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='salesOrder' type='salesOrder'
@ -45,6 +48,7 @@ const SalesOrders = () => {
/> />
<ExportListButton objectType='salesOrder' /> <ExportListButton objectType='salesOrder' />
</Space> </Space>
<ListViewTabs />
<Space> <Space>
<SortSidebarButton <SortSidebarButton
active={showSortSidebar} active={showSortSidebar}
@ -55,17 +59,16 @@ const SalesOrders = () => {
onClick={() => setShowFilterSidebar(!showFilterSidebar)} onClick={() => setShowFilterSidebar(!showFilterSidebar)}
/> />
<ObjectTableViewButton <ObjectTableViewButton
viewMode={viewMode} objectType='salesOrder'
setViewMode={setViewMode}
showEndingDivider={true}
/> />
<ListViewEditButtons showStartingDivider={true} />
</Space> </Space>
</Flex> </Flex>
<ObjectTable <ObjectTable
ref={tableRef} ref={tableRef}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='salesOrder' type='salesOrder'
cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
showSortSidebar={showSortSidebar} showSortSidebar={showSortSidebar}
expandHeight={true} expandHeight={true}
@ -79,7 +82,7 @@ const SalesOrders = () => {
useSortInUrl={true} useSortInUrl={true}
/> />
</Flex> </Flex>
</> </ObjectListViewProvider>
) )
} }

View File

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

View File

@ -28,7 +28,7 @@ const mainSections = ['production', 'inventory', 'management', 'developer']
const DashboardBreadcrumb = () => { const DashboardBreadcrumb = () => {
const location = useLocation() const location = useLocation()
const navigate = useNavigate() const navigate = useNavigate()
const { hasPageFilter, hasStoredFilter } = useTableState() const { hasPageFilter, hasStoredFilter, getObjectListView } = useTableState()
const pathSnippets = location.pathname.split('/').filter((i) => i) const pathSnippets = location.pathname.split('/').filter((i) => i)
function segmentToModel(segment) { function segmentToModel(segment) {
@ -45,7 +45,15 @@ const DashboardBreadcrumb = () => {
const isMainSection = mainSections.includes(segment) const isMainSection = mainSections.includes(segment)
const model = segmentToModel(segment) const model = segmentToModel(segment)
const modelLabelPlural = model?.labelPlural ? model.labelPlural : null const modelLabelPlural = model?.labelPlural ? model.labelPlural : null
const viewName =
modelLabelPlural && model?.name && model.name !== 'unknown'
? getObjectListView(model.name)?.name
: null
const name = breadcrumbNameMap[segment] || modelLabelPlural || segment const name = breadcrumbNameMap[segment] || modelLabelPlural || segment
const displayName =
modelLabelPlural && viewName
? `${modelLabelPlural} - ${viewName}`
: name
const showFilterIcon = const showFilterIcon =
hasPageFilter(url) || hasPageFilter(url) ||
(model?.name && model.name !== 'unknown' && hasStoredFilter(model.name)) (model?.name && model.name !== 'unknown' && hasStoredFilter(model.name))
@ -53,7 +61,7 @@ const DashboardBreadcrumb = () => {
return { return {
title: ( title: (
<span style={{ padding: '0 12px' }} key={segment}> <span style={{ padding: '0 12px' }} key={segment}>
{name} {displayName}
</span> </span>
), ),
key: segment key: segment
@ -71,7 +79,7 @@ const DashboardBreadcrumb = () => {
gap: 6 gap: 6
}} }}
> >
{name} {displayName}
{showFilterIcon && <FilterIcon style={{ fontSize: 12 }} />} {showFilterIcon && <FilterIcon style={{ fontSize: 12 }} />}
</Link> </Link>
), ),

View File

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

View File

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

View File

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

View File

@ -0,0 +1,426 @@
import {
forwardRef,
useCallback,
useContext,
useImperativeHandle,
useLayoutEffect,
useMemo,
useRef,
useState
} from 'react'
import { Empty, Flex, Spin } from 'antd'
import { LoadingOutlined } from '@ant-design/icons'
import PropTypes from 'prop-types'
import { ApiServerContext } from '../context/ApiServerContext'
import ObjectCard from './ObjectCard'
import ObjectKanbanColumn from './ObjectKanbanColumn'
import ObjectKanbanHeader from './ObjectKanbanHeader'
import ScrollBox from './ScrollBox'
import { getCategoryValueKey } from './viewModeUtils'
const KANBAN_COLUMN_WIDTH = 360
const KANBAN_GAP = 16
const KANBAN_CARD_MIN_HEIGHT = 136
const getKanbanSkeletonLayout = (width, height) => {
const columnCount =
Math.max(
1,
Math.floor((width + KANBAN_GAP) / (KANBAN_COLUMN_WIDTH + KANBAN_GAP))
) + 1
const cardCount = Math.max(
1,
Math.floor((height - 32) / KANBAN_CARD_MIN_HEIGHT)
)
return { columnCount, cardCount }
}
const ObjectKanbanSkeletonColumns = ({
columnCount,
cardCount = 0,
trackRef,
model,
modelProperties,
visibleColumns,
keyPrefix = 'skeleton'
}) => (
<div className='objectKanbanSkeletonColumns objectKanbanSkeletonColumns--loading'>
<div className='objectKanbanSkeletonTrack' ref={trackRef}>
<Flex gap='middle' className='objectKanbanSkeletonRow'>
{Array.from({ length: columnCount }).map((_, columnIndex) => (
<div
key={`${keyPrefix}-${columnIndex}`}
className='objectKanbanColumnSkeleton'
>
<div className='objectKanbanColumnCards'>
{cardCount > 0 && (
<Flex
vertical
gap='middle'
className='objectKanbanColumnCardsInner'
>
{Array.from({ length: cardCount }).map((_, cardIndex) => (
<ObjectCard
key={cardIndex}
isSkeleton
model={model}
modelProperties={modelProperties}
visibleColumns={visibleColumns}
record={{
_id: `${keyPrefix}-${columnIndex}-${cardIndex}`
}}
cardStyle='bordered'
/>
))}
</Flex>
)}
</div>
</div>
))}
</Flex>
</div>
</div>
)
ObjectKanbanSkeletonColumns.propTypes = {
columnCount: PropTypes.number.isRequired,
cardCount: PropTypes.number,
trackRef: PropTypes.object,
model: PropTypes.object.isRequired,
modelProperties: PropTypes.array.isRequired,
visibleColumns: PropTypes.object,
keyPrefix: PropTypes.string
}
const ObjectKanban = forwardRef(
(
{
type,
categoryProperty,
baseFilter = {},
masterFilter = {},
sorter = {},
pageSize = 25,
model,
modelProperties,
visibleColumns = {},
isEditing = false,
rowActions = [],
renderActions
},
ref
) => {
const { getModelPropertyValues } = useContext(ApiServerContext)
const columnRefs = useRef({})
const headerTrackRef = useRef(null)
const skeletonTrackRef = useRef(null)
const kanbanBodyRef = useRef(null)
const [scrollElement, setScrollElement] = useState(null)
const [categoryValues, setCategoryValues] = useState([])
const [hasLoaded, setHasLoaded] = useState(false)
const [loadedFilter, setLoadedFilter] = useState(baseFilter)
const [loadedSorter, setLoadedSorter] = useState(sorter)
const [skeletonLayout, setSkeletonLayout] = useState({
columnCount: 3,
cardCount: 3
})
const baseFilterRef = useRef(baseFilter)
const masterFilterRef = useRef(masterFilter)
const sorterRef = useRef(sorter)
const getModelPropertyValuesRef = useRef(getModelPropertyValues)
const lastCategoryQueryKeyRef = useRef(null)
const hasLoadedRef = useRef(false)
const loadGenerationRef = useRef(0)
baseFilterRef.current = baseFilter
masterFilterRef.current = masterFilter
sorterRef.current = sorter
getModelPropertyValuesRef.current = getModelPropertyValues
const setScrollContainerRef = useCallback((node) => {
setScrollElement(node)
}, [])
useLayoutEffect(() => {
const kanbanBody = kanbanBodyRef.current
if (!kanbanBody) return undefined
const updateLayout = () => {
const { width, height } = kanbanBody.getBoundingClientRect()
setSkeletonLayout(getKanbanSkeletonLayout(width, height))
}
updateLayout()
const observer = new ResizeObserver(updateLayout)
observer.observe(kanbanBody)
return () => observer.disconnect()
}, [categoryProperty])
useLayoutEffect(() => {
const mainScroll = scrollElement
const headerTrack = headerTrackRef.current
const skeletonTrack = skeletonTrackRef.current
if (!mainScroll || !headerTrack) return undefined
const handleMainScroll = () => {
const offset = `translate3d(-${mainScroll.scrollLeft}px, 0, 0)`
headerTrack.style.transform = offset
if (skeletonTrack) {
skeletonTrack.style.transform = offset
}
}
handleMainScroll()
mainScroll.addEventListener('scroll', handleMainScroll, { passive: true })
return () => {
mainScroll.removeEventListener('scroll', handleMainScroll)
}
}, [scrollElement, categoryValues])
const categoryPropertyDef = useMemo(
() =>
model?.properties?.find(
(property) => property.name === categoryProperty
),
[categoryProperty, model]
)
const buildCategoryQueryKey = useCallback(
(filter, activeSorter) =>
JSON.stringify({
type,
categoryProperty,
filter,
masterFilter: masterFilterRef.current,
sorter: activeSorter
}),
[categoryProperty, type]
)
const reloadColumns = useCallback(async () => {
await Promise.all(
Object.values(columnRefs.current)
.filter(Boolean)
.map((columnRef) => columnRef.reload?.())
)
}, [])
const load = useCallback(
async (filter = null, sorterArg = null, options = {}) => {
const silent = options.silent === true
const generation = ++loadGenerationRef.current
if (!categoryProperty) {
lastCategoryQueryKeyRef.current = null
hasLoadedRef.current = true
setCategoryValues([])
setHasLoaded(true)
return
}
const activeFilter = filter ?? baseFilterRef.current
const activeSorter = sorterArg ?? sorterRef.current
const activeMasterFilter = masterFilterRef.current
const queryKey = buildCategoryQueryKey(activeFilter, activeSorter)
const canReuseColumns =
lastCategoryQueryKeyRef.current === queryKey && hasLoadedRef.current
if (canReuseColumns) {
await reloadColumns()
if (generation !== loadGenerationRef.current) return
hasLoadedRef.current = true
setHasLoaded(true)
return
}
// Filter/sort changes keep current columns visible; objectView /
// initial loads clear to skeleton + Spin.
if (!silent || !hasLoadedRef.current) {
hasLoadedRef.current = false
setHasLoaded(false)
}
try {
const values = await getModelPropertyValuesRef.current(
type,
categoryProperty,
{
filter: activeFilter,
masterFilter: activeMasterFilter
}
)
if (generation !== loadGenerationRef.current) return
const nextValues = Array.isArray(values) ? values : []
lastCategoryQueryKeyRef.current = queryKey
hasLoadedRef.current = true
setLoadedFilter(activeFilter)
setLoadedSorter(activeSorter)
setCategoryValues(nextValues)
setHasLoaded(true)
} catch (error) {
if (generation !== loadGenerationRef.current) return
console.error('Error fetching kanban category values:', error)
lastCategoryQueryKeyRef.current = null
hasLoadedRef.current = true
setCategoryValues([])
setHasLoaded(true)
throw error
}
},
[buildCategoryQueryKey, categoryProperty, reloadColumns, type]
)
const reload = useCallback(async () => {
lastCategoryQueryKeyRef.current = null
hasLoadedRef.current = false
await load(baseFilterRef.current, sorterRef.current)
}, [load])
useImperativeHandle(
ref,
() => ({
load,
reload
}),
[load, reload]
)
if (!categoryProperty) {
return (
<Flex align='center' justify='center' style={{ height: '100%' }}>
<Empty description='Select a category property for kanban view' />
</Flex>
)
}
if (hasLoaded && categoryValues.length === 0) {
return (
<Flex align='center' justify='center' style={{ height: '100%' }}>
<Empty description='No category values found' />
</Flex>
)
}
const showSkeleton = !hasLoaded
return (
<div className='objectKanbanContainerWrapper'>
<Spin
indicator={<LoadingOutlined />}
spinning={showSkeleton}
style={{ height: '100%', flex: 1, minHeight: 0 }}
>
<div className='objectKanbanContainerSkeletons'>
<ObjectKanbanHeader
categoryValues={categoryValues}
categoryProperty={categoryProperty}
categoryPropertyDef={categoryPropertyDef}
trackRef={headerTrackRef}
skeletonColumnCount={
showSkeleton ? skeletonLayout.columnCount : 0
}
/>
<div className='objectKanbanKanbanBody' ref={kanbanBodyRef}>
{!showSkeleton && (
<div className='objectKanbanContainer'>
<ScrollBox
className='objectKanbanScroll'
scrollableNodeProps={{ ref: setScrollContainerRef }}
>
<Flex gap='middle' className='objectKanban'>
{categoryValues.map((categoryValue) => {
const columnKey = getCategoryValueKey(categoryValue)
return (
<ObjectKanbanColumn
key={columnKey}
ref={(node) => {
if (node) {
columnRefs.current[columnKey] = node
} else {
delete columnRefs.current[columnKey]
}
}}
scrollElement={scrollElement}
type={type}
categoryProperty={categoryProperty}
categoryValue={categoryValue}
baseFilter={loadedFilter}
masterFilter={masterFilter}
sorter={loadedSorter}
pageSize={pageSize}
model={model}
modelProperties={modelProperties}
visibleColumns={visibleColumns}
isEditing={isEditing}
rowActions={rowActions}
renderActions={renderActions}
/>
)
})}
</Flex>
</ScrollBox>
</div>
)}
{showSkeleton ? (
<ObjectKanbanSkeletonColumns
columnCount={skeletonLayout.columnCount}
cardCount={skeletonLayout.cardCount}
trackRef={skeletonTrackRef}
model={model}
modelProperties={modelProperties}
visibleColumns={visibleColumns}
/>
) : (
<div className='objectKanbanSkeletonColumns'>
<div
className='objectKanbanSkeletonTrack'
ref={skeletonTrackRef}
>
<Flex gap='middle' className='objectKanbanSkeletonRow'>
{categoryValues.map((categoryValue) => {
const columnKey = getCategoryValueKey(categoryValue)
return (
<div
key={columnKey}
className='objectKanbanColumnSkeleton'
>
<div className='objectKanbanColumnCards' />
</div>
)
})}
</Flex>
</div>
</div>
)}
</div>
</div>
</Spin>
</div>
)
}
)
ObjectKanban.displayName = 'ObjectKanban'
ObjectKanban.propTypes = {
type: PropTypes.string.isRequired,
categoryProperty: PropTypes.string,
baseFilter: PropTypes.object,
masterFilter: PropTypes.object,
sorter: PropTypes.object,
pageSize: PropTypes.number,
model: PropTypes.object.isRequired,
modelProperties: PropTypes.array.isRequired,
visibleColumns: PropTypes.object,
isEditing: PropTypes.bool,
rowActions: PropTypes.array,
renderActions: PropTypes.func
}
export default ObjectKanban

View File

@ -0,0 +1,567 @@
import {
forwardRef,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useLayoutEffect,
useMemo,
useRef,
useState
} from 'react'
import { Flex, Spin } from 'antd'
import { LoadingOutlined } from '@ant-design/icons'
import PropTypes from 'prop-types'
import { ApiServerContext } from '../context/ApiServerContext'
import ObjectCard from './ObjectCard'
import { toCategoryFilterValue } from './viewModeUtils'
const SCROLL_THRESHOLD = 50
const ObjectKanbanColumn = forwardRef(
(
{
type,
categoryProperty,
categoryValue,
baseFilter = {},
masterFilter = {},
sorter = {},
pageSize = 25,
model,
modelProperties,
visibleColumns = {},
isEditing = false,
rowActions = [],
renderActions,
scrollElement = null
},
ref
) => {
const { fetchObjects } = useContext(ApiServerContext)
const containerRef = useRef(null)
const pagesRef = useRef([])
const loadingPagesRef = useRef(new Set())
const dataLoadGenerationRef = useRef(0)
const pendingScrollAnchorRef = useRef(null)
const lastColumnQueryKeyRef = useRef(null)
const baseFilterRef = useRef(baseFilter)
const masterFilterRef = useRef(masterFilter)
const sorterRef = useRef(sorter)
const fetchObjectsRef = useRef(fetchObjects)
baseFilterRef.current = baseFilter
masterFilterRef.current = masterFilter
sorterRef.current = sorter
fetchObjectsRef.current = fetchObjects
const [pages, setPages] = useState([])
const [loading, setLoading] = useState(true)
const columnFilter = useMemo(
() => ({
...baseFilter,
[categoryProperty]: toCategoryFilterValue(categoryValue)
}),
[baseFilter, categoryProperty, categoryValue]
)
const columnQueryKey = useMemo(
() =>
JSON.stringify({
type,
categoryProperty,
categoryValue: toCategoryFilterValue(categoryValue),
filter: columnFilter,
sorter
}),
[columnFilter, categoryProperty, categoryValue, sorter, type]
)
const tableData = useMemo(() => {
const items = pages.flatMap((page) => page.items)
const seen = new Set()
return items.filter((item) => {
const id = item?._id
if (id == null) return true
if (seen.has(id)) return false
seen.add(id)
return true
})
}, [pages])
const createSkeletonData = useCallback(
(pageNum) =>
Array(pageSize)
.fill(null)
.map((_, index) => ({
_id: `skeleton-${categoryProperty}-${pageNum}-${index}`,
isSkeleton: true
})),
[categoryProperty, pageSize]
)
const createSkeletonPage = useCallback(
(pageNum) => ({
pageNum,
items: createSkeletonData(pageNum),
isSkeletonPage: true
}),
[createSkeletonData]
)
const createPageWindow = useCallback(
(loadedPages, direction) => {
const dedupedByPageNum = new Map()
loadedPages.forEach((page) => {
dedupedByPageNum.set(page.pageNum, page)
})
const sortedPages = [...dedupedByPageNum.values()].sort(
(a, b) => a.pageNum - b.pageNum
)
const visiblePages =
direction === 'previous'
? sortedPages.slice(0, 2)
: sortedPages.slice(-2)
const firstPage = visiblePages[0]
const lastPage = visiblePages[visiblePages.length - 1]
const nextPages = []
if (firstPage?.pageNum > 1) {
nextPages.push(createSkeletonPage(firstPage.pageNum - 1))
}
nextPages.push(...visiblePages)
if (lastPage?.hasMore) {
nextPages.push(createSkeletonPage(lastPage.pageNum + 1))
}
return nextPages
},
[createSkeletonPage]
)
const mergeLoadedPage = useCallback((currentPages, loadedPage) => {
const withoutSkeletons = currentPages.filter(
(page) => !page.isSkeletonPage
)
const withoutDuplicate = withoutSkeletons.filter(
(page) => page.pageNum !== loadedPage.pageNum
)
return [...withoutDuplicate, loadedPage].sort(
(a, b) => a.pageNum - b.pageNum
)
}, [])
const setTablePages = useCallback((nextPages) => {
pagesRef.current = nextPages
setPages(nextPages)
}, [])
const isStaleDataLoad = useCallback(
(generation) => generation !== dataLoadGenerationRef.current,
[]
)
const fetchPage = useCallback(
async (pageNum, overrides = {}) => {
const filter = overrides.filter ?? {
...masterFilterRef.current,
...baseFilterRef.current,
[categoryProperty]: toCategoryFilterValue(categoryValue)
}
const sorter = overrides.sorter ?? sorterRef.current
return fetchObjectsRef.current(type, {
page: pageNum,
limit: pageSize,
filter,
sorter
})
},
[categoryProperty, categoryValue, pageSize, type]
)
const fetchData = useCallback(
async (pageNum) => {
const generation = dataLoadGenerationRef.current
try {
const result = await fetchPage(pageNum)
if (isStaleDataLoad(generation)) return []
const loadedPage = {
pageNum,
items: result.data || [],
hasMore: result.hasMore
}
setPages((prev) =>
prev.map((page) => (page.pageNum === pageNum ? loadedPage : page))
)
return result.data || []
} catch (error) {
console.error(`Error loading kanban page ${pageNum}:`, error)
return []
}
},
[fetchPage, isStaleDataLoad]
)
const findRenderedCard = useCallback((scrollTarget, id) => {
if (!scrollTarget || id == null) return null
return scrollTarget.querySelector(`[data-kanban-card-id="${String(id)}"]`)
}, [])
const captureScrollAnchor = useCallback(
(scrollTarget, placeholderPage, direction, currentPages) => {
if (!scrollTarget) return null
const targetTop = scrollTarget.getBoundingClientRect().top
const closestCard = (items) =>
items
.map((item, index) => {
const element = findRenderedCard(scrollTarget, item._id)
return element
? {
index,
id: item._id,
top: element.getBoundingClientRect().top
}
: null
})
.filter(Boolean)
.sort(
(a, b) =>
Math.abs(a.top - targetTop) - Math.abs(b.top - targetTop)
)[0]
const placeholderAnchor = closestCard(placeholderPage.items)
const loadedPages = currentPages.filter((page) => !page.isSkeletonPage)
const retainedPage =
direction === 'previous'
? loadedPages[0]
: loadedPages[loadedPages.length - 1]
const fallbackAnchor = retainedPage
? closestCard(retainedPage.items)
: null
return { placeholderAnchor, fallbackAnchor }
},
[findRenderedCard]
)
const restoreScrollAnchor = useCallback(
(scrollTarget, anchor, loadedPage) => {
if (!scrollTarget || !anchor) return
const loadedItem = loadedPage.items[anchor.placeholderAnchor?.index]
const anchorId = loadedItem?._id ?? anchor.fallbackAnchor?.id
const previousTop = loadedItem
? anchor.placeholderAnchor?.top
: anchor.fallbackAnchor?.top
if (anchorId == null || previousTop == null) return
const element = findRenderedCard(scrollTarget, anchorId)
if (!element) return
const renderedTop = element.getBoundingClientRect().top
scrollTarget.scrollTop += renderedTop - previousTop
},
[findRenderedCard]
)
useLayoutEffect(() => {
const pendingAnchor = pendingScrollAnchorRef.current
if (!pendingAnchor) return
pendingScrollAnchorRef.current = null
restoreScrollAnchor(
pendingAnchor.scrollTarget,
pendingAnchor.anchor,
pendingAnchor.loadedPage
)
}, [pages, restoreScrollAnchor])
const loadBoundaryPage = useCallback(
async (pageNum, direction, scrollTarget) => {
if (loadingPagesRef.current.size > 0) return
const currentPages = pagesRef.current
const placeholderPage = currentPages.find(
(page) => page.pageNum === pageNum && page.isSkeletonPage
)
if (!placeholderPage) return
const scrollAnchor = captureScrollAnchor(
scrollTarget,
placeholderPage,
direction,
currentPages
)
const generation = dataLoadGenerationRef.current
loadingPagesRef.current.add(pageNum)
try {
const result = await fetchPage(pageNum)
if (isStaleDataLoad(generation)) return
const loadedPage = {
pageNum,
items: result.data || [],
hasMore: result.hasMore
}
pendingScrollAnchorRef.current = {
scrollTarget,
anchor: scrollAnchor,
loadedPage
}
setPages((prev) => {
if (
!prev.some(
(page) => page.pageNum === pageNum && page.isSkeletonPage
)
) {
return prev
}
const loadedPages = mergeLoadedPage(prev, loadedPage)
return createPageWindow(loadedPages, direction)
})
} catch (error) {
console.error(`Error loading kanban page ${pageNum}:`, error)
} finally {
loadingPagesRef.current.delete(pageNum)
}
},
[
captureScrollAnchor,
createPageWindow,
fetchPage,
isStaleDataLoad,
mergeLoadedPage
]
)
const loadNextPage = useCallback(
(scrollTarget) => {
const nextPage = pagesRef.current[pagesRef.current.length - 1]
if (nextPage?.isSkeletonPage) {
loadBoundaryPage(nextPage.pageNum, 'next', scrollTarget)
}
},
[loadBoundaryPage]
)
const loadPreviousPage = useCallback(
(scrollTarget) => {
const previousPage = pagesRef.current[0]
if (previousPage?.isSkeletonPage) {
loadBoundaryPage(previousPage.pageNum, 'previous', scrollTarget)
}
},
[loadBoundaryPage]
)
const loadInitialPage = useCallback(async ({ silent = false } = {}) => {
dataLoadGenerationRef.current += 1
loadingPagesRef.current.clear()
pendingScrollAnchorRef.current = null
const generation = dataLoadGenerationRef.current
const filter = {
...masterFilterRef.current,
...baseFilterRef.current,
[categoryProperty]: toCategoryFilterValue(categoryValue)
}
const sorter = sorterRef.current
if (!silent) {
pagesRef.current = []
setPages([])
setLoading(true)
const skeletonPage = createSkeletonPage(1)
setTablePages([skeletonPage])
} else {
setLoading(false)
}
try {
const firstResult = await fetchPage(1, { filter, sorter })
if (isStaleDataLoad(generation)) return
const loadedPages = [
{
pageNum: 1,
items: firstResult.data || [],
hasMore: firstResult.hasMore
}
]
if (!isStaleDataLoad(generation)) {
setTablePages(createPageWindow(loadedPages, 'next'))
}
} catch {
if (!silent && !isStaleDataLoad(generation)) {
setTablePages([])
}
} finally {
if (!silent && !isStaleDataLoad(generation)) {
setLoading(false)
}
}
}, [
categoryProperty,
categoryValue,
createPageWindow,
createSkeletonPage,
fetchPage,
isStaleDataLoad,
setTablePages
])
const reloadLoadedPages = useCallback(async () => {
const loadedPages = pagesRef.current.filter(
(page) => !page.isSkeletonPage
)
for (let i = 0; i < loadedPages.length; i++) {
await fetchData(loadedPages[i].pageNum)
}
}, [fetchData])
useImperativeHandle(ref, () => ({
reload: reloadLoadedPages
}))
useEffect(() => {
if (lastColumnQueryKeyRef.current === columnQueryKey) return
// First mount shows skeleton; later filter/sort updates load silently.
const silent = lastColumnQueryKeyRef.current != null
let cancelled = false
const runLoad = async () => {
await loadInitialPage({ silent })
if (!cancelled) {
lastColumnQueryKeyRef.current = columnQueryKey
}
}
runLoad()
return () => {
cancelled = true
}
}, [columnQueryKey, loadInitialPage])
const skeletonBoundaryIds = useMemo(() => {
const firstPage = pages[0]
const lastPage = pages[pages.length - 1]
return {
previous:
firstPage?.isSkeletonPage && firstPage.items.length > 0
? firstPage.items[firstPage.items.length - 1]._id
: null,
next:
lastPage?.isSkeletonPage && lastPage.items[0]
? lastPage.items[0]._id
: null
}
}, [pages])
useLayoutEffect(() => {
const container = containerRef.current
if (!container || !scrollElement) return
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue
const boundary = entry.target.dataset.skeletonBoundary
if (boundary === 'next') {
loadNextPage(scrollElement)
} else if (boundary === 'previous') {
loadPreviousPage(scrollElement)
}
}
},
{
root: scrollElement,
rootMargin: `${SCROLL_THRESHOLD}px`,
threshold: 0
}
)
container
.querySelectorAll('[data-skeleton-boundary]')
.forEach((el) => observer.observe(el))
return () => observer.disconnect()
}, [
scrollElement,
skeletonBoundaryIds,
loadNextPage,
loadPreviousPage,
tableData
])
return (
<Flex vertical className='objectKanbanColumn'>
<div className='objectKanbanColumnCards' ref={containerRef}>
<Spin indicator={<LoadingOutlined />} spinning={loading}>
<Flex
vertical
gap='middle'
className='objectKanbanColumnCardsInner'
>
{tableData.map((record) => {
if (record?._id == undefined) return null
const skeletonBoundary =
record._id === skeletonBoundaryIds.next
? 'next'
: record._id === skeletonBoundaryIds.previous
? 'previous'
: undefined
return (
<div
key={record._id}
data-kanban-card-id={record._id}
data-skeleton-boundary={skeletonBoundary}
>
<ObjectCard
isSkeleton={record?.isSkeleton || false}
model={model}
modelProperties={modelProperties}
visibleColumns={visibleColumns}
record={record}
isEditing={isEditing}
rowActions={rowActions}
renderActions={renderActions}
cardStyle='bordered'
/>
</div>
)
})}
</Flex>
</Spin>
</div>
</Flex>
)
}
)
ObjectKanbanColumn.displayName = 'ObjectKanbanColumn'
ObjectKanbanColumn.propTypes = {
type: PropTypes.string.isRequired,
categoryProperty: PropTypes.string.isRequired,
categoryValue: PropTypes.any,
baseFilter: PropTypes.object,
masterFilter: PropTypes.object,
sorter: PropTypes.object,
pageSize: PropTypes.number,
model: PropTypes.object.isRequired,
modelProperties: PropTypes.array.isRequired,
visibleColumns: PropTypes.object,
isEditing: PropTypes.bool,
rowActions: PropTypes.array,
renderActions: PropTypes.func,
scrollElement: PropTypes.object
}
export default ObjectKanbanColumn

View File

@ -0,0 +1,63 @@
import { Flex, Skeleton } from 'antd'
import PropTypes from 'prop-types'
import ObjectProperty from './ObjectProperty'
import { getCategoryValueKey } from './viewModeUtils'
const ObjectKanbanHeader = ({
categoryValues,
categoryProperty,
categoryPropertyDef,
trackRef,
skeletonColumnCount = 0
}) => {
const showSkeleton = skeletonColumnCount > 0
return (
<div className='objectKanbanHeader'>
<div className='objectKanbanHeaderTrack' ref={trackRef}>
<Flex gap='middle' className='objectKanbanHeaderRow'>
{showSkeleton
? Array.from({ length: skeletonColumnCount }).map((_, index) => (
<div
key={`skeleton-header-${index}`}
className='objectKanbanHeaderCell'
>
<Skeleton.Input
active
size='small'
style={{ width: '60%', height: 24 }}
/>
</div>
))
: categoryValues.map((categoryValue) => {
const columnKey = getCategoryValueKey(categoryValue)
return (
<div key={columnKey} className='objectKanbanHeaderCell'>
{categoryPropertyDef ? (
<ObjectProperty
{...categoryPropertyDef}
value={categoryValue}
objectData={{ [categoryProperty]: categoryValue }}
name={categoryProperty}
/>
) : null}
</div>
)
})}
</Flex>
</div>
</div>
)
}
ObjectKanbanHeader.displayName = 'ObjectKanbanHeader'
ObjectKanbanHeader.propTypes = {
categoryValues: PropTypes.array.isRequired,
categoryProperty: PropTypes.string.isRequired,
categoryPropertyDef: PropTypes.object,
trackRef: PropTypes.object,
skeletonColumnCount: PropTypes.number
}
export default ObjectKanbanHeader

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,24 +1,188 @@
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Button, Divider, Flex } from 'antd' import { useContext, useMemo, useState } from 'react'
import ObjectListViewContext from '../context/ObjectListViewContext'
import {
Button,
Divider,
Flex,
Modal,
Popover,
Radio,
Select,
Typography
} from 'antd'
import GridIcon from '../../Icons/GridIcon' import GridIcon from '../../Icons/GridIcon'
import ListIcon from '../../Icons/ListIcon' import ListIcon from '../../Icons/ListIcon'
import KanbanIcon from '../../Icons/KanbanIcon'
import SettingsIcon from '../../Icons/SettingsIcon'
import { getModelByName } from '../../../database/ObjectModels'
import { getViewModeType, normalizeViewMode } from './viewModeUtils'
const VIEW_MODE_OPTIONS = [
{ type: 'list', label: 'List' },
{ type: 'cards', label: 'Cards' },
{ type: 'kanban', label: 'Kanban' }
]
const { Text } = Typography
const ObjectTableViewButton = ({ const ObjectTableViewButton = ({
viewMode, objectType,
setViewMode, viewMode: viewModeProp,
setViewMode: setViewModeProp,
showEndingDivider = false, showEndingDivider = false,
...buttonProps ...buttonProps
}) => { }) => {
const content = ( const objectListView = useContext(ObjectListViewContext)
<Button const viewMode = viewModeProp ?? objectListView?.viewMode
icon={viewMode === 'cards' ? <ListIcon /> : <GridIcon />} const setViewMode = setViewModeProp ?? objectListView?.setViewMode
onClick={() => setViewMode(viewMode === 'cards' ? 'list' : 'cards')} const [settingsOpen, setSettingsOpen] = useState(false)
title={ const normalizedViewMode = normalizeViewMode(viewMode)
viewMode === 'cards' ? 'Switch to list view' : 'Switch to card view' const model = getModelByName(objectType)
}
{...buttonProps} const stateProperties = useMemo(
/> () =>
model?.properties?.filter((property) => property.type === 'state') || [],
[model]
) )
const hasKanbanOption = stateProperties.length > 0
const defaultCategoryProperty = stateProperties[0]?.name
const availableViewModes = useMemo(
() =>
VIEW_MODE_OPTIONS.filter(
(option) => option.type !== 'kanban' || hasKanbanOption
).map((option) => option.type),
[hasKanbanOption]
)
const handleTypeChange = (nextType) => {
if (nextType === 'kanban') {
setViewMode({
type: 'kanban',
settings: {
categoryProperty:
normalizedViewMode.type === 'kanban'
? normalizedViewMode.settings?.categoryProperty ||
defaultCategoryProperty
: defaultCategoryProperty
}
})
return
}
setViewMode({ type: nextType })
}
const handleCategoryPropertyChange = (categoryProperty) => {
setViewMode({
type: 'kanban',
settings: { categoryProperty }
})
}
const { onClick: buttonOnClick, ...restButtonProps } = buttonProps
const handleCycleView = (event) => {
buttonOnClick?.(event)
const currentType = getViewModeType(normalizedViewMode)
const currentIndex = availableViewModes.indexOf(currentType)
const nextIndex =
currentIndex === -1 ? 0 : (currentIndex + 1) % availableViewModes.length
handleTypeChange(availableViewModes[nextIndex])
}
const activeIcon =
normalizedViewMode.type === 'cards' ? (
<GridIcon />
) : normalizedViewMode.type === 'kanban' ? (
<KanbanIcon />
) : (
<ListIcon />
)
const content = (
<>
<Popover
content={
<Flex vertical>
<Radio.Group
value={getViewModeType(normalizedViewMode)}
onChange={(e) => handleTypeChange(e.target.value)}
>
<Flex vertical gap='middle' style={{ margin: '4px 8px' }}>
{VIEW_MODE_OPTIONS.filter(
(option) => option.type !== 'kanban' || hasKanbanOption
).map((option) => (
<Radio key={option.type} value={option.type}>
<Flex
gap='8px'
align='center'
style={{ marginLeft: '4px' }}
>
<Text>{option.label}</Text>
{option.type === 'kanban' && (
<Button
type='text'
size='small'
icon={
<SettingsIcon
style={{ fontSize: '14px', marginTop: '2.5px' }}
/>
}
disabled={normalizedViewMode.type !== 'kanban'}
onClick={(event) => {
event.preventDefault()
event.stopPropagation()
setSettingsOpen(true)
}}
/>
)}
</Flex>
</Radio>
))}
</Flex>
</Radio.Group>
</Flex>
}
placement='bottomLeft'
arrow={false}
trigger='hover'
>
<Button
icon={activeIcon}
title='View mode'
onClick={handleCycleView}
{...restButtonProps}
/>
</Popover>
<Modal
title='Kanban settings'
open={settingsOpen}
onCancel={() => setSettingsOpen(false)}
onOk={() => setSettingsOpen(false)}
destroyOnClose
>
<Select
style={{ width: '100%' }}
placeholder='Select category property'
value={
normalizedViewMode.settings?.categoryProperty ||
defaultCategoryProperty
}
onChange={handleCategoryPropertyChange}
options={stateProperties.map((property) => ({
value: property.name,
label: property.label || property.name
}))}
/>
</Modal>
</>
)
if (showEndingDivider) { if (showEndingDivider) {
return ( return (
<Flex gap='small' align='center'> <Flex gap='small' align='center'>
@ -31,8 +195,9 @@ const ObjectTableViewButton = ({
} }
ObjectTableViewButton.propTypes = { ObjectTableViewButton.propTypes = {
viewMode: PropTypes.oneOf(['list', 'cards']).isRequired, objectType: PropTypes.string.isRequired,
setViewMode: PropTypes.func.isRequired, viewMode: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
setViewMode: PropTypes.func,
showEndingDivider: PropTypes.bool showEndingDivider: PropTypes.bool
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,31 @@
export const DEFAULT_VIEW_MODE = { type: 'list' }
export const normalizeViewMode = (value) => {
if (!value) return DEFAULT_VIEW_MODE
if (typeof value === 'string') {
return {
type: value === 'cards' ? 'cards' : value === 'kanban' ? 'kanban' : 'list'
}
}
if (value?.type) return value
return DEFAULT_VIEW_MODE
}
export const isCardsView = (vm) => normalizeViewMode(vm).type === 'cards'
export const isKanbanView = (vm) => normalizeViewMode(vm).type === 'kanban'
export const getViewModeType = (vm) => normalizeViewMode(vm).type
export const toCategoryFilterValue = (value) => {
if (value && typeof value === 'object') {
return value.type ?? value._id ?? JSON.stringify(value)
}
return String(value)
}
export const getCategoryValueKey = (value) => {
if (value && typeof value === 'object' && value.type != null) {
return String(value.type)
}
if (value != null) return String(value)
return 'null'
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,9 @@ import {
createContext, createContext,
useCallback, useCallback,
useContext, useContext,
useEffect,
useMemo, useMemo,
useRef,
useState useState
} from 'react' } from 'react'
import { useSearchParams } from 'react-router-dom' import { useSearchParams } from 'react-router-dom'
@ -12,9 +14,13 @@ const TableStateContext = createContext()
export const FILTER_URL_PARAM = 'filter' export const FILTER_URL_PARAM = 'filter'
export const SORT_URL_PARAM = 'sort' export const SORT_URL_PARAM = 'sort'
export const VIEW_URL_PARAM = 'viewId'
const getSessionFilterKey = (scope) => `tableState:${scope}:filter` const getSessionFilterKey = (scope) => `tableState:${scope}:filter`
const getSessionSortKey = (scope) => `tableState:${scope}:sort` const getSessionSortKey = (scope) => `tableState:${scope}:sort`
const getSessionListFilterKey = (scope) => `tableState:${scope}:listFilter`
const getSessionListSortKey = (scope) => `tableState:${scope}:listSort`
const getSessionListViewKey = (scope) => `tableState:${scope}:listView`
// eslint-disable-next-line react-refresh/only-export-components // eslint-disable-next-line react-refresh/only-export-components
export const getActiveFilterValues = (filterState) => { export const getActiveFilterValues = (filterState) => {
@ -44,6 +50,8 @@ const readSortFromUrl = (searchParams) => {
return { field: parsed.field, order: parsed.order } return { field: parsed.field, order: parsed.order }
} }
const readViewFromUrl = (searchParams) => searchParams.get(VIEW_URL_PARAM) || null
const readFilterFromSession = (scope) => { const readFilterFromSession = (scope) => {
try { try {
return parseJsonParam(sessionStorage.getItem(getSessionFilterKey(scope))) return parseJsonParam(sessionStorage.getItem(getSessionFilterKey(scope)))
@ -86,6 +94,67 @@ const writeSortToSession = (scope, sorter) => {
} }
} }
const readListFilterFromSession = (scope) => {
try {
return parseJsonParam(sessionStorage.getItem(getSessionListFilterKey(scope)))
} catch {
return null
}
}
const readListSortFromSession = (scope) => {
try {
const parsed = parseJsonParam(sessionStorage.getItem(getSessionListSortKey(scope)))
if (!parsed?.field || !parsed?.order) return null
return { field: parsed.field, order: parsed.order }
} catch {
return null
}
}
const writeListFilterToSession = (scope, filter) => {
const key = getSessionListFilterKey(scope)
if (Object.keys(filter).length > 0) {
sessionStorage.setItem(key, JSON.stringify(filter))
} else {
sessionStorage.removeItem(key)
}
}
const writeListSortToSession = (scope, sorter) => {
const key = getSessionListSortKey(scope)
if (sorter?.field && sorter?.order) {
sessionStorage.setItem(key, JSON.stringify(sorter))
} else {
sessionStorage.removeItem(key)
}
}
const readListViewFromSession = (scope) => {
try {
const parsed = parseJsonParam(sessionStorage.getItem(getSessionListViewKey(scope)))
if (!parsed?.id) return null
return {
id: String(parsed.id),
name: parsed.name || null
}
} catch {
return null
}
}
const writeListViewToSession = (scope, view) => {
const key = getSessionListViewKey(scope)
if (view?.id) {
sessionStorage.setItem(
key,
JSON.stringify({ id: String(view.id), name: view.name || null })
)
} else {
sessionStorage.removeItem(key)
}
}
const normalizeSorter = (sorter) => { const normalizeSorter = (sorter) => {
if (sorter?.field && sorter?.order) { if (sorter?.field && sorter?.order) {
return { field: sorter.field, order: sorter.order } return { field: sorter.field, order: sorter.order }
@ -97,6 +166,50 @@ export const TableStateProvider = ({ children }) => {
const [searchParams, setSearchParams] = useSearchParams() const [searchParams, setSearchParams] = useSearchParams()
const [pageFilters, setPageFilters] = useState({}) const [pageFilters, setPageFilters] = useState({})
const [pageSorters, setPageSorters] = useState({}) const [pageSorters, setPageSorters] = useState({})
// Effective list filters (view filter + user filters). Survives navigating
// from the list page to an info page so breadcrumb/neighbors keep working.
const [objectListFilters, setObjectListFilters] = useState({})
const [objectListSorters, setObjectListSorters] = useState({})
// Active list view (id + name) per object type — same survival pattern as filters.
const [objectListViews, setObjectListViews] = useState({})
const searchParamsRef = useRef(searchParams)
// Tracks an in-flight optimistic URL write so a render with stale router
// searchParams cannot clobber searchParamsRef and resurrect deleted params
// (e.g. viewId briefly cleared on All, then written back by persistTableState).
const pendingSearchParamsRef = useRef(null)
const previousSearchParamsRef = useRef(searchParams.toString())
useEffect(() => {
const current = searchParams.toString()
if (pendingSearchParamsRef.current != null) {
if (current === pendingSearchParamsRef.current) {
pendingSearchParamsRef.current = null
} else if (current === previousSearchParamsRef.current) {
// Stale snapshot from before our write — keep the optimistic ref.
return
} else {
// External navigation while a write was pending — accept it.
pendingSearchParamsRef.current = null
}
}
previousSearchParamsRef.current = current
searchParamsRef.current = searchParams
}, [searchParams])
// Keep sequential URL writes in the same tick from clobbering each other
// (e.g. persistView then persistTableState both calling setSearchParams).
const updateSearchParams = useCallback(
(mutator) => {
const previous = searchParamsRef.current.toString()
const next = new URLSearchParams(searchParamsRef.current)
mutator(next)
previousSearchParamsRef.current = previous
searchParamsRef.current = next
pendingSearchParamsRef.current = next.toString()
setSearchParams(next, { replace: true })
},
[setSearchParams]
)
const getPersistedFilter = useCallback( const getPersistedFilter = useCallback(
(scope, { useFilterInUrl = false, useFilterInSession = false } = {}) => { (scope, { useFilterInUrl = false, useFilterInSession = false } = {}) => {
@ -128,6 +241,31 @@ export const TableStateProvider = ({ children }) => {
[searchParams] [searchParams]
) )
const getViewFromUrl = useCallback(
() => readViewFromUrl(searchParams),
[searchParams]
)
const persistView = useCallback(
(viewId, { clearFilterSort = Boolean(viewId) } = {}) => {
updateSearchParams((next) => {
// Drop legacy `view` param that previously stored `_reference`
next.delete('view')
if (viewId) {
next.set(VIEW_URL_PARAM, String(viewId))
} else {
next.delete(VIEW_URL_PARAM)
}
// View filter/sort live on the view object — never in the URL
if (clearFilterSort) {
next.delete(FILTER_URL_PARAM)
next.delete(SORT_URL_PARAM)
}
})
},
[updateSearchParams]
)
const persistFilter = useCallback( const persistFilter = useCallback(
( (
scope, scope,
@ -139,16 +277,16 @@ export const TableStateProvider = ({ children }) => {
writeFilterToSession(scope, active) writeFilterToSession(scope, active)
} }
if (saveFilterInUrl) { if (saveFilterInUrl) {
const next = new URLSearchParams(searchParams) updateSearchParams((next) => {
if (Object.keys(active).length > 0) { if (Object.keys(active).length > 0) {
next.set(FILTER_URL_PARAM, JSON.stringify(active)) next.set(FILTER_URL_PARAM, JSON.stringify(active))
} else { } else {
next.delete(FILTER_URL_PARAM) next.delete(FILTER_URL_PARAM)
} }
setSearchParams(next, { replace: true }) })
} }
}, },
[searchParams, setSearchParams] [updateSearchParams]
) )
const persistSort = useCallback( const persistSort = useCallback(
@ -162,16 +300,16 @@ export const TableStateProvider = ({ children }) => {
writeSortToSession(scope, nextSorter) writeSortToSession(scope, nextSorter)
} }
if (saveSortInUrl) { if (saveSortInUrl) {
const next = new URLSearchParams(searchParams) updateSearchParams((next) => {
if (nextSorter.field && nextSorter.order) { if (nextSorter.field && nextSorter.order) {
next.set(SORT_URL_PARAM, JSON.stringify(nextSorter)) next.set(SORT_URL_PARAM, JSON.stringify(nextSorter))
} else { } else {
next.delete(SORT_URL_PARAM) next.delete(SORT_URL_PARAM)
} }
setSearchParams(next, { replace: true }) })
} }
}, },
[searchParams, setSearchParams] [updateSearchParams]
) )
const persistTableState = useCallback( const persistTableState = useCallback(
@ -197,7 +335,7 @@ export const TableStateProvider = ({ children }) => {
} }
if (saveFilterInUrl || saveSortInUrl) { if (saveFilterInUrl || saveSortInUrl) {
const next = new URLSearchParams(searchParams) updateSearchParams((next) => {
if (saveFilterInUrl) { if (saveFilterInUrl) {
if (Object.keys(active).length > 0) { if (Object.keys(active).length > 0) {
next.set(FILTER_URL_PARAM, JSON.stringify(active)) next.set(FILTER_URL_PARAM, JSON.stringify(active))
@ -212,10 +350,10 @@ export const TableStateProvider = ({ children }) => {
next.delete(SORT_URL_PARAM) next.delete(SORT_URL_PARAM)
} }
} }
setSearchParams(next, { replace: true }) })
} }
}, },
[searchParams, setSearchParams] [updateSearchParams]
) )
const setPageFilter = useCallback((path, filter) => { const setPageFilter = useCallback((path, filter) => {
@ -245,39 +383,157 @@ export const TableStateProvider = ({ children }) => {
}) })
}, []) }, [])
const setObjectListFilter = useCallback((objectType, filter) => {
if (!objectType) return
const active = getActiveFilterValues(filter)
writeListFilterToSession(objectType, active)
setObjectListFilters((prev) => {
const hasActive = Object.keys(active).length > 0
if (!hasActive) {
if (!(objectType in prev)) return prev
const next = { ...prev }
delete next[objectType]
return next
}
return { ...prev, [objectType]: active }
})
}, [])
const setObjectListSorter = useCallback((objectType, sorter) => {
if (!objectType) return
const nextSorter = normalizeSorter(sorter)
writeListSortToSession(objectType, nextSorter)
setObjectListSorters((prev) => {
const hasSort = nextSorter?.field && nextSorter?.order
if (!hasSort) {
if (!(objectType in prev)) return prev
const next = { ...prev }
delete next[objectType]
return next
}
return { ...prev, [objectType]: nextSorter }
})
}, [])
const setObjectListView = useCallback((objectType, view) => {
if (!objectType) return
const nextView =
view?.id != null
? { id: String(view.id), name: view.name || null }
: null
writeListViewToSession(objectType, nextView)
setObjectListViews((prev) => {
if (!nextView) {
if (!(objectType in prev)) return prev
const next = { ...prev }
delete next[objectType]
return next
}
const existing = prev[objectType]
if (
existing &&
existing.id === nextView.id &&
existing.name === nextView.name
) {
return prev
}
return { ...prev, [objectType]: nextView }
})
}, [])
const getObjectListFilter = useCallback(
(objectType) => {
if (!objectType) return {}
if (objectListFilters[objectType]) {
return objectListFilters[objectType]
}
return getActiveFilterValues(readListFilterFromSession(objectType) || {})
},
[objectListFilters]
)
const getObjectListSorter = useCallback(
(objectType) => {
if (!objectType) return {}
if (objectListSorters[objectType]) {
return objectListSorters[objectType]
}
return readListSortFromSession(objectType) || {}
},
[objectListSorters]
)
const getObjectListView = useCallback(
(objectType) => {
if (!objectType) return null
if (objectListViews[objectType]) {
return objectListViews[objectType]
}
return readListViewFromSession(objectType)
},
[objectListViews]
)
const hasPageFilter = useCallback( const hasPageFilter = useCallback(
(path) => Object.keys(pageFilters[path] || {}).length > 0, (path) => Object.keys(pageFilters[path] || {}).length > 0,
[pageFilters] [pageFilters]
) )
const hasStoredFilter = useCallback((scope) => hasStoredSessionFilter(scope), []) const hasStoredFilter = useCallback((scope) => {
if (!scope) return false
if (hasStoredSessionFilter(scope)) return true
if (Object.keys(objectListFilters[scope] || {}).length > 0) return true
return Object.keys(getActiveFilterValues(readListFilterFromSession(scope) || {})).length > 0
}, [objectListFilters])
const value = useMemo( const value = useMemo(
() => ({ () => ({
getPersistedFilter, getPersistedFilter,
getPersistedSorter, getPersistedSorter,
getViewFromUrl,
persistView,
persistFilter, persistFilter,
persistSort, persistSort,
persistTableState, persistTableState,
setPageFilter, setPageFilter,
setPageSorter, setPageSorter,
setObjectListFilter,
setObjectListSorter,
setObjectListView,
getObjectListFilter,
getObjectListSorter,
getObjectListView,
hasPageFilter, hasPageFilter,
hasStoredFilter, hasStoredFilter,
pageFilters, pageFilters,
pageSorters pageSorters,
objectListFilters,
objectListSorters,
objectListViews
}), }),
[ [
getPersistedFilter, getPersistedFilter,
getPersistedSorter, getPersistedSorter,
getViewFromUrl,
persistView,
persistFilter, persistFilter,
persistSort, persistSort,
persistTableState, persistTableState,
setPageFilter, setPageFilter,
setPageSorter, setPageSorter,
setObjectListFilter,
setObjectListSorter,
setObjectListView,
getObjectListFilter,
getObjectListSorter,
getObjectListView,
hasPageFilter, hasPageFilter,
hasStoredFilter, hasStoredFilter,
pageFilters, pageFilters,
pageSorters pageSorters,
objectListFilters,
objectListSorters,
objectListViews
] ]
) )
@ -300,6 +556,7 @@ export const useTableState = () => {
// eslint-disable-next-line react-refresh/only-export-components // eslint-disable-next-line react-refresh/only-export-components
export const useTableStatePersistence = ({ export const useTableStatePersistence = ({
scope, scope,
viewId = null,
pagePath, pagePath,
saveFilterInSession = false, saveFilterInSession = false,
saveFilterInUrl = false, saveFilterInUrl = false,
@ -317,15 +574,58 @@ export const useTableStatePersistence = ({
persistSort: persistSortCtx, persistSort: persistSortCtx,
persistTableState: persistTableStateCtx, persistTableState: persistTableStateCtx,
setPageFilter, setPageFilter,
setPageSorter setPageSorter,
setObjectListFilter,
setObjectListSorter
} = useTableState() } = useTableState()
// View filter/sort belong to the view object — never read/write them via
// the shared filter/sort URL or session keys used by the "All" tab.
const isViewScope = Boolean(viewId)
const readOptions = useMemo( const readOptions = useMemo(
() => ({ useFilterInUrl, useFilterInSession, useSortInUrl, useSortInSession }), () => ({
[useFilterInUrl, useFilterInSession, useSortInUrl, useSortInSession] useFilterInUrl: isViewScope ? false : useFilterInUrl,
useFilterInSession: isViewScope ? false : useFilterInSession,
useSortInUrl: isViewScope ? false : useSortInUrl,
useSortInSession: isViewScope ? false : useSortInSession
}),
[
isViewScope,
useFilterInUrl,
useFilterInSession,
useSortInUrl,
useSortInSession
]
) )
const saveOptions = useMemo( const saveOptions = useMemo(
() => ({
saveFilterInSession: isViewScope ? false : saveFilterInSession,
saveFilterInUrl: isViewScope ? false : saveFilterInUrl,
saveSortInSession: isViewScope ? false : saveSortInSession,
saveSortInUrl: isViewScope ? false : saveSortInUrl
}),
[
isViewScope,
saveFilterInSession,
saveFilterInUrl,
saveSortInSession,
saveSortInUrl
]
)
const allTabReadOptions = useMemo(
() => ({
useFilterInUrl,
useFilterInSession,
useSortInUrl,
useSortInSession
}),
[useFilterInUrl, useFilterInSession, useSortInUrl, useSortInSession]
)
const allTabSaveOptions = useMemo(
() => ({ () => ({
saveFilterInSession, saveFilterInSession,
saveFilterInUrl, saveFilterInUrl,
@ -345,6 +645,18 @@ export const useTableStatePersistence = ({
[getPersistedSorterCtx, scope, readOptions] [getPersistedSorterCtx, scope, readOptions]
) )
// Always reads the All-tab filter/sort, even while a view is still selected
// (used when switching back to All before listViewId has cleared).
const getAllTabPersistedFilter = useCallback(
() => getPersistedFilterCtx(scope, allTabReadOptions),
[getPersistedFilterCtx, scope, allTabReadOptions]
)
const getAllTabPersistedSorter = useCallback(
() => getPersistedSorterCtx(scope, allTabReadOptions),
[getPersistedSorterCtx, scope, allTabReadOptions]
)
const persistFilter = useCallback( const persistFilter = useCallback(
(filterState) => persistFilterCtx(scope, filterState, saveOptions), (filterState) => persistFilterCtx(scope, filterState, saveOptions),
[persistFilterCtx, scope, saveOptions] [persistFilterCtx, scope, saveOptions]
@ -361,6 +673,12 @@ export const useTableStatePersistence = ({
[persistTableStateCtx, scope, saveOptions] [persistTableStateCtx, scope, saveOptions]
) )
const persistAllTabTableState = useCallback(
(filterState, sorter) =>
persistTableStateCtx(scope, filterState, sorter, allTabSaveOptions),
[persistTableStateCtx, scope, allTabSaveOptions]
)
const registerPageFilter = useCallback( const registerPageFilter = useCallback(
(filterState) => { (filterState) => {
if (pagePath) { if (pagePath) {
@ -379,14 +697,38 @@ export const useTableStatePersistence = ({
[pagePath, setPageSorter] [pagePath, setPageSorter]
) )
const registerObjectListFilter = useCallback(
(filterState) => {
if (scope) {
setObjectListFilter(scope, filterState)
}
},
[scope, setObjectListFilter]
)
const registerObjectListSorter = useCallback(
(sorter) => {
if (scope) {
setObjectListSorter(scope, sorter)
}
},
[scope, setObjectListSorter]
)
return { return {
persistenceScope: scope,
getPersistedFilter, getPersistedFilter,
getPersistedSorter, getPersistedSorter,
getAllTabPersistedFilter,
getAllTabPersistedSorter,
persistFilter, persistFilter,
persistSort, persistSort,
persistTableState, persistTableState,
persistAllTabTableState,
registerPageFilter, registerPageFilter,
registerPageSorter, registerPageSorter,
registerObjectListFilter,
registerObjectListSorter,
getActiveFilterValues getActiveFilterValues
} }
} }

View File

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

View File

@ -1,14 +1,21 @@
import { useCallback, useContext } from 'react' import { useCallback, useContext } from 'react'
import { ApiServerContext } from '../context/ApiServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import {
DEFAULT_VIEW_MODE,
normalizeViewMode
} from '../common/viewModeUtils'
const useViewMode = (componentName, defaultMode = 'list') => { const useViewMode = (componentName, defaultMode = DEFAULT_VIEW_MODE) => {
const { userSettings, updateUserSettings } = useContext(ApiServerContext) const { userSettings, updateUserSettings } = useContext(ApiServerContext)
const viewMode = userSettings.viewMode[componentName] ?? defaultMode const viewMode = normalizeViewMode(
userSettings.viewMode[componentName] ?? defaultMode
)
const setViewMode = useCallback( const setViewMode = useCallback(
(nextMode) => { (nextMode) => {
const mode = const mode = normalizeViewMode(
typeof nextMode === 'function' ? nextMode(viewMode) : nextMode typeof nextMode === 'function' ? nextMode(viewMode) : nextMode
)
updateUserSettings('viewMode', componentName, mode) updateUserSettings('viewMode', componentName, mode)
}, },
[componentName, updateUserSettings, viewMode] [componentName, updateUserSettings, viewMode]

View File

@ -0,0 +1,6 @@
import Icon from '@ant-design/icons'
import CustomIconSvg from '../../../assets/icons/kanbanicon.svg?react'
const KanbanIcon = (props) => <Icon component={CustomIconSvg} {...props} />
export default KanbanIcon

View File

@ -0,0 +1,6 @@
import Icon from '@ant-design/icons'
import CustomIconSvg from '../../../assets/icons/loadingicon.svg?react'
const LoadingIcon = (props) => <Icon component={CustomIconSvg} {...props} />
export default LoadingIcon

View File

@ -194,7 +194,7 @@ export function getModelByName(name, ignoreCase = false) {
export function getModelByPluralName(pluralName, ignoreCase = false) { export function getModelByPluralName(pluralName, ignoreCase = false) {
function formatName(formattedName) { function formatName(formattedName) {
if (ignoreCase == true) { if (ignoreCase == true) {
formattedName = formattedName.toUpperCase().replace(' ', '') formattedName = formattedName.toUpperCase().replaceAll(' ', '')
} }
return formattedName return formattedName
} }

View File

@ -110,7 +110,7 @@ export const DocumentPrinter = {
], ],
sorters: [ sorters: [
'name', 'name',
'documentSize', 'currentDocumentSize',
'connectedAt', 'connectedAt',
'connection.port', 'connection.port',
'updatedAt', 'updatedAt',
@ -261,15 +261,47 @@ export const DocumentPrinter = {
}, },
columnWidth: 85 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', name: 'currentDocumentSize',
label: 'Document Size', label: 'Current Document Size',
required: false, required: false,
type: 'object', type: 'object',
objectType: 'documentSize', objectType: 'documentSize',
showHyperlink: true, showHyperlink: true,
columnWidth: 200 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', name: 'tags',
label: 'Tags', label: 'Tags',