# ClientVirtualTable V3 Guide This guide documents the table components in `components/client-table-v2`, with an emphasis on server fetching (`fetchMode="server"`) and how supporting components fit together. ## Module Map - `client-virtual-table.tsx`: Core table (virtualized, DnD columns, pin/hide, presets hook point, toolbar, pagination). - `client-table-column-header.tsx`: Header cell with sort toggle, filter UI, context menu (hide/pin/group/reorder hook). - `client-table-toolbar.tsx` (from `components/client-table`): Search box, export button, view options, preset entry point. - `client-table-view-options.tsx` (from `components/client-table`): Column visibility toggles. - `client-table-filter.tsx`: Column filter UI (text/select/boolean). - `client-table-preset.tsx`: Save/load/delete presets per `tableKey` + user. - `client-table-save-view.tsx`, `client-table-preset.tsx`, `client-table-toolbar.tsx`: Preset and view controls. - `client-virtual-table` dependencies: `ClientDataTablePagination` (`components/client-data-table`), `export-utils`, `import-utils`. - Server helpers: `adapter/create-table-service.ts`, `adapter/drizzle-table-adapter.ts`. - Types: `types.ts`, `preset-types.ts`. ## Core Behaviors (ClientVirtualTable) - Virtualization: `height` is required; `estimateRowHeight` defaults to 40. - Drag & Drop: Columns reorder across pin sections; drag between pin states updates pinning. - Pin/Hide/Reorder: Managed client-side; state is exposed via `columnVisibility`, `columnPinning`, `columnOrder`. - Sorting/Filtering/Pagination/Grouping: - `fetchMode="client"`: uses TanStack models (`getSortedRowModel`, `getFilteredRowModel`, `getPaginationRowModel`, etc.). - `fetchMode="server"`: sets manual flags true and skips client models; **server must return already-sorted/filtered/paged data**. - Export: Uses current row model; in server mode it exports only the loaded rows unless you supply all data yourself via `onExport`. - Presets: When `enableUserPreset` and `tableKey` are set, toolbar shows the preset control; loading a preset resets pageIndex to 0 to avoid invalid pages on server mode. ## Key Props (ClientVirtualTable) - `fetchMode`: `"client"` | `"server"` (default `"client"`). - Data: `data`, `rowCount?`, `pageCount?`. - State + handlers (controlled or uncontrolled): - Pagination: `pagination`, `onPaginationChange`, `enablePagination`, `manualPagination?`. - Sorting: `sorting`, `onSortingChange`. - Filters: `columnFilters`, `onColumnFiltersChange`, `globalFilter`, `onGlobalFilterChange`. - Grouping: `grouping`, `onGroupingChange`, `expanded`, `onExpandedChange`, `enableGrouping`. - Visibility/Pinning/Order: `columnVisibility`, `onColumnVisibilityChange`, `columnPinning`, `onColumnPinningChange`, `columnOrder`, `onColumnOrderChange`. - Selection: `enableRowSelection`, `enableMultiRowSelection`, `rowSelection`, `onRowSelectionChange`. - UX: `actions`, `customToolbar`, `enableExport`, `onExport`, `renderHeaderVisualFeedback`, `getRowClassName`, `onRowClick`. - Presets: `enableUserPreset`, `tableKey`. - Meta: `meta`, `getRowId`. ## Server Fetching Patterns ### Pattern 1: Client-Side (baseline) - `fetchMode="client"`, pass full dataset; TanStack handles sorting/filtering/grouping locally. ### Pattern 2: Factory Service (`createTableService`) - Server action: `createTableService({ db, schema, columns, defaultWhere?, customQuery? })`. - The adapter maps `sorting`, `columnFilters`, `globalFilter`, `pagination`, `grouping` → Drizzle `where`, `orderBy`, `limit`, `offset`, `groupBy`. - Returns `{ data, totalRows, pageCount }`; always forward `totalRows` to the client and wire `rowCount`. - Client wiring: control `pagination`, `sorting`, `columnFilters`, `globalFilter`; refetch in `useEffect` on those deps. ### Pattern 2-B: Server Grouping - Uses `getProductTableDataWithGrouping` sample: if `grouping` is empty → normal server fetch; else returns `{ groups }` built from DB `GROUP BY`. - Columns must be marked `meta.serverGroupable` in server column defs. - Expanded groups fetch child rows per group key; grouping change clears expanded state. - UI may render a custom grouped view (not the virtual table) when grouped. ### Pattern 3: Custom Service - For joins/derived columns: read `tableState` and manually map `sorting` IDs to joined columns; supply a default order when no sort is present. - Filtering/global filter are not automatic—implement them if needed. - Grouping is manual; see `getOrderTableDataGroupedByStatus` pattern for a grouped response shape. ## State → Query Mapping (Server) - Sorting: `tableState.sorting` (id, desc) → map to DB columns; ignore unknown ids. - Filters: `columnFilters` supports text (ilike), boolean, number, range `[min,max]`, multi-select (IN). - Global filter: ilike OR across mapped columns. - Pagination: pageIndex/pageSize → limit/offset; return `rowCount`. - Grouping: `grouping` → `GROUP BY` for supported columns only. ## Presets (Server-Friendly) - Saved keys: sorting, columnFilters, globalFilter, columnVisibility, columnPinning, columnOrder, grouping, pageSize. - On load: applies `table.set*` and resets pageIndex to 0; parent `on*Change` handlers should trigger refetch. - Use unique `tableKey` per screen to avoid collisions; requires authenticated session. ## Feature Matrix (Server Mode) - Sorting: Yes—server implemented. - Filtering: Yes—server implemented. - Pagination: Yes—manual; provide `rowCount`. - Grouping: Not automatic; implement via server grouping or custom grouped view. - Column hide/pin/reorder: Client-only (visual); does not change server query unless you opt to read it. - Export: Only current rows unless you provide `onExport` with full data. ## Implementation Tips - Always set `rowCount` when `fetchMode="server"`. - Refetch on `pagination`, `sorting`, `columnFilters`, `globalFilter`, and `grouping` (if used). - Provide a default sort on the server when `sorting` is empty. - Reset `expanded` or group expand state when grouping changes in server grouping flows. - Ensure `height` is set; virtualization needs a scroll container. ## Quick Examples - Client: `fetchMode="client"` with `data` = full list; optional grouping enabled. - Factory server: `fetchMode="server"`, `createTableService` action, controlled state with `rowCount`. - Server grouping: `grouping` drives `{ groups }` vs `{ data }` response; only `serverGroupable` columns allowed. - Custom join: Manually map `sorting` ids; apply filters/global; return `rowCount`.