Technical docs
DataTable System
Purpose
- Shared table framework (TanStack Table v8) used across staff, invites, variables, MCPs, workflows, and other admin surfaces. Provides filtering UI, persisted user preferences, mobile-aware actions, and toolbar utilities.
Key Components
- `DataTable` + context providers under `context/`: wires column defs, selection, pagination, persistence, drag-select, and export helpers.
- `FilterPanel`: unified “Filters” popover with column filters plus optional custom filters slot (for example date range, roles, workflows). Shows an active badge and a footer `Clear filters`.
- `DateRangeFilter`: preset selector (`all`, `today`, `week`, `month`, `quarter`) for use in the `FilterPanel` header.
- `ActiveFilterChips`: animated chips that mirror active filters outside the popover; auto-compresses to icons/hides when space is tight; clicking a chip removes that filter.
- `Pagination`, `BulkActions`, `ColumnHeader`, `ViewOptions`, and `Skeleton` utilities are exported for feature pages.
- `ViewOptions` supports searchable column visibility, drag reorder, page-size changes, reset-to-defaults, CSV export, JSON export, and print when those capabilities are configured.
- `ActionsCell` provides a shared row-actions pattern:
- desktop: inline icon buttons
- mobile: a single direct action button when only one action is available, otherwise an ellipsis dropdown menu
Persistence (localStorage)
- Keys are namespaced per tableId. Stored pieces:
- Desktop column visibility, mobile column visibility, order, sorting.
- Page size.
- Collapsed group rows.
- Column filters (multi-select values).
- Custom filters (feature-defined objects such as date range, roles, or workflows).
- Columns version hash (`generateColumnsVersion`) auto-invalidates stored prefs when the set of columns changes.
- Helpers: `load*`/`save*`/`clearColumnFilters`/`loadCustomFilters` in `persistence.ts`. New tables should call `validateAndClearIfNeeded(tableId, columnsVersion)` on init.
- `validateAndClearIfNeeded` currently clears stale visibility, column order, sorting, and collapsed-group state when the columns version changes. It does not clear page size, column filters, or custom filters.
Filtering Behavior
- Column filter options are passed via `ExtendedFilterConfig` with `id`, `label`, `options`, and an optional `shouldRender` gate.
- Options can include counts and can be disabled. Zero-count options stay visible but cannot be selected when the feature marks them disabled.
- A filter can initially show a limited number of options and expose `Show all` to reveal the rest.
- Filter configurations and active chips can carry an optional scope so repeated value names from different feature scopes remain distinguishable.
- `FilterPanel` toggles values per column and counts active selections for the badge.
- `DataTable` accepts initial column filters. These defaults are used only when no persisted filter state exists; for example, active Staff initially selects both `Active` and `Paused`.
- Additional filters (children slot) supply their own state and “active count”; `onClearAdditional` is used by the footer clear button.
- The active badge counts individual selected values plus any additional-filter count supplied by the feature page.
- Chips outside the popover are driven by `activeChips` props so feature pages can surface non-column filters consistently.
- Cells can declare interactive content and a separate navigation label. Their buttons, badges, and hover-card triggers remain outside the row navigation link so operating the control does not open the row.
Date/Time and Chips UX
- `DateRangeFilter` is label-configurable (defaults to “Added”) and uses small `Select` UI; no calendar picker yet—preset only.
- Chips support color coding (`CHIP_COLOR_CLASSES`) for type, status, role, workflow, and date range and truncate text dynamically.
Scrolling and print behavior
- Populated shared DataTables use one `SystemScrollArea` for horizontal and vertical overflow. Custom horizontal and vertical scrollbar tracks appear only when that axis can scroll.
- The viewport is keyboard-focusable and exposed to assistive technology as a `Scrollable table` region.
- Horizontal overscroll is contained inside the table so wide content does not make the document itself wider on desktop, tablet, or mobile.
- Vertical wheel input can continue into an ancestor or page scroller when the table reaches its vertical boundary. Diagonal wheel input can move the table horizontally and the ancestor vertically when both can consume movement.
- Plain shared `Table` consumers remain horizontal-only unless they explicitly request both axes.
- In print media, DataTable overflow is released, sticky table-header positioning is removed, and interactive scrollbar chrome is hidden so table content can flow across pages.
Integration Notes
- Provide a stable `tableId` per route + view to avoid cross-page collisions.
- When adding/removing columns, update the columns version fed to `validateAndClearIfNeeded` to clear stale visibility/order/filter state.
- Persisted filters/visibility are read on the client; SSR paths should guard usage (`typeof window` checks exist in helpers).
- Server-pagination mode is enabled when `rowCount` and controlled pagination callbacks are provided; otherwise the table uses local pagination.
- Header search is debounced and passed through a deferred value before filtering.
- Footer controls render only when pagination is meaningful or there are selected rows.