feat: implement persistent AG Grid column state
This commit is contained in:
@@ -16,4 +16,7 @@ export const fullPageStore = create<FullPageStoreState>((set) => ({
|
||||
|
||||
privileges: [],
|
||||
setPrivileges: (privileges) => set({ privileges }),
|
||||
|
||||
tableConfig: null,
|
||||
setTableConfig: (config) => set({ tableConfig: config }),
|
||||
}));
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
MenuItemDef,
|
||||
DefaultMenuItem,
|
||||
StatusBar,
|
||||
ColumnMovedEvent,
|
||||
ColumnResizedEvent,
|
||||
ColumnVisibleEvent,
|
||||
SortChangedEvent,
|
||||
} from 'ag-grid-community';
|
||||
import { Box, Group, TextInput, Indicator, CloseButton } from '@mantine/core';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
@@ -181,6 +185,12 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
|
||||
searchKey = 'search',
|
||||
filterConfig,
|
||||
|
||||
// Grid config props
|
||||
onColumnMoved,
|
||||
onColumnResized,
|
||||
onColumnVisible,
|
||||
onSortChanged,
|
||||
|
||||
// Bulk action props
|
||||
customBulkActions,
|
||||
batchSize,
|
||||
@@ -200,8 +210,16 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
|
||||
// ---------------------------------------------------------------------------
|
||||
const { t } = useEnterpriseModuleTranslationContext();
|
||||
const { dataServices } = useEnterpriseModuleDataServiceContext<E>();
|
||||
const { selectedRows, setSelectedRows, metaData, setMetaData, filterData, setFilterData } =
|
||||
useEnterpriseModuleSelectionContext<E>();
|
||||
const {
|
||||
selectedRows,
|
||||
setSelectedRows,
|
||||
metaData,
|
||||
setMetaData,
|
||||
filterData,
|
||||
setFilterData,
|
||||
tableConfig,
|
||||
setTableConfig,
|
||||
} = useEnterpriseModuleSelectionContext<E>();
|
||||
const navigation = useEnterpriseModuleNavigationContext();
|
||||
|
||||
const { config } = useEnterpriseModuleConfigContext();
|
||||
@@ -791,6 +809,11 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
|
||||
setSelectedRows([]);
|
||||
|
||||
if (params.api) {
|
||||
// Restore grid configuration on mount
|
||||
if (tableConfig) {
|
||||
params.api.applyColumnState({ state: tableConfig, applyOrder: true });
|
||||
}
|
||||
|
||||
// Attach the server-side datasource to the grid API
|
||||
params.api.setGridOption('serverSideDatasource', datasource);
|
||||
|
||||
@@ -803,7 +826,7 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
|
||||
}
|
||||
}
|
||||
},
|
||||
[datasource, setSelectedRows, isPaginated, metaData],
|
||||
[datasource, setSelectedRows, isPaginated, metaData, tableConfig],
|
||||
);
|
||||
|
||||
// Triggered whenever the row selection in the grid changes
|
||||
@@ -817,6 +840,50 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
|
||||
[setSelectedRows],
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Save Grid Configuration State Handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
const saveGridState = useCallback(() => {
|
||||
if (!gridApiRef.current || !setTableConfig) return;
|
||||
const state = gridApiRef.current.getColumnState();
|
||||
setTableConfig(state);
|
||||
}, [setTableConfig]);
|
||||
|
||||
const handleColumnMoved = useCallback(
|
||||
(e: ColumnMovedEvent<E>) => {
|
||||
saveGridState();
|
||||
if (onColumnMoved) onColumnMoved(e);
|
||||
},
|
||||
[saveGridState, onColumnMoved],
|
||||
);
|
||||
|
||||
const handleColumnResized = useCallback(
|
||||
(e: ColumnResizedEvent<E>) => {
|
||||
// Only save when resizing is finished to prevent excessive re-renders
|
||||
if (e.finished) {
|
||||
saveGridState();
|
||||
}
|
||||
if (onColumnResized) onColumnResized(e);
|
||||
},
|
||||
[saveGridState, onColumnResized],
|
||||
);
|
||||
|
||||
const handleColumnVisible = useCallback(
|
||||
(e: ColumnVisibleEvent<E>) => {
|
||||
saveGridState();
|
||||
if (onColumnVisible) onColumnVisible(e);
|
||||
},
|
||||
[saveGridState, onColumnVisible],
|
||||
);
|
||||
|
||||
const handleSortChanged = useCallback(
|
||||
(e: SortChangedEvent<E>) => {
|
||||
saveGridState();
|
||||
if (onSortChanged) onSortChanged(e);
|
||||
},
|
||||
[saveGridState, onSortChanged],
|
||||
);
|
||||
|
||||
// Configures the context menu items available when right-clicking a cell
|
||||
const getContextMenuItems = useCallback(():
|
||||
| (DefaultMenuItem | MenuItemDef)[]
|
||||
@@ -923,6 +990,10 @@ export function EnterpriseDataTable<E extends BaseEntity>(props: EnterpriseDataT
|
||||
enableCellTextSelection={true}
|
||||
onSelectionChanged={handleSelectionChanged}
|
||||
onGridReady={onGridReady}
|
||||
onColumnMoved={handleColumnMoved}
|
||||
onColumnResized={handleColumnResized}
|
||||
onColumnVisible={handleColumnVisible}
|
||||
onSortChanged={handleSortChanged}
|
||||
getContextMenuItems={getContextMenuItems}
|
||||
statusBar={statusBar}
|
||||
domLayout={domLayout}
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { ZodType } from 'zod';
|
||||
import type { BaseEntity, BaseRemoteDataServices, StandardPaginationMeta } from '@repo/core-api/data-services';
|
||||
import type { ModulePageHeaderProps } from '../components/module-page-header';
|
||||
import { PageActionsProps } from '../../../components';
|
||||
import { ColumnState } from 'ag-grid-community';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Module Constants & Base Types
|
||||
@@ -140,6 +141,8 @@ export interface SelectionSlice<
|
||||
setMetaData: (data: TMeta | null) => void;
|
||||
filterData: TFilter | null;
|
||||
setFilterData: (data: TFilter | null) => void;
|
||||
tableConfig: ColumnState[] | null;
|
||||
setTableConfig: (config: ColumnState[] | null) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,6 +159,8 @@ export interface EnterpriseModuleState<
|
||||
setFilterData: (data: TFilter | null) => void;
|
||||
selectedRows: E[];
|
||||
setSelectedRows: (rows: E[]) => void;
|
||||
tableConfig: ColumnState[] | null;
|
||||
setTableConfig: (config: ColumnState[] | null) => void;
|
||||
privileges: string[];
|
||||
setPrivileges: (privileges: string[]) => void;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,8 @@ export function EnterpriseModuleProvider<
|
||||
const setMetaData = store((state: S) => state.setMetaData);
|
||||
const filterData = store((state: S) => state.filterData);
|
||||
const setFilterData = store((state: S) => state.setFilterData);
|
||||
const tableConfig = store((state: S) => state.tableConfig);
|
||||
const setTableConfig = store((state: S) => state.setTableConfig);
|
||||
|
||||
const selectionSlice = useMemo(
|
||||
() => ({
|
||||
@@ -91,8 +93,10 @@ export function EnterpriseModuleProvider<
|
||||
setMetaData,
|
||||
filterData,
|
||||
setFilterData,
|
||||
tableConfig,
|
||||
setTableConfig,
|
||||
}),
|
||||
[selectedRows, setSelectedRows, metaData, setMetaData, filterData, setFilterData],
|
||||
[selectedRows, setSelectedRows, metaData, setMetaData, filterData, setFilterData, tableConfig, setTableConfig],
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user