Skip to content

Commit 110c699

Browse files
os-zhuangclaude
andcommitted
fix(spec): render action body as composite, not a flat code editor
An action's `body` is a discriminated union (HookBodySchema: `{ language, source, capabilities?, timeoutMs? }`), the same shape hooks use. The action form layout mapped the whole field to `{ widget: 'code' }`, so the inspector fed the union object to a single JS editor and rendered "[object Object]". Mirror the working hook.form.ts layout: a composite with a `language` select, a `source` code editor, and the L2-only capability/timeout knobs. `visibleOn: data.type == 'script'` is preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 4a3ffef commit 110c699

1 file changed

Lines changed: 20 additions & 1 deletion

File tree

packages/spec/src/ui/action.form.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,26 @@ export const actionForm = defineForm({
3030
fields: [
3131
{ field: 'target', visibleOn: "data.type != 'script'", helpText: 'URL, flow name, or API endpoint to call' },
3232
{ field: 'method', visibleOn: "data.type == 'api'", helpText: 'HTTP method (GET, POST, PUT, DELETE)' },
33-
{ field: 'body', widget: 'code', visibleOn: "data.type == 'script'", helpText: 'JavaScript code to execute' },
33+
{
34+
field: 'body',
35+
type: 'composite',
36+
visibleOn: "data.type == 'script'",
37+
helpText: 'Either an L1 expression or an L2 sandboxed JS body',
38+
// Mirrors hook.form.ts: `body` is a discriminated union
39+
// (HookBodySchema) on `language`, not a bare string. A flat
40+
// `widget: 'code'` fed the whole object to the editor and rendered
41+
// "[object Object]". Render the union as language + source (+ the
42+
// L2-only capability/timeout knobs).
43+
fields: [
44+
{ field: 'language', type: 'select', required: true, helpText: 'expression = pure formula; js = sandboxed JavaScript', options: [
45+
{ label: 'Expression (L1)', value: 'expression' },
46+
{ label: 'JavaScript (L2 sandboxed)', value: 'js' },
47+
] },
48+
{ field: 'source', type: 'code', language: 'javascript', required: true, helpText: 'Function body source — no top-level imports' },
49+
{ field: 'capabilities', type: 'tags', helpText: 'Allowed ctx APIs (api.read, api.write, crypto.uuid, log, …)' },
50+
{ field: 'timeoutMs', type: 'number', helpText: 'Per-invocation timeout (ms)' },
51+
],
52+
},
3453
{ field: 'params', type: 'repeater', helpText: 'User input parameters (show form before executing)' },
3554
{ field: 'confirmText', helpText: 'Confirmation message (e.g., "Are you sure?")' },
3655
{ field: 'successMessage', helpText: 'Success message after completion' },

0 commit comments

Comments
 (0)