@w6w/embed 0.1.0 → 0.2.0
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.
- package/README.md +231 -4
- package/dist/ConfirmModal-RLbZT5_k.js +181 -0
- package/dist/ConfirmModal-RLbZT5_k.js.map +1 -0
- package/dist/CreateFunctionModal-DRsFx-FB.js +221 -0
- package/dist/CreateFunctionModal-DRsFx-FB.js.map +1 -0
- package/dist/DocumentFormModal-BExK1V-B.js +89 -0
- package/dist/DocumentFormModal-BExK1V-B.js.map +1 -0
- package/dist/ImportSpecModal-BDQIf6rg.js +136 -0
- package/dist/ImportSpecModal-BDQIf6rg.js.map +1 -0
- package/dist/W6WEmbedProvider.d.ts +22 -4
- package/dist/WorkflowEditor-DlbVv6Fs.js +854 -0
- package/dist/WorkflowEditor-DlbVv6Fs.js.map +1 -0
- package/dist/api-calls--JHyif6a.js +107 -0
- package/dist/api-calls--JHyif6a.js.map +1 -0
- package/dist/apps-1FNUwbGv.js +77 -0
- package/dist/apps-1FNUwbGv.js.map +1 -0
- package/dist/callables-3mFrMVG_.js +151 -0
- package/dist/callables-3mFrMVG_.js.map +1 -0
- package/dist/chrome/index.d.ts +6 -0
- package/dist/chrome/workspace.d.ts +29 -1
- package/dist/coerce-input-BicYr7nc.js +139 -0
- package/dist/coerce-input-BicYr7nc.js.map +1 -0
- package/dist/connections-CjjYeRqb.js +78 -0
- package/dist/connections-CjjYeRqb.js.map +1 -0
- package/dist/document-sources-C0grrtdq.js +86 -0
- package/dist/document-sources-C0grrtdq.js.map +1 -0
- package/dist/draft/index.d.ts +3 -1
- package/dist/draft/use-callable-draft.d.ts +65 -0
- package/dist/draft/workflow-save.d.ts +3 -0
- package/dist/draft.mjs +9 -5
- package/dist/draft.mjs.map +1 -1
- package/dist/editor/CallableEditorFrame.d.ts +33 -0
- package/dist/editor/EditorShell.d.ts +16 -0
- package/dist/editor/EndpointCards.d.ts +56 -0
- package/dist/editor/EndpointEditor.d.ts +26 -0
- package/dist/editor/FunctionEditor.d.ts +21 -0
- package/dist/editor/InputListEditor.d.ts +29 -0
- package/dist/editor/TargetSelector.d.ts +30 -0
- package/dist/editor/TargetSelector.types.d.ts +62 -0
- package/dist/editor/editor-apps.d.ts +8 -2
- package/dist/editor/types.d.ts +57 -0
- package/dist/editor-apps-BdenSV1o.js +95 -0
- package/dist/editor-apps-BdenSV1o.js.map +1 -0
- package/dist/editor-tools-RxmY5iyi.js +1279 -0
- package/dist/editor-tools-RxmY5iyi.js.map +1 -0
- package/dist/editor.mjs +2 -2166
- package/dist/editor.mjs.map +1 -1
- package/dist/editors/DocumentEditor.d.ts +20 -0
- package/dist/editors/doc-format.d.ts +3 -0
- package/dist/editors.d.ts +12 -0
- package/dist/editors.mjs +1313 -0
- package/dist/editors.mjs.map +1 -0
- package/dist/embed-status.d.ts +20 -0
- package/dist/endpoints-B2ynbZo-.js +227 -0
- package/dist/endpoints-B2ynbZo-.js.map +1 -0
- package/dist/forms/CreateEndpointModal.d.ts +54 -0
- package/dist/forms/CreateFunctionModal.d.ts +55 -0
- package/dist/forms/DocumentFormModal.d.ts +8 -0
- package/dist/forms/SecretsManager.d.ts +12 -0
- package/dist/forms/VarsManager.d.ts +29 -0
- package/dist/forms.d.ts +6 -0
- package/dist/forms.mjs +407 -0
- package/dist/forms.mjs.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +153 -50
- package/dist/index.mjs.map +1 -1
- package/dist/lib/callable-record.d.ts +21 -0
- package/dist/lib/coerce-input.d.ts +6 -0
- package/dist/lib/endpoint-editor.d.ts +23 -0
- package/dist/lib/index.d.ts +7 -0
- package/dist/lib/input-coverage.d.ts +28 -0
- package/dist/lib/input-seeding.d.ts +67 -0
- package/dist/lib/rail-settings.d.ts +3 -3
- package/dist/lib/recent-activity.d.ts +128 -0
- package/dist/lib/target-fields.d.ts +168 -0
- package/dist/lib/workflow-blank.d.ts +2 -0
- package/dist/lib.mjs +70 -48
- package/dist/lib.mjs.map +1 -1
- package/dist/lists/ActivitySummary.d.ts +29 -0
- package/dist/lists/CallableKindList.d.ts +34 -0
- package/dist/lists/ConnectionDetail.d.ts +17 -0
- package/dist/lists/ConnectionList.d.ts +16 -0
- package/dist/lists/DocumentList.d.ts +29 -0
- package/dist/lists/EndpointList.d.ts +19 -0
- package/dist/lists/FunctionList.d.ts +18 -0
- package/dist/lists/ReliabilityBoard.d.ts +23 -0
- package/dist/lists/RunHistory.d.ts +11 -0
- package/dist/lists/ServiceDetail.d.ts +20 -0
- package/dist/lists/WorkflowList.d.ts +19 -0
- package/dist/lists/vendor-history.d.ts +40 -0
- package/dist/lists.d.ts +20 -0
- package/dist/lists.mjs +1185 -0
- package/dist/lists.mjs.map +1 -0
- package/dist/project-context-BiCjv_E3.js +25 -0
- package/dist/project-context-BiCjv_E3.js.map +1 -0
- package/dist/project-context.d.ts +15 -1
- package/dist/rail/CallableRail.d.ts +12 -0
- package/dist/rail/CallableWorkspace.d.ts +16 -0
- package/dist/rail/SettingsTool.d.ts +7 -1
- package/dist/rail/settings-sections.d.ts +2 -2
- package/dist/rail-settings-XYGToh00.js +111 -0
- package/dist/rail-settings-XYGToh00.js.map +1 -0
- package/dist/rail.d.ts +11 -0
- package/dist/rail.mjs +35 -0
- package/dist/rail.mjs.map +1 -0
- package/dist/repos/api-calls.d.ts +4 -0
- package/dist/repos/apps.d.ts +14 -0
- package/dist/repos/callables.d.ts +91 -0
- package/dist/repos/connections.d.ts +33 -0
- package/dist/repos/dashboard.d.ts +4 -0
- package/dist/repos/endpoints.d.ts +125 -0
- package/dist/repos/functions.d.ts +79 -0
- package/dist/repos/index.d.ts +10 -0
- package/dist/repos/reliability.d.ts +42 -0
- package/dist/repos/saved-tests.d.ts +46 -0
- package/dist/repos/spec-export.d.ts +23 -0
- package/dist/repos/workflows.d.ts +138 -0
- package/dist/repos.mjs +174 -88
- package/dist/repos.mjs.map +1 -1
- package/dist/settings-rail--GdRMusb.js +33 -0
- package/dist/settings-rail--GdRMusb.js.map +1 -0
- package/dist/slug-C4ktDPdy.js +315 -0
- package/dist/slug-C4ktDPdy.js.map +1 -0
- package/dist/spec-export-Cf3VQSQS.js +176 -0
- package/dist/spec-export-Cf3VQSQS.js.map +1 -0
- package/dist/spec-import-CjmxyZDR.js +465 -0
- package/dist/spec-import-CjmxyZDR.js.map +1 -0
- package/dist/step-tests-CivICmTq.js +18 -0
- package/dist/step-tests-CivICmTq.js.map +1 -0
- package/dist/trigger-preview-VPkrryDl.js +120 -0
- package/dist/trigger-preview-VPkrryDl.js.map +1 -0
- package/dist/use-callable-draft-zHLpcr-b.js +271 -0
- package/dist/use-callable-draft-zHLpcr-b.js.map +1 -0
- package/dist/{use-workflow-draft-oI02dsP-.js → use-workflow-draft-DzAyUeA6.js} +48 -46
- package/dist/use-workflow-draft-DzAyUeA6.js.map +1 -0
- package/dist/vault-BSEWhMYC.js +117 -0
- package/dist/vault-BSEWhMYC.js.map +1 -0
- package/dist/workflow-blank-DyL3_RUA.js +14 -0
- package/dist/workflow-blank-DyL3_RUA.js.map +1 -0
- package/package.json +34 -5
- package/src/styles.css +408 -1
- package/dist/project-context-Dbk0Gr1K.js +0 -16
- package/dist/project-context-Dbk0Gr1K.js.map +0 -1
- package/dist/slug-ByKQgxrf.js +0 -642
- package/dist/slug-ByKQgxrf.js.map +0 -1
- package/dist/spec-import-HgO7ZkLZ.js +0 -898
- package/dist/spec-import-HgO7ZkLZ.js.map +0 -1
- package/dist/use-workflow-draft-oI02dsP-.js.map +0 -1
package/README.md
CHANGED
|
@@ -15,14 +15,81 @@ stay MIT.
|
|
|
15
15
|
npm i @w6w/embed react react-dom
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
`@tanstack/react-query` come with it as dependencies; `
|
|
18
|
+
This is the only w6w package most hosts install. `@w6w/sdk`, `@w6w/react`, `@w6w/ui` and
|
|
19
|
+
`@tanstack/react-query` come with it as dependencies; install `@w6w/ui` yourself too (`^0.2.0`, so
|
|
20
|
+
there is one copy) only if you write depth 2 below, since a strict resolver such as pnpm does not let
|
|
21
|
+
host code import a transitive dependency; `react` and `react-dom` (18 or later) are
|
|
20
22
|
yours. Import the one stylesheet once, at your app's root:
|
|
21
23
|
|
|
22
24
|
```ts
|
|
23
25
|
import "@w6w/embed/styles.css"; // @w6w/ui's styles, React Flow base included
|
|
24
26
|
```
|
|
25
27
|
|
|
28
|
+
## Entries
|
|
29
|
+
|
|
30
|
+
Every import path the published package exposes. Each carries `"use client"`, so a Next.js server
|
|
31
|
+
page can import it.
|
|
32
|
+
|
|
33
|
+
| Import | What it holds |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `@w6w/embed` | `W6WEmbedProvider`, `useEmbedStatus`, `useEmbedProject`, `EmbedAuthError`. |
|
|
36
|
+
| `@w6w/embed/editor` | `WorkflowEditor` alone, loaded lazily. |
|
|
37
|
+
| `@w6w/embed/editors` | The callable editors: `WorkflowEditor`, `FunctionEditor`, `EndpointEditor`, `DocumentEditor`. |
|
|
38
|
+
| `@w6w/embed/lists` | The connected lists and detail views: `FunctionList`, `EndpointList`, `WorkflowList`, `ReliabilityBoard`, `ActivitySummary`, `RunHistory`, `DocumentList`, `ServiceDetail`, `ConnectionList`, `ConnectionDetail`. |
|
|
39
|
+
| `@w6w/embed/forms` | The configuration forms: `CreateFunctionModal`, `CreateEndpointModal`, `VarsManager`, `SecretsManager`. |
|
|
40
|
+
| `@w6w/embed/rail` | `CallableWorkspace` and `CallableRail`, to place the editor's rail yourself. |
|
|
41
|
+
| `@w6w/embed/repos` | The data hooks the components read through (`useFunctionsQuery`, `useAppActionsQuery`, ...), on the provider's one cache. |
|
|
42
|
+
| `@w6w/embed/draft` | The headless draft lifecycle (autosave, flush on hide, the stale-write token). No UI. |
|
|
43
|
+
| `@w6w/embed/lib` | Pure helpers the editor shares with Studio. |
|
|
44
|
+
| `@w6w/embed/styles.css` | The one stylesheet: `@w6w/ui`'s styles, React Flow base included. |
|
|
45
|
+
|
|
46
|
+
## Three depths
|
|
47
|
+
|
|
48
|
+
Use as much of the package as you need.
|
|
49
|
+
|
|
50
|
+
**1. Drop in the component.** It fetches, renders and writes on its own:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { FunctionList } from "@w6w/embed/lists";
|
|
54
|
+
|
|
55
|
+
<FunctionList onOpen={(id) => router.push(`/functions/${id}`)} />;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**2. Keep `@w6w/ui`'s presentational component and feed it from an embed hook.** You own the rows:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { CallableList } from "@w6w/ui";
|
|
62
|
+
import { useFunctionsQuery } from "@w6w/embed/repos";
|
|
63
|
+
|
|
64
|
+
function MyFunctions() {
|
|
65
|
+
const { data = [], isLoading } = useFunctionsQuery();
|
|
66
|
+
return (
|
|
67
|
+
<CallableList
|
|
68
|
+
title="Functions"
|
|
69
|
+
loading={isLoading}
|
|
70
|
+
rows={data.map((f) => ({
|
|
71
|
+
id: f.id,
|
|
72
|
+
title: f.displayName || f.key,
|
|
73
|
+
archived: f.archivedAt != null,
|
|
74
|
+
}))}
|
|
75
|
+
onOpen={(id) => router.push(`/functions/${id}`)}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**3. Use the hook alone** and draw everything yourself:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { useFunctionsQuery } from "@w6w/embed/repos";
|
|
85
|
+
|
|
86
|
+
const { data } = useFunctionsQuery();
|
|
87
|
+
return <ul>{data?.map((f) => <li key={f.id}>{f.displayName || f.key}</li>)}</ul>;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Depth 2 imports `@w6w/ui` directly, so your host must list it (see [Install](#install)); depth 3 does not. All three read
|
|
91
|
+
the provider's one cache (see [One cache](#one-cache)).
|
|
92
|
+
|
|
26
93
|
## The provider
|
|
27
94
|
|
|
28
95
|
```tsx
|
|
@@ -52,6 +119,26 @@ never reaches the browser. The recipe is in the guide at `/guides/embed/`.
|
|
|
52
119
|
next one.
|
|
53
120
|
- The provider owns its `QueryClient`; it does not use, and does not need, one from your app.
|
|
54
121
|
- `ready={false}` holds every read until you have a user; `project` sets the default project.
|
|
122
|
+
- `project={{ use: "default" }}` uses the account's default project instead of an id you know. It
|
|
123
|
+
is looked up once per identity (one `GET /projects`, the row with `isDefault`), never the first
|
|
124
|
+
row of the list. `useEmbedProject()` returns `{ project, status, error? }` with `status` one of
|
|
125
|
+
`"resolving" | "ready" | "error"`: while resolving, `project` is `null` and editors stay in
|
|
126
|
+
their "project required" state; if the lookup fails or no row is the default, `status` is
|
|
127
|
+
`"error"` and nothing falls back to another project. A plain `project="proj_123"` is `"ready"`
|
|
128
|
+
at once; omitted, it is `{ project: null, status: "ready" }`.
|
|
129
|
+
- `identityKey={null}` means nobody is signed in: the provider renders `fallback` (default
|
|
130
|
+
nothing) and mounts none of the embed, so no session is requested and no API call is made.
|
|
131
|
+
Going `null` to an identity starts at once; going from an identity to `null` first writes any
|
|
132
|
+
pending draft into the account that made it, then shows `fallback`.
|
|
133
|
+
- `useEmbedStatus()` returns `{ status, error }` with `status` `"connecting" | "ready" | "error"`.
|
|
134
|
+
The session is acquired by the first request a mounted surface makes, so **without `eager` the
|
|
135
|
+
status stays `"connecting"` until then**. `eager` acquires the session when the provider
|
|
136
|
+
mounts. A token your backend minted but the API refused (401) is `"error"` with an
|
|
137
|
+
`EmbedAuthError` (`cause` is the SDK `ApiError`) until the next acquisition starts or the
|
|
138
|
+
identity changes; a failing `getSession` is `"error"` with its own error. With
|
|
139
|
+
`project={{ use: "default" }}` the lookup itself acquires a session on mount (so `getSession` is
|
|
140
|
+
called even without `eager`), and the client is rebuilt once the project resolves, which acquires
|
|
141
|
+
a session again: the status goes `connecting`, `ready`, `connecting`.
|
|
55
142
|
|
|
56
143
|
### Next.js server components
|
|
57
144
|
|
|
@@ -125,6 +212,15 @@ optional (default: a no-op) and hands navigation (back to the list, or to anothe
|
|
|
125
212
|
router; `slots` lets you place your own elements in the editor chrome; `initialRunId` opens the
|
|
126
213
|
editor on a run. The editor must render inside `<W6WEmbedProvider>`.
|
|
127
214
|
|
|
215
|
+
### Placing the rail yourself
|
|
216
|
+
|
|
217
|
+
By default the editor renders its own right rail (`rail` omitted or `true`). Pass `rail={false}` to
|
|
218
|
+
render no rail and place it elsewhere: wrap the editor in `<CallableWorkspace kind="workflow"
|
|
219
|
+
id={workflowId}>` and put `<CallableRail kind="workflow" id={workflowId} />` anywhere inside it,
|
|
220
|
+
such as a drawer. Both come from `@w6w/embed/rail`; the rail then edits the same draft the editor
|
|
221
|
+
saves. Without an enclosing workspace, `rail={false}` simply has no rail. See the
|
|
222
|
+
[components reference](../../docs/embed/components.md).
|
|
223
|
+
|
|
128
224
|
### The project rule
|
|
129
225
|
|
|
130
226
|
The editor takes its project from its `project` prop, else from the provider's `project`. Saves
|
|
@@ -147,6 +243,117 @@ comes from the nearest `[data-theme]` ancestor: the provider's `theme` prop puts
|
|
|
147
243
|
tree. Omit `theme` and the editor follows `data-theme` on `<html>` if you set it, else the OS
|
|
148
244
|
preference. The editor fills its parent (`width` and `height` 100%), so give its container a height.
|
|
149
245
|
|
|
246
|
+
The layout rules every embedded surface follows (it fills its parent, navigates by callback, and keeps
|
|
247
|
+
every class under that root) are in [`docs/layout.md`](docs/layout.md), a repo doc not shipped in the package.
|
|
248
|
+
|
|
249
|
+
## Function editor
|
|
250
|
+
|
|
251
|
+
| Component | Import | What it is |
|
|
252
|
+
| --- | --- | --- |
|
|
253
|
+
| `<FunctionEditor functionId project? onNavigate? slots? rail? tools?>` | `@w6w/embed/editors` | One Function: Interface (name, key, description), Inputs, Implementation, Test invoke, with History, a JSON toggle and Save in the header. |
|
|
254
|
+
|
|
255
|
+
Saving, the JSON toggle's Save and the rail's Error handling all write the same draft, and every
|
|
256
|
+
write carries the stored `updatedAt`. If the Function changed on the server since it was opened, the
|
|
257
|
+
save is refused with an inline "Reload from server" control and is never retried. `rail` defaults to
|
|
258
|
+
`true`; `rail={false}` publishes into an enclosing `<CallableWorkspace kind="function" id>` for the
|
|
259
|
+
same id (the rail's saves then use that workspace's `project`). `project` only scopes the expression
|
|
260
|
+
rail, since a Function belongs to the account. There is no Aliases section; add one through `tools`.
|
|
261
|
+
See the [components reference](../../docs/embed/components.md).
|
|
262
|
+
|
|
263
|
+
## Lists
|
|
264
|
+
|
|
265
|
+
`@w6w/embed/lists` holds the connected lists (`FunctionList`, `EndpointList`, `WorkflowList`, `ReliabilityBoard`, `ActivitySummary`, `RunHistory`, `DocumentList`, `ServiceDetail`, `ConnectionList`, `ConnectionDetail`). Each reads through the same provider as the editor and
|
|
266
|
+
writes through it, so a host mounts nothing else.
|
|
267
|
+
|
|
268
|
+
| Component | What it does |
|
|
269
|
+
| --- | --- |
|
|
270
|
+
| `<FunctionList project? onOpen? getHref? onCreated? slots?>`, `<EndpointList>`, `<WorkflowList>` | The account's Functions, Endpoints and the project's Workflows, each with a Show-archived toggle, New and Import, and rows that are buttons, or real links with `getHref`. `onOpen(id, event)` and `onCreated(id)` hand navigation to your router. Per-prop details, including `EndpointList` and `WorkflowList`, are in the [components reference](../../docs/embed/components.md). |
|
|
271
|
+
| `<ConnectionList onOpen? getHref? addLabel? slots?>` | Your connections with Add, Edit and Delete. Delete asks first. Edit appears only when the API behind the provider can save a connection, which `<W6WEmbedProvider>` always can. `getHref` makes each row a real link. `slots.actions` replaces the Add button (pass `null` to remove it), `slots.header` and `slots.empty` replace the heading and the empty state. Built-in "no credential" rows have no Edit, Delete or link. |
|
|
272
|
+
| `<ConnectionDetail connectionId onOpenAction onBack? slots?>` | One connection: Test connection, Edit, the app's actions with their saved tests, and recent runs. `onOpenAction(actionKey)` fires for an action and `onOpenAction(actionKey, savedTestId)` for a saved test; `onBack` shows a back button when given. A missing connection shows a "not found" state. |
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
import { ConnectionDetail, ConnectionList } from "@w6w/embed/lists";
|
|
276
|
+
|
|
277
|
+
<ConnectionList onOpen={(id) => router.push(`/connections/${id}`)} />;
|
|
278
|
+
<ConnectionDetail connectionId={id} onOpenAction={(key, testId) => {/* your router */}} />;
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`@w6w/embed/lists` holds the connected list components. `<ReliabilityBoard project? variant? limit?
|
|
282
|
+
days? showChart? getHref? onOpen? showAllHref? onShowAll? slots?>` shows one project's service
|
|
283
|
+
reliability: it loads the project's services itself (membership first, then status in serial batches
|
|
284
|
+
of at most ten) and draws them with `@w6w/ui`'s `ReliabilityList`. Icons come from the rows, so it
|
|
285
|
+
makes no app-catalog request. `days` defaults to 30; `limit` only trims what is shown. Omit `project`
|
|
286
|
+
to use the provider's; `null` or `""` makes no request and asks for a project.
|
|
287
|
+
|
|
288
|
+
`<ActivitySummary getHref? onOpen? slots?>` shows the account's run statistics and recent activity:
|
|
289
|
+
"Today" and "Last 7 days" headline cards, "Activity over time" and "Recent activity". It is
|
|
290
|
+
account-wide (it takes no `project`), and it resolves each row's function or workflow name against
|
|
291
|
+
the account's own lists (the workflow list follows the client's default project when the provider
|
|
292
|
+
names one, so a workflow outside it stays plain text). The name is a link only when it resolves: `getHref` makes it an `<a href>`,
|
|
293
|
+
`onOpen` alone makes it a button, and with neither it stays text. A click calls
|
|
294
|
+
`onOpen(target, event)` and is never cancelled by the component. It makes two `/dashboard/stats`
|
|
295
|
+
requests on purpose: "Today" is cut at the viewer's local midnight (`from`, `bucket=day`), and the
|
|
296
|
+
server only groups by `day` or `week`, cutting at midnight in the database's timezone, so one
|
|
297
|
+
request cannot give a local day. `<RunHistory scope? showKind? filters? onFiltersChange?
|
|
298
|
+
onOpenInEditor?>` shows the execution history for the provider's project (or the `scope` you pass);
|
|
299
|
+
omit `filters` and it keeps them itself, pass them and you own them. See the
|
|
300
|
+
[components reference](../../docs/embed/components.md).
|
|
301
|
+
|
|
302
|
+
`<ServiceDetail appId project? days? backHref? onBack? slots?>` shows one service's reliability
|
|
303
|
+
drill-down: health, error mix, the API's own status, daily history and recent calls. It makes one
|
|
304
|
+
single-service status request (`apps=<appId>`, never the whole board) plus one call-log request.
|
|
305
|
+
`days` defaults to 30; omit `project` to use
|
|
306
|
+
the provider's, and with none it makes no request. When the service has no row for the project it
|
|
307
|
+
shows a not-found card whose back link is an `<a href>` with `backHref`, a `<button>` with only
|
|
308
|
+
`onBack`, and absent with neither; a click calls `onBack` and is never cancelled.
|
|
309
|
+
|
|
310
|
+
## Configuration forms
|
|
311
|
+
|
|
312
|
+
`@w6w/embed/forms` holds the connected forms (`VarsManager`, `SecretsManager`, and the `CreateFunctionModal` / `CreateEndpointModal` dialogs the lists open). Each is one self-contained element (root class
|
|
313
|
+
`w6w-embed-root`) that reads and writes through the provider's client.
|
|
314
|
+
|
|
315
|
+
| Component | Scope | Props |
|
|
316
|
+
| --- | --- | --- |
|
|
317
|
+
| `<VarsManager>` | one project | `project?: string \| null`, `slots?` |
|
|
318
|
+
| `<SecretsManager>` | the whole account (no project) | `slots?` |
|
|
319
|
+
|
|
320
|
+
- `VarsManager` lists, adds, edits and deletes typed variables (`string`, `number`, `boolean`,
|
|
321
|
+
`json`). Omit `project` to use the `<W6WEmbedProvider project>`. `null` or `""` means no project:
|
|
322
|
+
nothing is requested and "Add" is disabled. Every request names the project it acts on.
|
|
323
|
+
- `SecretsManager` is write-only. A secret's value is typed into a form and sent; it is never
|
|
324
|
+
shown again, never held in the query cache, and never passed to a prop or callback. Rotating with
|
|
325
|
+
a blank value changes only the description. Secrets belong to the account, so the component takes
|
|
326
|
+
no project.
|
|
327
|
+
- `slots`: `{ header?, actions?, empty? }`. Leave a slot out for the default (the heading, the
|
|
328
|
+
"+ Add ..." button, "No ... yet."), pass `null` for nothing, or pass a node. `actions` also
|
|
329
|
+
accepts a function, `({ openCreate, canCreate }) => ReactNode`, so a host that supplies its own
|
|
330
|
+
button can still open the create form.
|
|
331
|
+
|
|
332
|
+
## Documents
|
|
333
|
+
|
|
334
|
+
| Component | Import | What it is |
|
|
335
|
+
| --- | --- | --- |
|
|
336
|
+
| `<DocumentList>` | `@w6w/embed/lists` | A project's documents: add, edit in place, delete. |
|
|
337
|
+
| `<DocumentEditor documentId>` | `@w6w/embed/editors` | One document: its key and content, with Edit and Delete. |
|
|
338
|
+
|
|
339
|
+
Both take `project` (omitted: the provider's project; `null` or `""`: nothing is read and writes
|
|
340
|
+
refuse) and `slots` (omitted: the default, `null`: nothing, a node: replaces). Documents the server
|
|
341
|
+
shares in from a repository show no Edit or Delete. The embed has no repository sync and no "synced
|
|
342
|
+
from" markers; a host that wants them adds them through the list's row slots (`lead`,
|
|
343
|
+
`sharedActions`, `footer`). Details are in the components reference.
|
|
344
|
+
|
|
345
|
+
## Endpoint editor
|
|
346
|
+
|
|
347
|
+
| Component | Import | What it is |
|
|
348
|
+
| --- | --- | --- |
|
|
349
|
+
| `<EndpointEditor endpointId project? onNavigate? slots? rail? tools?>` | `@w6w/embed/editors` | One Endpoint: Identity, the callable URL, Input, Target, Security, Test invoke, History and a JSON toggle, with a Save at the top and the bottom. |
|
|
350
|
+
|
|
351
|
+
Every write is one save carrying the stored `updatedAt`; if someone else saved first, the editor says
|
|
352
|
+
so inline with a Reload and never retries. Secret fields are write-only: a stored secret shows
|
|
353
|
+
"stored — type to replace" and is kept unless you type a new one. There is no Aliases section.
|
|
354
|
+
`rail={false}` inside a `<CallableWorkspace>` for the same id publishes into that workspace. Details
|
|
355
|
+
are in the components reference.
|
|
356
|
+
|
|
150
357
|
## Console exclusions
|
|
151
358
|
|
|
152
359
|
Your host code makes no `client.console` call. The package uses a public `@w6w/sdk` operation
|
|
@@ -159,9 +366,29 @@ with its reason.
|
|
|
159
366
|
| `src/repos/workflows.ts` | `console.workflows.upsert` | creating a workflow in a named project has no public operation |
|
|
160
367
|
| `src/lib/history-query.ts` | `console.workflows.getRun`; raw `GET /history`, `GET /history/stats`, `GET /invocations/:id` | no public history or invocation operation |
|
|
161
368
|
| `src/repos/step-tests.ts` | `console.stepTests.list`, `.save`, `.recordRun` | no public operation |
|
|
162
|
-
| `src/repos/vault.ts` | `console.vault.list`, `.seal`, `.create`, `.update`, `.delete` | vault is outside the public contract; used to add and
|
|
369
|
+
| `src/repos/vault.ts` | `console.vault.list`, `.seal`, `.create`, `.update`, `.delete` | vault is outside the public contract; used by `SecretsManager` (`@w6w/embed/forms`) to list, add, rotate and delete a secret, and to seal one from the expression editor |
|
|
163
370
|
| `src/repos/documents.ts` | raw `POST /documents/:id/sync` | no public operation |
|
|
164
371
|
| `src/repos/spec-import.ts` | raw `POST /spec/import` | no public operation (Settings import) |
|
|
165
|
-
| `src/repos/vars.ts` | raw `GET /vars`, `POST /vars`, `PATCH /vars/:id`, `DELETE /vars/:id` | the SDK's `vars` methods take no options argument, so they cannot send `?project
|
|
372
|
+
| `src/repos/vars.ts` | raw `GET /vars`, `POST /vars`, `PATCH /vars/:id`, `DELETE /vars/:id` | the SDK's `vars` methods take no options argument, so they cannot send `?project=`; `VarsManager` (`@w6w/embed/forms`) needs it on every call |
|
|
166
373
|
| `src/repos/versions.ts` | raw `GET /:c/:id/versions`, `GET /:c/:id/versions/:v`, `POST /:c/:id/publish`, `POST /:c/:id/:x`, `POST /:c/:id/versions/:v/revert`, `POST /:c/:id/versions/:v/:x` | the endpoint arm has no public version operation; the function arm of invoke-version keeps the raw invocation frame, which `functions.runVersion` unwraps |
|
|
374
|
+
| `src/repos/callables.ts` | `console.functions.list`, `.get`, `.upsert`; `console.endpoints.list`, `.get`, `.upsert`; `console.workflows.get`, `.upsert`, `.archive`, `.delete`; the function and endpoint archive (POST /:c/:id/archive) and delete (DELETE /:c/:id) go through the client's plain `request()` with a computed path | endpoints have no public list, read or write operation (the public SDK exposes only `endpoints.run`), and no public archive or delete; the function arm is not a missing-operation case: public `functions.list/get/create/update/archive` exist, but these calls moved verbatim from Studio, whose editor hydrates from the console `get` (which splices `valid`), and migrating them to the public operations is deferred; the workflow arm keeps the typed console calls its rail already used |
|
|
375
|
+
| `src/repos/functions.ts` | `console.functions.list`, `.get`, `.upsert` | moved verbatim from Studio and still on the console calls (the stored-definition read splices the server's `valid`; the guarded save sends `ifUnmodifiedSince`); public `functions.list/get/update` exist and migrating to them is deferred |
|
|
376
|
+
| `src/repos/endpoints.ts` | `console.endpoints.get`, `.upsert`, `.invoke` | endpoints have no public operation; the save keeps its own `mutationFn` because the 201 carries the rendered `invokeUrls[]` |
|
|
377
|
+
| `src/draft/use-callable-draft.ts` | `console.functions.upsert`, `console.endpoints.upsert` | the callable draft's guarded save (`ifUnmodifiedSince`) for the Function and Endpoint editors; endpoints have no public write operation, and the Function save is moved verbatim from Studio |
|
|
378
|
+
| `src/repos/spec-export.ts` | raw `GET /:c/:id/spec` | no public export operation (Settings export) |
|
|
379
|
+
| `src/repos/apps.ts` | `console.apps.getActions`, `console.apps.get` | the per-app Actions list and the app detail (version, source, actions) have no public operation; same `GET /apps/:id` payload the canvas adapter serves |
|
|
380
|
+
| `src/repos/connections.ts` | `console.connections.listForApp`, `.create`, `.update`, `.test` | no public per-app connection list, create, update or test; the list itself is the public `connections.list` |
|
|
381
|
+
| `src/repos/connections.ts` | `console.connections.get`, `.delete` | public `connections.get/delete` exist; these moved verbatim from Studio and still use the console calls, and migrating them is deferred |
|
|
382
|
+
| `src/repos/saved-tests.ts` | `console.savedTests.list`, `.listTestRuns`, `.create`, `.update`, `.delete`, `.recordTestRun` | saved tests and tester run history have no public operation |
|
|
383
|
+
| `src/repos/reliability.ts` | `console.reliability.listMembers`, `console.reliability.list` | no public reliability operation; the board's membership discovery and serial status batches |
|
|
384
|
+
| `src/repos/api-calls.ts` | `console.apiCalls.list` | no public operation; `ServiceDetail`'s recent-calls log |
|
|
167
385
|
| `@w6w/react` `createW6WUiAdapter` (canvas) | `console.apps.*`, saved and step tests, subscriptions | the adapter's own call sites, used by the canvas from `@w6w/ui/flow` |
|
|
386
|
+
|
|
387
|
+
## One cache
|
|
388
|
+
|
|
389
|
+
Inside `<W6WEmbedProvider>`, read data through the `@w6w/embed/repos` hooks (`useFunctionsQuery`,
|
|
390
|
+
`useAppActionsQuery`, `useConnectionsForAppQuery`, ...), not through `@w6w/react`'s read hooks. The
|
|
391
|
+
repos hooks share the provider's identity-scoped TanStack `QueryClient` under fixed query keys, so a
|
|
392
|
+
save in one surface refreshes every other surface that shows the same record. `@w6w/react`'s read
|
|
393
|
+
hooks keep their own `useAsync` state per hook call, which is a second cache: the two disagree after
|
|
394
|
+
a write and neither invalidates the other.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { jsx as e, jsxs as i, Fragment as u } from "react/jsx-runtime";
|
|
2
|
+
import { b as W, u as E } from "./slug-C4ktDPdy.js";
|
|
3
|
+
import { IconButton as S, Modal as _, CodeBlock as B } from "@w6w/ui";
|
|
4
|
+
import { useRef as L, useEffect as x, useState as N } from "react";
|
|
5
|
+
function R({
|
|
6
|
+
title: o,
|
|
7
|
+
onClose: n,
|
|
8
|
+
children: r,
|
|
9
|
+
wide: s = !1,
|
|
10
|
+
xl: m = !1,
|
|
11
|
+
headerRight: c
|
|
12
|
+
}) {
|
|
13
|
+
const p = L(null);
|
|
14
|
+
return x(() => {
|
|
15
|
+
const d = p.current;
|
|
16
|
+
if (!d) return;
|
|
17
|
+
d.open || d.showModal();
|
|
18
|
+
const f = (t) => {
|
|
19
|
+
t.preventDefault(), n();
|
|
20
|
+
}, b = (t) => {
|
|
21
|
+
if (t.target !== d) return;
|
|
22
|
+
const a = d.getBoundingClientRect();
|
|
23
|
+
(t.clientX < a.left || t.clientX > a.right || t.clientY < a.top || t.clientY > a.bottom) && n();
|
|
24
|
+
};
|
|
25
|
+
return d.addEventListener("cancel", f), d.addEventListener("click", b), () => {
|
|
26
|
+
d.removeEventListener("cancel", f), d.removeEventListener("click", b);
|
|
27
|
+
};
|
|
28
|
+
}, [n]), /* @__PURE__ */ e("div", { className: "modal-backdrop", children: /* @__PURE__ */ i(
|
|
29
|
+
"dialog",
|
|
30
|
+
{
|
|
31
|
+
ref: p,
|
|
32
|
+
className: `modal${s ? " modal-wide" : ""}${m ? " modal-xl" : ""}`,
|
|
33
|
+
"aria-label": o,
|
|
34
|
+
children: [
|
|
35
|
+
c ? /* @__PURE__ */ i("div", { className: "modal-head", children: [
|
|
36
|
+
/* @__PURE__ */ e("h3", { children: o }),
|
|
37
|
+
c
|
|
38
|
+
] }) : /* @__PURE__ */ e("h3", { children: o }),
|
|
39
|
+
r
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
) });
|
|
43
|
+
}
|
|
44
|
+
const y = [
|
|
45
|
+
{ id: "node", label: "Node", language: "TypeScript", grammar: "typescript", icon: "lang-node" },
|
|
46
|
+
{ id: "cli", label: "CLI", language: "Shell", grammar: "bash", icon: "terminal" },
|
|
47
|
+
{ id: "python", label: "Python", language: "Python", grammar: "python", icon: "lang-python" },
|
|
48
|
+
{ id: "curl", label: "curl", language: "Shell", grammar: "bash", icon: "lang-curl" }
|
|
49
|
+
];
|
|
50
|
+
function F(o) {
|
|
51
|
+
const n = W(o);
|
|
52
|
+
return n ? y.filter((r) => typeof n[r.id] == "string") : [];
|
|
53
|
+
}
|
|
54
|
+
function M({
|
|
55
|
+
resource: o,
|
|
56
|
+
triggers: n,
|
|
57
|
+
wrap: r = !1,
|
|
58
|
+
maxHeight: s = "420px",
|
|
59
|
+
initialTab: m
|
|
60
|
+
}) {
|
|
61
|
+
var v, C, w;
|
|
62
|
+
const [c, p] = N(m ?? "node"), [d, f] = N(0), b = !!n && n.length > 0, t = b ? n[Math.min(d, n.length - 1)] ?? n[0] : null, a = W(o, t == null ? void 0 : t.fields), g = a ? y.filter((l) => typeof a[l.id] == "string") : [], h = g.some((l) => l.id === c) ? c : ((v = g[0]) == null ? void 0 : v.id) ?? "node", k = (a == null ? void 0 : a[h]) ?? "";
|
|
63
|
+
return a === null ? /* @__PURE__ */ e("p", { className: "muted", children: E(o) }) : /* @__PURE__ */ i(u, { children: [
|
|
64
|
+
b && t && /* @__PURE__ */ i("div", { className: "subpanel", style: { marginTop: 0, paddingTop: 0, borderTop: "none" }, children: [
|
|
65
|
+
/* @__PURE__ */ i("div", { "data-testid": "trigger-panel", children: [
|
|
66
|
+
/* @__PURE__ */ e("div", { className: "code-tabs", children: n.map((l, T) => /* @__PURE__ */ e(
|
|
67
|
+
"button",
|
|
68
|
+
{
|
|
69
|
+
type: "button",
|
|
70
|
+
className: `code-tab${T === d ? " active" : ""}`,
|
|
71
|
+
"data-testid": "trigger-tab",
|
|
72
|
+
onClick: () => f(T),
|
|
73
|
+
children: l.label
|
|
74
|
+
},
|
|
75
|
+
l.id
|
|
76
|
+
)) }),
|
|
77
|
+
t.fields.length === 0 && /* @__PURE__ */ e("p", { className: "muted small", children: "This trigger declares no fields." })
|
|
78
|
+
] }),
|
|
79
|
+
n.length > 1 && /* @__PURE__ */ i("p", { className: "muted small", "data-testid": "trigger-multi-note", children: [
|
|
80
|
+
"This workflow has ",
|
|
81
|
+
n.length,
|
|
82
|
+
" manual triggers — the same input reaches every one of them identically; there is no per-trigger routing."
|
|
83
|
+
] })
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ e("div", { className: "code-tabs", children: g.map((l) => /* @__PURE__ */ e(
|
|
86
|
+
"button",
|
|
87
|
+
{
|
|
88
|
+
type: "button",
|
|
89
|
+
className: `code-tab${h === l.id ? " active" : ""}`,
|
|
90
|
+
onClick: () => p(l.id),
|
|
91
|
+
children: l.label
|
|
92
|
+
},
|
|
93
|
+
l.id
|
|
94
|
+
)) }),
|
|
95
|
+
/* @__PURE__ */ e(
|
|
96
|
+
B,
|
|
97
|
+
{
|
|
98
|
+
code: k,
|
|
99
|
+
language: ((C = y.find((l) => l.id === h)) == null ? void 0 : C.grammar) ?? "plaintext",
|
|
100
|
+
maxHeight: s,
|
|
101
|
+
wrap: r,
|
|
102
|
+
"aria-label": `${((w = y.find((l) => l.id === h)) == null ? void 0 : w.label) ?? h} snippet`,
|
|
103
|
+
copyable: !0
|
|
104
|
+
}
|
|
105
|
+
),
|
|
106
|
+
/* @__PURE__ */ e("p", { className: "muted small", style: { marginBottom: 0 }, children: h === "node" ? /* @__PURE__ */ i(u, { children: [
|
|
107
|
+
/* @__PURE__ */ e("code", { children: "npm i @w6w/sdk" }),
|
|
108
|
+
" · set ",
|
|
109
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
110
|
+
" and ",
|
|
111
|
+
/* @__PURE__ */ e("code", { children: "W6W_TOKEN" }),
|
|
112
|
+
" · operation ",
|
|
113
|
+
/* @__PURE__ */ e("code", { children: a.operation })
|
|
114
|
+
] }) : h === "cli" ? /* @__PURE__ */ i(u, { children: [
|
|
115
|
+
/* @__PURE__ */ e("code", { children: "npm i -g @w6w/cli" }),
|
|
116
|
+
" · set ",
|
|
117
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
118
|
+
" and",
|
|
119
|
+
" ",
|
|
120
|
+
/* @__PURE__ */ e("code", { children: "W6W_TOKEN" }),
|
|
121
|
+
" (or pass ",
|
|
122
|
+
/* @__PURE__ */ e("code", { children: "--base-url" }),
|
|
123
|
+
" / ",
|
|
124
|
+
/* @__PURE__ */ e("code", { children: "--token" }),
|
|
125
|
+
") · operation ",
|
|
126
|
+
/* @__PURE__ */ e("code", { children: a.operation })
|
|
127
|
+
] }) : h === "python" ? /* @__PURE__ */ i(u, { children: [
|
|
128
|
+
/* @__PURE__ */ e("code", { children: "pip install w6w" }),
|
|
129
|
+
" · set ",
|
|
130
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
131
|
+
" and ",
|
|
132
|
+
/* @__PURE__ */ e("code", { children: "W6W_TOKEN" }),
|
|
133
|
+
" ",
|
|
134
|
+
"· operation ",
|
|
135
|
+
/* @__PURE__ */ e("code", { children: a.operation })
|
|
136
|
+
] }) : /* @__PURE__ */ i(u, { children: [
|
|
137
|
+
"No client library — any HTTP client will do. Set ",
|
|
138
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
139
|
+
" to your w6w base URL (for an Endpoint, the URL above is the one this page is showing); substitute a w6w token for ",
|
|
140
|
+
/* @__PURE__ */ e("code", { children: "$W6W_TOKEN" }),
|
|
141
|
+
" and send the declared input as the JSON body."
|
|
142
|
+
] }) })
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
145
|
+
function I({
|
|
146
|
+
resource: o,
|
|
147
|
+
label: n = "Call from code",
|
|
148
|
+
triggers: r,
|
|
149
|
+
initialTab: s
|
|
150
|
+
}) {
|
|
151
|
+
const [m, c] = N(!1);
|
|
152
|
+
return /* @__PURE__ */ i(u, { children: [
|
|
153
|
+
/* @__PURE__ */ e(S, { icon: "code", label: n, onClick: () => c(!0) }),
|
|
154
|
+
m && /* @__PURE__ */ e(_, { title: "Call from code", size: "wide", onClose: () => c(!1), children: /* @__PURE__ */ e(M, { resource: o, triggers: r, initialTab: s }) })
|
|
155
|
+
] });
|
|
156
|
+
}
|
|
157
|
+
function K({
|
|
158
|
+
title: o,
|
|
159
|
+
message: n,
|
|
160
|
+
onConfirm: r,
|
|
161
|
+
onClose: s,
|
|
162
|
+
confirmLabel: m = "Confirm",
|
|
163
|
+
cancelLabel: c = "Cancel",
|
|
164
|
+
destructive: p = !0
|
|
165
|
+
}) {
|
|
166
|
+
return /* @__PURE__ */ i(R, { title: o, onClose: s, children: [
|
|
167
|
+
/* @__PURE__ */ e("div", { className: "modal-body", children: /* @__PURE__ */ e("p", { className: "muted small", children: n }) }),
|
|
168
|
+
/* @__PURE__ */ i("div", { className: "modal-actions", children: [
|
|
169
|
+
/* @__PURE__ */ e("button", { type: "button", className: "btn ghost", onClick: s, children: c }),
|
|
170
|
+
/* @__PURE__ */ e("button", { type: "button", className: p ? "btn danger" : "btn", onClick: r, children: m })
|
|
171
|
+
] })
|
|
172
|
+
] });
|
|
173
|
+
}
|
|
174
|
+
export {
|
|
175
|
+
I as C,
|
|
176
|
+
R as M,
|
|
177
|
+
K as a,
|
|
178
|
+
M as b,
|
|
179
|
+
F as s
|
|
180
|
+
};
|
|
181
|
+
//# sourceMappingURL=ConfirmModal-RLbZT5_k.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmModal-RLbZT5_k.js","sources":["../src/chrome/Modal.tsx","../src/chrome/CallFromCodeButton.tsx","../src/chrome/ConfirmModal.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\ninterface ModalProps {\n title: string;\n onClose: () => void;\n children: React.ReactNode;\n /** Widen the dialog (e.g. for a JSON editor that needs room). */\n wide?: boolean;\n /** Widen further still (e.g. for the plan comparison grid). */\n xl?: boolean;\n /** Trailing control on the title row (e.g. a close `IconButton`). Given,\n * the title and this node share one `.modal-head` row; absent, the title\n * renders as a direct child exactly as before. */\n headerRight?: React.ReactNode;\n}\n\n/**\n * Small dialog modal. Built on the native <dialog> element so it gets focus\n * trapping, Esc-dismiss, and accessibility semantics for free. A button\n * positioned over the backdrop catches outside-clicks to close.\n */\nexport function Modal({\n title,\n onClose,\n children,\n wide = false,\n xl = false,\n headerRight,\n}: ModalProps) {\n const ref = useRef<HTMLDialogElement>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n if (!el.open) el.showModal();\n const onCancel = (e: Event) => {\n e.preventDefault();\n onClose();\n };\n // A `showModal()` dialog + its ::backdrop sit in the top layer, above any\n // sibling overlay — so catch outside clicks on the dialog itself: backdrop\n // clicks target the dialog, and land outside its box.\n const onClick = (e: MouseEvent) => {\n if (e.target !== el) return;\n const r = el.getBoundingClientRect();\n const outside =\n e.clientX < r.left || e.clientX > r.right || e.clientY < r.top || e.clientY > r.bottom;\n if (outside) onClose();\n };\n el.addEventListener(\"cancel\", onCancel);\n el.addEventListener(\"click\", onClick);\n return () => {\n el.removeEventListener(\"cancel\", onCancel);\n el.removeEventListener(\"click\", onClick);\n };\n }, [onClose]);\n\n return (\n <div className=\"modal-backdrop\">\n <dialog\n ref={ref}\n className={`modal${wide ? \" modal-wide\" : \"\"}${xl ? \" modal-xl\" : \"\"}`}\n aria-label={title}\n >\n {headerRight ? (\n <div className=\"modal-head\">\n <h3>{title}</h3>\n {headerRight}\n </div>\n ) : (\n <h3>{title}</h3>\n )}\n {children}\n </dialog>\n </div>\n );\n}\n","import {\n type SnippetCallable,\n type TriggerPreview,\n buildSnippet,\n unavailableReason,\n} from \"@w6w/embed/lib\";\nimport { CodeBlock, type CodeLanguage, IconButton, type IconName, Modal } from \"@w6w/ui\";\nimport { useState } from \"react\";\n\n/**\n * \"Call from code\" — the button that shows how to reach the thing you are\n * looking at from the Node SDK (`@w6w/sdk`), the CLI (`w6w`), or the Python\n * SDK (`w6w`, PyPI).\n *\n * Mounted on the pages whose resource the wrapper contract actually covers.\n * Everything shown comes from `../lib/sdk-snippets.ts`, which builds against\n * `packages/wrappers/endpoints.json` — this component owns presentation only\n * and never composes an API call of its own.\n *\n * A modal rather than an inline block: the snippet is reference material a\n * reader wants once and then dismisses, and inlining it would push the page's\n * real content (a function's inputs, a workflow's steps) below the fold for\n * everyone who is not currently writing a client.\n */\n\n/**\n * Tabs, in the order the contract lists the wrappers — then `curl`, which is\n * not a wrapper at all and therefore comes last.\n *\n * The strip renders only the tabs the BUILT snippet actually carries\n * (`Snippet.curl` is optional): a Function, Endpoint or Workflow shows all\n * four tabs, while a Connection, Var or Document — which have no fixed\n * single-resource route to curl against — still show exactly the three\n * Node/CLI/Python tabs they show today.\n */\nconst TABS = [\n { id: \"node\", label: \"Node\", language: \"TypeScript\", grammar: \"typescript\", icon: \"lang-node\" },\n { id: \"cli\", label: \"CLI\", language: \"Shell\", grammar: \"bash\", icon: \"terminal\" },\n { id: \"python\", label: \"Python\", language: \"Python\", grammar: \"python\", icon: \"lang-python\" },\n { id: \"curl\", label: \"curl\", language: \"Shell\", grammar: \"bash\", icon: \"lang-curl\" },\n] as const satisfies readonly {\n id: string;\n label: string;\n language: string;\n grammar: CodeLanguage;\n /** The tab's glyph, by name from `@w6w/ui`'s icon set (`icons.tsx`). Every\n * language mark this file used to draw — its own `NodeGlyph`/`CliGlyph`/\n * `PythonGlyph`/`CurlGlyph` — is one of those entries, copied verbatim, so\n * the tab strip and the rail's language picker draw the same four shapes\n * from one place. */\n icon: IconName;\n}[];\n\n/**\n * The tab table, exported so a caller can render its OWN affordance per\n * language without re-deriving the set. `CodeTool`'s rail panel uses it to draw\n * one icon per language and open this component's modal on that language.\n *\n * Exported as the table rather than as a list of ids on purpose: label, grammar\n * and glyph belong to the same row, and a second place that decided \"which\n * languages exist\" would be a second place to forget `curl`.\n */\nexport const SNIPPET_TABS = TABS;\n\ntype TabId = (typeof TABS)[number][\"id\"];\nexport type SnippetTabId = TabId;\n\n/**\n * Which language tabs a resource actually has — the same filter the strip\n * below applies, hoisted so a caller can ask BEFORE rendering.\n *\n * `curl` is emitted only where a public URL exists and was handed in (today: a\n * Function, a Workflow, or an Endpoint that knows its own server-rendered URL),\n * so a var, document or connection yields exactly Node/CLI/Python. Trigger\n * fields are deliberately not a parameter: they change what the snippet SAYS,\n * never which languages it is available in.\n *\n * Empty when the resource has no snippet at all — the caller should then show\n * {@link unavailableReason} rather than an empty row of icons.\n */\nexport function snippetTabsFor(resource: SnippetCallable): readonly (typeof TABS)[number][] {\n const snippet = buildSnippet(resource);\n return snippet ? TABS.filter((t) => typeof snippet[t.id] === \"string\") : [];\n}\n\n/**\n * The headless body — everything that renders the snippet itself: the\n * trigger-tab strip, the language-tab strip, the `CodeBlock`, and the per-tab\n * install-hint paragraph. No button, no `Modal`. Split out (T2.1.2) so\n * `CodeTool.Panel` (`../ui/rail/CodeTool.tsx`) can render this INSIDE the\n * right rail's own already-open panel, without a second trigger button or a\n * Modal-on-top-of-a-panel double-wrap — the rail's strip + panel disclosure\n * IS the trigger; this component only needs to draw what's inside it.\n * `CallFromCodeButton` below is unchanged in outward shape: the same button +\n * `Modal`, now rendering this body inside.\n */\nexport function CallFromCodeBody({\n resource,\n triggers,\n wrap = false,\n maxHeight = \"420px\",\n initialTab,\n}: {\n resource: SnippetCallable;\n /**\n * The workflow's declared manual (`@w6w/trigger`) triggers, one entry per\n * step, in declared order — optional so every other `CallFromCodeBody`\n * caller (function, endpoint, connection, var, document) is unaffected.\n * Both call sites derive this from a workflow definition already in scope\n * (T2.2.1, HITL-2/HITL-4 pinned); nothing here fetches it. The selected\n * trigger's declared fields are passed straight into `buildSnippet` and\n * rendered INSIDE the generated code — required fields as active code with\n * a type-derived placeholder, optional fields commented out (D-3/D-4) — so\n * there is nothing left to duplicate in a panel above it.\n */\n triggers?: TriggerPreview[];\n /**\n * Soft-wrap the code box instead of scrolling it horizontally. Default OFF\n * — see the `CodeBlock` call below for why off is right wherever there is\n * room, and why the right rail is the place where it is not.\n */\n wrap?: boolean;\n /** The code box's max height. Default `\"420px\"`, the modal's size. */\n maxHeight?: string;\n /**\n * Which language to open on. Seeds the selection ONCE, at mount — this is a\n * starting point, not a controlled value, so the strip stays clickable\n * afterwards.\n *\n * That \"once\" is load-bearing for the rail: `CodeTool` mounts this inside a\n * modal that is conditionally rendered, so picking Python, closing, and\n * picking Node re-mounts and re-seeds. A tab this resource does not carry\n * falls back to the first one it does, via `activeTab` below.\n */\n initialTab?: TabId;\n}) {\n const [tab, setTab] = useState<TabId>(initialTab ?? \"node\");\n const [triggerIndex, setTriggerIndex] = useState(0);\n const hasTriggers = !!triggers && triggers.length > 0;\n const selectedTrigger = hasTriggers\n ? (triggers[Math.min(triggerIndex, triggers.length - 1)] ?? triggers[0])\n : null;\n const snippet = buildSnippet(resource, selectedTrigger?.fields);\n // Only the tabs this snippet carries. `curl` is emitted for a Function,\n // Workflow, or an Endpoint that knows its own server-rendered URL — a var,\n // document or connection still renders exactly Node/CLI/Python.\n const tabs = snippet ? TABS.filter((t) => typeof snippet[t.id] === \"string\") : [];\n // Never leave the selection pointing at a tab that is not on the strip — the\n // component is mounted once per page and `tab` outlives a resource change.\n const activeTab: TabId = tabs.some((t) => t.id === tab) ? tab : (tabs[0]?.id ?? \"node\");\n const code = snippet?.[activeTab] ?? \"\";\n\n if (snippet === null) return <p className=\"muted\">{unavailableReason(resource)}</p>;\n\n return (\n <>\n {hasTriggers && selectedTrigger && (\n <div className=\"subpanel\" style={{ marginTop: 0, paddingTop: 0, borderTop: \"none\" }}>\n {/* Reuses `.code-tabs`/`.code-tab` — the modal's own existing\n Node/CLI/Python strip pattern (HITL-2: \"mirroring the\n modal's existing Node/CLI/Python strip\"). Nested INSIDE\n the trigger panel so the language tab-strip assertion\n below (which filters out anything under\n `[data-testid='trigger-panel']`) still sees exactly\n Node/CLI/Python. The selected trigger's fields are no\n longer listed HERE — they are rendered inside the code\n below (required active, optional commented; D-3/D-4),\n so a list here would only duplicate it. */}\n <div data-testid=\"trigger-panel\">\n <div className=\"code-tabs\">\n {triggers.map((t, i) => (\n <button\n key={t.id}\n type=\"button\"\n className={`code-tab${i === triggerIndex ? \" active\" : \"\"}`}\n data-testid=\"trigger-tab\"\n onClick={() => setTriggerIndex(i)}\n >\n {t.label}\n </button>\n ))}\n </div>\n {selectedTrigger.fields.length === 0 && (\n <p className=\"muted small\">This trigger declares no fields.</p>\n )}\n </div>\n {triggers.length > 1 && (\n <p className=\"muted small\" data-testid=\"trigger-multi-note\">\n This workflow has {triggers.length} manual triggers — the same input reaches every one\n of them identically; there is no per-trigger routing.\n </p>\n )}\n </div>\n )}\n\n <div className=\"code-tabs\">\n {tabs.map((t) => (\n <button\n key={t.id}\n type=\"button\"\n className={`code-tab${activeTab === t.id ? \" active\" : \"\"}`}\n onClick={() => setTab(t.id)}\n >\n {t.label}\n </button>\n ))}\n </div>\n\n {/* `wrap` is a CALLER decision, defaulting OFF. Off is right wherever\n there is room: the CLI snippet's `\\`-continued lines are chosen line\n breaks, and soft-wrapping blurs them into the accidental ones, so a\n long Node line scrolls instead.\n It is wrong in the right RAIL, whose panel is ~395px wide — there\n every snippet scrolls horizontally, every time, and a snippet you\n have to drag sideways to read is not a snippet you can read. The\n rail passes `wrap`; the modal (which has the room) does not. The\n copy affordance lives inside the code box itself (`copyable`) — no\n local `CopyButton`, no `.code-tabs-spacer`. */}\n <CodeBlock\n code={code}\n language={TABS.find((t) => t.id === activeTab)?.grammar ?? \"plaintext\"}\n maxHeight={maxHeight}\n wrap={wrap}\n aria-label={`${TABS.find((t) => t.id === activeTab)?.label ?? activeTab} snippet`}\n copyable\n />\n\n {/* One arm per tab, and `python` is now EXPLICIT: it used to be\n the trailing `else`, so a fourth tab would silently have\n inherited \"pip install w6w\". The `curl` arm names no\n `operation` — raw HTTP maps to no wrapper-contract operation,\n and claiming one would be a promise the contract does not\n make. */}\n <p className=\"muted small\" style={{ marginBottom: 0 }}>\n {activeTab === \"node\" ? (\n <>\n <code>npm i @w6w/sdk</code> · set <code>W6W_BASE_URL</code> and <code>W6W_TOKEN</code> ·\n operation <code>{snippet.operation}</code>\n </>\n ) : activeTab === \"cli\" ? (\n <>\n <code>npm i -g @w6w/cli</code> · set <code>W6W_BASE_URL</code> and{\" \"}\n <code>W6W_TOKEN</code> (or pass <code>--base-url</code> / <code>--token</code>) ·\n operation <code>{snippet.operation}</code>\n </>\n ) : activeTab === \"python\" ? (\n <>\n <code>pip install w6w</code> · set <code>W6W_BASE_URL</code> and <code>W6W_TOKEN</code>{\" \"}\n · operation <code>{snippet.operation}</code>\n </>\n ) : (\n <>\n No client library — any HTTP client will do. Set <code>W6W_BASE_URL</code> to your w6w\n base URL (for an Endpoint, the URL above is the one this page is showing); substitute a\n w6w token for <code>$W6W_TOKEN</code> and send the declared input as the JSON body.\n </>\n )}\n </p>\n </>\n );\n}\n\nexport function CallFromCodeButton({\n resource,\n label = \"Call from code\",\n triggers,\n initialTab,\n}: {\n resource: SnippetCallable;\n label?: string;\n /** See {@link CallFromCodeBody}'s own doc — passed straight through. */\n triggers?: TriggerPreview[];\n /** See {@link CallFromCodeBody}'s own doc — passed straight through. */\n initialTab?: TabId;\n}) {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n <IconButton icon=\"code\" label={label} onClick={() => setOpen(true)} />\n\n {open && (\n <Modal title=\"Call from code\" size=\"wide\" onClose={() => setOpen(false)}>\n <CallFromCodeBody resource={resource} triggers={triggers} initialTab={initialTab} />\n </Modal>\n )}\n </>\n );\n}\n","import { Modal } from \"./Modal.tsx\";\n\ninterface ConfirmModalProps {\n title: string;\n message: string;\n /** Fired when the user confirms. The caller clears its pending state via onClose. */\n onConfirm: () => void;\n /** Fired on Cancel, Esc, or outside-click — dismisses without confirming. */\n onClose: () => void;\n confirmLabel?: string;\n cancelLabel?: string;\n /** Style the confirm button as destructive (default true — this dialog gates dangerous actions). */\n destructive?: boolean;\n}\n\n/**\n * A reusable confirmation dialog built on our <dialog>-based Modal, so it inherits\n * focus-trap, Esc-dismiss, and outside-click close. Replaces the browser's native\n * confirmation prompt for destructive actions: Confirm fires `onConfirm`;\n * Cancel/Esc/outside-click fires `onClose` only (no confirmation).\n */\nexport function ConfirmModal({\n title,\n message,\n onConfirm,\n onClose,\n confirmLabel = \"Confirm\",\n cancelLabel = \"Cancel\",\n destructive = true,\n}: ConfirmModalProps) {\n return (\n <Modal title={title} onClose={onClose}>\n <div className=\"modal-body\">\n <p className=\"muted small\">{message}</p>\n </div>\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={onClose}>\n {cancelLabel}\n </button>\n <button type=\"button\" className={destructive ? \"btn danger\" : \"btn\"} onClick={onConfirm}>\n {confirmLabel}\n </button>\n </div>\n </Modal>\n );\n}\n"],"names":["Modal","title","onClose","children","wide","xl","headerRight","ref","useRef","useEffect","el","onCancel","e","onClick","r","jsx","jsxs","TABS","snippetTabsFor","resource","snippet","buildSnippet","t","CallFromCodeBody","triggers","wrap","maxHeight","initialTab","tab","setTab","useState","triggerIndex","setTriggerIndex","hasTriggers","selectedTrigger","tabs","activeTab","_a","code","unavailableReason","Fragment","i","CodeBlock","_b","_c","CallFromCodeButton","label","open","setOpen","IconButton","ConfirmModal","message","onConfirm","confirmLabel","cancelLabel","destructive"],"mappings":"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"}
|