Skip to content

feat(apollo-wind): harden DataTable and add paging, loading and strings props - #1573

Merged
snuziale merged 1 commit into
mainfrom
feat/apollo-wind-data-table-hardening
Nov 13, 2026
Merged

snuziale merged 1 commit into
mainfrom
feat/apollo-wind-data-table-hardening

Conversation

@snuziale

@snuziale snuziale commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Hardens the apollo-wind DataTable (and EditableCell). An audit found 30+ defects, several of which silently showed users wrong data. This PR fixes them, closes the accessibility gaps, and adds the props consumers were working around. The public API is additive only.

Demo

Side-by-side recording, main on the left and this branch on the right, same props on both sides (11 scenes, 92 s).

data-table-before-after.mp4

Before and after

Scenario Before (main) After (this PR)
showPagination={false} with 25 rows Only the first 10 rows render, the rest are unreachable All 25 render
Sort a text column on a table of 10 rows or fewer Case-sensitive: Apple, Date, Elderberry, apple pie, banana Case-insensitive, natural number order
A row is removed while another is selected Selection is tied to position and slides onto the next record With getRowId, selection stays on the record
Edit a cell on page 2 Table jumps back to page 1, focus falls to <body> Same page, focus returns to the cell
Parent re-renders while a cell is being edited Editor closes and the text is lost Edit survives
Clear a number cell and commit NaN is committed Previous value kept (or null with meta.nullable), min/max clamped
Unparseable date in an editable date column The table throws RangeError Value shown as is
globalFilterFn when the first row has null or object values Typing filters nothing Predicate runs once per row
searchKey on a number column Nothing matches Case-insensitive "contains" match
Resize a column from the keyboard Handle takes focus but ignores keys Arrows, Shift+arrows, Home/End, Enter or double-click to reset
Date-only string such as 2024-12-15 Shown a day early west of Greenwich Shown as that calendar day

Other fixes

  • Sorted headers expose aria-sort.
  • Resize handles are named per column, have an orientation and sane value bounds.
  • Row checkboxes and editable cells have distinct accessible names.
  • No max-width: 9007199254740991px inline style on every cell, and an explicit size: 150 is honoured.
  • maxBodyHeight: header and body stay aligned with classic (non-overlay) scrollbars.
  • The toolbar and pager wrap on narrow screens instead of overflowing.
  • pageSize prop changes after mount are respected. Empty data reads "Page 1 of 1".
  • The column menu shows header text instead of raw column ids.
  • DataTableColumnHeader supports Shift+click multi-sort and renders plain text for non-sortable columns.
  • The date editor opens on the month of the current value.
  • Four em dashes removed from story copy.

New props

  • className, getRowId, loading, emptyState, onRowClick
  • strings (Partial<DataTableStrings>): every built-in string, following the existing strings convention in this package
  • pageSizeOptions, pagination, onPaginationChange, manualPagination, rowCount
  • searchValue, onSearchChange, showSelectionCount
  • Column meta.label and meta.nullable

New exports: DataTableStrings, DEFAULT_DATA_TABLE_STRINGS. Three new stories: "Editing with paging and selection", "Loading, empty state and row click", "Localization".

Behaviour changes to review

No prop was removed or retyped, but these are visible to existing consumers:

Change Who it affects
Accessible names: "Select row" is now "Select row 1", "Edit name" is now "Edit Name, row 1", "Toggle" is now "Active, row 1", "Resize column" is now "Resize Name column" Tests or automation that query the old names
"n of m row(s) selected" is hidden until there is a select column, controlled selection, or a selected row (showSelectionCount overrides) Tables showing the count with nothing selectable
Column menu shows header text instead of the raw id Tests reading menu items
showPagination={false} renders all rows Anyone relying on the truncation to 10
Text sort order on small tables Row order
The page no longer resets to 1 when data changes Consumers who swap in a whole new dataset and expected a reset
The select column is 48px wide and not resizable (was 150px) Resizable tables are 102px narrower
With maxBodyHeight and classic scrollbars, the scrollbar gutter is always reserved A blank strip when rows do not overflow

The commit is typed feat without a BREAKING CHANGE footer. If the accessible-name changes should count as breaking for semantic-release, that footer needs adding before merge.

Regression and performance checks

  • The original, unmodified test files run against the new code: 51 of 54 pass. The 3 failures are the first three rows of the table above.
  • Old and new were rendered side by side across 28 feature combinations and diffed element by element. Row content and order are identical in all 28.
  • No other package in the monorepo imports this DataTable.

Old vs new on identical data, interleaved runs, median, in Chromium against the Storybook dev build (absolute numbers are inflated by React dev mode):

Case Old (ms) New (ms) Change
Mount, 50 rows x 8 columns 31.2 31.4 +1%
Mount, 500 rows on one page 318.2 288.5 -9%
Mount, 1,000 rows on one page 709.7 711.1 0%
Mount, 500 rows, maxBodyHeight 348.6 279.5 -20%
Mount, 20,000 rows, page of 50 50.5 49.6 -2%
Sort text column, 20,000 rows 168.7 106.6 -37%
Sort number column, 20,000 rows 50.0 50.9 +2%
searchKey keystroke, 20,000 rows 36.0 34.7 -4%
globalFilterFn keystroke, no match 17.0 7.3 -57%
Toggle one row, 500 visible 148.8 142.0 -5%
Resize step, 500 visible 119.6 121.7 +2%

Differences within about 5% are noise. Gzipped size of the two source files: data-table 2.8 KB to 5.6 KB, editable-cell 1.5 KB to 1.8 KB.

Not in this PR

  • Row virtualization or memoized rows. With 500 rows on screen every interaction re-renders all of them, in both the old and new code.
  • Drag-and-drop rows and expandable rows. Those two stories still use the plain Table.
  • In maxBodyHeight mode, columns without an explicit size still share width equally.

Test plan

  • data-table.test.tsx and editable-cell.test.tsx: 130 tests, run under a US timezone
  • Full apollo-wind suite: 3513 tests pass with NODE_OPTIONS=--no-experimental-webstorage (without it, form-plugins.test.tsx fails on Node 26, a file this PR does not touch)
  • tsc --noEmit, biome lint, build
  • Driven by hand in Chromium: every editor type, paging, delete-selected, page-size picker, search, sort, resize by mouse and keyboard, sticky body scroll with forced classic scrollbars, loading and empty states, French strings, 375px viewport
  • Review the behaviour changes above and decide on the semantic-release footer

🤖 Generated with Claude Code

…gs props

Fixes defects that showed users wrong data, closes accessibility gaps, and adds
the props consumers were working around.

Correctness
- showPagination={false} renders every row instead of silently keeping 10
- getRowId keeps selection on the record when rows are added or removed
- globalFilterFn runs once per row and no longer depends on first-row values
- text sorts case-insensitively with natural number order on small tables too
- editing a cell no longer jumps back to page 1
- searchKey works on number columns; an unknown key no longer blocks typing
- number cells never commit NaN and clamp to min/max; bad dates do not throw
- date-only strings show the right day in every timezone
- an in-progress edit survives parent re-renders
- explicit column sizes are honoured and no bogus max-width reaches the DOM

Accessibility
- resize handles work from the keyboard and are named per column
- sorted headers expose aria-sort
- focus returns to the cell after Enter or Escape
- row checkboxes and editable cells have distinct accessible names

New props
- className, getRowId, strings, loading, emptyState, onRowClick
- pageSizeOptions, pagination, onPaginationChange, manualPagination, rowCount
- searchValue, onSearchChange, showSelectionCount
- column meta: label, nullable

Behaviour changes are listed in the pull request description.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 12, 2026 20:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@github-actions
github-actions Bot temporarily deployed to preview/apollo-landing November 12, 2026 20:05 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-vertex November 12, 2026 20:05 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-docs November 12, 2026 20:05 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-design November 12, 2026 20:05 Destroyed
@github-actions github-actions Bot added the size:XXL 1,000+ changed lines. label Nov 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Dependency License Review

  • ✅ 1958 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1722
ISC 91
Apache-2.0 57
BSD-3-Clause 28
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
CC0-1.0 4
MIT-0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.3.4 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

@snuziale
snuziale marked this pull request as ready for review November 12, 2026 20:14
@github-actions

Copy link
Copy Markdown
Contributor

Storybook visual diff

⚠️ Visual changes detected: 33 changed, 6 added, 1 errored (of 70 compared, 30 unchanged). View report

Baseline is the deployed main Storybook, so changes merged to main after this branch was last updated can also appear here. Logs

Updated (PT): Nov 12, 2026, 12:20:22 PM

@github-actions

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core — — 42.02 MB 50.17 MB ±0
@uipath/apollo-react 59.7% — 2.49 MB 14.02 MB +96 B
@uipath/apollo-ui-icons — — 2.86 MB 6.97 MB ±0
@uipath/apollo-vertex — — — — —
@uipath/apollo-wind 82.4% 96.9% (248/256) 908.5 KB 5.11 MB +10.9 KB
@uipath/ap-chat 85.8% — 40.48 MB 46.10 MB ±0

"Coverage" is each package's own coverage.include scope (e.g. apollo-core instruments only scripts/). "Packed"/"Unpacked" come from npm pack --dry-run and only cover built packages — "—" means not measured this run (package not affected / not built). "vs main" is the packed (gzipped) delta against the last successful main build (the package-sizes artifact from the Release workflow); "—" there means no main baseline was available this run. The baseline is main's latest build, not this PR's exact merge-base, so it includes any drift since the branch diverged. Packages with no vitest config are omitted.

@snuziale
snuziale merged commit 0cb8e3e into main Nov 13, 2026
41 of 42 checks passed
@snuziale
snuziale deleted the feat/apollo-wind-data-table-hardening branch November 13, 2026 06:07

This branch was successfully deployed

No deployments
preview/apollo-design — eefff4bd Deployed Nov 12, 2026 by github-actions[bot]
preview/apollo-docs — eefff4bd Deployed Nov 12, 2026 by github-actions[bot]
preview/apollo-landing — eefff4bd Deployed Nov 12, 2026 by github-actions[bot]
preview/apollo-vertex — eefff4bd Deployed Nov 12, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg:apollo-wind size:XXL 1,000+ changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants