diff --git a/docs/web/workspaces.md b/docs/web/workspaces.md index 57f1e4e1b145..1cfcaa372957 100644 --- a/docs/web/workspaces.md +++ b/docs/web/workspaces.md @@ -65,6 +65,11 @@ lists only pending entries from the Workspaces custom-widget registry. Its Appro Reject controls are disabled unless the current connection holds `operator.approvals`; it does not expose exec, plugin, or system-agent approvals. +Tabs use the 12-column widget grid by default. A tab containing zero or one widget can +instead use the `full` layout, which removes the widget card chrome and lets the widget +fill the tab. Switch layouts with `openclaw workspaces tabs full ` and +`openclaw workspaces tabs grid `. + Widgets declare data through **bindings**, they never fetch on their own: | Binding | Resolves to | @@ -110,6 +115,7 @@ per-invocation confirmation quoting the exact text, and passes a rate limit. ```sh openclaw workspaces tabs list openclaw workspaces tabs create --title Financials +openclaw workspaces tabs full financials openclaw workspaces widget-scaffold revenue-chart --title "Revenue Chart" openclaw workspaces widget-approve revenue-chart ``` diff --git a/extensions/workspaces/src/cli.ts b/extensions/workspaces/src/cli.ts index c11fb256c997..c9b6cce5abd3 100644 --- a/extensions/workspaces/src/cli.ts +++ b/extensions/workspaces/src/cli.ts @@ -287,6 +287,21 @@ export function registerWorkspaceCli(options: RegisterWorkspaceCliOptions): void }); } + for (const [verb, tabLayout] of [ + ["grid", "grid"], + ["full", "full"], + ] as const) { + addGatewayOptions( + tabs.command(verb).argument("", "Tab slug").description(`Use ${tabLayout} layout`), + ).action(async (slug: string, commandOptions: GatewayOptions) => { + const result = await callWorkspaceGateway("workspaces.tab.update", commandOptions, { + slug, + patch: { layout: tabLayout }, + }); + writeTabs(readWorkspaceResult(result).doc, commandOptions); + }); + } + addGatewayOptions( widgets .command("list") diff --git a/extensions/workspaces/src/gateway.ts b/extensions/workspaces/src/gateway.ts index 032f0c5784bf..0affa054f25e 100644 --- a/extensions/workspaces/src/gateway.ts +++ b/extensions/workspaces/src/gateway.ts @@ -276,8 +276,10 @@ function readRequiredBoolean(record: Record, key: string): bool return value; } -function readTabPatch(value: unknown): Partial> { - const patch = readParams(value, ["title", "icon", "hidden"]); +function readTabPatch( + value: unknown, +): Partial> { + const patch = readParams(value, ["title", "icon", "hidden", "layout"]); const title = readOptionalString(patch, "title"); if (title !== undefined && (title.length < 1 || title.length > 80)) { throw new Error("patch.title must be 1-80 characters"); @@ -287,10 +289,15 @@ function readTabPatch(value: unknown): Partial