Repository navigation
fix(plugin-view): an object-view grid exports the filter it shows and returns to page 1 when it changes (objectui#11880 item 5) - #12010
Merged
objectstack-fleet[bot] merged 5 commits intoOct 8, 2026
Conversation
…ectGrid (objectui#11880 item 5) Measures, on today's hand-off, the rung order (named view, then table.filter, then table.defaultFilters) through the real grid and a ValueDataSource that applies $filter, and the three ObjectGrid readers that look at one slot and not the other: the server-streamed export, the page reset on an in-place query change, and the refused-filter state. Claude-Session: https://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw Co-authored-by: Claude <noreply@anthropic.com>
…ilter` (objectui#11880 item 5) ObjectView's grid branch wrote an active view's filter and the deprecated table.defaultFilters into the grid node's `defaultFilters`, and table.filter into `filter`. ObjectGrid chose between them for the query, but its server export and its page reset read `filter` only, so on route 2 a view's filter narrowed the rows while the download held every record, and changing it in place kept the old page. The chain is now resolved here and handed over in `filter` alone: the active view's filter, else table.filter unless it lowers to nothing (toFilterNodeSafely, so a refused table.filter still draws its panel), else table.defaultFilters. No `defaultFilters` is written on the node, the key the spec retires on object-grid. The instrument becomes the pin file: the export and page-reset rows take the corrected answers; the thirteen rung readings are unchanged. Four plugin-view pins that asserted `grid.defaultFilters` are re-spelled, the README / plugin-view.mdx sentence about forwarding both slots is rewritten, and the stale gridSchema memo comment (ObjectGrid "raw-assigns the legacy one") is replaced. Claude-Session: https://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw Co-authored-by: Claude <noreply@anthropic.com>
Contributor
❌ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. Which half objected:
📦 Bundle Size Report
Size Limits
|
…fault-filters-handoff Claude-Session: https://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw Co-authored-by: Claude <noreply@anthropic.com>
… makes true (objectui#11880 item 5) The ObjectGridSchema.defaultFilters TSDoc said ObjectView hands the slot an active named view's filter, and ObjectGrid's legacy-read comment said plugin-view forwards a named view's rule array into it. Since this PR ObjectView writes no defaultFilters on the grid it draws: both rungs reach it in `filter`. Comment and TSDoc only; the mirror key, the legacy read and its readers are unchanged. Claude-Session: https://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
…fault-filters-handoff Claude-Session: https://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
objectstack-fleet
Bot
deleted the
claude/issue-11880-default-filters-handoff
branch
October 8, 2026 23:28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11880
Clause-②: no —
ObjectViewchanges which slot of the grid node it builds for its ownObjectGridcarries the filter. No published type, zod accept set, export or prop moves:ObjectGridSchema.defaultFiltersstays declared on both faces while the pinned spec (17.7.0) declares it.Item 5 of this card, its last item:
object-grid.defaultFiltersandObjectView's hand-off. Claim6068695486; the seat's answer6068966481(Q1 → A, Q2 → A1) to the needs_decision report6068935827. Ruling of record: objectstack-ai/objectstack#115096051498447(A-narrow; objectui first, and the spec retirement ships with the pin bump that carries it).Which of the two, and why
Item 5 asked to retire the mirror key or to retarget the internal hand-off to
filter, and to say which. This PR retargets the hand-off. The mirror key,ObjectGrid's read of it andObjectView's read of an authoredtable.defaultFiltersstay while the pinned spec still declares the key; under the ruling's order they retire with the pin bump that carries the spec half. After this PR objectui's own code writesdefaultFiltersinto no node (census below), so that retirement blanks nothing objectui builds, and the bump deletes readers only.User-visible corrections
Both on an
object-viewrendered by the registered renderer (route 2: anobject-viewpage node, the Studio's stored-view preview). A host that suppliesrenderListView(route 1,ListView) already behaved this way.table.defaultFiltersnarrowed the rows on screen, butObjectGrid's server-streamed export (CSV, XLSX, JSON) reads only thefilterslot, so it was handed no filter and downloaded every record of the object. It now downloads the rows the view shows, as it already did fortable.filter.ObjectGrid's page reset keys only on thefilterslot, so when a named view's filter ortable.defaultFilterschanged while the grid stayed mounted, the next query kept the old page index. It now returns to page 1, astable.filteralready did.Unchanged: which filter applies (every rung and pair sends the same
$filterand draws the same rows), and a refused filter still draws the grid's malformed-filter panel and queries nothing.What changed
packages/plugin-view/src/ObjectView.tsx, the grid branch:filter: viewFilter || gridTableFilterRung(authoredFilters); thedefaultFilterswrite is gone.gridTableFilterRungreturnstable.filterunless it lowers to nothing, elsetable.defaultFilters. "Lowers to nothing" is the sink's own answer (toFilterNodeSafelyfrom@object-ui/core), which is the choiceObjectGridmade itself while the two arrived in two slots, so an emptytable.filterbeside atable.defaultFilterskeeps the grid's answer (Q2 → A1). A refusedtable.filteris kept, so the grid still draws its panel. The named view's filter keeps today's truthiness (||): an empty named-view filter still filters nothing.objectui#5102paragraph above the memo no longer says the filter pair is forwarded in both slots, and the memo comment that saidObjectGrid"raw-assigns the legacy one" (false since objectui#4082; round 10's acceptance note named this PR's memo as its carrier) is replaced.ObjectView.gridFilterHandoff-11880.test.tsx(18 tests, realObjectView, realObjectGrid, aValueDataSourcethat applies$filter). Fourplugin-viewpins that assertedgrid.defaultFiltersare re-spelled togrid.filterplusgrid.defaultFiltersundefined:ObjectView.canonicalTableKeys,ObjectView.namedViewContextTokens-10506,ObjectView.specShapedNamedView-8254,ObjectView.tableSlotRelay-10976(its by-name loop skipsdefaultFilters, whose arrival infilteris pinned by a new case).packages/plugin-view/README.mdandcontent/docs/plugins/plugin-view.mdx, the sentence sayingObjectViewdefers toObjectGrid"by forwarding both slots" now covers the paging pairs only and states the filter pair's resolution and its two effects.6069594612, as comment / TSDoc only: theObjectGridSchema.defaultFiltersdocblock inpackages/types/src/objectql.ts, andObjectGrid.tsx's legacy-read comment. Each now says thatObjectViewhands its whole filter chain tofilter, and no longer writesdefaultFilters..changeset/11880-grid-filter-handoff.md:@object-ui/plugin-viewpatch, naming both corrections.Measurement
H1, the hand-off before (base
aa67386a5, instrument at601aeaf67, 17 of 17 green). Rows Acme/open, Beta/won, Cyan/lost, Dune/open; the view rule matches open,table.filterwon,table.defaultFilterslost. None: no$filter, four rows. View: open, Acme and Dune.table.filter: won, Beta.table.defaultFilters: lost, Cyan. View with either or both table rungs: open.table.filterwithtable.defaultFilters: won. Empty view filter beside both table rungs: no$filter, four rows. Refinement of H1:ObjectGridreaddefaultFilterswhenfilterLOWERED to nothing, not only when it was absent (table.filter: []besidetable.defaultFiltersdrew lost/Cyan).H2, one slot. It did not hold as worded:
ObjectGridtreats the slots differently in exactly two readers beyond the base filter, the server export and the page-reset effect (both readfilteronly;$selectcollectors, grouped queries, select-all-matching and the count all derive from the one query the load effect builds). The report stopped there; the seat ruled the two changed answers corrections. A naive||chain would also have changed the empty-canonical pair; the faithful chain keeps it.H3, census (populations enumerated with
git ls-treeon HEAD: packages 6325, apps 349, examples 513, content 203, docs 25, skills 27 files). Write-shapeddefaultFilterskeys (a quoted key allowed) outside tests and CHANGELOGs, before this PR: 7 hits, exactly one of which wrote a node,ObjectView's grid branch; the rest areObjectGrid's resolver input and interface member, anObjectGridcomment, the zod declaration and the two documentation rows teaching it as legacy. apps, examples, docs, skills: 0 (matcher control on examples:objectNamekeys, 36 hits, same regex shape). After this PR the node writer is gone. Authored metadata withtable.defaultFiltersstill renders through the readers that stay (pinned: rung 3 alone, rungs 2 + 3, the empty-canonical pair).H4, docs. The one sentence describing the hand-off is rewritten (above); the three-tier precedence paragraph stays true.
Tests
On head
d9f895bd9, every vitest run underos-verify-lock. The patch roundc8cf0365(the two sentences above) re-ran theplugin-view,plugin-gridandpackages/typessuites, plus every test that readsobjectql.tsorObjectGrid.tsxfrom disk: 647 files, 13494 tests, all passing. Type-check fortypes,plugin-gridandplugin-viewexits 0. The merges ofmainthat followed touched none of this PR's files, and the net diff'sgit patch-id --stableis unchanged (39130482).pnpm exec vitest run --maxWorkers=2 packages/plugin-view/ packages/plugin-grid/ apps/console/src/__tests__/registry-inputs-spec-parity.test.ts packages/core/src/utils/__tests__/filter-source-merge.test.ts packages/plugin-list/src/__tests__/ListView.exportMatchesView.test.tsx packages/types/src/__tests__/grid-default-filters-gantt-map-filter-round10-6152.test.ts(both whole suites, plus every test outside them that namesdefaultFilters,tableDefaultsoruseResolvedGridFilters):Test Files 269 passed (269),Tests 2858 passed (2858).pnpm exec vitest run --maxWorkers=2 scripts/__tests__/:Test Files 179 passed | 2 skipped (181),Tests 5452 passed | 2 skipped (5454).pnpm --filter @object-ui/plugin-view type-checkandpnpm --filter @object-ui/plugin-grid type-check(both script names echoed), exit 0, afterturbo run build --filter='@object-ui/console^...' --filter='@object-ui/example-schema-catalog^...'.tsconfig.test.jsonlists all five edited test files (--listFilesOnly, 5 of 5).pnpm check:doc-snippets(784 of 784 blocks judged, 0 failed),pnpm check:readme-exports(579 of 579 self-imports real),pnpm docs:check-links, all exit 0.node scripts/check-changeset-presence.mjs(6 source files of 1 released package, 1 changeset),node scripts/check-changeset-no-major.mjs,pnpm check:changeset-claims,pnpm check:pending-changeset-literals,pnpm check:new-line-citations(0 new),pnpm check:control-bytes, all exit 0.node scripts/check-governed-queue-guard.mjs --testover the 9 paths: NOT GOVERNED.Ablations (one-shot, objectstack's
scripts/ablation-replace.mjsin wrap mode; each mutation proven on disk, each restored to theHEADblob with an emptygit diff HEAD), over the pin file and the four re-spelled pins (80 tests):defaultFilters/filterpair): 12 red / 68 green. In the pin file exactly the four corrected rows go red with their before-readings (export of a named-view filter and oftable.defaultFilters:expected undefined to deeply equalthe lowered rule; page reset after an in-place change of either:expected 2 to be +0), while the ten rung rows, the two controls and both refusal rows stay green. The other 8 are the re-spelledgrid.filter/grid.defaultFiltersassertions in the four pins.table.filterskipped (canonical.ok && …): 1 red,a refused table.filter is kept, not skipped for table.defaultFilters.viewFilter || table || tableDefaults): 1 red,an EMPTY table.filter lowers to nothing, so table.defaultFilters answers.Bundle
check:eager-closureunder the lock, on this tree merged withmain7ebff399(green onBundle Analysis, after objectui#12009's revert and objectui#12004), and on thatmainalone:main7ebff399:eagerGzipBytes3,391,414;The ceiling constant is untouched.
Acceptance notes
object-gridnode's owndefaultFiltersis still skipped byObjectGrid's export and page reset (ObjectGridreads onlyfilterthere). No author writes one (census 0), and the read retires with the key. Carrier: the v18 pin-bump PR.table.filterbeside atable.defaultFilters(the grid applies the legacy rule; the calendar route queries nothing, measured). Kept by Q2 → A1; no author; it goes with the legacy read.Implemented by the dispatched
os-devrun (mode subagent) in sessionhttps://claude.ai/code/session_01DBZ9bntPZ7VKyQNtJeNsgw, claim6068695486.Generated by Claude Code