@w6w/embed 0.2.1 → 0.2.11
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/dist/{ConfirmModal-RLbZT5_k.js → ConfirmModal-BE-SdX-O.js} +53 -49
- package/dist/{ConfirmModal-RLbZT5_k.js.map → ConfirmModal-BE-SdX-O.js.map} +1 -1
- package/dist/{CreateFunctionModal-DRsFx-FB.js → CreateFunctionModal-D6CQLpa_.js} +25 -25
- package/dist/{CreateFunctionModal-DRsFx-FB.js.map → CreateFunctionModal-D6CQLpa_.js.map} +1 -1
- package/dist/{DocumentFormModal-BExK1V-B.js → DocumentFormModal-YauVdolr.js} +5 -5
- package/dist/{DocumentFormModal-BExK1V-B.js.map → DocumentFormModal-YauVdolr.js.map} +1 -1
- package/dist/{ImportSpecModal-BDQIf6rg.js → ImportSpecModal-B7qd1Km2.js} +3 -3
- package/dist/{ImportSpecModal-BDQIf6rg.js.map → ImportSpecModal-B7qd1Km2.js.map} +1 -1
- package/dist/ModelRoutesManager-BGESQahw.js +345 -0
- package/dist/ModelRoutesManager-BGESQahw.js.map +1 -0
- package/dist/WorkflowEditor-CwvmAGp2.js +925 -0
- package/dist/WorkflowEditor-CwvmAGp2.js.map +1 -0
- package/dist/{apps-1FNUwbGv.js → apps-CboASBKr.js} +14 -14
- package/dist/{apps-1FNUwbGv.js.map → apps-CboASBKr.js.map} +1 -1
- package/dist/{callables-3mFrMVG_.js → callables-tOlflvbl.js} +11 -11
- package/dist/{callables-3mFrMVG_.js.map → callables-tOlflvbl.js.map} +1 -1
- package/dist/chrome/ConfirmModal.d.ts +4 -1
- package/dist/chrome/workspace.d.ts +4 -0
- package/dist/{coerce-input-BicYr7nc.js → coerce-input-DttlcSdO.js} +70 -58
- package/dist/coerce-input-DttlcSdO.js.map +1 -0
- package/dist/connections-D7cgXhDS.js +119 -0
- package/dist/connections-D7cgXhDS.js.map +1 -0
- package/dist/credentials-DaQU3Ca_.js +171 -0
- package/dist/credentials-DaQU3Ca_.js.map +1 -0
- package/dist/document-sources-UCwe8x77.js +91 -0
- package/dist/document-sources-UCwe8x77.js.map +1 -0
- package/dist/draft.mjs +1 -1
- package/dist/editor/BindingBanner.d.ts +13 -0
- package/dist/editor/CallableEditorFrame.d.ts +7 -0
- package/dist/editor/EndpointCards.d.ts +4 -1
- package/dist/editor/PublishControl.d.ts +19 -0
- package/dist/editor/TargetSelector.d.ts +15 -0
- package/dist/editor/TargetSelector.types.d.ts +2 -0
- package/dist/editor/definition.d.ts +2 -0
- package/dist/{editor-apps-BdenSV1o.js → editor-apps-BUZWld-m.js} +5 -5
- package/dist/{editor-apps-BdenSV1o.js.map → editor-apps-BUZWld-m.js.map} +1 -1
- package/dist/{editor-tools-RxmY5iyi.js → editor-tools-B_Lfx3kw.js} +11 -11
- package/dist/editor-tools-B_Lfx3kw.js.map +1 -0
- package/dist/editor.mjs +1 -1
- package/dist/editors.mjs +768 -621
- package/dist/editors.mjs.map +1 -1
- package/dist/{endpoints-B2ynbZo-.js → endpoints-DSRo1Lc5.js} +113 -107
- package/dist/endpoints-DSRo1Lc5.js.map +1 -0
- package/dist/fields-DvS8XZFc.js +21 -0
- package/dist/fields-DvS8XZFc.js.map +1 -0
- package/dist/forms/ModelBudgetsManager.d.ts +9 -0
- package/dist/forms/ModelRoutesManager.d.ts +14 -0
- package/dist/forms.d.ts +4 -0
- package/dist/forms.mjs +611 -212
- package/dist/forms.mjs.map +1 -1
- package/dist/index.mjs +119 -112
- package/dist/index.mjs.map +1 -1
- package/dist/lib/binding-problems.d.ts +38 -0
- package/dist/lib/code-rail.d.ts +4 -2
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/invoke-error.d.ts +1 -0
- package/dist/lib/sdk-snippets.d.ts +1 -1
- package/dist/lib/target-fields.d.ts +8 -0
- package/dist/lib/trigger-preview.d.ts +1 -0
- package/dist/lib/workflow-live-run.d.ts +9 -2
- package/dist/lib/workflow-nodes.d.ts +5 -0
- package/dist/lib/workflow-validity.d.ts +1 -0
- package/dist/lib.mjs +72 -70
- package/dist/lists/ConnectionDependents.d.ts +31 -0
- package/dist/lists/ConnectionDetail.d.ts +4 -1
- package/dist/lists/ConnectionList.d.ts +4 -1
- package/dist/lists/CredentialDetail.d.ts +15 -0
- package/dist/lists/CredentialList.d.ts +14 -0
- package/dist/lists/ModelCatalog.d.ts +12 -0
- package/dist/lists/ModelUsage.d.ts +12 -0
- package/dist/lists.d.ts +8 -0
- package/dist/lists.mjs +1322 -604
- package/dist/lists.mjs.map +1 -1
- package/dist/models-bAayQPJ_.js +270 -0
- package/dist/models-bAayQPJ_.js.map +1 -0
- package/dist/{project-context-BiCjv_E3.js → project-context-Tvp-La7A.js} +3 -3
- package/dist/{project-context-BiCjv_E3.js.map → project-context-Tvp-La7A.js.map} +1 -1
- package/dist/rail.mjs +4 -4
- package/dist/repos/agents-studio-agents.d.ts +52 -0
- package/dist/repos/agents-studio-assets.d.ts +68 -0
- package/dist/repos/connections.d.ts +30 -12
- package/dist/repos/credentials.d.ts +83 -0
- package/dist/repos/endpoints.d.ts +9 -3
- package/dist/repos/fields.d.ts +34 -0
- package/dist/repos/functions.d.ts +7 -5
- package/dist/repos/index.d.ts +5 -0
- package/dist/repos/models.d.ts +289 -0
- package/dist/repos.mjs +613 -176
- package/dist/repos.mjs.map +1 -1
- package/dist/{slug-C4ktDPdy.js → slug-BVdgiP_L.js} +64 -60
- package/dist/slug-BVdgiP_L.js.map +1 -0
- package/dist/{spec-export-Cf3VQSQS.js → spec-export-CBbloO_n.js} +7 -7
- package/dist/{spec-export-Cf3VQSQS.js.map → spec-export-CBbloO_n.js.map} +1 -1
- package/dist/{spec-import-CjmxyZDR.js → spec-import-CW6R_Wk1.js} +160 -156
- package/dist/spec-import-CW6R_Wk1.js.map +1 -0
- package/dist/theme-context-E2ZhlXDX.js +6 -0
- package/dist/theme-context-E2ZhlXDX.js.map +1 -0
- package/dist/theme-context.d.ts +2 -0
- package/dist/trigger-preview-DKxfjzUY.js +145 -0
- package/dist/trigger-preview-DKxfjzUY.js.map +1 -0
- package/dist/{use-callable-draft-zHLpcr-b.js → use-callable-draft-DsALnSfF.js} +22 -22
- package/dist/{use-callable-draft-zHLpcr-b.js.map → use-callable-draft-DsALnSfF.js.map} +1 -1
- package/dist/{workflow-blank-DyL3_RUA.js → workflow-blank-DFpGObrn.js} +6 -6
- package/dist/{workflow-blank-DyL3_RUA.js.map → workflow-blank-DFpGObrn.js.map} +1 -1
- package/package.json +1 -1
- package/src/styles.css +2 -6
- package/dist/WorkflowEditor-DlbVv6Fs.js +0 -854
- package/dist/WorkflowEditor-DlbVv6Fs.js.map +0 -1
- package/dist/coerce-input-BicYr7nc.js.map +0 -1
- package/dist/connections-CjjYeRqb.js +0 -78
- package/dist/connections-CjjYeRqb.js.map +0 -1
- package/dist/document-sources-C0grrtdq.js +0 -86
- package/dist/document-sources-C0grrtdq.js.map +0 -1
- package/dist/editor-tools-RxmY5iyi.js.map +0 -1
- package/dist/endpoints-B2ynbZo-.js.map +0 -1
- package/dist/slug-C4ktDPdy.js.map +0 -1
- package/dist/spec-import-CjmxyZDR.js.map +0 -1
- package/dist/trigger-preview-VPkrryDl.js +0 -120
- package/dist/trigger-preview-VPkrryDl.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentFormModal-
|
|
1
|
+
{"version":3,"file":"DocumentFormModal-YauVdolr.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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"}
|
|
@@ -3,8 +3,8 @@ import { p as k } from "./rail-settings-XYGToh00.js";
|
|
|
3
3
|
import { ApiError as I } from "@w6w/sdk";
|
|
4
4
|
import { JsonEditor as C } from "@w6w/ui";
|
|
5
5
|
import { useState as p } from "react";
|
|
6
|
-
import {
|
|
7
|
-
import { M as y } from "./ConfirmModal-
|
|
6
|
+
import { b as j } from "./spec-import-CW6R_Wk1.js";
|
|
7
|
+
import { M as y } from "./ConfirmModal-BE-SdX-O.js";
|
|
8
8
|
const S = {
|
|
9
9
|
function: "functions",
|
|
10
10
|
endpoint: "endpoints",
|
|
@@ -133,4 +133,4 @@ function L(s) {
|
|
|
133
133
|
export {
|
|
134
134
|
L as I
|
|
135
135
|
};
|
|
136
|
-
//# sourceMappingURL=ImportSpecModal-
|
|
136
|
+
//# sourceMappingURL=ImportSpecModal-B7qd1Km2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImportSpecModal-BDQIf6rg.js","sources":["../src/chrome/ImportSpecModal.tsx"],"sourcesContent":["import { type SpecImportKind, type SpecImportListKeys, parseImportPaste } from \"@w6w/embed/lib\";\nimport { ApiError } from \"@w6w/sdk\";\nimport { JsonEditor } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport { type SpecImportReferenceReport, useImportSpecMutation } 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 const importMut = useImportSpecMutation(props.project, props.listKeys);\n\n const { parsed, blockedReason } = parseImportPaste(text, kind);\n const disabled = blockedReason !== null || importMut.isPending;\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 (blockedReason !== null || parsed === null || importMut.isPending) return;\n setError(null);\n setUnresolved(null);\n // The parsed paste, forwarded VERBATIM — note 1's mechanism pin (A4).\n importMut.mutate(parsed, {\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 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={(v) => {\n setText(v);\n setUnresolved(null);\n setError(null);\n }}\n minHeight=\"320px\"\n aria-label={`${kind} spec document JSON`}\n />\n </div>\n\n {blockedReason && text !== \"\" && <p className=\"muted small\">{blockedReason}</p>}\n {error && <div className=\"result error\">{error}</div>}\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 <button\n type=\"button\"\n className=\"btn\"\n data-testid={testids.submit}\n disabled={disabled}\n onClick={submit}\n >\n {importMut.isPending ? \"Importing…\" : \"Import\"}\n </button>\n </div>\n </Modal>\n );\n}\n"],"names":["COLLECTION","TESTIDS","ImportSpecModal","props","kind","collection","testids","text","setText","useState","error","setError","unresolved","setUnresolved","importMut","useImportSpecMutation","parsed","blockedReason","parseImportPaste","disabled","goto","id","submit","result","r","ApiError","jsxs","Modal","jsx","JsonEditor","v"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ImportSpecModal-B7qd1Km2.js","sources":["../src/chrome/ImportSpecModal.tsx"],"sourcesContent":["import { type SpecImportKind, type SpecImportListKeys, parseImportPaste } from \"@w6w/embed/lib\";\nimport { ApiError } from \"@w6w/sdk\";\nimport { JsonEditor } from \"@w6w/ui\";\nimport { useState } from \"react\";\nimport { type SpecImportReferenceReport, useImportSpecMutation } 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 const importMut = useImportSpecMutation(props.project, props.listKeys);\n\n const { parsed, blockedReason } = parseImportPaste(text, kind);\n const disabled = blockedReason !== null || importMut.isPending;\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 (blockedReason !== null || parsed === null || importMut.isPending) return;\n setError(null);\n setUnresolved(null);\n // The parsed paste, forwarded VERBATIM — note 1's mechanism pin (A4).\n importMut.mutate(parsed, {\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 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={(v) => {\n setText(v);\n setUnresolved(null);\n setError(null);\n }}\n minHeight=\"320px\"\n aria-label={`${kind} spec document JSON`}\n />\n </div>\n\n {blockedReason && text !== \"\" && <p className=\"muted small\">{blockedReason}</p>}\n {error && <div className=\"result error\">{error}</div>}\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 <button\n type=\"button\"\n className=\"btn\"\n data-testid={testids.submit}\n disabled={disabled}\n onClick={submit}\n >\n {importMut.isPending ? \"Importing…\" : \"Import\"}\n </button>\n </div>\n </Modal>\n );\n}\n"],"names":["COLLECTION","TESTIDS","ImportSpecModal","props","kind","collection","testids","text","setText","useState","error","setError","unresolved","setUnresolved","importMut","useImportSpecMutation","parsed","blockedReason","parseImportPaste","disabled","goto","id","submit","result","r","ApiError","jsxs","Modal","jsx","JsonEditor","v"],"mappings":";;;;;;;AAQA,MAAMA,IAA8E;AAAA,EAClF,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AACZ,GAQMC,IAGF;AAAA,EACF,UAAU;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,MAAM;AAAA,EAAA;AAAA,EAER,UAAU;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,MAAM;AAAA,EAAA;AAAA,EAER,UAAU;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,MAAM;AAAA,EAAA;AAEV;AAyCO,SAASC,EAAgBC,GAA6B;AAC3D,QAAM,EAAE,MAAAC,MAASD,GACXE,IAAaL,EAAWI,CAAI,GAC5BE,IAAUL,EAAQG,CAAI,GACtB,CAACG,GAAMC,CAAO,IAAIC,EAAS,EAAE,GAC7B,CAACC,GAAOC,CAAQ,IAAIF,EAAwB,IAAI,GAChD,CAACG,GAAYC,CAAa,IAAIJ,EAG1B,IAAI,GACRK,IAAYC,EAAsBZ,EAAM,SAASA,EAAM,QAAQ,GAE/D,EAAE,QAAAa,GAAQ,eAAAC,EAAA,IAAkBC,EAAiBX,GAAMH,CAAI,GACvDe,IAAWF,MAAkB,QAAQH,EAAU;AAErD,WAASM,EAAKC,GAAY;AACxB,IAAAlB,EAAM,QAAA,GACNA,EAAM,eAAeC,GAAMiB,CAAE;AAAA,EAC/B;AAEA,WAASC,IAAS;AAGhB,IAAIL,MAAkB,QAAQD,MAAW,QAAQF,EAAU,cAC3DH,EAAS,IAAI,GACbE,EAAc,IAAI,GAElBC,EAAU,OAAOE,GAAQ;AAAA,MACvB,WAAW,CAACO,MAAW;AAErB,YADoBA,EAAO,WAAW,MAAM,CAACC,MAAMA,EAAE,QAAQ,GAC5C;AACf,UAAAJ,EAAKG,EAAO,SAAS,EAAE;AACvB;AAAA,QACF;AAIA,QAAAV,EAAc;AAAA,UACZ,YAAYU,EAAO,SAAS;AAAA,UAC5B,YAAYA,EAAO,WAAW,OAAO,CAACC,MAAM,CAACA,EAAE,QAAQ;AAAA,QAAA,CACxD;AAAA,MACH;AAAA,MACA,SAAS,CAAC,MAAMb,EAAS,aAAac,IAAW,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IAAA,CACvE;AAAA,EACH;AAEA,SACE,gBAAAC,EAACC,GAAA,EAAM,OAAO,UAAUvB,CAAI,IAAI,SAASD,EAAM,SAAS,MAAI,IAC1D,UAAA;AAAA,IAAA,gBAAAuB,EAAC,OAAA,EAAI,WAAU,cACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,KAAA,EAAE,WAAU,eAAc,UAAA;AAAA,QAAA;AAAA,QACPtB;AAAA,QAAK;AAAA,QAA6B;AAAA,0BACnD,QAAA,EAAK,UAAA;AAAA,UAAA;AAAA,UAAMC;AAAA,UAAW;AAAA,QAAA,GAAS;AAAA,QAAO;AAAA,MAAA,GAGzC;AAAA,MAEA,gBAAAuB,EAAC,OAAA,EAAI,eAAatB,EAAQ,MACxB,UAAA,gBAAAsB;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,OAAOtB;AAAA,UACP,UAAU,CAACuB,MAAM;AACf,YAAAtB,EAAQsB,CAAC,GACTjB,EAAc,IAAI,GAClBF,EAAS,IAAI;AAAA,UACf;AAAA,UACA,WAAU;AAAA,UACV,cAAY,GAAGP,CAAI;AAAA,QAAA;AAAA,MAAA,GAEvB;AAAA,MAECa,KAAiBV,MAAS,wBAAO,KAAA,EAAE,WAAU,eAAe,UAAAU,GAAc;AAAA,MAC1EP,KAAS,gBAAAkB,EAAC,OAAA,EAAI,WAAU,gBAAgB,UAAAlB,GAAM;AAAA,MAE9CE,KACC,gBAAAc,EAAC,OAAA,EAAI,WAAU,UAAS,eAAapB,EAAQ,YAC3C,UAAA;AAAA,QAAA,gBAAAoB,EAAC,KAAA,EAAE,UAAA;AAAA,UAAA;AAAA,UACItB;AAAA,UAAK;AAAA,UAAmBQ,EAAW,WAAW;AAAA,UAAO;AAAA,UACzDA,EAAW,WAAW,WAAW,IAAI,KAAK;AAAA,UAAI;AAAA,QAAA,GACjD;AAAA,QACA,gBAAAgB,EAAC,MAAA,EAAG,WAAU,QACX,UAAAhB,EAAW,WAAW,IAAI,CAACY,MAC1B,gBAAAE,EAAC,MAAA,EACC,UAAA;AAAA,UAAA,gBAAAE,EAAC,QAAA,EAAM,YAAE,KAAA,CAAK;AAAA,UAAO;AAAA,UAAC,gBAAAF,EAAC,QAAA,EAAK,WAAU,SAAQ,UAAA;AAAA,YAAA;AAAA,YAAEF,EAAE;AAAA,YAAK;AAAA,UAAA,GAAC;AAAA,UACvDA,EAAE,UAAU,gBAAAE,EAAC,QAAA,EAAK,WAAU,SAAQ,UAAA;AAAA,YAAA;AAAA,YAAIF,EAAE;AAAA,UAAA,EAAA,CAAO;AAAA,QAAA,EAAA,GAF3CA,EAAE,IAGX,CACD,GACH;AAAA,QACA,gBAAAE;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,eAAapB,EAAQ;AAAA,YACrB,SAAS,MAAMc,EAAKR,EAAW,UAAU;AAAA,YAC1C,UAAA;AAAA,cAAA;AAAA,cACmBR;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MACpB,EAAA,CACF;AAAA,IAAA,GAEJ;AAAA,IAEA,gBAAAsB,EAAC,OAAA,EAAI,WAAU,iBACb,UAAA;AAAA,MAAA,gBAAAE,EAAC,UAAA,EAAO,MAAK,UAAS,WAAU,aAAY,SAASzB,EAAM,SAAS,UAAA,SAAA,CAEpE;AAAA,MACA,gBAAAyB;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,eAAatB,EAAQ;AAAA,UACrB,UAAAa;AAAA,UACA,SAASG;AAAA,UAER,UAAAR,EAAU,YAAY,eAAe;AAAA,QAAA;AAAA,MAAA;AAAA,IACxC,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { jsx as t, jsxs as l, Fragment as U } from "react/jsx-runtime";
|
|
2
|
+
import { ApiError as W } from "@w6w/sdk";
|
|
3
|
+
import { EmptyState as B, DataTable as K, EditButton as Y, DeleteButton as q, useEnterSubmit as z } from "@w6w/ui";
|
|
4
|
+
import { useState as h } from "react";
|
|
5
|
+
import { C as G, M as J } from "./ConfirmModal-BE-SdX-O.js";
|
|
6
|
+
import { u as V } from "./project-context-Tvp-La7A.js";
|
|
7
|
+
import { u as X } from "./connections-D7cgXhDS.js";
|
|
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
|
+
const L = {
|
|
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."
|
|
11
|
+
};
|
|
12
|
+
function H(e) {
|
|
13
|
+
return e instanceof W ? Object.hasOwn(L, e.code) ? L[e.code] : e.message : e instanceof Error ? e.message : String(e);
|
|
14
|
+
}
|
|
15
|
+
function O(e) {
|
|
16
|
+
const a = e.fallbacks.length, i = a === 0 ? "" : ` · ${a} fallback${a === 1 ? "" : "s"}`;
|
|
17
|
+
return `${e.modelId} via ${e.connectionId}${i}`;
|
|
18
|
+
}
|
|
19
|
+
function ge(e) {
|
|
20
|
+
var I;
|
|
21
|
+
const a = V(e.projectId), [i, c] = h(
|
|
22
|
+
() => e.initialEditRouteId ? { routeId: e.initialEditRouteId, connection: e.initialConnection } : null
|
|
23
|
+
), [s, b] = h(null), [r, n] = h(null), u = Z(a ?? void 0), g = ee(), f = u.data ?? [], M = a != null, C = (i == null ? void 0 : i.routeId) == null ? void 0 : f.find((o) => o.id === i.routeId), E = i != null && (i.routeId == null || C != null), y = [
|
|
24
|
+
{
|
|
25
|
+
key: "name",
|
|
26
|
+
header: "Route",
|
|
27
|
+
render: (o) => /* @__PURE__ */ l("div", { className: "list-main", style: { maxWidth: 0, minWidth: "100%" }, children: [
|
|
28
|
+
/* @__PURE__ */ t("strong", { className: "list-name", title: o.name, children: o.name }),
|
|
29
|
+
" ",
|
|
30
|
+
/* @__PURE__ */ t("span", { className: o.status === "broken" ? "tag warn" : "tag", children: o.status }),
|
|
31
|
+
/* @__PURE__ */ t("div", { className: "muted small list-preview", title: O(o), children: O(o) })
|
|
32
|
+
] })
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "connection",
|
|
36
|
+
header: "Connection",
|
|
37
|
+
render: (o) => /* @__PURE__ */ t("code", { children: o.connectionId })
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: "actions",
|
|
41
|
+
header: "",
|
|
42
|
+
align: "right",
|
|
43
|
+
link: !1,
|
|
44
|
+
render: (o) => /* @__PURE__ */ l("div", { style: { display: "flex", gap: "var(--w6w-sp-1-5)" }, children: [
|
|
45
|
+
/* @__PURE__ */ t(
|
|
46
|
+
Y,
|
|
47
|
+
{
|
|
48
|
+
label: "Edit",
|
|
49
|
+
onClick: () => c({ routeId: o.id }),
|
|
50
|
+
"data-testid": `model-route-edit-${o.name}`
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
/* @__PURE__ */ t(
|
|
54
|
+
q,
|
|
55
|
+
{
|
|
56
|
+
label: "Delete",
|
|
57
|
+
onClick: () => b(o),
|
|
58
|
+
disabled: g.isPending,
|
|
59
|
+
"data-testid": `model-route-delete-${o.name}`
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
] })
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
return /* @__PURE__ */ t("div", { className: "w6w-embed-root", children: /* @__PURE__ */ l("section", { className: "section", children: [
|
|
66
|
+
/* @__PURE__ */ l("div", { className: "section-head", children: [
|
|
67
|
+
/* @__PURE__ */ l("div", { children: [
|
|
68
|
+
/* @__PURE__ */ t("h3", { children: "Model routes" }),
|
|
69
|
+
/* @__PURE__ */ t("p", { className: "muted small", children: "The names callers ask for. Each route resolves to a model through a connection, with fallbacks when that model cannot answer." })
|
|
70
|
+
] }),
|
|
71
|
+
/* @__PURE__ */ t(
|
|
72
|
+
"button",
|
|
73
|
+
{
|
|
74
|
+
type: "button",
|
|
75
|
+
className: "btn",
|
|
76
|
+
disabled: !M,
|
|
77
|
+
onClick: () => c({ routeId: null }),
|
|
78
|
+
"data-testid": "model-route-add",
|
|
79
|
+
children: "+ Add route"
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
] }),
|
|
83
|
+
r && /* @__PURE__ */ t("div", { className: "result error", role: "alert", "data-testid": "model-route-delete-error", children: r }),
|
|
84
|
+
/* @__PURE__ */ l("div", { className: "card", children: [
|
|
85
|
+
u.isLoading && /* @__PURE__ */ t("p", { className: "muted", children: "Loading…" }),
|
|
86
|
+
((I = u.data) == null ? void 0 : I.length) === 0 && /* @__PURE__ */ t(B, { testId: "model-routes-empty", children: "No model routes yet. Add one to give callers a stable name for a model." }),
|
|
87
|
+
f.length > 0 && /* @__PURE__ */ t(
|
|
88
|
+
K,
|
|
89
|
+
{
|
|
90
|
+
columns: y,
|
|
91
|
+
rows: f,
|
|
92
|
+
rowKey: (o) => o.id,
|
|
93
|
+
testId: "model-routes-table"
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
] }),
|
|
97
|
+
E && a != null && i != null && /* @__PURE__ */ t(
|
|
98
|
+
ie,
|
|
99
|
+
{
|
|
100
|
+
project: a,
|
|
101
|
+
initial: C,
|
|
102
|
+
initialConnection: i.connection,
|
|
103
|
+
onClose: () => c(null),
|
|
104
|
+
onSaved: () => c(null)
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
s != null && a != null && /* @__PURE__ */ t(
|
|
108
|
+
G,
|
|
109
|
+
{
|
|
110
|
+
title: "Delete model route",
|
|
111
|
+
message: `Delete the model route "${s.name}"? Calls that name it will fail until another route covers the model.`,
|
|
112
|
+
confirmLabel: "Delete",
|
|
113
|
+
onConfirm: () => {
|
|
114
|
+
const o = s.name;
|
|
115
|
+
n(null), g.mutate(
|
|
116
|
+
{ project: a, name: o },
|
|
117
|
+
{
|
|
118
|
+
onError: (N) => n(`Could not delete "${o}": ${H(N)}`)
|
|
119
|
+
}
|
|
120
|
+
), b(null);
|
|
121
|
+
},
|
|
122
|
+
onClose: () => b(null)
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
] }) });
|
|
126
|
+
}
|
|
127
|
+
function ie(e) {
|
|
128
|
+
var D, A, Q, F, T;
|
|
129
|
+
const a = !!e.initial, [i, c] = h(((D = e.initial) == null ? void 0 : D.name) ?? ""), [s, b] = h(((A = e.initial) == null ? void 0 : A.modelId) ?? ""), [r, n] = h(
|
|
130
|
+
e.initialConnection ?? ((Q = e.initial) == null ? void 0 : Q.connectionId) ?? ""
|
|
131
|
+
), [u, g] = h(((F = e.initial) == null ? void 0 : F.fallbacks) ?? []), [f, M] = h(null), C = te({ status: "active" }), E = X(), y = ((T = C.data) == null ? void 0 : T.models) ?? [], I = ne(), o = oe(
|
|
132
|
+
E.data ?? [],
|
|
133
|
+
I.data ?? [],
|
|
134
|
+
"complete"
|
|
135
|
+
), N = C.isSuccess && y.length === 0, p = le(), x = ae(), R = p.isPending || x.isPending, P = !!i && !!s && !!r && u.every((d) => !!d.model && !!d.connection) && !R;
|
|
136
|
+
function j() {
|
|
137
|
+
M(null);
|
|
138
|
+
const d = {
|
|
139
|
+
onSuccess: () => e.onSaved(),
|
|
140
|
+
onError: (m) => M(H(m))
|
|
141
|
+
};
|
|
142
|
+
if (e.initial) {
|
|
143
|
+
x.mutate(
|
|
144
|
+
{
|
|
145
|
+
project: e.project,
|
|
146
|
+
name: e.initial.name,
|
|
147
|
+
patch: { model: s, connection: r, fallbacks: u }
|
|
148
|
+
},
|
|
149
|
+
d
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
p.mutate(
|
|
154
|
+
{
|
|
155
|
+
project: e.project,
|
|
156
|
+
input: { name: i, model: s, connection: r, ...u.length > 0 ? { fallbacks: u } : {} }
|
|
157
|
+
},
|
|
158
|
+
d
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const w = z(j, { enabled: P });
|
|
162
|
+
return /* @__PURE__ */ l(
|
|
163
|
+
J,
|
|
164
|
+
{
|
|
165
|
+
title: e.initial ? `Edit ${e.initial.name}` : "Add model route",
|
|
166
|
+
onClose: e.onClose,
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ l("div", { className: "modal-body", children: [
|
|
169
|
+
/* @__PURE__ */ l("label", { className: "field", children: [
|
|
170
|
+
/* @__PURE__ */ t("span", { children: "Name" }),
|
|
171
|
+
/* @__PURE__ */ t(
|
|
172
|
+
"input",
|
|
173
|
+
{
|
|
174
|
+
type: "text",
|
|
175
|
+
value: i,
|
|
176
|
+
disabled: a,
|
|
177
|
+
onChange: (d) => c(d.target.value),
|
|
178
|
+
placeholder: "e.g. gpt-4o-fast",
|
|
179
|
+
maxLength: 64,
|
|
180
|
+
"data-testid": "model-route-name",
|
|
181
|
+
...w
|
|
182
|
+
}
|
|
183
|
+
),
|
|
184
|
+
!a && /* @__PURE__ */ t("span", { className: "hint", children: "3 to 39 characters: lowercase letters, digits and dashes, starting with a letter, no double dashes, not ending in a dash. Callers use this name; it cannot be renamed later." })
|
|
185
|
+
] }),
|
|
186
|
+
N && /* @__PURE__ */ t(B, { testId: "model-route-catalog-empty", children: "The model catalog is empty. Open the Catalog tab to discover models; until then you can type ids by hand." }),
|
|
187
|
+
/* @__PURE__ */ t(
|
|
188
|
+
_,
|
|
189
|
+
{
|
|
190
|
+
label: "",
|
|
191
|
+
model: s,
|
|
192
|
+
connection: r,
|
|
193
|
+
onModel: b,
|
|
194
|
+
onConnection: n,
|
|
195
|
+
models: y,
|
|
196
|
+
connections: o,
|
|
197
|
+
catalogEmpty: N,
|
|
198
|
+
testIdPrefix: "model-route",
|
|
199
|
+
enterSubmit: w
|
|
200
|
+
}
|
|
201
|
+
),
|
|
202
|
+
/* @__PURE__ */ t("span", { className: "hint", children: "The connection holds the credentials for the model. Changing it fixes a broken route." }),
|
|
203
|
+
/* @__PURE__ */ l("div", { className: "field", children: [
|
|
204
|
+
/* @__PURE__ */ t("span", { children: "Fallbacks" }),
|
|
205
|
+
u.map((d, m) => (
|
|
206
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: rows have no identity beyond position
|
|
207
|
+
/* @__PURE__ */ l("div", { style: { display: "flex", gap: "var(--w6w-sp-1-5)" }, children: [
|
|
208
|
+
/* @__PURE__ */ t(
|
|
209
|
+
_,
|
|
210
|
+
{
|
|
211
|
+
label: `Fallback ${m + 1} `,
|
|
212
|
+
model: d.model,
|
|
213
|
+
connection: d.connection,
|
|
214
|
+
onModel: (k) => g(($) => $.map((v, S) => S === m ? { ...v, model: k } : v)),
|
|
215
|
+
onConnection: (k) => g(($) => $.map((v, S) => S === m ? { ...v, connection: k } : v)),
|
|
216
|
+
models: y,
|
|
217
|
+
connections: o,
|
|
218
|
+
catalogEmpty: N,
|
|
219
|
+
testIdPrefix: `model-route-fallback-${m}`,
|
|
220
|
+
enterSubmit: w
|
|
221
|
+
}
|
|
222
|
+
),
|
|
223
|
+
/* @__PURE__ */ t(
|
|
224
|
+
"button",
|
|
225
|
+
{
|
|
226
|
+
type: "button",
|
|
227
|
+
className: "btn ghost",
|
|
228
|
+
onClick: () => g((k) => k.filter(($, v) => v !== m)),
|
|
229
|
+
"data-testid": `model-route-fallback-${m}-remove`,
|
|
230
|
+
children: "Remove"
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
] }, m)
|
|
234
|
+
)),
|
|
235
|
+
/* @__PURE__ */ t(
|
|
236
|
+
"button",
|
|
237
|
+
{
|
|
238
|
+
type: "button",
|
|
239
|
+
className: "btn ghost",
|
|
240
|
+
onClick: () => g((d) => [...d, { model: "", connection: "" }]),
|
|
241
|
+
"data-testid": "model-route-fallback-add",
|
|
242
|
+
children: "+ Add fallback"
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
] }),
|
|
246
|
+
f && /* @__PURE__ */ t("div", { className: "result error", "data-testid": "model-route-error", children: f })
|
|
247
|
+
] }),
|
|
248
|
+
/* @__PURE__ */ l("div", { className: "modal-actions", children: [
|
|
249
|
+
/* @__PURE__ */ t("button", { type: "button", className: "btn ghost", onClick: e.onClose, children: "Cancel" }),
|
|
250
|
+
/* @__PURE__ */ t(
|
|
251
|
+
"button",
|
|
252
|
+
{
|
|
253
|
+
type: "button",
|
|
254
|
+
className: "btn",
|
|
255
|
+
disabled: !P,
|
|
256
|
+
onClick: j,
|
|
257
|
+
"data-testid": "model-route-save",
|
|
258
|
+
children: R ? "Saving…" : a ? "Save changes" : "Save route"
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
] })
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
function _(e) {
|
|
267
|
+
const a = e.models.find((n) => n.id === e.model), i = a ? e.connections.filter((n) => n.appId === a.providerAppId) : e.connections, c = a != null && i.length > 0, s = c ? i : e.connections, b = s.some((n) => n.id === e.connection), r = e.models.some((n) => n.id === e.model);
|
|
268
|
+
return /* @__PURE__ */ l(U, { children: [
|
|
269
|
+
/* @__PURE__ */ l("div", { className: "field", children: [
|
|
270
|
+
/* @__PURE__ */ l("span", { children: [
|
|
271
|
+
e.label,
|
|
272
|
+
"Model"
|
|
273
|
+
] }),
|
|
274
|
+
e.catalogEmpty ? /* @__PURE__ */ t(
|
|
275
|
+
"input",
|
|
276
|
+
{
|
|
277
|
+
type: "text",
|
|
278
|
+
value: e.model,
|
|
279
|
+
onChange: (n) => e.onModel(n.target.value),
|
|
280
|
+
placeholder: "model id",
|
|
281
|
+
"aria-label": `${e.label}Model`,
|
|
282
|
+
"data-testid": `${e.testIdPrefix}-model`,
|
|
283
|
+
...e.enterSubmit
|
|
284
|
+
}
|
|
285
|
+
) : /* @__PURE__ */ l(
|
|
286
|
+
"select",
|
|
287
|
+
{
|
|
288
|
+
value: e.model,
|
|
289
|
+
onChange: (n) => e.onModel(n.target.value),
|
|
290
|
+
"aria-label": `${e.label}Model`,
|
|
291
|
+
"data-testid": `${e.testIdPrefix}-model`,
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ t("option", { value: "", children: "Select a model…" }),
|
|
294
|
+
e.model && !r && /* @__PURE__ */ t("option", { value: e.model, children: e.model }),
|
|
295
|
+
e.models.map((n) => /* @__PURE__ */ l("option", { value: n.id, children: [
|
|
296
|
+
n.displayName,
|
|
297
|
+
" (",
|
|
298
|
+
n.provider,
|
|
299
|
+
")"
|
|
300
|
+
] }, n.id))
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
] }),
|
|
305
|
+
/* @__PURE__ */ l("div", { className: "field", children: [
|
|
306
|
+
/* @__PURE__ */ l("span", { children: [
|
|
307
|
+
e.label,
|
|
308
|
+
"Connection"
|
|
309
|
+
] }),
|
|
310
|
+
e.catalogEmpty && e.connections.length === 0 ? /* @__PURE__ */ t(
|
|
311
|
+
"input",
|
|
312
|
+
{
|
|
313
|
+
type: "text",
|
|
314
|
+
value: e.connection,
|
|
315
|
+
onChange: (n) => e.onConnection(n.target.value),
|
|
316
|
+
placeholder: "connection id",
|
|
317
|
+
"aria-label": `${e.label}Connection`,
|
|
318
|
+
"data-testid": `${e.testIdPrefix}-connection`,
|
|
319
|
+
...e.enterSubmit
|
|
320
|
+
}
|
|
321
|
+
) : /* @__PURE__ */ l(
|
|
322
|
+
"select",
|
|
323
|
+
{
|
|
324
|
+
value: e.connection,
|
|
325
|
+
onChange: (n) => e.onConnection(n.target.value),
|
|
326
|
+
"aria-label": `${e.label}Connection`,
|
|
327
|
+
"data-testid": `${e.testIdPrefix}-connection`,
|
|
328
|
+
children: [
|
|
329
|
+
/* @__PURE__ */ t("option", { value: "", children: "Select a connection…" }),
|
|
330
|
+
e.connection && !b && /* @__PURE__ */ t("option", { value: e.connection, children: e.connection }),
|
|
331
|
+
s.map((n) => /* @__PURE__ */ l("option", { value: n.id, disabled: n.disabledReason != null, children: [
|
|
332
|
+
n.displayName,
|
|
333
|
+
c ? "" : ` (${n.appId})`,
|
|
334
|
+
n.disabledReason != null ? ` — ${n.disabledReason}` : ""
|
|
335
|
+
] }, n.id))
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
] })
|
|
340
|
+
] });
|
|
341
|
+
}
|
|
342
|
+
export {
|
|
343
|
+
ge as M
|
|
344
|
+
};
|
|
345
|
+
//# sourceMappingURL=ModelRoutesManager-BGESQahw.js.map
|
|
@@ -0,0 +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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"}
|