@w6w/embed 0.2.11 → 0.2.20
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 +22 -5
- package/dist/ConfirmModal-Pv2-A_3U.js +186 -0
- package/dist/ConfirmModal-Pv2-A_3U.js.map +1 -0
- package/dist/{CreateFunctionModal-D6CQLpa_.js → CreateFunctionModal-DScxp_LN.js} +2 -2
- package/dist/{CreateFunctionModal-D6CQLpa_.js.map → CreateFunctionModal-DScxp_LN.js.map} +1 -1
- package/dist/{DocumentFormModal-YauVdolr.js → DocumentFormModal-Br4s8wmi.js} +3 -3
- package/dist/{DocumentFormModal-YauVdolr.js.map → DocumentFormModal-Br4s8wmi.js.map} +1 -1
- package/dist/ImportSpecModal-Cpzp8ndt.js +251 -0
- package/dist/ImportSpecModal-Cpzp8ndt.js.map +1 -0
- package/dist/{ModelRoutesManager-BGESQahw.js → ModelRoutesManager-1Ac5wcas.js} +3 -3
- package/dist/{ModelRoutesManager-BGESQahw.js.map → ModelRoutesManager-1Ac5wcas.js.map} +1 -1
- package/dist/WorkflowEditor-CmhXHRxi.js +1109 -0
- package/dist/WorkflowEditor-CmhXHRxi.js.map +1 -0
- package/dist/apps-ItBvnWX3.js +92 -0
- package/dist/apps-ItBvnWX3.js.map +1 -0
- package/dist/chrome/DangerZone.d.ts +4 -3
- package/dist/chrome/ExecutionProfileHeader.d.ts +3 -3
- package/dist/chrome/JsonToggle.d.ts +29 -20
- package/dist/chrome/Modal.d.ts +3 -1
- package/dist/chrome/RightRail.d.ts +6 -1
- package/dist/chrome/VersionHistoryModal.d.ts +2 -0
- package/dist/chrome/index.d.ts +1 -0
- package/dist/chrome/workspace.d.ts +32 -1
- package/dist/{coerce-input-DttlcSdO.js → coerce-input-DFJ4n_wc.js} +68 -69
- package/dist/coerce-input-DFJ4n_wc.js.map +1 -0
- package/dist/{connections-D7cgXhDS.js → connections-CzsCyIxY.js} +10 -10
- package/dist/{connections-D7cgXhDS.js.map → connections-CzsCyIxY.js.map} +1 -1
- package/dist/{credentials-DaQU3Ca_.js → credentials-Cn92LGhJ.js} +4 -4
- package/dist/{credentials-DaQU3Ca_.js.map → credentials-Cn92LGhJ.js.map} +1 -1
- package/dist/data-stores-UeQvwVCa.js +170 -0
- package/dist/data-stores-UeQvwVCa.js.map +1 -0
- package/dist/document-sources-DNmBojx6.js +169 -0
- package/dist/document-sources-DNmBojx6.js.map +1 -0
- package/dist/draft/use-workflow-draft.d.ts +2 -0
- package/dist/draft.mjs +2 -2
- package/dist/editor/PublishTooltip.d.ts +7 -0
- package/dist/editor/SetupIncompleteBanner.d.ts +12 -0
- package/dist/editor/StartingStateModal.d.ts +14 -0
- package/dist/editor/WorkflowSettingsModal.d.ts +6 -1
- package/dist/editor/WorkflowVariablesEditor.d.ts +6 -0
- package/dist/editor/definition.d.ts +4 -0
- package/dist/editor/json-apply.d.ts +29 -0
- package/dist/editor/step-problems-feed.d.ts +5 -0
- package/dist/editor/types.d.ts +2 -2
- package/dist/editor-apps-DkkC7wOQ.js +152 -0
- package/dist/editor-apps-DkkC7wOQ.js.map +1 -0
- package/dist/editor-tools-BR27RGto.js +1683 -0
- package/dist/editor-tools-BR27RGto.js.map +1 -0
- package/dist/editor.mjs +1 -1
- package/dist/editors.mjs +536 -478
- package/dist/editors.mjs.map +1 -1
- package/dist/forms.mjs +3 -3
- package/dist/{rail-settings-XYGToh00.js → import-bindings-EUtxZ9Ti.js} +90 -24
- package/dist/import-bindings-EUtxZ9Ti.js.map +1 -0
- package/dist/index.mjs +138 -108
- package/dist/index.mjs.map +1 -1
- package/dist/lib/binding-problems.d.ts +5 -1
- package/dist/lib/history-query.d.ts +45 -0
- package/dist/lib/import-bindings.d.ts +89 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/rail-settings.d.ts +1 -1
- package/dist/lib/setup-incomplete.d.ts +22 -0
- package/dist/lib/starting-data.d.ts +31 -0
- package/dist/lib/state-panel.d.ts +29 -0
- package/dist/lib/target-fields.d.ts +3 -15
- package/dist/lib/workflow-live-run.d.ts +84 -6
- package/dist/lib/workflow-validity.d.ts +64 -16
- package/dist/lib/workflow-variables.d.ts +1 -1
- package/dist/lib/workflow-version.d.ts +2 -0
- package/dist/lib.mjs +87 -72
- package/dist/lists/DataStoreList.d.ts +17 -0
- package/dist/lists/DataStoreView.d.ts +19 -0
- package/dist/lists/Logs.d.ts +19 -0
- package/dist/lists.d.ts +6 -0
- package/dist/lists.mjs +1255 -816
- package/dist/lists.mjs.map +1 -1
- package/dist/rail/ConnectionsTool.d.ts +2 -0
- package/dist/rail/HistoryTool.d.ts +2 -0
- package/dist/rail/StartingStateTool.d.ts +2 -0
- package/dist/rail/settings-sections.d.ts +4 -1
- package/dist/rail.mjs +1 -1
- package/dist/repos/connections.d.ts +1 -0
- package/dist/repos/constants.d.ts +12 -0
- package/dist/repos/data-stores.d.ts +84 -0
- package/dist/repos/history.d.ts +9 -0
- package/dist/repos/index.d.ts +2 -0
- package/dist/repos/spec-export.d.ts +3 -3
- package/dist/repos/spec-import.d.ts +30 -1
- package/dist/repos/step-tests.d.ts +2 -0
- package/dist/repos/webhook-listen.d.ts +35 -0
- package/dist/repos/workflows.d.ts +105 -2
- package/dist/repos.mjs +370 -328
- package/dist/repos.mjs.map +1 -1
- package/dist/setup-incomplete-BHs3Lpfy.js +199 -0
- package/dist/setup-incomplete-BHs3Lpfy.js.map +1 -0
- package/dist/{spec-export-CBbloO_n.js → spec-export-DGy5ijps.js} +72 -59
- package/dist/spec-export-DGy5ijps.js.map +1 -0
- package/dist/spec-import-SWOonsNr.js +116 -0
- package/dist/spec-import-SWOonsNr.js.map +1 -0
- package/dist/{step-tests-CivICmTq.js → step-tests-B4E4W3ly.js} +8 -7
- package/dist/step-tests-B4E4W3ly.js.map +1 -0
- package/dist/{use-callable-draft-DsALnSfF.js → use-callable-draft-DCauHt5o.js} +2 -2
- package/dist/{use-callable-draft-DsALnSfF.js.map → use-callable-draft-DCauHt5o.js.map} +1 -1
- package/dist/use-workflow-draft-l3P5KZzw.js +338 -0
- package/dist/use-workflow-draft-l3P5KZzw.js.map +1 -0
- package/dist/workflows-BZN4Hyz1.js +623 -0
- package/dist/workflows-BZN4Hyz1.js.map +1 -0
- package/package.json +4 -3
- package/src/styles.css +153 -1
- package/dist/ConfirmModal-BE-SdX-O.js +0 -185
- package/dist/ConfirmModal-BE-SdX-O.js.map +0 -1
- package/dist/ImportSpecModal-B7qd1Km2.js +0 -136
- package/dist/ImportSpecModal-B7qd1Km2.js.map +0 -1
- package/dist/WorkflowEditor-CwvmAGp2.js +0 -925
- package/dist/WorkflowEditor-CwvmAGp2.js.map +0 -1
- package/dist/apps-CboASBKr.js +0 -77
- package/dist/apps-CboASBKr.js.map +0 -1
- package/dist/coerce-input-DttlcSdO.js.map +0 -1
- package/dist/document-sources-UCwe8x77.js +0 -91
- package/dist/document-sources-UCwe8x77.js.map +0 -1
- package/dist/editor-apps-BUZWld-m.js +0 -95
- package/dist/editor-apps-BUZWld-m.js.map +0 -1
- package/dist/editor-tools-B_Lfx3kw.js +0 -1279
- package/dist/editor-tools-B_Lfx3kw.js.map +0 -1
- package/dist/rail-settings-XYGToh00.js.map +0 -1
- package/dist/spec-export-CBbloO_n.js.map +0 -1
- package/dist/spec-import-CW6R_Wk1.js +0 -469
- package/dist/spec-import-CW6R_Wk1.js.map +0 -1
- package/dist/step-tests-CivICmTq.js.map +0 -1
- package/dist/trigger-preview-DKxfjzUY.js +0 -145
- package/dist/trigger-preview-DKxfjzUY.js.map +0 -1
- package/dist/use-workflow-draft-DzAyUeA6.js +0 -316
- package/dist/use-workflow-draft-DzAyUeA6.js.map +0 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ page can import it.
|
|
|
35
35
|
| `@w6w/embed` | `W6WEmbedProvider`, `useEmbedStatus`, `useEmbedProject`, `EmbedAuthError`. |
|
|
36
36
|
| `@w6w/embed/editor` | `WorkflowEditor` alone, loaded lazily. |
|
|
37
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`. |
|
|
38
|
+
| `@w6w/embed/lists` | The connected lists and detail views: `FunctionList`, `EndpointList`, `WorkflowList`, `ReliabilityBoard`, `ActivitySummary`, `Logs`, `RunHistory`, `DocumentList`, `DataStoreList`, `DataStoreView`, `ServiceDetail`, `ConnectionList`, `ConnectionDetail`. |
|
|
39
39
|
| `@w6w/embed/forms` | The configuration forms: `CreateFunctionModal`, `CreateEndpointModal`, `VarsManager`, `SecretsManager`. |
|
|
40
40
|
| `@w6w/embed/rail` | `CallableWorkspace` and `CallableRail`, to place the editor's rail yourself. |
|
|
41
41
|
| `@w6w/embed/repos` | The data hooks the components read through (`useFunctionsQuery`, `useAppActionsQuery`, ...), on the provider's one cache. |
|
|
@@ -122,8 +122,9 @@ never reaches the browser. The recipe is in the guide at `/guides/embed/`.
|
|
|
122
122
|
- `project={{ use: "default" }}` uses the account's default project instead of an id you know. It
|
|
123
123
|
is looked up once per identity (one `GET /projects`, the row with `isDefault`), never the first
|
|
124
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
|
|
126
|
-
|
|
125
|
+
`"resolving" | "ready" | "error"`: while resolving, `project` is `null` and editors refuse to
|
|
126
|
+
save, without showing the "no project selected" notice (that notice appears only when there is
|
|
127
|
+
truly no project); if the lookup fails or no row is the default, `status` is
|
|
127
128
|
`"error"` and nothing falls back to another project. A plain `project="proj_123"` is `"ready"`
|
|
128
129
|
at once; omitted, it is `{ project: null, status: "ready" }`.
|
|
129
130
|
- `identityKey={null}` means nobody is signed in: the provider renders `fallback` (default
|
|
@@ -262,7 +263,7 @@ See the [components reference](../../docs/embed/components.md).
|
|
|
262
263
|
|
|
263
264
|
## Lists
|
|
264
265
|
|
|
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
|
+
`@w6w/embed/lists` holds the connected lists (`FunctionList`, `EndpointList`, `WorkflowList`, `ReliabilityBoard`, `ActivitySummary`, `Logs`, `RunHistory`, `DocumentList`, `DataStoreList`, `DataStoreView`, `ServiceDetail`, `ConnectionList`, `ConnectionDetail`). Each reads through the same provider as the editor and
|
|
266
267
|
writes through it, so a host mounts nothing else.
|
|
267
268
|
|
|
268
269
|
| Component | What it does |
|
|
@@ -296,7 +297,9 @@ requests on purpose: "Today" is cut at the viewer's local midnight (`from`, `buc
|
|
|
296
297
|
server only groups by `day` or `week`, cutting at midnight in the database's timezone, so one
|
|
297
298
|
request cannot give a local day. `<RunHistory scope? showKind? filters? onFiltersChange?
|
|
298
299
|
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.
|
|
300
|
+
omit `filters` and it keeps them itself, pass them and you own them. `<Logs title?>` is that view
|
|
301
|
+
under a heading (`"Logs"` by default, `null` for none): drop it inside `<W6WEmbedProvider>` for the
|
|
302
|
+
project's recent executions, each opening its detail in place. See the
|
|
300
303
|
[components reference](../../docs/embed/components.md).
|
|
301
304
|
|
|
302
305
|
`<ServiceDetail appId project? days? backHref? onBack? slots?>` shows one service's reliability
|
|
@@ -342,6 +345,20 @@ shares in from a repository show no Edit or Delete. The embed has no repository
|
|
|
342
345
|
from" markers; a host that wants them adds them through the list's row slots (`lead`,
|
|
343
346
|
`sharedActions`, `footer`). Details are in the components reference.
|
|
344
347
|
|
|
348
|
+
## Data stores
|
|
349
|
+
|
|
350
|
+
| Component | Import | What it is |
|
|
351
|
+
| --- | --- | --- |
|
|
352
|
+
| `<DataStoreList>` | `@w6w/embed/lists` | A project's data stores: create and archive. Opening one is the host's `onOpen` / `getHref`. |
|
|
353
|
+
| `<DataStoreView id>` | `@w6w/embed/lists` | One store: a table as an editable grid, a key-value or document store as an entry list with an editor. A table also imports and exports CSV. |
|
|
354
|
+
|
|
355
|
+
Both take `project` (omitted: the provider's project; `null` or `""`: nothing is read and writes
|
|
356
|
+
refuse). Every save sends the version it loaded; if someone else changed the entry first, the row or
|
|
357
|
+
editor shows a Reload prompt instead of overwriting. `<W6WEmbedProvider>` also fills the store
|
|
358
|
+
picker of the `@w6w/store` step in an embedded editor. A scoped or IP-restricted `tsec_` token can
|
|
359
|
+
read stores but not write them, so a view opened with one lists and shows entries and every save
|
|
360
|
+
is refused by the server. Details are in the components reference.
|
|
361
|
+
|
|
345
362
|
## Endpoint editor
|
|
346
363
|
|
|
347
364
|
| Component | Import | What it is |
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { jsx as e, jsxs as a, Fragment as f } from "react/jsx-runtime";
|
|
2
|
+
import { b as W, u as E } from "./slug-BVdgiP_L.js";
|
|
3
|
+
import { IconButton as S, Modal as _, CodeBlock as B } from "@w6w/ui";
|
|
4
|
+
import { useRef as L, useEffect as $, useState as N } from "react";
|
|
5
|
+
function x({
|
|
6
|
+
title: i,
|
|
7
|
+
onClose: n,
|
|
8
|
+
children: c,
|
|
9
|
+
wide: p = !1,
|
|
10
|
+
xl: s = !1,
|
|
11
|
+
headerRight: d,
|
|
12
|
+
className: b
|
|
13
|
+
}) {
|
|
14
|
+
const u = L(null);
|
|
15
|
+
return $(() => {
|
|
16
|
+
const o = u.current;
|
|
17
|
+
if (!o) return;
|
|
18
|
+
o.open || o.showModal();
|
|
19
|
+
const g = (l) => {
|
|
20
|
+
l.preventDefault(), n();
|
|
21
|
+
}, h = (l) => {
|
|
22
|
+
if (l.target !== o) return;
|
|
23
|
+
const m = o.getBoundingClientRect();
|
|
24
|
+
(l.clientX < m.left || l.clientX > m.right || l.clientY < m.top || l.clientY > m.bottom) && n();
|
|
25
|
+
};
|
|
26
|
+
return o.addEventListener("cancel", g), o.addEventListener("click", h), () => {
|
|
27
|
+
o.removeEventListener("cancel", g), o.removeEventListener("click", h);
|
|
28
|
+
};
|
|
29
|
+
}, [n]), /* @__PURE__ */ e("div", { className: "modal-backdrop", children: /* @__PURE__ */ a(
|
|
30
|
+
"dialog",
|
|
31
|
+
{
|
|
32
|
+
ref: u,
|
|
33
|
+
className: `modal${p ? " modal-wide" : ""}${s ? " modal-xl" : ""}${b ? ` ${b}` : ""}`,
|
|
34
|
+
"aria-label": i,
|
|
35
|
+
children: [
|
|
36
|
+
d ? /* @__PURE__ */ a("div", { className: "modal-head", children: [
|
|
37
|
+
/* @__PURE__ */ e("h3", { children: i }),
|
|
38
|
+
d
|
|
39
|
+
] }) : /* @__PURE__ */ e("h3", { children: i }),
|
|
40
|
+
c
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
) });
|
|
44
|
+
}
|
|
45
|
+
const y = [
|
|
46
|
+
{ id: "node", label: "Node", language: "TypeScript", grammar: "typescript", icon: "lang-node" },
|
|
47
|
+
{ id: "cli", label: "CLI", language: "Shell", grammar: "bash", icon: "terminal" },
|
|
48
|
+
{ id: "python", label: "Python", language: "Python", grammar: "python", icon: "lang-python" },
|
|
49
|
+
{ id: "curl", label: "curl", language: "Shell", grammar: "bash", icon: "lang-curl" }
|
|
50
|
+
];
|
|
51
|
+
function F(i) {
|
|
52
|
+
const n = W(i);
|
|
53
|
+
return n ? y.filter((c) => typeof n[c.id] == "string") : [];
|
|
54
|
+
}
|
|
55
|
+
function R({
|
|
56
|
+
resource: i,
|
|
57
|
+
triggers: n,
|
|
58
|
+
wrap: c = !1,
|
|
59
|
+
maxHeight: p = "420px",
|
|
60
|
+
initialTab: s
|
|
61
|
+
}) {
|
|
62
|
+
var v, C, w;
|
|
63
|
+
const [d, b] = N(s ?? "node"), [u, o] = N(0), g = !!n && n.length > 0, h = g ? n[Math.min(u, n.length - 1)] ?? n[0] : null, l = W(i, h == null ? void 0 : h.fields), m = l ? y.filter((t) => typeof l[t.id] == "string") : [], r = m.some((t) => t.id === d) ? d : ((v = m[0]) == null ? void 0 : v.id) ?? "node", k = (l == null ? void 0 : l[r]) ?? "";
|
|
64
|
+
return l === null ? /* @__PURE__ */ e("p", { className: "muted", children: E(i) }) : /* @__PURE__ */ a(f, { children: [
|
|
65
|
+
g && h && /* @__PURE__ */ a("div", { className: "subpanel", style: { marginTop: 0, paddingTop: 0, borderTop: "none" }, children: [
|
|
66
|
+
/* @__PURE__ */ a("div", { "data-testid": "trigger-panel", children: [
|
|
67
|
+
/* @__PURE__ */ e("div", { className: "code-tabs", children: n.map((t, T) => /* @__PURE__ */ e(
|
|
68
|
+
"button",
|
|
69
|
+
{
|
|
70
|
+
type: "button",
|
|
71
|
+
className: `code-tab${T === u ? " active" : ""}`,
|
|
72
|
+
"data-testid": "trigger-tab",
|
|
73
|
+
onClick: () => o(T),
|
|
74
|
+
children: t.label
|
|
75
|
+
},
|
|
76
|
+
t.id
|
|
77
|
+
)) }),
|
|
78
|
+
h.fields.length === 0 && /* @__PURE__ */ e("p", { className: "muted small", children: "This trigger declares no fields." })
|
|
79
|
+
] }),
|
|
80
|
+
n.length > 1 && /* @__PURE__ */ a("p", { className: "muted small", "data-testid": "trigger-multi-note", children: [
|
|
81
|
+
"This workflow has ",
|
|
82
|
+
n.length,
|
|
83
|
+
" manual triggers — the same input reaches every one of them identically; there is no per-trigger routing."
|
|
84
|
+
] })
|
|
85
|
+
] }),
|
|
86
|
+
/* @__PURE__ */ e("div", { className: "code-tabs", children: m.map((t) => /* @__PURE__ */ e(
|
|
87
|
+
"button",
|
|
88
|
+
{
|
|
89
|
+
type: "button",
|
|
90
|
+
className: `code-tab${r === t.id ? " active" : ""}`,
|
|
91
|
+
onClick: () => b(t.id),
|
|
92
|
+
children: t.label
|
|
93
|
+
},
|
|
94
|
+
t.id
|
|
95
|
+
)) }),
|
|
96
|
+
/* @__PURE__ */ e(
|
|
97
|
+
B,
|
|
98
|
+
{
|
|
99
|
+
code: k,
|
|
100
|
+
language: ((C = y.find((t) => t.id === r)) == null ? void 0 : C.grammar) ?? "plaintext",
|
|
101
|
+
maxHeight: p,
|
|
102
|
+
wrap: c,
|
|
103
|
+
"aria-label": `${((w = y.find((t) => t.id === r)) == null ? void 0 : w.label) ?? r} snippet`,
|
|
104
|
+
copyable: !0
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/* @__PURE__ */ e("p", { className: "muted small", style: { marginBottom: 0 }, children: r === "node" ? /* @__PURE__ */ a(f, { children: [
|
|
108
|
+
/* @__PURE__ */ e("code", { children: "npm i @w6w/sdk" }),
|
|
109
|
+
" · set ",
|
|
110
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
111
|
+
" and ",
|
|
112
|
+
/* @__PURE__ */ e("code", { children: "W6W_TOKEN" }),
|
|
113
|
+
" · operation ",
|
|
114
|
+
/* @__PURE__ */ e("code", { children: l.operation })
|
|
115
|
+
] }) : r === "cli" ? /* @__PURE__ */ a(f, { children: [
|
|
116
|
+
/* @__PURE__ */ e("code", { children: "npm i -g @w6w/cli" }),
|
|
117
|
+
" · set ",
|
|
118
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
119
|
+
" and",
|
|
120
|
+
" ",
|
|
121
|
+
/* @__PURE__ */ e("code", { children: "W6W_TOKEN" }),
|
|
122
|
+
" (or pass ",
|
|
123
|
+
/* @__PURE__ */ e("code", { children: "--base-url" }),
|
|
124
|
+
" / ",
|
|
125
|
+
/* @__PURE__ */ e("code", { children: "--token" }),
|
|
126
|
+
") · operation ",
|
|
127
|
+
/* @__PURE__ */ e("code", { children: l.operation })
|
|
128
|
+
] }) : r === "python" ? /* @__PURE__ */ a(f, { children: [
|
|
129
|
+
/* @__PURE__ */ e("code", { children: "pip install w6w" }),
|
|
130
|
+
" · set ",
|
|
131
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
132
|
+
" and ",
|
|
133
|
+
/* @__PURE__ */ e("code", { children: "W6W_TOKEN" }),
|
|
134
|
+
" ",
|
|
135
|
+
"· operation ",
|
|
136
|
+
/* @__PURE__ */ e("code", { children: l.operation })
|
|
137
|
+
] }) : /* @__PURE__ */ a(f, { children: [
|
|
138
|
+
"No client library — any HTTP client will do. Set ",
|
|
139
|
+
/* @__PURE__ */ e("code", { children: "W6W_BASE_URL" }),
|
|
140
|
+
" to your w6w base URL (for an Endpoint, the URL above is the one this page is showing); substitute a w6w token for ",
|
|
141
|
+
/* @__PURE__ */ e("code", { children: "$W6W_TOKEN" }),
|
|
142
|
+
" and send the declared input as the JSON body."
|
|
143
|
+
] }) })
|
|
144
|
+
] });
|
|
145
|
+
}
|
|
146
|
+
function I({
|
|
147
|
+
resource: i,
|
|
148
|
+
label: n = "Call from code",
|
|
149
|
+
triggers: c,
|
|
150
|
+
initialTab: p
|
|
151
|
+
}) {
|
|
152
|
+
const [s, d] = N(!1);
|
|
153
|
+
return /* @__PURE__ */ a(f, { children: [
|
|
154
|
+
/* @__PURE__ */ e(S, { icon: "code", label: n, onClick: () => d(!0) }),
|
|
155
|
+
s && /* @__PURE__ */ e(_, { title: "Call from code", size: "wide", onClose: () => d(!1), children: /* @__PURE__ */ e(R, { resource: i, triggers: c, initialTab: p }) })
|
|
156
|
+
] });
|
|
157
|
+
}
|
|
158
|
+
function K({
|
|
159
|
+
title: i,
|
|
160
|
+
message: n,
|
|
161
|
+
children: c,
|
|
162
|
+
onConfirm: p,
|
|
163
|
+
onClose: s,
|
|
164
|
+
confirmLabel: d = "Confirm",
|
|
165
|
+
cancelLabel: b = "Cancel",
|
|
166
|
+
destructive: u = !0
|
|
167
|
+
}) {
|
|
168
|
+
return /* @__PURE__ */ a(x, { title: i, onClose: s, children: [
|
|
169
|
+
/* @__PURE__ */ a("div", { className: "modal-body", children: [
|
|
170
|
+
/* @__PURE__ */ e("p", { className: "muted small", children: n }),
|
|
171
|
+
c
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ a("div", { className: "modal-actions", children: [
|
|
174
|
+
/* @__PURE__ */ e("button", { type: "button", className: "btn ghost", onClick: s, children: b }),
|
|
175
|
+
/* @__PURE__ */ e("button", { type: "button", className: u ? "btn danger" : "btn", onClick: p, children: d })
|
|
176
|
+
] })
|
|
177
|
+
] });
|
|
178
|
+
}
|
|
179
|
+
export {
|
|
180
|
+
K as C,
|
|
181
|
+
x as M,
|
|
182
|
+
I as a,
|
|
183
|
+
R as b,
|
|
184
|
+
F as s
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=ConfirmModal-Pv2-A_3U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmModal-Pv2-A_3U.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 /** Extra class on the `<dialog>` (e.g. `modal-json`, the fill-and-scroll JSON layout). */\n className?: string;\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 className,\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\" : \"\"}${className ? ` ${className}` : \"\"}`}\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 type { ReactNode } from \"react\";\nimport { Modal } from \"./Modal.tsx\";\n\ninterface ConfirmModalProps {\n title: string;\n message: string;\n /** Optional content rendered under the message (e.g. a list of impacted items). */\n children?: ReactNode;\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 children,\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 {children}\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","className","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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"}
|
|
@@ -2,7 +2,7 @@ import { jsx as n, jsxs as i } from "react/jsx-runtime";
|
|
|
2
2
|
import { ApiError as I } from "@w6w/sdk";
|
|
3
3
|
import { useEnterSubmit as K } from "@w6w/ui";
|
|
4
4
|
import { useState as d } from "react";
|
|
5
|
-
import { M } from "./ConfirmModal-
|
|
5
|
+
import { M } from "./ConfirmModal-Pv2-A_3U.js";
|
|
6
6
|
import { n as F, u as D, a as O, E as T, b as P, c as B, F as L } from "./endpoints-DSRo1Lc5.js";
|
|
7
7
|
import { i as x, s as A } from "./slug-BVdgiP_L.js";
|
|
8
8
|
function R(e) {
|
|
@@ -218,4 +218,4 @@ export {
|
|
|
218
218
|
V as F,
|
|
219
219
|
J as a
|
|
220
220
|
};
|
|
221
|
-
//# sourceMappingURL=CreateFunctionModal-
|
|
221
|
+
//# sourceMappingURL=CreateFunctionModal-DScxp_LN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateFunctionModal-D6CQLpa_.js","sources":["../src/forms/CreateEndpointModal.tsx","../src/forms/CreateFunctionModal.tsx"],"sourcesContent":["import { ApiError } from \"@w6w/sdk\";\nimport { useEnterSubmit } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport { Modal } from \"../chrome/Modal.tsx\";\nimport { newCallableId } from \"../lib/callable-descriptors.ts\";\nimport { isEndpointKey, slugify } from \"../lib/slug.ts\";\nimport {\n ENDPOINT_MANIFEST_VERSION,\n useEndpointsQuery,\n useSaveEndpointMutation,\n} from \"../repos/endpoints.ts\";\n\n/**\n * Identity modal shared by the Endpoints list (\"+ New endpoint\" — create\n * mode) and the editor's read-only info block (\"edit\" icon-button — edit\n * mode). `isEdit = !!props.initial`, mirroring `VarModal` and `FunctionIdentityModal`.\n *\n * **Create mode POSTs for real, right here — before any editor exists.**\n * That is this node's whole point: the row is created against the server\n * before the operator can put target/input work into a plain `useState` that\n * used to die on a missing var, a lost tab, or anything else short of a\n * completed Save. Submit is disabled unless the key clears\n * {@link isEndpointKey}; `takenKeys` (from the list's own `GET /endpoints`)\n * is an ADVISORY pre-check only — the account-scoped unique index is the\n * arbiter, and any refusal (409 `endpoint_key_conflict`, 409\n * `key_immutable`, 400 `invalid_endpoint`) renders `ApiError.message`\n * verbatim and leaves the modal open with what was typed intact.\n *\n * **Edit mode writes NOTHING.** `POST /endpoints` is a whole-definition\n * upsert, so an identity-only PATCH here would silently wipe the target and\n * input the editor already has saved — precisely the data loss this whole\n * node exists to stop. The patched fields go back through `onSaved`; the\n * editor's own `onSave()` stays the one path that ever persists them.\n */\nexport function EndpointIdentityModal(props: {\n /** Edit mode when present; create mode when absent. Mirrors VarModal's `isEdit = !!props.initial`. */\n initial?: { key: string; displayName: string; description: string };\n /** Create mode only: the caller-minted `ep_…` id the POST carries. */\n newId?: string;\n /** Create mode only: keys already taken in this account — advisory pre-check. */\n takenKeys?: readonly string[];\n onClose: () => void;\n /** Create mode: the id the SERVER returned (`saved.endpoint.id`). */\n onCreated?: (id: string) => void;\n /** Edit mode: the patched identity fields. The modal itself writes NOTHING. */\n onSaved?: (next: { displayName: string; description: string }) => void;\n}) {\n const isEdit = !!props.initial;\n const [displayName, setDisplayName] = useState(props.initial?.displayName ?? \"\");\n const [key, setKey] = useState(props.initial?.key ?? \"\");\n const [description, setDescription] = useState(props.initial?.description ?? \"\");\n const [error, setError] = useState<string | null>(null);\n\n const saveMut = useSaveEndpointMutation();\n\n const keyTaken = !isEdit && key !== \"\" && (props.takenKeys ?? []).includes(key);\n const canSubmit = isEndpointKey(key) && !saveMut.isPending;\n\n function onNameBlur() {\n // The intake's own gate: \"on `name` blur, if the key is still empty, use\n // the name to generate it.\" — `!key`, not SignupPage's richer\n // `slugManual` latch (that richer behavior was not asked for here).\n if (key) return;\n const candidate = slugify(displayName);\n if (!candidate) return;\n setKey(candidate);\n }\n\n function submit() {\n setError(null);\n if (isEdit) {\n props.onSaved?.({ displayName: displayName.trim(), description });\n props.onClose();\n return;\n }\n saveMut.mutate(\n {\n manifestVersion: ENDPOINT_MANIFEST_VERSION,\n id: props.newId,\n key,\n displayName: displayName.trim(),\n description,\n // Deliberately NO `target` — this is the draft state (HITL-8): the\n // row is created, holds its `(account, key)` slot, and the operator\n // finishes it in the editor that opens next.\n },\n {\n onSuccess: (saved) => props.onCreated?.(saved.endpoint.id),\n onError: (e) => setError(e instanceof ApiError ? e.message : String(e)),\n },\n );\n }\n\n const enterSubmit = useEnterSubmit(submit, { enabled: canSubmit });\n\n return (\n <Modal title={isEdit ? \"Edit identity\" : \"New endpoint\"} onClose={props.onClose}>\n <div className=\"modal-body\">\n <div className=\"row field-row\">\n <label className=\"field\">\n <span>Name</span>\n <input\n type=\"text\"\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n onBlur={onNameBlur}\n placeholder=\"Notify Customer\"\n autoFocus\n {...enterSubmit}\n />\n </label>\n <label className=\"field\">\n <span>Key</span>\n <input\n type=\"text\"\n value={key}\n disabled={isEdit}\n onChange={(e) => setKey(e.target.value)}\n placeholder=\"notify-customer\"\n {...enterSubmit}\n />\n {!isEdit && (\n <span className=\"hint\">\n Lowercase, kebab-case, 3–39 characters. A public URL path segment — immutable after\n the first save.\n </span>\n )}\n {keyTaken && (\n <span className=\"hint\" data-testid=\"endpoint-key-taken\">\n Already in use in this account — the server has the final say.\n </span>\n )}\n </label>\n </div>\n\n <label className=\"field\">\n <span>Description</span>\n <input\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional\"\n {...enterSubmit}\n />\n </label>\n\n {error && <div className=\"result error\">{error}</div>}\n </div>\n\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n <button type=\"button\" className=\"btn\" disabled={!canSubmit} onClick={submit}>\n {saveMut.isPending ? \"Creating…\" : isEdit ? \"Save\" : \"Create\"}\n </button>\n </div>\n </Modal>\n );\n}\n\n/**\n * Creates an Endpoint: the identity modal in create mode, in its own `.w6w-embed-root`. The id is\n * minted once per mount. Without `takenKeys` the modal reads the account's keys itself\n * (`GET /endpoints`) for the advisory \"already in use\" hint; the server stays the arbiter.\n */\nexport function CreateEndpointModal(props: {\n onClose: () => void;\n /** The id the SERVER returned for the new Endpoint. */\n onCreated: (id: string) => void;\n /** Keys already taken in this account. Omitted: read from the Endpoints list. */\n takenKeys?: readonly string[];\n}) {\n const [newId] = useState(() => newCallableId(\"endpoint\"));\n const keys = useEndpointsQuery(props.takenKeys === undefined);\n return (\n <div className=\"w6w-embed-root\">\n <EndpointIdentityModal\n newId={newId}\n takenKeys={props.takenKeys ?? (keys.data ?? []).map((row) => row.key)}\n onClose={props.onClose}\n onCreated={props.onCreated}\n />\n </div>\n );\n}\n","import { ApiError } from \"@w6w/sdk\";\nimport { useEnterSubmit } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport { Modal } from \"../chrome/Modal.tsx\";\nimport { newCallableId } from \"../lib/callable-descriptors.ts\";\nimport { isEndpointKey, slugify } from \"../lib/slug.ts\";\nimport {\n FUNCTION_MANIFEST_VERSION,\n useFunctionsQuery,\n useSaveFunctionMutation,\n} from \"../repos/functions.ts\";\n\n/**\n * Identity modal shared by the Functions list (\"+ New function\" — create\n * mode) and the editor's read-only info block (\"edit\" icon-button — edit\n * mode). `isEdit = !!props.initial`, mirroring `VarModal` and\n * `EndpointIdentityModal`.\n *\n * **Create mode POSTs for real, right here — before any editor exists.**\n * That is this node's whole point: the row is created against the server\n * before the operator can put impl/input work into a plain `useState` that\n * used to die on a missing var, a lost tab, or anything else short of a\n * completed Save. Submit is disabled unless the key clears\n * {@link isEndpointKey} (reused — pin 2: the grammar is identical, so no\n * `isFunctionKey`); `takenKeys` (from the list's own `GET /functions`) is an\n * ADVISORY pre-check only — the account-scoped unique index is the arbiter,\n * and any refusal renders `ApiError.message` verbatim and leaves the modal\n * open with what was typed intact.\n *\n * **Edit mode writes NOTHING.** `POST /functions` is a whole-definition\n * upsert, so an identity-only PATCH here would silently wipe the impl and\n * inputs the editor already has saved — precisely the data loss this whole\n * node exists to stop. The patched fields go back through `onSaved`; the\n * editor's own `onSave()` stays the one path that ever persists them.\n */\nexport function FunctionIdentityModal(props: {\n /** Edit mode when present; create mode when absent. Mirrors VarModal's `isEdit = !!props.initial`. */\n initial?: { key: string; displayName: string; description: string };\n /** Create mode only: the caller-minted `fn_…` id the POST carries. */\n newId?: string;\n /** Create mode only: keys already taken in this account — advisory pre-check. */\n takenKeys?: readonly string[];\n onClose: () => void;\n /** Create mode: the id the SERVER returned (`saved.function.id`). */\n onCreated?: (id: string) => void;\n /** Edit mode: the patched identity fields. The modal itself writes NOTHING. */\n onSaved?: (next: { displayName: string; description: string }) => void;\n}) {\n const isEdit = !!props.initial;\n const [displayName, setDisplayName] = useState(props.initial?.displayName ?? \"\");\n const [key, setKey] = useState(props.initial?.key ?? \"\");\n const [description, setDescription] = useState(props.initial?.description ?? \"\");\n const [error, setError] = useState<string | null>(null);\n\n const saveMut = useSaveFunctionMutation();\n\n const keyTaken = !isEdit && key !== \"\" && (props.takenKeys ?? []).includes(key);\n // Pin 2: reuse `isEndpointKey` — the grammar is identical (kebab-case,\n // 3–39 chars, no `--` or trailing `-`), so a second `isFunctionKey` would\n // drift. Import it under its own name and note why right here.\n const canSubmit = isEndpointKey(key) && !saveMut.isPending;\n\n function onNameBlur() {\n // The intake's own gate: \"on `name` blur, if the key is still empty, use\n // the name to generate it.\" — `!key`, not SignupPage's richer\n // `slugManual` latch (that richer behavior was not asked for here).\n if (key) return;\n const candidate = slugify(displayName);\n if (!candidate) return;\n setKey(candidate);\n }\n\n function submit() {\n setError(null);\n if (isEdit) {\n props.onSaved?.({ displayName: displayName.trim(), description });\n props.onClose();\n return;\n }\n saveMut.mutate(\n {\n manifestVersion: FUNCTION_MANIFEST_VERSION,\n id: props.newId,\n key,\n displayName: displayName.trim(),\n description,\n inputs: [],\n // Deliberately NO `impl` — this is the draft state: the row is\n // created, holds its `(account, key)` slot, and the operator\n // finishes it in the editor that opens next.\n },\n {\n onSuccess: (saved: { id: string; key: string }) => props.onCreated?.(saved.id),\n onError: (e) => setError(e instanceof ApiError ? e.message : String(e)),\n },\n );\n }\n\n const enterSubmit = useEnterSubmit(submit, { enabled: canSubmit });\n\n return (\n <Modal title={isEdit ? \"Edit identity\" : \"New function\"} onClose={props.onClose}>\n <div className=\"modal-body\">\n <div className=\"row field-row\">\n <label className=\"field\">\n <span>Name</span>\n <input\n type=\"text\"\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n onBlur={onNameBlur}\n placeholder=\"Send Email\"\n autoFocus\n {...enterSubmit}\n />\n </label>\n <label className=\"field\">\n <span>Key</span>\n <input\n type=\"text\"\n value={key}\n disabled={isEdit}\n onChange={(e) => setKey(e.target.value)}\n placeholder=\"send-email\"\n {...enterSubmit}\n />\n {!isEdit && (\n <span className=\"hint\">\n Lowercase, kebab-case, 3–39 characters. A public URL path segment — immutable after\n the first save.\n </span>\n )}\n {keyTaken && (\n <span className=\"hint\" data-testid=\"function-key-taken\">\n Already in use in this account — the server has the final say.\n </span>\n )}\n </label>\n </div>\n\n <label className=\"field\">\n <span>Description</span>\n <input\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional\"\n {...enterSubmit}\n />\n </label>\n\n {error && <div className=\"result error\">{error}</div>}\n </div>\n\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n <button type=\"button\" className=\"btn\" disabled={!canSubmit} onClick={submit}>\n {saveMut.isPending ? \"Creating…\" : isEdit ? \"Save\" : \"Create\"}\n </button>\n </div>\n </Modal>\n );\n}\n\n/**\n * Creates a Function: the identity modal in create mode, in its own `.w6w-embed-root`. The id is\n * minted once per mount. Without `takenKeys` the modal reads the account's keys itself\n * (`GET /functions`) for the advisory \"already in use\" hint; the server stays the arbiter.\n */\nexport function CreateFunctionModal(props: {\n onClose: () => void;\n /** The id the SERVER returned for the new Function. */\n onCreated: (id: string) => void;\n /** Keys already taken in this account. Omitted: read from the Functions list. */\n takenKeys?: readonly string[];\n}) {\n const [newId] = useState(() => newCallableId(\"function\"));\n const keys = useFunctionsQuery(props.takenKeys === undefined);\n return (\n <div className=\"w6w-embed-root\">\n <FunctionIdentityModal\n newId={newId}\n takenKeys={props.takenKeys ?? (keys.data ?? []).map((row) => row.key)}\n onClose={props.onClose}\n onCreated={props.onCreated}\n />\n </div>\n );\n}\n"],"names":["EndpointIdentityModal","props","isEdit","displayName","setDisplayName","useState","_a","key","setKey","_b","description","setDescription","_c","error","setError","saveMut","useSaveEndpointMutation","keyTaken","canSubmit","isEndpointKey","onNameBlur","candidate","slugify","submit","ENDPOINT_MANIFEST_VERSION","saved","e","ApiError","enterSubmit","useEnterSubmit","jsxs","Modal","jsx","CreateEndpointModal","newId","newCallableId","keys","useEndpointsQuery","row","FunctionIdentityModal","useSaveFunctionMutation","FUNCTION_MANIFEST_VERSION","CreateFunctionModal","useFunctionsQuery"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateFunctionModal-DScxp_LN.js","sources":["../src/forms/CreateEndpointModal.tsx","../src/forms/CreateFunctionModal.tsx"],"sourcesContent":["import { ApiError } from \"@w6w/sdk\";\nimport { useEnterSubmit } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport { Modal } from \"../chrome/Modal.tsx\";\nimport { newCallableId } from \"../lib/callable-descriptors.ts\";\nimport { isEndpointKey, slugify } from \"../lib/slug.ts\";\nimport {\n ENDPOINT_MANIFEST_VERSION,\n useEndpointsQuery,\n useSaveEndpointMutation,\n} from \"../repos/endpoints.ts\";\n\n/**\n * Identity modal shared by the Endpoints list (\"+ New endpoint\" — create\n * mode) and the editor's read-only info block (\"edit\" icon-button — edit\n * mode). `isEdit = !!props.initial`, mirroring `VarModal` and `FunctionIdentityModal`.\n *\n * **Create mode POSTs for real, right here — before any editor exists.**\n * That is this node's whole point: the row is created against the server\n * before the operator can put target/input work into a plain `useState` that\n * used to die on a missing var, a lost tab, or anything else short of a\n * completed Save. Submit is disabled unless the key clears\n * {@link isEndpointKey}; `takenKeys` (from the list's own `GET /endpoints`)\n * is an ADVISORY pre-check only — the account-scoped unique index is the\n * arbiter, and any refusal (409 `endpoint_key_conflict`, 409\n * `key_immutable`, 400 `invalid_endpoint`) renders `ApiError.message`\n * verbatim and leaves the modal open with what was typed intact.\n *\n * **Edit mode writes NOTHING.** `POST /endpoints` is a whole-definition\n * upsert, so an identity-only PATCH here would silently wipe the target and\n * input the editor already has saved — precisely the data loss this whole\n * node exists to stop. The patched fields go back through `onSaved`; the\n * editor's own `onSave()` stays the one path that ever persists them.\n */\nexport function EndpointIdentityModal(props: {\n /** Edit mode when present; create mode when absent. Mirrors VarModal's `isEdit = !!props.initial`. */\n initial?: { key: string; displayName: string; description: string };\n /** Create mode only: the caller-minted `ep_…` id the POST carries. */\n newId?: string;\n /** Create mode only: keys already taken in this account — advisory pre-check. */\n takenKeys?: readonly string[];\n onClose: () => void;\n /** Create mode: the id the SERVER returned (`saved.endpoint.id`). */\n onCreated?: (id: string) => void;\n /** Edit mode: the patched identity fields. The modal itself writes NOTHING. */\n onSaved?: (next: { displayName: string; description: string }) => void;\n}) {\n const isEdit = !!props.initial;\n const [displayName, setDisplayName] = useState(props.initial?.displayName ?? \"\");\n const [key, setKey] = useState(props.initial?.key ?? \"\");\n const [description, setDescription] = useState(props.initial?.description ?? \"\");\n const [error, setError] = useState<string | null>(null);\n\n const saveMut = useSaveEndpointMutation();\n\n const keyTaken = !isEdit && key !== \"\" && (props.takenKeys ?? []).includes(key);\n const canSubmit = isEndpointKey(key) && !saveMut.isPending;\n\n function onNameBlur() {\n // The intake's own gate: \"on `name` blur, if the key is still empty, use\n // the name to generate it.\" — `!key`, not SignupPage's richer\n // `slugManual` latch (that richer behavior was not asked for here).\n if (key) return;\n const candidate = slugify(displayName);\n if (!candidate) return;\n setKey(candidate);\n }\n\n function submit() {\n setError(null);\n if (isEdit) {\n props.onSaved?.({ displayName: displayName.trim(), description });\n props.onClose();\n return;\n }\n saveMut.mutate(\n {\n manifestVersion: ENDPOINT_MANIFEST_VERSION,\n id: props.newId,\n key,\n displayName: displayName.trim(),\n description,\n // Deliberately NO `target` — this is the draft state (HITL-8): the\n // row is created, holds its `(account, key)` slot, and the operator\n // finishes it in the editor that opens next.\n },\n {\n onSuccess: (saved) => props.onCreated?.(saved.endpoint.id),\n onError: (e) => setError(e instanceof ApiError ? e.message : String(e)),\n },\n );\n }\n\n const enterSubmit = useEnterSubmit(submit, { enabled: canSubmit });\n\n return (\n <Modal title={isEdit ? \"Edit identity\" : \"New endpoint\"} onClose={props.onClose}>\n <div className=\"modal-body\">\n <div className=\"row field-row\">\n <label className=\"field\">\n <span>Name</span>\n <input\n type=\"text\"\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n onBlur={onNameBlur}\n placeholder=\"Notify Customer\"\n autoFocus\n {...enterSubmit}\n />\n </label>\n <label className=\"field\">\n <span>Key</span>\n <input\n type=\"text\"\n value={key}\n disabled={isEdit}\n onChange={(e) => setKey(e.target.value)}\n placeholder=\"notify-customer\"\n {...enterSubmit}\n />\n {!isEdit && (\n <span className=\"hint\">\n Lowercase, kebab-case, 3–39 characters. A public URL path segment — immutable after\n the first save.\n </span>\n )}\n {keyTaken && (\n <span className=\"hint\" data-testid=\"endpoint-key-taken\">\n Already in use in this account — the server has the final say.\n </span>\n )}\n </label>\n </div>\n\n <label className=\"field\">\n <span>Description</span>\n <input\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional\"\n {...enterSubmit}\n />\n </label>\n\n {error && <div className=\"result error\">{error}</div>}\n </div>\n\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n <button type=\"button\" className=\"btn\" disabled={!canSubmit} onClick={submit}>\n {saveMut.isPending ? \"Creating…\" : isEdit ? \"Save\" : \"Create\"}\n </button>\n </div>\n </Modal>\n );\n}\n\n/**\n * Creates an Endpoint: the identity modal in create mode, in its own `.w6w-embed-root`. The id is\n * minted once per mount. Without `takenKeys` the modal reads the account's keys itself\n * (`GET /endpoints`) for the advisory \"already in use\" hint; the server stays the arbiter.\n */\nexport function CreateEndpointModal(props: {\n onClose: () => void;\n /** The id the SERVER returned for the new Endpoint. */\n onCreated: (id: string) => void;\n /** Keys already taken in this account. Omitted: read from the Endpoints list. */\n takenKeys?: readonly string[];\n}) {\n const [newId] = useState(() => newCallableId(\"endpoint\"));\n const keys = useEndpointsQuery(props.takenKeys === undefined);\n return (\n <div className=\"w6w-embed-root\">\n <EndpointIdentityModal\n newId={newId}\n takenKeys={props.takenKeys ?? (keys.data ?? []).map((row) => row.key)}\n onClose={props.onClose}\n onCreated={props.onCreated}\n />\n </div>\n );\n}\n","import { ApiError } from \"@w6w/sdk\";\nimport { useEnterSubmit } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport { Modal } from \"../chrome/Modal.tsx\";\nimport { newCallableId } from \"../lib/callable-descriptors.ts\";\nimport { isEndpointKey, slugify } from \"../lib/slug.ts\";\nimport {\n FUNCTION_MANIFEST_VERSION,\n useFunctionsQuery,\n useSaveFunctionMutation,\n} from \"../repos/functions.ts\";\n\n/**\n * Identity modal shared by the Functions list (\"+ New function\" — create\n * mode) and the editor's read-only info block (\"edit\" icon-button — edit\n * mode). `isEdit = !!props.initial`, mirroring `VarModal` and\n * `EndpointIdentityModal`.\n *\n * **Create mode POSTs for real, right here — before any editor exists.**\n * That is this node's whole point: the row is created against the server\n * before the operator can put impl/input work into a plain `useState` that\n * used to die on a missing var, a lost tab, or anything else short of a\n * completed Save. Submit is disabled unless the key clears\n * {@link isEndpointKey} (reused — pin 2: the grammar is identical, so no\n * `isFunctionKey`); `takenKeys` (from the list's own `GET /functions`) is an\n * ADVISORY pre-check only — the account-scoped unique index is the arbiter,\n * and any refusal renders `ApiError.message` verbatim and leaves the modal\n * open with what was typed intact.\n *\n * **Edit mode writes NOTHING.** `POST /functions` is a whole-definition\n * upsert, so an identity-only PATCH here would silently wipe the impl and\n * inputs the editor already has saved — precisely the data loss this whole\n * node exists to stop. The patched fields go back through `onSaved`; the\n * editor's own `onSave()` stays the one path that ever persists them.\n */\nexport function FunctionIdentityModal(props: {\n /** Edit mode when present; create mode when absent. Mirrors VarModal's `isEdit = !!props.initial`. */\n initial?: { key: string; displayName: string; description: string };\n /** Create mode only: the caller-minted `fn_…` id the POST carries. */\n newId?: string;\n /** Create mode only: keys already taken in this account — advisory pre-check. */\n takenKeys?: readonly string[];\n onClose: () => void;\n /** Create mode: the id the SERVER returned (`saved.function.id`). */\n onCreated?: (id: string) => void;\n /** Edit mode: the patched identity fields. The modal itself writes NOTHING. */\n onSaved?: (next: { displayName: string; description: string }) => void;\n}) {\n const isEdit = !!props.initial;\n const [displayName, setDisplayName] = useState(props.initial?.displayName ?? \"\");\n const [key, setKey] = useState(props.initial?.key ?? \"\");\n const [description, setDescription] = useState(props.initial?.description ?? \"\");\n const [error, setError] = useState<string | null>(null);\n\n const saveMut = useSaveFunctionMutation();\n\n const keyTaken = !isEdit && key !== \"\" && (props.takenKeys ?? []).includes(key);\n // Pin 2: reuse `isEndpointKey` — the grammar is identical (kebab-case,\n // 3–39 chars, no `--` or trailing `-`), so a second `isFunctionKey` would\n // drift. Import it under its own name and note why right here.\n const canSubmit = isEndpointKey(key) && !saveMut.isPending;\n\n function onNameBlur() {\n // The intake's own gate: \"on `name` blur, if the key is still empty, use\n // the name to generate it.\" — `!key`, not SignupPage's richer\n // `slugManual` latch (that richer behavior was not asked for here).\n if (key) return;\n const candidate = slugify(displayName);\n if (!candidate) return;\n setKey(candidate);\n }\n\n function submit() {\n setError(null);\n if (isEdit) {\n props.onSaved?.({ displayName: displayName.trim(), description });\n props.onClose();\n return;\n }\n saveMut.mutate(\n {\n manifestVersion: FUNCTION_MANIFEST_VERSION,\n id: props.newId,\n key,\n displayName: displayName.trim(),\n description,\n inputs: [],\n // Deliberately NO `impl` — this is the draft state: the row is\n // created, holds its `(account, key)` slot, and the operator\n // finishes it in the editor that opens next.\n },\n {\n onSuccess: (saved: { id: string; key: string }) => props.onCreated?.(saved.id),\n onError: (e) => setError(e instanceof ApiError ? e.message : String(e)),\n },\n );\n }\n\n const enterSubmit = useEnterSubmit(submit, { enabled: canSubmit });\n\n return (\n <Modal title={isEdit ? \"Edit identity\" : \"New function\"} onClose={props.onClose}>\n <div className=\"modal-body\">\n <div className=\"row field-row\">\n <label className=\"field\">\n <span>Name</span>\n <input\n type=\"text\"\n value={displayName}\n onChange={(e) => setDisplayName(e.target.value)}\n onBlur={onNameBlur}\n placeholder=\"Send Email\"\n autoFocus\n {...enterSubmit}\n />\n </label>\n <label className=\"field\">\n <span>Key</span>\n <input\n type=\"text\"\n value={key}\n disabled={isEdit}\n onChange={(e) => setKey(e.target.value)}\n placeholder=\"send-email\"\n {...enterSubmit}\n />\n {!isEdit && (\n <span className=\"hint\">\n Lowercase, kebab-case, 3–39 characters. A public URL path segment — immutable after\n the first save.\n </span>\n )}\n {keyTaken && (\n <span className=\"hint\" data-testid=\"function-key-taken\">\n Already in use in this account — the server has the final say.\n </span>\n )}\n </label>\n </div>\n\n <label className=\"field\">\n <span>Description</span>\n <input\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional\"\n {...enterSubmit}\n />\n </label>\n\n {error && <div className=\"result error\">{error}</div>}\n </div>\n\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n <button type=\"button\" className=\"btn\" disabled={!canSubmit} onClick={submit}>\n {saveMut.isPending ? \"Creating…\" : isEdit ? \"Save\" : \"Create\"}\n </button>\n </div>\n </Modal>\n );\n}\n\n/**\n * Creates a Function: the identity modal in create mode, in its own `.w6w-embed-root`. The id is\n * minted once per mount. Without `takenKeys` the modal reads the account's keys itself\n * (`GET /functions`) for the advisory \"already in use\" hint; the server stays the arbiter.\n */\nexport function CreateFunctionModal(props: {\n onClose: () => void;\n /** The id the SERVER returned for the new Function. */\n onCreated: (id: string) => void;\n /** Keys already taken in this account. Omitted: read from the Functions list. */\n takenKeys?: readonly string[];\n}) {\n const [newId] = useState(() => newCallableId(\"function\"));\n const keys = useFunctionsQuery(props.takenKeys === undefined);\n return (\n <div className=\"w6w-embed-root\">\n <FunctionIdentityModal\n newId={newId}\n takenKeys={props.takenKeys ?? (keys.data ?? []).map((row) => row.key)}\n onClose={props.onClose}\n onCreated={props.onCreated}\n />\n </div>\n );\n}\n"],"names":["EndpointIdentityModal","props","isEdit","displayName","setDisplayName","useState","_a","key","setKey","_b","description","setDescription","_c","error","setError","saveMut","useSaveEndpointMutation","keyTaken","canSubmit","isEndpointKey","onNameBlur","candidate","slugify","submit","ENDPOINT_MANIFEST_VERSION","saved","e","ApiError","enterSubmit","useEnterSubmit","jsxs","Modal","jsx","CreateEndpointModal","newId","newCallableId","keys","useEndpointsQuery","row","FunctionIdentityModal","useSaveFunctionMutation","FUNCTION_MANIFEST_VERSION","CreateFunctionModal","useFunctionsQuery"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { jsxs as a, jsx as t } from "react/jsx-runtime";
|
|
|
2
2
|
import { ApiError as k } from "@w6w/sdk";
|
|
3
3
|
import { useEnterSubmit as x, JsonEditor as D, YamlEditor as A, CodeEditor as F } from "@w6w/ui";
|
|
4
4
|
import { useState as o } from "react";
|
|
5
|
-
import { M as w } from "./ConfirmModal-
|
|
6
|
-
import { u as K, a as O } from "./spec-import-
|
|
5
|
+
import { M as w } from "./ConfirmModal-Pv2-A_3U.js";
|
|
6
|
+
import { u as K, a as O } from "./spec-import-SWOonsNr.js";
|
|
7
7
|
const P = ["text", "markdown", "yaml", "html", "json"];
|
|
8
8
|
function $(e) {
|
|
9
9
|
var y, N, j, p;
|
|
@@ -86,4 +86,4 @@ function $(e) {
|
|
|
86
86
|
export {
|
|
87
87
|
$ as D
|
|
88
88
|
};
|
|
89
|
-
//# sourceMappingURL=DocumentFormModal-
|
|
89
|
+
//# sourceMappingURL=DocumentFormModal-Br4s8wmi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentFormModal-
|
|
1
|
+
{"version":3,"file":"DocumentFormModal-Br4s8wmi.js","sources":["../src/forms/DocumentFormModal.tsx"],"sourcesContent":["/**\n * Create/edit modal for a document (internal: not exported from `@w6w/embed/forms`). Content is\n * stored verbatim in whatever format is selected, with no parsing or validation. The key is\n * immutable once set, so an edit never sends it.\n */\nimport { ApiError } from \"@w6w/sdk\";\nimport type { Doc, DocFormat } from \"@w6w/sdk\";\nimport { CodeEditor, JsonEditor, YamlEditor, useEnterSubmit } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport { Modal } from \"../chrome/Modal.tsx\";\nimport { useCreateDocumentMutation, useUpdateDocumentMutation } from \"../repos/documents.ts\";\n\nconst FORMATS: readonly DocFormat[] = [\"text\", \"markdown\", \"yaml\", \"html\", \"json\"];\n\nexport function DocumentFormModal(props: {\n initial?: Doc;\n /** The resolved project, or `null` (none yet): a save is refused, never sent project-less. */\n project: string | null;\n onClose: () => void;\n onSaved: () => void;\n}) {\n const isEdit = !!props.initial;\n const [key, setKey] = useState(props.initial?.key ?? \"\");\n const [format, setFormat] = useState<DocFormat>(props.initial?.format ?? \"text\");\n const [content, setContent] = useState(props.initial?.content ?? \"\");\n const [description, setDescription] = useState(props.initial?.description ?? \"\");\n const [error, setError] = useState<string | null>(null);\n\n const createMut = useCreateDocumentMutation();\n const updateMut = useUpdateDocumentMutation();\n const saving = createMut.isPending || updateMut.isPending;\n\n function save() {\n setError(null);\n if (props.project == null) {\n setError(\"No project selected: nothing was saved.\");\n return;\n }\n const onSettled = {\n onSuccess: () => props.onSaved(),\n onError: (e: unknown) => setError(e instanceof ApiError ? e.message : (e as Error).message),\n };\n if (props.initial) {\n updateMut.mutate(\n { id: props.initial.id, patch: { content, format, description }, project: props.project },\n onSettled,\n );\n return;\n }\n createMut.mutate(\n { input: { key: key.trim(), content, format, description }, project: props.project },\n onSettled,\n );\n }\n\n const enterSubmit = useEnterSubmit(save, { enabled: !!key.trim() && !saving });\n\n return (\n <Modal\n title={props.initial ? `Edit ${props.initial.key}` : \"Add document\"}\n onClose={props.onClose}\n >\n <div className=\"modal-body\">\n <label className=\"field\">\n <span>Key</span>\n <input\n type=\"text\"\n value={key}\n disabled={isEdit}\n onChange={(e) => setKey(e.target.value)}\n placeholder=\"e.g. welcome-email\"\n {...enterSubmit}\n />\n {!isEdit && <span className=\"hint\">A unique name to reference this document by.</span>}\n </label>\n\n <label className=\"field\">\n <span>Format</span>\n <select value={format} onChange={(e) => setFormat(e.target.value as DocFormat)}>\n {FORMATS.map((f) => (\n <option key={f} value={f}>\n {f}\n </option>\n ))}\n </select>\n </label>\n\n {/* A `div`, not a `label`: none of JsonEditor/YamlEditor/CodeEditor render a native\n control for a label to name; each carries its own `aria-label` instead. */}\n <div className=\"field\">\n <span>Content</span>\n {format === \"json\" ? (\n <JsonEditor value={content} onChange={setContent} aria-label=\"Content\" />\n ) : format === \"yaml\" ? (\n <YamlEditor value={content} onChange={setContent} aria-label=\"Content\" />\n ) : (\n <CodeEditor value={content} onChange={setContent} aria-label=\"Content\" />\n )}\n </div>\n\n <label className=\"field\">\n <span>Description</span>\n <input\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Optional\"\n {...enterSubmit}\n />\n </label>\n\n {error && <div className=\"result error\">{error}</div>}\n </div>\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n <button type=\"button\" className=\"btn\" disabled={!key.trim() || saving} onClick={save}>\n {saving ? \"Saving…\" : isEdit ? \"Save changes\" : \"Save document\"}\n </button>\n </div>\n </Modal>\n );\n}\n"],"names":["FORMATS","DocumentFormModal","props","isEdit","key","setKey","useState","_a","format","setFormat","_b","content","setContent","_c","description","setDescription","_d","error","setError","createMut","useCreateDocumentMutation","updateMut","useUpdateDocumentMutation","saving","save","onSettled","e","ApiError","enterSubmit","useEnterSubmit","jsxs","Modal","jsx","f","JsonEditor","YamlEditor","CodeEditor"],"mappings":"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"}
|