@datatechsolutions/ui 2.11.81 → 2.11.82

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.
Files changed (57) hide show
  1. package/dist/astrlabe/contracts.d.mts +5 -0
  2. package/dist/astrlabe/contracts.d.ts +5 -0
  3. package/dist/astrlabe/index.d.mts +11 -83
  4. package/dist/astrlabe/index.d.ts +11 -83
  5. package/dist/astrlabe/index.js +175 -4777
  6. package/dist/astrlabe/index.js.map +1 -1
  7. package/dist/astrlabe/index.mjs +3 -4740
  8. package/dist/astrlabe/index.mjs.map +1 -1
  9. package/dist/astrlabe/workflow-canvas.d.mts +69 -5
  10. package/dist/astrlabe/workflow-canvas.d.ts +69 -5
  11. package/dist/chunk-6PBTB5ZX.js +165 -0
  12. package/dist/chunk-6PBTB5ZX.js.map +1 -0
  13. package/dist/chunk-HAZP5J67.mjs +4781 -0
  14. package/dist/chunk-HAZP5J67.mjs.map +1 -0
  15. package/dist/chunk-HZ4LOVHM.js +46 -0
  16. package/dist/chunk-HZ4LOVHM.js.map +1 -0
  17. package/dist/chunk-K4QJV3GC.js +4825 -0
  18. package/dist/chunk-K4QJV3GC.js.map +1 -0
  19. package/dist/chunk-UHHPBREK.mjs +135 -0
  20. package/dist/chunk-UHHPBREK.mjs.map +1 -0
  21. package/dist/chunk-ZJPNP2YW.mjs +44 -0
  22. package/dist/chunk-ZJPNP2YW.mjs.map +1 -0
  23. package/dist/{workflow-canvas-NSxfr5dy.d.ts → index-AioB90qq.d.mts} +2 -67
  24. package/dist/{workflow-canvas-D4928AfA.d.mts → index-D5ai0cGZ.d.ts} +2 -67
  25. package/dist/platform/index.d.mts +41 -0
  26. package/dist/platform/index.d.ts +41 -0
  27. package/dist/platform/index.js +237 -0
  28. package/dist/platform/index.js.map +1 -0
  29. package/dist/platform/index.mjs +109 -0
  30. package/dist/platform/index.mjs.map +1 -0
  31. package/dist/platform/pages/index.d.mts +272 -0
  32. package/dist/platform/pages/index.d.ts +272 -0
  33. package/dist/platform/pages/index.js +1793 -0
  34. package/dist/platform/pages/index.js.map +1 -0
  35. package/dist/platform/pages/index.mjs +1777 -0
  36. package/dist/platform/pages/index.mjs.map +1 -0
  37. package/dist/platform/rbac.d.mts +41 -0
  38. package/dist/platform/rbac.d.ts +41 -0
  39. package/dist/platform/rbac.js +13 -0
  40. package/dist/platform/rbac.js.map +1 -0
  41. package/dist/platform/rbac.mjs +4 -0
  42. package/dist/platform/rbac.mjs.map +1 -0
  43. package/dist/platform/utils/index.d.mts +32 -0
  44. package/dist/platform/utils/index.d.ts +32 -0
  45. package/dist/platform/utils/index.js +131 -0
  46. package/dist/platform/utils/index.js.map +1 -0
  47. package/dist/platform/utils/index.mjs +119 -0
  48. package/dist/platform/utils/index.mjs.map +1 -0
  49. package/dist/platform/windsock-admin-client.d.mts +57 -0
  50. package/dist/platform/windsock-admin-client.d.ts +57 -0
  51. package/dist/platform/windsock-admin-client.js +125 -0
  52. package/dist/platform/windsock-admin-client.js.map +1 -0
  53. package/dist/platform/windsock-admin-client.mjs +4 -0
  54. package/dist/platform/windsock-admin-client.mjs.map +1 -0
  55. package/dist/rule-form-F5jBOeqk.d.mts +79 -0
  56. package/dist/rule-form-F5jBOeqk.d.ts +79 -0
  57. package/package.json +27 -1
@@ -0,0 +1,1777 @@
1
+ "use client";
2
+ import { defaultRuleForm, RuleForm } from '../../chunk-HAZP5J67.mjs';
3
+ import '../../chunk-JB6RNAD2.mjs';
4
+ import '../../chunk-53SRKVKQ.mjs';
5
+ import '../../chunk-J3OYJ44D.mjs';
6
+ import { HeroSection, CreateActionButton, EntityCard, InlineForm, FormSelect, Button, GlassModal, FormGrid, FormInput, PageLoadingState, PageEmptyState, Badge, ManagementPageLayout, FormTextarea } from '../../chunk-LLFU42KC.mjs';
7
+ import '../../chunk-7VJ7CMMT.mjs';
8
+ import '../../chunk-QWG2FMUN.mjs';
9
+ import '../../chunk-D2JF6C3E.mjs';
10
+ import '../../chunk-OZNTQROP.mjs';
11
+ import '../../chunk-WNCPAWLC.mjs';
12
+ import { useState, useMemo } from 'react';
13
+ import { CircleStackIcon, ServerStackIcon, CloudIcon, ClockIcon, ShareIcon, KeyIcon, MagnifyingGlassIcon, UserGroupIcon, CubeTransparentIcon, CpuChipIcon, ChatBubbleLeftEllipsisIcon, WrenchScrewdriverIcon, AdjustmentsHorizontalIcon, ArrowLeftIcon, CheckCircleIcon, XCircleIcon } from '@heroicons/react/24/outline';
14
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
15
+
16
+ var ROLE_OPTIONS = [
17
+ { value: "admin", label: "Admin" },
18
+ { value: "manager", label: "Manager" },
19
+ { value: "analyst", label: "Analyst" },
20
+ { value: "viewer", label: "Viewer" }
21
+ ];
22
+ function UsersPageView({ labels, users, onCreateUser, onUpdateRole }) {
23
+ const [createOpen, setCreateOpen] = useState(false);
24
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
25
+ /* @__PURE__ */ jsx(
26
+ HeroSection,
27
+ {
28
+ icon: /* @__PURE__ */ jsx(UserGroupIcon, { className: "h-5 w-5" }),
29
+ label: labels.title,
30
+ title: labels.title,
31
+ subtitle: labels.subtitle,
32
+ gradient: "from-violet-500 to-indigo-600",
33
+ toolbar: /* @__PURE__ */ jsx(
34
+ CreateActionButton,
35
+ {
36
+ mode: "desktop",
37
+ label: labels.create,
38
+ onClick: () => setCreateOpen(true),
39
+ accent: "violet"
40
+ }
41
+ )
42
+ }
43
+ ),
44
+ /* @__PURE__ */ jsx(
45
+ CreateActionButton,
46
+ {
47
+ mode: "mobile",
48
+ label: labels.create,
49
+ onClick: () => setCreateOpen(true),
50
+ accent: "violet"
51
+ }
52
+ ),
53
+ /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
54
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: labels.list }),
55
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: users.map((user) => /* @__PURE__ */ jsx(
56
+ EntityCard,
57
+ {
58
+ accentGradient: "from-violet-500 to-indigo-700",
59
+ icon: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg bg-violet-500/10 text-violet-600 dark:bg-violet-500/20 dark:text-violet-400", children: /* @__PURE__ */ jsx(UserGroupIcon, { className: "h-6 w-6" }) }),
60
+ title: user.name,
61
+ subtitle: user.email,
62
+ status: /* @__PURE__ */ jsx(
63
+ "span",
64
+ {
65
+ className: `shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold ${user.active ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300" : "bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300"}`,
66
+ children: user.active ? labels.statusActive : labels.statusInactive
67
+ }
68
+ ),
69
+ footer: /* @__PURE__ */ jsx(
70
+ "form",
71
+ {
72
+ onSubmit: (event) => {
73
+ event.preventDefault();
74
+ const formData = new FormData(event.currentTarget);
75
+ const role = String(formData.get("role") ?? "viewer");
76
+ onUpdateRole({ email: user.email, role });
77
+ },
78
+ children: /* @__PURE__ */ jsxs(InlineForm, { children: [
79
+ /* @__PURE__ */ jsx(FormSelect, { name: "role", options: ROLE_OPTIONS, defaultValue: user.role }),
80
+ /* @__PURE__ */ jsx(Button, { type: "submit", outline: true, size: "sm", children: labels.save })
81
+ ] })
82
+ }
83
+ )
84
+ },
85
+ user.email
86
+ )) })
87
+ ] }),
88
+ /* @__PURE__ */ jsx(
89
+ GlassModal,
90
+ {
91
+ open: createOpen,
92
+ onClose: () => setCreateOpen(false),
93
+ title: labels.create,
94
+ maxWidth: "lg",
95
+ showFormFooter: true,
96
+ cancelLabel: labels.list,
97
+ submitLabel: labels.add,
98
+ onSubmit: (event) => {
99
+ const formData = new FormData(event.currentTarget);
100
+ const name = String(formData.get("name") ?? "").trim();
101
+ const email = String(formData.get("email") ?? "").trim().toLowerCase();
102
+ const role = String(formData.get("role") ?? "viewer");
103
+ if (!name || !email) return;
104
+ onCreateUser({ name, email, role });
105
+ setCreateOpen(false);
106
+ },
107
+ children: /* @__PURE__ */ jsxs(FormGrid, { children: [
108
+ /* @__PURE__ */ jsx(FormInput, { name: "name", label: labels.name, placeholder: labels.userNamePlaceholder, required: true }),
109
+ /* @__PURE__ */ jsx(FormInput, { name: "email", label: labels.email, placeholder: labels.userEmailPlaceholder, required: true, type: "email" }),
110
+ /* @__PURE__ */ jsx(FormSelect, { name: "role", label: labels.role, options: ROLE_OPTIONS })
111
+ ] })
112
+ }
113
+ )
114
+ ] });
115
+ }
116
+ function AgentsModelsPageView({ labels, models, loading }) {
117
+ const hero = /* @__PURE__ */ jsx(
118
+ HeroSection,
119
+ {
120
+ icon: /* @__PURE__ */ jsx(CubeTransparentIcon, { className: "h-5 w-5" }),
121
+ label: labels.title,
122
+ title: labels.title,
123
+ subtitle: labels.subtitle,
124
+ gradient: "from-emerald-500 to-teal-700"
125
+ }
126
+ );
127
+ const content = loading ? /* @__PURE__ */ jsx(PageLoadingState, {}) : models.length === 0 ? /* @__PURE__ */ jsx(PageEmptyState, { title: labels.empty, message: labels.subtitle, iconName: "folder-open" }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: models.map((model) => /* @__PURE__ */ jsx(
128
+ EntityCard,
129
+ {
130
+ accentGradient: "from-emerald-500 to-teal-700",
131
+ icon: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg bg-emerald-500/10 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400", children: /* @__PURE__ */ jsx(CubeTransparentIcon, { className: "h-6 w-6" }) }),
132
+ title: model.name,
133
+ subtitle: `${labels.provider}: ${model.provider}`,
134
+ status: /* @__PURE__ */ jsx(Badge, { color: model.enabled ? "emerald" : "zinc", children: model.enabled ? labels.enabled : labels.disabled })
135
+ },
136
+ model.id
137
+ )) });
138
+ return /* @__PURE__ */ jsx(ManagementPageLayout, { hero, content });
139
+ }
140
+ function AgentsConfigPageView({ labels, agents, models, loading, onCreate, onUpdate, onDelete }) {
141
+ const [editing, setEditing] = useState(null);
142
+ const [createOpen, setCreateOpen] = useState(false);
143
+ const modelOptions = models.map((model) => ({ value: model.id, label: `${model.name} (${model.provider})` }));
144
+ const hero = /* @__PURE__ */ jsx(
145
+ HeroSection,
146
+ {
147
+ icon: /* @__PURE__ */ jsx(CpuChipIcon, { className: "h-5 w-5" }),
148
+ label: labels.title,
149
+ title: labels.title,
150
+ subtitle: labels.subtitle,
151
+ gradient: "from-violet-500 to-indigo-700",
152
+ toolbar: /* @__PURE__ */ jsx(
153
+ CreateActionButton,
154
+ {
155
+ mode: "desktop",
156
+ label: labels.addAgent,
157
+ onClick: () => setCreateOpen(true),
158
+ accent: "violet"
159
+ }
160
+ )
161
+ }
162
+ );
163
+ const mobileAction = /* @__PURE__ */ jsx(
164
+ CreateActionButton,
165
+ {
166
+ mode: "mobile",
167
+ label: labels.addAgent,
168
+ onClick: () => setCreateOpen(true),
169
+ accent: "violet"
170
+ }
171
+ );
172
+ const content = loading ? /* @__PURE__ */ jsx(PageLoadingState, {}) : agents.length === 0 ? /* @__PURE__ */ jsx(PageEmptyState, { title: labels.empty, message: labels.subtitle, iconName: "folder-open" }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: agents.map((agent) => {
173
+ const modelRecord = models.find((model) => model.id === String(agent.modelId ?? ""));
174
+ return /* @__PURE__ */ jsx(
175
+ EntityCard,
176
+ {
177
+ accentGradient: "from-violet-500 to-indigo-700",
178
+ icon: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg bg-violet-500/10 text-violet-600 dark:bg-violet-500/20 dark:text-violet-400", children: /* @__PURE__ */ jsx(CpuChipIcon, { className: "h-6 w-6" }) }),
179
+ title: String(agent.name ?? ""),
180
+ subtitle: String(modelRecord?.name ?? agent.modelId ?? ""),
181
+ status: agent.activePromptVersion > 0 ? /* @__PURE__ */ jsxs(Badge, { color: "emerald", children: [
182
+ "v",
183
+ agent.activePromptVersion
184
+ ] }) : null,
185
+ footer: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
186
+ /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", outline: true, onClick: () => setEditing(agent), children: labels.edit }),
187
+ /* @__PURE__ */ jsx(
188
+ Button,
189
+ {
190
+ type: "button",
191
+ size: "sm",
192
+ color: "rose",
193
+ onClick: () => {
194
+ if (window.confirm(labels.deleteConfirm)) onDelete(agent);
195
+ },
196
+ children: labels.delete
197
+ }
198
+ )
199
+ ] }),
200
+ children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-slate-500 dark:text-slate-400", children: [
201
+ labels.activeVersion,
202
+ ": ",
203
+ agent.activePromptVersion,
204
+ " \xB7 Prompts: ",
205
+ agent.promptCount
206
+ ] })
207
+ },
208
+ String(agent.agentId ?? agent.id ?? agent.name)
209
+ );
210
+ }) });
211
+ const renderForm = (initial, onSubmit) => /* @__PURE__ */ jsx(
212
+ GlassModal,
213
+ {
214
+ open: true,
215
+ onClose: () => {
216
+ setEditing(null);
217
+ setCreateOpen(false);
218
+ },
219
+ title: initial.title,
220
+ maxWidth: "lg",
221
+ showFormFooter: true,
222
+ submitLabel: labels.save,
223
+ onSubmit: (event) => {
224
+ const form = new FormData(event.currentTarget);
225
+ onSubmit({
226
+ agentId: initial.agentId,
227
+ name: String(form.get("name") ?? "").trim(),
228
+ modelId: String(form.get("modelId") ?? ""),
229
+ systemPrompt: String(form.get("systemPrompt") ?? "").trim(),
230
+ maxTokens: Number(form.get("maxTokens") ?? 2048),
231
+ temperature: Number(form.get("temperature") ?? 0.2),
232
+ outputSchema: String(form.get("outputSchema") ?? "").trim() || void 0
233
+ });
234
+ },
235
+ children: /* @__PURE__ */ jsxs(FormGrid, { children: [
236
+ /* @__PURE__ */ jsx(FormInput, { name: "name", label: labels.name, defaultValue: initial.name ?? "", required: true }),
237
+ /* @__PURE__ */ jsx(FormSelect, { name: "modelId", label: labels.model, options: modelOptions, defaultValue: initial.modelId ?? modelOptions[0]?.value ?? "", required: true }),
238
+ /* @__PURE__ */ jsx(FormInput, { name: "maxTokens", label: String(labels.maxTokens), type: "number", defaultValue: String(initial.maxTokens ?? 2048) }),
239
+ /* @__PURE__ */ jsx(FormInput, { name: "temperature", label: labels.temperature, type: "number", step: 0.1, min: 0, max: 2, defaultValue: String(initial.temperature ?? 0.2) }),
240
+ /* @__PURE__ */ jsx(FormTextarea, { name: "systemPrompt", label: labels.systemPrompt, defaultValue: initial.systemPrompt ?? "", rows: 4 }),
241
+ /* @__PURE__ */ jsx(FormTextarea, { name: "outputSchema", label: labels.outputSchema, placeholder: labels.outputSchemaPlaceholder, defaultValue: initial.outputSchema ?? "", rows: 4 })
242
+ ] })
243
+ }
244
+ );
245
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
246
+ /* @__PURE__ */ jsx(ManagementPageLayout, { hero, content, mobileAction }),
247
+ createOpen && renderForm({ title: labels.createTitle }, (input) => {
248
+ onCreate(input);
249
+ setCreateOpen(false);
250
+ }),
251
+ editing && renderForm(
252
+ {
253
+ title: labels.editTitle,
254
+ agentId: String(editing.agentId ?? editing.id ?? ""),
255
+ name: String(editing.name ?? ""),
256
+ modelId: String(editing.modelId ?? ""),
257
+ systemPrompt: String(editing.systemPrompt ?? ""),
258
+ maxTokens: Number(editing.maxTokens ?? 2048),
259
+ temperature: Number(editing.temperature ?? 0.2),
260
+ outputSchema: String(editing.outputSchema ?? "")
261
+ },
262
+ (input) => {
263
+ onUpdate(String(editing.agentId ?? editing.id ?? ""), input);
264
+ setEditing(null);
265
+ }
266
+ )
267
+ ] });
268
+ }
269
+ var LOCALE_OPTIONS = [
270
+ { value: "en", label: "English" },
271
+ { value: "pt-BR", label: "Portugu\xEAs (Brasil)" },
272
+ { value: "es", label: "Espa\xF1ol" },
273
+ { value: "fr", label: "Fran\xE7ais" },
274
+ { value: "de", label: "Deutsch" },
275
+ { value: "it", label: "Italiano" }
276
+ ];
277
+ function AgentsPromptsPageView({ labels, agents, prompts, loading, onCreate, onActivate, onDelete }) {
278
+ const [createOpen, setCreateOpen] = useState(false);
279
+ const agentOptions = useMemo(
280
+ () => agents.map((agent) => ({
281
+ value: String(agent.agentId ?? agent.id ?? ""),
282
+ label: String(agent.name ?? agent.agentId ?? agent.id ?? "")
283
+ })),
284
+ [agents]
285
+ );
286
+ const agentNameById = useMemo(() => {
287
+ const map = /* @__PURE__ */ new Map();
288
+ for (const agent of agents) {
289
+ const id = String(agent.agentId ?? agent.id ?? "");
290
+ if (id) map.set(id, String(agent.name ?? id));
291
+ }
292
+ return map;
293
+ }, [agents]);
294
+ const hero = /* @__PURE__ */ jsx(
295
+ HeroSection,
296
+ {
297
+ icon: /* @__PURE__ */ jsx(ChatBubbleLeftEllipsisIcon, { className: "h-5 w-5" }),
298
+ label: labels.title,
299
+ title: labels.title,
300
+ subtitle: labels.subtitle,
301
+ gradient: "from-sky-500 to-blue-700",
302
+ toolbar: /* @__PURE__ */ jsx(
303
+ CreateActionButton,
304
+ {
305
+ mode: "desktop",
306
+ label: labels.addPrompt,
307
+ onClick: () => setCreateOpen(true),
308
+ accent: "sky"
309
+ }
310
+ )
311
+ }
312
+ );
313
+ const mobileAction = /* @__PURE__ */ jsx(
314
+ CreateActionButton,
315
+ {
316
+ mode: "mobile",
317
+ label: labels.addPrompt,
318
+ onClick: () => setCreateOpen(true),
319
+ accent: "sky"
320
+ }
321
+ );
322
+ const content = loading ? /* @__PURE__ */ jsx(PageLoadingState, {}) : prompts.length === 0 ? /* @__PURE__ */ jsx(PageEmptyState, { title: labels.empty, message: labels.subtitle, iconName: "folder-open" }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: prompts.map((prompt) => {
323
+ const agentName = agentNameById.get(prompt.agentId) ?? prompt.agentId;
324
+ const key = `${prompt.agentId}:${prompt.locale}:${prompt.version}`;
325
+ return /* @__PURE__ */ jsx(
326
+ EntityCard,
327
+ {
328
+ accentGradient: "from-sky-500 to-blue-700",
329
+ icon: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg bg-sky-500/10 text-sky-600 dark:bg-sky-500/20 dark:text-sky-400", children: /* @__PURE__ */ jsx(ChatBubbleLeftEllipsisIcon, { className: "h-6 w-6" }) }),
330
+ title: agentName,
331
+ subtitle: `${prompt.locale} \xB7 v${prompt.version}`,
332
+ status: prompt.isActive ? /* @__PURE__ */ jsx(Badge, { color: "emerald", children: labels.isActive }) : null,
333
+ footer: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
334
+ !prompt.isActive && /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", outline: true, onClick: () => onActivate(prompt), children: labels.activate }),
335
+ /* @__PURE__ */ jsx(
336
+ Button,
337
+ {
338
+ type: "button",
339
+ size: "sm",
340
+ color: "rose",
341
+ onClick: () => {
342
+ if (window.confirm(labels.deleteConfirm)) onDelete(prompt);
343
+ },
344
+ children: labels.delete
345
+ }
346
+ )
347
+ ] }),
348
+ children: prompt.prompt && /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-3 text-xs text-slate-500 dark:text-slate-400", children: prompt.prompt })
349
+ },
350
+ key
351
+ );
352
+ }) });
353
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
354
+ /* @__PURE__ */ jsx(ManagementPageLayout, { hero, content, mobileAction }),
355
+ /* @__PURE__ */ jsx(
356
+ GlassModal,
357
+ {
358
+ open: createOpen,
359
+ onClose: () => setCreateOpen(false),
360
+ title: labels.createTitle,
361
+ maxWidth: "2xl",
362
+ showFormFooter: true,
363
+ submitLabel: labels.save,
364
+ onSubmit: (event) => {
365
+ const form = new FormData(event.currentTarget);
366
+ const systemPrompt = String(form.get("systemPrompt") ?? "").trim();
367
+ const userTemplate = String(form.get("userTemplate") ?? "").trim();
368
+ const reason = String(form.get("reason") ?? "").trim();
369
+ onCreate({
370
+ agentId: String(form.get("agentId") ?? "").trim(),
371
+ locale: String(form.get("locale") ?? "en").trim(),
372
+ prompt: String(form.get("prompt") ?? "").trim(),
373
+ systemPrompt: systemPrompt || void 0,
374
+ userTemplate: userTemplate || void 0,
375
+ reason: reason || void 0,
376
+ isActive: String(form.get("isActive") ?? "true") === "true"
377
+ });
378
+ setCreateOpen(false);
379
+ },
380
+ children: /* @__PURE__ */ jsxs(FormGrid, { children: [
381
+ /* @__PURE__ */ jsx(FormSelect, { name: "agentId", label: labels.agent, options: agentOptions, required: true }),
382
+ /* @__PURE__ */ jsx(FormSelect, { name: "locale", label: labels.locale, options: LOCALE_OPTIONS, defaultValue: "en" }),
383
+ /* @__PURE__ */ jsx(
384
+ FormSelect,
385
+ {
386
+ name: "isActive",
387
+ label: labels.isActive,
388
+ options: [{ value: "true", label: labels.isActive }, { value: "false", label: labels.isActive }],
389
+ defaultValue: "true"
390
+ }
391
+ ),
392
+ /* @__PURE__ */ jsx(FormInput, { name: "reason", label: labels.reason }),
393
+ /* @__PURE__ */ jsx(FormTextarea, { name: "systemPrompt", label: labels.systemPrompt, rows: 3 }),
394
+ /* @__PURE__ */ jsx(FormTextarea, { name: "userTemplate", label: labels.userTemplate, rows: 3 }),
395
+ /* @__PURE__ */ jsx(FormTextarea, { name: "prompt", label: labels.prompt, rows: 6, required: true })
396
+ ] })
397
+ }
398
+ )
399
+ ] });
400
+ }
401
+ var TOOL_TYPES = [
402
+ "http",
403
+ "function",
404
+ "database_query",
405
+ "code_execution",
406
+ "api_call"
407
+ ];
408
+ var TOOL_TYPE_OPTIONS = [
409
+ { value: "http", label: "HTTP", description: "Call an HTTP endpoint with templated URL/body." },
410
+ { value: "function", label: "Function", description: "Invoke a pre-registered server-side implementation." },
411
+ { value: "database_query", label: "Database query", description: "Run a parameterized SELECT against a datasource." },
412
+ { value: "code_execution", label: "Code execution", description: "Run sandboxed code (JS/Python) \u2014 experimental." },
413
+ { value: "api_call", label: "API call", description: "Call a third-party API via stored credentials." }
414
+ ];
415
+ var PARAMETER_TYPE_OPTIONS = [
416
+ { value: "string", label: "string" },
417
+ { value: "number", label: "number" },
418
+ { value: "boolean", label: "boolean" },
419
+ { value: "array", label: "array" },
420
+ { value: "object", label: "object" }
421
+ ];
422
+ function AgentsToolDefinitionsPageView({ labels, tools, loading, onCreate, onUpdate, onDelete }) {
423
+ const [editing, setEditing] = useState(null);
424
+ const [createOpen, setCreateOpen] = useState(false);
425
+ const hero = /* @__PURE__ */ jsx(
426
+ HeroSection,
427
+ {
428
+ icon: /* @__PURE__ */ jsx(WrenchScrewdriverIcon, { className: "h-5 w-5" }),
429
+ label: labels.title,
430
+ title: labels.title,
431
+ subtitle: labels.subtitle,
432
+ gradient: "from-amber-500 to-orange-700",
433
+ toolbar: /* @__PURE__ */ jsx(
434
+ CreateActionButton,
435
+ {
436
+ mode: "desktop",
437
+ label: labels.addTool,
438
+ onClick: () => setCreateOpen(true),
439
+ accent: "amber"
440
+ }
441
+ )
442
+ }
443
+ );
444
+ const mobileAction = /* @__PURE__ */ jsx(
445
+ CreateActionButton,
446
+ {
447
+ mode: "mobile",
448
+ label: labels.addTool,
449
+ onClick: () => setCreateOpen(true),
450
+ accent: "amber"
451
+ }
452
+ );
453
+ const content = loading ? /* @__PURE__ */ jsx(PageLoadingState, {}) : tools.length === 0 ? /* @__PURE__ */ jsx(PageEmptyState, { title: labels.empty, message: labels.subtitle, iconName: "folder-open" }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: tools.map((tool) => /* @__PURE__ */ jsx(
454
+ EntityCard,
455
+ {
456
+ accentGradient: "from-amber-500 to-orange-700",
457
+ icon: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg bg-amber-500/10 text-amber-600 dark:bg-amber-500/20 dark:text-amber-400", children: /* @__PURE__ */ jsx(WrenchScrewdriverIcon, { className: "h-6 w-6" }) }),
458
+ title: tool.name,
459
+ subtitle: toolTypeLabel(tool),
460
+ status: /* @__PURE__ */ jsx(Badge, { color: tool.enabled ? "emerald" : "zinc", children: tool.enabled ? labels.enabled : labels.disabled }),
461
+ footer: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
462
+ /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", outline: true, onClick: () => setEditing(tool), children: labels.edit }),
463
+ /* @__PURE__ */ jsx(
464
+ Button,
465
+ {
466
+ type: "button",
467
+ size: "sm",
468
+ color: "rose",
469
+ onClick: () => {
470
+ if (window.confirm(labels.deleteConfirm)) onDelete(tool);
471
+ },
472
+ children: labels.delete
473
+ }
474
+ )
475
+ ] }),
476
+ children: tool.description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: tool.description })
477
+ },
478
+ tool.agentToolId
479
+ )) });
480
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
481
+ /* @__PURE__ */ jsx(ManagementPageLayout, { hero, content, mobileAction }),
482
+ createOpen && /* @__PURE__ */ jsx(
483
+ ToolEditor,
484
+ {
485
+ title: labels.createTitle,
486
+ saveLabel: labels.save,
487
+ initial: defaultForm(),
488
+ onClose: () => setCreateOpen(false),
489
+ onSubmit: (input) => {
490
+ onCreate(input);
491
+ setCreateOpen(false);
492
+ }
493
+ }
494
+ ),
495
+ editing && /* @__PURE__ */ jsx(
496
+ ToolEditor,
497
+ {
498
+ title: labels.editTitle,
499
+ saveLabel: labels.save,
500
+ initial: toolToForm(editing),
501
+ onClose: () => setEditing(null),
502
+ onSubmit: (input) => {
503
+ onUpdate(editing.agentToolId, input);
504
+ setEditing(null);
505
+ }
506
+ }
507
+ )
508
+ ] });
509
+ }
510
+ function ToolEditor({
511
+ title,
512
+ saveLabel,
513
+ initial,
514
+ onSubmit,
515
+ onClose
516
+ }) {
517
+ const [value, setValue] = useState(initial);
518
+ const [error, setError] = useState(null);
519
+ const handleSubmit = () => {
520
+ if (!value.name.trim()) {
521
+ setError("Name is required");
522
+ return;
523
+ }
524
+ const names = value.parameters.map((p) => p.name.trim());
525
+ if (names.some((n) => n.length === 0)) {
526
+ setError("Every parameter must have a name");
527
+ return;
528
+ }
529
+ if (new Set(names).size !== names.length) {
530
+ setError("Parameter names must be unique");
531
+ return;
532
+ }
533
+ onSubmit(value);
534
+ };
535
+ const update = (key, next) => {
536
+ setValue((v) => ({ ...v, [key]: next }));
537
+ };
538
+ return /* @__PURE__ */ jsx(
539
+ GlassModal,
540
+ {
541
+ open: true,
542
+ onClose,
543
+ title,
544
+ maxWidth: "3xl",
545
+ showFormFooter: true,
546
+ submitLabel: saveLabel,
547
+ onSubmit: (event) => {
548
+ event.preventDefault();
549
+ handleSubmit();
550
+ },
551
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
552
+ /* @__PURE__ */ jsxs(FormGrid, { children: [
553
+ /* @__PURE__ */ jsx(
554
+ FormInput,
555
+ {
556
+ label: "Name",
557
+ required: true,
558
+ value: value.name,
559
+ onValueChange: (name) => update("name", name),
560
+ placeholder: "get_station_prices"
561
+ }
562
+ ),
563
+ /* @__PURE__ */ jsx(
564
+ FormSelect,
565
+ {
566
+ label: "Tool type",
567
+ value: value.toolType,
568
+ options: TOOL_TYPE_OPTIONS.map((o) => ({ value: o.value, label: o.label })),
569
+ onValueChange: (v) => update("toolType", v),
570
+ hint: TOOL_TYPE_OPTIONS.find((o) => o.value === value.toolType)?.description
571
+ }
572
+ ),
573
+ /* @__PURE__ */ jsx(
574
+ FormSelect,
575
+ {
576
+ label: "Enabled",
577
+ value: value.enabled ? "true" : "false",
578
+ options: [{ value: "true", label: "Enabled" }, { value: "false", label: "Disabled" }],
579
+ onValueChange: (v) => update("enabled", v === "true")
580
+ }
581
+ ),
582
+ /* @__PURE__ */ jsx(
583
+ FormInput,
584
+ {
585
+ label: "Icon (optional)",
586
+ value: value.icon ?? "",
587
+ onValueChange: (icon) => update("icon", icon),
588
+ placeholder: "heroicons:wrench-screwdriver"
589
+ }
590
+ )
591
+ ] }),
592
+ /* @__PURE__ */ jsx(
593
+ FormTextarea,
594
+ {
595
+ label: "Description",
596
+ rows: 2,
597
+ value: value.description ?? "",
598
+ onValueChange: (description) => update("description", description),
599
+ placeholder: "One-sentence summary shown to the agent when it picks tools."
600
+ }
601
+ ),
602
+ /* @__PURE__ */ jsx(
603
+ ParametersEditor,
604
+ {
605
+ parameters: value.parameters,
606
+ onChange: (parameters) => update("parameters", parameters)
607
+ }
608
+ ),
609
+ /* @__PURE__ */ jsx(
610
+ HandlerConfigEditor,
611
+ {
612
+ toolType: value.toolType,
613
+ config: value.handlerConfig,
614
+ onChange: (handlerConfig) => update("handlerConfig", handlerConfig)
615
+ }
616
+ ),
617
+ error && /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-red-400/40 bg-red-500/10 p-2 text-xs text-red-600 dark:text-red-300", children: error })
618
+ ] })
619
+ }
620
+ );
621
+ }
622
+ function ParametersEditor({
623
+ parameters,
624
+ onChange
625
+ }) {
626
+ const update = (index, patch) => {
627
+ onChange(parameters.map((p, i) => i === index ? { ...p, ...patch } : p));
628
+ };
629
+ const remove = (index) => {
630
+ onChange(parameters.filter((_, i) => i !== index));
631
+ };
632
+ const add = () => {
633
+ onChange([...parameters, { name: "", type: "string", description: "", required: false }]);
634
+ };
635
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-xl border border-slate-200 bg-slate-50/60 p-3 dark:border-slate-700 dark:bg-slate-900/40", children: [
636
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold text-slate-700 dark:text-slate-200", children: "Parameters" }),
637
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500 dark:text-slate-400", children: "The agent gets these as a JSON Schema. Any parameter marked required must be supplied for the LLM to call the tool." }),
638
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
639
+ parameters.map((param, index) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_160px_1fr_110px_auto] items-end gap-2", children: [
640
+ /* @__PURE__ */ jsx(
641
+ FormInput,
642
+ {
643
+ label: "Name",
644
+ value: param.name,
645
+ onValueChange: (name) => update(index, { name }),
646
+ placeholder: "station_id"
647
+ }
648
+ ),
649
+ /* @__PURE__ */ jsx(
650
+ FormSelect,
651
+ {
652
+ label: "Type",
653
+ value: param.type,
654
+ options: PARAMETER_TYPE_OPTIONS,
655
+ onValueChange: (t) => update(index, { type: t })
656
+ }
657
+ ),
658
+ /* @__PURE__ */ jsx(
659
+ FormInput,
660
+ {
661
+ label: "Description",
662
+ value: param.description,
663
+ onValueChange: (description) => update(index, { description })
664
+ }
665
+ ),
666
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 pb-2 text-xs text-gray-700 dark:text-gray-300", children: [
667
+ /* @__PURE__ */ jsx(
668
+ "input",
669
+ {
670
+ type: "checkbox",
671
+ checked: param.required,
672
+ onChange: (event) => update(index, { required: event.target.checked }),
673
+ className: "h-4 w-4 rounded border-gray-300"
674
+ }
675
+ ),
676
+ "Required"
677
+ ] }),
678
+ /* @__PURE__ */ jsx(Button, { type: "button", plain: true, onClick: () => remove(index), children: "Remove" })
679
+ ] }, index)),
680
+ /* @__PURE__ */ jsx(Button, { type: "button", outline: true, onClick: add, children: "+ Add parameter" })
681
+ ] })
682
+ ] });
683
+ }
684
+ function HandlerConfigEditor({
685
+ toolType,
686
+ config,
687
+ onChange
688
+ }) {
689
+ const set = (key, value) => onChange({ ...config, [key]: value });
690
+ if (toolType === "http") {
691
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-xl border border-slate-200 bg-slate-50/60 p-3 dark:border-slate-700 dark:bg-slate-900/40", children: [
692
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold text-slate-700 dark:text-slate-200", children: "HTTP handler" }),
693
+ /* @__PURE__ */ jsxs(FormGrid, { children: [
694
+ /* @__PURE__ */ jsx(
695
+ FormSelect,
696
+ {
697
+ label: "Method",
698
+ value: stringProp(config, "method", "GET"),
699
+ options: ["GET", "POST", "PUT", "PATCH", "DELETE"].map((m) => ({ value: m, label: m })),
700
+ onValueChange: (m) => set("method", m)
701
+ }
702
+ ),
703
+ /* @__PURE__ */ jsx(
704
+ FormInput,
705
+ {
706
+ label: "URL template",
707
+ value: stringProp(config, "url"),
708
+ onValueChange: (u) => set("url", u),
709
+ placeholder: "https://api.example.com/stations/{{ station_id }}"
710
+ }
711
+ )
712
+ ] }),
713
+ /* @__PURE__ */ jsx(
714
+ FormTextarea,
715
+ {
716
+ label: "Headers (JSON)",
717
+ rows: 3,
718
+ value: jsonProp(config, "headers"),
719
+ onValueChange: (raw) => setFromJson(set, "headers", raw),
720
+ placeholder: '{ "Authorization": "Bearer {{ apiKey }}" }'
721
+ }
722
+ ),
723
+ /* @__PURE__ */ jsx(
724
+ FormTextarea,
725
+ {
726
+ label: "Body template",
727
+ rows: 3,
728
+ value: stringProp(config, "bodyTemplate"),
729
+ onValueChange: (b) => set("bodyTemplate", b),
730
+ placeholder: '{"query": "{{ search }}"}'
731
+ }
732
+ )
733
+ ] });
734
+ }
735
+ if (toolType === "function") {
736
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-xl border border-slate-200 bg-slate-50/60 p-3 dark:border-slate-700 dark:bg-slate-900/40", children: [
737
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold text-slate-700 dark:text-slate-200", children: "Function handler" }),
738
+ /* @__PURE__ */ jsx(
739
+ FormInput,
740
+ {
741
+ label: "Implementation key",
742
+ value: stringProp(config, "implementationKey"),
743
+ onValueChange: (k) => set("implementationKey", k),
744
+ placeholder: "fuel.get_station_prices",
745
+ hint: "Must match a pre-registered handler on the server side."
746
+ }
747
+ )
748
+ ] });
749
+ }
750
+ if (toolType === "database_query") {
751
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-xl border border-slate-200 bg-slate-50/60 p-3 dark:border-slate-700 dark:bg-slate-900/40", children: [
752
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold text-slate-700 dark:text-slate-200", children: "Database query handler" }),
753
+ /* @__PURE__ */ jsxs(FormGrid, { children: [
754
+ /* @__PURE__ */ jsx(
755
+ FormInput,
756
+ {
757
+ label: "Datasource ID",
758
+ value: stringProp(config, "datasourceId"),
759
+ onValueChange: (v) => set("datasourceId", v),
760
+ placeholder: "UUID from /datasources"
761
+ }
762
+ ),
763
+ /* @__PURE__ */ jsx(
764
+ FormInput,
765
+ {
766
+ label: "Max rows",
767
+ type: "number",
768
+ value: numberProp(config, "maxRows", 100),
769
+ onValueChange: (v) => set("maxRows", Number(v) || 100)
770
+ }
771
+ )
772
+ ] }),
773
+ /* @__PURE__ */ jsx(
774
+ FormTextarea,
775
+ {
776
+ label: "Query template",
777
+ rows: 4,
778
+ value: stringProp(config, "queryTemplate"),
779
+ onValueChange: (v) => set("queryTemplate", v),
780
+ placeholder: "SELECT id, current_price FROM current_prices WHERE station_id = {{ station_id }}"
781
+ }
782
+ )
783
+ ] });
784
+ }
785
+ if (toolType === "code_execution") {
786
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-xl border border-slate-200 bg-slate-50/60 p-3 dark:border-slate-700 dark:bg-slate-900/40", children: [
787
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold text-slate-700 dark:text-slate-200", children: "Code execution handler" }),
788
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-amber-600 dark:text-amber-400", children: "Experimental \u2014 sandbox is not yet enforced. Only enable for trusted tools." }),
789
+ /* @__PURE__ */ jsx(
790
+ FormSelect,
791
+ {
792
+ label: "Language",
793
+ value: stringProp(config, "language", "javascript"),
794
+ options: [
795
+ { value: "javascript", label: "JavaScript" },
796
+ { value: "python", label: "Python" }
797
+ ],
798
+ onValueChange: (v) => set("language", v)
799
+ }
800
+ ),
801
+ /* @__PURE__ */ jsx(
802
+ FormTextarea,
803
+ {
804
+ label: "Code",
805
+ rows: 6,
806
+ value: stringProp(config, "code"),
807
+ onValueChange: (v) => set("code", v),
808
+ placeholder: "// return value becomes the tool output\nreturn { price: inputs.x * 1.08 }"
809
+ }
810
+ )
811
+ ] });
812
+ }
813
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-xl border border-slate-200 bg-slate-50/60 p-3 dark:border-slate-700 dark:bg-slate-900/40", children: [
814
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold text-slate-700 dark:text-slate-200", children: "API call handler" }),
815
+ /* @__PURE__ */ jsxs(FormGrid, { children: [
816
+ /* @__PURE__ */ jsx(
817
+ FormInput,
818
+ {
819
+ label: "URL",
820
+ value: stringProp(config, "url"),
821
+ onValueChange: (v) => set("url", v)
822
+ }
823
+ ),
824
+ /* @__PURE__ */ jsx(
825
+ FormSelect,
826
+ {
827
+ label: "Auth",
828
+ value: stringProp(config, "authType", "bearer"),
829
+ options: [
830
+ { value: "none", label: "None" },
831
+ { value: "bearer", label: "Bearer token" },
832
+ { value: "api_key", label: "API key header" },
833
+ { value: "basic", label: "Basic auth" }
834
+ ],
835
+ onValueChange: (v) => set("authType", v)
836
+ }
837
+ ),
838
+ /* @__PURE__ */ jsx(
839
+ FormInput,
840
+ {
841
+ label: "Credential secret id",
842
+ value: stringProp(config, "credentialRef"),
843
+ onValueChange: (v) => set("credentialRef", v),
844
+ placeholder: "UUID from vault",
845
+ hint: "Leave blank if Auth is None."
846
+ }
847
+ )
848
+ ] })
849
+ ] });
850
+ }
851
+ function parametersToJsonSchema(params) {
852
+ const properties = {};
853
+ const required = [];
854
+ for (const param of params) {
855
+ if (!param.name.trim()) continue;
856
+ properties[param.name] = {
857
+ type: param.type,
858
+ ...param.description ? { description: param.description } : {}
859
+ };
860
+ if (param.required) required.push(param.name);
861
+ }
862
+ const schema = { type: "object", properties };
863
+ if (required.length > 0) schema.required = required;
864
+ return schema;
865
+ }
866
+ function jsonSchemaToParameters(schema) {
867
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) return [];
868
+ const root = schema;
869
+ const properties = root.properties;
870
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) return [];
871
+ const required = Array.isArray(root.required) ? root.required.filter((r) => typeof r === "string") : [];
872
+ const entries = Object.entries(properties);
873
+ return entries.map(([name, raw]) => {
874
+ const def = raw ?? {};
875
+ const rawType = def.type;
876
+ const type = isParameterType(rawType) ? rawType : "string";
877
+ return {
878
+ name,
879
+ type,
880
+ description: typeof def.description === "string" ? def.description : "",
881
+ required: required.includes(name)
882
+ };
883
+ });
884
+ }
885
+ function isParameterType(v) {
886
+ return v === "string" || v === "number" || v === "boolean" || v === "array" || v === "object";
887
+ }
888
+ function defaultForm() {
889
+ return {
890
+ name: "",
891
+ description: "",
892
+ toolType: "http",
893
+ parameters: [],
894
+ handlerConfig: { method: "GET" },
895
+ enabled: true
896
+ };
897
+ }
898
+ function toolToForm(tool) {
899
+ const raw = tool;
900
+ const implRaw = raw.implementationKey ?? raw.implementation_key;
901
+ let handlerConfig = {};
902
+ if (typeof implRaw === "string") {
903
+ try {
904
+ const parsed = JSON.parse(implRaw);
905
+ if (parsed && typeof parsed === "object") {
906
+ const inner = parsed.handlerConfig ?? parsed.handler_config;
907
+ if (inner && typeof inner === "object" && !Array.isArray(inner)) {
908
+ handlerConfig = inner;
909
+ }
910
+ }
911
+ } catch {
912
+ handlerConfig = { implementationKey: implRaw };
913
+ }
914
+ }
915
+ const toolTypeRaw = raw.toolType ?? raw.tool_type ?? raw.category;
916
+ const toolType = TOOL_TYPES.includes(String(toolTypeRaw)) ? toolTypeRaw : "function";
917
+ const parameters = jsonSchemaToParameters(raw.parameters ?? raw.inputSchema ?? raw.input_schema);
918
+ return {
919
+ agentToolId: tool.agentToolId,
920
+ name: tool.name,
921
+ description: tool.description,
922
+ toolType,
923
+ parameters,
924
+ handlerConfig,
925
+ enabled: tool.enabled,
926
+ icon: tool.icon
927
+ };
928
+ }
929
+ function toolTypeLabel(tool) {
930
+ const raw = tool;
931
+ const t = raw.toolType ?? raw.tool_type ?? tool.category;
932
+ const entry = TOOL_TYPE_OPTIONS.find((o) => o.value === t);
933
+ return entry?.label ?? (typeof t === "string" ? t : "tool");
934
+ }
935
+ function stringProp(obj, key, fallback = "") {
936
+ const value = obj[key];
937
+ return typeof value === "string" ? value : fallback;
938
+ }
939
+ function numberProp(obj, key, fallback) {
940
+ const value = obj[key];
941
+ return typeof value === "number" && Number.isFinite(value) ? String(value) : String(fallback);
942
+ }
943
+ function jsonProp(obj, key) {
944
+ const value = obj[key];
945
+ if (!value) return "";
946
+ if (typeof value === "string") return value;
947
+ try {
948
+ return JSON.stringify(value, null, 2);
949
+ } catch {
950
+ return "";
951
+ }
952
+ }
953
+ function setFromJson(set, key, raw) {
954
+ if (!raw.trim()) {
955
+ set(key, void 0);
956
+ return;
957
+ }
958
+ try {
959
+ set(key, JSON.parse(raw));
960
+ } catch {
961
+ set(key, raw);
962
+ }
963
+ }
964
+ function RulesPageView({ labels, rules, loading, onCreate, onUpdate, onDelete }) {
965
+ const [createOpen, setCreateOpen] = useState(false);
966
+ const [editing, setEditing] = useState(null);
967
+ const hero = /* @__PURE__ */ jsx(
968
+ HeroSection,
969
+ {
970
+ icon: /* @__PURE__ */ jsx(AdjustmentsHorizontalIcon, { className: "h-5 w-5" }),
971
+ label: labels.title,
972
+ title: labels.title,
973
+ subtitle: labels.subtitle,
974
+ gradient: "from-fuchsia-500 to-purple-700",
975
+ toolbar: /* @__PURE__ */ jsx(
976
+ CreateActionButton,
977
+ {
978
+ mode: "desktop",
979
+ label: labels.addRule,
980
+ onClick: () => setCreateOpen(true),
981
+ accent: "fuchsia"
982
+ }
983
+ )
984
+ }
985
+ );
986
+ const mobileAction = /* @__PURE__ */ jsx(
987
+ CreateActionButton,
988
+ {
989
+ mode: "mobile",
990
+ label: labels.addRule,
991
+ onClick: () => setCreateOpen(true),
992
+ accent: "fuchsia"
993
+ }
994
+ );
995
+ const content = loading ? /* @__PURE__ */ jsx(PageLoadingState, {}) : rules.length === 0 ? /* @__PURE__ */ jsx(PageEmptyState, { title: labels.empty, message: labels.subtitle, iconName: "folder-open" }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: rules.map((rule) => /* @__PURE__ */ jsx(
996
+ EntityCard,
997
+ {
998
+ accentGradient: "from-fuchsia-500 to-purple-700",
999
+ icon: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg bg-fuchsia-500/10 text-fuchsia-600 dark:bg-fuchsia-500/20 dark:text-fuchsia-400", children: /* @__PURE__ */ jsx(AdjustmentsHorizontalIcon, { className: "h-6 w-6" }) }),
1000
+ title: rule.name,
1001
+ subtitle: `${labels.order}: ${rule.order ?? 0}`,
1002
+ status: /* @__PURE__ */ jsx(Badge, { color: rule.enabled ? "emerald" : "zinc", children: rule.enabled ? labels.enabled : labels.disabled }),
1003
+ footer: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1004
+ /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", outline: true, onClick: () => setEditing(rule), children: labels.edit }),
1005
+ /* @__PURE__ */ jsx(
1006
+ Button,
1007
+ {
1008
+ type: "button",
1009
+ size: "sm",
1010
+ color: "rose",
1011
+ onClick: () => {
1012
+ if (window.confirm(labels.deleteConfirm)) onDelete(rule);
1013
+ },
1014
+ children: labels.delete
1015
+ }
1016
+ )
1017
+ ] }),
1018
+ children: rule.description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: rule.description })
1019
+ },
1020
+ rule.ruleId
1021
+ )) });
1022
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1023
+ /* @__PURE__ */ jsx(ManagementPageLayout, { hero, content, mobileAction }),
1024
+ createOpen && /* @__PURE__ */ jsx(
1025
+ RuleEditor,
1026
+ {
1027
+ title: labels.createTitle,
1028
+ saveLabel: labels.save,
1029
+ initial: defaultRuleForm(),
1030
+ onClose: () => setCreateOpen(false),
1031
+ onSubmit: (value) => {
1032
+ onCreate(value);
1033
+ setCreateOpen(false);
1034
+ }
1035
+ }
1036
+ ),
1037
+ editing && /* @__PURE__ */ jsx(
1038
+ RuleEditor,
1039
+ {
1040
+ title: labels.editTitle,
1041
+ saveLabel: labels.save,
1042
+ initial: ruleToFormValue(editing),
1043
+ onClose: () => setEditing(null),
1044
+ onSubmit: (value) => {
1045
+ onUpdate(editing.ruleId, value);
1046
+ setEditing(null);
1047
+ }
1048
+ }
1049
+ )
1050
+ ] });
1051
+ }
1052
+ function RuleEditor({
1053
+ title,
1054
+ saveLabel,
1055
+ initial,
1056
+ onSubmit,
1057
+ onClose
1058
+ }) {
1059
+ const [value, setValue] = useState(initial);
1060
+ return /* @__PURE__ */ jsx(
1061
+ GlassModal,
1062
+ {
1063
+ open: true,
1064
+ onClose,
1065
+ title,
1066
+ maxWidth: "3xl",
1067
+ showFormFooter: true,
1068
+ submitLabel: saveLabel,
1069
+ onSubmit: (event) => {
1070
+ event.preventDefault();
1071
+ onSubmit(value);
1072
+ },
1073
+ children: /* @__PURE__ */ jsx(RuleForm, { value, onChange: setValue })
1074
+ }
1075
+ );
1076
+ }
1077
+ function ruleToFormValue(rule) {
1078
+ const base = defaultRuleForm();
1079
+ const rawCondition = rule.condition ?? rule.conditions;
1080
+ const rawAction = pickAction(rule);
1081
+ return {
1082
+ ...base,
1083
+ ruleId: rule.ruleId,
1084
+ name: rule.name ?? "",
1085
+ description: rule.description ?? "",
1086
+ enabled: rule.enabled,
1087
+ priority: typeof rule.order === "number" ? rule.order : typeof rule.priority === "number" ? rule.priority : 0,
1088
+ condition: rawCondition && typeof rawCondition === "object" ? rawCondition : base.condition,
1089
+ action: rawAction ?? base.action,
1090
+ status: typeof rule.status === "string" ? rule.status : base.status,
1091
+ validFrom: typeof rule.validFrom === "string" ? rule.validFrom : base.validFrom,
1092
+ validUntil: typeof rule.validUntil === "string" ? rule.validUntil : base.validUntil,
1093
+ tags: Array.isArray(rule.tags) ? rule.tags.filter((tag) => typeof tag === "string") : base.tags
1094
+ };
1095
+ }
1096
+ function pickAction(rule) {
1097
+ const singular = rule.action;
1098
+ if (singular && typeof singular === "object" && "type" in singular) {
1099
+ return singular;
1100
+ }
1101
+ if (Array.isArray(rule.actions) && rule.actions.length > 0) {
1102
+ const first = rule.actions[0];
1103
+ if (first && typeof first === "object" && "type" in first) {
1104
+ return first;
1105
+ }
1106
+ }
1107
+ return void 0;
1108
+ }
1109
+ var DIALECT_CATEGORIES = [
1110
+ {
1111
+ id: "relational",
1112
+ labelKey: "categoryRelational",
1113
+ icon: CircleStackIcon,
1114
+ gradient: "from-blue-500 to-indigo-600",
1115
+ dialects: [
1116
+ { value: "postgres", label: "PostgreSQL", defaultPort: 5432, formType: "standard" },
1117
+ { value: "mysql", label: "MySQL", defaultPort: 3306, formType: "standard" },
1118
+ { value: "mariadb", label: "MariaDB", defaultPort: 3306, formType: "standard" },
1119
+ { value: "mssql", label: "SQL Server", defaultPort: 1433, formType: "standard" },
1120
+ { value: "oracle", label: "Oracle", defaultPort: 1521, formType: "standard" },
1121
+ { value: "db2", label: "IBM Db2", defaultPort: 5e4, formType: "standard" },
1122
+ { value: "cockroachdb", label: "CockroachDB", defaultPort: 26257, formType: "standard" },
1123
+ { value: "timescaledb", label: "TimescaleDB", defaultPort: 5432, formType: "standard" },
1124
+ { value: "sqlite", label: "SQLite", formType: "connection-string" },
1125
+ { value: "duckdb", label: "DuckDB", formType: "connection-string" }
1126
+ ]
1127
+ },
1128
+ {
1129
+ id: "nosql",
1130
+ labelKey: "categoryNoSql",
1131
+ icon: ServerStackIcon,
1132
+ gradient: "from-emerald-500 to-teal-600",
1133
+ dialects: [
1134
+ { value: "mongodb", label: "MongoDB", defaultPort: 27017, formType: "connection-string" },
1135
+ { value: "cassandra", label: "Cassandra", defaultPort: 9042, formType: "standard" },
1136
+ { value: "scylladb", label: "ScyllaDB", defaultPort: 9042, formType: "standard" },
1137
+ { value: "dynamodb", label: "DynamoDB", formType: "cloud-key" },
1138
+ { value: "cosmosdb", label: "CosmosDB", formType: "connection-string" },
1139
+ { value: "arangodb", label: "ArangoDB", defaultPort: 8529, formType: "standard" }
1140
+ ]
1141
+ },
1142
+ {
1143
+ id: "warehouse",
1144
+ labelKey: "categoryWarehouse",
1145
+ icon: CloudIcon,
1146
+ gradient: "from-purple-500 to-violet-600",
1147
+ dialects: [
1148
+ { value: "bigquery", label: "BigQuery", formType: "cloud-bigquery" },
1149
+ { value: "snowflake", label: "Snowflake", formType: "cloud-snowflake" },
1150
+ { value: "clickhouse", label: "ClickHouse", defaultPort: 8123, formType: "standard" }
1151
+ ]
1152
+ },
1153
+ {
1154
+ id: "timeseries",
1155
+ labelKey: "categoryTimeSeries",
1156
+ icon: ClockIcon,
1157
+ gradient: "from-sky-500 to-cyan-600",
1158
+ dialects: [
1159
+ { value: "influxdb", label: "InfluxDB", formType: "cloud-key" },
1160
+ { value: "timestream", label: "Timestream", formType: "cloud-key" }
1161
+ ]
1162
+ },
1163
+ {
1164
+ id: "graph",
1165
+ labelKey: "categoryGraph",
1166
+ icon: ShareIcon,
1167
+ gradient: "from-pink-500 to-rose-600",
1168
+ dialects: [
1169
+ { value: "neo4j", label: "Neo4j", defaultPort: 7687, formType: "standard" },
1170
+ { value: "neptune", label: "Neptune", formType: "connection-string" }
1171
+ ]
1172
+ },
1173
+ {
1174
+ id: "keyvalue",
1175
+ labelKey: "categoryKeyValue",
1176
+ icon: KeyIcon,
1177
+ gradient: "from-red-500 to-orange-600",
1178
+ dialects: [
1179
+ { value: "redis", label: "Redis", defaultPort: 6379, formType: "standard" }
1180
+ ]
1181
+ },
1182
+ {
1183
+ id: "search",
1184
+ labelKey: "categorySearch",
1185
+ icon: MagnifyingGlassIcon,
1186
+ gradient: "from-amber-500 to-yellow-600",
1187
+ dialects: [
1188
+ { value: "elasticsearch", label: "Elasticsearch", defaultPort: 9200, formType: "standard" },
1189
+ { value: "opensearch", label: "OpenSearch", defaultPort: 9200, formType: "standard" },
1190
+ { value: "pinecone", label: "Pinecone", formType: "vector-key" },
1191
+ { value: "qdrant", label: "Qdrant", defaultPort: 6333, formType: "standard" },
1192
+ { value: "weaviate", label: "Weaviate", defaultPort: 8080, formType: "standard" },
1193
+ { value: "milvus", label: "Milvus", defaultPort: 19530, formType: "standard" },
1194
+ { value: "chromadb", label: "ChromaDB", defaultPort: 8e3, formType: "standard" }
1195
+ ]
1196
+ }
1197
+ ];
1198
+ function findDialect(value) {
1199
+ for (const category of DIALECT_CATEGORIES) {
1200
+ const found = category.dialects.find((d) => d.value === value);
1201
+ if (found) return found;
1202
+ }
1203
+ return void 0;
1204
+ }
1205
+ function findCategory(dialectValue) {
1206
+ return DIALECT_CATEGORIES.find((c) => c.dialects.some((d) => d.value === dialectValue));
1207
+ }
1208
+ function DialectPicker({
1209
+ labels,
1210
+ onSelect
1211
+ }) {
1212
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
1213
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: labels.stepSelectType }),
1214
+ DIALECT_CATEGORIES.map((category) => /* @__PURE__ */ jsxs("div", { children: [
1215
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
1216
+ /* @__PURE__ */ jsx("div", { className: `flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br ${category.gradient}`, children: /* @__PURE__ */ jsx(category.icon, { className: "h-4 w-4 text-white" }) }),
1217
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-700 dark:text-gray-200", children: labels[category.labelKey] ?? category.id })
1218
+ ] }),
1219
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 sm:grid-cols-3", children: category.dialects.map((dialect) => /* @__PURE__ */ jsxs(
1220
+ "button",
1221
+ {
1222
+ type: "button",
1223
+ onClick: () => onSelect(dialect.value),
1224
+ className: "group flex items-center gap-2 rounded-xl border border-gray-200/60 bg-white/60 px-3 py-2.5 text-left text-sm font-medium text-gray-700 transition-all hover:border-amber-400/60 hover:bg-amber-50/50 hover:text-amber-700 active:scale-[0.97] dark:border-white/10 dark:bg-white/5 dark:text-gray-300 dark:hover:border-amber-400/40 dark:hover:bg-amber-500/10 dark:hover:text-amber-300",
1225
+ children: [
1226
+ /* @__PURE__ */ jsx(CircleStackIcon, { className: "h-4 w-4 shrink-0 text-gray-400 transition-colors group-hover:text-amber-500 dark:text-gray-500" }),
1227
+ dialect.label
1228
+ ]
1229
+ },
1230
+ dialect.value
1231
+ )) })
1232
+ ] }, category.id))
1233
+ ] });
1234
+ }
1235
+ function ConnectionForm({
1236
+ dialect,
1237
+ labels,
1238
+ onBack,
1239
+ onSubmit
1240
+ }) {
1241
+ const [testStatus, setTestStatus] = useState("idle");
1242
+ const category = findCategory(dialect.value);
1243
+ function handleSubmit(event) {
1244
+ event.preventDefault();
1245
+ const formData = new FormData(event.currentTarget);
1246
+ const data = {
1247
+ name: String(formData.get("name") ?? "").trim(),
1248
+ dialect: dialect.value
1249
+ };
1250
+ for (const key of ["host", "database", "username", "password", "schema", "connectionString", "projectId", "dataset", "keyFile", "account", "warehouse", "region", "bucket", "token", "apiKey", "environment", "index", "url"]) {
1251
+ const val = String(formData.get(key) ?? "").trim();
1252
+ if (val) data[key] = val;
1253
+ }
1254
+ const port = String(formData.get("port") ?? "").trim();
1255
+ if (port) data.port = Number(port);
1256
+ data.ssl = formData.get("ssl") === "on";
1257
+ data.readOnly = formData.get("readOnly") === "on";
1258
+ const maxPoolSize = String(formData.get("maxPoolSize") ?? "").trim();
1259
+ if (maxPoolSize) {
1260
+ const parsed = Number(maxPoolSize);
1261
+ if (Number.isFinite(parsed) && parsed > 0) data.maxPoolSize = parsed;
1262
+ }
1263
+ const timeoutMs = String(formData.get("timeoutMs") ?? "").trim();
1264
+ if (timeoutMs) {
1265
+ const parsed = Number(timeoutMs);
1266
+ if (Number.isFinite(parsed) && parsed > 0) data.timeoutMs = parsed;
1267
+ }
1268
+ const allowedTables = splitList(String(formData.get("allowedTables") ?? ""));
1269
+ if (allowedTables.length > 0) data.allowedTables = allowedTables;
1270
+ const blockedColumns = splitList(String(formData.get("blockedColumns") ?? ""));
1271
+ if (blockedColumns.length > 0) data.blockedColumns = blockedColumns;
1272
+ onSubmit(data);
1273
+ }
1274
+ function handleTestConnection() {
1275
+ setTestStatus("testing");
1276
+ setTimeout(() => {
1277
+ setTestStatus("success");
1278
+ setTimeout(() => setTestStatus("idle"), 3e3);
1279
+ }, 1500);
1280
+ }
1281
+ function renderFields() {
1282
+ switch (dialect.formType) {
1283
+ case "standard":
1284
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1285
+ /* @__PURE__ */ jsx(FormInput, { name: "host", label: labels.fieldHost, placeholder: labels.fieldHostPlaceholder, required: true }),
1286
+ /* @__PURE__ */ jsx(FormInput, { name: "port", label: labels.fieldPort, type: "number", defaultValue: dialect.defaultPort }),
1287
+ /* @__PURE__ */ jsx(FormInput, { name: "database", label: labels.fieldDatabase, placeholder: labels.fieldDatabasePlaceholder, required: true }),
1288
+ /* @__PURE__ */ jsx(FormInput, { name: "username", label: labels.fieldUsername, placeholder: labels.fieldUsernamePlaceholder }),
1289
+ /* @__PURE__ */ jsx(FormInput, { name: "password", label: labels.fieldPassword, type: "password", placeholder: labels.fieldPasswordPlaceholder }),
1290
+ /* @__PURE__ */ jsx(FormInput, { name: "schema", label: labels.fieldSchema, placeholder: labels.fieldSchemaPlaceholder })
1291
+ ] });
1292
+ case "connection-string":
1293
+ return /* @__PURE__ */ jsx("div", { className: "col-span-full", children: /* @__PURE__ */ jsx(FormInput, { name: "connectionString", label: labels.fieldConnectionString, placeholder: labels.fieldConnectionStringPlaceholder, required: true }) });
1294
+ case "cloud-bigquery":
1295
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1296
+ /* @__PURE__ */ jsx(FormInput, { name: "projectId", label: labels.fieldProjectId, placeholder: labels.fieldProjectIdPlaceholder, required: true }),
1297
+ /* @__PURE__ */ jsx(FormInput, { name: "dataset", label: labels.fieldDataset, placeholder: labels.fieldDatasetPlaceholder, required: true }),
1298
+ /* @__PURE__ */ jsx("div", { className: "col-span-full", children: /* @__PURE__ */ jsx(FormInput, { name: "keyFile", label: labels.fieldKeyFile, placeholder: labels.fieldKeyFilePlaceholder }) })
1299
+ ] });
1300
+ case "cloud-snowflake":
1301
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1302
+ /* @__PURE__ */ jsx(FormInput, { name: "account", label: labels.fieldAccount, placeholder: labels.fieldAccountPlaceholder, required: true }),
1303
+ /* @__PURE__ */ jsx(FormInput, { name: "warehouse", label: labels.fieldWarehouse, placeholder: labels.fieldWarehousePlaceholder, required: true }),
1304
+ /* @__PURE__ */ jsx(FormInput, { name: "database", label: labels.fieldDatabase, placeholder: labels.fieldDatabasePlaceholder, required: true }),
1305
+ /* @__PURE__ */ jsx(FormInput, { name: "username", label: labels.fieldUsername, placeholder: labels.fieldUsernamePlaceholder, required: true }),
1306
+ /* @__PURE__ */ jsx(FormInput, { name: "password", label: labels.fieldPassword, type: "password", placeholder: labels.fieldPasswordPlaceholder }),
1307
+ /* @__PURE__ */ jsx(FormInput, { name: "schema", label: labels.fieldSchema, placeholder: labels.fieldSchemaPlaceholder })
1308
+ ] });
1309
+ case "cloud-key":
1310
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1311
+ /* @__PURE__ */ jsx(FormInput, { name: "region", label: labels.fieldRegion, placeholder: labels.fieldRegionPlaceholder, required: true }),
1312
+ /* @__PURE__ */ jsx(FormInput, { name: "token", label: labels.fieldToken, type: "password", placeholder: labels.fieldTokenPlaceholder, required: true }),
1313
+ /* @__PURE__ */ jsx(FormInput, { name: "bucket", label: labels.fieldBucket, placeholder: labels.fieldBucketPlaceholder })
1314
+ ] });
1315
+ case "vector-key":
1316
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1317
+ /* @__PURE__ */ jsx(FormInput, { name: "apiKey", label: labels.fieldApiKey, type: "password", placeholder: labels.fieldApiKeyPlaceholder, required: true }),
1318
+ /* @__PURE__ */ jsx(FormInput, { name: "environment", label: labels.fieldEnvironment, placeholder: labels.fieldEnvironmentPlaceholder, required: true }),
1319
+ /* @__PURE__ */ jsx(FormInput, { name: "index", label: labels.fieldIndex, placeholder: labels.fieldIndexPlaceholder })
1320
+ ] });
1321
+ }
1322
+ }
1323
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [
1324
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1325
+ /* @__PURE__ */ jsx(
1326
+ "button",
1327
+ {
1328
+ type: "button",
1329
+ onClick: onBack,
1330
+ className: "flex h-8 w-8 items-center justify-center rounded-lg text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 dark:hover:bg-white/10 dark:hover:text-gray-300",
1331
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, { className: "h-4 w-4" })
1332
+ }
1333
+ ),
1334
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1335
+ /* @__PURE__ */ jsx("div", { className: `flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br ${category?.gradient ?? "from-gray-400 to-gray-500"}`, children: category ? /* @__PURE__ */ jsx(category.icon, { className: "h-4 w-4 text-white" }) : /* @__PURE__ */ jsx(CircleStackIcon, { className: "h-4 w-4 text-white" }) }),
1336
+ /* @__PURE__ */ jsxs("div", { children: [
1337
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-gray-900 dark:text-white", children: dialect.label }),
1338
+ /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-gray-400", children: labels[category?.labelKey ?? ""] ?? "" })
1339
+ ] })
1340
+ ] })
1341
+ ] }),
1342
+ /* @__PURE__ */ jsx(FormInput, { name: "name", label: labels.fieldName, placeholder: labels.fieldNamePlaceholder, required: true }),
1343
+ /* @__PURE__ */ jsx(FormGrid, { children: renderFields() }),
1344
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-6 pt-2", children: [
1345
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300", children: [
1346
+ /* @__PURE__ */ jsx(
1347
+ "input",
1348
+ {
1349
+ type: "checkbox",
1350
+ name: "ssl",
1351
+ defaultChecked: true,
1352
+ className: "h-4 w-4 rounded border-gray-300 text-amber-600 focus:ring-amber-500 dark:border-gray-600 dark:bg-gray-800"
1353
+ }
1354
+ ),
1355
+ labels.fieldSsl
1356
+ ] }),
1357
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300", children: [
1358
+ /* @__PURE__ */ jsx(
1359
+ "input",
1360
+ {
1361
+ type: "checkbox",
1362
+ name: "readOnly",
1363
+ defaultChecked: true,
1364
+ className: "h-4 w-4 rounded border-gray-300 text-amber-600 focus:ring-amber-500 dark:border-gray-600 dark:bg-gray-800"
1365
+ }
1366
+ ),
1367
+ labels.fieldReadOnly
1368
+ ] })
1369
+ ] }),
1370
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500", children: labels.fieldReadOnlyHelp }),
1371
+ /* @__PURE__ */ jsxs("details", { className: "rounded-xl border border-gray-200/60 bg-white/40 p-3 dark:border-white/10 dark:bg-white/5", children: [
1372
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-gray-700 dark:text-gray-300", children: labels.advancedToggle ?? "Governance & performance" }),
1373
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-3", children: [
1374
+ /* @__PURE__ */ jsxs(FormGrid, { children: [
1375
+ /* @__PURE__ */ jsx(
1376
+ FormInput,
1377
+ {
1378
+ name: "maxPoolSize",
1379
+ label: labels.fieldMaxPoolSize ?? "Max pool size",
1380
+ type: "number",
1381
+ min: 1,
1382
+ max: 100,
1383
+ placeholder: "5"
1384
+ }
1385
+ ),
1386
+ /* @__PURE__ */ jsx(
1387
+ FormInput,
1388
+ {
1389
+ name: "timeoutMs",
1390
+ label: labels.fieldTimeoutMs ?? "Timeout (ms)",
1391
+ type: "number",
1392
+ min: 100,
1393
+ placeholder: "5000"
1394
+ }
1395
+ )
1396
+ ] }),
1397
+ /* @__PURE__ */ jsx(
1398
+ FormInput,
1399
+ {
1400
+ name: "allowedTables",
1401
+ label: labels.fieldAllowedTables ?? "Allowed tables (comma-separated)",
1402
+ placeholder: "stations, current_prices, competitor_prices"
1403
+ }
1404
+ ),
1405
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500", children: labels.fieldAllowedTablesHelp ?? "Leave blank to allow every table the credential can see. Otherwise only the listed tables are queryable from workflows." }),
1406
+ /* @__PURE__ */ jsx(
1407
+ FormInput,
1408
+ {
1409
+ name: "blockedColumns",
1410
+ label: labels.fieldBlockedColumns ?? "Blocked columns (comma-separated)",
1411
+ placeholder: "customers.ssn, employees.salary"
1412
+ }
1413
+ ),
1414
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500", children: labels.fieldBlockedColumnsHelp ?? "Columns the driver must never surface, even if referenced by a workflow. Use table.column notation for specificity." })
1415
+ ] })
1416
+ ] }),
1417
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 border-t border-gray-200/60 pt-5 dark:border-white/10", children: [
1418
+ /* @__PURE__ */ jsx(
1419
+ Button,
1420
+ {
1421
+ type: "button",
1422
+ size: "sm",
1423
+ color: "zinc",
1424
+ onClick: handleTestConnection,
1425
+ disabled: testStatus === "testing",
1426
+ children: testStatus === "testing" ? labels.testing : labels.testConnection
1427
+ }
1428
+ ),
1429
+ testStatus === "success" && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs font-medium text-emerald-600 dark:text-emerald-400", children: [
1430
+ /* @__PURE__ */ jsx(CheckCircleIcon, { className: "h-4 w-4" }),
1431
+ labels.connectionSuccess
1432
+ ] }),
1433
+ testStatus === "failed" && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs font-medium text-red-600 dark:text-red-400", children: [
1434
+ /* @__PURE__ */ jsx(XCircleIcon, { className: "h-4 w-4" }),
1435
+ labels.connectionFailed
1436
+ ] }),
1437
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
1438
+ /* @__PURE__ */ jsx(Button, { type: "submit", size: "sm", color: "amber", children: labels.save })
1439
+ ] })
1440
+ ] });
1441
+ }
1442
+ function DatasourceFormModal({ open, onClose, labels, onSave }) {
1443
+ const [selectedDialect, setSelectedDialect] = useState(null);
1444
+ const dialect = selectedDialect ? findDialect(selectedDialect) : null;
1445
+ function handleClose() {
1446
+ setSelectedDialect(null);
1447
+ onClose();
1448
+ }
1449
+ function handleSave(data) {
1450
+ onSave(data);
1451
+ handleClose();
1452
+ }
1453
+ return /* @__PURE__ */ jsx(
1454
+ GlassModal,
1455
+ {
1456
+ open,
1457
+ onClose: handleClose,
1458
+ title: labels.createTitle,
1459
+ subtitle: dialect ? labels.stepConfigure : labels.stepSelectType,
1460
+ icon: /* @__PURE__ */ jsx(CircleStackIcon, { className: "h-5 w-5" }),
1461
+ gradient: "from-amber-500 to-orange-600",
1462
+ maxWidth: "3xl",
1463
+ children: dialect ? /* @__PURE__ */ jsx(
1464
+ ConnectionForm,
1465
+ {
1466
+ dialect,
1467
+ labels,
1468
+ onBack: () => setSelectedDialect(null),
1469
+ onSubmit: handleSave
1470
+ }
1471
+ ) : /* @__PURE__ */ jsx(DialectPicker, { labels, onSelect: setSelectedDialect })
1472
+ }
1473
+ );
1474
+ }
1475
+ function DatasourceModal({ open, onClose, labels, onSave }) {
1476
+ const [selectedDialect, setSelectedDialect] = useState(null);
1477
+ const dialect = selectedDialect ? findDialect(selectedDialect) : null;
1478
+ function handleClose() {
1479
+ setSelectedDialect(null);
1480
+ onClose();
1481
+ }
1482
+ function handleSave(data) {
1483
+ onSave(data);
1484
+ handleClose();
1485
+ }
1486
+ return /* @__PURE__ */ jsx(
1487
+ GlassModal,
1488
+ {
1489
+ open,
1490
+ onClose: handleClose,
1491
+ title: labels.createTitle,
1492
+ subtitle: dialect ? labels.stepConfigure : labels.stepSelectType,
1493
+ icon: /* @__PURE__ */ jsx(CircleStackIcon, { className: "h-5 w-5" }),
1494
+ gradient: "from-amber-500 to-orange-600",
1495
+ maxWidth: "3xl",
1496
+ children: dialect ? /* @__PURE__ */ jsx(
1497
+ ConnectionForm,
1498
+ {
1499
+ dialect,
1500
+ labels,
1501
+ onBack: () => setSelectedDialect(null),
1502
+ onSubmit: handleSave
1503
+ }
1504
+ ) : /* @__PURE__ */ jsx(DialectPicker, { labels, onSelect: setSelectedDialect })
1505
+ }
1506
+ );
1507
+ }
1508
+ function splitList(raw) {
1509
+ return raw.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
1510
+ }
1511
+ var SAMPLE_DATASOURCES = [
1512
+ {
1513
+ id: "ds_bigquery_analytics",
1514
+ organizationId: "org_demo",
1515
+ name: "BigQuery Analytics",
1516
+ dialect: "bigquery",
1517
+ credentials: null,
1518
+ readOnly: true,
1519
+ maxPoolSize: null,
1520
+ timeoutMs: 3e4,
1521
+ allowedTables: null,
1522
+ blockedColumns: null,
1523
+ enabled: true,
1524
+ createdAt: "2026-03-20T10:00:00Z",
1525
+ updatedAt: "2026-03-20T10:00:00Z",
1526
+ slug: "bigquery-analytics"
1527
+ },
1528
+ {
1529
+ id: "ds_postgres_prod",
1530
+ organizationId: "org_demo",
1531
+ name: "Production PostgreSQL",
1532
+ dialect: "postgres",
1533
+ credentials: null,
1534
+ readOnly: true,
1535
+ maxPoolSize: 10,
1536
+ timeoutMs: 15e3,
1537
+ allowedTables: null,
1538
+ blockedColumns: null,
1539
+ enabled: true,
1540
+ createdAt: "2026-03-18T08:30:00Z",
1541
+ updatedAt: "2026-03-22T14:00:00Z",
1542
+ slug: "production-postgresql"
1543
+ },
1544
+ {
1545
+ id: "ds_snowflake_dw",
1546
+ organizationId: "org_demo",
1547
+ name: "Snowflake Data Warehouse",
1548
+ dialect: "snowflake",
1549
+ credentials: null,
1550
+ readOnly: true,
1551
+ maxPoolSize: null,
1552
+ timeoutMs: 3e4,
1553
+ allowedTables: null,
1554
+ blockedColumns: null,
1555
+ enabled: true,
1556
+ createdAt: "2026-03-15T09:00:00Z",
1557
+ updatedAt: "2026-03-21T11:00:00Z",
1558
+ slug: "snowflake-data-warehouse"
1559
+ },
1560
+ {
1561
+ id: "ds_mongodb_events",
1562
+ organizationId: "org_demo",
1563
+ name: "Event Store (MongoDB)",
1564
+ dialect: "mongodb",
1565
+ credentials: null,
1566
+ readOnly: true,
1567
+ maxPoolSize: 5,
1568
+ timeoutMs: 1e4,
1569
+ allowedTables: null,
1570
+ blockedColumns: null,
1571
+ enabled: false,
1572
+ createdAt: "2026-03-10T12:00:00Z",
1573
+ updatedAt: "2026-03-19T16:00:00Z",
1574
+ slug: "event-store-mongodb"
1575
+ },
1576
+ {
1577
+ id: "ds_redis_cache",
1578
+ organizationId: "org_demo",
1579
+ name: "Redis Cache Layer",
1580
+ dialect: "redis",
1581
+ credentials: null,
1582
+ readOnly: false,
1583
+ maxPoolSize: 20,
1584
+ timeoutMs: 5e3,
1585
+ allowedTables: null,
1586
+ blockedColumns: null,
1587
+ enabled: true,
1588
+ createdAt: "2026-03-12T07:00:00Z",
1589
+ updatedAt: "2026-03-23T09:00:00Z",
1590
+ slug: "redis-cache-layer"
1591
+ },
1592
+ {
1593
+ id: "ds_pinecone_vectors",
1594
+ organizationId: "org_demo",
1595
+ name: "Pinecone Embeddings",
1596
+ dialect: "pinecone",
1597
+ credentials: null,
1598
+ readOnly: true,
1599
+ maxPoolSize: null,
1600
+ timeoutMs: 2e4,
1601
+ allowedTables: null,
1602
+ blockedColumns: null,
1603
+ enabled: true,
1604
+ createdAt: "2026-03-22T15:00:00Z",
1605
+ updatedAt: "2026-03-25T10:00:00Z",
1606
+ slug: "pinecone-embeddings"
1607
+ }
1608
+ ];
1609
+ function getDialectLabel(dialect) {
1610
+ if (!dialect) return "Unknown";
1611
+ for (const category of DIALECT_CATEGORIES) {
1612
+ const found = category.dialects.find((d) => d.value === dialect);
1613
+ if (found) return found.label;
1614
+ }
1615
+ return dialect;
1616
+ }
1617
+ function getDialectGradient(dialect) {
1618
+ if (!dialect) return "from-gray-400 to-gray-500";
1619
+ const category = findCategory(dialect);
1620
+ return category?.gradient ?? "from-gray-400 to-gray-500";
1621
+ }
1622
+ function getDialectIcon(dialect) {
1623
+ if (!dialect) return CircleStackIcon;
1624
+ const category = findCategory(dialect);
1625
+ return category?.icon ?? CircleStackIcon;
1626
+ }
1627
+ var DIALECT_LOGO = {
1628
+ bigquery: "/logos/datasources/bigquery.svg",
1629
+ postgres: "/logos/datasources/postgres.svg",
1630
+ postgresql: "/logos/datasources/postgres.svg",
1631
+ mysql: "/logos/datasources/mysql.svg",
1632
+ mariadb: "/logos/datasources/mariadb.svg",
1633
+ snowflake: "/logos/datasources/snowflake.svg",
1634
+ mongodb: "/logos/datasources/mongodb.svg",
1635
+ redis: "/logos/datasources/redis.svg",
1636
+ clickhouse: "/logos/datasources/clickhouse.svg",
1637
+ elasticsearch: "/logos/datasources/elasticsearch.svg",
1638
+ duckdb: "/logos/datasources/duckdb.svg",
1639
+ sqlite: "/logos/datasources/sqlite.svg",
1640
+ oracle: "/logos/datasources/oracle.svg",
1641
+ mssql: "/logos/datasources/mssql.svg",
1642
+ sqlserver: "/logos/datasources/mssql.svg",
1643
+ cassandra: "/logos/datasources/cassandra.svg",
1644
+ dynamodb: "/logos/datasources/dynamodb.svg",
1645
+ cockroach: "/logos/datasources/cockroachdb.svg",
1646
+ cockroachdb: "/logos/datasources/cockroachdb.svg",
1647
+ supabase: "/logos/datasources/supabase.svg",
1648
+ firebase: "/logos/datasources/firebase.svg",
1649
+ neo4j: "/logos/datasources/neo4j.svg"
1650
+ };
1651
+ function getDialectLogoSrc(dialect) {
1652
+ if (!dialect) return null;
1653
+ return DIALECT_LOGO[dialect.toLowerCase()] ?? null;
1654
+ }
1655
+ function DatasourcesPageView({
1656
+ labels,
1657
+ datasources: externalDatasources,
1658
+ useSampleData = false,
1659
+ onCreate
1660
+ }) {
1661
+ const [modalOpen, setModalOpen] = useState(false);
1662
+ const [localDatasources, setLocalDatasources] = useState(
1663
+ useSampleData ? SAMPLE_DATASOURCES : []
1664
+ );
1665
+ const datasources = externalDatasources ?? localDatasources;
1666
+ const isEmpty = datasources.length === 0;
1667
+ function handleCreate(data) {
1668
+ if (onCreate) {
1669
+ onCreate(data);
1670
+ return;
1671
+ }
1672
+ const newDs = {
1673
+ id: `ds_${Date.now()}`,
1674
+ organizationId: "org_demo",
1675
+ name: data.name,
1676
+ dialect: data.dialect,
1677
+ credentials: null,
1678
+ readOnly: data.readOnly ?? true,
1679
+ maxPoolSize: null,
1680
+ timeoutMs: 3e4,
1681
+ allowedTables: null,
1682
+ blockedColumns: null,
1683
+ enabled: true,
1684
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1685
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1686
+ slug: data.name.toLowerCase().replace(/\s+/g, "-")
1687
+ };
1688
+ setLocalDatasources((previous) => [...previous, newDs]);
1689
+ }
1690
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1691
+ /* @__PURE__ */ jsx(
1692
+ HeroSection,
1693
+ {
1694
+ icon: /* @__PURE__ */ jsx(CircleStackIcon, { className: "h-5 w-5" }),
1695
+ label: labels.title,
1696
+ title: labels.title,
1697
+ subtitle: labels.subtitle,
1698
+ gradient: "from-amber-500 to-orange-600",
1699
+ toolbar: /* @__PURE__ */ jsx(
1700
+ CreateActionButton,
1701
+ {
1702
+ mode: "desktop",
1703
+ label: labels.addDatasource,
1704
+ onClick: () => setModalOpen(true),
1705
+ accent: "amber"
1706
+ }
1707
+ )
1708
+ }
1709
+ ),
1710
+ /* @__PURE__ */ jsx(
1711
+ CreateActionButton,
1712
+ {
1713
+ mode: "mobile",
1714
+ label: labels.addDatasource,
1715
+ onClick: () => setModalOpen(true),
1716
+ accent: "amber"
1717
+ }
1718
+ ),
1719
+ isEmpty ? /* @__PURE__ */ jsx(
1720
+ PageEmptyState,
1721
+ {
1722
+ title: labels.emptyTitle,
1723
+ message: labels.emptyDescription,
1724
+ iconName: "link",
1725
+ customIcon: /* @__PURE__ */ jsx(CircleStackIcon, { className: "h-10 w-10 text-amber-500 dark:text-amber-400" })
1726
+ }
1727
+ ) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: datasources.map((ds) => {
1728
+ const Icon = getDialectIcon(ds.dialect);
1729
+ const gradient = getDialectGradient(ds.dialect);
1730
+ const dialectLabel = getDialectLabel(ds.dialect);
1731
+ const logoSrc = getDialectLogoSrc(ds.dialect);
1732
+ const iconElement = logoSrc ? /* @__PURE__ */ jsx("div", { className: "flex h-11 w-11 items-center justify-center rounded-lg bg-white shadow-sm ring-1 ring-black/5 dark:bg-white/10 dark:ring-white/10", children: /* @__PURE__ */ jsx("img", { src: logoSrc, alt: dialectLabel, className: "h-7 w-7 object-contain" }) }) : /* @__PURE__ */ jsx("div", { className: `flex h-11 w-11 items-center justify-center rounded-lg bg-gradient-to-br ${gradient} shadow-lg`, children: /* @__PURE__ */ jsx(Icon, { className: "h-6 w-6 text-white" }) });
1733
+ return /* @__PURE__ */ jsx(
1734
+ EntityCard,
1735
+ {
1736
+ accentGradient: gradient,
1737
+ icon: iconElement,
1738
+ title: ds.name ?? ds.id,
1739
+ subtitle: dialectLabel,
1740
+ status: /* @__PURE__ */ jsx(Badge, { color: ds.enabled ? "emerald" : "zinc", children: ds.enabled ? labels.enabled : labels.disabled }),
1741
+ footer: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-400 dark:text-gray-500", children: [
1742
+ ds.readOnly && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-blue-100 px-2 py-0.5 text-[10px] font-semibold text-blue-700 dark:bg-blue-900/30 dark:text-blue-300", children: "Read-only" }),
1743
+ ds.timeoutMs && /* @__PURE__ */ jsxs("span", { children: [
1744
+ ds.timeoutMs / 1e3,
1745
+ "s timeout"
1746
+ ] })
1747
+ ] }),
1748
+ children: /* @__PURE__ */ jsxs("div", { className: "mt-2 text-xs text-gray-500 dark:text-gray-400", children: [
1749
+ /* @__PURE__ */ jsxs("div", { children: [
1750
+ labels.dialect,
1751
+ ": ",
1752
+ dialectLabel
1753
+ ] }),
1754
+ ds.slug && /* @__PURE__ */ jsxs("div", { className: "truncate text-gray-400", children: [
1755
+ "/",
1756
+ ds.slug
1757
+ ] })
1758
+ ] })
1759
+ },
1760
+ ds.id
1761
+ );
1762
+ }) }),
1763
+ /* @__PURE__ */ jsx(
1764
+ DatasourceModal,
1765
+ {
1766
+ open: modalOpen,
1767
+ onClose: () => setModalOpen(false),
1768
+ labels,
1769
+ onSave: handleCreate
1770
+ }
1771
+ )
1772
+ ] });
1773
+ }
1774
+
1775
+ export { AgentsConfigPageView, AgentsModelsPageView, AgentsPromptsPageView, AgentsToolDefinitionsPageView, DIALECT_CATEGORIES, DatasourceFormModal, DatasourceModal, DatasourcesPageView, RulesPageView, TOOL_TYPES, UsersPageView, findCategory, findDialect, jsonSchemaToParameters, parametersToJsonSchema };
1776
+ //# sourceMappingURL=index.mjs.map
1777
+ //# sourceMappingURL=index.mjs.map