@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
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { jsxs as i, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { p as R, g as F, j as x, w as L, k as D, s as J, b as U, t as B } from "./import-bindings-EUtxZ9Ti.js";
|
|
3
|
+
import { ApiError as I } from "@w6w/sdk";
|
|
4
|
+
import { JsonEditor as G, AddConnectionModal as H } from "@w6w/ui";
|
|
5
|
+
import { useState as p } from "react";
|
|
6
|
+
import { b as K, c as V } from "./spec-import-SWOonsNr.js";
|
|
7
|
+
import { M as q } from "./ConfirmModal-Pv2-A_3U.js";
|
|
8
|
+
const z = {
|
|
9
|
+
function: "functions",
|
|
10
|
+
endpoint: "endpoints",
|
|
11
|
+
workflow: "workflows"
|
|
12
|
+
}, Q = {
|
|
13
|
+
function: {
|
|
14
|
+
json: "functions-import-json",
|
|
15
|
+
submit: "functions-import-submit",
|
|
16
|
+
unresolved: "functions-import-unresolved",
|
|
17
|
+
goto: "functions-import-goto"
|
|
18
|
+
},
|
|
19
|
+
endpoint: {
|
|
20
|
+
json: "endpoints-import-json",
|
|
21
|
+
submit: "endpoints-import-submit",
|
|
22
|
+
unresolved: "endpoints-import-unresolved",
|
|
23
|
+
goto: "endpoints-import-goto"
|
|
24
|
+
},
|
|
25
|
+
workflow: {
|
|
26
|
+
json: "workflows-import-json",
|
|
27
|
+
submit: "workflows-import-submit",
|
|
28
|
+
unresolved: "workflows-import-unresolved",
|
|
29
|
+
goto: "workflows-import-goto"
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function te(a) {
|
|
33
|
+
const { kind: s } = a, d = z[s], f = Q[s], [v, P] = p(""), [N, r] = p(null), [m, k] = p(null), [l, c] = p(null), [C, y] = p(null), h = K(a.project, a.listKeys), b = V(a.project), { parsed: g, blockedReason: u } = R(v, s), j = l !== null, w = !j || !F(l) || u !== null || h.isPending;
|
|
34
|
+
function S(e) {
|
|
35
|
+
P(e), k(null), r(null), c(null);
|
|
36
|
+
}
|
|
37
|
+
function E() {
|
|
38
|
+
u !== null || g === null || b.isPending || (r(null), b.mutate(g, {
|
|
39
|
+
onSuccess: (e) => c(U(e.dependencies)),
|
|
40
|
+
onError: (e) => {
|
|
41
|
+
c(null), r(e instanceof I ? e.message : String(e));
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
function M(e) {
|
|
46
|
+
e && e.text().then(S, (n) => r(String(n)));
|
|
47
|
+
}
|
|
48
|
+
function $(e) {
|
|
49
|
+
a.onClose(), a.onOpenImported(s, e);
|
|
50
|
+
}
|
|
51
|
+
function T() {
|
|
52
|
+
l === null || u !== null || g === null || h.isPending || (r(null), k(null), h.mutate(
|
|
53
|
+
{ document: g, selections: B(l) },
|
|
54
|
+
{
|
|
55
|
+
onSuccess: (e) => {
|
|
56
|
+
if (e.references.every((o) => o.resolved)) {
|
|
57
|
+
$(e.callable.id);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
k({
|
|
61
|
+
callableId: e.callable.id,
|
|
62
|
+
references: e.references.filter((o) => !o.resolved)
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
onError: (e) => r(e instanceof I ? e.message : String(e))
|
|
66
|
+
}
|
|
67
|
+
));
|
|
68
|
+
}
|
|
69
|
+
function A(e) {
|
|
70
|
+
const n = e.selection;
|
|
71
|
+
return n.mode === "bind" ? `bind:${n.target}` : n.mode;
|
|
72
|
+
}
|
|
73
|
+
function O(e, n) {
|
|
74
|
+
c((o) => o && (n === "unconfigured" ? D(o, e.key) : n === "create" ? x(o, e.key, e.createName) : J(o, e.key, n.slice(5))));
|
|
75
|
+
}
|
|
76
|
+
return /* @__PURE__ */ i(q, { title: `Import ${s}`, onClose: a.onClose, wide: !0, children: [
|
|
77
|
+
/* @__PURE__ */ i("div", { className: "modal-body", children: [
|
|
78
|
+
/* @__PURE__ */ i("p", { className: "muted small", children: [
|
|
79
|
+
"Paste a portable ",
|
|
80
|
+
s,
|
|
81
|
+
" spec document (exported via",
|
|
82
|
+
" ",
|
|
83
|
+
/* @__PURE__ */ i("code", { children: [
|
|
84
|
+
"GET /",
|
|
85
|
+
d,
|
|
86
|
+
"/:id/spec"
|
|
87
|
+
] }),
|
|
88
|
+
"). A fresh id is minted here; connection references are re-bound to whatever this account already has connected, and anything that couldn't be re-bound is reported below."
|
|
89
|
+
] }),
|
|
90
|
+
/* @__PURE__ */ t("div", { "data-testid": f.json, children: /* @__PURE__ */ t(
|
|
91
|
+
G,
|
|
92
|
+
{
|
|
93
|
+
value: v,
|
|
94
|
+
onChange: S,
|
|
95
|
+
minHeight: "320px",
|
|
96
|
+
"aria-label": `${s} spec document JSON`
|
|
97
|
+
}
|
|
98
|
+
) }),
|
|
99
|
+
/* @__PURE__ */ i("label", { className: "muted small", children: [
|
|
100
|
+
"Or choose a ",
|
|
101
|
+
/* @__PURE__ */ t("code", { children: ".json" }),
|
|
102
|
+
" file:",
|
|
103
|
+
" ",
|
|
104
|
+
/* @__PURE__ */ t(
|
|
105
|
+
"input",
|
|
106
|
+
{
|
|
107
|
+
type: "file",
|
|
108
|
+
accept: ".json,application/json",
|
|
109
|
+
"data-testid": `${d}-import-file`,
|
|
110
|
+
onChange: (e) => {
|
|
111
|
+
var n;
|
|
112
|
+
return M((n = e.target.files) == null ? void 0 : n[0]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] }),
|
|
117
|
+
u && v !== "" && /* @__PURE__ */ t("p", { className: "muted small", children: u }),
|
|
118
|
+
N && /* @__PURE__ */ t("div", { className: "result error", children: N }),
|
|
119
|
+
l && l.length === 0 && /* @__PURE__ */ i("p", { className: "muted small", "data-testid": `${d}-import-nodeps`, children: [
|
|
120
|
+
"This ",
|
|
121
|
+
s,
|
|
122
|
+
" has no dependencies."
|
|
123
|
+
] }),
|
|
124
|
+
l && l.length > 0 && /* @__PURE__ */ t("ul", { className: "list", "data-testid": `${d}-import-rows`, children: l.map((e) => /* @__PURE__ */ i("li", { "data-testid": `${d}-import-row-${e.key}`, children: [
|
|
125
|
+
/* @__PURE__ */ t("code", { children: e.dep.name }),
|
|
126
|
+
" ",
|
|
127
|
+
/* @__PURE__ */ i("span", { className: "muted", children: [
|
|
128
|
+
"(",
|
|
129
|
+
e.dep.kind,
|
|
130
|
+
")"
|
|
131
|
+
] }),
|
|
132
|
+
" ",
|
|
133
|
+
e.dep.dynamic ? /* @__PURE__ */ t("span", { className: "muted small", children: "Dynamic store name — configure it manually after import." }) : null,
|
|
134
|
+
/* @__PURE__ */ i(
|
|
135
|
+
"select",
|
|
136
|
+
{
|
|
137
|
+
value: A(e),
|
|
138
|
+
onChange: (n) => O(e, n.target.value),
|
|
139
|
+
"aria-label": `Configure ${e.dep.name}`,
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ t("option", { value: "unconfigured", children: "Leave unconfigured" }),
|
|
142
|
+
!e.dep.dynamic && e.options.map((n) => /* @__PURE__ */ i(
|
|
143
|
+
"option",
|
|
144
|
+
{
|
|
145
|
+
value: `bind:${n.id}`,
|
|
146
|
+
disabled: n.compatible === !1,
|
|
147
|
+
title: n.reason,
|
|
148
|
+
children: [
|
|
149
|
+
n.label,
|
|
150
|
+
n.compatible === !1 && n.reason ? ` — ${n.reason}` : ""
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
n.id
|
|
154
|
+
)),
|
|
155
|
+
e.dep.kind === "store" && e.dep.canCreate && !e.dep.dynamic && /* @__PURE__ */ t("option", { value: "create", children: "Create new" })
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
e.selection.mode === "create" && /* @__PURE__ */ t(
|
|
160
|
+
"input",
|
|
161
|
+
{
|
|
162
|
+
type: "text",
|
|
163
|
+
value: e.selection.name,
|
|
164
|
+
"aria-label": `New name for ${e.dep.name}`,
|
|
165
|
+
onChange: (n) => c((o) => o && x(o, e.key, n.target.value))
|
|
166
|
+
}
|
|
167
|
+
),
|
|
168
|
+
e.dep.kind === "connection" && e.dep.app && /* @__PURE__ */ t("button", { type: "button", className: "btn ghost", onClick: () => y(e), children: "Add connection" })
|
|
169
|
+
] }, e.key)) }),
|
|
170
|
+
C && /* @__PURE__ */ t(
|
|
171
|
+
H,
|
|
172
|
+
{
|
|
173
|
+
initialAppId: C.dep.app,
|
|
174
|
+
onClose: () => y(null),
|
|
175
|
+
onCreated: ({ connectionId: e }) => {
|
|
176
|
+
const n = C.key;
|
|
177
|
+
c(
|
|
178
|
+
(o) => o && L(o, n, e, e)
|
|
179
|
+
), y(null);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
m && /* @__PURE__ */ i("div", { className: "result", "data-testid": f.unresolved, children: [
|
|
184
|
+
/* @__PURE__ */ i("p", { children: [
|
|
185
|
+
"The ",
|
|
186
|
+
s,
|
|
187
|
+
" was created, but ",
|
|
188
|
+
m.references.length,
|
|
189
|
+
" reference",
|
|
190
|
+
m.references.length === 1 ? "" : "s",
|
|
191
|
+
" could not be resolved:"
|
|
192
|
+
] }),
|
|
193
|
+
/* @__PURE__ */ t("ul", { className: "list", children: m.references.map((e) => /* @__PURE__ */ i("li", { children: [
|
|
194
|
+
/* @__PURE__ */ t("code", { children: e.path }),
|
|
195
|
+
" ",
|
|
196
|
+
/* @__PURE__ */ i("span", { className: "muted", children: [
|
|
197
|
+
"(",
|
|
198
|
+
e.kind,
|
|
199
|
+
")"
|
|
200
|
+
] }),
|
|
201
|
+
e.reason && /* @__PURE__ */ i("span", { className: "muted", children: [
|
|
202
|
+
" — ",
|
|
203
|
+
e.reason
|
|
204
|
+
] })
|
|
205
|
+
] }, e.path)) }),
|
|
206
|
+
/* @__PURE__ */ i(
|
|
207
|
+
"button",
|
|
208
|
+
{
|
|
209
|
+
type: "button",
|
|
210
|
+
className: "btn",
|
|
211
|
+
"data-testid": f.goto,
|
|
212
|
+
onClick: () => $(m.callableId),
|
|
213
|
+
children: [
|
|
214
|
+
"Open the created ",
|
|
215
|
+
s
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
] })
|
|
220
|
+
] }),
|
|
221
|
+
/* @__PURE__ */ i("div", { className: "modal-actions", children: [
|
|
222
|
+
/* @__PURE__ */ t("button", { type: "button", className: "btn ghost", onClick: a.onClose, children: "Cancel" }),
|
|
223
|
+
!j && /* @__PURE__ */ t(
|
|
224
|
+
"button",
|
|
225
|
+
{
|
|
226
|
+
type: "button",
|
|
227
|
+
className: "btn",
|
|
228
|
+
"data-testid": `${d}-import-next`,
|
|
229
|
+
disabled: u !== null || b.isPending,
|
|
230
|
+
onClick: E,
|
|
231
|
+
children: b.isPending ? "Checking…" : "Next"
|
|
232
|
+
}
|
|
233
|
+
),
|
|
234
|
+
/* @__PURE__ */ t(
|
|
235
|
+
"button",
|
|
236
|
+
{
|
|
237
|
+
type: "button",
|
|
238
|
+
className: "btn",
|
|
239
|
+
"data-testid": f.submit,
|
|
240
|
+
disabled: w,
|
|
241
|
+
onClick: T,
|
|
242
|
+
children: h.isPending ? "Importing…" : "Create"
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
] })
|
|
246
|
+
] });
|
|
247
|
+
}
|
|
248
|
+
export {
|
|
249
|
+
te as I
|
|
250
|
+
};
|
|
251
|
+
//# sourceMappingURL=ImportSpecModal-Cpzp8ndt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImportSpecModal-Cpzp8ndt.js","sources":["../src/chrome/ImportSpecModal.tsx"],"sourcesContent":["import {\n type ImportRow,\n type SpecImportKind,\n type SpecImportListKeys,\n buildRows,\n parseImportPaste,\n rowsReady,\n setBind,\n setCreateName,\n setUnconfigured,\n toSelections,\n withCreatedConnection,\n} from \"@w6w/embed/lib\";\nimport { ApiError } from \"@w6w/sdk\";\nimport { AddConnectionModal, JsonEditor } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport {\n type SpecImportReferenceReport,\n useImportSpecMutation,\n useSpecPreviewMutation,\n} from \"../repos/spec-import.ts\";\nimport { Modal } from \"./Modal.tsx\";\n\n/** The list route segment for each kind — `goto()`'s `<collection>/<id>` nav target. */\nconst COLLECTION: Record<SpecImportKind, \"functions\" | \"endpoints\" | \"workflows\"> = {\n function: \"functions\",\n endpoint: \"endpoints\",\n workflow: \"workflows\",\n};\n\n/**\n * P2's `<collection>-import-*` testid scheme, spelled out literally per kind rather than built by\n * string interpolation — so the Functions arm's four testids stay the exact byte strings\n * `functions-page-guards.test.cjs` (IM1–IM3) already asserts against, verifiable by a plain\n * substring search over this file rather than only by running the browser suite.\n */\nconst TESTIDS: Record<\n SpecImportKind,\n { json: string; submit: string; unresolved: string; goto: string }\n> = {\n function: {\n json: \"functions-import-json\",\n submit: \"functions-import-submit\",\n unresolved: \"functions-import-unresolved\",\n goto: \"functions-import-goto\",\n },\n endpoint: {\n json: \"endpoints-import-json\",\n submit: \"endpoints-import-submit\",\n unresolved: \"endpoints-import-unresolved\",\n goto: \"endpoints-import-goto\",\n },\n workflow: {\n json: \"workflows-import-json\",\n submit: \"workflows-import-submit\",\n unresolved: \"workflows-import-unresolved\",\n goto: \"workflows-import-goto\",\n },\n};\n\n/**\n * Import modal for the Functions, Endpoints and Workflows lists (T1.2.1, generalizing T3.2.1's\n * Functions-only `ImportFunctionModal`): paste a portable spec document (rfcs/function.md), POST\n * it to `/spec/import` and either land in the created resource's editor (every reference resolved)\n * or stay open with the unresolved-reference report (A5).\n *\n * **P1 — one parameterized component, not three.** The Function-specific surface was four strings,\n * one nav target and a testid prefix — forking it into three siblings would duplicate the state\n * machine below for no gain. The `kind` prop drives all of it: `parseImportPaste`'s expected kind,\n * the title/copy, the `goto()` navigation target (`<collection>/<id>`), and every testid (P2 — the\n * four `functions-import-*` ones this file used to hardcode keep matching byte-for-byte; see\n * `TESTIDS` above for why they are spelled out literally per kind rather than interpolated).\n *\n * Mirrors `FunctionIdentityModal.tsx` (note 3 — same studio-local `Modal`,\n * same `ApiError.message` handling, same \"the row was created, hand the\n * operator the id\" shape as `onCreated`) but is a structurally PARALLEL,\n * distinct trigger — not a second \"create a resource and land in its editor\"\n * flow built on top of it. It owns its own navigation (unlike the identity\n * modal, which reports back to the list) because A5's \"created but\n * partially resolved\" outcome has nowhere else to render the report: the\n * modal has to stay mounted to show it, so it is also the one place that can\n * decide whether and when to leave the list route.\n *\n * **A `201` whose `references` carry any `resolved: false` entry is NOT\n * \"done\" (A5)** — the near-miss this exists to kill is \"201 ⇒ close and\n * navigate\", which would hide exactly the unresolved-reference report the\n * intake asks for.\n */\nexport interface ImportSpecModalProps {\n kind: SpecImportKind;\n /** The host's current project (only the workflow list key reads it). */\n project: string | undefined;\n /** The three list query keys, injected by the host. */\n listKeys: SpecImportListKeys;\n /** Navigate to the imported row; the modal closes itself first. */\n onOpenImported: (kind: SpecImportKind, id: string) => void;\n onClose: () => void;\n}\n\nexport function ImportSpecModal(props: ImportSpecModalProps) {\n const { kind } = props;\n const collection = COLLECTION[kind];\n const testids = TESTIDS[kind];\n const [text, setText] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [unresolved, setUnresolved] = useState<{\n callableId: string;\n references: SpecImportReferenceReport[];\n } | null>(null);\n // Two steps: \"paste\" (parse → explicit Next → ONE preview request) then \"configure\" (rows).\n const [rows, setRows] = useState<ImportRow[] | null>(null);\n const [addingFor, setAddingFor] = useState<ImportRow | null>(null);\n const importMut = useImportSpecMutation(props.project, props.listKeys);\n const previewMut = useSpecPreviewMutation(props.project);\n\n const { parsed, blockedReason } = parseImportPaste(text, kind);\n const configuring = rows !== null;\n // Create is enabled ONLY after a successful preview (never a verbatim post).\n const disabled =\n !configuring || !rowsReady(rows) || blockedReason !== null || importMut.isPending;\n\n function edit(next: string) {\n setText(next);\n setUnresolved(null);\n setError(null);\n setRows(null);\n }\n\n function next() {\n if (blockedReason !== null || parsed === null || previewMut.isPending) return;\n setError(null);\n previewMut.mutate(parsed as Record<string, unknown>, {\n onSuccess: (res) => setRows(buildRows(res.dependencies)),\n onError: (e) => {\n setRows(null);\n setError(e instanceof ApiError ? e.message : String(e));\n },\n });\n }\n\n function onFile(file: File | undefined) {\n if (!file) return;\n file.text().then(edit, (e) => setError(String(e)));\n }\n\n function goto(id: string) {\n props.onClose();\n props.onOpenImported(kind, id);\n }\n\n function submit() {\n // Defensive, not decorative: a forced click (e.g. `dispatchEvent`) on a\n // disabled button must still issue zero requests (A3, IM1(a)/(b)).\n if (rows === null || blockedReason !== null || parsed === null || importMut.isPending) return;\n setError(null);\n setUnresolved(null);\n // The parsed paste plus EVERY row's selection (`unconfigured` included).\n importMut.mutate(\n { document: parsed as Record<string, unknown>, selections: toSelections(rows) },\n {\n onSuccess: (result) => {\n const allResolved = result.references.every((r) => r.resolved);\n if (allResolved) {\n goto(result.callable.id);\n return;\n }\n // Kept open (A5): the resource WAS created, but at least one\n // reference did not bind — report every unresolved entry, and give\n // the operator an explicit way to still reach the row.\n setUnresolved({\n callableId: result.callable.id,\n references: result.references.filter((r) => !r.resolved),\n });\n },\n onError: (e) => setError(e instanceof ApiError ? e.message : String(e)),\n },\n );\n }\n\n function selectValue(row: ImportRow): string {\n const s = row.selection;\n return s.mode === \"bind\" ? `bind:${s.target}` : s.mode;\n }\n\n function onPick(row: ImportRow, value: string) {\n setRows((cur) => {\n if (!cur) return cur;\n if (value === \"unconfigured\") return setUnconfigured(cur, row.key);\n if (value === \"create\") return setCreateName(cur, row.key, row.createName);\n return setBind(cur, row.key, value.slice(\"bind:\".length));\n });\n }\n\n return (\n <Modal title={`Import ${kind}`} onClose={props.onClose} wide>\n <div className=\"modal-body\">\n <p className=\"muted small\">\n Paste a portable {kind} spec document (exported via{\" \"}\n <code>GET /{collection}/:id/spec</code>\n ). A fresh id is minted here; connection references are re-bound to whatever this account\n already has connected, and anything that couldn't be re-bound is reported below.\n </p>\n\n <div data-testid={testids.json}>\n <JsonEditor\n value={text}\n onChange={edit}\n minHeight=\"320px\"\n aria-label={`${kind} spec document JSON`}\n />\n </div>\n\n <label className=\"muted small\">\n Or choose a <code>.json</code> file:{\" \"}\n <input\n type=\"file\"\n accept=\".json,application/json\"\n data-testid={`${collection}-import-file`}\n onChange={(e) => onFile(e.target.files?.[0])}\n />\n </label>\n\n {blockedReason && text !== \"\" && <p className=\"muted small\">{blockedReason}</p>}\n {error && <div className=\"result error\">{error}</div>}\n\n {rows && rows.length === 0 && (\n <p className=\"muted small\" data-testid={`${collection}-import-nodeps`}>\n This {kind} has no dependencies.\n </p>\n )}\n {rows && rows.length > 0 && (\n <ul className=\"list\" data-testid={`${collection}-import-rows`}>\n {rows.map((row) => (\n <li key={row.key} data-testid={`${collection}-import-row-${row.key}`}>\n <code>{row.dep.name}</code> <span className=\"muted\">({row.dep.kind})</span>{\" \"}\n {row.dep.dynamic ? (\n <span className=\"muted small\">\n Dynamic store name — configure it manually after import.\n </span>\n ) : null}\n <select\n value={selectValue(row)}\n onChange={(e) => onPick(row, e.target.value)}\n aria-label={`Configure ${row.dep.name}`}\n >\n <option value=\"unconfigured\">Leave unconfigured</option>\n {!row.dep.dynamic &&\n row.options.map((o) => (\n <option\n key={o.id}\n value={`bind:${o.id}`}\n disabled={o.compatible === false}\n title={o.reason}\n >\n {o.label}\n {o.compatible === false && o.reason ? ` — ${o.reason}` : \"\"}\n </option>\n ))}\n {row.dep.kind === \"store\" && row.dep.canCreate && !row.dep.dynamic && (\n <option value=\"create\">Create new</option>\n )}\n </select>\n {row.selection.mode === \"create\" && (\n <input\n type=\"text\"\n value={row.selection.name}\n aria-label={`New name for ${row.dep.name}`}\n onChange={(e) =>\n setRows((cur) => (cur ? setCreateName(cur, row.key, e.target.value) : cur))\n }\n />\n )}\n {row.dep.kind === \"connection\" && row.dep.app && (\n <button type=\"button\" className=\"btn ghost\" onClick={() => setAddingFor(row)}>\n Add connection\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n {addingFor && (\n <AddConnectionModal\n initialAppId={addingFor.dep.app}\n onClose={() => setAddingFor(null)}\n onCreated={({ connectionId }) => {\n // Append the new connection as an option and bind the row to it (no re-preview).\n const key = addingFor.key;\n setRows((cur) =>\n cur ? withCreatedConnection(cur, key, connectionId, connectionId) : cur,\n );\n setAddingFor(null);\n }}\n />\n )}\n\n {unresolved && (\n <div className=\"result\" data-testid={testids.unresolved}>\n <p>\n The {kind} was created, but {unresolved.references.length} reference\n {unresolved.references.length === 1 ? \"\" : \"s\"} could not be resolved:\n </p>\n <ul className=\"list\">\n {unresolved.references.map((r) => (\n <li key={r.path}>\n <code>{r.path}</code> <span className=\"muted\">({r.kind})</span>\n {r.reason && <span className=\"muted\"> — {r.reason}</span>}\n </li>\n ))}\n </ul>\n <button\n type=\"button\"\n className=\"btn\"\n data-testid={testids.goto}\n onClick={() => goto(unresolved.callableId)}\n >\n Open the created {kind}\n </button>\n </div>\n )}\n </div>\n\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n {!configuring && (\n <button\n type=\"button\"\n className=\"btn\"\n data-testid={`${collection}-import-next`}\n disabled={blockedReason !== null || previewMut.isPending}\n onClick={next}\n >\n {previewMut.isPending ? \"Checking…\" : \"Next\"}\n </button>\n )}\n <button\n type=\"button\"\n className=\"btn\"\n data-testid={testids.submit}\n disabled={disabled}\n onClick={submit}\n >\n {importMut.isPending ? \"Importing…\" : \"Create\"}\n </button>\n </div>\n </Modal>\n );\n}\n"],"names":["COLLECTION","TESTIDS","ImportSpecModal","props","kind","collection","testids","text","setText","useState","error","setError","unresolved","setUnresolved","rows","setRows","addingFor","setAddingFor","importMut","useImportSpecMutation","previewMut","useSpecPreviewMutation","parsed","blockedReason","parseImportPaste","configuring","disabled","rowsReady","edit","next","res","buildRows","ApiError","onFile","file","e","goto","id","submit","toSelections","result","r","selectValue","row","s","onPick","value","cur","setUnconfigured","setCreateName","setBind","jsxs","Modal","jsx","JsonEditor","_a","o","AddConnectionModal","connectionId","key","withCreatedConnection"],"mappings":"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"}
|
|
@@ -2,9 +2,9 @@ import { jsx as t, jsxs as l, Fragment as U } from "react/jsx-runtime";
|
|
|
2
2
|
import { ApiError as W } from "@w6w/sdk";
|
|
3
3
|
import { EmptyState as B, DataTable as K, EditButton as Y, DeleteButton as q, useEnterSubmit as z } from "@w6w/ui";
|
|
4
4
|
import { useState as h } from "react";
|
|
5
|
-
import { C as G, M as J } from "./ConfirmModal-
|
|
5
|
+
import { C as G, M as J } from "./ConfirmModal-Pv2-A_3U.js";
|
|
6
6
|
import { u as V } from "./project-context-Tvp-La7A.js";
|
|
7
|
-
import { u as X } from "./connections-
|
|
7
|
+
import { u as X } from "./connections-CzsCyIxY.js";
|
|
8
8
|
import { u as Z, a as ee, b as te, c as ne, d as oe, e as le, f as ae } from "./models-bAayQPJ_.js";
|
|
9
9
|
const L = {
|
|
10
10
|
invalid_route_name: "That route name is not valid. Use lowercase letters, digits and dashes (e.g. gpt-4o-fast): 3 to 39 characters, starting with a letter, no double dashes, not ending in a dash."
|
|
@@ -342,4 +342,4 @@ function _(e) {
|
|
|
342
342
|
export {
|
|
343
343
|
ge as M
|
|
344
344
|
};
|
|
345
|
-
//# sourceMappingURL=ModelRoutesManager-
|
|
345
|
+
//# sourceMappingURL=ModelRoutesManager-1Ac5wcas.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelRoutesManager-BGESQahw.js","sources":["../src/forms/ModelRoutesManager.tsx"],"sourcesContent":["/**\n * `<ModelRoutesManager>` — list, add, edit and delete the project's model routes. A route is the\n * name callers ask for; it resolves to one model reached through one connection, plus optional\n * fallbacks. `broken` marks a route whose connection stopped working, so it stays visible (and\n * editable) instead of silently disappearing from the list.\n *\n * The project comes from `useEditorProject(projectId)`: omitted defers to `<W6WEmbedProvider\n * project>`; `null` or `\"\"` REFUSES — the list query is disabled, no `/model-routes` request is\n * sent and \"Add\" is disabled. Every write names the resolved project, never `undefined`.\n *\n * `initialEditRouteId` (with `initialConnection`) opens that route's editor on mount, prefilled:\n * the connection dependents view's reconnect affordance lands here, naming the replacement\n * connection. Both are read ONCE — remount to reopen the editor.\n */\nimport { ApiError } from \"@w6w/sdk\";\nimport {\n DataTable,\n type DataTableColumn,\n DeleteButton,\n EditButton,\n EmptyState,\n useEnterSubmit,\n} from \"@w6w/ui\";\nimport { type ReactNode, useState } from \"react\";\nimport { ConfirmModal } from \"../chrome/ConfirmModal.tsx\";\nimport { Modal } from \"../chrome/Modal.tsx\";\nimport { useEditorProject } from \"../project-context.ts\";\nimport { useConnectionsQuery } from \"../repos/connections.ts\";\nimport {\n type ConnectionChoice,\n type Model,\n type ModelFallback,\n type ModelRoute,\n connectionChoices,\n useCreateModelRouteMutation,\n useDeleteModelRouteMutation,\n useAllModelCatalogQuery,\n useModelProvidersQuery,\n useModelRoutesQuery,\n useUpdateModelRouteMutation,\n} from \"../repos/models.ts\";\n\n/**\n * Actionable copy for the route write failures the server names by code. `invalid_route_name` is\n * a 400 the NAME field caused, so it states the rule instead of only echoing the server's\n * sentence; any other error falls back to its own message.\n */\nconst COPY: Record<string, string> = {\n invalid_route_name:\n \"That route name is not valid. Use lowercase letters, digits and dashes (e.g. gpt-4o-fast): 3 to 39 characters, starting with a letter, no double dashes, not ending in a dash.\",\n};\n\nexport function modelRouteErrorCopy(e: unknown): string {\n if (e instanceof ApiError) {\n if (Object.hasOwn(COPY, e.code)) return COPY[e.code];\n return e.message;\n }\n return e instanceof Error ? e.message : String(e);\n}\n\nexport interface ModelRoutesManagerProps {\n /**\n * The project whose routes are managed. Omitted: the `<W6WEmbedProvider project>`. `null` or\n * `\"\"`: no project — nothing is requested and nothing can be written.\n */\n projectId?: string | null;\n /** Open this route's editor on mount (read once). The dependents view's reconnect passes it. */\n initialEditRouteId?: string;\n /** Prefill the editor's connection — a reconnect names the connection that should replace it. */\n initialConnection?: string;\n}\n\n/** Which route the editor has open: `routeId: null` is the create form. */\ninterface EditorState {\n routeId: string | null;\n connection?: string;\n}\n\n/** One-line summary of a route's resolution, safe against long ids. */\nfunction routeSummary(r: ModelRoute): string {\n const fallbacks = r.fallbacks.length;\n const tail = fallbacks === 0 ? \"\" : ` · ${fallbacks} fallback${fallbacks === 1 ? \"\" : \"s\"}`;\n return `${r.modelId} via ${r.connectionId}${tail}`;\n}\n\nexport function ModelRoutesManager(props: ModelRoutesManagerProps): ReactNode {\n const project = useEditorProject(props.projectId);\n const [editor, setEditor] = useState<EditorState | null>(() =>\n props.initialEditRouteId\n ? { routeId: props.initialEditRouteId, connection: props.initialConnection }\n : null,\n );\n const [pending, setPending] = useState<ModelRoute | null>(null);\n const [deleteError, setDeleteError] = useState<string | null>(null);\n\n const routesQuery = useModelRoutesQuery(project ?? undefined);\n const deleteMut = useDeleteModelRouteMutation();\n const routes = routesQuery.data ?? [];\n const canCreate = project != null;\n // The reconnect flow names a route by id; the row itself arrives with the list.\n const editing = editor?.routeId == null ? undefined : routes.find((r) => r.id === editor.routeId);\n const editorReady = editor != null && (editor.routeId == null || editing != null);\n\n const columns: DataTableColumn<ModelRoute>[] = [\n {\n key: \"name\",\n header: \"Route\",\n render: (r) => (\n <div className=\"list-main\" style={{ maxWidth: 0, minWidth: \"100%\" }}>\n <strong className=\"list-name\" title={r.name}>\n {r.name}\n </strong>{\" \"}\n <span className={r.status === \"broken\" ? \"tag warn\" : \"tag\"}>{r.status}</span>\n <div className=\"muted small list-preview\" title={routeSummary(r)}>\n {routeSummary(r)}\n </div>\n </div>\n ),\n },\n {\n key: \"connection\",\n header: \"Connection\",\n render: (r) => <code>{r.connectionId}</code>,\n },\n {\n key: \"actions\",\n header: \"\",\n align: \"right\",\n link: false,\n render: (r) => (\n <div style={{ display: \"flex\", gap: \"var(--w6w-sp-1-5)\" }}>\n <EditButton\n label=\"Edit\"\n onClick={() => setEditor({ routeId: r.id })}\n data-testid={`model-route-edit-${r.name}`}\n />\n <DeleteButton\n label=\"Delete\"\n onClick={() => setPending(r)}\n disabled={deleteMut.isPending}\n data-testid={`model-route-delete-${r.name}`}\n />\n </div>\n ),\n },\n ];\n\n return (\n <div className=\"w6w-embed-root\">\n <section className=\"section\">\n <div className=\"section-head\">\n <div>\n <h3>Model routes</h3>\n <p className=\"muted small\">\n The names callers ask for. Each route resolves to a model through a connection, with\n fallbacks when that model cannot answer.\n </p>\n </div>\n <button\n type=\"button\"\n className=\"btn\"\n disabled={!canCreate}\n onClick={() => setEditor({ routeId: null })}\n data-testid=\"model-route-add\"\n >\n + Add route\n </button>\n </div>\n\n {deleteError && (\n <div className=\"result error\" role=\"alert\" data-testid=\"model-route-delete-error\">\n {deleteError}\n </div>\n )}\n\n <div className=\"card\">\n {routesQuery.isLoading && <p className=\"muted\">Loading…</p>}\n {routesQuery.data?.length === 0 && (\n <EmptyState testId=\"model-routes-empty\">\n No model routes yet. Add one to give callers a stable name for a model.\n </EmptyState>\n )}\n {routes.length > 0 && (\n <DataTable\n columns={columns}\n rows={routes}\n rowKey={(r) => r.id}\n testId=\"model-routes-table\"\n />\n )}\n </div>\n\n {editorReady && project != null && editor != null && (\n <RouteModal\n project={project}\n initial={editing}\n initialConnection={editor.connection}\n onClose={() => setEditor(null)}\n onSaved={() => setEditor(null)}\n />\n )}\n\n {pending != null && project != null && (\n <ConfirmModal\n title=\"Delete model route\"\n message={`Delete the model route \"${pending.name}\"? Calls that name it will fail until another route covers the model.`}\n confirmLabel=\"Delete\"\n onConfirm={() => {\n const name = pending.name;\n setDeleteError(null);\n deleteMut.mutate(\n { project, name },\n {\n onError: (e: unknown) =>\n setDeleteError(`Could not delete \"${name}\": ${modelRouteErrorCopy(e)}`),\n },\n );\n setPending(null);\n }}\n onClose={() => setPending(null)}\n />\n )}\n </section>\n </div>\n );\n}\n\n/**\n * Create/edit modal. The name is the route's address, so it is fixed once created (the server\n * patches by name); model and connection stay editable — a reconnect is exactly a connection\n * change.\n */\nfunction RouteModal(props: {\n project: string;\n initial?: ModelRoute;\n initialConnection?: string;\n onClose: () => void;\n onSaved: () => void;\n}) {\n const isEdit = !!props.initial;\n const [name, setName] = useState(props.initial?.name ?? \"\");\n const [model, setModel] = useState(props.initial?.modelId ?? \"\");\n const [connection, setConnection] = useState(\n props.initialConnection ?? props.initial?.connectionId ?? \"\",\n );\n const [fallbacks, setFallbacks] = useState<ModelFallback[]>(props.initial?.fallbacks ?? []);\n const [error, setError] = useState<string | null>(null);\n\n const catalog = useAllModelCatalogQuery({ status: \"active\" });\n const connectionsQuery = useConnectionsQuery();\n const models = catalog.data?.models ?? [];\n const providersQuery = useModelProvidersQuery();\n // Descriptor-driven: only designated providers, disabled with a reason when `complete` is not\n // supported. Never an app id or category guess.\n const connections = connectionChoices(\n connectionsQuery.data ?? [],\n providersQuery.data ?? [],\n \"complete\",\n );\n const catalogEmpty = catalog.isSuccess && models.length === 0;\n\n const createMut = useCreateModelRouteMutation();\n const updateMut = useUpdateModelRouteMutation();\n const saving = createMut.isPending || updateMut.isPending;\n const canSave =\n !!name &&\n !!model &&\n !!connection &&\n fallbacks.every((f) => !!f.model && !!f.connection) &&\n !saving;\n\n function save() {\n setError(null);\n const onSettled = {\n onSuccess: () => props.onSaved(),\n onError: (e: unknown) => setError(modelRouteErrorCopy(e)),\n };\n if (props.initial) {\n updateMut.mutate(\n {\n project: props.project,\n name: props.initial.name,\n patch: { model, connection, fallbacks },\n },\n onSettled,\n );\n return;\n }\n createMut.mutate(\n {\n project: props.project,\n input: { name, model, connection, ...(fallbacks.length > 0 ? { fallbacks } : {}) },\n },\n onSettled,\n );\n }\n\n const enterSubmit = useEnterSubmit(save, { enabled: canSave });\n\n return (\n <Modal\n title={props.initial ? `Edit ${props.initial.name}` : \"Add model route\"}\n onClose={props.onClose}\n >\n <div className=\"modal-body\">\n <label className=\"field\">\n <span>Name</span>\n <input\n type=\"text\"\n value={name}\n disabled={isEdit}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. gpt-4o-fast\"\n maxLength={64}\n data-testid=\"model-route-name\"\n {...enterSubmit}\n />\n {!isEdit && (\n <span className=\"hint\">\n 3 to 39 characters: lowercase letters, digits and dashes, starting with a letter, no\n double dashes, not ending in a dash. Callers use this name; it cannot be renamed\n later.\n </span>\n )}\n </label>\n\n {catalogEmpty && (\n <EmptyState testId=\"model-route-catalog-empty\">\n The model catalog is empty. Open the Catalog tab to discover models; until then you can\n type ids by hand.\n </EmptyState>\n )}\n\n <PairFields\n label=\"\"\n model={model}\n connection={connection}\n onModel={setModel}\n onConnection={setConnection}\n models={models}\n connections={connections}\n catalogEmpty={catalogEmpty}\n testIdPrefix=\"model-route\"\n enterSubmit={enterSubmit}\n />\n <span className=\"hint\">\n The connection holds the credentials for the model. Changing it fixes a broken route.\n </span>\n\n <div className=\"field\">\n <span>Fallbacks</span>\n {fallbacks.map((f, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: rows have no identity beyond position\n <div key={i} style={{ display: \"flex\", gap: \"var(--w6w-sp-1-5)\" }}>\n <PairFields\n label={`Fallback ${i + 1} `}\n model={f.model}\n connection={f.connection}\n onModel={(v) =>\n setFallbacks((fs) => fs.map((x, j) => (j === i ? { ...x, model: v } : x)))\n }\n onConnection={(v) =>\n setFallbacks((fs) => fs.map((x, j) => (j === i ? { ...x, connection: v } : x)))\n }\n models={models}\n connections={connections}\n catalogEmpty={catalogEmpty}\n testIdPrefix={`model-route-fallback-${i}`}\n enterSubmit={enterSubmit}\n />\n <button\n type=\"button\"\n className=\"btn ghost\"\n onClick={() => setFallbacks((fs) => fs.filter((_, j) => j !== i))}\n data-testid={`model-route-fallback-${i}-remove`}\n >\n Remove\n </button>\n </div>\n ))}\n <button\n type=\"button\"\n className=\"btn ghost\"\n onClick={() => setFallbacks((fs) => [...fs, { model: \"\", connection: \"\" }])}\n data-testid=\"model-route-fallback-add\"\n >\n + Add fallback\n </button>\n </div>\n\n {error && (\n <div className=\"result error\" data-testid=\"model-route-error\">\n {error}\n </div>\n )}\n </div>\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"btn\"\n disabled={!canSave}\n onClick={save}\n data-testid=\"model-route-save\"\n >\n {saving ? \"Saving…\" : isEdit ? \"Save changes\" : \"Save route\"}\n </button>\n </div>\n </Modal>\n );\n}\n\ninterface PairFieldsProps {\n label: string;\n model: string;\n connection: string;\n onModel: (v: string) => void;\n onConnection: (v: string) => void;\n models: Model[];\n connections: ConnectionChoice[];\n catalogEmpty: boolean;\n testIdPrefix: string;\n enterSubmit: Record<string, unknown>;\n}\n\n/**\n * A model + connection pair as selects fed by the catalog and the connections list. Connections\n * narrow to the chosen model's provider app; if none match, all are listed (labelled) so the\n * route can still be saved. An empty catalog falls back to free text.\n */\nfunction PairFields(p: PairFieldsProps) {\n const picked = p.models.find((m) => m.id === p.model);\n const matching = picked\n ? p.connections.filter((c) => c.appId === picked.providerAppId)\n : p.connections;\n const narrowed = picked != null && matching.length > 0;\n const options = narrowed ? matching : p.connections;\n const connHas = options.some((c) => c.id === p.connection);\n const modelHas = p.models.some((m) => m.id === p.model);\n return (\n <>\n <div className=\"field\">\n <span>{p.label}Model</span>\n {p.catalogEmpty ? (\n <input\n type=\"text\"\n value={p.model}\n onChange={(e) => p.onModel(e.target.value)}\n placeholder=\"model id\"\n aria-label={`${p.label}Model`}\n data-testid={`${p.testIdPrefix}-model`}\n {...p.enterSubmit}\n />\n ) : (\n <select\n value={p.model}\n onChange={(e) => p.onModel(e.target.value)}\n aria-label={`${p.label}Model`}\n data-testid={`${p.testIdPrefix}-model`}\n >\n <option value=\"\">Select a model…</option>\n {p.model && !modelHas && <option value={p.model}>{p.model}</option>}\n {p.models.map((m) => (\n <option key={m.id} value={m.id}>\n {m.displayName} ({m.provider})\n </option>\n ))}\n </select>\n )}\n </div>\n <div className=\"field\">\n <span>{p.label}Connection</span>\n {p.catalogEmpty && p.connections.length === 0 ? (\n <input\n type=\"text\"\n value={p.connection}\n onChange={(e) => p.onConnection(e.target.value)}\n placeholder=\"connection id\"\n aria-label={`${p.label}Connection`}\n data-testid={`${p.testIdPrefix}-connection`}\n {...p.enterSubmit}\n />\n ) : (\n <select\n value={p.connection}\n onChange={(e) => p.onConnection(e.target.value)}\n aria-label={`${p.label}Connection`}\n data-testid={`${p.testIdPrefix}-connection`}\n >\n <option value=\"\">Select a connection…</option>\n {p.connection && !connHas && <option value={p.connection}>{p.connection}</option>}\n {options.map((c) => (\n <option key={c.id} value={c.id} disabled={c.disabledReason != null}>\n {c.displayName}\n {narrowed ? \"\" : ` (${c.appId})`}\n {c.disabledReason != null ? ` — ${c.disabledReason}` : \"\"}\n </option>\n ))}\n </select>\n )}\n </div>\n </>\n );\n}\n"],"names":["COPY","modelRouteErrorCopy","ApiError","routeSummary","r","fallbacks","tail","ModelRoutesManager","props","project","useEditorProject","editor","setEditor","useState","pending","setPending","deleteError","setDeleteError","routesQuery","useModelRoutesQuery","deleteMut","useDeleteModelRouteMutation","routes","canCreate","editing","editorReady","columns","jsxs","jsx","EditButton","DeleteButton","_a","EmptyState","DataTable","RouteModal","ConfirmModal","name","e","isEdit","setName","model","setModel","_b","connection","setConnection","_c","setFallbacks","_d","error","setError","catalog","useAllModelCatalogQuery","connectionsQuery","useConnectionsQuery","models","_e","providersQuery","useModelProvidersQuery","connections","connectionChoices","catalogEmpty","createMut","useCreateModelRouteMutation","updateMut","useUpdateModelRouteMutation","saving","canSave","f","save","onSettled","enterSubmit","useEnterSubmit","Modal","PairFields","i","v","fs","x","j","_","p","picked","m","matching","c","narrowed","options","connHas","modelHas","Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ModelRoutesManager-1Ac5wcas.js","sources":["../src/forms/ModelRoutesManager.tsx"],"sourcesContent":["/**\n * `<ModelRoutesManager>` — list, add, edit and delete the project's model routes. A route is the\n * name callers ask for; it resolves to one model reached through one connection, plus optional\n * fallbacks. `broken` marks a route whose connection stopped working, so it stays visible (and\n * editable) instead of silently disappearing from the list.\n *\n * The project comes from `useEditorProject(projectId)`: omitted defers to `<W6WEmbedProvider\n * project>`; `null` or `\"\"` REFUSES — the list query is disabled, no `/model-routes` request is\n * sent and \"Add\" is disabled. Every write names the resolved project, never `undefined`.\n *\n * `initialEditRouteId` (with `initialConnection`) opens that route's editor on mount, prefilled:\n * the connection dependents view's reconnect affordance lands here, naming the replacement\n * connection. Both are read ONCE — remount to reopen the editor.\n */\nimport { ApiError } from \"@w6w/sdk\";\nimport {\n DataTable,\n type DataTableColumn,\n DeleteButton,\n EditButton,\n EmptyState,\n useEnterSubmit,\n} from \"@w6w/ui\";\nimport { type ReactNode, useState } from \"react\";\nimport { ConfirmModal } from \"../chrome/ConfirmModal.tsx\";\nimport { Modal } from \"../chrome/Modal.tsx\";\nimport { useEditorProject } from \"../project-context.ts\";\nimport { useConnectionsQuery } from \"../repos/connections.ts\";\nimport {\n type ConnectionChoice,\n type Model,\n type ModelFallback,\n type ModelRoute,\n connectionChoices,\n useAllModelCatalogQuery,\n useCreateModelRouteMutation,\n useDeleteModelRouteMutation,\n useModelProvidersQuery,\n useModelRoutesQuery,\n useUpdateModelRouteMutation,\n} from \"../repos/models.ts\";\n\n/**\n * Actionable copy for the route write failures the server names by code. `invalid_route_name` is\n * a 400 the NAME field caused, so it states the rule instead of only echoing the server's\n * sentence; any other error falls back to its own message.\n */\nconst COPY: Record<string, string> = {\n invalid_route_name:\n \"That route name is not valid. Use lowercase letters, digits and dashes (e.g. gpt-4o-fast): 3 to 39 characters, starting with a letter, no double dashes, not ending in a dash.\",\n};\n\nexport function modelRouteErrorCopy(e: unknown): string {\n if (e instanceof ApiError) {\n if (Object.hasOwn(COPY, e.code)) return COPY[e.code];\n return e.message;\n }\n return e instanceof Error ? e.message : String(e);\n}\n\nexport interface ModelRoutesManagerProps {\n /**\n * The project whose routes are managed. Omitted: the `<W6WEmbedProvider project>`. `null` or\n * `\"\"`: no project — nothing is requested and nothing can be written.\n */\n projectId?: string | null;\n /** Open this route's editor on mount (read once). The dependents view's reconnect passes it. */\n initialEditRouteId?: string;\n /** Prefill the editor's connection — a reconnect names the connection that should replace it. */\n initialConnection?: string;\n}\n\n/** Which route the editor has open: `routeId: null` is the create form. */\ninterface EditorState {\n routeId: string | null;\n connection?: string;\n}\n\n/** One-line summary of a route's resolution, safe against long ids. */\nfunction routeSummary(r: ModelRoute): string {\n const fallbacks = r.fallbacks.length;\n const tail = fallbacks === 0 ? \"\" : ` · ${fallbacks} fallback${fallbacks === 1 ? \"\" : \"s\"}`;\n return `${r.modelId} via ${r.connectionId}${tail}`;\n}\n\nexport function ModelRoutesManager(props: ModelRoutesManagerProps): ReactNode {\n const project = useEditorProject(props.projectId);\n const [editor, setEditor] = useState<EditorState | null>(() =>\n props.initialEditRouteId\n ? { routeId: props.initialEditRouteId, connection: props.initialConnection }\n : null,\n );\n const [pending, setPending] = useState<ModelRoute | null>(null);\n const [deleteError, setDeleteError] = useState<string | null>(null);\n\n const routesQuery = useModelRoutesQuery(project ?? undefined);\n const deleteMut = useDeleteModelRouteMutation();\n const routes = routesQuery.data ?? [];\n const canCreate = project != null;\n // The reconnect flow names a route by id; the row itself arrives with the list.\n const editing = editor?.routeId == null ? undefined : routes.find((r) => r.id === editor.routeId);\n const editorReady = editor != null && (editor.routeId == null || editing != null);\n\n const columns: DataTableColumn<ModelRoute>[] = [\n {\n key: \"name\",\n header: \"Route\",\n render: (r) => (\n <div className=\"list-main\" style={{ maxWidth: 0, minWidth: \"100%\" }}>\n <strong className=\"list-name\" title={r.name}>\n {r.name}\n </strong>{\" \"}\n <span className={r.status === \"broken\" ? \"tag warn\" : \"tag\"}>{r.status}</span>\n <div className=\"muted small list-preview\" title={routeSummary(r)}>\n {routeSummary(r)}\n </div>\n </div>\n ),\n },\n {\n key: \"connection\",\n header: \"Connection\",\n render: (r) => <code>{r.connectionId}</code>,\n },\n {\n key: \"actions\",\n header: \"\",\n align: \"right\",\n link: false,\n render: (r) => (\n <div style={{ display: \"flex\", gap: \"var(--w6w-sp-1-5)\" }}>\n <EditButton\n label=\"Edit\"\n onClick={() => setEditor({ routeId: r.id })}\n data-testid={`model-route-edit-${r.name}`}\n />\n <DeleteButton\n label=\"Delete\"\n onClick={() => setPending(r)}\n disabled={deleteMut.isPending}\n data-testid={`model-route-delete-${r.name}`}\n />\n </div>\n ),\n },\n ];\n\n return (\n <div className=\"w6w-embed-root\">\n <section className=\"section\">\n <div className=\"section-head\">\n <div>\n <h3>Model routes</h3>\n <p className=\"muted small\">\n The names callers ask for. Each route resolves to a model through a connection, with\n fallbacks when that model cannot answer.\n </p>\n </div>\n <button\n type=\"button\"\n className=\"btn\"\n disabled={!canCreate}\n onClick={() => setEditor({ routeId: null })}\n data-testid=\"model-route-add\"\n >\n + Add route\n </button>\n </div>\n\n {deleteError && (\n <div className=\"result error\" role=\"alert\" data-testid=\"model-route-delete-error\">\n {deleteError}\n </div>\n )}\n\n <div className=\"card\">\n {routesQuery.isLoading && <p className=\"muted\">Loading…</p>}\n {routesQuery.data?.length === 0 && (\n <EmptyState testId=\"model-routes-empty\">\n No model routes yet. Add one to give callers a stable name for a model.\n </EmptyState>\n )}\n {routes.length > 0 && (\n <DataTable\n columns={columns}\n rows={routes}\n rowKey={(r) => r.id}\n testId=\"model-routes-table\"\n />\n )}\n </div>\n\n {editorReady && project != null && editor != null && (\n <RouteModal\n project={project}\n initial={editing}\n initialConnection={editor.connection}\n onClose={() => setEditor(null)}\n onSaved={() => setEditor(null)}\n />\n )}\n\n {pending != null && project != null && (\n <ConfirmModal\n title=\"Delete model route\"\n message={`Delete the model route \"${pending.name}\"? Calls that name it will fail until another route covers the model.`}\n confirmLabel=\"Delete\"\n onConfirm={() => {\n const name = pending.name;\n setDeleteError(null);\n deleteMut.mutate(\n { project, name },\n {\n onError: (e: unknown) =>\n setDeleteError(`Could not delete \"${name}\": ${modelRouteErrorCopy(e)}`),\n },\n );\n setPending(null);\n }}\n onClose={() => setPending(null)}\n />\n )}\n </section>\n </div>\n );\n}\n\n/**\n * Create/edit modal. The name is the route's address, so it is fixed once created (the server\n * patches by name); model and connection stay editable — a reconnect is exactly a connection\n * change.\n */\nfunction RouteModal(props: {\n project: string;\n initial?: ModelRoute;\n initialConnection?: string;\n onClose: () => void;\n onSaved: () => void;\n}) {\n const isEdit = !!props.initial;\n const [name, setName] = useState(props.initial?.name ?? \"\");\n const [model, setModel] = useState(props.initial?.modelId ?? \"\");\n const [connection, setConnection] = useState(\n props.initialConnection ?? props.initial?.connectionId ?? \"\",\n );\n const [fallbacks, setFallbacks] = useState<ModelFallback[]>(props.initial?.fallbacks ?? []);\n const [error, setError] = useState<string | null>(null);\n\n const catalog = useAllModelCatalogQuery({ status: \"active\" });\n const connectionsQuery = useConnectionsQuery();\n const models = catalog.data?.models ?? [];\n const providersQuery = useModelProvidersQuery();\n // Descriptor-driven: only designated providers, disabled with a reason when `complete` is not\n // supported. Never an app id or category guess.\n const connections = connectionChoices(\n connectionsQuery.data ?? [],\n providersQuery.data ?? [],\n \"complete\",\n );\n const catalogEmpty = catalog.isSuccess && models.length === 0;\n\n const createMut = useCreateModelRouteMutation();\n const updateMut = useUpdateModelRouteMutation();\n const saving = createMut.isPending || updateMut.isPending;\n const canSave =\n !!name &&\n !!model &&\n !!connection &&\n fallbacks.every((f) => !!f.model && !!f.connection) &&\n !saving;\n\n function save() {\n setError(null);\n const onSettled = {\n onSuccess: () => props.onSaved(),\n onError: (e: unknown) => setError(modelRouteErrorCopy(e)),\n };\n if (props.initial) {\n updateMut.mutate(\n {\n project: props.project,\n name: props.initial.name,\n patch: { model, connection, fallbacks },\n },\n onSettled,\n );\n return;\n }\n createMut.mutate(\n {\n project: props.project,\n input: { name, model, connection, ...(fallbacks.length > 0 ? { fallbacks } : {}) },\n },\n onSettled,\n );\n }\n\n const enterSubmit = useEnterSubmit(save, { enabled: canSave });\n\n return (\n <Modal\n title={props.initial ? `Edit ${props.initial.name}` : \"Add model route\"}\n onClose={props.onClose}\n >\n <div className=\"modal-body\">\n <label className=\"field\">\n <span>Name</span>\n <input\n type=\"text\"\n value={name}\n disabled={isEdit}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. gpt-4o-fast\"\n maxLength={64}\n data-testid=\"model-route-name\"\n {...enterSubmit}\n />\n {!isEdit && (\n <span className=\"hint\">\n 3 to 39 characters: lowercase letters, digits and dashes, starting with a letter, no\n double dashes, not ending in a dash. Callers use this name; it cannot be renamed\n later.\n </span>\n )}\n </label>\n\n {catalogEmpty && (\n <EmptyState testId=\"model-route-catalog-empty\">\n The model catalog is empty. Open the Catalog tab to discover models; until then you can\n type ids by hand.\n </EmptyState>\n )}\n\n <PairFields\n label=\"\"\n model={model}\n connection={connection}\n onModel={setModel}\n onConnection={setConnection}\n models={models}\n connections={connections}\n catalogEmpty={catalogEmpty}\n testIdPrefix=\"model-route\"\n enterSubmit={enterSubmit}\n />\n <span className=\"hint\">\n The connection holds the credentials for the model. Changing it fixes a broken route.\n </span>\n\n <div className=\"field\">\n <span>Fallbacks</span>\n {fallbacks.map((f, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: rows have no identity beyond position\n <div key={i} style={{ display: \"flex\", gap: \"var(--w6w-sp-1-5)\" }}>\n <PairFields\n label={`Fallback ${i + 1} `}\n model={f.model}\n connection={f.connection}\n onModel={(v) =>\n setFallbacks((fs) => fs.map((x, j) => (j === i ? { ...x, model: v } : x)))\n }\n onConnection={(v) =>\n setFallbacks((fs) => fs.map((x, j) => (j === i ? { ...x, connection: v } : x)))\n }\n models={models}\n connections={connections}\n catalogEmpty={catalogEmpty}\n testIdPrefix={`model-route-fallback-${i}`}\n enterSubmit={enterSubmit}\n />\n <button\n type=\"button\"\n className=\"btn ghost\"\n onClick={() => setFallbacks((fs) => fs.filter((_, j) => j !== i))}\n data-testid={`model-route-fallback-${i}-remove`}\n >\n Remove\n </button>\n </div>\n ))}\n <button\n type=\"button\"\n className=\"btn ghost\"\n onClick={() => setFallbacks((fs) => [...fs, { model: \"\", connection: \"\" }])}\n data-testid=\"model-route-fallback-add\"\n >\n + Add fallback\n </button>\n </div>\n\n {error && (\n <div className=\"result error\" data-testid=\"model-route-error\">\n {error}\n </div>\n )}\n </div>\n <div className=\"modal-actions\">\n <button type=\"button\" className=\"btn ghost\" onClick={props.onClose}>\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"btn\"\n disabled={!canSave}\n onClick={save}\n data-testid=\"model-route-save\"\n >\n {saving ? \"Saving…\" : isEdit ? \"Save changes\" : \"Save route\"}\n </button>\n </div>\n </Modal>\n );\n}\n\ninterface PairFieldsProps {\n label: string;\n model: string;\n connection: string;\n onModel: (v: string) => void;\n onConnection: (v: string) => void;\n models: Model[];\n connections: ConnectionChoice[];\n catalogEmpty: boolean;\n testIdPrefix: string;\n enterSubmit: Record<string, unknown>;\n}\n\n/**\n * A model + connection pair as selects fed by the catalog and the connections list. Connections\n * narrow to the chosen model's provider app; if none match, all are listed (labelled) so the\n * route can still be saved. An empty catalog falls back to free text.\n */\nfunction PairFields(p: PairFieldsProps) {\n const picked = p.models.find((m) => m.id === p.model);\n const matching = picked\n ? p.connections.filter((c) => c.appId === picked.providerAppId)\n : p.connections;\n const narrowed = picked != null && matching.length > 0;\n const options = narrowed ? matching : p.connections;\n const connHas = options.some((c) => c.id === p.connection);\n const modelHas = p.models.some((m) => m.id === p.model);\n return (\n <>\n <div className=\"field\">\n <span>{p.label}Model</span>\n {p.catalogEmpty ? (\n <input\n type=\"text\"\n value={p.model}\n onChange={(e) => p.onModel(e.target.value)}\n placeholder=\"model id\"\n aria-label={`${p.label}Model`}\n data-testid={`${p.testIdPrefix}-model`}\n {...p.enterSubmit}\n />\n ) : (\n <select\n value={p.model}\n onChange={(e) => p.onModel(e.target.value)}\n aria-label={`${p.label}Model`}\n data-testid={`${p.testIdPrefix}-model`}\n >\n <option value=\"\">Select a model…</option>\n {p.model && !modelHas && <option value={p.model}>{p.model}</option>}\n {p.models.map((m) => (\n <option key={m.id} value={m.id}>\n {m.displayName} ({m.provider})\n </option>\n ))}\n </select>\n )}\n </div>\n <div className=\"field\">\n <span>{p.label}Connection</span>\n {p.catalogEmpty && p.connections.length === 0 ? (\n <input\n type=\"text\"\n value={p.connection}\n onChange={(e) => p.onConnection(e.target.value)}\n placeholder=\"connection id\"\n aria-label={`${p.label}Connection`}\n data-testid={`${p.testIdPrefix}-connection`}\n {...p.enterSubmit}\n />\n ) : (\n <select\n value={p.connection}\n onChange={(e) => p.onConnection(e.target.value)}\n aria-label={`${p.label}Connection`}\n data-testid={`${p.testIdPrefix}-connection`}\n >\n <option value=\"\">Select a connection…</option>\n {p.connection && !connHas && <option value={p.connection}>{p.connection}</option>}\n {options.map((c) => (\n <option key={c.id} value={c.id} disabled={c.disabledReason != null}>\n {c.displayName}\n {narrowed ? \"\" : ` (${c.appId})`}\n {c.disabledReason != null ? ` — ${c.disabledReason}` : \"\"}\n </option>\n ))}\n </select>\n )}\n </div>\n </>\n );\n}\n"],"names":["COPY","modelRouteErrorCopy","ApiError","routeSummary","r","fallbacks","tail","ModelRoutesManager","props","project","useEditorProject","editor","setEditor","useState","pending","setPending","deleteError","setDeleteError","routesQuery","useModelRoutesQuery","deleteMut","useDeleteModelRouteMutation","routes","canCreate","editing","editorReady","columns","jsxs","jsx","EditButton","DeleteButton","_a","EmptyState","DataTable","RouteModal","ConfirmModal","name","e","isEdit","setName","model","setModel","_b","connection","setConnection","_c","setFallbacks","_d","error","setError","catalog","useAllModelCatalogQuery","connectionsQuery","useConnectionsQuery","models","_e","providersQuery","useModelProvidersQuery","connections","connectionChoices","catalogEmpty","createMut","useCreateModelRouteMutation","updateMut","useUpdateModelRouteMutation","saving","canSave","f","save","onSettled","enterSubmit","useEnterSubmit","Modal","PairFields","i","v","fs","x","j","_","p","picked","m","matching","c","narrowed","options","connHas","modelHas","Fragment"],"mappings":"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"}
|