Repository navigation
feat(app-shell,plugin-list): a page list-view node's addRecord opens the object list's create; publish list-view.addRecord - #13098
Merged
objectstack-fleet[bot] merged 5 commits intoOct 20, 2026
Conversation
… header New's create (objectui#13089) renderListView forwarded addRecord and no onAddRecord, so ListView drew an Add button whose click did nothing, also for a viewer who may not create. The button now calls the header New's create and follows its verdict. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
…the object list's create; publish list-view.addRecord (objectui#13089) The console's page host answered every parent-less resolve with no handlers, so a page list-view node's Add button was withheld. It now serves the bridge's create pair, and nothing else, to an object-scoped list: one that names no relationshipField and no parent. A related list whose parent did not resolve is still served nothing. ResolveRelatedRecordActionsInput documents the shape. An unlinked create opens an editMode 'page' object's full-page create route, as the object list does. list-view.addRecord is published. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
…by input shape (objectui#13089) Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
…jectui#13089) Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
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
|
This was referenced Oct 19, 2026
…he renderer's divergence; changeset levels minor (objectui#13089) The description, README and mdx no longer present "top" as the default: the spec row declares enabled true and position bottom, the renderer reads only an explicit enabled: true and puts an absent position at the top, and objectui#13099 owns the gap. plugin-list and app-shell bump minor. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
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
|
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 #13089
Clause-②: yes
What this changes
A page
list-viewnode'saddRecordAdd button now opens the create form that the object list opens.list-view.addRecordis published. The console's object list no longer draws a dead Add button.Page host (
pageRecordActions.tspageRelatedHandlers). Under the seat ruling on the card (Q1 = A), the input's shape decides what is served.relationshipField(absent or empty) and noparentId. This is a pagelist-viewnode, which resolves{ objectName }. It is served the bridge's create pair,onCreate/createDisabled, and nothing else.relationshipField. It is still served nothing, so it draws no "+ New". That button would have opened a child form linked to no parent.Contract (
@object-ui/react,ResolveRelatedRecordActionsInputdocblock only, no type or member change). The docblock says what an input withoutrelationshipFieldasks for. The spec'srecord:related_listrequiresrelationshipField, so a spec-valid related list always names one. The docblock also names the limit of this reading: a future consumer that must not create needs an explicit member.editMode: 'page'(ruling 6).RelatedRecordActionsBridgeopenChildFormgets one branch. A create linked to no parent now goes toresolveRecordFormTarget, the resolverAppContent'shandleEdituses. For aneditMode: 'page'object it navigates to the full-page create route, as the object list does; otherwise it opens the overlay as before.Console object list (item 2,
ObjectView.tsxrenderListView). It forwardedaddRecordand noonAddRecord. The Add button now calls the header New's create (actions.create, which isonEdit(null)). It is offered only where the New is offered and not greyed:objectCanCreate && createVisible && !createDisabled.Publishing (
plugin-list).addRecordjoinsLIST_VIEW_INPUTS(shared bylist-viewandlist). Its description says what is read:enabledandposition;modeandformVieware not read. It also says what the click opens. TheUNPUBLISHED_EXEMPTIONSrow is struck and aMEMBER_PINSentry points at the real-PageViewpin. The README, the mdx and the stale docblocks are updated.Changeset (
.changeset/13089-page-list-create.md):@object-ui/plugin-listminor(a published registry input, as objectui#13074 did),@object-ui/app-shellminor(a page-host capability and a new create route),@object-ui/reactpatch(docblock only). These levels were set in the patch round3b8fab4ff1after the contract review.Measured before changing (each leg is a run, not a reading)
record:related_listprobe. When the create pair was served to every parent-less resolve, the probe drewrelated-list-new(4/4 green). Onorigin/mainthe same probe was red: 1 failed, 3 passed.ObjectView.addRecordOpensCreate-13089.test.tsxran on the base before the fix:Tests 2 failed | 1 passed (3).onEdit0 times.Tests 3 passed (3).editMode: 'page'case stayed at/apps/cloud/page/team(overlay params) before theopenChildFormbranch:expected '/apps/cloud/page/team' to be '/apps/cloud/sys_contract/new'. It is green after the branch.Pins
packages/app-shell/src/views/__tests__/PageView.listViewAddRecord-13089.test.tsxruns through the realPageView, the real console action runtime, and theplugin-listandplugin-detailregistrations.form=newandformObject=sys_member, with noformLink. AneditMode: 'page'object navigates to/apps/cloud/sys_contract/new.createDisabledcreate (userActions.create.disabledWhen).addRecorddraws no button.list-viewbeside it is served.relationshipField) getsonCreateonly: no Edit, Delete, row click, "View all" or executor. An unbound related list gets nothing. Bound getsonRowAction,onToolbarAction.addRecord. The parity row is struck and the member pin is green.ObjectView.addRecordOpensCreate-13089.test.tsx: the Add button and the header New make the sameonEdit(null)call. Without a create grant there is no Add button. A view withoutaddRecorddraws no Add button.Rewritten to the new fact:
resolve({ objectName })equals{}on a page. It now asserts nothing for a related-list input andonCreatealone for an object-scoped one.addRecordto be published.Ablations
Each ablation used
ablation-replace.mjs. Each mutation was proven on disk (anchor x1 to x0), and each restore was proven by blob hash:47fc21a275c6equals HEAD, andgit diff HEADis empty.onCreateserving (if (!onCreate)becomes always return). Result: 4 failed, 6 passed. Red: (a), theeditModecase, the unbound-related-list control (thelist-viewbeside it is no longer served) and the served-set control.return related.resolve(input)). Result: 1 failed, the served-set control. It receivedonCreate,onDelete,onEdit,onRowAction,onToolbarAction,onView,rowActions,toolbarActions.relationshipFieldcondition. Result: 2 failed. The unbound related list draws "+ New", and the probe's unbound-related row readsonCreate.Gates
Final head
1fbb3d66ac, basecd4623d063. Exit codes were recorded to files.pnpm --filter '@object-ui/app-shell^...' build), then rantype-checkfor@object-ui/react,@object-ui/plugin-listand@object-ui/app-shell: VERDICT command-exit 0.apps/console(test file only): NOT MEASURED. Itstsc --noEmitcannot resolve@object-ui/app-shelland plugins whose dist this worktree did not build. That is a prerequisite failure, not a type verdict. Declared to CI.--maxWorkers=1, under the shared lock), on this head's test content:PageView.*andRelatedRecordActionsBridge.*families plus readers of the touched files: 148 passed and 1 failed. The failure was the 11293 row, rewritten above, then 6/6 passed.ObjectView*files: 633/633.addRecordreaders, and the plugin-detail, plugin-form and components readers of the bridge: 445 passed and 1 failed. The failure was the 13074 registration row, rewritten above, then 15/15 passed.app-shell,plugin-list,react,apps/console) are declared to CI.pnpm lint, narrowed to the 12 changed.ts/.tsxfiles witheslint --no-inline-config --format json: 0 errors. The 203 warnings are almost all on pre-existing lines ofObjectView.tsx/RelatedRecordActionsBridge.tsx. One newno-explicit-anywarning is on theobjects.find((o: any)lookup inopenChildForm, the pattern the file already uses.check:phantom-deps,self-import,unreferenced-sources,doc-example-readers,handler-key-reads,side-effects-array,element-data-source-declaration,spec-symbols,action-forward-parity,designer-field-key-parity,icon-record-names,i18n-keys,i18n-drift,i18n-designer-parity,control-bytes,new-line-citations, pluscheck-hand-rolled-comment-mask,check-changeset-fixedandcheck-changeset-presence).check:spec-floorsexits 1, as on main; recorded, not fixed.Acceptance notes
openChildFormbranch keys on "create with no link", so it also covers a record page's related list whose parent link value is still null (itsonCreatealready sends noformLink). For aneditMode: 'page'object that create now goes to the full-page route and not the overlay. It is the same object-level create either way.userActions.create.visibleWhen/disabledWhenagainst no parent record, as the object list evaluates them againstnull. A predicate that readsrecord.*fails closed forvisibleWhen, so the Add button is withheld. Observation only.AddRecordConfigdeclaresenableddefaulttrueandpositiondefault'bottom'.ListViewdraws the button only for an explicitenabled: trueand places an absentpositionat the top. The contract review measured that neither the write door nor the client materialises the nested defaults. The published description, README and mdx now name the declared defaults and the divergence, and cite objectui#13099, which carries the enforce-or-remove decision. The renderer is unchanged here.Writes
Branch pushes, this draft PR (with the card's assignee), and one
os-dev-reportcomment on the card. No labels: no objectui gate reads one, and the dispatch named none.Implemented by the os-dev run in session
https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB.Generated by Claude Code