From a7e6f28def7595a1fbe4bc328e301a3ea0e84468 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 01:50:59 +0000 Subject: [PATCH] docs(app-shell): page-route action examples taught the unreadable nested `action` bag (objectui#7866) `packages/app-shell/README.md` taught the `action:button` page-route triggers as `"action": { "action": "navigate_create", ... }`. Nothing reads that shape: `action-button.tsx:160,173` forwards `type: schema.actionType` and `params: schema.params` and never reads `schema.action`, so `ActionRunner.execute`'s `action.type || action.actionType || action.name` resolves to the empty string and no handler is dispatched. Both examples now hoist the handler name to `actionType` with a top-level `params`. The `navigate_edit` example additionally drops its `"recordId": "${record.id}"`: values under `params` are never template-evaluated (SchemaRenderer evaluates `properties`/`props` per-value and shallowly, `content`, and the spec's bindable top-level text keys, and `action:button` has no row in that carriage map), while `resolveNavigateEditUrl` has no context fallback for `recordId` -- so the template reached the handler verbatim and would have been URL-encoded into the route. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3 --- packages/app-shell/README.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/app-shell/README.md b/packages/app-shell/README.md index f02562b472..1304531be8 100644 --- a/packages/app-shell/README.md +++ b/packages/app-shell/README.md @@ -604,28 +604,44 @@ These routes are deep-linkable (refresh-safe), respect the browser back button, and render the same `` pipeline as the modal — so `tabbed`, `wizard`, and section configurations work in both modes. -JSON `` schemas can also trigger the page routes directly -via the action runner, regardless of the object's `editMode`: +JSON `action:button` schemas can also trigger the page routes directly +via the action runner, regardless of the object's `editMode`. The handler +name goes in `actionType` — that is the key the button renderer forwards +to the action runner as the action's type, and the runner dispatches to +the handler registered under it. Arguments go in a top-level `params` +object: ```json { "type": "action:button", "label": "New Account", - "action": { "action": "navigate_create", "params": { "objectName": "account" } } + "actionType": "navigate_create", + "params": { "objectName": "account" } } ``` +`navigate_edit` additionally needs the record to open. `params` reaches +the handler verbatim: template expressions such as `${record.id}` are not +evaluated inside `params`, and `action:button` does not inject the +surrounding row, so a declared `navigate_edit` button carries a literal +`recordId`: + ```json { "type": "action:button", "label": "Edit", - "action": { - "action": "navigate_edit", - "params": { "objectName": "account", "recordId": "${record.id}" } + "actionType": "navigate_edit", + "params": { + "objectName": "account", + "recordId": "0015e000abcd" } } ``` +For a per-row **Edit** that follows the record under the cursor, use the +list or detail view's built-in **Edit** entry point instead: under +`editMode: 'page'` it already routes to the same URL. + See [`content/docs/guide/record-edit-modes.md`](../../content/docs/guide/record-edit-modes.md) for a longer walkthrough.