Improve data table selection#563
Conversation
- Add shift+click range selection in selection mode - Fix selection/filter desync: report all selected rows, not just filter-visible ones, so checked boxes match the reported selection - Add filter-aware selection count message - Fix virtualized rows not reflecting column/selection visibility changes until scrolled (stale visibleColumnKey memo dependency) - Add data-table selection tests
Greptile SummaryThis PR addresses three pre-existing bugs in the reusable
Confidence Score: 5/5All three bug fixes are narrow, correct, and covered by new tests; no regressions introduced in consumer components. The shift+click anchor logic is correctly scoped to visible rows and properly resets on select-all. The switch to getSelectedRowModel() fixes the real desync without breaking any consumer. The inline visibleColumnKey computation is a straightforward correctness fix. The filter-count guard covers both edge cases and is verified by tests. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Checkbox onClick] -->|captures e.shiftKey| B[shiftKeyRef.current = shiftKey]
B --> C[onCheckedChange fires]
C --> D[rowCheckboxHandlerRef.current invoked]
D --> E{isShift && value && anchorId?}
E -->|Yes| F[Find anchor + target in visibleRows]
F --> G{Both found?}
G -->|Yes| H[Range-select lo..hi, skip grouped rows]
H --> I[Update lastSelectedRowIdRef to rowId]
G -->|No, anchor on another page| J[Single toggle via table.getRow]
E -->|No| J
J --> I
I --> K[useEffect fires on rowSelection change]
K --> L[table.getSelectedRowModel — all selected rows]
L --> M[onRowSelectionChange reported to parent]
subgraph Count display
N{columnFilters active?} -->|Yes| O{filteredSelected < selected?}
O -->|Yes| P[rowsSelectedFiltered: X selected, Y match filter]
O -->|No| Q[rowsSelected: X of filteredTotal selected]
N -->|No| Q
end
Reviews (2): Last reviewed commit: "Fix misleading selection count when filt..." | Re-trigger Greptile |
Switch to the filter-aware count whenever the filter hides any selected row (filteredSelected < selected), not only when selected > filteredTotal. Previously 'X of Y selected' could show e.g. '2 of 3 selected' while none of the 3 visible rows were checked.
|
@greptile |
Problem
The reusable data table (
frontend/src/components/ui/data-table.tsx) had three selection shortcomings:Changes
shiftKeyvia the checkboxonClick(RadixonCheckedChangedoesn't expose the event) and tracks an anchor. Select-all resets the anchor; anchors clear on exit; grouped rows are skipped; range is scoped to the current page under pagination.getSelectedRowModel()(all selected) instead ofgetFilteredSelectedRowModel()(only filter-visible), andcolumnFilterswas added to the effect deps. Selections now persist across filtering and always match the checked boxes.rowsSelectedFilteredmessage (e.g. "5 selected (2 match filter)") avoids nonsensical "5 of 2 selected" when a filter hides selected rows. Added to en/fr/escommon.json.visibleColumnKeywas memoized on[table.getVisibleLeafColumns]— a stable function reference that never changes — so the key was computed once and never updated. Now computed inline each render; the memo comparison is by string value, so cell content still won't re-render on scroll.i18n
Added
rowsSelectedFilteredtofrontend/public/locales/{en,fr,es}/common.json.Testing
frontend/src/components/ui/data-table.test.tsx— 4 tests: shift+click inclusive range, anchor reset after select-all, filter persistence sync, and the filtered count message.pnpm typecheck— cleanpnpm test:rundata-table tests (4/4) and locale-keys (200/200) passReviewer notes
manualPaginationlimitation in a code comment: selections on other (server) pages live inrowSelectionby id but can't be reported as row objects; true cross-page selection is out of scope.ProjectTasksTableView,UserPermissionsCard, andDocumentsListViewall map selections to ids only.