Repository navigation
fix(app-shell): a print record page draws the record's header actions beside Print - #12921
Conversation
… beside Print A page that declares `print` holds only the printable component types and `page:header` is not one of them, so such a record page drew none of the record's header actions. Lift `page:header`'s action row out of `PageHeaderRenderer` into an exported `PageHeaderActions` (the one resolver, used by `page:header` itself), and draw it in the print page's screen-only chrome row beside Print, outside the print page root, where the print stylesheet hides it on paper as it hides Print. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
…geHeaderActions export Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
✅ 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 read: card #12906 (body, triage ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #12906
Clause-②: yes (measured correction of the claim's
no:@object-ui/componentsgains a new export,PageHeaderActionsand its props typePageHeaderActionsProps. No spec key, registry key or printable component type changes.)What changed
@object-ui/components,containers.tsx.page:header's action row (declared-id resolution, the location / capability /visible/hiddengates, the merge withRecordContext.headerSystemActions, ordering, the inline /⋯split, localization anddispatchHeaderAction) is lifted, unchanged, out ofPageHeaderRendererinto an exportedPageHeaderActionscomponent.PageHeaderRenderernow draws its tail through it, passing its ownactions/maxVisible/mobileMaxVisibleand the empty slot. One resolver, two callers; ⛔ no second resolver.@object-ui/app-shell,RecordDetailView.tsx. On a page that declaresprint, the view draws a screen-only chrome row (data-record-print-chrome) at the top of the content column, inside the record'sRecordContextProvider/ActionProvider: the shared chrome (presence, managed-by badge),PageHeaderActionsfed the object's declaredrecord_header/record_moreactions (synthParts.headerActions; the system Edit / Share / Delete come from the context as on every record page), and the Print button. The row is outside the print page root, so the print stylesheet's existing hide rule (everything that neither is the print page, holds it, nor sits in it) hides it on paper exactly as it hid Print. The Print button moved from the absolute top-right overlay into this row so the new buttons are not drawn over the page's own top-right content.printis unchanged: the absolute overlay keeps presence and the badge, andpage:headerdraws the actions.Mechanism readings (dispatch A1 to A3)
PageHeaderRenderer(containers.tsx), now the exportedPageHeaderActions; the system set reaches it throughRecordContext.headerSystemActions(synthSystemActionsinRecordDetailView). The print chrome reaches it by renderingPageHeaderActionsinside the same providers.RecordDetailView.printPageHeaderActions-12906.test.tsx: (a) Submit for Sign-off, Edit and the⋯(favorites / Share / Delete) in the chrome beside Print, Edit calling the host'sonEdit; (b) Print, the toolbar and the chrome are neither inside nor around[data-print-page], the page's stylesheet carries the hide rule verbatim, and toolbar and Print share one chrome container; (c) clicking the declaredtype: 'api'action sendsPOST /api/v1/data/OBJECT/INV-1/submitthrough the record page's api handler, and the request equals the one the same click sends on the default (non-print) record page; (d) CONTROL: withoutprint, no chrome, no Print, one toolbar inside theheader, each action drawn once.page-header-actions-shared-12906.test.tsxpins thatPageHeaderActionsdraws byte-identical toolbar markup (React ids blanked) topage:headerfor the same context and keys, the system set alone, and the empty slot.ablation-replace.mjs, anchor thePageHeaderActionsline in the print chrome, deleted): anchor 1 to 0, blobc6680e738e59toa51ab974dbe1; (a), (b), (c) red, (d) green; restore verified blob equals HEADc6680e738e59andgit diff HEADempty. No dist in the path: the test resolves both packages from source through the vitest alias.record_headeraction, so it rides the same route as Submit for Sign-off once it lands in the example.Verification at 5741ebd
pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' run build: exit 0.pnpm --filter @object-ui/components run type-checkandpnpm --filter @object-ui/app-shell run type-check: exit 0, both echoedtsc --noEmit && tsc -p tsconfig.test.json.packages/components/: 404 files passed, 1 skipped; 4047 tests passed. vitestpackages/app-shell/: 1555 files passed, 1 skipped; 14635 tests passed.--no-inline-config --format json): 5 files, 0 errors. Population: the per-packageeslint .the lint workflow runs; type-aware linting is not enabled ineslint.config.js(noparserOptions.project/projectService), so this diff cannot move a verdict on an untouched file.check:phantom-deps,check:self-import,check:unreferenced-sources,check:doc-example-readers,check:handler-key-reads,check:side-effects-array,check:element-data-source-declaration,check:spec-symbols,check:action-forward-parity,check:designer-field-key-parity,check:icon-record-names,check:i18n-keys,check:i18n-drift,check:i18n-designer-parity,check:control-bytes,check-hand-rolled-comment-mask.mjs,check-changeset-fixed.mjs,check-changeset-presence.mjs,check:new-line-citations(0 new).Acceptance notes
packages/components/src/index.tsgains the one export line pair. It is outside the dispatched surface, and it is the only wayapp-shellcan reach the shared resolver (the package exports only its root barrel). Declared here and in the report.content/docs/guide, package README) are not updated in this round; the surface did not include them.The session that wrote this:
https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB.Generated by Claude Code