@burdenoff/microfe-botmanor 2026.1031.1 → 2026.1101.1

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.
@@ -12,13 +12,14 @@ import { FormField as p, Input as m, Textarea as h } from "../components/Input.j
12
12
  import { ErrorState as g } from "../components/ErrorState.js";
13
13
  import { promptTemplateVariables as _, usePromptTemplates as v, useRenderPromptTemplate as y } from "../hooks/usePromptTemplates.js";
14
14
  import "../hooks/index.js";
15
- import { useEffect as b, useMemo as x, useState as S } from "react";
16
- import { GlassCard as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
17
- import { jsx as T, jsxs as E } from "react/jsx-runtime";
18
- import { Play as D, Plus as O, Tag as k } from "lucide-react";
19
- import { toast as A } from "sonner";
15
+ import { graphqlErrorMessage as b } from "../utils/errors.js";
16
+ import { useEffect as x, useMemo as S, useState as C } from "react";
17
+ import { GlassCard as w, PagePurpose as T } from "@burdenoff/fe-libs/ui";
18
+ import { jsx as E, jsxs as D } from "react/jsx-runtime";
19
+ import { Play as O, Plus as k, Tag as A } from "lucide-react";
20
+ import { toast as j } from "sonner";
20
21
  //#region src/botlit/pages/PromptStudioPage.tsx
21
- function j(e) {
22
+ function M(e) {
22
23
  if (!e || typeof e != "object" || Array.isArray(e)) return null;
23
24
  let t = e, n = typeof t.name == "string" ? t.name : void 0;
24
25
  return n ? {
@@ -29,91 +30,91 @@ function j(e) {
29
30
  defaultValue: t.defaultValue
30
31
  } : null;
31
32
  }
32
- function M(e) {
33
- return e ? _(e).map(j).filter((e) => e !== null) : [];
33
+ function N(e) {
34
+ return e ? _(e).map(M).filter((e) => e !== null) : [];
34
35
  }
35
- var N = () => {
36
- let { navigateTo: _ } = e(), { data: j, loading: N, error: P, refetch: F } = v(), { render: I, loading: L } = y(), [R, z] = S(null), [B, V] = S({}), [H, U] = S("");
37
- b(() => {
38
- !R && j.length > 0 && z(j[0].id);
39
- }, [j, R]);
40
- let W = x(() => j.find((e) => e.id === R), [j, R]), G = x(() => M(W), [W]), K = async () => {
41
- if (W) try {
42
- U(await I({
43
- templateId: W.id,
44
- variables: B
36
+ var P = () => {
37
+ let { navigateTo: _ } = e(), { data: M, loading: P, error: F, refetch: I } = v(), { render: L, loading: R } = y(), [z, B] = C(null), [V, H] = C({}), [U, W] = C("");
38
+ x(() => {
39
+ !z && M.length > 0 && B(M[0].id);
40
+ }, [M, z]);
41
+ let G = S(() => M.find((e) => e.id === z), [M, z]), K = S(() => N(G), [G]), q = async () => {
42
+ if (G) try {
43
+ W(await L({
44
+ templateId: G.id,
45
+ variables: V
45
46
  }));
46
47
  } catch (e) {
47
- A.error(e instanceof Error ? e.message : "Failed to render prompt");
48
+ j.error(b(e, "Failed to render prompt"));
48
49
  }
49
50
  };
50
- return /* @__PURE__ */ T(i, {
51
+ return /* @__PURE__ */ E(i, {
51
52
  title: "Prompt Studio",
52
53
  description: "Create, test, and manage prompts for your AI agents",
53
- actions: /* @__PURE__ */ T(r, {
54
+ actions: /* @__PURE__ */ E(r, {
54
55
  permission: n.PROMPT_TEMPLATE_CREATE,
55
- children: /* @__PURE__ */ T(a, {
56
- leftIcon: /* @__PURE__ */ T(O, { size: 16 }),
56
+ children: /* @__PURE__ */ E(a, {
57
+ leftIcon: /* @__PURE__ */ E(k, { size: 16 }),
57
58
  onClick: () => _("prompt-templates/new"),
58
59
  children: "New Prompt"
59
60
  })
60
61
  }),
61
- children: /* @__PURE__ */ E("div", {
62
+ children: /* @__PURE__ */ D("div", {
62
63
  className: "space-y-6",
63
- children: [/* @__PURE__ */ T(w, {
64
- icon: /* @__PURE__ */ T(D, { size: 18 }),
64
+ children: [/* @__PURE__ */ E(T, {
65
+ icon: /* @__PURE__ */ E(O, { size: 18 }),
65
66
  children: "Prompt Studio is your interactive workbench for writing and testing prompts before they go live. Pick a prompt, edit its text and variables on the left, then fill in sample values and hit Run Test to preview exactly what the agent will receive — so you can iterate on wording and catch mistakes here instead of in production."
66
- }), /* @__PURE__ */ E("div", {
67
+ }), /* @__PURE__ */ D("div", {
67
68
  className: "grid grid-cols-12 gap-6",
68
69
  children: [
69
- /* @__PURE__ */ T("div", {
70
+ /* @__PURE__ */ E("div", {
70
71
  className: "col-span-3",
71
- children: /* @__PURE__ */ E(o, { children: [/* @__PURE__ */ T(l, { children: /* @__PURE__ */ T(u, {
72
+ children: /* @__PURE__ */ D(o, { children: [/* @__PURE__ */ E(l, { children: /* @__PURE__ */ E(u, {
72
73
  className: "text-base",
73
74
  children: "Prompts"
74
- }) }), /* @__PURE__ */ T(s, {
75
+ }) }), /* @__PURE__ */ E(s, {
75
76
  className: "p-0",
76
- children: N ? /* @__PURE__ */ T("div", {
77
+ children: P ? /* @__PURE__ */ E("div", {
77
78
  className: "space-y-2 p-4",
78
79
  children: [
79
80
  1,
80
81
  2,
81
82
  3
82
- ].map((e) => /* @__PURE__ */ T("div", { className: "h-14 bg-bg-sunken motion-safe:animate-vc-shimmer rounded" }, e))
83
- }) : P ? /* @__PURE__ */ T(g, {
83
+ ].map((e) => /* @__PURE__ */ E("div", { className: "h-14 bg-bg-sunken motion-safe:animate-vc-shimmer rounded" }, e))
84
+ }) : F ? /* @__PURE__ */ E(g, {
84
85
  resource: "prompt templates",
85
- error: P,
86
- onRetry: () => void F(),
86
+ error: F,
87
+ onRetry: () => void I(),
87
88
  className: "m-4"
88
- }) : j.length === 0 ? /* @__PURE__ */ T("p", {
89
+ }) : M.length === 0 ? /* @__PURE__ */ E("p", {
89
90
  className: "p-4 text-sm text-text-secondary",
90
91
  children: "No prompt templates yet. Create one to start iterating."
91
- }) : /* @__PURE__ */ T("div", {
92
+ }) : /* @__PURE__ */ E("div", {
92
93
  className: "divide-y divide-border-subtle",
93
- children: j.map((e) => /* @__PURE__ */ E("button", {
94
+ children: M.map((e) => /* @__PURE__ */ D("button", {
94
95
  type: "button",
95
- className: `w-full text-left p-4 hover:bg-accent transition-colors ${W?.id === e.id ? "bg-accent" : ""}`,
96
+ className: `w-full text-left p-4 hover:bg-accent transition-colors ${G?.id === e.id ? "bg-accent" : ""}`,
96
97
  onClick: () => {
97
- z(e.id), V({}), U("");
98
+ B(e.id), H({}), W("");
98
99
  },
99
100
  children: [
100
- /* @__PURE__ */ T("p", {
101
+ /* @__PURE__ */ E("p", {
101
102
  className: "font-medium truncate",
102
103
  children: e.name
103
104
  }),
104
- /* @__PURE__ */ E("p", {
105
+ /* @__PURE__ */ D("p", {
105
106
  className: "text-xs text-text-secondary mt-1 truncate",
106
107
  children: ["v", e.version]
107
108
  }),
108
- /* @__PURE__ */ E("div", {
109
+ /* @__PURE__ */ D("div", {
109
110
  className: "flex items-center gap-2 mt-2",
110
- children: [e.visibility === "PUBLIC" && /* @__PURE__ */ T(d, {
111
+ children: [e.visibility === "PUBLIC" && /* @__PURE__ */ E(d, {
111
112
  variant: "secondary",
112
113
  className: "text-[10px]",
113
114
  children: "Public"
114
- }), /* @__PURE__ */ E("span", {
115
+ }), /* @__PURE__ */ D("span", {
115
116
  className: "text-xs text-text-secondary",
116
- children: [M(e).length, " vars"]
117
+ children: [N(e).length, " vars"]
117
118
  })]
118
119
  })
119
120
  ]
@@ -121,115 +122,115 @@ var N = () => {
121
122
  })
122
123
  })] })
123
124
  }),
124
- /* @__PURE__ */ T("div", {
125
+ /* @__PURE__ */ E("div", {
125
126
  className: "col-span-6",
126
- children: W ? /* @__PURE__ */ E(C, {
127
+ children: G ? /* @__PURE__ */ D(w, {
127
128
  treatment: "glass",
128
129
  glow: !0,
129
130
  className: "overflow-hidden",
130
- children: [/* @__PURE__ */ E(l, {
131
+ children: [/* @__PURE__ */ D(l, {
131
132
  className: "flex flex-row items-center justify-between",
132
- children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T(u, { children: W.name }), /* @__PURE__ */ T(c, { children: W.description })] }), /* @__PURE__ */ T(a, {
133
+ children: [/* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E(u, { children: G.name }), /* @__PURE__ */ E(c, { children: G.description })] }), /* @__PURE__ */ E(a, {
133
134
  size: "sm",
134
135
  variant: "outline",
135
- onClick: () => _(`prompt-templates/${W.id}`),
136
+ onClick: () => _(`prompt-templates/${G.id}`),
136
137
  children: "Open template"
137
138
  })]
138
- }), /* @__PURE__ */ E(s, {
139
+ }), /* @__PURE__ */ D(s, {
139
140
  className: "space-y-4",
140
141
  children: [
141
- /* @__PURE__ */ E("div", {
142
+ /* @__PURE__ */ D("div", {
142
143
  className: "flex items-center gap-2",
143
- children: [/* @__PURE__ */ T(k, {
144
+ children: [/* @__PURE__ */ E(A, {
144
145
  size: 14,
145
146
  className: "text-text-secondary"
146
- }), W.tags.map((e) => /* @__PURE__ */ T(d, {
147
+ }), G.tags.map((e) => /* @__PURE__ */ E(d, {
147
148
  variant: "secondary",
148
149
  children: e
149
150
  }, e))]
150
151
  }),
151
- /* @__PURE__ */ T(p, {
152
+ /* @__PURE__ */ E(p, {
152
153
  label: "Prompt Content",
153
- children: /* @__PURE__ */ T(h, {
154
- value: W.templateText,
154
+ children: /* @__PURE__ */ E(h, {
155
+ value: G.templateText,
155
156
  rows: 15,
156
157
  readOnly: !0,
157
158
  className: "font-mono text-sm"
158
159
  })
159
160
  }),
160
- G.length > 0 && /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
161
+ K.length > 0 && /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("p", {
161
162
  className: "text-sm font-medium mb-2",
162
163
  children: "Variables"
163
- }), /* @__PURE__ */ T("div", {
164
+ }), /* @__PURE__ */ E("div", {
164
165
  className: "space-y-2",
165
- children: G.map((e) => /* @__PURE__ */ E("div", {
166
+ children: K.map((e) => /* @__PURE__ */ D("div", {
166
167
  className: "flex items-center gap-4 p-3 bg-bg-sunken rounded-lg",
167
- children: [/* @__PURE__ */ E("div", {
168
+ children: [/* @__PURE__ */ D("div", {
168
169
  className: "flex-1",
169
- children: [/* @__PURE__ */ E("p", {
170
+ children: [/* @__PURE__ */ D("p", {
170
171
  className: "font-medium text-sm",
171
- children: [`{{${e.name}}}`, e.required && /* @__PURE__ */ T("span", {
172
+ children: [`{{${e.name}}}`, e.required && /* @__PURE__ */ E("span", {
172
173
  className: "text-status-error-text ml-1",
173
174
  children: "*"
174
175
  })]
175
- }), e.description && /* @__PURE__ */ T("p", {
176
+ }), e.description && /* @__PURE__ */ E("p", {
176
177
  className: "text-xs text-text-secondary",
177
178
  children: e.description
178
179
  })]
179
- }), /* @__PURE__ */ T(d, {
180
+ }), /* @__PURE__ */ E(d, {
180
181
  variant: "outline",
181
182
  className: "capitalize",
182
183
  children: e.type
183
184
  })]
184
185
  }, e.name))
185
186
  })] }),
186
- /* @__PURE__ */ E("div", {
187
+ /* @__PURE__ */ D("div", {
187
188
  className: "pt-4 text-xs text-text-secondary",
188
- children: ["Updated ", t(W.updatedAt)]
189
+ children: ["Updated ", t(G.updatedAt)]
189
190
  })
190
191
  ]
191
192
  })]
192
- }) : /* @__PURE__ */ T(f, {
193
+ }) : /* @__PURE__ */ E(f, {
193
194
  illustration: "onboarding",
194
195
  title: "Select a prompt",
195
196
  description: "Choose a prompt from the list to view and edit"
196
197
  })
197
198
  }),
198
- /* @__PURE__ */ T("div", {
199
+ /* @__PURE__ */ E("div", {
199
200
  className: "col-span-3",
200
- children: /* @__PURE__ */ E(o, { children: [/* @__PURE__ */ T(l, { children: /* @__PURE__ */ E(u, {
201
+ children: /* @__PURE__ */ D(o, { children: [/* @__PURE__ */ E(l, { children: /* @__PURE__ */ D(u, {
201
202
  className: "text-base flex items-center gap-2",
202
- children: [/* @__PURE__ */ T(D, { size: 16 }), "Test Prompt"]
203
- }) }), /* @__PURE__ */ E(s, {
203
+ children: [/* @__PURE__ */ E(O, { size: 16 }), "Test Prompt"]
204
+ }) }), /* @__PURE__ */ D(s, {
204
205
  className: "space-y-4",
205
206
  children: [
206
- G.map((e) => /* @__PURE__ */ T(p, {
207
+ K.map((e) => /* @__PURE__ */ E(p, {
207
208
  label: e.name,
208
- children: /* @__PURE__ */ T(m, {
209
+ children: /* @__PURE__ */ E(m, {
209
210
  placeholder: e.description || `Enter ${e.name}`,
210
- value: B[e.name] || "",
211
- onChange: (t) => V({
212
- ...B,
211
+ value: V[e.name] || "",
212
+ onChange: (t) => H({
213
+ ...V,
213
214
  [e.name]: t.target.value
214
215
  })
215
216
  })
216
217
  }, e.name)),
217
- /* @__PURE__ */ T(r, {
218
+ /* @__PURE__ */ E(r, {
218
219
  permission: n.PROMPT_TEMPLATE_EXECUTE,
219
- children: /* @__PURE__ */ T(a, {
220
+ children: /* @__PURE__ */ E(a, {
220
221
  className: "w-full",
221
- onClick: () => void K(),
222
- isLoading: L,
223
- disabled: !W,
222
+ onClick: () => void q(),
223
+ isLoading: R,
224
+ disabled: !G,
224
225
  children: "Run Test"
225
226
  })
226
227
  }),
227
- H && /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
228
+ U && /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("p", {
228
229
  className: "text-sm font-medium mb-2",
229
230
  children: "Output"
230
- }), /* @__PURE__ */ T("div", {
231
+ }), /* @__PURE__ */ E("div", {
231
232
  className: "p-3 bg-bg-sunken rounded-lg text-sm whitespace-pre-wrap font-mono max-h-64 overflow-auto",
232
- children: H
233
+ children: U
233
234
  })] })
234
235
  ]
235
236
  })] })
@@ -240,6 +241,6 @@ var N = () => {
240
241
  });
241
242
  };
242
243
  //#endregion
243
- export { N as PromptStudioPage };
244
+ export { P as PromptStudioPage };
244
245
 
245
246
  //# sourceMappingURL=PromptStudioPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PromptStudioPage.js","names":[],"sources":["../../../src/botlit/pages/PromptStudioPage.tsx"],"sourcesContent":["/**\n * Prompt Studio Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Plus, Play, Tag } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { Badge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n usePromptTemplates,\n useRenderPromptTemplate,\n promptTemplateVariables,\n type PromptTemplateRecord,\n} from '../hooks';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { PromptVariable } from '../types';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\n/** Normalises one entry of a template's free-form `variables` JSON. */\nfunction toPromptVariable(value: unknown): PromptVariable | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n const record = value as Record<string, unknown>;\n const name = typeof record.name === 'string' ? record.name : undefined;\n if (!name) return null;\n const type = typeof record.type === 'string' ? record.type : 'string';\n return {\n name,\n type: type as PromptVariable['type'],\n description: typeof record.description === 'string' ? record.description : undefined,\n required: record.required === true,\n defaultValue: record.defaultValue,\n };\n}\n\nfunction templateVariables(template: PromptTemplateRecord | undefined): PromptVariable[] {\n if (!template) return [];\n return promptTemplateVariables(template)\n .map(toPromptVariable)\n .filter((variable): variable is PromptVariable => variable !== null);\n}\n\nexport const PromptStudioPage: FC = () => {\n const { navigateTo } = useBotlit();\n const { data: templates, loading, error, refetch } = usePromptTemplates();\n const { render, loading: isRunning } = useRenderPromptTemplate();\n\n const [selectedPromptId, setSelectedPromptId] = useState<string | null>(null);\n const [testVariables, setTestVariables] = useState<Record<string, string>>({});\n const [testOutput, setTestOutput] = useState('');\n\n // Select the first template once the list arrives.\n useEffect(() => {\n if (!selectedPromptId && templates.length > 0) {\n setSelectedPromptId(templates[0].id);\n }\n }, [templates, selectedPromptId]);\n\n const selectedPrompt = useMemo(\n () => templates.find((template) => template.id === selectedPromptId),\n [templates, selectedPromptId]\n );\n\n const selectedVariables = useMemo(() => templateVariables(selectedPrompt), [selectedPrompt]);\n\n const handleTest = async () => {\n if (!selectedPrompt) return;\n try {\n // Rendered by wspace-botlit-svc so the preview matches what the agent\n // actually receives — never a client-side string substitution.\n const output = await render({\n templateId: selectedPrompt.id,\n variables: testVariables,\n });\n setTestOutput(output);\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to render prompt');\n }\n };\n\n return (\n <PageLayout\n title=\"Prompt Studio\"\n description=\"Create, test, and manage prompts for your AI agents\"\n actions={\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_CREATE}>\n <Button leftIcon={<Plus size={16} />} onClick={() => navigateTo('prompt-templates/new')}>\n New Prompt\n </Button>\n </BotmanorPermissionGate>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Play size={18} />}>\n Prompt Studio is your interactive workbench for writing and testing prompts before they go\n live. Pick a prompt, edit its text and variables on the left, then fill in sample values\n and hit Run Test to preview exactly what the agent will receive — so you can iterate on\n wording and catch mistakes here instead of in production.\n </PagePurpose>\n\n <div className=\"grid grid-cols-12 gap-6\">\n {/* Prompt List */}\n <div className=\"col-span-3\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Prompts</CardTitle>\n </CardHeader>\n <CardContent className=\"p-0\">\n {loading ? (\n <div className=\"space-y-2 p-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-14 bg-bg-sunken motion-safe:animate-vc-shimmer rounded\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState\n resource=\"prompt templates\"\n error={error}\n onRetry={() => void refetch()}\n className=\"m-4\"\n />\n ) : templates.length === 0 ? (\n <p className=\"p-4 text-sm text-text-secondary\">\n No prompt templates yet. Create one to start iterating.\n </p>\n ) : (\n <div className=\"divide-y divide-border-subtle\">\n {templates.map((prompt: PromptTemplateRecord) => (\n <button\n key={prompt.id}\n type=\"button\"\n className={`w-full text-left p-4 hover:bg-accent transition-colors ${\n selectedPrompt?.id === prompt.id ? 'bg-accent' : ''\n }`}\n onClick={() => {\n setSelectedPromptId(prompt.id);\n setTestVariables({});\n setTestOutput('');\n }}\n >\n <p className=\"font-medium truncate\">{prompt.name}</p>\n <p className=\"text-xs text-text-secondary mt-1 truncate\">\n v{prompt.version}\n </p>\n <div className=\"flex items-center gap-2 mt-2\">\n {prompt.visibility === 'PUBLIC' && (\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n Public\n </Badge>\n )}\n <span className=\"text-xs text-text-secondary\">\n {templateVariables(prompt).length} vars\n </span>\n </div>\n </button>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* Editor */}\n <div className=\"col-span-6\">\n {selectedPrompt ? (\n <GlassCard treatment=\"glass\" glow className=\"overflow-hidden\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <div>\n <CardTitle>{selectedPrompt.name}</CardTitle>\n <CardDescription>{selectedPrompt.description}</CardDescription>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigateTo(`prompt-templates/${selectedPrompt.id}`)}\n >\n Open template\n </Button>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {/* Tags */}\n <div className=\"flex items-center gap-2\">\n <Tag size={14} className=\"text-text-secondary\" />\n {selectedPrompt.tags.map((tag) => (\n <Badge key={tag} variant=\"secondary\">\n {tag}\n </Badge>\n ))}\n </div>\n\n {/* Content */}\n <FormField label=\"Prompt Content\">\n <Textarea\n value={selectedPrompt.templateText}\n rows={15}\n readOnly\n className=\"font-mono text-sm\"\n />\n </FormField>\n\n {/* Variables */}\n {selectedVariables.length > 0 && (\n <div>\n <p className=\"text-sm font-medium mb-2\">Variables</p>\n <div className=\"space-y-2\">\n {selectedVariables.map((variable: PromptVariable) => (\n <div\n key={variable.name}\n className=\"flex items-center gap-4 p-3 bg-bg-sunken rounded-lg\"\n >\n <div className=\"flex-1\">\n <p className=\"font-medium text-sm\">\n {`{{${variable.name}}}`}\n {variable.required && (\n <span className=\"text-status-error-text ml-1\">*</span>\n )}\n </p>\n {variable.description && (\n <p className=\"text-xs text-text-secondary\">\n {variable.description}\n </p>\n )}\n </div>\n <Badge variant=\"outline\" className=\"capitalize\">\n {variable.type}\n </Badge>\n </div>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"pt-4 text-xs text-text-secondary\">\n Updated {formatRelativeTime(selectedPrompt.updatedAt)}\n </div>\n </CardContent>\n </GlassCard>\n ) : (\n <EmptyState\n illustration=\"onboarding\"\n title=\"Select a prompt\"\n description=\"Choose a prompt from the list to view and edit\"\n />\n )}\n </div>\n\n {/* Test Panel */}\n <div className=\"col-span-3\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Play size={16} />\n Test Prompt\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {selectedVariables.map((variable: PromptVariable) => (\n <FormField key={variable.name} label={variable.name}>\n <Input\n placeholder={variable.description || `Enter ${variable.name}`}\n value={testVariables[variable.name] || ''}\n onChange={(e) =>\n setTestVariables({ ...testVariables, [variable.name]: e.target.value })\n }\n />\n </FormField>\n ))}\n\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_EXECUTE}>\n <Button\n className=\"w-full\"\n onClick={() => void handleTest()}\n isLoading={isRunning}\n disabled={!selectedPrompt}\n >\n Run Test\n </Button>\n </BotmanorPermissionGate>\n\n {testOutput && (\n <div>\n <p className=\"text-sm font-medium mb-2\">Output</p>\n <div className=\"p-3 bg-bg-sunken rounded-lg text-sm whitespace-pre-wrap font-mono max-h-64 overflow-auto\">\n {testOutput}\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PromptStudioPage.js","names":[],"sources":["../../../src/botlit/pages/PromptStudioPage.tsx"],"sourcesContent":["/**\n * Prompt Studio Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Plus, Play, Tag } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { Badge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n usePromptTemplates,\n useRenderPromptTemplate,\n promptTemplateVariables,\n type PromptTemplateRecord,\n} from '../hooks';\nimport { graphqlErrorMessage } from '../utils/errors';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { PromptVariable } from '../types';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\n/** Normalises one entry of a template's free-form `variables` JSON. */\nfunction toPromptVariable(value: unknown): PromptVariable | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n const record = value as Record<string, unknown>;\n const name = typeof record.name === 'string' ? record.name : undefined;\n if (!name) return null;\n const type = typeof record.type === 'string' ? record.type : 'string';\n return {\n name,\n type: type as PromptVariable['type'],\n description: typeof record.description === 'string' ? record.description : undefined,\n required: record.required === true,\n defaultValue: record.defaultValue,\n };\n}\n\nfunction templateVariables(template: PromptTemplateRecord | undefined): PromptVariable[] {\n if (!template) return [];\n return promptTemplateVariables(template)\n .map(toPromptVariable)\n .filter((variable): variable is PromptVariable => variable !== null);\n}\n\nexport const PromptStudioPage: FC = () => {\n const { navigateTo } = useBotlit();\n const { data: templates, loading, error, refetch } = usePromptTemplates();\n const { render, loading: isRunning } = useRenderPromptTemplate();\n\n const [selectedPromptId, setSelectedPromptId] = useState<string | null>(null);\n const [testVariables, setTestVariables] = useState<Record<string, string>>({});\n const [testOutput, setTestOutput] = useState('');\n\n // Select the first template once the list arrives.\n useEffect(() => {\n if (!selectedPromptId && templates.length > 0) {\n setSelectedPromptId(templates[0].id);\n }\n }, [templates, selectedPromptId]);\n\n const selectedPrompt = useMemo(\n () => templates.find((template) => template.id === selectedPromptId),\n [templates, selectedPromptId]\n );\n\n const selectedVariables = useMemo(() => templateVariables(selectedPrompt), [selectedPrompt]);\n\n const handleTest = async () => {\n if (!selectedPrompt) return;\n try {\n // Rendered by wspace-botlit-svc so the preview matches what the agent\n // actually receives — never a client-side string substitution.\n const output = await render({\n templateId: selectedPrompt.id,\n variables: testVariables,\n });\n setTestOutput(output);\n } catch (err) {\n toast.error(graphqlErrorMessage(err, 'Failed to render prompt'));\n }\n };\n\n return (\n <PageLayout\n title=\"Prompt Studio\"\n description=\"Create, test, and manage prompts for your AI agents\"\n actions={\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_CREATE}>\n <Button leftIcon={<Plus size={16} />} onClick={() => navigateTo('prompt-templates/new')}>\n New Prompt\n </Button>\n </BotmanorPermissionGate>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Play size={18} />}>\n Prompt Studio is your interactive workbench for writing and testing prompts before they go\n live. Pick a prompt, edit its text and variables on the left, then fill in sample values\n and hit Run Test to preview exactly what the agent will receive — so you can iterate on\n wording and catch mistakes here instead of in production.\n </PagePurpose>\n\n <div className=\"grid grid-cols-12 gap-6\">\n {/* Prompt List */}\n <div className=\"col-span-3\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Prompts</CardTitle>\n </CardHeader>\n <CardContent className=\"p-0\">\n {loading ? (\n <div className=\"space-y-2 p-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-14 bg-bg-sunken motion-safe:animate-vc-shimmer rounded\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState\n resource=\"prompt templates\"\n error={error}\n onRetry={() => void refetch()}\n className=\"m-4\"\n />\n ) : templates.length === 0 ? (\n <p className=\"p-4 text-sm text-text-secondary\">\n No prompt templates yet. Create one to start iterating.\n </p>\n ) : (\n <div className=\"divide-y divide-border-subtle\">\n {templates.map((prompt: PromptTemplateRecord) => (\n <button\n key={prompt.id}\n type=\"button\"\n className={`w-full text-left p-4 hover:bg-accent transition-colors ${\n selectedPrompt?.id === prompt.id ? 'bg-accent' : ''\n }`}\n onClick={() => {\n setSelectedPromptId(prompt.id);\n setTestVariables({});\n setTestOutput('');\n }}\n >\n <p className=\"font-medium truncate\">{prompt.name}</p>\n <p className=\"text-xs text-text-secondary mt-1 truncate\">\n v{prompt.version}\n </p>\n <div className=\"flex items-center gap-2 mt-2\">\n {prompt.visibility === 'PUBLIC' && (\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n Public\n </Badge>\n )}\n <span className=\"text-xs text-text-secondary\">\n {templateVariables(prompt).length} vars\n </span>\n </div>\n </button>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* Editor */}\n <div className=\"col-span-6\">\n {selectedPrompt ? (\n <GlassCard treatment=\"glass\" glow className=\"overflow-hidden\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <div>\n <CardTitle>{selectedPrompt.name}</CardTitle>\n <CardDescription>{selectedPrompt.description}</CardDescription>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigateTo(`prompt-templates/${selectedPrompt.id}`)}\n >\n Open template\n </Button>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {/* Tags */}\n <div className=\"flex items-center gap-2\">\n <Tag size={14} className=\"text-text-secondary\" />\n {selectedPrompt.tags.map((tag) => (\n <Badge key={tag} variant=\"secondary\">\n {tag}\n </Badge>\n ))}\n </div>\n\n {/* Content */}\n <FormField label=\"Prompt Content\">\n <Textarea\n value={selectedPrompt.templateText}\n rows={15}\n readOnly\n className=\"font-mono text-sm\"\n />\n </FormField>\n\n {/* Variables */}\n {selectedVariables.length > 0 && (\n <div>\n <p className=\"text-sm font-medium mb-2\">Variables</p>\n <div className=\"space-y-2\">\n {selectedVariables.map((variable: PromptVariable) => (\n <div\n key={variable.name}\n className=\"flex items-center gap-4 p-3 bg-bg-sunken rounded-lg\"\n >\n <div className=\"flex-1\">\n <p className=\"font-medium text-sm\">\n {`{{${variable.name}}}`}\n {variable.required && (\n <span className=\"text-status-error-text ml-1\">*</span>\n )}\n </p>\n {variable.description && (\n <p className=\"text-xs text-text-secondary\">\n {variable.description}\n </p>\n )}\n </div>\n <Badge variant=\"outline\" className=\"capitalize\">\n {variable.type}\n </Badge>\n </div>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"pt-4 text-xs text-text-secondary\">\n Updated {formatRelativeTime(selectedPrompt.updatedAt)}\n </div>\n </CardContent>\n </GlassCard>\n ) : (\n <EmptyState\n illustration=\"onboarding\"\n title=\"Select a prompt\"\n description=\"Choose a prompt from the list to view and edit\"\n />\n )}\n </div>\n\n {/* Test Panel */}\n <div className=\"col-span-3\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <Play size={16} />\n Test Prompt\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {selectedVariables.map((variable: PromptVariable) => (\n <FormField key={variable.name} label={variable.name}>\n <Input\n placeholder={variable.description || `Enter ${variable.name}`}\n value={testVariables[variable.name] || ''}\n onChange={(e) =>\n setTestVariables({ ...testVariables, [variable.name]: e.target.value })\n }\n />\n </FormField>\n ))}\n\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_EXECUTE}>\n <Button\n className=\"w-full\"\n onClick={() => void handleTest()}\n isLoading={isRunning}\n disabled={!selectedPrompt}\n >\n Run Test\n </Button>\n </BotmanorPermissionGate>\n\n {testOutput && (\n <div>\n <p className=\"text-sm font-medium mb-2\">Output</p>\n <div className=\"p-3 bg-bg-sunken rounded-lg text-sm whitespace-pre-wrap font-mono max-h-64 overflow-auto\">\n {testOutput}\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -13,11 +13,12 @@ import { FormField as m, Input as h, Textarea as g } from "../components/Input.j
13
13
  import { toUnion as _ } from "../utils/unions.js";
14
14
  import { promptTemplateExamples as v, promptTemplateVariables as ae, useCreatePromptTemplate as oe, useDeletePromptTemplate as se, usePromptTemplate as ce, useRenderPromptTemplate as le, useUpdatePromptTemplate as ue } from "../hooks/usePromptTemplates.js";
15
15
  import "../hooks/index.js";
16
- import { useMemo as de, useState as y } from "react";
17
- import { PagePurpose as fe } from "@burdenoff/fe-libs/ui";
16
+ import { graphqlErrorMessage as de } from "../utils/errors.js";
17
+ import { useMemo as fe, useState as y } from "react";
18
+ import { PagePurpose as pe } from "@burdenoff/fe-libs/ui";
18
19
  import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
19
- import { useParams as pe } from "react-router";
20
- import { ArrowLeft as me, Check as he, Code as C, Copy as ge, Edit3 as _e, Eye as w, FileText as T, Play as E, Save as D, Settings as ve, Trash2 as O, Variable as k } from "lucide-react";
20
+ import { useParams as me } from "react-router";
21
+ import { ArrowLeft as he, Check as ge, Code as C, Copy as _e, Edit3 as ve, Eye as w, FileText as T, Play as E, Save as D, Settings as ye, Trash2 as O, Variable as k } from "lucide-react";
21
22
  import { toast as A } from "sonner";
22
23
  //#region src/botlit/pages/PromptTemplateDetailPage.tsx
23
24
  var j = [
@@ -26,12 +27,12 @@ var j = [
26
27
  "boolean",
27
28
  "array",
28
29
  "object"
29
- ], ye = [
30
+ ], be = [
30
31
  "PRIVATE",
31
32
  "WORKSPACE",
32
33
  "PUBLIC"
33
34
  ], M = ({ isNew: M }) => {
34
- let { templateId: be } = pe(), { navigateTo: N } = e(), { data: P, loading: xe } = ce(M ? void 0 : be), { create: Se, loading: Ce } = oe(), { update: we, loading: Te } = ue(), { remove: Ee, loading: De } = se(), { render: Oe, loading: ke } = le(), [F, I] = y("edit"), [L, R] = y(!1), [z, Ae] = y({}), [B, V] = y(null), [H, U] = y(null), [W, G] = y(!1), [je, K] = y(!1), [q, J] = y({
35
+ let { templateId: xe } = me(), { navigateTo: N } = e(), { data: P, loading: Se } = ce(M ? void 0 : xe), { create: Ce, loading: we } = oe(), { update: Te, loading: Ee } = ue(), { remove: De, loading: Oe } = se(), { render: ke, loading: Ae } = le(), [F, I] = y("edit"), [L, R] = y(!1), [z, je] = y({}), [B, V] = y(null), [H, U] = y(null), [W, G] = y(!1), [Me, K] = y(!1), [q, J] = y({
35
36
  name: "",
36
37
  slug: "",
37
38
  description: "",
@@ -39,7 +40,7 @@ var j = [
39
40
  templateText: "",
40
41
  variables: [],
41
42
  exampleInputs: [{}]
42
- }), Y = de(() => {
43
+ }), Y = fe(() => {
43
44
  let e = M ? q.templateText : P?.templateText || "", t = /\{\{(\w+)\}\}/g, n = /* @__PURE__ */ new Set(), r;
44
45
  for (; (r = t.exec(e)) !== null;) n.add(r[1]);
45
46
  return Array.from(n);
@@ -47,10 +48,10 @@ var j = [
47
48
  M,
48
49
  q.templateText,
49
50
  P?.templateText
50
- ]), Me = async () => {
51
+ ]), Ne = async () => {
51
52
  if (!(!q.name || !q.slug)) {
52
53
  try {
53
- await Se({
54
+ await Ce({
54
55
  name: q.name,
55
56
  slug: q.slug,
56
57
  description: q.description,
@@ -65,7 +66,7 @@ var j = [
65
66
  }
66
67
  A.success(`Template "${q.name}" created`), N("prompt-templates");
67
68
  }
68
- }, Ne = () => {
69
+ }, Pe = () => {
69
70
  J({
70
71
  ...q,
71
72
  variables: [...q.variables, {
@@ -84,40 +85,40 @@ var j = [
84
85
  ...q,
85
86
  variables: n
86
87
  });
87
- }, Pe = (e) => {
88
+ }, Fe = (e) => {
88
89
  J({
89
90
  ...q,
90
91
  variables: q.variables.filter((t, n) => n !== e)
91
92
  });
92
- }, Fe = async () => {
93
+ }, Ie = async () => {
93
94
  if (P) {
94
95
  U(null);
95
96
  try {
96
- V(await Oe({
97
+ V(await ke({
97
98
  templateId: P.id,
98
99
  variables: z
99
100
  }));
100
101
  } catch (e) {
101
- let t = e instanceof Error ? e.message : "Failed to render prompt template";
102
+ let t = de(e, "Failed to render prompt template");
102
103
  V(null), U(t), A.error(t);
103
104
  }
104
105
  }
105
- }, Ie = async () => {
106
+ }, Le = async () => {
106
107
  await te(P?.templateText || q.templateText), R(!0), f() && re("Copied"), setTimeout(() => R(!1), 2e3);
107
- }, Le = () => {
108
+ }, Re = () => {
108
109
  P && (J({
109
110
  name: P.name,
110
111
  slug: P.slug,
111
112
  description: P.description || "",
112
- visibility: _(P.visibility, ye, "PRIVATE"),
113
+ visibility: _(P.visibility, be, "PRIVATE"),
113
114
  templateText: P.templateText,
114
115
  variables: ae(P),
115
116
  exampleInputs: v(P)
116
117
  }), G(!0));
117
- }, Re = async () => {
118
+ }, ze = async () => {
118
119
  if (!(!P || !q.name || !q.slug)) {
119
120
  try {
120
- await we({
121
+ await Te({
121
122
  templateId: P.id,
122
123
  input: {
123
124
  name: q.name,
@@ -135,9 +136,9 @@ var j = [
135
136
  }
136
137
  A.success("Template updated"), G(!1);
137
138
  }
138
- }, ze = async () => {
139
+ }, Be = async () => {
139
140
  if (P) try {
140
- await Ee(P.id), f() && p("success"), N("prompt-templates");
141
+ await De(P.id), f() && p("success"), N("prompt-templates");
141
142
  } catch (e) {
142
143
  throw f() && p("error"), e;
143
144
  }
@@ -153,8 +154,8 @@ var j = [
153
154
  children: "Cancel"
154
155
  }), /* @__PURE__ */ x(a, {
155
156
  leftIcon: /* @__PURE__ */ x(D, { size: 16 }),
156
- onClick: Me,
157
- isLoading: Ce,
157
+ onClick: Ne,
158
+ isLoading: we,
158
159
  disabled: !q.name || !q.slug,
159
160
  children: "Create Template"
160
161
  })]
@@ -267,7 +268,7 @@ var j = [
267
268
  }), /* @__PURE__ */ x(a, {
268
269
  variant: "outline",
269
270
  size: "sm",
270
- onClick: Ne,
271
+ onClick: Pe,
271
272
  children: "Add Variable"
272
273
  })]
273
274
  }), /* @__PURE__ */ x(c, { children: "Define the variables used in your template" })] }), /* @__PURE__ */ x(s, { children: q.variables.length > 0 ? /* @__PURE__ */ x("div", {
@@ -323,7 +324,7 @@ var j = [
323
324
  variant: "ghost",
324
325
  size: "sm",
325
326
  className: "text-status-error-text",
326
- onClick: () => Pe(t),
327
+ onClick: () => Fe(t),
327
328
  children: "Remove"
328
329
  })]
329
330
  })
@@ -385,7 +386,7 @@ var j = [
385
386
  })]
386
387
  })
387
388
  });
388
- if (xe) return /* @__PURE__ */ x(i, {
389
+ if (Se) return /* @__PURE__ */ x(i, {
389
390
  title: "Loading...",
390
391
  children: /* @__PURE__ */ x("div", { className: "h-96 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" })
391
392
  });
@@ -410,7 +411,7 @@ var j = [
410
411
  variant: "ghost",
411
412
  size: "icon",
412
413
  onClick: () => N("prompt-templates"),
413
- children: /* @__PURE__ */ x(me, { size: 20 })
414
+ children: /* @__PURE__ */ x(he, { size: 20 })
414
415
  }),
415
416
  /* @__PURE__ */ x("div", {
416
417
  className: "p-2 rounded-lg bg-action-primary-bg/10",
@@ -441,8 +442,8 @@ var j = [
441
442
  className: "flex gap-2",
442
443
  children: [/* @__PURE__ */ x(a, {
443
444
  variant: "outline",
444
- leftIcon: x(L ? he : ge, { size: 16 }),
445
- onClick: Ie,
445
+ leftIcon: x(L ? ge : _e, { size: 16 }),
446
+ onClick: Le,
446
447
  children: L ? "Copied!" : "Copy"
447
448
  }), W ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(a, {
448
449
  variant: "outline",
@@ -450,11 +451,11 @@ var j = [
450
451
  children: "Cancel"
451
452
  }), /* @__PURE__ */ x(a, {
452
453
  leftIcon: /* @__PURE__ */ x(D, { size: 16 }),
453
- onClick: Re,
454
- isLoading: Te,
454
+ onClick: ze,
455
+ isLoading: Ee,
455
456
  disabled: !q.name || !q.slug,
456
457
  children: "Save Changes"
457
- })] }) : je ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(a, {
458
+ })] }) : Me ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(a, {
458
459
  variant: "outline",
459
460
  onClick: () => K(!1),
460
461
  children: "Cancel"
@@ -462,16 +463,16 @@ var j = [
462
463
  variant: "destructive",
463
464
  leftIcon: /* @__PURE__ */ x(O, { size: 16 }),
464
465
  onClick: () => {
465
- ne("medium"), ze();
466
+ ne("medium"), Be();
466
467
  },
467
- isLoading: De,
468
+ isLoading: Oe,
468
469
  children: "Confirm Delete"
469
470
  })] }) : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(r, {
470
471
  permission: n.PROMPT_TEMPLATE_UPDATE,
471
472
  children: /* @__PURE__ */ x(a, {
472
473
  variant: "outline",
473
- leftIcon: /* @__PURE__ */ x(_e, { size: 16 }),
474
- onClick: Le,
474
+ leftIcon: /* @__PURE__ */ x(ve, { size: 16 }),
475
+ onClick: Re,
475
476
  children: "Edit Template"
476
477
  })
477
478
  }), /* @__PURE__ */ x(r, {
@@ -487,7 +488,7 @@ var j = [
487
488
  children: /* @__PURE__ */ S("div", {
488
489
  className: "space-y-6",
489
490
  children: [
490
- /* @__PURE__ */ S(fe, {
491
+ /* @__PURE__ */ S(pe, {
491
492
  icon: /* @__PURE__ */ x(T, { size: 18 }),
492
493
  children: [
493
494
  "This is a single reusable prompt template — its content with",
@@ -738,7 +739,7 @@ var j = [
738
739
  children: [/* @__PURE__ */ x(h, {
739
740
  placeholder: e.defaultValue ? String(e.defaultValue) : `Enter ${e.name}`,
740
741
  value: z[e.name] || "",
741
- onChange: (t) => Ae({
742
+ onChange: (t) => je({
742
743
  ...z,
743
744
  [e.name]: t.target.value
744
745
  })
@@ -751,8 +752,8 @@ var j = [
751
752
  children: /* @__PURE__ */ x(a, {
752
753
  className: "w-full",
753
754
  leftIcon: /* @__PURE__ */ x(E, { size: 16 }),
754
- onClick: Fe,
755
- isLoading: ke,
755
+ onClick: Ie,
756
+ isLoading: Ae,
756
757
  children: "Render Template"
757
758
  })
758
759
  })]
@@ -792,7 +793,7 @@ var j = [
792
793
  }) })] }),
793
794
  /* @__PURE__ */ S(o, { children: [/* @__PURE__ */ x(l, { children: /* @__PURE__ */ S(u, {
794
795
  className: "flex items-center gap-2",
795
- children: [/* @__PURE__ */ x(ve, { size: 18 }), "Metadata"]
796
+ children: [/* @__PURE__ */ x(ye, { size: 18 }), "Metadata"]
796
797
  }) }), /* @__PURE__ */ x(s, { children: /* @__PURE__ */ S("div", {
797
798
  className: "grid grid-cols-2 md:grid-cols-4 gap-6 text-sm",
798
799
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"PromptTemplateDetailPage.js","names":[],"sources":["../../../src/botlit/pages/PromptTemplateDetailPage.tsx"],"sourcesContent":["/**\n * Prompt Template Detail Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState, useMemo } from 'react';\nimport { useParams } from 'react-router';\nimport { toast } from 'sonner';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n isNative,\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../utils/nativeBridge';\nimport {\n ArrowLeft,\n FileText,\n Variable,\n Play,\n Save,\n Copy,\n Check,\n Settings,\n Code,\n Eye,\n Edit3,\n Trash2,\n} from 'lucide-react';\nimport { PageLayout } from '../components/PageLayout';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { EmptyState } from '../components/EmptyState';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { StatusBadge, Badge } from '../components/Badge';\nimport {\n usePromptTemplate,\n useCreatePromptTemplate,\n useUpdatePromptTemplate,\n useDeletePromptTemplate,\n useRenderPromptTemplate,\n} from '../hooks';\nimport {\n promptTemplateExamples,\n promptTemplateVariables,\n type PromptTemplateVariable,\n} from '../hooks/usePromptTemplates';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { toUnion } from '../utils/unions';\nimport type { Visibility } from '../types';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\ninterface PromptTemplateDetailPageProps {\n isNew?: boolean;\n}\n\nconst VARIABLE_TYPES = ['string', 'number', 'boolean', 'array', 'object'] as const;\n\nconst VISIBILITIES: Visibility[] = ['PRIVATE', 'WORKSPACE', 'PUBLIC'];\n\nexport const PromptTemplateDetailPage: FC<PromptTemplateDetailPageProps> = ({ isNew }) => {\n const { templateId } = useParams();\n const { navigateTo } = useBotlit();\n const { data: template, loading } = usePromptTemplate(isNew ? undefined : templateId);\n const { create: createTemplate, loading: createLoading } = useCreatePromptTemplate();\n const { update: updateTemplate, loading: updateLoading } = useUpdatePromptTemplate();\n const { remove: deleteTemplate, loading: deleteLoading } = useDeletePromptTemplate();\n const { render: renderTemplate, loading: renderLoading } = useRenderPromptTemplate();\n\n const [activeTab, setActiveTab] = useState<'edit' | 'preview' | 'test'>('edit');\n const [copied, setCopied] = useState(false);\n const [testInputs, setTestInputs] = useState<Record<string, string>>({});\n const [renderedOutput, setRenderedOutput] = useState<string | null>(null);\n const [renderError, setRenderError] = useState<string | null>(null);\n const [isEditing, setIsEditing] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n\n const [formData, setFormData] = useState({\n name: '',\n slug: '',\n description: '',\n visibility: 'PRIVATE' as Visibility,\n templateText: '',\n variables: [] as PromptTemplateVariable[],\n exampleInputs: [{}] as Record<string, unknown>[],\n });\n\n // Extract variables from template text\n const detectedVariables = useMemo(() => {\n const text = isNew ? formData.templateText : template?.templateText || '';\n const regex = /\\{\\{(\\w+)\\}\\}/g;\n const matches = new Set<string>();\n let match;\n while ((match = regex.exec(text)) !== null) {\n matches.add(match[1]);\n }\n return Array.from(matches);\n }, [isNew, formData.templateText, template?.templateText]);\n\n const handleCreate = async () => {\n if (!formData.name || !formData.slug) return;\n try {\n await createTemplate({\n name: formData.name,\n slug: formData.slug,\n description: formData.description,\n visibility: formData.visibility,\n templateText: formData.templateText,\n variables: formData.variables,\n exampleInputs: formData.exampleInputs,\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to create prompt template');\n return;\n }\n toast.success(`Template \"${formData.name}\" created`);\n navigateTo('prompt-templates');\n };\n\n const handleAddVariable = () => {\n setFormData({\n ...formData,\n variables: [\n ...formData.variables,\n { name: '', type: 'string', required: true, defaultValue: undefined },\n ],\n });\n };\n\n const handleUpdateVariable = (index: number, updates: Partial<PromptTemplateVariable>) => {\n const newVariables = [...formData.variables];\n newVariables[index] = { ...newVariables[index], ...updates };\n setFormData({ ...formData, variables: newVariables });\n };\n\n const handleRemoveVariable = (index: number) => {\n setFormData({\n ...formData,\n variables: formData.variables.filter((_, i) => i !== index),\n });\n };\n\n const handleTestRender = async () => {\n if (!template) return;\n setRenderError(null);\n try {\n const result = await renderTemplate({\n templateId: template.id,\n variables: testInputs,\n });\n setRenderedOutput(result);\n } catch (err) {\n // The service enforces the declared variable contract (missing required\n // variables, unknown keys, residual placeholders) — surface that error\n // here instead of dying as an unhandled rejection.\n const message = err instanceof Error ? err.message : 'Failed to render prompt template';\n setRenderedOutput(null);\n setRenderError(message);\n toast.error(message);\n }\n };\n\n const handleCopyTemplate = async () => {\n const text = template?.templateText || formData.templateText;\n await nativeCopyText(text);\n setCopied(true);\n if (isNative()) void nativeToast('Copied');\n setTimeout(() => setCopied(false), 2000);\n };\n\n const startEditing = () => {\n if (template) {\n setFormData({\n name: template.name,\n slug: template.slug,\n description: template.description || '',\n visibility: toUnion(template.visibility, VISIBILITIES, 'PRIVATE'),\n templateText: template.templateText,\n variables: promptTemplateVariables(template),\n exampleInputs: promptTemplateExamples(template),\n });\n setIsEditing(true);\n }\n };\n\n const handleUpdate = async () => {\n if (!template || !formData.name || !formData.slug) return;\n try {\n await updateTemplate({\n templateId: template.id,\n input: {\n name: formData.name,\n slug: formData.slug,\n description: formData.description,\n visibility: formData.visibility,\n templateText: formData.templateText,\n variables: formData.variables,\n exampleInputs: formData.exampleInputs,\n },\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to update prompt template');\n return;\n }\n toast.success('Template updated');\n setIsEditing(false);\n };\n\n const handleDelete = async () => {\n if (!template) return;\n try {\n await deleteTemplate(template.id);\n if (isNative()) void nativeNotify('success');\n navigateTo('prompt-templates');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n };\n\n const highlightVariables = (text: string) => {\n return text.replace(\n /\\{\\{(\\w+)\\}\\}/g,\n '<span class=\"bg-action-primary-bg/20 text-primary px-1 rounded font-mono\">{{$1}}</span>'\n );\n };\n\n if (isNew) {\n return (\n <PageLayout\n title=\"Create Prompt Template\"\n description=\"Define a reusable prompt template with variables\"\n actions={\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" onClick={() => navigateTo('prompt-templates')}>\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleCreate}\n isLoading={createLoading}\n disabled={!formData.name || !formData.slug}\n >\n Create Template\n </Button>\n </div>\n }\n >\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Left: Form */}\n <div className=\"lg:col-span-2 space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Template Name\" required>\n <Input\n placeholder=\"e.g., Technical Support Template\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField\n label=\"Slug\"\n required\n description=\"Unique identifier (lowercase, dashes)\"\n >\n <Input\n placeholder=\"e.g., technical-support\"\n value={formData.slug}\n onChange={(e) =>\n setFormData({\n ...formData,\n slug: e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '-'),\n })\n }\n />\n </FormField>\n </div>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this template used for?\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={2}\n />\n </FormField>\n\n <FormField label=\"Visibility\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.visibility}\n onChange={(e) =>\n setFormData({ ...formData, visibility: e.target.value as Visibility })\n }\n >\n <option value=\"PRIVATE\">Private</option>\n <option value=\"WORKSPACE\">Workspace</option>\n <option value=\"PUBLIC\">Public</option>\n </select>\n </FormField>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Code size={18} />\n Template Content\n </CardTitle>\n <CardDescription>Use {'{{variable_name}}'} syntax for variables</CardDescription>\n </CardHeader>\n <CardContent>\n <Textarea\n className=\"font-mono text-sm min-h-[300px]\"\n placeholder={`You are a helpful assistant for {{company_name}}.\n\nYour role is to help users with {{task_type}}.\n\nGuidelines:\n- Be helpful and friendly\n- Provide accurate information\n- Reference: {{docs_url}}`}\n value={formData.templateText}\n onChange={(e) => setFormData({ ...formData, templateText: e.target.value })}\n />\n {detectedVariables.length > 0 && (\n <div className=\"mt-3 flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Detected variables:</span>\n {detectedVariables.map((v) => (\n <Badge key={v} variant=\"secondary\" className=\"font-mono\">\n {v}\n </Badge>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2\">\n <Variable size={18} />\n Variables\n </span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleAddVariable}>\n Add Variable\n </Button>\n </CardTitle>\n <CardDescription>Define the variables used in your template</CardDescription>\n </CardHeader>\n <CardContent>\n {formData.variables.length > 0 ? (\n <div className=\"space-y-4\">\n {formData.variables.map((variable, index) => (\n <div key={index} className=\"p-4 border rounded-lg bg-bg-sunken/30 space-y-3\">\n <div className=\"grid grid-cols-4 gap-3\">\n <FormField label=\"Name\">\n <Input\n className=\"font-mono\"\n placeholder=\"variable_name\"\n value={variable.name}\n onChange={(e) =>\n handleUpdateVariable(index, { name: e.target.value })\n }\n />\n </FormField>\n <FormField label=\"Type\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={variable.type}\n onChange={(e) =>\n handleUpdateVariable(index, {\n type: toUnion(e.target.value, VARIABLE_TYPES, 'string'),\n })\n }\n >\n {VARIABLE_TYPES.map((type) => (\n <option key={type} value={type}>\n {type}\n </option>\n ))}\n </select>\n </FormField>\n <FormField label=\"Default Value\">\n <Input\n placeholder=\"Optional\"\n value={String(variable.defaultValue || '')}\n onChange={(e) =>\n handleUpdateVariable(index, {\n defaultValue: e.target.value || undefined,\n })\n }\n />\n </FormField>\n <div className=\"flex items-end gap-2\">\n <label className=\"flex items-center gap-2 h-10\">\n <input\n type=\"checkbox\"\n checked={variable.required}\n onChange={(e) =>\n handleUpdateVariable(index, { required: e.target.checked })\n }\n className=\"h-4 w-4\"\n />\n <span className=\"text-sm\">Required</span>\n </label>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-status-error-text\"\n onClick={() => handleRemoveVariable(index)}\n >\n Remove\n </Button>\n </div>\n </div>\n <FormField label=\"Description\">\n <Input\n placeholder=\"What is this variable for?\"\n value={variable.description || ''}\n onChange={(e) =>\n handleUpdateVariable(index, { description: e.target.value })\n }\n />\n </FormField>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-8 text-text-secondary\">\n <Variable className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>No variables defined yet</p>\n <p className=\"text-sm\">\n Variables are automatically detected from {'{{variable}}'} syntax\n </p>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* Right: Preview */}\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Eye size={18} />\n Preview\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div\n className=\"p-4 bg-bg-sunken rounded-lg text-sm whitespace-pre-wrap font-mono\"\n dangerouslySetInnerHTML={{\n __html: highlightVariables(formData.templateText || 'Enter template text...'),\n }}\n />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Quick Tips</CardTitle>\n </CardHeader>\n <CardContent className=\"text-sm space-y-2\">\n <p>\n <strong>Variables:</strong> Use {'{{name}}'} syntax\n </p>\n <p>\n <strong>Best Practices:</strong>\n </p>\n <ul className=\"list-disc list-inside text-text-secondary space-y-1\">\n <li>Use descriptive variable names</li>\n <li>Provide default values when possible</li>\n <li>Include example inputs for testing</li>\n <li>Version your templates for changes</li>\n </ul>\n </CardContent>\n </Card>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n if (loading) {\n return (\n <PageLayout title=\"Loading...\">\n <div className=\"h-96 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n </PageLayout>\n );\n }\n\n if (!template) {\n return (\n <PageLayout title=\"Template Not Found\">\n <EmptyState\n illustration=\"empty-files\"\n title=\"Template Not Found\"\n description=\"This prompt template doesn't exist.\"\n action={<Button onClick={() => navigateTo('prompt-templates')}>Back to Templates</Button>}\n />\n </PageLayout>\n );\n }\n\n // `variables`/`exampleInputs` are free-form JSON columns — normalise once.\n const templateVariables = promptTemplateVariables(template);\n const templateExamples = promptTemplateExamples(template);\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigateTo('prompt-templates')}>\n <ArrowLeft size={20} />\n </Button>\n <div className=\"p-2 rounded-lg bg-action-primary-bg/10\">\n <FileText className=\"h-6 w-6 text-primary\" />\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <span>{template.name}</span>\n <StatusBadge status={template.status} />\n <Badge variant=\"secondary\" className=\"font-mono\">\n v{template.version}\n </Badge>\n </div>\n <p className=\"text-sm font-normal text-text-secondary\">\n {template.slug} - {template.description}\n </p>\n </div>\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n leftIcon={copied ? <Check size={16} /> : <Copy size={16} />}\n onClick={handleCopyTemplate}\n >\n {copied ? 'Copied!' : 'Copy'}\n </Button>\n {isEditing ? (\n <>\n <Button variant=\"outline\" onClick={() => setIsEditing(false)}>\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleUpdate}\n isLoading={updateLoading}\n disabled={!formData.name || !formData.slug}\n >\n Save Changes\n </Button>\n </>\n ) : showDeleteConfirm ? (\n <>\n <Button variant=\"outline\" onClick={() => setShowDeleteConfirm(false)}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n leftIcon={<Trash2 size={16} />}\n onClick={() => {\n nativeImpact('medium');\n void handleDelete();\n }}\n isLoading={deleteLoading}\n >\n Confirm Delete\n </Button>\n </>\n ) : (\n <>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_UPDATE}>\n <Button variant=\"outline\" leftIcon={<Edit3 size={16} />} onClick={startEditing}>\n Edit Template\n </Button>\n </BotmanorPermissionGate>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_DELETE}>\n <Button\n variant=\"outline\"\n leftIcon={<Trash2 size={16} />}\n onClick={() => setShowDeleteConfirm(true)}\n >\n Delete\n </Button>\n </BotmanorPermissionGate>\n </>\n )}\n </div>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<FileText size={18} />}>\n This is a single reusable prompt template — its content with{' '}\n <code>{'{{variables}}'}</code>, its declared variables and example inputs, and its version\n history. Edit and preview it here to perfect the instructions, then reuse it across agents\n so they share consistent, version-controlled behaviour.\n </PagePurpose>\n\n {/* Edit Form */}\n {isEditing && (\n <Card>\n <CardHeader>\n <CardTitle>Edit Template</CardTitle>\n <CardDescription>Update template details and content</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Template Name\" required>\n <Input\n placeholder=\"e.g., Technical Support Template\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField\n label=\"Slug\"\n required\n description=\"Unique identifier (lowercase, dashes)\"\n >\n <Input\n placeholder=\"e.g., technical-support\"\n value={formData.slug}\n onChange={(e) =>\n setFormData({\n ...formData,\n slug: e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '-'),\n })\n }\n />\n </FormField>\n </div>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this template used for?\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={2}\n />\n </FormField>\n\n <FormField label=\"Visibility\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.visibility}\n onChange={(e) =>\n setFormData({ ...formData, visibility: e.target.value as Visibility })\n }\n >\n <option value=\"PRIVATE\">Private</option>\n <option value=\"WORKSPACE\">Workspace</option>\n <option value=\"PUBLIC\">Public</option>\n </select>\n </FormField>\n\n <FormField\n label=\"Template Content\"\n description=\"Use {{variable_name}} syntax for variables\"\n >\n <Textarea\n className=\"font-mono text-sm min-h-[200px]\"\n value={formData.templateText}\n onChange={(e) => setFormData({ ...formData, templateText: e.target.value })}\n />\n </FormField>\n\n {detectedVariables.length > 0 && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Detected variables:</span>\n {detectedVariables.map((v) => (\n <Badge key={v} variant=\"secondary\" className=\"font-mono\">\n {v}\n </Badge>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n )}\n\n {/* Stats */}\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card treatment=\"glass\" glow>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary\">{templateVariables.length}</p>\n <p className=\"text-sm text-text-secondary\">Variables</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary\">{templateExamples.length}</p>\n <p className=\"text-sm text-text-secondary\">Examples</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary\">{template.revision}</p>\n <p className=\"text-sm text-text-secondary\">Revision</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-lg font-bold text-text-primary capitalize\">\n {template.visibility.toLowerCase()}\n </p>\n <p className=\"text-sm text-text-secondary\">Visibility</p>\n </CardContent>\n </Card>\n </div>\n\n {/* Tabs */}\n <div className=\"flex gap-2 border-b\">\n <Button\n variant={activeTab === 'edit' ? 'default' : 'ghost'}\n onClick={() => setActiveTab('edit')}\n >\n <Code className=\"h-4 w-4 mr-2\" />\n Template\n </Button>\n <Button\n variant={activeTab === 'preview' ? 'default' : 'ghost'}\n onClick={() => setActiveTab('preview')}\n >\n <Eye className=\"h-4 w-4 mr-2\" />\n Preview\n </Button>\n <Button\n variant={activeTab === 'test' ? 'default' : 'ghost'}\n onClick={() => setActiveTab('test')}\n >\n <Play className=\"h-4 w-4 mr-2\" />\n Test\n </Button>\n </div>\n\n {/* Tab Content */}\n {activeTab === 'edit' && (\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2\">\n <Card>\n <CardHeader>\n <CardTitle>Template Content</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"p-4 bg-bg-sunken rounded-lg font-mono text-sm whitespace-pre-wrap\">\n <div\n dangerouslySetInnerHTML={{\n __html: highlightVariables(template.templateText),\n }}\n />\n </div>\n </CardContent>\n </Card>\n </div>\n\n <div>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Variable size={18} />\n Variables ({templateVariables.length})\n </CardTitle>\n </CardHeader>\n <CardContent>\n {templateVariables.length > 0 ? (\n <div className=\"space-y-3\">\n {templateVariables.map(\n (\n v: {\n name: string;\n type: string;\n required?: boolean;\n description?: string | null;\n defaultValue?: unknown;\n },\n i: number\n ) => (\n <div key={i} className=\"p-3 border rounded-lg\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"font-mono font-medium\">{v.name}</span>\n <div className=\"flex gap-1\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {v.type}\n </Badge>\n {v.required && (\n <Badge variant=\"destructive\" className=\"text-xs\">\n required\n </Badge>\n )}\n </div>\n </div>\n {v.description && (\n <p className=\"text-sm text-text-secondary\">{v.description}</p>\n )}\n {v.defaultValue !== undefined && (\n <p className=\"text-xs text-text-secondary mt-1\">\n Default:{' '}\n <code className=\"bg-bg-sunken px-1\">{String(v.defaultValue)}</code>\n </p>\n )}\n </div>\n )\n )}\n </div>\n ) : (\n <p className=\"text-text-secondary text-center py-4\">No variables defined</p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n )}\n\n {activeTab === 'preview' && (\n <Card>\n <CardHeader>\n <CardTitle>Rendered Preview</CardTitle>\n <CardDescription>Preview with example inputs (first example set)</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"p-4 bg-bg-sunken rounded-lg font-mono text-sm whitespace-pre-wrap\">\n {templateExamples[0] ? (\n template.templateText.replace(/\\{\\{(\\w+)\\}\\}/g, (_: string, key: string) => {\n const value = templateExamples[0][key];\n return value !== undefined ? String(value) : `{{${key}}}`;\n })\n ) : (\n <span className=\"text-text-secondary\">\n No example inputs defined. Add examples to preview rendered output.\n </span>\n )}\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeTab === 'test' && (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>Test Inputs</CardTitle>\n <CardDescription>Enter values to test the template</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {templateVariables.map((v) => (\n <FormField key={v.name} label={v.name} required={v.required}>\n <Input\n placeholder={v.defaultValue ? String(v.defaultValue) : `Enter ${v.name}`}\n value={testInputs[v.name] || ''}\n onChange={(e) => setTestInputs({ ...testInputs, [v.name]: e.target.value })}\n />\n {v.description && (\n <p className=\"text-xs text-text-secondary mt-1\">{v.description}</p>\n )}\n </FormField>\n ))}\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_EXECUTE}>\n <Button\n className=\"w-full\"\n leftIcon={<Play size={16} />}\n onClick={handleTestRender}\n isLoading={renderLoading}\n >\n Render Template\n </Button>\n </BotmanorPermissionGate>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Output</CardTitle>\n </CardHeader>\n <CardContent>\n {renderError ? (\n <div\n role=\"alert\"\n className=\"flex items-start gap-2 rounded-lg border border-status-error-border/40 bg-status-error-bg/10 px-3 py-2 text-sm text-status-error-text\"\n >\n <p>{renderError}</p>\n </div>\n ) : renderedOutput ? (\n <div className=\"p-4 bg-bg-sunken rounded-lg font-mono text-sm whitespace-pre-wrap\">\n {renderedOutput}\n </div>\n ) : (\n <div className=\"p-8 text-center text-text-secondary\">\n <Play className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>Enter inputs and click \"Render Template\" to see output</p>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Example Inputs */}\n {templateExamples.length > 0 && activeTab === 'edit' && (\n <Card>\n <CardHeader>\n <CardTitle>Example Inputs</CardTitle>\n <CardDescription>Pre-defined inputs for testing and documentation</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {templateExamples.map((example, index) => (\n <div key={index} className=\"p-4 border rounded-lg bg-bg-sunken/30\">\n <p className=\"text-sm font-medium mb-2\">Example {index + 1}</p>\n <div className=\"space-y-1 text-sm\">\n {Object.entries(example).map(([key, value]) => (\n <div key={key} className=\"flex justify-between\">\n <span className=\"font-mono text-text-secondary\">{key}:</span>\n <span className=\"font-mono truncate max-w-[60%]\">{String(value)}</span>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Metadata */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Settings size={18} />\n Metadata\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-6 text-sm\">\n <div>\n <p className=\"text-text-secondary\">Created</p>\n <p className=\"font-medium\">{formatRelativeTime(template.createdAt)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Updated</p>\n <p className=\"font-medium\">{formatRelativeTime(template.updatedAt)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Tags</p>\n <div className=\"flex gap-1\">\n {template.tags.length > 0 ? (\n template.tags.map((tag: string) => (\n <Badge key={tag} variant=\"secondary\" className=\"text-xs\">\n {tag}\n </Badge>\n ))\n ) : (\n <span className=\"text-text-secondary\">None</span>\n )}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PromptTemplateDetailPage.js","names":[],"sources":["../../../src/botlit/pages/PromptTemplateDetailPage.tsx"],"sourcesContent":["/**\n * Prompt Template Detail Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState, useMemo } from 'react';\nimport { useParams } from 'react-router';\nimport { toast } from 'sonner';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n isNative,\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../utils/nativeBridge';\nimport {\n ArrowLeft,\n FileText,\n Variable,\n Play,\n Save,\n Copy,\n Check,\n Settings,\n Code,\n Eye,\n Edit3,\n Trash2,\n} from 'lucide-react';\nimport { PageLayout } from '../components/PageLayout';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { EmptyState } from '../components/EmptyState';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { StatusBadge, Badge } from '../components/Badge';\nimport {\n usePromptTemplate,\n useCreatePromptTemplate,\n useUpdatePromptTemplate,\n useDeletePromptTemplate,\n useRenderPromptTemplate,\n} from '../hooks';\nimport {\n promptTemplateExamples,\n promptTemplateVariables,\n type PromptTemplateVariable,\n} from '../hooks/usePromptTemplates';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { graphqlErrorMessage } from '../utils/errors';\nimport { toUnion } from '../utils/unions';\nimport type { Visibility } from '../types';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\ninterface PromptTemplateDetailPageProps {\n isNew?: boolean;\n}\n\nconst VARIABLE_TYPES = ['string', 'number', 'boolean', 'array', 'object'] as const;\n\nconst VISIBILITIES: Visibility[] = ['PRIVATE', 'WORKSPACE', 'PUBLIC'];\n\nexport const PromptTemplateDetailPage: FC<PromptTemplateDetailPageProps> = ({ isNew }) => {\n const { templateId } = useParams();\n const { navigateTo } = useBotlit();\n const { data: template, loading } = usePromptTemplate(isNew ? undefined : templateId);\n const { create: createTemplate, loading: createLoading } = useCreatePromptTemplate();\n const { update: updateTemplate, loading: updateLoading } = useUpdatePromptTemplate();\n const { remove: deleteTemplate, loading: deleteLoading } = useDeletePromptTemplate();\n const { render: renderTemplate, loading: renderLoading } = useRenderPromptTemplate();\n\n const [activeTab, setActiveTab] = useState<'edit' | 'preview' | 'test'>('edit');\n const [copied, setCopied] = useState(false);\n const [testInputs, setTestInputs] = useState<Record<string, string>>({});\n const [renderedOutput, setRenderedOutput] = useState<string | null>(null);\n const [renderError, setRenderError] = useState<string | null>(null);\n const [isEditing, setIsEditing] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n\n const [formData, setFormData] = useState({\n name: '',\n slug: '',\n description: '',\n visibility: 'PRIVATE' as Visibility,\n templateText: '',\n variables: [] as PromptTemplateVariable[],\n exampleInputs: [{}] as Record<string, unknown>[],\n });\n\n // Extract variables from template text\n const detectedVariables = useMemo(() => {\n const text = isNew ? formData.templateText : template?.templateText || '';\n const regex = /\\{\\{(\\w+)\\}\\}/g;\n const matches = new Set<string>();\n let match;\n while ((match = regex.exec(text)) !== null) {\n matches.add(match[1]);\n }\n return Array.from(matches);\n }, [isNew, formData.templateText, template?.templateText]);\n\n const handleCreate = async () => {\n if (!formData.name || !formData.slug) return;\n try {\n await createTemplate({\n name: formData.name,\n slug: formData.slug,\n description: formData.description,\n visibility: formData.visibility,\n templateText: formData.templateText,\n variables: formData.variables,\n exampleInputs: formData.exampleInputs,\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to create prompt template');\n return;\n }\n toast.success(`Template \"${formData.name}\" created`);\n navigateTo('prompt-templates');\n };\n\n const handleAddVariable = () => {\n setFormData({\n ...formData,\n variables: [\n ...formData.variables,\n { name: '', type: 'string', required: true, defaultValue: undefined },\n ],\n });\n };\n\n const handleUpdateVariable = (index: number, updates: Partial<PromptTemplateVariable>) => {\n const newVariables = [...formData.variables];\n newVariables[index] = { ...newVariables[index], ...updates };\n setFormData({ ...formData, variables: newVariables });\n };\n\n const handleRemoveVariable = (index: number) => {\n setFormData({\n ...formData,\n variables: formData.variables.filter((_, i) => i !== index),\n });\n };\n\n const handleTestRender = async () => {\n if (!template) return;\n setRenderError(null);\n try {\n const result = await renderTemplate({\n templateId: template.id,\n variables: testInputs,\n });\n setRenderedOutput(result);\n } catch (err) {\n // The service enforces the declared variable contract (missing required\n // variables, unknown keys, residual placeholders) — surface that error\n // here instead of dying as an unhandled rejection.\n const message = graphqlErrorMessage(err, 'Failed to render prompt template');\n setRenderedOutput(null);\n setRenderError(message);\n toast.error(message);\n }\n };\n\n const handleCopyTemplate = async () => {\n const text = template?.templateText || formData.templateText;\n await nativeCopyText(text);\n setCopied(true);\n if (isNative()) void nativeToast('Copied');\n setTimeout(() => setCopied(false), 2000);\n };\n\n const startEditing = () => {\n if (template) {\n setFormData({\n name: template.name,\n slug: template.slug,\n description: template.description || '',\n visibility: toUnion(template.visibility, VISIBILITIES, 'PRIVATE'),\n templateText: template.templateText,\n variables: promptTemplateVariables(template),\n exampleInputs: promptTemplateExamples(template),\n });\n setIsEditing(true);\n }\n };\n\n const handleUpdate = async () => {\n if (!template || !formData.name || !formData.slug) return;\n try {\n await updateTemplate({\n templateId: template.id,\n input: {\n name: formData.name,\n slug: formData.slug,\n description: formData.description,\n visibility: formData.visibility,\n templateText: formData.templateText,\n variables: formData.variables,\n exampleInputs: formData.exampleInputs,\n },\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to update prompt template');\n return;\n }\n toast.success('Template updated');\n setIsEditing(false);\n };\n\n const handleDelete = async () => {\n if (!template) return;\n try {\n await deleteTemplate(template.id);\n if (isNative()) void nativeNotify('success');\n navigateTo('prompt-templates');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n };\n\n const highlightVariables = (text: string) => {\n return text.replace(\n /\\{\\{(\\w+)\\}\\}/g,\n '<span class=\"bg-action-primary-bg/20 text-primary px-1 rounded font-mono\">{{$1}}</span>'\n );\n };\n\n if (isNew) {\n return (\n <PageLayout\n title=\"Create Prompt Template\"\n description=\"Define a reusable prompt template with variables\"\n actions={\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" onClick={() => navigateTo('prompt-templates')}>\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleCreate}\n isLoading={createLoading}\n disabled={!formData.name || !formData.slug}\n >\n Create Template\n </Button>\n </div>\n }\n >\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Left: Form */}\n <div className=\"lg:col-span-2 space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Template Name\" required>\n <Input\n placeholder=\"e.g., Technical Support Template\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField\n label=\"Slug\"\n required\n description=\"Unique identifier (lowercase, dashes)\"\n >\n <Input\n placeholder=\"e.g., technical-support\"\n value={formData.slug}\n onChange={(e) =>\n setFormData({\n ...formData,\n slug: e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '-'),\n })\n }\n />\n </FormField>\n </div>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this template used for?\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={2}\n />\n </FormField>\n\n <FormField label=\"Visibility\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.visibility}\n onChange={(e) =>\n setFormData({ ...formData, visibility: e.target.value as Visibility })\n }\n >\n <option value=\"PRIVATE\">Private</option>\n <option value=\"WORKSPACE\">Workspace</option>\n <option value=\"PUBLIC\">Public</option>\n </select>\n </FormField>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Code size={18} />\n Template Content\n </CardTitle>\n <CardDescription>Use {'{{variable_name}}'} syntax for variables</CardDescription>\n </CardHeader>\n <CardContent>\n <Textarea\n className=\"font-mono text-sm min-h-[300px]\"\n placeholder={`You are a helpful assistant for {{company_name}}.\n\nYour role is to help users with {{task_type}}.\n\nGuidelines:\n- Be helpful and friendly\n- Provide accurate information\n- Reference: {{docs_url}}`}\n value={formData.templateText}\n onChange={(e) => setFormData({ ...formData, templateText: e.target.value })}\n />\n {detectedVariables.length > 0 && (\n <div className=\"mt-3 flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Detected variables:</span>\n {detectedVariables.map((v) => (\n <Badge key={v} variant=\"secondary\" className=\"font-mono\">\n {v}\n </Badge>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-2\">\n <Variable size={18} />\n Variables\n </span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleAddVariable}>\n Add Variable\n </Button>\n </CardTitle>\n <CardDescription>Define the variables used in your template</CardDescription>\n </CardHeader>\n <CardContent>\n {formData.variables.length > 0 ? (\n <div className=\"space-y-4\">\n {formData.variables.map((variable, index) => (\n <div key={index} className=\"p-4 border rounded-lg bg-bg-sunken/30 space-y-3\">\n <div className=\"grid grid-cols-4 gap-3\">\n <FormField label=\"Name\">\n <Input\n className=\"font-mono\"\n placeholder=\"variable_name\"\n value={variable.name}\n onChange={(e) =>\n handleUpdateVariable(index, { name: e.target.value })\n }\n />\n </FormField>\n <FormField label=\"Type\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={variable.type}\n onChange={(e) =>\n handleUpdateVariable(index, {\n type: toUnion(e.target.value, VARIABLE_TYPES, 'string'),\n })\n }\n >\n {VARIABLE_TYPES.map((type) => (\n <option key={type} value={type}>\n {type}\n </option>\n ))}\n </select>\n </FormField>\n <FormField label=\"Default Value\">\n <Input\n placeholder=\"Optional\"\n value={String(variable.defaultValue || '')}\n onChange={(e) =>\n handleUpdateVariable(index, {\n defaultValue: e.target.value || undefined,\n })\n }\n />\n </FormField>\n <div className=\"flex items-end gap-2\">\n <label className=\"flex items-center gap-2 h-10\">\n <input\n type=\"checkbox\"\n checked={variable.required}\n onChange={(e) =>\n handleUpdateVariable(index, { required: e.target.checked })\n }\n className=\"h-4 w-4\"\n />\n <span className=\"text-sm\">Required</span>\n </label>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-status-error-text\"\n onClick={() => handleRemoveVariable(index)}\n >\n Remove\n </Button>\n </div>\n </div>\n <FormField label=\"Description\">\n <Input\n placeholder=\"What is this variable for?\"\n value={variable.description || ''}\n onChange={(e) =>\n handleUpdateVariable(index, { description: e.target.value })\n }\n />\n </FormField>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-8 text-text-secondary\">\n <Variable className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>No variables defined yet</p>\n <p className=\"text-sm\">\n Variables are automatically detected from {'{{variable}}'} syntax\n </p>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* Right: Preview */}\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Eye size={18} />\n Preview\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div\n className=\"p-4 bg-bg-sunken rounded-lg text-sm whitespace-pre-wrap font-mono\"\n dangerouslySetInnerHTML={{\n __html: highlightVariables(formData.templateText || 'Enter template text...'),\n }}\n />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Quick Tips</CardTitle>\n </CardHeader>\n <CardContent className=\"text-sm space-y-2\">\n <p>\n <strong>Variables:</strong> Use {'{{name}}'} syntax\n </p>\n <p>\n <strong>Best Practices:</strong>\n </p>\n <ul className=\"list-disc list-inside text-text-secondary space-y-1\">\n <li>Use descriptive variable names</li>\n <li>Provide default values when possible</li>\n <li>Include example inputs for testing</li>\n <li>Version your templates for changes</li>\n </ul>\n </CardContent>\n </Card>\n </div>\n </div>\n </PageLayout>\n );\n }\n\n if (loading) {\n return (\n <PageLayout title=\"Loading...\">\n <div className=\"h-96 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n </PageLayout>\n );\n }\n\n if (!template) {\n return (\n <PageLayout title=\"Template Not Found\">\n <EmptyState\n illustration=\"empty-files\"\n title=\"Template Not Found\"\n description=\"This prompt template doesn't exist.\"\n action={<Button onClick={() => navigateTo('prompt-templates')}>Back to Templates</Button>}\n />\n </PageLayout>\n );\n }\n\n // `variables`/`exampleInputs` are free-form JSON columns — normalise once.\n const templateVariables = promptTemplateVariables(template);\n const templateExamples = promptTemplateExamples(template);\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigateTo('prompt-templates')}>\n <ArrowLeft size={20} />\n </Button>\n <div className=\"p-2 rounded-lg bg-action-primary-bg/10\">\n <FileText className=\"h-6 w-6 text-primary\" />\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <span>{template.name}</span>\n <StatusBadge status={template.status} />\n <Badge variant=\"secondary\" className=\"font-mono\">\n v{template.version}\n </Badge>\n </div>\n <p className=\"text-sm font-normal text-text-secondary\">\n {template.slug} - {template.description}\n </p>\n </div>\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n leftIcon={copied ? <Check size={16} /> : <Copy size={16} />}\n onClick={handleCopyTemplate}\n >\n {copied ? 'Copied!' : 'Copy'}\n </Button>\n {isEditing ? (\n <>\n <Button variant=\"outline\" onClick={() => setIsEditing(false)}>\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleUpdate}\n isLoading={updateLoading}\n disabled={!formData.name || !formData.slug}\n >\n Save Changes\n </Button>\n </>\n ) : showDeleteConfirm ? (\n <>\n <Button variant=\"outline\" onClick={() => setShowDeleteConfirm(false)}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n leftIcon={<Trash2 size={16} />}\n onClick={() => {\n nativeImpact('medium');\n void handleDelete();\n }}\n isLoading={deleteLoading}\n >\n Confirm Delete\n </Button>\n </>\n ) : (\n <>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_UPDATE}>\n <Button variant=\"outline\" leftIcon={<Edit3 size={16} />} onClick={startEditing}>\n Edit Template\n </Button>\n </BotmanorPermissionGate>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_DELETE}>\n <Button\n variant=\"outline\"\n leftIcon={<Trash2 size={16} />}\n onClick={() => setShowDeleteConfirm(true)}\n >\n Delete\n </Button>\n </BotmanorPermissionGate>\n </>\n )}\n </div>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<FileText size={18} />}>\n This is a single reusable prompt template — its content with{' '}\n <code>{'{{variables}}'}</code>, its declared variables and example inputs, and its version\n history. Edit and preview it here to perfect the instructions, then reuse it across agents\n so they share consistent, version-controlled behaviour.\n </PagePurpose>\n\n {/* Edit Form */}\n {isEditing && (\n <Card>\n <CardHeader>\n <CardTitle>Edit Template</CardTitle>\n <CardDescription>Update template details and content</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Template Name\" required>\n <Input\n placeholder=\"e.g., Technical Support Template\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField\n label=\"Slug\"\n required\n description=\"Unique identifier (lowercase, dashes)\"\n >\n <Input\n placeholder=\"e.g., technical-support\"\n value={formData.slug}\n onChange={(e) =>\n setFormData({\n ...formData,\n slug: e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, '-'),\n })\n }\n />\n </FormField>\n </div>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this template used for?\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={2}\n />\n </FormField>\n\n <FormField label=\"Visibility\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.visibility}\n onChange={(e) =>\n setFormData({ ...formData, visibility: e.target.value as Visibility })\n }\n >\n <option value=\"PRIVATE\">Private</option>\n <option value=\"WORKSPACE\">Workspace</option>\n <option value=\"PUBLIC\">Public</option>\n </select>\n </FormField>\n\n <FormField\n label=\"Template Content\"\n description=\"Use {{variable_name}} syntax for variables\"\n >\n <Textarea\n className=\"font-mono text-sm min-h-[200px]\"\n value={formData.templateText}\n onChange={(e) => setFormData({ ...formData, templateText: e.target.value })}\n />\n </FormField>\n\n {detectedVariables.length > 0 && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Detected variables:</span>\n {detectedVariables.map((v) => (\n <Badge key={v} variant=\"secondary\" className=\"font-mono\">\n {v}\n </Badge>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n )}\n\n {/* Stats */}\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card treatment=\"glass\" glow>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary\">{templateVariables.length}</p>\n <p className=\"text-sm text-text-secondary\">Variables</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary\">{templateExamples.length}</p>\n <p className=\"text-sm text-text-secondary\">Examples</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary\">{template.revision}</p>\n <p className=\"text-sm text-text-secondary\">Revision</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-lg font-bold text-text-primary capitalize\">\n {template.visibility.toLowerCase()}\n </p>\n <p className=\"text-sm text-text-secondary\">Visibility</p>\n </CardContent>\n </Card>\n </div>\n\n {/* Tabs */}\n <div className=\"flex gap-2 border-b\">\n <Button\n variant={activeTab === 'edit' ? 'default' : 'ghost'}\n onClick={() => setActiveTab('edit')}\n >\n <Code className=\"h-4 w-4 mr-2\" />\n Template\n </Button>\n <Button\n variant={activeTab === 'preview' ? 'default' : 'ghost'}\n onClick={() => setActiveTab('preview')}\n >\n <Eye className=\"h-4 w-4 mr-2\" />\n Preview\n </Button>\n <Button\n variant={activeTab === 'test' ? 'default' : 'ghost'}\n onClick={() => setActiveTab('test')}\n >\n <Play className=\"h-4 w-4 mr-2\" />\n Test\n </Button>\n </div>\n\n {/* Tab Content */}\n {activeTab === 'edit' && (\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2\">\n <Card>\n <CardHeader>\n <CardTitle>Template Content</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"p-4 bg-bg-sunken rounded-lg font-mono text-sm whitespace-pre-wrap\">\n <div\n dangerouslySetInnerHTML={{\n __html: highlightVariables(template.templateText),\n }}\n />\n </div>\n </CardContent>\n </Card>\n </div>\n\n <div>\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Variable size={18} />\n Variables ({templateVariables.length})\n </CardTitle>\n </CardHeader>\n <CardContent>\n {templateVariables.length > 0 ? (\n <div className=\"space-y-3\">\n {templateVariables.map(\n (\n v: {\n name: string;\n type: string;\n required?: boolean;\n description?: string | null;\n defaultValue?: unknown;\n },\n i: number\n ) => (\n <div key={i} className=\"p-3 border rounded-lg\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"font-mono font-medium\">{v.name}</span>\n <div className=\"flex gap-1\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {v.type}\n </Badge>\n {v.required && (\n <Badge variant=\"destructive\" className=\"text-xs\">\n required\n </Badge>\n )}\n </div>\n </div>\n {v.description && (\n <p className=\"text-sm text-text-secondary\">{v.description}</p>\n )}\n {v.defaultValue !== undefined && (\n <p className=\"text-xs text-text-secondary mt-1\">\n Default:{' '}\n <code className=\"bg-bg-sunken px-1\">{String(v.defaultValue)}</code>\n </p>\n )}\n </div>\n )\n )}\n </div>\n ) : (\n <p className=\"text-text-secondary text-center py-4\">No variables defined</p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n )}\n\n {activeTab === 'preview' && (\n <Card>\n <CardHeader>\n <CardTitle>Rendered Preview</CardTitle>\n <CardDescription>Preview with example inputs (first example set)</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"p-4 bg-bg-sunken rounded-lg font-mono text-sm whitespace-pre-wrap\">\n {templateExamples[0] ? (\n template.templateText.replace(/\\{\\{(\\w+)\\}\\}/g, (_: string, key: string) => {\n const value = templateExamples[0][key];\n return value !== undefined ? String(value) : `{{${key}}}`;\n })\n ) : (\n <span className=\"text-text-secondary\">\n No example inputs defined. Add examples to preview rendered output.\n </span>\n )}\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeTab === 'test' && (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>Test Inputs</CardTitle>\n <CardDescription>Enter values to test the template</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {templateVariables.map((v) => (\n <FormField key={v.name} label={v.name} required={v.required}>\n <Input\n placeholder={v.defaultValue ? String(v.defaultValue) : `Enter ${v.name}`}\n value={testInputs[v.name] || ''}\n onChange={(e) => setTestInputs({ ...testInputs, [v.name]: e.target.value })}\n />\n {v.description && (\n <p className=\"text-xs text-text-secondary mt-1\">{v.description}</p>\n )}\n </FormField>\n ))}\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.PROMPT_TEMPLATE_EXECUTE}>\n <Button\n className=\"w-full\"\n leftIcon={<Play size={16} />}\n onClick={handleTestRender}\n isLoading={renderLoading}\n >\n Render Template\n </Button>\n </BotmanorPermissionGate>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Output</CardTitle>\n </CardHeader>\n <CardContent>\n {renderError ? (\n <div\n role=\"alert\"\n className=\"flex items-start gap-2 rounded-lg border border-status-error-border/40 bg-status-error-bg/10 px-3 py-2 text-sm text-status-error-text\"\n >\n <p>{renderError}</p>\n </div>\n ) : renderedOutput ? (\n <div className=\"p-4 bg-bg-sunken rounded-lg font-mono text-sm whitespace-pre-wrap\">\n {renderedOutput}\n </div>\n ) : (\n <div className=\"p-8 text-center text-text-secondary\">\n <Play className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>Enter inputs and click \"Render Template\" to see output</p>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Example Inputs */}\n {templateExamples.length > 0 && activeTab === 'edit' && (\n <Card>\n <CardHeader>\n <CardTitle>Example Inputs</CardTitle>\n <CardDescription>Pre-defined inputs for testing and documentation</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {templateExamples.map((example, index) => (\n <div key={index} className=\"p-4 border rounded-lg bg-bg-sunken/30\">\n <p className=\"text-sm font-medium mb-2\">Example {index + 1}</p>\n <div className=\"space-y-1 text-sm\">\n {Object.entries(example).map(([key, value]) => (\n <div key={key} className=\"flex justify-between\">\n <span className=\"font-mono text-text-secondary\">{key}:</span>\n <span className=\"font-mono truncate max-w-[60%]\">{String(value)}</span>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Metadata */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Settings size={18} />\n Metadata\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-6 text-sm\">\n <div>\n <p className=\"text-text-secondary\">Created</p>\n <p className=\"font-medium\">{formatRelativeTime(template.createdAt)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Updated</p>\n <p className=\"font-medium\">{formatRelativeTime(template.updatedAt)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Tags</p>\n <div className=\"flex gap-1\">\n {template.tags.length > 0 ? (\n template.tags.map((tag: string) => (\n <Badge key={tag} variant=\"secondary\" className=\"text-xs\">\n {tag}\n </Badge>\n ))\n ) : (\n <span className=\"text-text-secondary\">None</span>\n )}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ //#region src/botlit/utils/errors.ts
2
+ function e(e, t) {
3
+ if (typeof e == "object" && e && "graphQLErrors" in e) {
4
+ let t = e.graphQLErrors;
5
+ if (Array.isArray(t)) {
6
+ let e = t[0];
7
+ if (typeof e == "object" && e && "message" in e) {
8
+ let t = e.message;
9
+ if (typeof t == "string" && t.trim() !== "") return t;
10
+ }
11
+ }
12
+ }
13
+ return e instanceof Error && e.message.trim() !== "" ? e.message : t;
14
+ }
15
+ //#endregion
16
+ export { e as graphqlErrorMessage };
17
+
18
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../../../src/botlit/utils/errors.ts"],"sourcesContent":["/**\n * Extracts the user-actionable message from a failed GraphQL mutation.\n *\n * The workspace gateway returns field-level errors (e.g. the prompt-template\n * variable-contract rejections) inside the response's `errors` array. Apollo\n * surfaces them on the thrown error's `graphQLErrors`, while `err.message`\n * alone is often a generic transport/status message. Prefers the first\n * GraphQL error message, falls back to the Error message, then the caller's\n * fallback.\n */\nexport function graphqlErrorMessage(error: unknown, fallback: string): string {\n if (error !== null && typeof error === 'object' && 'graphQLErrors' in error) {\n const graphQLErrors = (error as { graphQLErrors?: unknown }).graphQLErrors;\n if (Array.isArray(graphQLErrors)) {\n const first = graphQLErrors[0];\n if (first !== null && typeof first === 'object' && 'message' in first) {\n const message = (first as { message?: unknown }).message;\n if (typeof message === 'string' && message.trim() !== '') {\n return message;\n }\n }\n }\n }\n if (error instanceof Error && error.message.trim() !== '') {\n return error.message;\n }\n return fallback;\n}\n"],"mappings":";AAUA,SAAgB,EAAoB,GAAgB,GAA0B;AAC5E,KAAsB,OAAO,KAAU,YAAnC,KAA+C,mBAAmB,GAAO;EAC3E,IAAM,IAAiB,EAAsC;AAC7D,MAAI,MAAM,QAAQ,EAAc,EAAE;GAChC,IAAM,IAAQ,EAAc;AAC5B,OAAsB,OAAO,KAAU,YAAnC,KAA+C,aAAa,GAAO;IACrE,IAAM,IAAW,EAAgC;AACjD,QAAI,OAAO,KAAY,YAAY,EAAQ,MAAM,KAAK,GACpD,QAAO;;;;AAQf,QAHI,aAAiB,SAAS,EAAM,QAAQ,MAAM,KAAK,KAC9C,EAAM,UAER"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-botmanor",
3
- "version": "2026.1031.1",
3
+ "version": "2026.1101.1",
4
4
  "description": "Burdenoff BotManor Microfrontend - AI Agent platform interface for building, deploying and managing AI agents",
5
5
  "type": "module",
6
6
  "files": [