Repository navigation
feat(plugin-grid,types,react): ObjectGrid takes onNavigate as a prop that wins over schema.onNavigate, and the four onNavigate faces take one closed token, RecordNavigateAction (objectui#9547) - #11218
Conversation
…e token, RecordNavigateAction = 'view' | 'new_window' (objectui#9547) ObjectGridSchema.onNavigate, ListViewRuntimeProps.onNavigate and UseNavigationOverlayOptions.onNavigate declared their second argument as `action?: string`, and two of them described it as `'view' | 'edit'`. useNavigationOverlay's click handler, the one producer of that value, emits exactly 'view' and 'new_window'; 'edit' is emitted by no branch. The installed @objectstack/spec 17.5.0 catalogue types ListView.onNavigate as `(recordId, action: 'view' | 'new_window') => void`, but only as text, so the union is written once, as `RecordNavigateAction` in @object-ui/types, and the three faces reference it and carry one sentence. Two comments that contrasted ObjectViewSchema.onNavigate with the grid's `action?: string` now name the grid's new type. Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ Co-authored-by: Claude <noreply@anthropic.com>
…he prop wins over schema.onNavigate (objectui#9547) ObjectGridSchema.onNavigate's docblock sent programmatic callers to ObjectGridComponentProps, and the interface did not declare the key, so a host that followed the advice passed a function the grid never called. The interface now declares `onNavigate?: (recordId, action: RecordNavigateAction) => void`, the grid reads `onNavigate ?? schema.onNavigate` (ruling C: the prop wins), and the two docblocks that counted the nine sibling callbacks now count ten. Pins: onNavigateProp-9547.test.tsx (the prop fires in page mode with 'view', a modifier click hands it 'new_window', the prop beats the schema key; the four faces' second parameter is RecordNavigateAction, required; the spec react-tier ListView catalogue row names the same two members). gridNonAuthorKeys.test.tsx's read-line anchor is re-aimed at the new read, and two comments quoting the old read line now quote the new one. Changeset: minor for plugin-grid, types and react, Clause-② yes. Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ Co-authored-by: Claude <noreply@anthropic.com>
…prop Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ Co-authored-by: Claude <noreply@anthropic.com>
|
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: Inputs: card objectui#9547 (body and all 13 comments — ruling letter 1 ① Derived judgmentsEvery public-surface and accept-set change the diff implies, each named right or wrong:
Nothing wrong found in the diff. ② Semver level
Clause-②: yes ③ Boundary flagsDev flags (report
Gate verdicts on the head, read 2026-09-30T13:56Z: 42 check-runs — 35 success (among them Type Check, Lint, Test shards 1, 5, 6, 7 and 8 of 8, Test (dist pins), Build & E2E, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Declaration, Changeset Claim Re-read, README Export Check, Pre-Install Import Graph Check, Doc Snippet Type Check, Doc Component Type Check, Governed Surface Queue Guard), 3 skipped by design (Test (coverage), Test (coverage shard), dependabot), 0 failed, and 4 not yet concluded: Test (shard 2/8), Test (shard 3/8), Test (shard 4/8), Spec Main Shape Gate. Those four are named as unconcluded — read as neither pass nor fail — and the queue attempt waits for them. Implemented-by: VERDICT: PASS At-tier contract review rendered by the |
Fixes #9547
Clause-②: yes
What this does
Ruling C on this card (decision batch 166, item 1, comment
5731678470, maintainer 「同意」), step 3, in one pass now that objectui resolves@objectstack/spec17.5.0 (triage probe5904192911):ObjectGridComponentPropsdeclaresonNavigate?: (recordId: string | number, action: RecordNavigateAction) => void, andObjectGridreadsonNavigate: onNavigate ?? schema.onNavigate— the ruling'sprops.onNavigate ?? schema.onNavigate, spelled with the destructured prop the way its nine siblings are. When both are supplied, the prop wins.RecordNavigateAction = 'view' | 'new_window'is a new type export of@object-ui/types, and all four faces take it: the new prop,ObjectGridSchema.onNavigate,ListViewRuntimeProps.onNavigate(soListViewSchema['onNavigate']), andUseNavigationOverlayOptions.onNavigatein@object-ui/react. Each face opens with the same sentence. ⛔ No interimstring, ⛔ no'edit'.ObjectGridSchema.onNavigate, and the read-site exemption comment inObjectGrid.tsx. Every pinned phrase of both is unchanged.gridNonAuthorKeys.test.tsx: the read-line anchor is re-aimed atonNavigate: onNavigate ?? schema.onNavigate,, by content.onNavigateProp-9547.test.tsx: the ruling's two pins (the prop is wired inpagemode; the prop beats the schema key), plus a modifier click handing the prop'new_window', type-level pins that each face's second parameter ISRecordNavigateActionand is required, and a read of the spec catalogue row against the union..changeset/9547-ongrid-onnavigate-prop.md:minorfor@object-ui/plugin-grid,@object-ui/types,@object-ui/react, with the Clause-② paragraph and what a host has to change.Two commits:
1432197b88(the type and the three sibling faces),0c73dfb843(the prop, the read, the pins, the changeset), thenfc90ce532dmergesmainat0389650f3c(it brought PR #10278, objectui#9853, intoObjectGrid.tsx/objectql.ts/objectql.zod.ts; no conflict and no hunk nearonNavigate).The PM's mechanism assumptions, measured
846cec0efe:ObjectGridComponentPropsdeclared noonNavigate; the grid readonNavigate: schema.onNavigate. Inobjectql.ts,ObjectGridSchema.onNavigateandListViewRuntimeProps.onNavigatewere(recordId, action?: string); the'view' | 'edit'declaration isObjectViewSchema.onNavigate— a different channel (plugin-view'sObjectViewinvokes it with'new'/'edit'/'view'itself), not one of the ruling's three sibling faces, and it is untouched.UseNavigationOverlayOptionslives inpackages/react/src/hooks/useNavigationOverlay.ts, typed(recordId, action?: string).@objectstack/spec17.5.0 exports no TypeScript type for the union:onNavigateoccurs in none of its.d.tsfiles, and'view' | 'new_window'occurs only as thetypeSTRING of theonNavigaterow in theListViewentry ofREACT_BLOCKS(dist/ui/index.mjs). objectstackmain(05a7547c9f) is the same. ⇒ the literal is spelled once, asRecordNavigateAction, and the spec-row case in the new test fails if the two vocabularies part.handleClickinuseNavigationOverlaycallsonNavigateat four sites: two pass'new_window', two pass'view', none passes'edit'(the retirednavigation.viewread is already gone). The option is now typed against the union, so a third token there is a compile error. The pins assert that('1', 'view')inpagemode and('1', 'new_window')on a meta-click reach the prop.ObjectGridComponentPropsmembers; the "nine" census is the two docblocks' prose.NINE_SIBLINGSingridNonAuthorKeys.test.tsxasserts the nine are NOT declared onObjectGridSchema, which stays true, so it is unchanged.Files outside the claim's list, and why
packages/types/src/index.ts— one barrel line exportingRecordNavigateAction; "one place, reused" across three packages needs the export.packages/types/src/zod/objectql.zod.ts,packages/types/src/__tests__/zod-mirror-parity.test.ts— comments only. Two contrastedObjectViewSchema.onNavigatewith "the grid'saction?: string" and two quoted the grid's read asonNavigate: schema.onNavigate. This change made all four false, so they now name the new type and quote the new read.What a host sees
(id, action?: string) => …, or with one parameter, still compiles and receives what it received before.'new_window'(the old docblock's'view' | 'edit') is refused with TS2322. Measured with a throwaway probe compiled byplugin-grid'stsconfig.test.jsonand deleted afterwards: TS2322 on a'view' | 'edit'handler, TS2345 on a call passing'edit', TS2554 on a call omitting the token, no error on the two accepted shapes.app-shell'sObjectView,InterfaceListPage,ObjectDataPage;plugin-gantt'sObjectGantt;plugin-list'sListView) all type-check unchanged.Tests — all on
fc90ce532d(the head this PR opens at) unless markedEvery heavy run went through the shared lock; the verdict lines quoted are the lock's own.
pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' --filter '@object-ui/plugin-gantt^...' build→VERDICT command-exit 0(covers theplugin-gridclosure).pnpm --workspace-concurrency=2 --filter @object-ui/types --filter @object-ui/react --filter @object-ui/plugin-grid --filter @object-ui/plugin-list --filter @object-ui/plugin-gantt --filter @object-ui/plugin-view --filter @object-ui/app-shell run type-check→ all seventype-check: Done,VERDICT command-exit 0.tsc -p tsconfig.test.json --listFilesinplugin-gridlistsonNavigateProp-9547.test.tsx, so the type-level pins are compiled.pnpm exec vitest run --maxWorkers=2 --shard=1/2 packages/plugin-grid/→Test Files 87 passed (87),Tests 769 passed (769);--shard=2/2→Test Files 86 passed (86),Tests 824 passed (824).pnpm exec vitest run --maxWorkers=2 packages/types/ packages/react/→Test Files 393 passed (393),Tests 8257 passed (8257).node scripts/check-changeset-presence.mjs→ exit 0, "8 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)".pnpm check:control-bytes→ exit 0 ·check:spec-symbols→ exit 0 ·check:new-line-citations→VERDICT new-cross-file-line-citations: 0 new citation(s)·check:handler-key-reads→ exit 0, "every judged read is a declared member of its arm" ·check:doc-example-readers→ exit 0 ·check:changeset-claims→ exit 0 (report-only) ·check:pending-changeset-literals→ exit 0.eslint .form: 8 file results in--format json, 0 errors, 252 warnings (1 of them in the new test:no-explicit-anyon the fake adapter cast, the same idiomgridNonAuthorKeys.test.tsxuses).eslint.config.jssets noparserOptions/projectService, so linting is not type-aware and this diff cannot move a verdict on an untouched file. The repo-wide lint is CI's.Reverse verification (committed first, restored by blob hash)
0c73dfb843, throughablation-replace.mjswith the read reverted toonNavigate: schema.onNavigate,(on-disk counts during the run: mutated line 1, real line 0):Tests 4 failed | 41 passed (45)— the three new prop cases and the re-aimed anchor went red; the schema-only control ("the renderer still reads it") stayed green. Restored: blob equals HEAD,git diff HEADempty.0c73dfb843, through the rebuiltdist/(plugin-grid resolves@object-ui/typesthrough its exports):ListViewRuntimeProps.onNavigatewidened back toaction?: string, types rebuilt, the mutated declaration counted 1 indist/objectql.d.ts, thentsc -p tsconfig.test.jsonin plugin-grid → exit 2 with exactly two TS2344 errors, on theListViewFaceandListViewAritypins. Restore leg: source restored by blob hash, types rebuilt, mutated declaration 0 indist, real declaration 2, the sametscexit 0.Acceptance notes
packages/plugin-grid/README.mdandcontent/docs/plugins/plugin-grid.mdx("Row callbacks are component props") stay true — they already tell callers to prefer passingonNavigateas a prop — but neither lists it with the nine or namesRecordNavigateAction. Not edited: outside the claimed file surface. Carrier: the dispatching seat.check:readme-exports→ exit 1 because 8 packages outside this change were unbuilt here ("could not be judged", 0 fabricated). NOT MEASURED; this diff edits no README.Generated by Claude Code