Repository navigation
fix(plugin-list,plugin-gantt,types): toolbar Filter and chips reach the tree and chart queries; toolbar Search reaches the gantt query (objectui#10250) - #10323
Conversation
…and chart queries; toolbar Search reaches the gantt query Tree and object-bound chart list views run their own query from the node's `filter`, which carried only the authored filter; the gantt node carried no search term. Each toolbar control changed ListView's own fetch and nothing drawn. - ListView: the effective filter (`buildEffectiveFilter`, payload-cached, refusal keeps the last value) now goes onto the tree and chart nodes as it already did for gantt; the gantt node also carries the toolbar Search term and the view's `searchableFields`. - ObjectGantt.reload sends `search` as `$search` and, with a term, `searchableFields` as `$searchFields`. - ObjectGanttSchema declares both keys on the interface and the zod mirror. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BP8CMtACxTdLjqR6rhd33C
…ectui#10250 pin Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BP8CMtACxTdLjqR6rhd33C
…ctui#10250 pins Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BP8CMtACxTdLjqR6rhd33C
|
changeset-claim-re-read
|
✅ 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
|
Contract reviewServed-tier: Rendered by an isolated review subagent spawned by the ① Derived judgments
② Semver levelInconsistent — the sole blocker. Frontmatter: ③ Boundary flags
Implemented-by: VERDICT: FAIL Generated by Claude Code |
…lugin-gantt (objectui#10250) The change adds two optional authorable keys (`search`, `searchableFields`) to the published `ObjectGanttSchema` and its zod mirror, which the renderer now reads. That is a widening of a published schema, declared `minor` as the earlier declarations on this schema were. `@object-ui/plugin-list` stays `patch`. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BP8CMtACxTdLjqR6rhd33C
✅ 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
|
Contract reviewServed-tier: Rendered by an isolated review subagent spawned by the ① Derived judgments
② Semver levelCorrect. Frontmatter at the head: ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #10250
Clause-②: yes (widening)
What was wrong (re-measured on
mainat8b1f06619, real renderers)ListView's toolbar offers Filter, theUserFilterschips and Search on every view, and its own fetch applies all three. Three views do not draw those rows; they run their own query from their node, and their nodes did not carry the toolbar state. A temporary probe (not committed) renderedListViewover the REAL registeredobject-tree,object-chartandobject-ganttrenderers, with toolbarstatus equals open, authoredname != zzzand searchneedle:main$filter=["and",[["name","!=","zzz"]],["status","=","open"]],$search="needle"findwith$top 2001,$filter=[["name","!=","zzz"]], no$searchaggregatewithfilter=[["name","!=","zzz"]]findwith$top 2001, the full effective$filter(objectui#10037), no$searchAll three sites reproduce as the card describes.
The change
packages/plugin-list/src/ListView.tsxselfQueryFilter. It is the samebuildEffectiveFilter(...)valueListView's own fetch sends, cached by its serialised payload (AGENTS.md [WIP] Enhance every detail of the designer #10), and a refused filter (FilterOperatorError) keeps the last value instead of widening.treenode and the object-boundchartnode now carryfilter: selfQueryFilter(the tree after thebasePropsspread, the chart in place offilter: schema.filter). The dataset-bound chart shape is unchanged; see the findings below.ganttnode also carries the toolbar term assearchand, with a term, the view'ssearchableFields. That is the same pairListView's own fetch sends ($search, plus$searchFieldswhen the view declaressearchableFields). The term is held as a gantt-only primitive (ganttSearchTerm), so a keystroke does not rebuild other views' nodes.packages/plugin-gantt/src/ObjectGantt.tsx:reloadsendssearchas$searchand, only alongside a term,searchableFieldsas$searchFields. Both reload dependency lists take the term (a string) and a serialised key for the field list, never an array identity (objectui#10036's parity pair).packages/types:ObjectGanttSchemadeclaressearch?: stringandsearchableFields?: string[]on the interface and on the zod mirror. This is why the claim carriesClause-②: yes: two new optional keys on a published schema. A declared key is validated, and the renderer reads both.plugin-gantt.mdxSchema API block and the plugin README name the pair (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2). These two files are outside the claim's file fence. They are the documentation of the declared keys.10250-self-querying-views-toolbar-state.md(@object-ui/typesminor,@object-ui/plugin-ganttminor,@object-ui/plugin-listpatch). The pending10037-gantt-toolbar-filter-reaches-chart.mdsaid "Every other view draws the rowsListViewfetched" and "The gantt chart is the one view that queries for itself". Both statements were false (tree and chart query for themselves), so that paragraph is corrected here. Its other claims still hold.Mechanism assumptions (from the dispatch), measured
filteris the only filter inputObjectChart's aggregate reads.ListViewwrites nodataSourcebinding,compareToordrillDownonto that node. The probe's aggregatefilterafter the fix is exactly the host's$filter(no double AND).@objectstack/spec'sisFilterASTaccepts that shape, andparseFilterASTlowers it to{"$and":[{"name":{"$ne":"zzz"}},{"status":"open"}]}. That is the pathdata-objectstackuses to lower an array filter foraggregate.ObjectTree's object-provider branch readsschema.filter, soplugin-treeis untouched.@object-ui/types, listed above. If the server refuses a term for an object,ListView's own fetch fails inside its loadtryand the load-error panel replaces the chart. The chart's query receives the same term, so the behaviour matchesListView's and no fallback was added.ListView's own fetch sends$searchon tree and chart too, and neither view's query carries it. It is not a one-line forwarding:ObjectTreehas no search channel (it would need a new key and aplugin-treechange), and the aggregate call has no search parameter at all. It is reported as a finding and not handled here.Tests and measurements (final head
3bd041e6a)packages/plugin-list/src/__tests__/ListView.selfQueryingViewsToolbarState-10250.test.tsx. Its stand-ins follow each registered renderer's query contract: the tree keys on the identity ofschema.filterand of the hostdata; the chart keys on the serialised filter; the gantt takes onlyschema. Tree and chart each get CONTROL, FORWARDS (toolbar Filter at mount), CHANGE (aUserFilterstoggle chip clicked after mount) and STABILITY (unrelated re-renders cause no new view query). Gantt search gets CONTROL, FORWARDS (term typed into the toolbar box), SEARCHABLE FIELDS, CLEARED and STABILITY. 13 passed.packages/plugin-gantt/src/ObjectGantt.searchTerm-10250.test.tsx: CONTROL, TERM, FIELDS, INERT FIELDS (a field list with no term sends neither key), CHANGE, STABILITY (a new but equal node does not re-query) and INLINE (avalueprovider is narrowed byValueDataSource). 7 passed.packages/types/src/__tests__/gantt-search-keys-10250.test.ts: both keys are declared, optional and without defaults, wrong-typed values are refused on their path, and a@ts-expect-errorpair is compiled bytsconfig.test.json. 5 passed.plugin-listdoes not declare):find$filter= the host's effective filter.filter= the host's effective filter.findcarries$search: "needle", and withsearchableFields: ['name']also$searchFields: ["name"], identical to the host's.ablation-replace.mjs: the anchor hit once, the blob changed, and the restore was proven by blob equal to HEAD and an emptygit diff HEAD. Tests resolve../ListViewand./ObjectGanttfrom source, so nodistwas involved.schema.filter: 3 failed / 10 passed (tree FORWARDS, CHANGE, STABILITY).schema.filter: 3 failed / 10 passed (chart FORWARDS, CHANGE, STABILITY).searchspread disabled: 4 failed / 9 passed (FORWARDS, SEARCHABLE FIELDS, CLEARED, STABILITY). CLEARED and STABILITY fail because their preconditions wait for the term.reload's$searchspread disabled: 5 failed / 2 passed (TERM, FIELDS, CHANGE, INLINE, STABILITY).pnpm --filter '@object-ui/plugin-list^...' --filter '@object-ui/plugin-gantt^...' build). A throwaway file assigningsearch: 5toObjectGanttSchemainplugin-gantt's test program failed with TS2322, which proves the rebuilt declaration was read. The file was deleted.pnpm exec vitest run packages/plugin-list/ packages/plugin-gantt/on838eff69e: 155 files / 1576 tests passed.pnpm exec vitest run packages/types/on838eff69e: 215 files / 4928 tests passed.838eff69echange only the two new pins' header comments and one unused lint directive. On3bd041e6athe union of the three new pins, the objectui#10037 pin,zod-mirror-parityand the objectui#10036 reload-identity pin passed: 6 files / 72 tests.pnpm --filter @object-ui/types --filter @object-ui/plugin-list --filter @object-ui/plugin-gantt type-check: exit 0, and each new test file is in its package'stsconfig.test.json(--listFilesOnly).lintfor the same three packages: exit 0, 0 errors.3bd041e6a:check:new-line-citations(0 new),changeset:check,check-changeset-presence.mjs,check:changeset-claims(report-only),check:control-bytes,check:vi-mock-specifiers/-inherit/-override-shape,check:test-path-roots,check:phantom-deps,check:unreferenced-sources,check:doc-types,check:doc-fences,check:doc-example-ids,check:spec-symbols,check-doc-links.mjs.check:doc-snippetsandcheck:doc-examples(PRECONDITION NOT MET, exit 2) andcheck-readme-exports.mjs(population collapse). All three need a build of about 34 packages. Both doc edits are prose or aplaintextfence, which none of those gates compiles. Left to CI.Findings outside this card (for the seat; not fixed here)
treeview's own query (the probe: host$searchpresent, the tree's ownfindhas none).chart(the aggregate call has no search parameter).chartview bound to a semanticdataset: its node carries nofilterat all, so neither the authored filter nor the toolbar Filter and chips reachqueryDataset. The probe's call was["task_ds",{"dimensions":["status"],"measures":["total_estimate"]}]with noruntimeFilter. This one is not a one-line forwarding:runtimeFilteris the spec'sFilterCondition, and a dataset's field namespace need not be the list object's.Acceptance notes
ObjectTreealso keys its record effect on the hostdataidentity. When a host fetch returns a fresh rows array, one toolbar change therefore gives the tree two queries with the same new filter: one when the node filter changes, one when the host rows land. Measured with the probe: after one chip click the tree queries went from 1 to 3 with fresh arrays, and from 1 to 2 with a stable array. The same dependency means a host refetch onmainalso re-queried the tree, with the authored filter. That is read from the effect's dependency list and was not measured onmain. The duplicate comes from that pre-existing dependency inplugin-treeand is not changed here.searchableFieldsis forwarded only alongside a term, matchingListView's own fetch andObjectGrid. On a standalone gantt it acts only whensearchis authored.react-hooks/refslint warnings inListView.tsxgo from 7 onmainto 9 (ESLint--format json, same config, both files linted in one run). The five in the cache block are the objectui#10037 ones on the renamed ref. The rule also fires once per read site of the cached value: gantt before, now tree and chart too. They are warnings, and the file has 0 errors.Generated by Claude Code