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
feat(spec): element:button declares the action it executes — InlineActionSchema (objectui#2997) (#4135)
element:button's renderer reads `properties.action` and dispatches it
through the ActionRunner — it is the only thing making a standalone-page
button interactive — and ElementButtonPropsSchema did not declare it.
It is authored anyway: cloud's service-tenant pages carry five sites across
the billing and pricing funnel, each `{type:'navigation', to: …}`, each cast
`as any`.
An undeclared prop is STRIPPED, not ignored — safeParse returned success
with no `action` in `data`. Harmless only because page block `properties`
are still z.record(z.string(), z.unknown()); the moment that is tightened
to validate against ComponentPropsMap, every one of those buttons loses its
action at save with a green parse.
InlineActionSchema is derived, not a new dialect. ActionSchema is
z.object(…).refine(…).refine(…), so `.pick()` is unavailable on the export;
the object half is now a factory both build from, preserving lazySchema's
deferral. The inline schema picks the twelve fields element:button actually
forwards, sharing their describe() text, the ActionType vocabulary and the
target-required refinement.
`name`/`label` are optional — a registry entry needs an identity and a menu
label, an inline action has neither (the button supplies its own label).
Registry-only concerns are excluded, as are icon/variant (the button has its
own) and body (a page button running a sandboxed script is a separate
decision).
`navigation` and `to` become normalizing aliases folding to `url`/`target`,
the VIEW_FILTER_OPERATOR_ALIASES pattern: cloud's pages keep validating
while output is always canonical, and the aliases can be tombstoned once
producers migrate. `url` is also the better target — its runner path has
${param} interpolation, apiBase promotion and popup-safe openIn; the
navigation path has none of those.
NOT done: promoting `navigation` into ActionType bare (declined in #4070) —
it names the type while leaving the prop undeclared and `to` homeless, and
adds a permanent synonym to a vocabulary whose members cannot be removed.
Nothing narrowed; all generated surfaces gain entries only. spec suite
7038/271 green, tsc clean, all twelve check:* gates pass.
Refs objectstack-ai/objectui#2997, objectstack-ai/objectui#2945, #4070
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
|**name**|`string`| optional | Machine name (lowercase snake_case) |
200
+
|**label**|`string`| optional | Display label |
201
+
|**target**|`string`| optional | URL, Script Name, Flow ID, or API Endpoint. Supports $`{param.X}` and $`{ctx.X}` interpolation. |
202
+
|**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). |
203
+
|**method**|`Enum<'POST' \| 'PATCH' \| 'PUT' \| 'DELETE'>`| optional | HTTP method for type:"api" actions. Defaults to POST. |
204
+
|**params**|`{ name?: string; field?: string; objectOverride?: string; label?: string; … }[]`| optional | Input parameters required from user |
205
+
|**confirmText**|`string`| optional | Confirmation message before execution |
206
+
|**successMessage**|`string`| optional | Success message to show after execution |
207
+
|**errorMessage**|`string`| optional | Error message to show when the action fails (overrides the raw error). |
208
+
|**refreshAfter**|`boolean`| optional | Refresh view after execution |
209
+
|**opensInNewTab**|`boolean`| optional | Open the action result in a new tab. The renderer pre-opens the tab synchronously on click (popup-blocker-safe) and navigates it to the handler's redirectUrl. |
0 commit comments