@w6w/ui 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/LICENSE +21 -0
  3. package/README.md +275 -2
  4. package/dist/ActionTestForm.d.ts +76 -0
  5. package/dist/AddConnectionModal.d.ts +24 -0
  6. package/dist/AppPicker.d.ts +83 -0
  7. package/dist/CodeBlock-CZu4TFSi.cjs +15 -0
  8. package/dist/CodeBlock-CZu4TFSi.cjs.map +1 -0
  9. package/dist/CodeBlock-Dot3Pd7P.js +2889 -0
  10. package/dist/CodeBlock-Dot3Pd7P.js.map +1 -0
  11. package/dist/CodeBlock.d.ts +65 -0
  12. package/dist/CodeEditor.d.ts +42 -0
  13. package/dist/ConfirmModal-8avl9Nv8.cjs +11 -0
  14. package/dist/ConfirmModal-8avl9Nv8.cjs.map +1 -0
  15. package/dist/ConfirmModal-CD-P8mhN.js +6335 -0
  16. package/dist/ConfirmModal-CD-P8mhN.js.map +1 -0
  17. package/dist/Copyable-1niV9gUa.js +771 -0
  18. package/dist/Copyable-1niV9gUa.js.map +1 -0
  19. package/dist/Copyable-CYZU1o4X.cjs +2 -0
  20. package/dist/Copyable-CYZU1o4X.cjs.map +1 -0
  21. package/dist/JsonEditor.d.ts +60 -0
  22. package/dist/NodeConfigForm.d.ts +70 -0
  23. package/dist/ParamsForm.d.ts +56 -0
  24. package/dist/PropertyEntryForm.d.ts +56 -0
  25. package/dist/RetryPolicyFields.d.ts +18 -0
  26. package/dist/StepBuilderModal.d.ts +375 -0
  27. package/dist/TriggerFillForm.d.ts +52 -0
  28. package/dist/WaitEditor.d.ts +6 -0
  29. package/dist/WorkflowFlowEditor.d.ts +119 -0
  30. package/dist/YamlEditor.d.ts +46 -0
  31. package/dist/app-categories.d.ts +38 -0
  32. package/dist/app-pages.d.ts +111 -0
  33. package/dist/code.cjs +2 -0
  34. package/dist/code.cjs.map +1 -0
  35. package/dist/code.d.ts +29 -0
  36. package/dist/code.mjs +8 -0
  37. package/dist/code.mjs.map +1 -0
  38. package/dist/components/ApiCallsPanel.d.ts +41 -0
  39. package/dist/components/AppIcon.d.ts +25 -0
  40. package/dist/components/AuthFieldsForm.d.ts +22 -0
  41. package/dist/components/Combobox.d.ts +24 -0
  42. package/dist/components/ConfirmModal.d.ts +33 -0
  43. package/dist/components/Copyable.d.ts +51 -0
  44. package/dist/components/CopyableText.d.ts +40 -0
  45. package/dist/components/DeleteButton.d.ts +16 -0
  46. package/dist/components/EditButton.d.ts +10 -0
  47. package/dist/components/ExecutionDetail.d.ts +70 -0
  48. package/dist/components/ExecutionFilters.d.ts +59 -0
  49. package/dist/components/ExecutionList.d.ts +60 -0
  50. package/dist/components/ExecutionLogPanel.d.ts +98 -0
  51. package/dist/components/ExecutionStats.d.ts +47 -0
  52. package/dist/components/ExpressionEditorModal.d.ts +42 -0
  53. package/dist/components/ExpressionInput.d.ts +36 -0
  54. package/dist/components/ExpressionOptions.d.ts +185 -0
  55. package/dist/components/HealthStatusPill.d.ts +25 -0
  56. package/dist/components/HistoryTimeline.d.ts +56 -0
  57. package/dist/components/Icon.d.ts +34 -0
  58. package/dist/components/IconButton.d.ts +60 -0
  59. package/dist/components/InfoTip.d.ts +15 -0
  60. package/dist/components/InternalIcon.d.ts +19 -0
  61. package/dist/components/ListItem.d.ts +25 -0
  62. package/dist/components/Modal.d.ts +29 -0
  63. package/dist/components/RepoSyncIndicator.d.ts +29 -0
  64. package/dist/components/ResolvedParams.d.ts +31 -0
  65. package/dist/components/ServerResources.d.ts +47 -0
  66. package/dist/components/StepStatusPill.d.ts +51 -0
  67. package/dist/components/UptimeStrip.d.ts +56 -0
  68. package/dist/components/execution-format.d.ts +24 -0
  69. package/dist/components/expression-dom.d.ts +154 -0
  70. package/dist/components/expression-template.d.ts +86 -0
  71. package/dist/components/history-scale.d.ts +33 -0
  72. package/dist/components/icons.d.ts +41 -0
  73. package/dist/components/resolved-clip.d.ts +42 -0
  74. package/dist/components/server-resources-format.d.ts +68 -0
  75. package/dist/components/server-resources.fixture.d.ts +9 -0
  76. package/dist/components/use-copy.d.ts +14 -0
  77. package/dist/createW6WApi.d.ts +31 -0
  78. package/dist/flow-connect.d.ts +138 -0
  79. package/dist/flow-fanout.d.ts +15 -0
  80. package/dist/flow-types.d.ts +356 -0
  81. package/dist/flow-utils.d.ts +284 -0
  82. package/dist/flow.cjs +3 -0
  83. package/dist/flow.cjs.map +1 -0
  84. package/dist/flow.d.ts +24 -0
  85. package/dist/flow.mjs +1978 -0
  86. package/dist/flow.mjs.map +1 -0
  87. package/dist/index.cjs +2 -0
  88. package/dist/index.cjs.map +1 -0
  89. package/dist/index.d.ts +94 -0
  90. package/dist/index.mjs +1812 -0
  91. package/dist/index.mjs.map +1 -0
  92. package/dist/oauth-popup.d.ts +17 -0
  93. package/dist/output-shape.d.ts +58 -0
  94. package/dist/provider.d.ts +421 -0
  95. package/dist/resolve-params.d.ts +112 -0
  96. package/dist/resolved-json.d.ts +21 -0
  97. package/dist/run-visuals.d.ts +90 -0
  98. package/dist/step-preview-state.d.ts +143 -0
  99. package/dist/theme.d.ts +32 -0
  100. package/dist/trigger-fields.d.ts +56 -0
  101. package/dist/types.d.ts +413 -0
  102. package/dist/use-app-action-defs.d.ts +7 -0
  103. package/dist/use-enter-submit.d.ts +23 -0
  104. package/dist/use-seed-sources.d.ts +16 -0
  105. package/package.json +112 -3
  106. package/src/code.css +561 -0
  107. package/src/styles/_buttons.scss +38 -0
  108. package/src/styles/_chips.scss +210 -0
  109. package/src/styles/_code.scss +139 -0
  110. package/src/styles/_copyable.scss +147 -0
  111. package/src/styles/_data-vars.scss +38 -0
  112. package/src/styles/_execution-history.scss +282 -0
  113. package/src/styles/_execution-log.scss +178 -0
  114. package/src/styles/_expression-field.scss +65 -0
  115. package/src/styles/_expression-inline.scss +63 -0
  116. package/src/styles/_expression-modal.scss +292 -0
  117. package/src/styles/_fields.scss +161 -0
  118. package/src/styles/_flow.scss +217 -0
  119. package/src/styles/_fx.scss +158 -0
  120. package/src/styles/_health.scss +46 -0
  121. package/src/styles/_history-timeline.scss +156 -0
  122. package/src/styles/_icon-button.scss +22 -0
  123. package/src/styles/_icon.scss +15 -0
  124. package/src/styles/_icons.scss +31 -0
  125. package/src/styles/_incoming-state.scss +46 -0
  126. package/src/styles/_info-tip.scss +9 -0
  127. package/src/styles/_layout.scss +6 -0
  128. package/src/styles/_lists.scss +64 -0
  129. package/src/styles/_modal.scss +125 -0
  130. package/src/styles/_multiselect.scss +69 -0
  131. package/src/styles/_repo-sync-indicator.scss +99 -0
  132. package/src/styles/_scale.scss +70 -0
  133. package/src/styles/_sections.scss +36 -0
  134. package/src/styles/_server-resources.scss +163 -0
  135. package/src/styles/_step-builder.scss +376 -0
  136. package/src/styles/_step-config.scss +195 -0
  137. package/src/styles/_tabs.scss +54 -0
  138. package/src/styles/_tester.scss +111 -0
  139. package/src/styles/_tokens.scss +160 -0
  140. package/src/styles/_uptime.scss +61 -0
  141. package/src/styles.css +4894 -0
  142. package/src/styles.scss +61 -0
@@ -0,0 +1,18 @@
1
+ import { FlowStep } from './flow-types.ts';
2
+ /** Who this retry policy applies to — picks the helper line's wording. */
3
+ export type RetryTarget = "step" | "function" | "endpoint" | "workflow";
4
+ /** The persisted retry shape (core `rfcs/node-types.md`), minus the `undefined` case. */
5
+ export type RetryPolicyValue = NonNullable<FlowStep["retry"]>;
6
+ /**
7
+ * The "Retry on failure" checkbox + helper line + Attempts/Delay (ms)/Backoff
8
+ * row — the one retry shape shared by every host that can offer a retry
9
+ * policy (core rfcs/R-2 "one retry shape everywhere"). `value` is the
10
+ * persisted policy or `undefined` for "no retry"; `target` only changes the
11
+ * helper line's wording, never the behavior.
12
+ */
13
+ export declare function RetryPolicyFields({ value, onChange, readOnly, target, }: {
14
+ value: RetryPolicyValue | undefined;
15
+ onChange: (next: RetryPolicyValue | undefined) => void;
16
+ readOnly?: boolean;
17
+ target?: RetryTarget;
18
+ }): import("react").JSX.Element;
@@ -0,0 +1,375 @@
1
+ import { NodeConfig } from './NodeConfigForm.tsx';
2
+ import { ExpressionStepSource } from './components/ExpressionOptions.tsx';
3
+ import { InternalNodeDef } from './flow-types.ts';
4
+ import { StepStartState } from './provider.tsx';
5
+ import { ActionParam, AppSummary, FunctionSummary, ThemeMode, WorkflowSummary } from './types.ts';
6
+ /** The step the builder emits — the editor assigns the final `id`. `NodeConfig`
7
+ * carries the base settings (retry / onError / notes) set on the Config view. */
8
+ export interface BuiltStep extends NodeConfig {
9
+ uses: {
10
+ app: string;
11
+ action: string;
12
+ connection?: string | null;
13
+ };
14
+ with?: Record<string, unknown>;
15
+ }
16
+ export interface StepBuilderModalProps {
17
+ onClose: () => void;
18
+ /**
19
+ * Fired once per session, the moment the step first has identity — for an
20
+ * app step, when Setup completes (action + connection, if needed); for a
21
+ * control node, on mount. Returns the minted step id so subsequent edits can
22
+ * target it via {@link StepBuilderModalProps.onDraftChange}.
23
+ */
24
+ onAdd: (step: BuiltStep) => string | undefined | void;
25
+ /**
26
+ * Fired for every field change **after** the step has been committed via
27
+ * `onAdd` — keeps the already-added node current without minting a second
28
+ * one. `id` is the id `onAdd` returned. Progressive commit (mint-then-update)
29
+ * only engages when this is supplied; omitted callers (the Functions/
30
+ * Endpoints pickers) keep the original one-shot "Add step" behavior.
31
+ */
32
+ onDraftChange?: (id: string, step: BuiltStep) => void;
33
+ theme?: ThemeMode;
34
+ /**
35
+ * Hide the GRAPH-ONLY tabs — Triggers / Controls / Utilities / Data, the
36
+ * flow-control and internal `@w6w/*` node kinds that only mean something
37
+ * inside a workflow canvas. Used by every picker that binds a *target*
38
+ * rather than adding a node to a graph.
39
+ *
40
+ * ⚠️ It does NOT hide Functions and Workflows, and did not always behave
41
+ * that way: it used to, which is why the Implementation card's picker
42
+ * showed only `Connected apps / Apps / AI` and F-2.0's tabs were
43
+ * unreachable outside the canvas. A Function and a Workflow are *callable
44
+ * targets*, not graph-only node kinds — they belong in every picker.
45
+ * {@link StepBuilderModalProps.callables} is the knob for those two.
46
+ */
47
+ appsOnly?: boolean;
48
+ /**
49
+ * Which callable families the Functions/Workflows tabs offer. Defaults to
50
+ * BOTH, so a caller that says nothing keeps the full F-2.0 homepage
51
+ * (`Connected apps | Functions | Workflows`). Pass a narrower array — or
52
+ * `[]` — where the surrounding contract cannot accept one of them.
53
+ */
54
+ callables?: readonly ("function" | "workflow")[];
55
+ /**
56
+ * Which homepage tab opens first. Defaults to `"connected"` — F-2.0's
57
+ * homepage. A caller re-opening the picker for an already-bound target
58
+ * passes that target's own family, so "Change" lands where the current
59
+ * value lives instead of making the author re-find the tab.
60
+ */
61
+ initialTab?: "connected" | "functions" | "workflows";
62
+ /** Modal heading. Defaults to "Add a step". */
63
+ title?: string;
64
+ /**
65
+ * Workflow-step context, when the builder is opened for a step that already
66
+ * lives in a workflow. When present the `testRequired` save-gate can discover a
67
+ * previously-saved **passing** test for the step via {@link W6WApi.listStepTests}.
68
+ * Absent in the plain add-step flow (the step has no id yet) — there the gate is
69
+ * satisfied by running a passing test in-session.
70
+ */
71
+ workflowId?: string;
72
+ /** Step id paired with {@link StepBuilderModalProps.workflowId}. */
73
+ stepId?: string;
74
+ /**
75
+ * The new step's known graph ancestors, when the builder is opened from the
76
+ * workflow canvas (`stepBuilderUpstreamSteps`, derived from the connection
77
+ * drag that opened it). Threaded into the Test tab's `<StepTestRun>` the same
78
+ * way `StepEditModal` seeds an existing step's Test tab, so a `with` block
79
+ * written as `{{ steps.<id>.output.<field> }}` resolves instead of coming
80
+ * back empty. Absent (defaults to `[]`) for the Functions/Endpoints pickers,
81
+ * which have no graph to draw ancestors from.
82
+ */
83
+ upstreamSteps?: ExpressionStepSource[];
84
+ /**
85
+ * Pre-select an app when the modal opens. When provided along with
86
+ * initialAction/initialConnection/initialWith, the modal opens directly
87
+ * to the action configuration view instead of the app picker.
88
+ * Used when editing an existing action (e.g., clicking "Change" on an
89
+ * Endpoint's already-configured target).
90
+ */
91
+ initialApp?: AppSummary;
92
+ /**
93
+ * Pre-select an action key. Requires initialApp to be set.
94
+ */
95
+ initialAction?: string;
96
+ /**
97
+ * Pre-select a connection. Requires initialApp and initialAction.
98
+ */
99
+ initialConnection?: string;
100
+ /**
101
+ * Pre-fill the action's parameter values. Requires initialApp and initialAction.
102
+ */
103
+ initialWith?: Record<string, unknown>;
104
+ /**
105
+ * Narrow which apps a scoped caller may pick, everywhere an app list is
106
+ * computed — the "Apps" tab's grid, the "AI" tab's composed filter, and
107
+ * {@link StepBuilderModalProps.callables}'s "Ready to use" tab. An
108
+ * `undefined` filter is a no-op; every existing caller (none of which sets
109
+ * this) is unaffected.
110
+ *
111
+ * On "Ready to use", an app built from a connection's inline `app` meta
112
+ * carries only `id` plus those meta keys (`displayName`, icons, brand
113
+ * colours) — no `version` or `categories` — so the filter sees just those,
114
+ * and the selected-app header omits the ` · v<version>` suffix for it.
115
+ */
116
+ appsFilter?: (app: AppSummary) => boolean;
117
+ /**
118
+ * Stop at "a connection is chosen" — no Action, no Configure/Test. Renders
119
+ * {@link AppConnectionOnlyConfig} in place of the usual `AppStepConfig`
120
+ * once an app is picked. Used by a caller that only needs a connection
121
+ * (e.g. binding a repository), not a runnable step.
122
+ */
123
+ connectionOnly?: boolean;
124
+ /**
125
+ * Fired once, on {@link AppConnectionOnlyConfig}'s footer button — never on
126
+ * selection alone. Only meaningful with {@link StepBuilderModalProps.connectionOnly}.
127
+ */
128
+ onConnected?: (connectionId: string, app: AppSummary) => void;
129
+ }
130
+ /** The four representations of the Configure tab: form, full-step JSON,
131
+ * params-only JSON, node settings. */
132
+ export type ConfigView = "props" | "code" | "params-code" | "config";
133
+ /**
134
+ * The props / code / params-code / config view toggle, right-aligned in the
135
+ * tabs bar. Disabled off the Configure tab (all four views represent the
136
+ * action's config).
137
+ *
138
+ * `views` narrows it to a subset, in the order given — a fields ⇄ raw-JSON
139
+ * property form (see `PropertyEntryForm`) passes `["props", "code"]`. There is
140
+ * deliberately no second toggle component: one glyph set, one styling, one
141
+ * pressed-state behaviour, however many views a host offers.
142
+ */
143
+ export declare function ConfigViewToggle({ view, onChange, disabled, views, }: {
144
+ view: ConfigView;
145
+ onChange: (v: ConfigView) => void;
146
+ disabled?: boolean;
147
+ /** Which views to offer, in order. Defaults to all four. */
148
+ views?: ConfigView[];
149
+ }): import("react").JSX.Element;
150
+ /**
151
+ * Guided "add a step" flow. A sidebar toggles between **Apps** (pick app →
152
+ * ensure a connection → pick action → fill params) and **Controls** — the
153
+ * internal nodes: triggers, flow control (if/foreach/parallel/wait), and compute
154
+ * (script/data). Emits a `BuiltStep` via `onAdd`.
155
+ *
156
+ * Data + IO come from `useW6WApi()`, so mount it under `<W6WUIProvider>`.
157
+ */
158
+ export declare function StepBuilderModal({ onClose, onAdd, onDraftChange, theme, appsOnly, callables, initialTab, title, workflowId, stepId, upstreamSteps, initialApp, initialAction, initialConnection, initialWith, appsFilter, connectionOnly, onConnected, }: StepBuilderModalProps): import("react").JSX.Element;
159
+ /**
160
+ * Config form for a chosen internal node — its schema rendered through the same
161
+ * `ParamsForm` as app actions, seeded with the node's defaults. Emits the built
162
+ * step on Add.
163
+ */
164
+ export declare function ControlStepConfig({ node, onAdd, onClose, onDraftChange, workflowId, upstreamSteps, }: {
165
+ node: InternalNodeDef;
166
+ onAdd: (s: BuiltStep) => string | undefined | void;
167
+ onClose: () => void;
168
+ /** See {@link StepBuilderModalProps.onDraftChange}. */
169
+ onDraftChange?: (id: string, step: BuiltStep) => void;
170
+ workflowId?: string;
171
+ /** The new step's known graph ancestors — see {@link StepBuilderModalProps.upstreamSteps}. */
172
+ upstreamSteps?: ExpressionStepSource[];
173
+ }): import("react").JSX.Element;
174
+ /**
175
+ * Config → test → add flow for a picked Function/Workflow target (D-12,
176
+ * D-15). Mints a single `@w6w/call` step — `family` only decides which
177
+ * summary/detail/invoke endpoints are called and what `with.targetKind` is
178
+ * stamped; it is never two near-copies. Mirrors `ControlStepConfig`'s
179
+ * progressive-commit shape (mint via `onAdd` the instant the target is
180
+ * picked, then `onDraftChange` on every later change) — unlike `AppStepConfig`
181
+ * there is no Setup tab (the target picked in `CallableList` IS the identity)
182
+ * and no `NodeConfigForm` here: a second onError/retry form is out of scope —
183
+ * `NodeConfigForm` is reached once the `@w6w/call` step already lives on a
184
+ * canvas, not at add-time.
185
+ */
186
+ export declare function CallableStepConfig({ family, targetId, targetLabel, onAdd, onClose, onDraftChange, }: {
187
+ family: "function" | "workflow";
188
+ targetId: string;
189
+ targetLabel: string;
190
+ onAdd: (s: BuiltStep) => string | undefined | void;
191
+ onClose: () => void;
192
+ /** See {@link StepBuilderModalProps.onDraftChange}. */
193
+ onDraftChange?: (id: string, step: BuiltStep) => void;
194
+ }): import("react").JSX.Element;
195
+ /**
196
+ * Whether every required param has a usable value — gates the inline "Test run".
197
+ * A required array (e.g. a `vars` table) may be empty (see the Data node); other
198
+ * required fields must be non-empty.
199
+ *
200
+ * A param hidden by its own `showIf` is skipped, matching `ParamsForm`'s render
201
+ * visibility — this is what lets `required` and `showIf` combine at all (e.g.
202
+ * SendGrid's `contentValue`, required only when NOT using a dynamic template):
203
+ * without it, a conditionally-required field would either block the gate in the
204
+ * branch where it's moot, or (if left non-required to dodge that) never be
205
+ * caught here and only surface as a raw runtime error from the app's own
206
+ * `execute()` — the app was previously written the second way for exactly this
207
+ * reason; that workaround was fixed alongside this once the gate learned `showIf`.
208
+ */
209
+ export declare function requiredParamsFilled(params: ActionParam[], values: Record<string, unknown>): boolean;
210
+ /**
211
+ * Whether adding this step is gated on a **passing** saved test — the per-app
212
+ * `testRequired` save-gate. Defaults to **required**; an app/node surface may
213
+ * opt out by carrying `testRequired: false`.
214
+ *
215
+ * The flag is read defensively off the app/node surface because the core app
216
+ * manifest does not carry a `testRequired` field yet (a recorded follow-up); an
217
+ * absent flag therefore means **required**, so today every app step must pass a
218
+ * test before it can be added.
219
+ */
220
+ export declare function isTestRequired(surface: unknown): boolean;
221
+ /**
222
+ * Where a test run should be persisted. When present, `StepTestRun` saves the
223
+ * fixture (`saveStepTest`) and records the run's outcome (`recordStepTestRun`)
224
+ * against the given workflow step after each invoke. `input` is the resolved
225
+ * incoming state captured alongside the params (`values` → `with`). Absent in
226
+ * the add-step builder (the step isn't in a workflow yet).
227
+ */
228
+ export interface StepTestPersist {
229
+ workflowId: string;
230
+ stepId: string;
231
+ input: Record<string, unknown>;
232
+ }
233
+ /** Imperative handle so a host (e.g. the step modal footer) can trigger the run. */
234
+ export interface StepTestRunHandle {
235
+ run: () => void;
236
+ }
237
+ /**
238
+ * Inline "Test run" — invokes the action/node with the current params (and, for
239
+ * app actions, the chosen connection) so the user can try a step from inside the
240
+ * builder before adding it. Pressable only once required fields are filled.
241
+ *
242
+ * When `persist` is supplied (the node editor's Test tab), each run also saves
243
+ * the fixture and records the outcome server-side, so a step test becomes saved
244
+ * and re-runnable. `hideRunButton` suppresses the inline button when the host
245
+ * drives the run from elsewhere (the modal footer) via the imperative handle.
246
+ */
247
+ export declare const StepTestRun: import('react').ForwardRefExoticComponent<{
248
+ app: string;
249
+ action: string;
250
+ connectionId?: string;
251
+ values: Record<string, unknown>;
252
+ canRun: boolean;
253
+ hideRunButton?: boolean;
254
+ persist?: StepTestPersist;
255
+ /**
256
+ * The run's start state — what the upstream steps last produced — so a
257
+ * `values` entry written as `{{ steps.<id>.output.<field> }}` resolves
258
+ * server-side instead of coming back empty. The host builds it (both the
259
+ * node editor's Test tab and, since T1.1.1, the add-step builder's Test
260
+ * tab seed it from the upstream fixtures, via `useSeedSources` +
261
+ * `startStateFromSeeds`); absent only when the host itself has no upstream
262
+ * steps to offer — the Functions/Endpoints pickers, which have no graph.
263
+ */
264
+ state?: StepStartState;
265
+ /** Notified when the run starts/finishes so a host button can reflect it. */
266
+ onBusyChange?: (busy: boolean) => void;
267
+ /**
268
+ * Notified with the outcome of each finished run (`true` = passed). Lets a
269
+ * host satisfy the `testRequired` save-gate from an in-session test run.
270
+ */
271
+ onResult?: (passed: boolean) => void;
272
+ } & import('react').RefAttributes<StepTestRunHandle>>;
273
+ /**
274
+ * What the home tab has to show. Lifted out of the tab's own component because
275
+ * the MODAL needs the answer too: a home tab with nothing in it is not
276
+ * rendered at all (no connected apps, no Functions, no Workflows ⇒ no tab),
277
+ * and that decision belongs to whoever draws the sidebar.
278
+ *
279
+ * `state` is deliberately four-valued. "Empty" and "not loaded yet" must not
280
+ * collapse into one: hiding the tab while its fetches are in flight would make
281
+ * it appear a beat later, moving the sidebar under the cursor.
282
+ */
283
+ interface ReadyToUse {
284
+ state: "loading" | "error" | "empty" | "ready";
285
+ error?: string;
286
+ apps: AppSummary[];
287
+ fns: FunctionSummary[];
288
+ wfs: WorkflowSummary[];
289
+ /** More connected-app ids remain unresolved — draw an explicit "load more" affordance. */
290
+ moreApps: boolean;
291
+ /** Resolve the next bounded batch of connected-app ids. No-op off the bounded path or with nothing left. */
292
+ loadMoreApps: () => void;
293
+ }
294
+ /**
295
+ * Clamp the poll-interval text to an integer number of minutes ≥ `min`. Blank,
296
+ * non-numeric or below-minimum input yields `min`; fractions round to nearest.
297
+ */
298
+ export declare function clampMinutes(raw: string, min: number): number;
299
+ /**
300
+ * "Ready to use"'s data: distinct connected app ids (A3) resolved in bounded
301
+ * batches via the optional `listAppsByIds`, plus Functions/Workflows.
302
+ *
303
+ * `/connections` already includes a synthetic zero-credential row per
304
+ * zero-credential-flagged app the caller's tenant can use with no connection
305
+ * step (`admin/connections.ts`) — so the DISTINCT connection app ids alone are
306
+ * the full "ready" membership; unlike the old full-catalog scan, no separate
307
+ * `AppSummary.zeroCredential` check is needed on this path.
308
+ *
309
+ * `listAppsByIds` is optional (older/imported providers implement only
310
+ * `listApps`): capability is `typeof api.listAppsByIds === "function"`
311
+ * ALONE — never inferred from a runtime result. A first batch that resolves
312
+ * to an empty array is a LEGITIMATE answer from a fully-working
313
+ * `listAppsByIds` (every connected app was since deleted from the catalog,
314
+ * an ordinary case) and must be shown as such, not treated as evidence the
315
+ * optional method "isn't really implemented" (T2.1.1 ROUND 2 — that
316
+ * conflation previously made a correct, well-typed empty result permanently
317
+ * fall back to the unbounded `listApps()` for the rest of the component's
318
+ * lifetime, the exact "one request per entire catalog at open" A3 forbids).
319
+ * When the method is genuinely absent, this hook falls back to the ORIGINAL
320
+ * full-catalog scan (`listApps()` + the zero-credential check), unchanged —
321
+ * and with `listApps` itself also absent (now optional, like this member),
322
+ * settles on the empty catalog instead of calling an undefined function.
323
+ *
324
+ * On the bounded path each connection's inline `app` meta is read FIRST: an
325
+ * app id with a non-null `app` on any of its rows is built as
326
+ * `{ ...c.app, id: c.appId }` and seeded as resolved + requested, so
327
+ * `listAppsByIds` is called only for ids whose rows all lack it (`app` absent
328
+ * or `null`) — and not at all when none do. Such inline apps have no
329
+ * `version`/`categories`: the selected-app header drops its ` · v<version>`
330
+ * suffix and `appsFilter` sees only `id` and the meta keys.
331
+ *
332
+ * Exported for tests only (not re-exported from the package index).
333
+ */
334
+ export declare function useReadyToUse(callables: readonly ("function" | "workflow")[], appsFilter?: (app: AppSummary) => boolean): ReadyToUse;
335
+ export declare function AppStepConfig({ appId, app, onAdd, onClose, onDraftChange, onChangeApp, theme, workflowId, stepId, upstreamSteps, initialAction, initialConnection, initialWith, }: {
336
+ appId: string;
337
+ app?: AppSummary;
338
+ onAdd: (s: BuiltStep) => string | undefined | void;
339
+ onClose: () => void;
340
+ /** See {@link StepBuilderModalProps.onDraftChange}. */
341
+ onDraftChange?: (id: string, step: BuiltStep) => void;
342
+ onChangeApp?: () => void;
343
+ theme?: ThemeMode;
344
+ workflowId?: string;
345
+ stepId?: string;
346
+ /** The new step's known graph ancestors — see {@link StepBuilderModalProps.upstreamSteps}. */
347
+ upstreamSteps?: ExpressionStepSource[];
348
+ /** Pre-selected action key, opens directly to Configure tab when provided with initialWith */
349
+ initialAction?: string;
350
+ /** Pre-selected connection id */
351
+ initialConnection?: string;
352
+ /** Pre-filled parameter values */
353
+ initialWith?: Record<string, unknown>;
354
+ }): import("react").JSX.Element;
355
+ /**
356
+ * {@link AppStepConfig}'s Setup tab, minus the Action and Configure/Test
357
+ * gate — for a caller that only needs "a connection is chosen" (e.g. binding
358
+ * a repository), not a runnable step. Copies its App section and all three
359
+ * Connection-section branches verbatim, same CSS classes; fetches only
360
+ * {@link W6WApi.getAppAuth} + {@link W6WApi.listConnectionsForApp} (never
361
+ * `getAppActions`). Ends in one footer button, gated on `connectionSatisfied`
362
+ * alone, that fires {@link onConnected} once — never on selection (D-sbm-2).
363
+ */
364
+ export declare function AppConnectionOnlyConfig({ appId, app, onClose, onChangeApp, theme, initialConnection, onConnected, }: {
365
+ appId: string;
366
+ app?: AppSummary;
367
+ onClose: () => void;
368
+ onChangeApp?: () => void;
369
+ theme?: ThemeMode;
370
+ /** Pre-selected connection id */
371
+ initialConnection?: string;
372
+ /** Fired once, on the footer button — never on a state change (D-sbm-2). */
373
+ onConnected: (connectionId: string, app: AppSummary) => void;
374
+ }): import("react").JSX.Element;
375
+ export {};
@@ -0,0 +1,52 @@
1
+ import { StepTestPersist } from './StepBuilderModal.tsx';
2
+ /**
3
+ * The Test-tab widget for a manual/webhook trigger. A trigger's configured
4
+ * `fields` ARE the run's starting state, so testing it means **filling those
5
+ * fields**, not running the raw config (which is why the trigger's output used to
6
+ * come back `{}` — the invoke never carried an `input`).
7
+ *
8
+ * It projects the trigger's `fields` into params (see `./trigger-fields.ts`) and
9
+ * hands them to {@link PropertyEntryForm} — the one property-entry surface, which
10
+ * gives it the per-field widgets, per-field `ƒx`, and the fields ⇄ raw-JSON
11
+ * toggle. This component keeps only the *run*: it enforces each field's
12
+ * `required` via {@link requiredParamsFilled} before enabling Test, and invokes
13
+ * with `{ input: {…filled} }` so the handler (which passes `params.input`
14
+ * through) returns the populated values as the trigger's output state.
15
+ *
16
+ * A trigger with no declared fields (e.g. a webhook, whose payload is arbitrary)
17
+ * gets the raw JSON payload editor — that is the entry form's own empty-params
18
+ * path, not a second code path here — so the operator can still supply a
19
+ * starting state, and the same `{ input }` projection applies.
20
+ *
21
+ * **Remembered values (T4.1.3).** With `persist` supplied, the values are not
22
+ * just used for the invoke: they are saved as the step's latest `step_tests`
23
+ * fixture (`with`) and the run is recorded **against that fixture's id**, and the
24
+ * form seeds itself from the latest fixture next time it opens. The store is
25
+ * project-owned and shared per workflow — any editor of the workflow sees the
26
+ * same saved values, which is the answer to HITL-2. The canvas ▶ Run collect
27
+ * form reads and writes the same fixture, so values entered on either surface
28
+ * come back on the other.
29
+ *
30
+ * That persistence is **local to testing** — `TriggerFillForm` itself never
31
+ * calls `POST /workflows/:id/run`. It does not by itself reach a production
32
+ * workflow run: that route does accept an `input` body field, and the server
33
+ * lands it as the entry trigger's output (`run-workflow.ts`,
34
+ * `EnqueueRunInput.input`), but a CALLER has to fetch the saved fixture and
35
+ * pass it in. Studio's header ▶ Run is that caller (`WorkflowsPage.tsx`'s
36
+ * `onRunClick` → `resolveHeaderRunInput`,
37
+ * `packages/studio/src/lib/workflow-live-run.ts`): it fetches the manual
38
+ * trigger's latest `step_tests` row and sends its `with` verbatim as `input`.
39
+ * This form is not in that path; it only writes the fixture that call reads.
40
+ */
41
+ export declare function TriggerFillForm({ app, action, fields, persist, }: {
42
+ app: string;
43
+ action: string;
44
+ /** The trigger's `fields` param value (an array of field definitions). */
45
+ fields: unknown;
46
+ /**
47
+ * Where to remember the entered values. Absent in the add-step builder — that
48
+ * step is not in a workflow yet, so there is no `(workflowId, stepId)` to key
49
+ * a fixture by and this form neither reads nor writes one.
50
+ */
51
+ persist?: StepTestPersist;
52
+ }): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ /** Both input modes write the same duration field; switching never discards a compound value. */
2
+ export declare function WaitEditor({ values, onChange, readOnly, }: {
3
+ values: Record<string, unknown>;
4
+ onChange: (values: Record<string, unknown>) => void;
5
+ readOnly?: boolean;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,119 @@
1
+ import { ExpressionOptions, ExpressionStepSource } from './components/ExpressionOptions.tsx';
2
+ import { FlowStep, FlowWorkflow } from './flow-types.ts';
3
+ import { RunState } from './run-visuals.ts';
4
+ import { AppSummary } from './types.ts';
5
+ export interface WorkflowFlowEditorProps {
6
+ /** The workflow being edited. The editor re-derives layout when this changes identity. */
7
+ value: FlowWorkflow;
8
+ /** Fired whenever the user changes the graph — new nodes, edges, or step edits. */
9
+ onChange: (next: FlowWorkflow) => void;
10
+ /** Disable all interactions — pans/zooms are still enabled. */
11
+ readOnly?: boolean;
12
+ /** Height of the editor viewport. Defaults to 480px. */
13
+ height?: string | number;
14
+ /**
15
+ * Registered apps, used to render each action node with its owning app's icon,
16
+ * display name, and version. A step only carries `uses.app` (an id), so the
17
+ * card joins that id against this list. Optional — unknown/absent apps degrade
18
+ * to an initials tile with no version. Metadata is looked up at render time and
19
+ * never stored on nodes, so it can't corrupt round-tripping back to a workflow.
20
+ */
21
+ apps?: AppSummary[];
22
+ /**
23
+ * EXTRA scope for each step field's expression picker, on top of whatever
24
+ * this editor is already mounted under.
25
+ *
26
+ * Optional, and normally omitted: `ExpressionOptionsProvider` layers, so a
27
+ * host that provides the project's vars/secrets/documents above this editor
28
+ * (studio does, once, in its app shell) needs to pass nothing here. Use it
29
+ * only to add or override something at this level.
30
+ *
31
+ * Names only — secret plaintext never reaches the client.
32
+ */
33
+ exprOptions?: ExpressionOptions;
34
+ /**
35
+ * The workflow's currently-selected project id. Threaded into ad-hoc
36
+ * test-invokes so document expressions resolve against that project's docs
37
+ * (not the scope's default/starter project). The host (studio) passes the
38
+ * active project here; omitted → server default-project behavior. See T2.1.2 /
39
+ * HITL-4(b): the invoke path's ambient scope is already project-aware.
40
+ */
41
+ project?: string;
42
+ /**
43
+ * The live run's per-step state, when the canvas is showing one (T1.1.1).
44
+ * Omitted ⇒ the canvas renders exactly as it does today: every node in its
45
+ * default look, every edge unstyled beyond its own `when` lane. This
46
+ * editor does no fetching of its own — the host (`studio`) owns polling
47
+ * `GET /runs/:id` and passes each successive result here, the same
48
+ * "host owns the query, editor is presentational" split `apps`/`readOnly`
49
+ * already establish for every other external data source.
50
+ *
51
+ * A structural subset of `RunState` in `@w6w/workflow-types` (mirrors this
52
+ * file's own `FlowWorkflow`/`FlowStep` — see `flow-types.ts`'s header
53
+ * note): `packages/ui` takes no dependency on the engine's types, so a
54
+ * caller who already has the real `RunState` is compatible for free.
55
+ *
56
+ * Never persisted: {@link flowToWorkflow} never reads it — a run is not
57
+ * part of the workflow that ran, and `data.stepStatus`/`data.runStatus`
58
+ * (where this ends up on the canvas) are never among the fields it reads
59
+ * back off a node.
60
+ */
61
+ runState?: RunState;
62
+ /**
63
+ * Fired the instant a step test starts — the ▶ collect form's Run button, or
64
+ * `StepEditModal`'s footer Test button — before the invoke goes out, so a host
65
+ * can drop whatever run its canvas was showing (T1.1.1) instead of leaving a
66
+ * test to run underneath a stale run's highlighting.
67
+ *
68
+ * On the click, never on the result: only one of those two surfaces has a
69
+ * completion to report at all, and the click is the one moment both share.
70
+ */
71
+ onTestRun?: () => void;
72
+ /**
73
+ * Re-frames the canvas when the host changes the space around it. When this
74
+ * value changes after mount (compared with `Object.is`), the editor calls
75
+ * `fitView({ duration: 300 })` once. It never fires on mount, and omitting it
76
+ * or passing the same value again adds no fit.
77
+ *
78
+ * For a host whose page layout resizes the canvas without the graph changing,
79
+ * e.g. a side panel docking beside it (pass the panel's open state). React Flow
80
+ * keeps its pan/zoom transform when its pane narrows, so nodes near the edge
81
+ * would otherwise end up behind the panel. The editor does not watch its own
82
+ * size, so the host decides which layout changes deserve a re-frame.
83
+ *
84
+ * A fit replaces whatever camera is showing, including a saved viewport the
85
+ * editor restored on open. The fit is not user-initiated, so it never emits
86
+ * `onChange` and never overwrites the stored viewport.
87
+ */
88
+ fitViewKey?: string | number | boolean;
89
+ }
90
+ /** Which view the step edit modal opens in: the tabbed form, raw JSON, or node settings. */
91
+ type EditView = "props" | "json" | "settings";
92
+ /**
93
+ * Visual workflow editor. Renders a Workflow's DAG as a React Flow graph:
94
+ *
95
+ * - Auto-layouted on load (topological columns + sibling rows).
96
+ * - Nodes render differently for action steps vs. control steps
97
+ * (`uses.app === "@w6w/control"`).
98
+ * - `+ Step` opens a guided builder (pick app → connection → action → params,
99
+ * or a flow control). Drag nodes to reposition; connect handles to add edges.
100
+ * - Selecting a node reveals a toolbar above it: Edit / Duplicate / Delete.
101
+ * - Edit opens a modal with a Form ⇄ JSON toggle for that step.
102
+ * - Every meaningful change fires `onChange` with an updated Workflow.
103
+ */
104
+ export declare function WorkflowFlowEditor(props: WorkflowFlowEditorProps): import("react").JSX.Element;
105
+ export declare function StepEditModal({ workflowId, step: initialStep, upstreamSteps, onChange, onClose, readOnly, initialView, fanOutCount, onTestRun, }: {
106
+ workflowId: string;
107
+ step: FlowStep;
108
+ /** Graph ancestors of this step (from `upstreamStateSources`); the incoming-state picker seeds from their saved tests. */
109
+ upstreamSteps: ExpressionStepSource[];
110
+ onChange: (next: FlowStep) => void;
111
+ onClose: () => void;
112
+ readOnly?: boolean;
113
+ initialView?: EditView;
114
+ /** Most outgoing edges this step has in one lane; "Run next steps" needs >= 2. */
115
+ fanOutCount?: number;
116
+ /** Fired the instant the footer Test button is clicked, before the test runs (T1.1.1). */
117
+ onTestRun?: () => void;
118
+ }): import("react").JSX.Element;
119
+ export {};
@@ -0,0 +1,46 @@
1
+ import { ThemeMode } from './types.ts';
2
+ export interface YamlEditorProps {
3
+ value: string;
4
+ onChange: (value: string) => void;
5
+ /** Placeholder text shown when value is empty. */
6
+ placeholder?: string;
7
+ /** Minimum editor height. Defaults to "240px". */
8
+ minHeight?: string;
9
+ /** Maximum editor height before scrolling. Defaults to no cap. */
10
+ maxHeight?: string;
11
+ /**
12
+ * Explicit editor height. Pass `"100%"` to fill a flex parent (the whole-config
13
+ * "code" view). Omit to let the editor grow with its content between
14
+ * `minHeight` and `maxHeight` — an inline YAML/group field wants this.
15
+ */
16
+ height?: string;
17
+ /** Read-only mode — useful for previewing a stored definition. */
18
+ readOnly?: boolean;
19
+ /**
20
+ * Explicit theme. If omitted, the editor auto-detects `data-theme` on
21
+ * `<html>` and falls back to `prefers-color-scheme` — same behavior as
22
+ * `<AppIcon>`. Uses CodeMirror's built-in one-dark for dark mode.
23
+ */
24
+ theme?: ThemeMode;
25
+ /** Accessible label for the editor. */
26
+ "aria-label"?: string;
27
+ /**
28
+ * Render an in-box copy-to-clipboard button, a direct child of this
29
+ * component's own `.w6w-yaml-editor` wrapper (sibling to the CodeMirror
30
+ * mount — no extra DOM node). Copies the current `value` verbatim.
31
+ *
32
+ * Off by default: the other mounts of this component must render byte-
33
+ * identically to before this prop existed.
34
+ */
35
+ copyable?: boolean;
36
+ }
37
+ /**
38
+ * YAML editor built on CodeMirror 6. Syntax highlighting, folding, gutter,
39
+ * and line numbers. Themed with the `--w6w-*` custom properties so it
40
+ * inherits from the consumer's palette.
41
+ *
42
+ * ```tsx
43
+ * <YamlEditor value={text} onChange={setText} minHeight="320px" />
44
+ * ```
45
+ */
46
+ export declare function YamlEditor(props: YamlEditorProps): import("react").JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { AppSummary } from './types.ts';
2
+ /**
3
+ * Display label for a category slug. A known override wins; otherwise the
4
+ * slug is split on `-`/`_`/whitespace and each word is capitalized. Never
5
+ * throws — an empty/non-string slug renders as `""`, and any out-of-
6
+ * vocabulary slug still gets a readable (title-cased) label.
7
+ *
8
+ * @example
9
+ * categoryLabel("crm"); // "CRM" (override)
10
+ * categoryLabel("project-management"); // "Project Management"
11
+ * categoryLabel("sales"); // "Sales" (out-of-vocabulary, still safe)
12
+ */
13
+ export declare function categoryLabel(slug: string): string;
14
+ /** One category chip's derived data — a slug, its display label, and how
15
+ * many of the supplied apps carry it. */
16
+ export interface CategoryChip {
17
+ slug: string;
18
+ label: string;
19
+ count: number;
20
+ }
21
+ /**
22
+ * Distinct category slugs present across `apps`, each with its app count.
23
+ * Ordered by count DESCENDING; ties break on the derived LABEL, ascending
24
+ * (a deterministic order — never insertion/slug order, which would vary with
25
+ * the catalog's own listing order).
26
+ *
27
+ * Derive from the caller's already-visible catalog (post any `filter` prop),
28
+ * never from the full RFC vocabulary — a category with nothing behind it in
29
+ * the current list is a dead end (D-1a).
30
+ */
31
+ export declare function deriveCategories(apps: readonly AppSummary[]): CategoryChip[];
32
+ /**
33
+ * Whether `app` matches a set of selected category slugs. An EMPTY selection
34
+ * means "all" (every app matches); a non-empty selection is OR-across-
35
+ * selected — the app matches if it carries ANY of the selected slugs. Mirrors
36
+ * `AppsPage.tsx`'s `cats.size === 0 ? … : appCats.some((c) => cats.has(c))`.
37
+ */
38
+ export declare function matchesCategories(app: AppSummary, selected: readonly string[]): boolean;