tenantpilot/lib/hooks/usePolicyTable.ts
Ahmed Darrazi 41e80b6c0c
All checks were successful
Trigger Cloudarix Deploy / call-webhook (push) Successful in 2s
feat(policy-explorer-v2): implement MVP Phase 1-3
 New Features
- Advanced data table with TanStack Table v8 + Server Actions
- Server-side pagination (10/25/50/100 rows per page)
- Multi-column sorting with visual indicators
- Column management (show/hide, resize) persisted to localStorage
- URL state synchronization for shareable filtered views
- Sticky header with compact/comfortable density modes

📦 Components Added
- PolicyTableV2.tsx - Main table with TanStack integration
- PolicyTableColumns.tsx - 7 column definitions with sorting
- PolicyTablePagination.tsx - Pagination controls
- PolicyTableToolbar.tsx - Density toggle + column visibility menu
- ColumnVisibilityMenu.tsx - Show/hide columns dropdown

🔧 Hooks Added
- usePolicyTable.ts - TanStack Table initialization
- useURLState.ts - URL query param sync with nuqs
- useTablePreferences.ts - localStorage persistence

🎨 Server Actions Updated
- getPolicySettingsV2 - Pagination + sorting + filtering + Zod validation
- exportPolicySettingsCSV - Server-side CSV generation (max 5000 rows)

📚 Documentation Added
- Intune Migration Guide (1400+ lines) - Reverse engineering strategy
- Intune Reference Version tracking
- Tasks completed: 22/62 (Phase 1-3)

 Zero TypeScript compilation errors
 All MVP success criteria met (pagination, sorting, column management)
 Ready for Phase 4-7 (filtering, export, detail view, polish)

Refs: specs/004-policy-explorer-v2/tasks.md
2025-12-10 00:18:05 +01:00

110 lines
3.0 KiB
TypeScript

/**
* usePolicyTable Hook
*
* Initializes TanStack Table with manual pagination mode for server-side data fetching.
* Integrates with URL state and localStorage preferences.
*
* Key Features:
* - Manual pagination (data fetched via Server Actions)
* - Column visibility persistence
* - Column sizing with drag resize
* - Row selection for CSV export
* - Sorting with URL sync
*/
import { useEffect, useMemo, useState } from 'react';
import {
getCoreRowModel,
useReactTable,
type ColumnDef,
type SortingState,
type VisibilityState,
type ColumnSizingState,
type RowSelectionState,
type PaginationState,
} from '@tanstack/react-table';
import type { PolicySettingRow, PaginationMeta } from '@/lib/types/policy-table';
interface UsePolicyTableProps {
data: PolicySettingRow[];
columns: ColumnDef<PolicySettingRow>[];
pagination: PaginationState;
onPaginationChange: (updater: PaginationState | ((old: PaginationState) => PaginationState)) => void;
sorting: SortingState;
onSortingChange: (updater: SortingState | ((old: SortingState) => SortingState)) => void;
columnVisibility?: VisibilityState;
onColumnVisibilityChange?: (updater: VisibilityState | ((old: VisibilityState) => VisibilityState)) => void;
columnSizing?: ColumnSizingState;
onColumnSizingChange?: (updater: ColumnSizingState | ((old: ColumnSizingState) => ColumnSizingState)) => void;
meta?: PaginationMeta;
enableRowSelection?: boolean;
}
export function usePolicyTable({
data,
columns,
pagination,
onPaginationChange,
sorting,
onSortingChange,
columnVisibility = {},
onColumnVisibilityChange,
columnSizing = {},
onColumnSizingChange,
meta,
enableRowSelection = false,
}: UsePolicyTableProps) {
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
// Reset row selection when page changes
useEffect(() => {
setRowSelection({});
}, [pagination.pageIndex]);
// Initialize TanStack Table
const table = useReactTable({
data,
columns,
pageCount: meta?.pageCount ?? -1,
state: {
pagination,
sorting,
columnVisibility,
columnSizing,
rowSelection,
},
onPaginationChange,
onSortingChange,
onColumnVisibilityChange,
onColumnSizingChange,
onRowSelectionChange: setRowSelection,
getCoreRowModel: getCoreRowModel(),
manualPagination: true, // Server-side pagination
manualSorting: true, // Server-side sorting
manualFiltering: true, // Server-side filtering
enableRowSelection,
enableColumnResizing: true,
columnResizeMode: 'onChange',
});
// Get selected rows
const selectedRows = useMemo(() => {
return table.getSelectedRowModel().rows.map(row => row.original);
}, [table, rowSelection]);
// Selection helpers
const selectedCount = selectedRows.length;
const totalCount = meta?.totalCount ?? 0;
const hasSelection = selectedCount > 0;
const allRowsSelected = table.getIsAllPageRowsSelected();
return {
table,
selectedRows,
selectedCount,
totalCount,
hasSelection,
allRowsSelected,
};
}