From 46ae4ef62b62d6d8951928bb846f79744dc90aa1 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Fri, 12 Jun 2026 18:20:58 +0500 Subject: [PATCH] feat(spec): ActionSchema gains opensInNewTab + newTabUrl zero-roundtrip contract Documents the existing opensInNewTab renderer behavior in the schema and adds newTabUrl: a direct new-tab URL template ({recordId} placeholder) the renderer navigates the pre-opened tab to immediately on click, skipping the action POST. The target endpoint must enforce all auth/authz itself (e.g. the cloud /sso-open endpoint, which re-runs every check the POST half would have done). Removes one full network round trip of white-screen latency from click-to-popup on actions like sys_environment sso_as_owner. Co-Authored-By: Claude Fable 5 --- packages/spec/src/ui/action.zod.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/spec/src/ui/action.zod.ts b/packages/spec/src/ui/action.zod.ts index 3b7f4cd8d0..5079c40fad 100644 --- a/packages/spec/src/ui/action.zod.ts +++ b/packages/spec/src/ui/action.zod.ts @@ -421,6 +421,25 @@ export const ActionSchema = lazySchema(() => z.object({ */ mode: z.enum(['create', 'edit', 'delete', 'custom']).optional().describe('Semantic mode of the action.'), + /** + * Open the action's result in a NEW TAB. The renderer pre-opens the tab + * synchronously on click (preserving the user gesture so popup blockers + * don't fire), paints a progress page, then drives the tab to the + * handler's returned `redirectUrl` — or, when `newTabUrl` is set, straight + * to that URL with no server round trip. + */ + opensInNewTab: z.boolean().optional().describe('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.'), + + /** + * Zero-roundtrip new-tab target. A path template the renderer navigates + * the pre-opened tab to IMMEDIATELY on click, skipping the action POST + * entirely. Only valid together with `opensInNewTab`. The target endpoint + * MUST perform all auth/authz itself (e.g. the cloud `/sso-open` endpoint, + * which re-runs every check the POST half would have done). Supports the + * `{recordId}` placeholder, URL-encoded on substitution. + */ + newTabUrl: z.string().optional().describe('Direct new-tab URL template ({recordId} placeholder). When set with opensInNewTab, the renderer navigates the pre-opened tab here immediately — no action POST. The endpoint must enforce auth itself.'), + /** Execution */ timeout: z.number().optional().describe('Maximum execution time in milliseconds for the action'),