You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Cross-page "Select all N matching" can never appear in the console — totalMatching is only written by ObjectGrid's own loader, which never runs under ListView's external pagination #4464
Found by a retest of records-forms.bulk-select-all-matching (framework QA run objectstack-ai/objectstack#7439) against the console at pin 6314e87f2d49. The fix under retest — #4140 (the selectionResetKey bump) — is verified working; this is a separate, pre-existing gap that the retest was able to reach for the first time.
Symptom
Selecting an entire page in a genuinely server-paginated grid shows only N selected | Delete | Clear. The cross-page banner never renders: [data-testid=bulk-cross-page-banner] and [data-testid=bulk-select-all-matching] are both absent, for any match-set size. Reproduced on two fresh loads.
Reproduction
As admin, author a paginated view: PUT /api/v1/meta/view/showcase_contact.rt5_paged with config {type:'grid', data:{provider:'object',object:'showcase_contact'}, filter:[{field:'account',operator:'equals',value:'<Northwind id>'}], pagination:{pageSize:10}}
Open /_console/apps/com.example.showcase/showcase_contact?view=showcase_contact.rt5_paged.
The grid pages server-side for real — GET /api/v1/data/showcase_contact?top=10&filter=… → total=26, 10 rows, count bar "26 records", pager "Page 1 of 3".
Click the header select-all checkbox to select the whole visible page.
Expected: BulkActionBar shows "All 10 on this page are selected." plus a "Select all 26 matching" button. Actual: no banner — only 10 selected | Delete | Clear.
ObjectGrid passes totalMatching={singleSelection ? undefined : totalMatching}, and the only writer of that state is setTotalMatching(...) inside ObjectGrid's own data loader (ObjectGrid.tsx ~:710).
In the console the grid is hosted by ListView, which fetches rows itself and passes manualPagination:true, rowCount:serverTotal, page, pageSize, onPageChange down (plugin-list/src/ListView.tsx ~:2859-2864). So externalManualPagination is true, ObjectGrid's loader never runs, totalMatching stays undefined, and the banner condition is permanently false.
The tell that the data is right there: the pager shows the correct page count because it reads manualRowCount = externalManualPagination ? rest.rowCount : totalMatching
— the grid has the real total on the external path; it just never reaches BulkActionBar.
Suggested fix: fall back to rest.rowCount when externalManualPagination is on.
This is the same shape as #4138 (fixed): a feature gated on internal-data state that the console's external-data path never populates. Worth a sweep for other totalMatching-style state with a single internal writer.
Consequence for the checklist item
With the affordance unreachable, three further clauses cannot run at all: the collected-id set can't be compared against the filtered API count, the aggregate-vs-per-record distinction over the matching set is undefined, and the HARD_CAP (5000) path is doubly out of reach. Only the clause #4140 addressed is green.
The unit tests cannot see this.automated.ref exercises ObjectGrid in isolation, where the internal loader does run — precisely the path the console does not take. A regression test for this needs the ListView-hosted composition.
Fixture correction worth recording
The previous run recorded these clauses blocked(fixture) believing no object exceeds the page window. Half of that is true — the stock console fetches top=100 and showcase_contact's 32 rows fit one page — but the blocker is not a hard 100-row limit: authoring a view with config.pagination.pageSize turns on real server-side paging, which is what made this defect reachable. (The probe view was deleted afterwards; no repo file was touched.)
Source
Retest of records-forms.bulk-select-all-matching at console pin 6314e87f2d49, framework b602d536.
Ruling (delegated authority; open veto window): fix as the card diagnoses — the same #4138 shape (feature gated on internal-loader state the external path never populates), and the card's own tell is the design: the pager already reads manualRowCount = externalManualPagination ? rest.rowCount : totalMatching. One derived value, one answer: hoist that exact derivation so the pager AND BulkActionBar's totalMatching consume the SAME resolved total — do not write a second conditional beside the first (two copies of the fallback is how the next #4464 happens). singleSelection ? undefined : … gating stays.
Test half — the card names the trap: ObjectGrid-in-isolation runs the internal loader, precisely the path the console does not take, so unit tests on ObjectGrid alone are structurally blind here. The red-first pin is a ListView-hosted composition test (new file in packages/plugin-list/src/__tests__/): external server pagination (manualPagination, rowCount > pageSize), select the whole visible page → pre-fix [data-testid=bulk-cross-page-banner] and [data-testid=bulk-select-all-matching] absent (capture verbatim); post-fix both present with "Select all N matching" carrying the server total. Must-not-change: the internal-loader path (standalone ObjectGrid) still shows the banner (green both sides); singleSelection still suppresses; selection short of a full page still shows no banner.
Census (report-only, the card's suggested sweep): grep ObjectGrid for other internal-loader-only state consumed by features reachable on the external path (the #4138 class) — LIST them in the report, fix nothing extra.
Grading: patch @object-ui/plugin-grid (runtime wiring only; .d.ts-checked both ways). Never major.
Surface (mutual exclusion): packages/plugin-grid/src/ObjectGrid.tsx + one NEW composition test file in packages/plugin-list/src/__tests__/ + one changeset. ⛔ NOT: plugin-list/src/ListView.tsx SOURCE (in-flight #4408/PR #4495 owns it — your composition test imports it read-only), BulkActionBar's own component file unless measurement demands (report first), chart files (#4466), plugin-calendar (#4492), the sweep file (#4434). If the derivation hoist genuinely requires a ListView.tsx edit, STOP and report.
Activity
yinlianghui commentedon Aug 12, 2026
CLAIM — session
session_017Qqyix2QcnpUC9XeYVDzx3, branchclaude/issue-4464-crosspage-totalmatching.Ruling (delegated authority; open veto window): fix as the card diagnoses — the same #4138 shape (feature gated on internal-loader state the external path never populates), and the card's own tell is the design: the pager already reads
manualRowCount = externalManualPagination ? rest.rowCount : totalMatching. One derived value, one answer: hoist that exact derivation so the pager ANDBulkActionBar'stotalMatchingconsume the SAME resolved total — do not write a second conditional beside the first (two copies of the fallback is how the next #4464 happens).singleSelection ? undefined : …gating stays.Test half — the card names the trap: ObjectGrid-in-isolation runs the internal loader, precisely the path the console does not take, so unit tests on ObjectGrid alone are structurally blind here. The red-first pin is a ListView-hosted composition test (new file in
packages/plugin-list/src/__tests__/): external server pagination (manualPagination,rowCount>pageSize), select the whole visible page → pre-fix[data-testid=bulk-cross-page-banner]and[data-testid=bulk-select-all-matching]absent (capture verbatim); post-fix both present with "Select all N matching" carrying the server total. Must-not-change: the internal-loader path (standalone ObjectGrid) still shows the banner (green both sides);singleSelectionstill suppresses; selection short of a full page still shows no banner.Census (report-only, the card's suggested sweep): grep ObjectGrid for other internal-loader-only state consumed by features reachable on the external path (the #4138 class) — LIST them in the report, fix nothing extra.
Grading: patch
@object-ui/plugin-grid(runtime wiring only;.d.ts-checked both ways). Never major.Surface (mutual exclusion):
packages/plugin-grid/src/ObjectGrid.tsx+ one NEW composition test file inpackages/plugin-list/src/__tests__/+ one changeset. ⛔ NOT:plugin-list/src/ListView.tsxSOURCE (in-flight #4408/PR #4495 owns it — your composition test imports it read-only), BulkActionBar's own component file unless measurement demands (report first), chart files (#4466), plugin-calendar (#4492), the sweep file (#4434). If the derivation hoist genuinely requires a ListView.tsx edit, STOP and report.Generated by Claude Code
Generated by Claude Code
Merge origin/main into #4464 branch — the floor and the resolved tota…
fix(plugin-grid): the cross-page select-all banner works under extern…