@w6w/ui 0.2.0 → 0.2.54

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 (160) hide show
  1. package/CHANGELOG.md +146 -2
  2. package/README.md +28 -10
  3. package/dist/AppPicker.d.ts +58 -2
  4. package/dist/CanvasContextMenu.d.ts +19 -0
  5. package/dist/CanvasLayer.d.ts +38 -0
  6. package/dist/{CodeBlock-Dot3Pd7P.js → CodeBlock-C-oIIYfC.js} +1436 -555
  7. package/dist/CodeBlock-C-oIIYfC.js.map +1 -0
  8. package/dist/CodeBlock-CymlfyeA.cjs +15 -0
  9. package/dist/CodeBlock-CymlfyeA.cjs.map +1 -0
  10. package/dist/CodeEditor.d.ts +4 -1
  11. package/dist/ConditionEditor.d.ts +11 -0
  12. package/dist/EditConnectionModal.d.ts +6 -1
  13. package/dist/JsonEditor.d.ts +20 -0
  14. package/dist/Markdown.d.ts +25 -0
  15. package/dist/ParamCustomization.d.ts +5 -0
  16. package/dist/ParamsForm.d.ts +18 -4
  17. package/dist/RouterEditor.d.ts +5 -0
  18. package/dist/StepBuilderModal.d.ts +103 -15
  19. package/dist/StepNameEditor.d.ts +11 -0
  20. package/dist/StopEditor.d.ts +5 -0
  21. package/dist/TriggerFillForm.d.ts +14 -1
  22. package/dist/WebhookListenPanel.d.ts +28 -0
  23. package/dist/WorkflowConnections.d.ts +29 -0
  24. package/dist/WorkflowFlowEditor.d.ts +74 -7
  25. package/dist/app-pages.d.ts +2 -0
  26. package/dist/assets/script-completion.worker-DDJKkj5M.js +8290 -0
  27. package/dist/assets/script-completion.worker-DDJKkj5M.js.map +1 -0
  28. package/dist/canvas-context-menu.d.ts +27 -0
  29. package/dist/canvas-types.d.ts +36 -0
  30. package/dist/canvas-utils.d.ts +44 -0
  31. package/dist/code.cjs +1 -1
  32. package/dist/code.mjs +3 -4
  33. package/dist/code.mjs.map +1 -1
  34. package/dist/components/AnchoredFlyout.d.ts +7 -0
  35. package/dist/components/AuthFieldsForm.d.ts +11 -0
  36. package/dist/components/BudgetMeter.d.ts +15 -0
  37. package/dist/components/CallableList.d.ts +3 -2
  38. package/dist/components/ColumnsEditor.d.ts +27 -0
  39. package/dist/components/Combobox.d.ts +19 -1
  40. package/dist/components/ConnectionList.d.ts +2 -3
  41. package/dist/components/CredentialPicker.d.ts +35 -0
  42. package/dist/components/CsvPanel.d.ts +21 -0
  43. package/dist/components/DataEntryEditor.d.ts +38 -0
  44. package/dist/components/DataEntryList.d.ts +33 -0
  45. package/dist/components/DataStoreList.d.ts +33 -0
  46. package/dist/components/DataTable.d.ts +27 -0
  47. package/dist/components/DataTableGrid.d.ts +46 -0
  48. package/dist/components/EmptyState.d.ts +9 -0
  49. package/dist/components/EventbriteTriggerPicker.d.ts +7 -0
  50. package/dist/components/ExecutionDetail.d.ts +17 -1
  51. package/dist/components/ExecutionList.d.ts +19 -1
  52. package/dist/components/ExecutionLogPanel.d.ts +61 -3
  53. package/dist/components/ExpressionEditorModal.d.ts +33 -10
  54. package/dist/components/ExpressionOptions.d.ts +101 -15
  55. package/dist/components/HtmlPreview.d.ts +7 -0
  56. package/dist/components/JsonTree.d.ts +32 -0
  57. package/dist/components/ResolvedParams.d.ts +6 -1
  58. package/dist/components/ResultViewer.d.ts +46 -0
  59. package/dist/components/ScriptBindingsNotice.d.ts +31 -0
  60. package/dist/components/ScriptCodeField.d.ts +13 -0
  61. package/dist/components/StepStatusPill.d.ts +7 -0
  62. package/dist/components/expression-authoring.d.ts +13 -0
  63. package/dist/components/expression-dom.d.ts +17 -2
  64. package/dist/components/expression-template.d.ts +25 -3
  65. package/dist/components/icons.d.ts +1 -1
  66. package/dist/components/json-compose.d.ts +53 -0
  67. package/dist/components/result-format.d.ts +13 -0
  68. package/dist/condition-editor.d.ts +44 -0
  69. package/dist/data-stores/data-store-view.d.ts +371 -0
  70. package/dist/dynamic-fields.d.ts +60 -0
  71. package/dist/editor-theme.d.ts +24 -0
  72. package/dist/eventbrite-trigger-selection.d.ts +13 -0
  73. package/dist/flow-connect.d.ts +22 -16
  74. package/dist/flow-delete.d.ts +16 -0
  75. package/dist/flow-fanout.d.ts +2 -2
  76. package/dist/flow-history.d.ts +75 -0
  77. package/dist/flow-layout.d.ts +13 -0
  78. package/dist/flow-loop-colors.d.ts +39 -0
  79. package/dist/flow-loop.d.ts +98 -0
  80. package/dist/flow-node-flags.d.ts +14 -0
  81. package/dist/flow-problems.d.ts +69 -0
  82. package/dist/flow-state.d.ts +20 -0
  83. package/dist/flow-types.d.ts +155 -10
  84. package/dist/flow-utils.d.ts +33 -12
  85. package/dist/flow.cjs +4 -2
  86. package/dist/flow.cjs.map +1 -1
  87. package/dist/flow.d.ts +15 -2
  88. package/dist/flow.mjs +3737 -1350
  89. package/dist/flow.mjs.map +1 -1
  90. package/dist/index.cjs +2 -1
  91. package/dist/index.cjs.map +1 -1
  92. package/dist/index.d.ts +43 -5
  93. package/dist/index.mjs +2855 -1333
  94. package/dist/index.mjs.map +1 -1
  95. package/dist/node-samples-ChdyMBnJ.cjs +22 -0
  96. package/dist/node-samples-ChdyMBnJ.cjs.map +1 -0
  97. package/dist/node-samples-DkJL07EX.js +12302 -0
  98. package/dist/node-samples-DkJL07EX.js.map +1 -0
  99. package/dist/node-samples.d.ts +80 -0
  100. package/dist/note-markdown.d.ts +22 -0
  101. package/dist/output-shape.d.ts +30 -14
  102. package/dist/param-customization.d.ts +7 -0
  103. package/dist/provider.d.ts +174 -13
  104. package/dist/resolve-params.d.ts +50 -11
  105. package/dist/run-visuals.d.ts +18 -22
  106. package/dist/script-bindings.d.ts +63 -0
  107. package/dist/script-completion-service.d.ts +9 -0
  108. package/dist/script-completion.worker.d.ts +1 -0
  109. package/dist/script-completions.d.ts +2 -0
  110. package/dist/state-shape.d.ts +38 -0
  111. package/dist/step-preview-state.d.ts +155 -6
  112. package/dist/step-problems.d.ts +64 -0
  113. package/dist/test-inputs.d.ts +25 -0
  114. package/dist/trigger-registration.d.ts +28 -0
  115. package/dist/types.d.ts +179 -11
  116. package/dist/use-app-action-defs.d.ts +9 -1
  117. package/dist/use-dynamic-fields.d.ts +23 -0
  118. package/dist/use-test-input.d.ts +18 -0
  119. package/dist/workflow-connections.d.ts +30 -0
  120. package/package.json +18 -7
  121. package/src/code.css +60 -6
  122. package/src/styles/_budget-meter.scss +46 -0
  123. package/src/styles/_callable-list.scss +15 -6
  124. package/src/styles/_canvas.scss +353 -0
  125. package/src/styles/_code-editor.scss +35 -0
  126. package/src/styles/_code.scss +6 -5
  127. package/src/styles/_connections.scss +2 -14
  128. package/src/styles/_copyable.scss +24 -0
  129. package/src/styles/_data-stores.scss +138 -0
  130. package/src/styles/_data-table.scss +55 -0
  131. package/src/styles/_data-vars.scss +17 -6
  132. package/src/styles/_empty-state.scss +21 -0
  133. package/src/styles/_execution-history.scss +73 -0
  134. package/src/styles/_execution-log.scss +145 -1
  135. package/src/styles/_expression-modal.scss +106 -16
  136. package/src/styles/_fields.scss +11 -0
  137. package/src/styles/_flow.scss +171 -0
  138. package/src/styles/_fx.scss +26 -1
  139. package/src/styles/_incoming-state.scss +33 -0
  140. package/src/styles/_layout.scss +10 -0
  141. package/src/styles/_markdown.scss +20 -0
  142. package/src/styles/_modal.scss +12 -0
  143. package/src/styles/_multiselect.scss +35 -0
  144. package/src/styles/_sections.scss +36 -0
  145. package/src/styles/_step-builder.scss +145 -0
  146. package/src/styles/_tester.scss +57 -14
  147. package/src/styles/_tokens.scss +27 -1
  148. package/src/styles.css +1861 -115
  149. package/src/styles.scss +7 -0
  150. package/dist/CodeBlock-CZu4TFSi.cjs +0 -15
  151. package/dist/CodeBlock-CZu4TFSi.cjs.map +0 -1
  152. package/dist/CodeBlock-Dot3Pd7P.js.map +0 -1
  153. package/dist/ConfirmModal-ChoiGy2K.cjs +0 -11
  154. package/dist/ConfirmModal-ChoiGy2K.cjs.map +0 -1
  155. package/dist/ConfirmModal-Wx3i8F1n.js +0 -6359
  156. package/dist/ConfirmModal-Wx3i8F1n.js.map +0 -1
  157. package/dist/Copyable-1niV9gUa.js +0 -771
  158. package/dist/Copyable-1niV9gUa.js.map +0 -1
  159. package/dist/Copyable-CYZU1o4X.cjs +0 -2
  160. package/dist/Copyable-CYZU1o4X.cjs.map +0 -1
package/dist/types.d.ts CHANGED
@@ -1,8 +1,4 @@
1
- /**
2
- * Wire types the components consume. These mirror the shapes the w6w server
3
- * returns over HTTP. They are intentionally a local copy so consumers who
4
- * don't use `@w6w/types` (partners, non-TypeScript backends) don't need it.
5
- */
1
+ import { ParamWhen } from '@w6w/expr';
6
2
  /** Summary of a registered app as returned by GET /apps. */
7
3
  export interface AppSummary {
8
4
  id: string;
@@ -22,12 +18,19 @@ export interface AppSummary {
22
18
  maturity?: string;
23
19
  visibility?: string;
24
20
  successor?: string;
21
+ /** Model-provider designation; absent when the app does not declare one. */
22
+ modelProvider?: {
23
+ modelTypes: string[];
24
+ modelFamilies?: string[];
25
+ };
25
26
  /**
26
27
  * True when the calling tenant has zero-credential access flagged for this
27
28
  * app — usable with no connection step at all (server-computed per caller;
28
29
  * `packages/server/packages/api/wire-summary.ts`'s `zeroCredential`).
29
30
  */
30
31
  zeroCredential?: boolean;
32
+ /** Number of triggers the app declares (wire already carries it). */
33
+ triggerCount?: number;
31
34
  }
32
35
  /** One trigger an app declares, as returned by GET /apps/:id/triggers. */
33
36
  export interface TriggerSummary {
@@ -38,9 +41,15 @@ export interface TriggerSummary {
38
41
  description?: string;
39
42
  requiresAuth?: boolean;
40
43
  /** `"poll"` triggers are fetched on an interval; absent or `"webhook"` receive pushes. */
41
- type?: "webhook" | "poll";
44
+ type?: "webhook" | "poll" | "protocol";
42
45
  /** Host floor for a poll trigger's interval, in milliseconds. */
43
46
  minIntervalMs?: number;
47
+ /** The trigger's declared parameters (the route returns the full declaration). */
48
+ params?: readonly unknown[];
49
+ /** The event's declared fields (an `OutputField[]`) — keys for `trigger.event.<key>`. */
50
+ output?: unknown;
51
+ /** A representative event payload the app declares (never fabricated). */
52
+ sample?: unknown;
44
53
  }
45
54
  /** A Subscription (rfcs/trigger.md) as returned by the console subscription routes. */
46
55
  export interface SubscriptionSummary {
@@ -51,15 +60,43 @@ export interface SubscriptionSummary {
51
60
  connectionId: string | null;
52
61
  /** Present only for `appId === "@w6w/webhook"` — the server's own computed receive URL. */
53
62
  webhookUrl?: string;
54
- type?: "webhook" | "poll";
55
- status?: string;
63
+ type?: "webhook" | "poll" | "protocol";
64
+ status?: SubscriptionStatus;
56
65
  /** Poll interval in milliseconds; null for webhook subscriptions. */
57
66
  intervalMs?: number | null;
58
67
  lastError?: {
59
68
  code: string;
60
69
  message: string;
61
70
  } | null;
71
+ /** The workflow trigger node this subscription is bound to; null for a workflow-level one. */
72
+ nodeId?: string | null;
73
+ /** When registration with the app succeeded; null until it has. */
74
+ registeredAt?: string | null;
75
+ /** When the subscription last fired; null/absent when it never has. */
76
+ lastFireAt?: string | null;
77
+ }
78
+ /**
79
+ * A "Listen for test event" session on a `@w6w/webhook` subscription
80
+ * (`POST /subscriptions/:id/listen`). `request` is the captured, credential-masked call —
81
+ * exactly what a real run's webhook trigger emits as its output.
82
+ */
83
+ export interface WebhookListenSession {
84
+ id: string;
85
+ subscriptionId: string;
86
+ nodeId: string | null;
87
+ expiresAt: string;
88
+ status: "waiting" | "captured" | "expired";
89
+ request?: {
90
+ method: string;
91
+ path: string;
92
+ query: Record<string, string>;
93
+ headers: Record<string, string>;
94
+ body: unknown;
95
+ };
96
+ receivedAt?: string;
62
97
  }
98
+ /** Registration state of a Subscription (rfcs/trigger-protocol.md §Lifecycle). */
99
+ export type SubscriptionStatus = "pending" | "registered" | "failed" | "paused" | "destroying";
63
100
  /** One field on an Auth method's connection form. Drives the input widgets. */
64
101
  export interface AuthField {
65
102
  key: string;
@@ -68,6 +105,8 @@ export interface AuthField {
68
105
  required?: boolean;
69
106
  default?: unknown;
70
107
  hint?: string;
108
+ /** Masks the input like a `secret` field whatever its `type` (e.g. a `json` key file). */
109
+ secret?: boolean;
71
110
  }
72
111
  /**
73
112
  * One declared parameter of an action, as returned by GET /apps/:id (the
@@ -87,6 +126,8 @@ export interface ActionParam {
87
126
  required?: boolean;
88
127
  default?: unknown;
89
128
  hint?: string;
129
+ /** Render hint; multiselect supports "checkboxes" or the default chip picker. */
130
+ ui?: string;
90
131
  /** Placeholder text for the input (e.g. the trailing prompt on a multiselect). */
91
132
  placeholder?: string;
92
133
  /**
@@ -95,6 +136,18 @@ export interface ActionParam {
95
136
  * params (they always show).
96
137
  */
97
138
  advanced?: boolean;
139
+ /**
140
+ * The field holds ONE value or expression, never a composed container: in the JSON-binding
141
+ * editor, picking a reference into an empty draft (or a bare `[]` / `{}`) stores the bare
142
+ * whole-value ref `"{{ ref }}"`, not `[ref]`. A literal still can be typed.
143
+ */
144
+ whole?: boolean;
145
+ /**
146
+ * The param is declared on the action but never rendered by any param form, and never gates
147
+ * the required check. Its stored value is preserved untouched (e.g. a canvas-owned `body`).
148
+ * Not the entry-level `InternalNodeDef.hidden` (a palette hide).
149
+ */
150
+ hidden?: boolean;
98
151
  /**
99
152
  * Lay this param out on a shared row with adjacent params carrying the same
100
153
  * `row` id — e.g. a username/password pair side by side.
@@ -115,11 +168,17 @@ export interface ActionParam {
115
168
  * (e.g. Basic-auth fields shown only when `auth` is `"basic"`).
116
169
  */
117
170
  showIf?: ParamCondition;
171
+ /**
172
+ * Conditional overlay: the first entry whose `if` holds overlays
173
+ * label/hint/required/ui/options onto this param (see `effectiveParam` in
174
+ * `@w6w/expr`). Mirrors `@w6w/types`' `Param.when`.
175
+ */
176
+ when?: ParamWhen<ParamOption[] | DynamicOptions>[];
118
177
  /**
119
178
  * Constrained choices. Renders as a single-select dropdown for `select` (or any
120
179
  * param with options), and as a multi-select pill picker for `multiselect`.
121
180
  */
122
- options?: ParamOption[];
181
+ options?: ParamOption[] | DynamicOptions;
123
182
  /** Type-specific render/behavior options. */
124
183
  config?: ParamConfig;
125
184
  /**
@@ -141,11 +200,47 @@ export interface ActionParam {
141
200
  layout?: "row" | "stack";
142
201
  /** `section: "collapsible"` only — start collapsed (default `true`). */
143
202
  collapsed?: boolean;
203
+ /** `section: "collapsible"` only — start open when any child already holds a value. */
204
+ openWhenSet?: boolean;
205
+ /**
206
+ * `type: "code"` only — a Run script's code, which reads run data from its `state` / `vars` /
207
+ * `consts` globals: its insert actions write code reads, never `{{ }}` (the host does not
208
+ * substitute in code).
209
+ */
210
+ scriptReads?: boolean;
144
211
  }
145
212
  /** A single choice for a param rendered as a dropdown. */
146
213
  export interface ParamOption {
147
214
  value: string | number;
148
215
  label: string;
216
+ description?: string;
217
+ }
218
+ /** Host-resolved options (mirrors @w6w/types `DynamicOptions`). */
219
+ export interface DynamicOptions {
220
+ source: string;
221
+ searchable?: boolean;
222
+ cache?: "session" | "none";
223
+ refreshOn?: string[];
224
+ }
225
+ /** True for the form-resolved arm: a non-array object with `source === "resolveFields"`. */
226
+ export declare function isFormResolvedOptions(o: unknown): o is DynamicOptions;
227
+ /** Body of `W6WApi.resolveActionFields`. */
228
+ export interface ResolveFieldsBody {
229
+ connectionId: string;
230
+ version?: string;
231
+ reason: "init" | "change";
232
+ form: Record<string, unknown>;
233
+ previous?: Record<string, unknown>;
234
+ changed?: string[];
235
+ fields: string[];
236
+ unresolved: string[];
237
+ }
238
+ /** Result of `W6WApi.resolveActionFields`. */
239
+ export interface ResolveFieldsResult {
240
+ fields: Record<string, {
241
+ options?: ParamOption[];
242
+ error?: string;
243
+ }>;
149
244
  }
150
245
  /**
151
246
  * The element schema for a `type: "array"` param. Either a scalar list
@@ -184,6 +279,10 @@ export interface ParamCondition {
184
279
  export interface ParamConfig {
185
280
  /** Render as a multi-line textarea. Implied by `type: "text"`. */
186
281
  multiline?: boolean;
282
+ /** With options: accept a value not in the list (Combobox `forceSelection` off). */
283
+ allowCustom?: boolean;
284
+ /** Multiselect storage format. Defaults to an array; CSV preserves string-based API inputs. */
285
+ valueFormat?: "array" | "csv";
187
286
  }
188
287
  /** Summary of an action an app exposes, as returned by GET /apps/:id. */
189
288
  export interface ActionDef {
@@ -267,16 +366,83 @@ export interface WorkflowDetail {
267
366
  name: string;
268
367
  displayName?: string;
269
368
  description?: string;
270
- steps: WorkflowStepSummary[];
369
+ /** The canonical (manifest v2) step list. */
370
+ nodes?: WorkflowStepSummary[];
371
+ /** The legacy (v1) step list; a definition carries one or the other. */
372
+ steps?: WorkflowStepSummary[];
373
+ }
374
+ /** A `serviceAccount` auth's declaration: the credential contract it accepts and its binding. */
375
+ export interface ServiceAccountConfig {
376
+ /** Credential contract ids this auth accepts; the first one is used to list/create. */
377
+ accepts: string[];
378
+ /** Scopes the binding requests by default (shown read-only; the server applies them). */
379
+ scopes: string[];
380
+ /** Whether a connection must/may name an impersonated user (`delegatedUser`). */
381
+ impersonation: "none" | "optional" | "required";
382
+ /** Extra per-connection (binding) fields; each lands in `binding.settings`. */
383
+ bindingFields?: AuthField[];
384
+ }
385
+ export type CredentialStatus = "active" | "disabled" | "revoked";
386
+ /** A stored credential as the API lists it. Never carries the secret payload. */
387
+ export interface CredentialSummary {
388
+ id: string;
389
+ name: string;
390
+ contract: string;
391
+ status: CredentialStatus | string;
392
+ revision: number;
393
+ /** Non-secret display values (e.g. the service account's email). */
394
+ display: Record<string, string>;
395
+ private: boolean;
396
+ connectionCount: number;
397
+ createdAt: string;
398
+ updatedAt: string;
399
+ }
400
+ /** The connections that use a credential. */
401
+ export interface CredentialDependents {
402
+ connections: Array<{
403
+ id: string;
404
+ appId: string;
405
+ authKey: string;
406
+ displayName?: string | null;
407
+ }>;
408
+ }
409
+ export interface CredentialTestResult {
410
+ ok: boolean;
411
+ code?: string;
412
+ message?: string;
413
+ }
414
+ /** Per-connection settings applied on top of a shared credential. */
415
+ export interface ConnectionBinding {
416
+ scopes?: string[];
417
+ /** The user the credential impersonates (Google domain-wide delegation). */
418
+ delegatedUser?: string;
419
+ settings?: Record<string, string | number | boolean>;
271
420
  }
421
+ /** Body of `createConnection`: an inline credential XOR a reference to a stored one. */
422
+ export type CreateConnectionBody = {
423
+ authKey: string;
424
+ credential: Record<string, unknown>;
425
+ credentialId?: never;
426
+ displayName?: string;
427
+ profile?: Record<string, unknown>;
428
+ } | {
429
+ authKey: string;
430
+ credentialId: string;
431
+ credential?: never;
432
+ binding?: ConnectionBinding;
433
+ displayName?: string;
434
+ profile?: never;
435
+ };
272
436
  /** Auth method declaration as exposed by an app's manifest. */
273
437
  export interface AuthDef {
274
438
  key: string;
275
- type: "oauth2" | "apiKey" | "basic" | "bearer" | "custom" | "tenantAuth" | "jit" | string;
439
+ type: "oauth2" | "apiKey" | "basic" | "bearer" | "custom" | "tenantAuth" | "jit" | "serviceAccount" | string;
276
440
  displayName?: string;
277
441
  description?: string;
278
442
  connectionLabel?: string;
279
443
  fields?: AuthField[];
444
+ /** Present when `type === "serviceAccount"`: what credential it accepts and how it binds. */
445
+ serviceAccount?: ServiceAccountConfig;
280
446
  /** OAuth2 endpoints (only present when type === "oauth2"). */
281
447
  oauth2?: Record<string, unknown>;
282
448
  /**
@@ -314,6 +480,8 @@ export interface ConnectionSummary {
314
480
  id: string;
315
481
  appId: string;
316
482
  authKey: string;
483
+ /** The stored credential this connection uses, when it has one. */
484
+ credentialId?: string | null;
317
485
  /** The owning tenant. The server sends `tenant`/`subject`, never `owner`. */
318
486
  tenant?: string;
319
487
  /** The owning subject (the partner's user id). */
@@ -1,7 +1,15 @@
1
1
  import { PortsLookup } from './flow-types.ts';
2
2
  import { StepNode } from './flow-utils.ts';
3
3
  import { W6WApi } from './provider.tsx';
4
- import { ActionDef } from './types.ts';
4
+ import { ActionDef, TriggerSummary } from './types.ts';
5
5
  export declare function useAppActionDefs(api: W6WApi, nodes: StepNode[]): Record<string, ActionDef[]>;
6
+ /**
7
+ * The trigger definitions of every app a workflow's APP-TRIGGER nodes (`uses.trigger === true`)
8
+ * use, so the editor can offer `trigger.event.<field>` from a trigger's declared `output` /
9
+ * `sample` without a run. Same shape as {@link useAppActionDefs}: fetched once per app id
10
+ * (`getAppTriggers`, optional on the api — absent means no claim), keyed on the sorted set of
11
+ * app ids, best-effort, a failed fetch retried by a later change.
12
+ */
13
+ export declare function useAppTriggerDefs(api: W6WApi, nodes: StepNode[]): Record<string, TriggerSummary[]>;
6
14
  /** Build a `PortsLookup` over the fetched catalog defs (`useAppActionDefs`' result). */
7
15
  export declare function portsLookupFromDefs(defs: Record<string, ActionDef[]>): PortsLookup;
@@ -0,0 +1,23 @@
1
+ import { DynamicContext } from './dynamic-fields.ts';
2
+ import { ActionParam, ParamOption } from './types.ts';
3
+ /** Per-field state the form renders from. */
4
+ export interface DynamicFieldState {
5
+ options?: ParamOption[];
6
+ loading: boolean;
7
+ error?: string;
8
+ /** Why the field is free text (no connection / unresolved refreshOn). */
9
+ hint?: string;
10
+ /** Flag for a kept value not in the returned list. */
11
+ notInList?: string;
12
+ }
13
+ export interface UseDynamicFields {
14
+ fields: Record<string, DynamicFieldState>;
15
+ /** A pick committed `value` for `key` (select/Combobox/checkbox): one change call if any field refreshes on it. */
16
+ commit(key: string, value: unknown): void;
17
+ /** Focus entered `key`: remember the pre-edit form (the `previous` of a later blur commit). */
18
+ focus(key: string): void;
19
+ /** Focus left `key`: commit a text edit made since focus (never per keystroke). */
20
+ blur(key: string): void;
21
+ retry(key: string): void;
22
+ }
23
+ export declare function useDynamicFields(params: ActionParam[], values: Record<string, unknown>, dynamic: DynamicContext | undefined, onChange: (next: Record<string, unknown>) => void): UseDynamicFields;
@@ -0,0 +1,18 @@
1
+ import { ActionParam } from './types.ts';
2
+ export interface RememberedTestInput {
3
+ /** `true` once the read settled (or there was nothing to read). */
4
+ loaded: boolean;
5
+ /** `false` when the host has no `loadTestInputs` — fall back to the older source. */
6
+ supported: boolean;
7
+ /** `undefined` = no row; `{}` = cleared; else the values last used. */
8
+ input: Record<string, unknown> | undefined;
9
+ /** Remember `values` (secret literals dropped). Best-effort: never throws. */
10
+ save: (values: Record<string, unknown>, params?: readonly ActionParam[]) => void;
11
+ /** Forget the values (stored as `{}`, so no older source refills the form). */
12
+ clear: () => void;
13
+ }
14
+ export declare function useRememberedTestInput(workflowId: string | undefined, nodeId: string | undefined): RememberedTestInput;
15
+ /** The small muted note under a prefilled form: "last used values · Clear". */
16
+ export declare function LastUsedNote({ onClear }: {
17
+ onClear: () => void;
18
+ }): import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { FlowStep, FlowWorkflow } from './flow-types.ts';
2
+ import { AuthDef, ConnectionSummary } from './types.ts';
3
+ export type FlowConnections = Record<string, {
4
+ app: string;
5
+ connection: string | null;
6
+ }>;
7
+ /** Missing/foreign bindings stay unresolved in the editor; the server rejects invalid references. */
8
+ export declare function connectionIdFor(step: FlowStep, connections?: FlowConnections): string | undefined;
9
+ /** Lift old inline IDs on the next editor save. Independent bindings remain independent. */
10
+ export declare function centralizeConnections<T extends Pick<FlowWorkflow, "connections" | "nodes">>(workflow: T): T;
11
+ /** Drop only unreferenced aliases when serializing the complete workflow. */
12
+ export declare function pruneUnusedConnections<T extends Pick<FlowWorkflow, "connections" | "nodes">>(workflow: T): T;
13
+ export declare function withConnectionRef(step: FlowStep, connectionRef: string): FlowStep;
14
+ /** An ordinary account selection affects this node only, detaching it from a shared entry. */
15
+ export declare function selectNodeConnection(step: FlowStep, connection: string | undefined, nodes: FlowStep[], connections: FlowConnections): {
16
+ step: FlowStep;
17
+ connections: FlowConnections;
18
+ };
19
+ export declare function connectionSourceNodes(step: FlowStep, nodes: FlowStep[], connections: FlowConnections): FlowStep[];
20
+ /** Accounts used anywhere in the workflow, including independently stored bindings. */
21
+ export declare function connectionUsers(app: string, connection: string | undefined, nodes: FlowStep[], connections: FlowConnections): FlowStep[];
22
+ /** An explicit initial selection wins; otherwise inherit the last added configured node. */
23
+ export declare function defaultConnectionFor(step: FlowStep, choices: ConnectionSummary[], nodes: FlowStep[], connections: FlowConnections, initialConnection?: string): {
24
+ connection?: string;
25
+ connectionRef?: string;
26
+ };
27
+ /** The server's zero-credential sentinel is a real picker choice, without creating a row. */
28
+ export declare function withDefaultConnection(appId: string, auths: AuthDef[], choices: ConnectionSummary[]): ConnectionSummary[];
29
+ /** Change every binding used by the displayed account's consumers, retaining reference keys. */
30
+ export declare function replaceWorkflowConnection(app: string, before: string, after: string, nodes: FlowStep[], connections: FlowConnections): FlowConnections;
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@w6w/ui",
3
- "version": "0.2.0",
3
+ "version": "0.2.54",
4
4
  "description": "React components for w6w — central API management. Build plugins, apps and integrations on them.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://w6w.io",
7
7
  "author": "W6W (https://w6w.io)",
8
- "bugs": "https://github.com/w6w-io/w6w-ui/issues",
8
+ "bugs": "https://github.com/w6w-io/w6w-studio/issues",
9
9
  "keywords": [
10
10
  "w6w",
11
11
  "react",
@@ -14,7 +14,8 @@
14
14
  ],
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://github.com/w6w-io/w6w-ui.git"
17
+ "url": "https://github.com/w6w-io/w6w-studio.git",
18
+ "directory": "packages/ui"
18
19
  },
19
20
  "type": "module",
20
21
  "main": "./dist/index.cjs",
@@ -71,9 +72,12 @@
71
72
  "@codemirror/state": "^6.5.0",
72
73
  "@codemirror/view": "^6.35.0",
73
74
  "@uiw/react-codemirror": "^4.23.7",
74
- "@w6w/expr": "^0.1.0",
75
+ "@w6w/expr": "^0.1.2",
75
76
  "@xyflow/react": "^12.3.6",
76
- "prism-react-renderer": "^2.4.1"
77
+ "prism-react-renderer": "^2.4.1",
78
+ "react-markdown": "^10.1.0",
79
+ "typescript": "^5.7.2",
80
+ "@codemirror/autocomplete": "^6.18.0"
77
81
  },
78
82
  "devDependencies": {
79
83
  "@biomejs/biome": "^1.9.4",
@@ -89,7 +93,6 @@
89
93
  "react-dom": "^18.3.1",
90
94
  "sass": "^1.102.0",
91
95
  "storybook": "^10.5.8",
92
- "typescript": "^5.7.2",
93
96
  "vite": "^6.0.5",
94
97
  "vite-plugin-dts": "^4.3.0"
95
98
  },
@@ -100,16 +103,24 @@
100
103
  "typecheck": "tsc -b --noEmit",
101
104
  "test": "node --max-old-space-size=2048 --conditions=w6w-source --import ./src/test-jsx-loader.mjs --test --test-concurrency=4 --test-timeout=120000 src/__tests__/*.test.ts src/components/__tests__/*.test.ts",
102
105
  "test:picker-layout": "bash test/picker-layout/run.sh",
106
+ "test:canvas-layer": "bash test/canvas-layer/run.sh",
107
+ "test:foreach-loop": "bash test/foreach-loop/run.sh",
103
108
  "test:expr-template": "bash test/expr-template/run.sh",
109
+ "test:friendly-expressions": "node test/friendly-expressions/run.mjs",
104
110
  "test:action-test-form": "bash test/action-test-form/run.sh",
105
111
  "test:host-isolation": "bash test/host-isolation/run.sh",
106
112
  "test:copyable": "bash test/copyable/run.sh",
113
+ "test:code-editor-fill": "bash test/code-editor-fill/run.sh",
107
114
  "test:pack-smoke": "bash test/pack-smoke/run.sh",
108
115
  "storybook": "storybook dev -p 6006 --no-open",
109
116
  "build-storybook": "storybook build",
110
117
  "lint": "biome check .",
111
118
  "lint:tokens": "node scripts/lint-tokens.mjs",
112
119
  "coverage:stories": "node scripts/coverage-stories.mjs",
113
- "format": "biome format --write ."
120
+ "format": "biome format --write .",
121
+ "test:workflow-connections": "node test/workflow-connections/run.mjs",
122
+ "test:workflow-undo": "node test/workflow-connections/undo.mjs",
123
+ "test:workflow-context-menu": "node test/workflow-connections/context-menu.mjs",
124
+ "test:script-completion": "node test/script-completion/run.mjs"
114
125
  }
115
126
  }
package/src/code.css CHANGED
@@ -32,7 +32,9 @@
32
32
  * host rule — even a plain `:root { ... }` — wins without !important. Tokens are
33
33
  * defined on :root so every `.w6w-*` component inherits them out of the box.
34
34
  */
35
- /* Light — the base defaults. */
35
+ /* Light — the base defaults.
36
+ `--w6w-loop-N` is the For each palette (flow-loop-colors.ts, LOOP_TONES): no red,
37
+ black or green, so a loop never reads as an error port or a success edge. */
36
38
  :where(:root) {
37
39
  --w6w-bg: #f7f8fa;
38
40
  --w6w-panel: #ffffff;
@@ -48,6 +50,12 @@
48
50
  --w6w-health-down: var(--w6w-danger);
49
51
  --w6w-health-unknown: #5f6875;
50
52
  --w6w-icon-swatch: #f0f2f6;
53
+ --w6w-loop-1: #2f6fdf;
54
+ --w6w-loop-2: #7c4ddb;
55
+ --w6w-loop-3: #b7791f;
56
+ --w6w-loop-4: #0e8fa8;
57
+ --w6w-loop-5: #b0399f;
58
+ --w6w-loop-6: #4f4fc7;
51
59
  --w6w-code-comment: #6b7280;
52
60
  --w6w-code-keyword: #8250df;
53
61
  --w6w-code-string: #0a7b34;
@@ -77,6 +85,12 @@
77
85
  --w6w-health-down: var(--w6w-danger);
78
86
  --w6w-health-unknown: #9aa3b2;
79
87
  --w6w-icon-swatch: #1f232c;
88
+ --w6w-loop-1: #5b9bff;
89
+ --w6w-loop-2: #a98bff;
90
+ --w6w-loop-3: #f0b13a;
91
+ --w6w-loop-4: #3cc6e0;
92
+ --w6w-loop-5: #e47ad6;
93
+ --w6w-loop-6: #8a8aff;
80
94
  --w6w-scheme: dark;
81
95
  --w6w-code-comment: #7d8797;
82
96
  --w6w-code-keyword: #d2a8ff;
@@ -105,6 +119,12 @@
105
119
  --w6w-health-down: var(--w6w-danger);
106
120
  --w6w-health-unknown: #5f6875;
107
121
  --w6w-icon-swatch: #f0f2f6;
122
+ --w6w-loop-1: #2f6fdf;
123
+ --w6w-loop-2: #7c4ddb;
124
+ --w6w-loop-3: #b7791f;
125
+ --w6w-loop-4: #0e8fa8;
126
+ --w6w-loop-5: #b0399f;
127
+ --w6w-loop-6: #4f4fc7;
108
128
  --w6w-code-comment: #6b7280;
109
129
  --w6w-code-keyword: #8250df;
110
130
  --w6w-code-string: #0a7b34;
@@ -130,6 +150,12 @@
130
150
  --w6w-health-down: var(--w6w-danger);
131
151
  --w6w-health-unknown: #9aa3b2;
132
152
  --w6w-icon-swatch: #1f232c;
153
+ --w6w-loop-1: #5b9bff;
154
+ --w6w-loop-2: #a98bff;
155
+ --w6w-loop-3: #f0b13a;
156
+ --w6w-loop-4: #3cc6e0;
157
+ --w6w-loop-5: #e47ad6;
158
+ --w6w-loop-6: #8a8aff;
133
159
  --w6w-code-comment: #7d8797;
134
160
  --w6w-code-keyword: #d2a8ff;
135
161
  --w6w-code-string: #7ee787;
@@ -405,6 +431,32 @@
405
431
  min-width: 0;
406
432
  }
407
433
 
434
+ /* ── Hover modifier: ResultViewer — the button overlays the top-right corner of
435
+ ANY child and is revealed on hover/focus; always shown where there is no hover. */
436
+ .w6w-copyable--hover {
437
+ position: relative;
438
+ align-items: flex-start;
439
+ }
440
+
441
+ .w6w-copyable--hover > .w6w-copyable-btn {
442
+ position: absolute;
443
+ top: var(--w6w-sp-1);
444
+ right: var(--w6w-sp-1);
445
+ background: var(--w6w-panel);
446
+ border-color: var(--w6w-border);
447
+ opacity: 0;
448
+ }
449
+
450
+ .w6w-copyable--hover:hover > .w6w-copyable-btn,
451
+ .w6w-copyable--hover:focus-within > .w6w-copyable-btn {
452
+ opacity: 1;
453
+ }
454
+
455
+ @media (hover: none) {
456
+ .w6w-copyable--hover > .w6w-copyable-btn {
457
+ opacity: 1;
458
+ }
459
+ }
408
460
  .w6w-code-block {
409
461
  background: var(--w6w-panel-2);
410
462
  border: 1px solid var(--w6w-border);
@@ -528,15 +580,17 @@
528
580
  /* The expanded form of a clipped value (`resolved-clip.ts`). A block with its
529
581
  own scroll, so "Show all" can never restore the unbounded inline paste that
530
582
  buried the other params and the run's result. */
583
+ .w6w-resolved-copy {
584
+ margin: var(--w6w-sp-1) 0;
585
+ }
586
+
531
587
  .w6w-resolved-text-full {
532
588
  display: block;
533
- margin: var(--w6w-sp-1) 0;
589
+ margin: 0;
534
590
  max-height: 14em;
535
591
  overflow: auto;
536
- padding: var(--w6w-sp-2);
537
- background: var(--w6w-panel-2);
538
- border: 1px solid var(--w6w-border);
539
- border-radius: var(--w6w-radius);
592
+ padding: 0;
593
+ padding-right: var(--w6w-sp-10);
540
594
  font-family: var(--w6w-font-mono);
541
595
  font-size: 0.85em; /* lint-tokens-allow: matches the sibling code-typography rules above in this same file */
542
596
  line-height: var(--w6w-lh-normal);
@@ -0,0 +1,46 @@
1
+ /* BudgetMeter — usage-vs-limit bar with a reserved segment.
2
+ *
3
+ * Token-only: every colour is a --w6w-* custom property, so a host restyles
4
+ * the meter (including the over-limit state) by overriding tokens, never by
5
+ * targeting a hex value here. */
6
+ .w6w-budget-meter {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--w6w-sp-1);
10
+ }
11
+ .w6w-budget-meter-head {
12
+ display: flex;
13
+ align-items: baseline;
14
+ justify-content: space-between;
15
+ gap: var(--w6w-sp-2);
16
+ color: var(--w6w-muted);
17
+ }
18
+ .w6w-budget-meter-label {
19
+ color: var(--w6w-text);
20
+ }
21
+ .w6w-budget-meter-value {
22
+ font-variant-numeric: tabular-nums;
23
+ }
24
+ .w6w-budget-meter-track {
25
+ display: flex;
26
+ width: 100%;
27
+ height: 8px;
28
+ overflow: hidden;
29
+ background: var(--w6w-panel-2);
30
+ border: 1px solid var(--w6w-border);
31
+ border-radius: var(--w6w-radius);
32
+ }
33
+ .w6w-budget-meter-used {
34
+ height: 100%;
35
+ background: var(--w6w-accent);
36
+ }
37
+ .w6w-budget-meter-reserved {
38
+ height: 100%;
39
+ background: var(--w6w-health-degraded);
40
+ }
41
+ .w6w-budget-meter-over .w6w-budget-meter-used {
42
+ background: var(--w6w-danger);
43
+ }
44
+ .w6w-budget-meter-over .w6w-budget-meter-value {
45
+ color: var(--w6w-danger);
46
+ }
@@ -36,15 +36,21 @@
36
36
  .w6w-callable-list-body {
37
37
  border: 1px solid var(--w6w-border);
38
38
  border-radius: 8px;
39
- padding: var(--w6w-sp-2);
39
+ background: var(--w6w-panel);
40
+ overflow: hidden;
40
41
  }
41
- .w6w-callable-list-rows {
42
- list-style: none;
43
- margin: 0;
44
- padding: 0;
42
+ .w6w-callable-list-main {
45
43
  display: flex;
46
44
  flex-direction: column;
47
- gap: var(--w6w-sp-1);
45
+ gap: var(--w6w-sp-0-5);
46
+ min-width: 0;
47
+ text-align: left;
48
+ }
49
+ .w6w-callable-list-open {
50
+ all: unset;
51
+ cursor: pointer;
52
+ display: block;
53
+ width: 100%;
48
54
  }
49
55
  .w6w-callable-list-trail {
50
56
  display: inline-flex;
@@ -58,3 +64,6 @@
58
64
  color: var(--w6w-muted);
59
65
  font-size: var(--w6w-fs-xs);
60
66
  }
67
+ .w6w-callable-list-row-desc {
68
+ display: block;
69
+ }