Skip to content

feat: upgrade TanStack Table to v9 with faster rendering and multi-range cell selection - #1920

Open
paustint wants to merge 1 commit into
mainfrom
chore/upgrade-tanstack-table
Open

feat: upgrade TanStack Table to v9 with faster rendering and multi-range cell selection#1920
paustint wants to merge 1 commit into
mainfrom
chore/upgrade-tanstack-table

Conversation

@paustint

@paustint paustint commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Upgrade @tanstack/react-table 8.21.3 → 9.x (pinned ^9.0.0; 9.1.x blocked by the 3-day minimumReleaseAge gate until ~Aug 10). All TanStack usage is confined to the libs/ui grid, so feature code is untouched except where noted.

Core port

  • useReactTable → useTable with an explicit tableFeatures registry (grid-features.ts); unused features (pagination, pinning, faceting) are now tree-shaken out of the bundle
  • Central Tanstack* type aliases bake in the new TFeatures generic; module augmentation updated; RowData constraint contained via extends object
  • table.getState() → table.store.state; columnSizingInfo → columnResizing
  • Stable table facade: v9 returns a new wrapper per state change, so useJetstreamTable exposes a stable Proxy to preserve the "one table identity" contract for context memos and effects
  • GridRowHandle: variance-safe subset type for the tanstackRow escape hatch (v9 rows are invariant in their data generic)
  • Adopted v9 built-in shift-click row range selection (replaces hand-rolled selectRowRange); bare-checkbox tables gain shift-click; select-all indeterminate updated for v9's changed getIsSomeRowsSelected semantics

Fine-grained rendering (v9 store/atoms)

  • Column-resize drag re-renders only the dragged header's handle island
  • rowSelection/expanded moved to external atoms (dual controlled/internal mode preserved; consumer callbacks fire exactly once under StrictMode)
  • A selection toggle re-renders only the affected row + select-all island; GridHeader is memoized and skips re-renders during typing/navigation

Cell range selection (new)

  • Spreadsheet-style multi-range selection via v9 cellSelectionFeature: Ctrl/Cmd+click adds/subtracts rectangles, ranges survive sort/filter/reorder, Escape collapses, multi-range copy, Delete/revert across all ranges
  • All v9 selection API access confined to a grid-selection facade

Fixes found while testing

  • Preview Changes: Warnings/Error column copied blank (value lived on row.status); added copy context menu; empty cells copy blank (em-dash is now render-only); Status column copies its compact state
  • Error popovers restored to the strong red header (SLDS 2 Cosmos restyled the error variant to a pink container)
  • Frozen-column divider and header resize handle no longer clip focus/selection ring edges
  • Automation Control: SET filter popover was empty for tree tables (computeFilterSetValues now traverses getSubRows); Reset left flows marked dirty (activeVersionNumber is now restored); checkbox centered and toggles only on the checkbox itself
  • Deploy: group counts no longer include the "No metadata found" placeholder
  • Paste (and Delete-to-clear) implemented for boolean checkbox tables: permission manager (all four editors) and Automation Control's Active column, routed through the same handlers as checkbox clicks

Copilot AI lite review requested due to automatic review settings August 8, 2026 18:42
@socket-security

socket-security Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​tanstack/​react-store@​0.11.01001006989100
Added@​tanstack/​react-table@​9.0.010010010098100

View full report

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Upgrades Jetstream’s internal grid implementation from TanStack Table v8 to v9, introducing a feature-registry based setup, store/atom-driven fine-grained rendering, and new spreadsheet-style multi-range cell selection while keeping the external DataTable/DataTree APIs largely stable.

Changes:

  • Upgrade @tanstack/react-table to v9 and introduce a centralized jetstreamTableFeatures registry to control bundled features.
  • Refactor grid state management to leverage TanStack v9 store/atoms for finer-grained re-renders (selection/expanded/cellSelection, resize handle “islands”, memoized header).
  • Add multi-range (Ctrl/Cmd) cell selection + updated copy/paste/clear behavior and migrate row shift-range selection to v9’s built-in handler.

Reviewed changes

Copilot reviewed 49 out of 50 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pnpm-lock.yaml Locks TanStack v9 packages and new store dependencies.
package.json Upgrades @tanstack/react-table to ^9.0.0 and adds @tanstack/react-store.
libs/ui/src/lib/data-table/PreviewChangesModal.tsx Fixes copy/export behavior for status/error fields and empty display values; adds context menu copy.
libs/ui/src/lib/data-table/gridExport.ts Tightens generics (T extends object) for v9 type compatibility.
libs/ui/src/lib/data-table/grid/selection/grid-selection.ts Adds a facade around v9 cellSelectionFeature (bounds, spans, edges, active range).
libs/ui/src/lib/data-table/grid/renderers/CellRenderers.tsx Ensures error column copy returns status; routes row shift-range selection through v9 handler.
libs/ui/src/lib/data-table/grid/rdg-compat.ts Updates rdg-compat types to v9 generics and extends object constraints.
libs/ui/src/lib/data-table/grid/keyboard/useGridKeyboardNavigation.ts Implements multi-range cell selection, range copy behavior, and Escape collapse semantics.
libs/ui/src/lib/data-table/grid/grid-types.ts Introduces TanStack v9 type aliases + GridRowHandle variance-safe escape hatch and module augmentation updates.
libs/ui/src/lib/data-table/grid/grid-row-utils.ts Removes hand-rolled row range selection helper; updates types for v9.
libs/ui/src/lib/data-table/grid/grid-paste.ts Updates paste target computation types for v9 table/row/column aliases.
libs/ui/src/lib/data-table/grid/grid-filters.ts Extends SET filter value computation to traverse tree rows via getSubRows.
libs/ui/src/lib/data-table/grid/grid-features.ts Central v9 feature registration + row model factories + sortFns registry.
libs/ui/src/lib/data-table/grid/grid-context.tsx Updates runtime context to v9 table alias and adds row-model input selector utility.
libs/ui/src/lib/data-table/grid/grid-column-utils.tsx Tightens generic constraints for v9 row typing (T extends object).
libs/ui/src/lib/data-table/grid/filterFns.ts Ports filter functions to v9 aliases (TanstackFilterFn, TanstackRow).
libs/ui/src/lib/data-table/grid/editors/EditorHost.tsx Updates table typing for v9 (TanstackTable) and extends object generics.
libs/ui/src/lib/data-table/grid/editors/CellEditors.tsx Tightens editor generics (TRow extends object) and minor formatting.
libs/ui/src/lib/data-table/grid/DataTableV2.tsx Adds enableCellSelection prop plumbed into the v9 grid core.
libs/ui/src/lib/data-table/grid/data-table-grid.css Adds multi-range selection borders and adjusts frozen divider/resize handle focus clipping.
libs/ui/src/lib/data-table/grid/core/useJetstreamTable.ts Migrates to useTable + feature registry; moves selection/expanded/cellSelection into atoms; stable proxy facade.
libs/ui/src/lib/data-table/grid/components/HeaderCell.tsx Adds fine-grained subscriptions for sort state, select-all checkbox, and resize-handle drag island.
libs/ui/src/lib/data-table/grid/components/GridSummaryRow.tsx Updates to v9 column typing alias.
libs/ui/src/lib/data-table/grid/components/GridRow.tsx Subscribes per-row selection via atom; switches range highlighting to span/edge model.
libs/ui/src/lib/data-table/grid/components/GridHeader.tsx Memoizes header block and narrows active cell to sticky region to avoid re-renders on body navigation.
libs/ui/src/lib/data-table/grid/components/GridGroupRow.tsx Subscribes group rows to rowSelection atom for correct descendant selection visuals.
libs/ui/src/lib/data-table/grid/components/GridContainer.tsx Adds cell selection bounds plumbing, multi-range copy/paste/clear targeting, and row-model subscriptions.
libs/ui/src/lib/data-table/grid/components/GridCell.tsx Uses edge-bitmask range highlighting and forwards ctrl/meta state for multi-range selection.
libs/ui/src/lib/data-table/grid/components/GridBody.tsx Subscribes to row-model inputs for atom-driven expanded changes; computes per-row selection spans.
libs/ui/src/lib/data-table/grid/components/grid-layout.ts Updates frozen/layout helpers to v9 column alias.
libs/ui/src/lib/data-table/grid/buildColumnDefs.ts Ports to v9 column def alias and enables cell selection on data columns only.
libs/ui/src/lib/data-table/grid/tests/selection-expansion-atoms.spec.tsx Adds tests for atom-backed selection/expanded dual controlled/internal behavior (StrictMode-safe).
libs/ui/src/lib/data-table/grid/tests/row-range-selection.spec.ts Adds tests for v9 shift-range row selection via getToggleSelectedHandler.
libs/ui/src/lib/data-table/grid/tests/grid-selection.spec.tsx Adds tests for multi-range cell selection facade and span/edge helpers.
libs/ui/src/lib/data-table/grid/tests/grid-row-utils.spec.ts Removes tests for deleted hand-rolled selectRowRange.
libs/ui/src/lib/data-table/grid/tests/grid-filters.spec.ts Adds test coverage for getSubRows traversal in SET filter value computation.
libs/ui/src/lib/data-table/DataTree.tsx Tightens generics to extends object to match v9 constraints.
libs/ui/src/lib/data-table/DataTable.tsx Adds enableCellSelection to the public DataTable surface and tightens generic constraints.
libs/ui/src/lib/data-table/tests/PreviewChangesModal.spec.ts Updates tests for blank-vs-em-dash behavior and error column copy value plumbing.
libs/shared/ui-core/src/app/GridDownloadButton.tsx Tightens export button generics to extends object.
libs/features/manage-permissions/src/utils/permission-manager-table-utils.tsx Marks checkbox columns editable for paste/clear and adds paste application helper for permissions tables.
libs/features/manage-permissions/src/utils/tests/permission-manager-table-label-column.spec.ts Updates helper generics to extends object and aligns with SET filter changes.
libs/features/manage-permissions/src/ManagePermissionsEditorTabVisibilityTable.tsx Wires grid paste into permission checkbox updates.
libs/features/manage-permissions/src/ManagePermissionsEditorSystemPermissionTable.tsx Wires grid paste into permission checkbox updates.
libs/features/manage-permissions/src/ManagePermissionsEditorObjectTable.tsx Wires grid paste into permission checkbox updates.
libs/features/manage-permissions/src/ManagePermissionsEditorFieldTable.tsx Wires grid paste into permission checkbox updates.
libs/features/deploy/src/utils/deploy-metadata.utils.tsx Fixes group counts to exclude placeholder “No metadata found” rows.
libs/features/automation-control/src/useAutomationControlData.ts Fixes Reset to restore activeVersionNumber for flow/process builder rows.
libs/features/automation-control/src/AutomationControlEditorTable.tsx Adds paste support for Active checkbox column and marks paste-eligible rows via editable.
libs/features/automation-control/src/automation-control-table-renderers.tsx Centers Active checkbox and hides label for better grid rendering/interaction.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread libs/ui/src/lib/data-table/grid/selection/grid-selection.ts Outdated
Copilot AI review requested due to automatic review settings August 8, 2026 19:11
@paustint
paustint force-pushed the chore/upgrade-tanstack-table branch from 53520a4 to 597769c Compare August 8, 2026 19:11
…nge cell selection

Upgrade @tanstack/react-table 8.21.3 → 9.x (pinned ^9.0.0; 9.1.x blocked by the
3-day minimumReleaseAge gate until ~Aug 10). All TanStack usage is confined to the
libs/ui grid, so feature code is untouched except where noted.

## Core port
- useReactTable → useTable with an explicit tableFeatures registry
  (grid-features.ts); unused features (pagination, pinning, faceting) are now
  tree-shaken out of the bundle
- Central Tanstack* type aliases bake in the new TFeatures generic; module
  augmentation updated; RowData constraint contained via `extends object`
- table.getState() → table.store.state; columnSizingInfo → columnResizing
- Stable table facade: v9 returns a new wrapper per state change, so
  useJetstreamTable exposes a stable Proxy to preserve the "one table identity"
  contract for context memos and effects
- GridRowHandle: variance-safe subset type for the tanstackRow escape hatch
  (v9 rows are invariant in their data generic)
- Adopted v9 built-in shift-click row range selection (replaces hand-rolled
  selectRowRange); bare-checkbox tables gain shift-click; select-all
  indeterminate updated for v9's changed getIsSomeRowsSelected semantics

## Fine-grained rendering (v9 store/atoms)
- Column-resize drag re-renders only the dragged header's handle island
- rowSelection/expanded moved to external atoms (dual controlled/internal mode
  preserved; consumer callbacks fire exactly once under StrictMode)
- A selection toggle re-renders only the affected row + select-all island;
  GridHeader is memoized and skips re-renders during typing/navigation

## Cell range selection (new)
- Spreadsheet-style multi-range selection via v9 cellSelectionFeature:
  Ctrl/Cmd+click adds/subtracts rectangles, ranges survive sort/filter/reorder,
  Escape collapses, multi-range copy, Delete/revert across all ranges
- All v9 selection API access confined to a grid-selection facade

## Fixes found while testing
- Preview Changes: Warnings/Error column copied blank (value lived on
  row.status); added copy context menu; empty cells copy blank (em-dash is now
  render-only); Status column copies its compact state
- Error popovers restored to the strong red header (SLDS 2 Cosmos restyled the
  error variant to a pink container)
- Frozen-column divider and header resize handle no longer clip focus/selection
  ring edges
- Automation Control: SET filter popover was empty for tree tables
  (computeFilterSetValues now traverses getSubRows); Reset left flows marked
  dirty (activeVersionNumber is now restored); checkbox centered and toggles
  only on the checkbox itself
- Deploy: group counts no longer include the "No metadata found" placeholder
- Paste (and Delete-to-clear) implemented for boolean checkbox tables:
  permission manager (all four editors) and Automation Control's Active column,
  routed through the same handlers as checkbox clicks
@paustint
paustint force-pushed the chore/upgrade-tanstack-table branch from 597769c to 44bf10f Compare August 8, 2026 19:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 49 out of 50 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (3)

libs/ui/src/lib/data-table/grid/selection/grid-selection.ts:155

  • The docstring for getCellRangeEdges says the bitmask is only top/right/bottom/left (1/2/4/8), but the implementation also sets bit 16 to represent the selected fill. This mismatch can cause misuse when adding new range-related UI logic.
    libs/ui/src/lib/data-table/grid/renderers/CellRenderers.tsx:422
  • SelectFormatter fabricates an event object for getToggleSelectedHandler(), but it does not include nativeEvent.shiftKey even though the comment notes TanStack may read it. If TanStack checks event.nativeEvent.shiftKey (common in their handlers), Shift-range selection will silently stop working for the SLDS label-driven checkbox path.
    libs/features/automation-control/src/AutomationControlEditorTable.tsx:128
  • handlePaste traverses the tree via getSubRows(row, 0) for every node. Since getSubRows is explicitly typed as (row, index), hard-coding 0 can break consumers that depend on the index (and it’s inconsistent with other tree traversals in this PR that propagate the real index).
        const visit = (row: TableRowOrItemOrChild) => {
          rowByKey.set(row.key, row);
          getSubRows(row, 0)?.forEach(visit);
        };
        rows.forEach(visit);

Copilot AI review requested due to automatic review settings August 8, 2026 19:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 49 out of 50 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (1)

libs/features/manage-permissions/src/utils/permission-manager-table-utils.tsx:1695

  • columnKey.lastIndexOf('-') can return -1 (or point at the first/last char). In that case slice(0, -1) / slice(0) mis-parses the key and can apply a paste to the wrong permission id/action (or accidentally treat almost the whole string as a permission id). Add a guard to skip malformed keys before slicing.
    const separatorIndex = columnKey.lastIndexOf('-');
    const permissionId = columnKey.slice(0, separatorIndex);
    const actionKey = columnKey.slice(separatorIndex + 1);
    const row = updatedRows[rowIndex];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants