You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit ab0bc89
Browse filesBrowse the repository at this point in the historyBrowse files
docs(spec): onSuccess.navigate and a url target say an in-app path is an app-qualified console route (#25458) (#26435)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBErsDvMNeedf4Bt2ucCK9Yt)_Fixes#25458
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么:** 只改说明文字。`onSuccess.navigate` 与 `type: 'url'` 动作的 `target`
现在写明:应用内路径是控制台路由,记录页是 `/apps/APP/OBJECT/record/ID`,APP 是应用的路由段(包
id,应用名也能解析);规范里的示例与协议文档的示例同步改正。
- **为什么改:** 原文只说「以 `/` 开头的应用内路径」,没说要带应用段,作者照写 `/crm_opportunity/ID`
就走偏了;hotcrm#2247 裁决 C 第 2(b) 项要求把这一点写清楚,且不新增写法。
- **风险与回滚:** 零运行时风险,schema 接受与拒绝的取值完全不变,只有 describe
文本、生成的参考文档和一页手写文档变了;回滚即 revert 本 PR。
- **先看:** `packages/spec/src/ui/action.zod.ts`(onSuccess 文档块新增的 console
route 一段,以及 `navigate` 的
describe)、`content/docs/protocol/objectui/actions.mdx`(URL Actions
一节)、`.changeset/25458-navigate-console-route.md`。
- **两分钟验证:** 在本分支跑 `grep -n "console route"
packages/spec/src/ui/action.zod.ts`,预期 4 处命中(target 的文档块与
describe、onSuccess 的文档块与 navigate 的 describe)。
- **需要你做的:** 无,席位落地。
## What changes
Wording only, on the route ruling C on objectstack-ai/hotcrm#2247
ordered as item 2(b). No schema accepts or refuses anything it did not
before; no new authorable form (no `${ctx.app}` member, no
object-plus-record target).
- `packages/spec/src/ui/action.zod.ts`, `onSuccess` docblock: a new
paragraph says that an in-app path is a console route, written without
the console's mount prefix (`/_console` under the framework CLI). The
record page is `/apps/APP/OBJECT/record/ID`, and the object's list is
`/apps/APP/OBJECT`. `APP` is the app's route segment (ADR-0048): its
package id, e.g. `app.objectstack.hotcrm`. The app's `name` resolves
too, and it is the only segment that reaches an app other than the first
in a package that ships several. A `./` path resolves against the
current route. The contract declares no app-relative form, so write the
app segment.
- Same docblock: the example `navigate: '/apps/crm/tasks/${result.id}'`
becomes `'/apps/crm/tasks/record/${result.id}'`. The old one worked only
through the console's shorthand redirect, which fires only when the last
segment looks like a record id.
- `onSuccess.navigate` `.describe()`: the same facts in one sentence
after the scheme set.
- `target` docblock and `.describe()` (the `type: 'url'` scheme set): an
in-app path is a console route, and a record is
`/apps/APP/OBJECT/record/ID`. It points to `onSuccess.navigate` for what
`APP` is, so the explanation lives in one place.
- `content/docs/protocol/objectui/actions.mdx`, URL Actions: the same
sentence. The example `target: /_console/dashboards/sales_overview`
becomes `/apps/crm/dashboard/sales_overview`. The old one carried the
mount prefix the router adds itself, and the console has no `dashboards`
route at the root; the dashboard route is `dashboard/:dashboardName`
under `/apps/:appName/*`.
- Regenerated with `gen:schema && gen:docs`:
`content/docs/references/ui/action.mdx`, `ui/component.mdx`,
`data/object.mdx` and `kernel/metadata-plugin.mdx` (the last three embed
`ActionSchema`'s `target`).
- `.changeset/25458-navigate-console-route.md`: `'@objectstack/spec':
patch`.
The console's routes, quoted from `main` at `9a0108cd`:
- `ui/apps/console/src/App.tsx:332`, the app mount: `Route
path="/apps/:appName/*" element={AppContent}`.
- `ui/packages/app-shell/src/console/AppContent.tsx:1443`, the record
route inside it: `Route path=":objectName/record/:recordId"`. At `:1478`
is the shorthand `":objectName/:maybeRecordId"`, which redirects only
when `looksLikeRecordId` holds (at least 6 URL-safe characters, not a
reserved second segment).
- `ui/packages/app-shell/src/utils/appRoute.ts:46`, `appRouteSegment`:
the package id `_packageId`, falling back to `name`. `matchAppBySegment`
matches the package id first and then the name.
## Tests
Head `a7e78c3d`.
- `pnpm --filter @objectstack/spec build`: lock VERDICT command-exit 0.
- `pnpm --filter @objectstack/spec test`: Test Files 727 passed (727),
Tests 22009 passed, 1 todo (22010). Lock VERDICT command-exit 0.
- Targeted: `src/ui/action.test.ts`, `src/ui/action-on-success.test.ts`
and `src/ui/action-url-target-scheme-set.test.ts` pass, 322 tests.
- `pnpm --filter @objectstack/spec check:generated`: exit 0, all 14
generated artifacts up to date.
- No ablation: the diff changes describe text and docs, not a behaviour
a test pins.
## Acceptance notes
- **The card's premise is partly stale.** objectui#13379, the console
half, landed when objectui moved into `ui/`.
`ui/packages/app-shell/src/utils/hostInConsolePath.ts` is wired into
`useConsoleActionRuntime.tsx` and `RecordDetailView.tsx`. On `main`
today, a rooted path whose first segment names no console route, such as
`/crm_opportunity/${result.id}`, is hosted under the app the user is in.
It no longer redirects Home. The wording does not promise that
behaviour: the triage line and the dispatch exclude an app-relative
form. The docblock names it as the console's accommodation and not a
form the schema promises. The description and its example now match what
the console does for the form they teach.
- The same scheme-set sentence ("an in-app path starting with / or ./")
also appears outside this card's file surface and is left unchanged:
`packages/spec/src/ui/dashboard.zod.ts` (`actionUrl`, ~:143/:151),
`packages/spec/src/ui/view.zod.ts` (the empty-state link url, ~:1971)
and `packages/spec/src/ui/component.zod.ts` (the action row's `target`
and `onSuccess`, ~:4066, :4085, :4166). This is noted here and not filed
as a card; carrier: none.
- `skills/objectstack-ui/rules/actions.md:71` already writes the
app-qualified record route (`/apps/crm/opportunity/record/...`). It
agrees with the new text and is untouched (governed surface).
- Both docblocks still cite the console's classifier as
`navigation-target.ts`. The file today is
`ui/packages/core/src/actions/navigationTarget.ts`. This is a naming
drift outside the wording asked for here; noted, not touched.
## Verification
<details><summary>dispatch-gates (head a7e78c3)</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`: 100 derived commands over 7 changed paths,
56 changed lines.
The first pass gave 93 exit 0 and 7 exit 3 (PREREQUISITE NOT MET). I
then built the closures `@objectstack/lint...`,
`@objectstack/objectql...` and `@objectstack/client-react...` (turbo, 37
of 37 tasks; lock VERDICT command-exit 0) and ran `git fetch --unshallow
origin main`. After that, six of the seven re-ran to exit 0:
`check-plugin-teardown-shape.mjs --self-test`,
`check:doc-formula-expressions`, `check:doc-security-posture`,
`check:skill-examples`, `check:docs-transcript-drift` and
`check:lean-entry-closure`.
NOT MEASURED: `pnpm check:dual-build-cjs-loads`, exit 3. It needs every
workspace package's `dist` (a full `pnpm build`), so I left it to CI.
`--ran` reconciliation: `✓ dispatch-gates --ran: 100 derived famil(ies)
accounted for — 99 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit
3).`
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01WGufzi6gpRSxJRE6UzJn2x)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
docs(spec): `onSuccess.navigate` and a `type: 'url'` action's `target` say that an in-app path is an app-qualified console route (`/apps/APP/OBJECT/record/ID`) (#25458)
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
Wording only; no schema accepts or refuses anything new. The describe text of `ActionSchema.onSuccess.navigate` and of `ActionSchema.target` said "an in-app path starting with / or ./" and never said which path. They now say that an in-app path is a console route, written without the console's mount prefix, and that a record is `/apps/APP/OBJECT/record/ID`. `APP` is the app's route segment (ADR-0048): its package id, and its `name` also resolves. No app-relative form is declared and no `${ctx.*}` member names the current app, so write the app segment. The docblock example `/apps/crm/tasks/${result.id}` becomes `/apps/crm/tasks/record/${result.id}`, the route it was only redirected to.
Copy file name to clipboardExpand all lines: content/docs/protocol/objectui/actions.mdx
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -88,11 +88,13 @@ body:
88
88
89
89
Navigate to an internal route or external URL. `target` supports `${param.X}` and `${ctx.X}` interpolation (renderers `encodeURIComponent` interpolated values before substituting them into query positions).
90
90
91
+
An internal route is a console route, written without the console's mount prefix (`/_console` under the framework CLI; the router adds it). Object, record and dashboard routes carry the app segment: a record is `/apps/APP/OBJECT/record/ID`, where `APP` is the app's route segment, its package id (its `name` also resolves). No app-relative form is declared, so write the app segment. The same holds for an action's `onSuccess.navigate`.
|**type**|`Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>`| optional (default: `"script"`) | Action functionality type — the dispatch route. The declarative single-record field write is not a type: it is `operation: 'update'` + `patch` on the default `script` route. |
492
-
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ — every other scheme and a protocol-relative //host are refused. |
492
+
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (a console route; a record is /apps/APP/OBJECT/record/ID, APP being the app's route segment — see onSuccess.navigate) — every other scheme and a protocol-relative //host are refused. |
493
493
|**openIn**|`Enum<'self' \| 'new-tab'>`| optional | For type:'url' — where to open `target`. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of `params` (which is user-input-collection only). |
494
494
|**body**|`{ language: 'expression'; source: string } \| { language: 'js'; source: string; capabilities?: Enum<'api.read' \| 'api.write' \| 'api.transaction' \| 'crypto.uuid' \| 'log'>[]; timeoutMs?: integer; … }`| optional | Action body — expression (L1) or sandboxed JS (L2). Only used when type is `script`. |
495
495
|**operation**|`Enum<'update'>`| optional | The declarative single-record field write, mirroring a list view's `bulkActionDefs`: `'update'` applies `patch` (merged under the collected `params`) to the current record on the data plane AS THE CALLER — never system-elevated — so the caller's permissions, the object's hooks and its validations fire as for a user edit. `type` stays at its default `'script'` (the platform action route the write is performed on); `target`/`body`/`method`/`bodyExtra` are refused beside it. `'delete'` and `'custom'` have no row-level form. |
|**type**|`Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>`| optional (default: `"script"`) | Action functionality type — the dispatch route. The declarative single-record field write is not a type: it is `operation: 'update'` + `patch` on the default `script` route. |
325
-
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ — every other scheme and a protocol-relative //host are refused. |
325
+
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (a console route; a record is /apps/APP/OBJECT/record/ID, APP being the app's route segment — see onSuccess.navigate) — every other scheme and a protocol-relative //host are refused. |
326
326
|**openIn**|`Enum<'self' \| 'new-tab'>`| optional | For type:'url' — where to open `target`. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of `params` (which is user-input-collection only). |
327
327
|**body**|`{ language: 'expression'; source: string } \| { language: 'js'; source: string; capabilities?: Enum<'api.read' \| 'api.write' \| 'api.transaction' \| 'crypto.uuid' \| 'log'>[]; timeoutMs?: integer; … }`| optional | Action body — expression (L1) or sandboxed JS (L2). Only used when type is `script`. |
328
328
|**operation**|`Enum<'update'>`| optional | The declarative single-record field write, mirroring a list view's `bulkActionDefs`: `'update'` applies `patch` (merged under the collected `params`) to the current record on the data plane AS THE CALLER — never system-elevated — so the caller's permissions, the object's hooks and its validations fire as for a user edit. `type` stays at its default `'script'` (the platform action route the write is performed on); `target`/`body`/`method`/`bodyExtra` are refused beside it. `'delete'` and `'custom'` have no row-level form. |
|**type**|`Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>`| optional (default: `"script"`) | Action functionality type — the dispatch route. The declarative single-record field write is not a type: it is `operation: 'update'` + `patch` on the default `script` route. |
39
-
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ — every other scheme and a protocol-relative //host are refused. |
39
+
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (a console route; a record is /apps/APP/OBJECT/record/ID, APP being the app's route segment — see onSuccess.navigate) — every other scheme and a protocol-relative //host are refused. |
40
40
|**openIn**|`Enum<'self' \| 'new-tab'>`| optional | For type:'url' — where to open `target`. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of `params` (which is user-input-collection only). |
41
41
|**body**|`{ language: 'expression'; source: string } \| { language: 'js'; source: string; capabilities?: Enum<'api.read' \| 'api.write' \| 'api.transaction' \| 'crypto.uuid' \| 'log'>[]; timeoutMs?: integer; … }`| optional | Action body — expression (L1) or sandboxed JS (L2). Only used when type is `script`. |
42
42
|**operation**|`Enum<'update'>`| optional | The declarative single-record field write, mirroring a list view's `bulkActionDefs`: `'update'` applies `patch` (merged under the collected `params`) to the current record on the data plane AS THE CALLER — never system-elevated — so the caller's permissions, the object's hooks and its validations fire as for a user edit. `type` stays at its default `'script'` (the platform action route the write is performed on); `target`/`body`/`method`/`bodyExtra` are refused beside it. `'delete'` and `'custom'` have no row-level form. |
@@ -178,7 +178,7 @@ L2 sandboxed JS body — runs inside an isolated VM with declared capabilities
178
178
179
179
| Property | Type | Required | Description |
180
180
| :--- | :--- | :--- | :--- |
181
-
|**navigate**|`string`| ✅ | Route/URL template navigated to after the action succeeds. Interpolates $`{param.*}` (params-dialog values), $`{ctx.*}` (origin/apiBase/user/org/recordId/selection) and $`{result.*}` (the action's server response payload — NEW with this key, e.g. $`{result.id}`; on a type:'flow' action the completed run's answer, whose `output` carries the flow's isOutput variables, e.g. $`{result.output.renewal.id}`). An http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (an SPA route hop); a template that opens with ${ is judged after interpolation. Every other scheme and a protocol-relative //host are refused. Renderers MUST encodeURIComponent values in query positions. |
181
+
| **navigate** | `string` | ✅ | Route/URL template navigated to after the action succeeds. Interpolates $`{param.*}` (params-dialog values), $`{ctx.*}` (origin/apiBase/user/org/recordId/selection) and $`{result.*}` (the action's server response payload — NEW with this key, e.g. $`{result.id}`; on a type:'flow' action the completed run's answer, whose `output` carries the flow's isOutput variables, e.g. $`{result.output.renewal.id}`). An http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (an SPA route hop); a template that opens with ${ is judged after interpolation. Every other scheme and a protocol-relative //host are refused. An in-app path is a console route, written without the console's mount prefix; a record is /apps/APP/OBJECT/record/ID, where APP is the app's route segment (its package id; its name also resolves). No app-relative form is declared and no $`{ctx.*}` member names the current app, so write the app segment. Renderers MUST encodeURIComponent values in query positions. |
182
182
|**openIn**|`Enum<'self' \| 'newTab'>`| optional (default: `"self"`) | Where to perform the post-success navigation: 'self' (default — in-place SPA navigation, immune to popup blocking) or 'newTab'. Closed enum — no general navigation DSL. |
183
183
184
184
@@ -340,7 +340,7 @@ L2 sandboxed JS body — runs inside an isolated VM with declared capabilities
340
340
|**type**|`Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>`| optional (default: `"script"`) | Action functionality type — the dispatch route. The declarative single-record field write is not a type: it is `operation: 'update'` + `patch` on the default `script` route. |
341
341
|**name**|`string`| optional | Machine name (lowercase snake_case) |
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ — every other scheme and a protocol-relative //host are refused. |
343
+
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (a console route; a record is /apps/APP/OBJECT/record/ID, APP being the app's route segment — see onSuccess.navigate) — every other scheme and a protocol-relative //host are refused. |
344
344
|**openIn**|`Enum<'self' \| 'new-tab'>`| optional | For type:'url' — where to open `target`. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of `params` (which is user-input-collection only). |
345
345
|**method**|`Enum<'POST' \| 'PATCH' \| 'PUT' \| 'DELETE'>`| optional | HTTP method for type:"api" actions. Defaults to POST. |
346
346
|**params**|`{ name?: string; field?: string; objectOverride?: string; label?: string \| Record<string, string>; … }[]`| optional | Input parameters required from user — an ActionParam[] DEFINITION array, never a payload map (a static request body goes in `bodyExtra`). |
Copy file name to clipboardExpand all lines: content/docs/references/ui/component.mdx
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -61,7 +61,7 @@ const result = ActionButtonPropsSchema.parse(data);
61
61
62
62
| Property | Type | Required | Description |
63
63
| :--- | :--- | :--- | :--- |
64
-
|**navigate**|`string`| ✅ | Route/URL template navigated to after the action succeeds. Interpolates $`{param.*}` (params-dialog values), $`{ctx.*}` (origin/apiBase/user/org/recordId/selection) and $`{result.*}` (the action's server response payload — NEW with this key, e.g. $`{result.id}`; on a type:'flow' action the completed run's answer, whose `output` carries the flow's isOutput variables, e.g. $`{result.output.renewal.id}`). An http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (an SPA route hop); a template that opens with ${ is judged after interpolation. Every other scheme and a protocol-relative //host are refused. Renderers MUST encodeURIComponent values in query positions. |
64
+
| **navigate** | `string` | ✅ | Route/URL template navigated to after the action succeeds. Interpolates $`{param.*}` (params-dialog values), $`{ctx.*}` (origin/apiBase/user/org/recordId/selection) and $`{result.*}` (the action's server response payload — NEW with this key, e.g. $`{result.id}`; on a type:'flow' action the completed run's answer, whose `output` carries the flow's isOutput variables, e.g. $`{result.output.renewal.id}`). An http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (an SPA route hop); a template that opens with ${ is judged after interpolation. Every other scheme and a protocol-relative //host are refused. An in-app path is a console route, written without the console's mount prefix; a record is /apps/APP/OBJECT/record/ID, where APP is the app's route segment (its package id; its name also resolves). No app-relative form is declared and no $`{ctx.*}` member names the current app, so write the app segment. Renderers MUST encodeURIComponent values in query positions. |
65
65
|**openIn**|`Enum<'self' \| 'newTab'>`| optional (default: `"self"`) | Where to perform the post-success navigation: 'self' (default — in-place SPA navigation, immune to popup blocking) or 'newTab'. Closed enum — no general navigation DSL. |
66
66
67
67
@@ -153,7 +153,7 @@ const result = ActionButtonPropsSchema.parse(data);
153
153
154
154
| Property | Type | Required | Description |
155
155
| :--- | :--- | :--- | :--- |
156
-
|**navigate**|`string`| ✅ | Route/URL template navigated to after the action succeeds. Interpolates $`{param.*}` (params-dialog values), $`{ctx.*}` (origin/apiBase/user/org/recordId/selection) and $`{result.*}` (the action's server response payload — NEW with this key, e.g. $`{result.id}`; on a type:'flow' action the completed run's answer, whose `output` carries the flow's isOutput variables, e.g. $`{result.output.renewal.id}`). An http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (an SPA route hop); a template that opens with ${ is judged after interpolation. Every other scheme and a protocol-relative //host are refused. Renderers MUST encodeURIComponent values in query positions. |
156
+
| **navigate** | `string` | ✅ | Route/URL template navigated to after the action succeeds. Interpolates $`{param.*}` (params-dialog values), $`{ctx.*}` (origin/apiBase/user/org/recordId/selection) and $`{result.*}` (the action's server response payload — NEW with this key, e.g. $`{result.id}`; on a type:'flow' action the completed run's answer, whose `output` carries the flow's isOutput variables, e.g. $`{result.output.renewal.id}`). An http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (an SPA route hop); a template that opens with ${ is judged after interpolation. Every other scheme and a protocol-relative //host are refused. An in-app path is a console route, written without the console's mount prefix; a record is /apps/APP/OBJECT/record/ID, where APP is the app's route segment (its package id; its name also resolves). No app-relative form is declared and no $`{ctx.*}` member names the current app, so write the app segment. Renderers MUST encodeURIComponent values in query positions. |
157
157
|**openIn**|`Enum<'self' \| 'newTab'>`| optional (default: `"self"`) | Where to perform the post-success navigation: 'self' (default — in-place SPA navigation, immune to popup blocking) or 'newTab'. Closed enum — no general navigation DSL. |
158
158
159
159
@@ -228,7 +228,7 @@ const result = ActionButtonPropsSchema.parse(data);
228
228
|**type**|`Enum<'script' \| 'url' \| 'modal' \| 'flow' \| 'api' \| 'form'>`| optional (default: `"script"`) | Action functionality type — the dispatch route. The declarative single-record field write is not a type: it is `operation: 'update'` + `patch` on the default `script` route. |
229
229
|**name**|`string`| optional | Machine name (lowercase snake_case) |
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ — every other scheme and a protocol-relative //host are refused. |
231
+
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. For type:'url': an http:// or https:// URL, a mailto: address, or an in-app path starting with / or ./ (a console route; a record is /apps/APP/OBJECT/record/ID, APP being the app's route segment — see onSuccess.navigate) — every other scheme and a protocol-relative //host are refused. |
232
232
|**openIn**|`Enum<'self' \| 'new-tab'>`| optional | For type:'url' — where to open `target`. 'new-tab' opens a new browser tab; 'self' navigates in place. When omitted, external/absolute URLs open in a new tab and relative URLs navigate in place. Static execution option — keep it OUT of `params` (which is user-input-collection only). |
233
233
|**method**|`Enum<'POST' \| 'PATCH' \| 'PUT' \| 'DELETE'>`| optional | HTTP method for type:"api" actions. Defaults to POST. |
234
234
|**params**|`{ name?: string; field?: string; objectOverride?: string; label?: string \| Record<string, string>; … }[]`| optional | Input parameters required from user — an ActionParam[] DEFINITION array, never a payload map (a static request body goes in `bodyExtra`). |
0 commit comments