@burdenoff/microfe-botmanor 2026.821.1 → 2026.925.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.
Files changed (65) hide show
  1. package/dist/botlit/BotlitRoutes.js.map +1 -1
  2. package/dist/botlit/BotmanorRoot.js.map +1 -1
  3. package/dist/botlit/BotmanorRootInner.js +4 -4
  4. package/dist/botlit/BotmanorRootInner.js.map +1 -1
  5. package/dist/botlit/components/ErrorState.js +33 -29
  6. package/dist/botlit/components/ErrorState.js.map +1 -1
  7. package/dist/botlit/components/RouteLoader.js +52 -48
  8. package/dist/botlit/components/RouteLoader.js.map +1 -1
  9. package/dist/botlit/components/VersionHistoryPanel.js +74 -77
  10. package/dist/botlit/components/VersionHistoryPanel.js.map +1 -1
  11. package/dist/botlit/components/WorkspaceRequired.js +31 -30
  12. package/dist/botlit/components/WorkspaceRequired.js.map +1 -1
  13. package/dist/botlit/hooks/internal/workspaceGateway.js.map +1 -1
  14. package/dist/botlit/hooks/useConversations.js.map +1 -1
  15. package/dist/botlit/hooks/useLLMProviders.js.map +1 -1
  16. package/dist/botlit/pages/A2AAgentDetailPage.js +1 -1
  17. package/dist/botlit/pages/A2AAgentDetailPage.js.map +1 -1
  18. package/dist/botlit/pages/A2ARegistryPage.js +116 -124
  19. package/dist/botlit/pages/A2ARegistryPage.js.map +1 -1
  20. package/dist/botlit/pages/AgentDetailPage.js +169 -172
  21. package/dist/botlit/pages/AgentDetailPage.js.map +1 -1
  22. package/dist/botlit/pages/AgentsListPage.js +96 -90
  23. package/dist/botlit/pages/AgentsListPage.js.map +1 -1
  24. package/dist/botlit/pages/BotChannelsTab.js.map +1 -1
  25. package/dist/botlit/pages/BotDetailPage.js +228 -231
  26. package/dist/botlit/pages/BotDetailPage.js.map +1 -1
  27. package/dist/botlit/pages/BotWorkflowTab.js +84 -87
  28. package/dist/botlit/pages/BotWorkflowTab.js.map +1 -1
  29. package/dist/botlit/pages/BotsListPage.js +144 -147
  30. package/dist/botlit/pages/BotsListPage.js.map +1 -1
  31. package/dist/botlit/pages/BucketsPage.js +3 -3
  32. package/dist/botlit/pages/BucketsPage.js.map +1 -1
  33. package/dist/botlit/pages/ChannelDetailPage.js +1 -1
  34. package/dist/botlit/pages/ChannelDetailPage.js.map +1 -1
  35. package/dist/botlit/pages/ChannelsPage.js +156 -149
  36. package/dist/botlit/pages/ChannelsPage.js.map +1 -1
  37. package/dist/botlit/pages/ChatPage.js +126 -129
  38. package/dist/botlit/pages/ChatPage.js.map +1 -1
  39. package/dist/botlit/pages/DashboardPage.js +111 -114
  40. package/dist/botlit/pages/DashboardPage.js.map +1 -1
  41. package/dist/botlit/pages/ExecutionsPage.js +163 -159
  42. package/dist/botlit/pages/ExecutionsPage.js.map +1 -1
  43. package/dist/botlit/pages/InstalledPackagesPage.js +3 -3
  44. package/dist/botlit/pages/InstalledPackagesPage.js.map +1 -1
  45. package/dist/botlit/pages/KnowledgeBasesPage.js +84 -78
  46. package/dist/botlit/pages/KnowledgeBasesPage.js.map +1 -1
  47. package/dist/botlit/pages/MCPServersPage.js +159 -154
  48. package/dist/botlit/pages/MCPServersPage.js.map +1 -1
  49. package/dist/botlit/pages/PoliciesPage.js +119 -114
  50. package/dist/botlit/pages/PoliciesPage.js.map +1 -1
  51. package/dist/botlit/pages/RetrievalProfilesPage.js +102 -109
  52. package/dist/botlit/pages/RetrievalProfilesPage.js.map +1 -1
  53. package/dist/botlit/pages/SettingsPage.js +144 -159
  54. package/dist/botlit/pages/SettingsPage.js.map +1 -1
  55. package/dist/botlit/pages/SkillsPage.js +122 -105
  56. package/dist/botlit/pages/SkillsPage.js.map +1 -1
  57. package/dist/botlit/pages/StorePage.js +176 -175
  58. package/dist/botlit/pages/StorePage.js.map +1 -1
  59. package/dist/botlit/providers/BotlitProvider.js.map +1 -1
  60. package/dist/botlit/store/botlitStore.js +1 -1
  61. package/dist/botlit/store/botlitStore.js.map +1 -1
  62. package/dist/botlit/utils/navigation.js.map +1 -1
  63. package/dist/shared/hooks/useTr.js +14 -0
  64. package/dist/shared/hooks/useTr.js.map +1 -0
  65. package/package.json +33 -9
@@ -1,18 +1,19 @@
1
- import { useConfigureLLMProvider as e, useLLMModels as t, useLLMProviders as n } from "../hooks/useLLMProviders.js";
2
- import { cn as r } from "../utils/cn.js";
3
- import { PageLayout as i } from "../components/PageLayout.js";
4
- import { Card as a, CardContent as o, CardDescription as s, CardHeader as c, CardTitle as l } from "../components/Card.js";
5
- import { Button as u } from "../components/Button.js";
6
- import { Badge as d } from "../components/Badge.js";
7
- import { FormField as f, Input as p } from "../components/Input.js";
8
- import { toUnion as m } from "../utils/unions.js";
9
- import { useState as h } from "react";
10
- import { PagePurpose as g } from "@burdenoff/fe-libs/ui";
11
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
12
- import { Brain as y, ExternalLink as b, Key as x, Link2 as S, Save as C } from "lucide-react";
13
- import { toast as w } from "sonner";
1
+ import { useTr as e } from "../../shared/hooks/useTr.js";
2
+ import { useConfigureLLMProvider as t, useLLMModels as n, useLLMProviders as r } from "../hooks/useLLMProviders.js";
3
+ import { cn as i } from "../utils/cn.js";
4
+ import { PageLayout as a } from "../components/PageLayout.js";
5
+ import { Card as o, CardContent as s, CardDescription as c, CardHeader as l, CardTitle as u } from "../components/Card.js";
6
+ import { Button as d } from "../components/Button.js";
7
+ import { Badge as f } from "../components/Badge.js";
8
+ import { FormField as p, Input as m } from "../components/Input.js";
9
+ import { toUnion as h } from "../utils/unions.js";
10
+ import { useState as g } from "react";
11
+ import { PagePurpose as _ } from "@burdenoff/fe-libs/ui";
12
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
13
+ import { Brain as b, ExternalLink as x, Key as S, Link2 as C, Save as w } from "lucide-react";
14
+ import { toast as T } from "sonner";
14
15
  //#region src/botlit/pages/SettingsPage.tsx
15
- var T = [
16
+ var E = [
16
17
  "OPENAI",
17
18
  "ANTHROPIC",
18
19
  "GOOGLE",
@@ -20,295 +21,279 @@ var T = [
20
21
  "AWS_BEDROCK",
21
22
  "CUSTOM"
22
23
  ];
23
- function E(e) {
24
- return m(e.toUpperCase(), T, "CUSTOM");
24
+ function D(e) {
25
+ return h(e.toUpperCase(), E, "CUSTOM");
25
26
  }
26
- var D = () => {
27
- let { data: m, refetch: T } = n(), { configureProvider: D, isConfiguring: O } = e(), { data: k } = t(), [A, j] = h(""), [M, N] = h("openai"), [P, F] = h(null), [I, L] = h("apikey"), [R, z] = h("");
28
- return /* @__PURE__ */ _(i, {
29
- title: "Settings",
30
- description: "Configure your Botlit workspace settings",
31
- children: /* @__PURE__ */ v("div", {
27
+ var O = () => {
28
+ let h = e(), { data: E, refetch: O } = r(), { configureProvider: k, isConfiguring: A } = t(), { data: j } = n(), [M, N] = g(""), [P, F] = g("openai"), [I, L] = g(null), [R, z] = g("apikey"), [B, V] = g("");
29
+ return /* @__PURE__ */ v(a, {
30
+ title: h("botlit.settings.title", "Settings"),
31
+ description: h("botlit.settings.description", "Configure your BotManor workspace settings"),
32
+ children: /* @__PURE__ */ y("div", {
32
33
  className: "space-y-6",
33
34
  children: [
34
- /* @__PURE__ */ _(g, {
35
- icon: /* @__PURE__ */ _(x, { size: 18 }),
36
- children: "Workspace-wide settings for LLM Providers — connect at least one model provider (OpenAI, Anthropic, Google and others) so your agents have a brain to think with."
35
+ /* @__PURE__ */ v(_, {
36
+ icon: /* @__PURE__ */ v(S, { size: 18 }),
37
+ children: h("botlit.settings.purpose", "Workspace-wide settings for LLM Providers — connect at least one model provider (OpenAI, Anthropic, Google and others) so your agents have a brain to think with.")
37
38
  }),
38
- /* @__PURE__ */ v(a, {
39
+ /* @__PURE__ */ y(o, {
39
40
  treatment: "glass",
40
41
  glow: !0,
41
- children: [/* @__PURE__ */ v(c, { children: [/* @__PURE__ */ _(l, { children: "LLM Providers" }), /* @__PURE__ */ _(s, { children: "Configure API keys for AI model providers" })] }), /* @__PURE__ */ _(o, {
42
+ children: [/* @__PURE__ */ y(l, { children: [/* @__PURE__ */ v(u, { children: h("botlit.settings.providers.title", "LLM Providers") }), /* @__PURE__ */ v(c, { children: h("botlit.settings.providers.description", "Configure API keys for AI model providers") })] }), /* @__PURE__ */ v(s, {
42
43
  className: "space-y-4",
43
- children: m?.map((e) => /* @__PURE__ */ v("div", {
44
+ children: E?.map((e) => /* @__PURE__ */ y("div", {
44
45
  className: "flex items-center justify-between p-4 border border-border-subtle rounded-lg",
45
- children: [/* @__PURE__ */ v("div", {
46
+ children: [/* @__PURE__ */ y("div", {
46
47
  className: "flex items-center gap-4",
47
- children: [/* @__PURE__ */ _("div", {
48
+ children: [/* @__PURE__ */ v("div", {
48
49
  className: "p-2 bg-action-primary-bg/10 rounded-lg",
49
- children: e.connectionId ? /* @__PURE__ */ _(S, { className: "h-5 w-5 text-primary" }) : /* @__PURE__ */ _(x, { className: "h-5 w-5 text-primary" })
50
- }), /* @__PURE__ */ v("div", { children: [
51
- /* @__PURE__ */ _("p", {
50
+ children: e.connectionId ? /* @__PURE__ */ v(C, { className: "h-5 w-5 text-primary" }) : /* @__PURE__ */ v(S, { className: "h-5 w-5 text-primary" })
51
+ }), /* @__PURE__ */ y("div", { children: [
52
+ /* @__PURE__ */ v("p", {
52
53
  className: "font-medium",
53
54
  children: e.name
54
55
  }),
55
56
  /* @__PURE__ */ v("p", {
56
57
  className: "text-sm text-text-secondary",
57
- children: ["Type: ", e.type]
58
+ children: h("botlit.settings.providers.type", "Type: {{type}}", { type: e.type })
58
59
  }),
59
- e.connectionId && /* @__PURE__ */ _("p", {
60
+ e.connectionId && /* @__PURE__ */ v("p", {
60
61
  className: "text-xs text-text-secondary mt-0.5",
61
- children: "Connected via Integrations"
62
+ children: h("botlit.settings.providers.connectedViaIntegrations", "Connected via Integrations")
62
63
  }),
63
- !e.connectionId && e.credentialsHash && /* @__PURE__ */ _("p", {
64
+ !e.connectionId && e.credentialsHash && /* @__PURE__ */ v("p", {
64
65
  className: "text-xs text-text-secondary mt-0.5",
65
- children: "API key stored locally"
66
+ children: h("botlit.settings.providers.apiKeyStored", "API key stored locally")
66
67
  })
67
68
  ] })]
68
- }), /* @__PURE__ */ v("div", {
69
+ }), /* @__PURE__ */ y("div", {
69
70
  className: "flex items-center gap-3",
70
71
  children: [
71
- e.connectionId && /* @__PURE__ */ _(d, {
72
+ e.connectionId && /* @__PURE__ */ v(f, {
72
73
  variant: "default",
73
- children: "Integration"
74
+ children: h("botlit.settings.providers.integrationBadge", "Integration")
74
75
  }),
75
- /* @__PURE__ */ _(d, {
76
+ /* @__PURE__ */ v(f, {
76
77
  variant: e.isActive ? "success" : "secondary",
77
- children: e.isActive ? "Active" : "Inactive"
78
+ children: e.isActive ? h("botlit.settings.providers.active", "Active") : h("botlit.settings.providers.inactive", "Inactive")
78
79
  }),
79
- /* @__PURE__ */ _(u, {
80
+ /* @__PURE__ */ v(d, {
80
81
  variant: "outline",
81
82
  size: "sm",
82
83
  onClick: () => {
83
- F(e.id), N(e.type.toLowerCase()), j(""), z(e.connectionId || ""), L(e.connectionId ? "integration" : "apikey"), document.getElementById("provider-form")?.scrollIntoView({ behavior: "smooth" });
84
+ L(e.id), F(e.type.toLowerCase()), N(""), V(e.connectionId || ""), z(e.connectionId ? "integration" : "apikey"), document.getElementById("provider-form")?.scrollIntoView({ behavior: "smooth" });
84
85
  },
85
- children: "Configure"
86
+ children: h("botlit.settings.actions.configure", "Configure")
86
87
  })
87
88
  ]
88
89
  })]
89
90
  }, e.id))
90
91
  })]
91
92
  }),
92
- /* @__PURE__ */ v(a, { children: [/* @__PURE__ */ v(c, { children: [/* @__PURE__ */ _(l, { children: "LLM Models" }), /* @__PURE__ */ _(s, { children: "Registered models across your providers" })] }), /* @__PURE__ */ _(o, {
93
+ /* @__PURE__ */ y(o, { children: [/* @__PURE__ */ y(l, { children: [/* @__PURE__ */ v(u, { children: h("botlit.settings.models.title", "LLM Models") }), /* @__PURE__ */ v(c, { children: h("botlit.settings.models.description", "Registered models across your providers") })] }), /* @__PURE__ */ v(s, {
93
94
  className: "space-y-4",
94
- children: k && k.length > 0 ? k.map((e) => {
95
- let t = m?.find((t) => t.id === e.providerId)?.name;
96
- return /* @__PURE__ */ v("div", {
95
+ children: j && j.length > 0 ? j.map((e) => {
96
+ let t = E?.find((t) => t.id === e.providerId)?.name;
97
+ return /* @__PURE__ */ y("div", {
97
98
  className: "flex items-center justify-between p-4 border border-border-subtle rounded-lg",
98
- children: [/* @__PURE__ */ v("div", {
99
+ children: [/* @__PURE__ */ y("div", {
99
100
  className: "flex items-center gap-4",
100
- children: [/* @__PURE__ */ _("div", {
101
+ children: [/* @__PURE__ */ v("div", {
101
102
  className: "p-2 bg-purple-500/10 rounded-lg",
102
- children: /* @__PURE__ */ _(y, { className: "h-5 w-5 text-purple-500" })
103
- }), /* @__PURE__ */ v("div", { children: [
104
- /* @__PURE__ */ _("p", {
103
+ children: /* @__PURE__ */ v(b, { className: "h-5 w-5 text-purple-500" })
104
+ }), /* @__PURE__ */ y("div", { children: [
105
+ /* @__PURE__ */ v("p", {
105
106
  className: "font-medium",
106
107
  children: e.name
107
108
  }),
108
- /* @__PURE__ */ v("p", {
109
+ /* @__PURE__ */ y("p", {
109
110
  className: "text-sm text-text-secondary",
110
111
  children: [e.modelId, t && ` · ${t}`]
111
112
  }),
112
- /* @__PURE__ */ v("div", {
113
+ /* @__PURE__ */ y("div", {
113
114
  className: "flex gap-3 mt-1 text-xs text-text-secondary",
114
115
  children: [
115
- e.contextWindow != null && /* @__PURE__ */ v("span", { children: [
116
- "Context: ",
117
- (e.contextWindow / 1e3).toFixed(0),
118
- "K"
119
- ] }),
120
- e.maxOutputTokens != null && /* @__PURE__ */ v("span", { children: [
121
- "Max out: ",
122
- (e.maxOutputTokens / 1e3).toFixed(0),
123
- "K"
124
- ] }),
125
- e.inputPricePerMToken != null && /* @__PURE__ */ v("span", { children: [
126
- "$",
127
- e.inputPricePerMToken,
128
- "/M in"
129
- ] }),
130
- e.outputPricePerMToken != null && /* @__PURE__ */ v("span", { children: [
131
- "$",
132
- e.outputPricePerMToken,
133
- "/M out"
134
- ] })
116
+ e.contextWindow != null && /* @__PURE__ */ v("span", { children: h("botlit.settings.models.context", "Context: {{value}}K", { value: (e.contextWindow / 1e3).toFixed(0) }) }),
117
+ e.maxOutputTokens != null && /* @__PURE__ */ v("span", { children: h("botlit.settings.models.maxOut", "Max out: {{value}}K", { value: (e.maxOutputTokens / 1e3).toFixed(0) }) }),
118
+ e.inputPricePerMToken != null && /* @__PURE__ */ v("span", { children: h("botlit.settings.models.priceIn", "${{value}}/M in", { value: e.inputPricePerMToken }) }),
119
+ e.outputPricePerMToken != null && /* @__PURE__ */ v("span", { children: h("botlit.settings.models.priceOut", "${{value}}/M out", { value: e.outputPricePerMToken }) })
135
120
  ]
136
121
  })
137
122
  ] })]
138
- }), /* @__PURE__ */ _(d, {
123
+ }), /* @__PURE__ */ v(f, {
139
124
  variant: e.isActive ? "success" : "secondary",
140
- children: e.isActive ? "Active" : "Inactive"
125
+ children: e.isActive ? h("botlit.settings.providers.active", "Active") : h("botlit.settings.providers.inactive", "Inactive")
141
126
  })]
142
127
  }, e.id);
143
- }) : /* @__PURE__ */ _("p", {
128
+ }) : /* @__PURE__ */ v("p", {
144
129
  className: "text-sm text-text-secondary text-center py-4",
145
- children: "No models registered yet."
130
+ children: h("botlit.settings.models.empty", "No models registered yet.")
146
131
  })
147
132
  })] }),
148
- /* @__PURE__ */ v(a, {
133
+ /* @__PURE__ */ y(o, {
149
134
  id: "provider-form",
150
- children: [/* @__PURE__ */ v(c, { children: [/* @__PURE__ */ _(l, { children: P ? "Update Provider" : "Add Provider" }), /* @__PURE__ */ _(s, { children: P ? "Update credentials for this provider" : "Configure a new LLM provider" })] }), /* @__PURE__ */ v(o, {
135
+ children: [/* @__PURE__ */ y(l, { children: [/* @__PURE__ */ v(u, { children: I ? h("botlit.settings.form.updateTitle", "Update Provider") : h("botlit.settings.form.addTitle", "Add Provider") }), /* @__PURE__ */ v(c, { children: I ? h("botlit.settings.form.updateDescription", "Update credentials for this provider") : h("botlit.settings.form.addDescription", "Configure a new LLM provider") })] }), /* @__PURE__ */ y(s, {
151
136
  className: "space-y-4",
152
137
  children: [
153
- /* @__PURE__ */ _(f, {
154
- label: "Provider",
155
- children: /* @__PURE__ */ v("select", {
138
+ /* @__PURE__ */ v(p, {
139
+ label: h("botlit.settings.form.providerLabel", "Provider"),
140
+ children: /* @__PURE__ */ y("select", {
156
141
  className: "flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm",
157
- value: M,
158
- onChange: (e) => N(e.target.value),
142
+ value: P,
143
+ onChange: (e) => F(e.target.value),
159
144
  children: [
160
- /* @__PURE__ */ _("option", {
145
+ /* @__PURE__ */ v("option", {
161
146
  value: "openai",
162
147
  children: "OpenAI"
163
148
  }),
164
- /* @__PURE__ */ _("option", {
149
+ /* @__PURE__ */ v("option", {
165
150
  value: "anthropic",
166
151
  children: "Anthropic"
167
152
  }),
168
- /* @__PURE__ */ _("option", {
153
+ /* @__PURE__ */ v("option", {
169
154
  value: "google",
170
155
  children: "Google AI"
171
156
  }),
172
- /* @__PURE__ */ _("option", {
157
+ /* @__PURE__ */ v("option", {
173
158
  value: "azure_openai",
174
159
  children: "Azure OpenAI"
175
160
  }),
176
- /* @__PURE__ */ _("option", {
161
+ /* @__PURE__ */ v("option", {
177
162
  value: "aws_bedrock",
178
163
  children: "AWS Bedrock"
179
164
  }),
180
- /* @__PURE__ */ _("option", {
165
+ /* @__PURE__ */ v("option", {
181
166
  value: "custom",
182
167
  children: "Custom"
183
168
  })
184
169
  ]
185
170
  })
186
171
  }),
187
- /* @__PURE__ */ _(f, {
188
- label: "Credential Method",
189
- children: /* @__PURE__ */ v("div", {
172
+ /* @__PURE__ */ v(p, {
173
+ label: h("botlit.settings.form.credentialMethod", "Credential Method"),
174
+ children: /* @__PURE__ */ y("div", {
190
175
  className: "flex gap-3",
191
- children: [/* @__PURE__ */ v("label", {
192
- className: r("flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1", I === "integration" ? "border-primary bg-action-primary-bg/5" : "border-border-subtle hover:border-primary/50"),
193
- children: [/* @__PURE__ */ _("input", {
176
+ children: [/* @__PURE__ */ y("label", {
177
+ className: i("flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1", R === "integration" ? "border-primary bg-action-primary-bg/5" : "border-border-subtle hover:border-primary/50"),
178
+ children: [/* @__PURE__ */ v("input", {
194
179
  type: "radio",
195
180
  name: "credentialMethod",
196
181
  value: "integration",
197
- checked: I === "integration",
198
- onChange: () => L("integration"),
182
+ checked: R === "integration",
183
+ onChange: () => z("integration"),
199
184
  className: "h-4 w-4"
200
- }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
185
+ }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
201
186
  className: "font-medium text-sm",
202
- children: "Connect via Integrations"
203
- }), /* @__PURE__ */ _("p", {
187
+ children: h("botlit.settings.form.integrationOption", "Connect via Integrations")
188
+ }), /* @__PURE__ */ v("p", {
204
189
  className: "text-xs text-text-secondary",
205
- children: "Managed credentials (recommended)"
190
+ children: h("botlit.settings.form.integrationHint", "Managed credentials (recommended)")
206
191
  })] })]
207
- }), /* @__PURE__ */ v("label", {
208
- className: r("flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1", I === "apikey" ? "border-primary bg-action-primary-bg/5" : "border-border-subtle hover:border-primary/50"),
209
- children: [/* @__PURE__ */ _("input", {
192
+ }), /* @__PURE__ */ y("label", {
193
+ className: i("flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1", R === "apikey" ? "border-primary bg-action-primary-bg/5" : "border-border-subtle hover:border-primary/50"),
194
+ children: [/* @__PURE__ */ v("input", {
210
195
  type: "radio",
211
196
  name: "credentialMethod",
212
197
  value: "apikey",
213
- checked: I === "apikey",
214
- onChange: () => L("apikey"),
198
+ checked: R === "apikey",
199
+ onChange: () => z("apikey"),
215
200
  className: "h-4 w-4"
216
- }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
201
+ }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
217
202
  className: "font-medium text-sm",
218
- children: "Enter API Key"
219
- }), /* @__PURE__ */ _("p", {
203
+ children: h("botlit.settings.form.apiKeyOption", "Enter API Key")
204
+ }), /* @__PURE__ */ v("p", {
220
205
  className: "text-xs text-text-secondary",
221
- children: "Paste key directly (legacy)"
206
+ children: h("botlit.settings.form.apiKeyHint", "Paste key directly (legacy)")
222
207
  })] })]
223
208
  })]
224
209
  })
225
210
  }),
226
- I === "integration" && /* @__PURE__ */ v("div", {
211
+ R === "integration" && /* @__PURE__ */ y("div", {
227
212
  className: "space-y-3",
228
- children: [/* @__PURE__ */ _("div", {
213
+ children: [/* @__PURE__ */ v("div", {
229
214
  className: "p-4 bg-bg-sunken/50 border border-border-subtle rounded-lg",
230
- children: /* @__PURE__ */ v("div", {
215
+ children: /* @__PURE__ */ y("div", {
231
216
  className: "flex items-start gap-3",
232
- children: [/* @__PURE__ */ _(S, { className: "h-5 w-5 text-primary mt-0.5 flex-shrink-0" }), /* @__PURE__ */ v("div", {
217
+ children: [/* @__PURE__ */ v(C, { className: "h-5 w-5 text-primary mt-0.5 flex-shrink-0" }), /* @__PURE__ */ y("div", {
233
218
  className: "space-y-2 flex-1",
234
219
  children: [
235
- /* @__PURE__ */ _("p", {
220
+ /* @__PURE__ */ v("p", {
236
221
  className: "text-sm font-medium",
237
- children: "Integration Connection"
222
+ children: h("botlit.settings.form.integrationTitle", "Integration Connection")
238
223
  }),
239
- /* @__PURE__ */ _("p", {
224
+ /* @__PURE__ */ v("p", {
240
225
  className: "text-xs text-text-secondary",
241
- children: "Create a connection in the Integrations module, then paste the Connection ID here. This stores your API key securely in the Integrations vault."
226
+ children: h("botlit.settings.form.integrationDescription", "Create a connection in the Integrations module, then paste the Connection ID here. This stores your API key securely in the Integrations vault.")
242
227
  }),
243
- /* @__PURE__ */ _("div", {
228
+ /* @__PURE__ */ v("div", {
244
229
  className: "flex gap-2 mt-2",
245
- children: /* @__PURE__ */ v(u, {
230
+ children: /* @__PURE__ */ y(d, {
246
231
  variant: "outline",
247
232
  size: "sm",
248
233
  onClick: () => {
249
234
  window.open("/integrations/connections", "_blank");
250
235
  },
251
- children: [/* @__PURE__ */ _(b, {
236
+ children: [/* @__PURE__ */ v(x, {
252
237
  size: 14,
253
238
  className: "mr-1.5"
254
- }), "Open Integrations"]
239
+ }), h("botlit.settings.form.openIntegrations", "Open Integrations")]
255
240
  })
256
241
  })
257
242
  ]
258
243
  })]
259
244
  })
260
- }), /* @__PURE__ */ _(f, {
261
- label: "Connection ID",
262
- children: /* @__PURE__ */ _(p, {
263
- placeholder: "Paste connection ID from Integrations...",
264
- value: R,
265
- onChange: (e) => z(e.target.value)
245
+ }), /* @__PURE__ */ v(p, {
246
+ label: h("botlit.settings.form.connectionIdPlaceholder", "Connection ID"),
247
+ children: /* @__PURE__ */ v(m, {
248
+ placeholder: h("botlit.settings.form.connectionIdPlaceholder", "Paste connection ID from Integrations..."),
249
+ value: B,
250
+ onChange: (e) => V(e.target.value)
266
251
  })
267
252
  })]
268
253
  }),
269
- I === "apikey" && /* @__PURE__ */ _(f, {
270
- label: "API Key",
271
- children: /* @__PURE__ */ _(p, {
254
+ R === "apikey" && /* @__PURE__ */ v(p, {
255
+ label: h("botlit.settings.form.apiKeyLabel", "API Key"),
256
+ children: /* @__PURE__ */ v(m, {
272
257
  type: "password",
273
- placeholder: "sk-...",
274
- value: A,
275
- onChange: (e) => j(e.target.value)
258
+ placeholder: h("botlit.settings.form.apiKeyPlaceholder", "sk-..."),
259
+ value: M,
260
+ onChange: (e) => N(e.target.value)
276
261
  })
277
262
  }),
278
- /* @__PURE__ */ v("div", {
263
+ /* @__PURE__ */ y("div", {
279
264
  className: "flex gap-2",
280
- children: [/* @__PURE__ */ _(u, {
281
- leftIcon: /* @__PURE__ */ _(C, { size: 16 }),
282
- isLoading: O,
283
- disabled: I === "apikey" ? !A : !R,
265
+ children: [/* @__PURE__ */ v(d, {
266
+ leftIcon: /* @__PURE__ */ v(w, { size: 16 }),
267
+ isLoading: A,
268
+ disabled: R === "apikey" ? !M : !B,
284
269
  onClick: async () => {
285
270
  try {
286
- let e = M.charAt(0).toUpperCase() + M.slice(1), t = I === "integration" ? void 0 : A ? { apiKey: A } : void 0, n = I === "integration" ? R : void 0;
287
- P ? await D({
271
+ let e = P.charAt(0).toUpperCase() + P.slice(1), t = R === "integration" ? void 0 : M ? { apiKey: M } : void 0, n = R === "integration" ? B : void 0;
272
+ I ? await k({
288
273
  name: e,
289
- type: E(M),
274
+ type: D(P),
290
275
  connectionId: n,
291
276
  credentials: t
292
- }, P) : await D({
277
+ }, I) : await k({
293
278
  name: e,
294
- type: E(M),
279
+ type: D(P),
295
280
  connectionId: n,
296
281
  credentials: t
297
- }), j(""), z(""), F(null), await T();
298
- let r = M.charAt(0).toUpperCase() + M.slice(1);
299
- w.success(P ? `${r} provider updated successfully` : `${r} provider added successfully`);
282
+ }), N(""), V(""), L(null), await O();
283
+ let r = P.charAt(0).toUpperCase() + P.slice(1);
284
+ T.success(I ? h("botlit.settings.form.updateSuccess", "{{provider}} provider updated successfully", { provider: r }) : h("botlit.settings.form.addSuccess", "{{provider}} provider added successfully", { provider: r }));
300
285
  } catch (e) {
301
- let t = e instanceof Error ? e.message : "Failed to save provider";
302
- w.error(t);
286
+ let t = e instanceof Error ? e.message : h("botlit.settings.form.saveError", "Failed to save provider");
287
+ T.error(t);
303
288
  }
304
289
  },
305
- children: P ? "Update Provider" : "Save Provider"
306
- }), P && /* @__PURE__ */ _(u, {
290
+ children: I ? h("botlit.settings.form.updateProvider", "Update Provider") : h("botlit.settings.form.saveProvider", "Save Provider")
291
+ }), I && /* @__PURE__ */ v(d, {
307
292
  variant: "outline",
308
293
  onClick: () => {
309
- F(null), j(""), z(""), L("apikey"), N("openai");
294
+ L(null), N(""), V(""), z("apikey"), F("openai");
310
295
  },
311
- children: "Cancel"
296
+ children: h("botlit.settings.form.cancel", "Cancel")
312
297
  })]
313
298
  })
314
299
  ]
@@ -319,6 +304,6 @@ var D = () => {
319
304
  });
320
305
  };
321
306
  //#endregion
322
- export { D as SettingsPage };
307
+ export { O as SettingsPage };
323
308
 
324
309
  //# sourceMappingURL=SettingsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsPage.js","names":[],"sources":["../../../src/botlit/pages/SettingsPage.tsx"],"sourcesContent":["/**\n * Settings Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Key, Save, Brain, Link2, ExternalLink } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { PagePurpose } 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, FormField } from '../components/Input';\nimport { Badge } from '../components/Badge';\nimport { useLLMProviders, useConfigureLLMProvider, useLLMModels } from '../hooks/useLLMProviders';\nimport { cn } from '../utils/cn';\nimport { toUnion } from '../utils/unions';\n\n/** Provider kinds the form offers, in the casing the service stores. */\nconst PROVIDER_TYPES = [\n 'OPENAI',\n 'ANTHROPIC',\n 'GOOGLE',\n 'AZURE_OPENAI',\n 'AWS_BEDROCK',\n 'CUSTOM',\n] as const;\n\n/** The `<option>` values are lowercase; the column is the uppercase enum. */\nfunction toProviderType(value: string): (typeof PROVIDER_TYPES)[number] {\n return toUnion(value.toUpperCase(), PROVIDER_TYPES, 'CUSTOM');\n}\n\nexport const SettingsPage: FC = () => {\n const { data: providers, refetch: refetchProviders } = useLLMProviders();\n const { configureProvider, isConfiguring } = useConfigureLLMProvider();\n const { data: llmModels } = useLLMModels();\n const [apiKey, setApiKey] = useState('');\n const [selectedProviderType, setSelectedProviderType] = useState('openai');\n const [editingProviderId, setEditingProviderId] = useState<string | null>(null);\n // Credential method: 'integration' (preferred) or 'apikey' (legacy)\n const [credentialMethod, setCredentialMethod] = useState<'integration' | 'apikey'>('apikey');\n const [connectionId, setConnectionId] = useState('');\n\n return (\n <PageLayout title=\"Settings\" description=\"Configure your Botlit workspace settings\">\n <div className=\"space-y-6\">\n <PagePurpose icon={<Key size={18} />}>\n Workspace-wide settings for LLM Providers — connect at least one model provider (OpenAI,\n Anthropic, Google and others) so your agents have a brain to think with.\n </PagePurpose>\n\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>LLM Providers</CardTitle>\n <CardDescription>Configure API keys for AI model providers</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {providers?.map(\n (provider: {\n id: string;\n name: string;\n type: string;\n isActive: boolean;\n connectionId?: string | null;\n credentialsHash?: string | null;\n }) => (\n <div\n key={provider.id}\n className=\"flex items-center justify-between p-4 border border-border-subtle rounded-lg\"\n >\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-lg\">\n {provider.connectionId ? (\n <Link2 className=\"h-5 w-5 text-primary\" />\n ) : (\n <Key className=\"h-5 w-5 text-primary\" />\n )}\n </div>\n <div>\n <p className=\"font-medium\">{provider.name}</p>\n <p className=\"text-sm text-text-secondary\">Type: {provider.type}</p>\n {provider.connectionId && (\n <p className=\"text-xs text-text-secondary mt-0.5\">\n Connected via Integrations\n </p>\n )}\n {!provider.connectionId && provider.credentialsHash && (\n <p className=\"text-xs text-text-secondary mt-0.5\">API key stored locally</p>\n )}\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n {provider.connectionId && <Badge variant=\"default\">Integration</Badge>}\n <Badge variant={provider.isActive ? 'success' : 'secondary'}>\n {provider.isActive ? 'Active' : 'Inactive'}\n </Badge>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setEditingProviderId(provider.id);\n setSelectedProviderType(provider.type.toLowerCase());\n setApiKey('');\n setConnectionId(provider.connectionId || '');\n setCredentialMethod(provider.connectionId ? 'integration' : 'apikey');\n // Scroll to the Add Provider form\n document\n .getElementById('provider-form')\n ?.scrollIntoView({ behavior: 'smooth' });\n }}\n >\n Configure\n </Button>\n </div>\n </div>\n )\n )}\n </CardContent>\n </Card>\n\n {/* LLM Models List */}\n <Card>\n <CardHeader>\n <CardTitle>LLM Models</CardTitle>\n <CardDescription>Registered models across your providers</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {llmModels && llmModels.length > 0 ? (\n llmModels.map(\n (model: {\n id: string;\n name: string;\n modelId: string;\n providerId: string;\n isActive: boolean;\n contextWindow?: number;\n maxOutputTokens?: number;\n inputPricePerMToken?: number;\n outputPricePerMToken?: number;\n }) => {\n const providerName = providers?.find(\n (p: { id: string; name: string }) => p.id === model.providerId\n )?.name;\n return (\n <div\n key={model.id}\n className=\"flex items-center justify-between p-4 border border-border-subtle rounded-lg\"\n >\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 bg-purple-500/10 rounded-lg\">\n <Brain className=\"h-5 w-5 text-purple-500\" />\n </div>\n <div>\n <p className=\"font-medium\">{model.name}</p>\n <p className=\"text-sm text-text-secondary\">\n {model.modelId}\n {providerName && ` · ${providerName}`}\n </p>\n <div className=\"flex gap-3 mt-1 text-xs text-text-secondary\">\n {model.contextWindow != null && (\n <span>Context: {(model.contextWindow / 1000).toFixed(0)}K</span>\n )}\n {model.maxOutputTokens != null && (\n <span>Max out: {(model.maxOutputTokens / 1000).toFixed(0)}K</span>\n )}\n {model.inputPricePerMToken != null && (\n <span>${model.inputPricePerMToken}/M in</span>\n )}\n {model.outputPricePerMToken != null && (\n <span>${model.outputPricePerMToken}/M out</span>\n )}\n </div>\n </div>\n </div>\n <Badge variant={model.isActive ? 'success' : 'secondary'}>\n {model.isActive ? 'Active' : 'Inactive'}\n </Badge>\n </div>\n );\n }\n )\n ) : (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n No models registered yet.\n </p>\n )}\n </CardContent>\n </Card>\n\n <Card id=\"provider-form\">\n <CardHeader>\n <CardTitle>{editingProviderId ? 'Update Provider' : 'Add Provider'}</CardTitle>\n <CardDescription>\n {editingProviderId\n ? 'Update credentials for this provider'\n : 'Configure a new LLM provider'}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Provider\">\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={selectedProviderType}\n onChange={(e) => setSelectedProviderType(e.target.value)}\n >\n <option value=\"openai\">OpenAI</option>\n <option value=\"anthropic\">Anthropic</option>\n <option value=\"google\">Google AI</option>\n <option value=\"azure_openai\">Azure OpenAI</option>\n <option value=\"aws_bedrock\">AWS Bedrock</option>\n <option value=\"custom\">Custom</option>\n </select>\n </FormField>\n\n {/* Credential method selector */}\n <FormField label=\"Credential Method\">\n <div className=\"flex gap-3\">\n <label\n className={cn(\n 'flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1',\n credentialMethod === 'integration'\n ? 'border-primary bg-action-primary-bg/5'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n <input\n type=\"radio\"\n name=\"credentialMethod\"\n value=\"integration\"\n checked={credentialMethod === 'integration'}\n onChange={() => setCredentialMethod('integration')}\n className=\"h-4 w-4\"\n />\n <div>\n <p className=\"font-medium text-sm\">Connect via Integrations</p>\n <p className=\"text-xs text-text-secondary\">Managed credentials (recommended)</p>\n </div>\n </label>\n <label\n className={cn(\n 'flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1',\n credentialMethod === 'apikey'\n ? 'border-primary bg-action-primary-bg/5'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n <input\n type=\"radio\"\n name=\"credentialMethod\"\n value=\"apikey\"\n checked={credentialMethod === 'apikey'}\n onChange={() => setCredentialMethod('apikey')}\n className=\"h-4 w-4\"\n />\n <div>\n <p className=\"font-medium text-sm\">Enter API Key</p>\n <p className=\"text-xs text-text-secondary\">Paste key directly (legacy)</p>\n </div>\n </label>\n </div>\n </FormField>\n\n {/* Integration connection method */}\n {credentialMethod === 'integration' && (\n <div className=\"space-y-3\">\n <div className=\"p-4 bg-bg-sunken/50 border border-border-subtle rounded-lg\">\n <div className=\"flex items-start gap-3\">\n <Link2 className=\"h-5 w-5 text-primary mt-0.5 flex-shrink-0\" />\n <div className=\"space-y-2 flex-1\">\n <p className=\"text-sm font-medium\">Integration Connection</p>\n <p className=\"text-xs text-text-secondary\">\n Create a connection in the Integrations module, then paste the Connection ID\n here. This stores your API key securely in the Integrations vault.\n </p>\n <div className=\"flex gap-2 mt-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n window.open('/integrations/connections', '_blank');\n }}\n >\n <ExternalLink size={14} className=\"mr-1.5\" />\n Open Integrations\n </Button>\n </div>\n </div>\n </div>\n </div>\n <FormField label=\"Connection ID\">\n <Input\n placeholder=\"Paste connection ID from Integrations...\"\n value={connectionId}\n onChange={(e) => setConnectionId(e.target.value)}\n />\n </FormField>\n </div>\n )}\n\n {/* Legacy API key method */}\n {credentialMethod === 'apikey' && (\n <FormField label=\"API Key\">\n <Input\n type=\"password\"\n placeholder=\"sk-...\"\n value={apiKey}\n onChange={(e) => setApiKey(e.target.value)}\n />\n </FormField>\n )}\n\n <div className=\"flex gap-2\">\n <Button\n leftIcon={<Save size={16} />}\n isLoading={isConfiguring}\n disabled={credentialMethod === 'apikey' ? !apiKey : !connectionId}\n onClick={async () => {\n try {\n const providerName =\n selectedProviderType.charAt(0).toUpperCase() + selectedProviderType.slice(1);\n\n // `useConfigureLLMProvider` projects each payload\n // onto the fields its input type declares and adds\n // the workspace id, so only real fields go here.\n const credentials =\n credentialMethod === 'integration'\n ? undefined\n : apiKey\n ? { apiKey }\n : undefined;\n const linkedConnectionId =\n credentialMethod === 'integration' ? connectionId : undefined;\n\n if (editingProviderId) {\n await configureProvider(\n {\n name: providerName,\n type: toProviderType(selectedProviderType),\n connectionId: linkedConnectionId,\n credentials,\n },\n editingProviderId\n );\n } else {\n await configureProvider({\n name: providerName,\n type: toProviderType(selectedProviderType),\n connectionId: linkedConnectionId,\n credentials,\n });\n }\n\n setApiKey('');\n setConnectionId('');\n setEditingProviderId(null);\n await refetchProviders();\n const providerLabel =\n selectedProviderType.charAt(0).toUpperCase() + selectedProviderType.slice(1);\n toast.success(\n editingProviderId\n ? `${providerLabel} provider updated successfully`\n : `${providerLabel} provider added successfully`\n );\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to save provider';\n toast.error(message);\n }\n }}\n >\n {editingProviderId ? 'Update Provider' : 'Save Provider'}\n </Button>\n {editingProviderId && (\n <Button\n variant=\"outline\"\n onClick={() => {\n setEditingProviderId(null);\n setApiKey('');\n setConnectionId('');\n setCredentialMethod('apikey');\n setSelectedProviderType('openai');\n }}\n >\n Cancel\n </Button>\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;AAoBA,IAAM,IAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACD;AAGD,SAAS,EAAe,GAAgD;AACtE,QAAO,EAAQ,EAAM,aAAa,EAAE,GAAgB,SAAS;;AAG/D,IAAa,UAAyB;CACpC,IAAM,EAAE,MAAM,GAAW,SAAS,MAAqB,GAAiB,EAClE,EAAE,sBAAmB,qBAAkB,GAAyB,EAChE,EAAE,MAAM,MAAc,GAAc,EACpC,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAsB,KAA2B,EAAS,SAAS,EACpE,CAAC,GAAmB,KAAwB,EAAwB,KAAK,EAEzE,CAAC,GAAkB,KAAuB,EAAmC,SAAS,EACtF,CAAC,GAAc,KAAmB,EAAS,GAAG;AAEpD,QACE,kBAAC,GAAD;EAAY,OAAM;EAAW,aAAY;YACvC,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KAAa,MAAM,kBAAC,GAAD,EAAK,MAAM,IAAM,CAAA;eAAE;KAGxB,CAAA;IAEd,kBAAC,GAAD;KAAM,WAAU;KAAQ,MAAA;eAAxB,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAW,iBAAyB,CAAA,EACpC,kBAAC,GAAD,EAAA,UAAiB,6CAA2D,CAAA,CACjE,EAAA,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBACpB,GAAW,KACT,MAQC,kBAAC,OAAD;OAEE,WAAU;iBAFZ,CAIE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBACZ,EAAS,eACR,kBAAC,GAAD,EAAO,WAAU,wBAAyB,CAAA,GAE1C,kBAAC,GAAD,EAAK,WAAU,wBAAyB,CAAA;SAEtC,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA;SACE,kBAAC,KAAD;UAAG,WAAU;oBAAe,EAAS;UAAS,CAAA;SAC9C,kBAAC,KAAD;UAAG,WAAU;oBAAb,CAA2C,UAAO,EAAS,KAAS;;SACnE,EAAS,gBACR,kBAAC,KAAD;UAAG,WAAU;oBAAqC;UAE9C,CAAA;SAEL,CAAC,EAAS,gBAAgB,EAAS,mBAClC,kBAAC,KAAD;UAAG,WAAU;oBAAqC;UAA0B,CAAA;SAE1E,EAAA,CAAA,CACF;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACG,EAAS,gBAAgB,kBAAC,GAAD;UAAO,SAAQ;oBAAU;UAAmB,CAAA;SACtE,kBAAC,GAAD;UAAO,SAAS,EAAS,WAAW,YAAY;oBAC7C,EAAS,WAAW,WAAW;UAC1B,CAAA;SACR,kBAAC,GAAD;UACE,SAAQ;UACR,MAAK;UACL,eAAe;AAOb,WANA,EAAqB,EAAS,GAAG,EACjC,EAAwB,EAAS,KAAK,aAAa,CAAC,EACpD,EAAU,GAAG,EACb,EAAgB,EAAS,gBAAgB,GAAG,EAC5C,EAAoB,EAAS,eAAe,gBAAgB,SAAS,EAErE,SACG,eAAe,gBAAgB,EAC9B,eAAe,EAAE,UAAU,UAAU,CAAC;;oBAE7C;UAEQ,CAAA;SACL;UACF;SA/CC,EAAS,GA+CV,CAET;MACW,CAAA,CACT;;IAGP,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAW,cAAsB,CAAA,EACjC,kBAAC,GAAD,EAAA,UAAiB,2CAAyD,CAAA,CAC/D,EAAA,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eACpB,KAAa,EAAU,SAAS,IAC/B,EAAU,KACP,MAUK;MACJ,IAAM,IAAe,GAAW,MAC7B,MAAoC,EAAE,OAAO,EAAM,WACrD,EAAE;AACH,aACE,kBAAC,OAAD;OAEE,WAAU;iBAFZ,CAIE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,GAAD,EAAO,WAAU,2BAA4B,CAAA;SACzC,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA;SACE,kBAAC,KAAD;UAAG,WAAU;oBAAe,EAAM;UAAS,CAAA;SAC3C,kBAAC,KAAD;UAAG,WAAU;oBAAb,CACG,EAAM,SACN,KAAgB,MAAM,IACrB;;SACJ,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACG,EAAM,iBAAiB,QACtB,kBAAC,QAAD,EAAA,UAAA;YAAM;aAAW,EAAM,gBAAgB,KAAM,QAAQ,EAAE;YAAC;YAAQ,EAAA,CAAA;WAEjE,EAAM,mBAAmB,QACxB,kBAAC,QAAD,EAAA,UAAA;YAAM;aAAW,EAAM,kBAAkB,KAAM,QAAQ,EAAE;YAAC;YAAQ,EAAA,CAAA;WAEnE,EAAM,uBAAuB,QAC5B,kBAAC,QAAD,EAAA,UAAA;YAAM;YAAE,EAAM;YAAoB;YAAY,EAAA,CAAA;WAE/C,EAAM,wBAAwB,QAC7B,kBAAC,QAAD,EAAA,UAAA;YAAM;YAAE,EAAM;YAAqB;YAAa,EAAA,CAAA;WAE9C;;SACF,EAAA,CAAA,CACF;WACN,kBAAC,GAAD;QAAO,SAAS,EAAM,WAAW,YAAY;kBAC1C,EAAM,WAAW,WAAW;QACvB,CAAA,CACJ;SAhCC,EAAM,GAgCP;OAGX,GAED,kBAAC,KAAD;MAAG,WAAU;gBAA+C;MAExD,CAAA;KAEM,CAAA,CACT,EAAA,CAAA;IAEP,kBAAC,GAAD;KAAM,IAAG;eAAT,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAY,IAAoB,oBAAoB,gBAA2B,CAAA,EAC/E,kBAAC,GAAD,EAAA,UACG,IACG,yCACA,gCACY,CAAA,CACP,EAAA,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,GAAD;QAAW,OAAM;kBACf,kBAAC,UAAD;SACE,WAAU;SACV,OAAO;SACP,WAAW,MAAM,EAAwB,EAAE,OAAO,MAAM;mBAH1D;UAKE,kBAAC,UAAD;WAAQ,OAAM;qBAAS;WAAe,CAAA;UACtC,kBAAC,UAAD;WAAQ,OAAM;qBAAY;WAAkB,CAAA;UAC5C,kBAAC,UAAD;WAAQ,OAAM;qBAAS;WAAkB,CAAA;UACzC,kBAAC,UAAD;WAAQ,OAAM;qBAAe;WAAqB,CAAA;UAClD,kBAAC,UAAD;WAAQ,OAAM;qBAAc;WAAoB,CAAA;UAChD,kBAAC,UAAD;WAAQ,OAAM;qBAAS;WAAe,CAAA;UAC/B;;QACC,CAAA;OAGZ,kBAAC,GAAD;QAAW,OAAM;kBACf,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,SAAD;UACE,WAAW,EACT,+FACA,MAAqB,gBACjB,0CACA,+CACL;oBANH,CAQE,kBAAC,SAAD;WACE,MAAK;WACL,MAAK;WACL,OAAM;WACN,SAAS,MAAqB;WAC9B,gBAAgB,EAAoB,cAAc;WAClD,WAAU;WACV,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAsB;WAA4B,CAAA,EAC/D,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAqC,CAAA,CAC5E,EAAA,CAAA,CACA;aACR,kBAAC,SAAD;UACE,WAAW,EACT,+FACA,MAAqB,WACjB,0CACA,+CACL;oBANH,CAQE,kBAAC,SAAD;WACE,MAAK;WACL,MAAK;WACL,OAAM;WACN,SAAS,MAAqB;WAC9B,gBAAgB,EAAoB,SAAS;WAC7C,WAAU;WACV,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAsB;WAAiB,CAAA,EACpD,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAA+B,CAAA,CACtE,EAAA,CAAA,CACA;YACJ;;QACI,CAAA;OAGX,MAAqB,iBACpB,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD,EAAO,WAAU,6CAA8C,CAAA,EAC/D,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,KAAD;aAAG,WAAU;uBAAsB;aAA0B,CAAA;YAC7D,kBAAC,KAAD;aAAG,WAAU;uBAA8B;aAGvC,CAAA;YACJ,kBAAC,OAAD;aAAK,WAAU;uBACb,kBAAC,GAAD;cACE,SAAQ;cACR,MAAK;cACL,eAAe;AACb,sBAAO,KAAK,6BAA6B,SAAS;;wBAJtD,CAOE,kBAAC,GAAD;eAAc,MAAM;eAAI,WAAU;eAAW,CAAA,EAAA,oBAEtC;;aACL,CAAA;YACF;aACF;;SACF,CAAA,EACN,kBAAC,GAAD;SAAW,OAAM;mBACf,kBAAC,GAAD;UACE,aAAY;UACZ,OAAO;UACP,WAAW,MAAM,EAAgB,EAAE,OAAO,MAAM;UAChD,CAAA;SACQ,CAAA,CACR;;OAIP,MAAqB,YACpB,kBAAC,GAAD;QAAW,OAAM;kBACf,kBAAC,GAAD;SACE,MAAK;SACL,aAAY;SACZ,OAAO;SACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;SAC1C,CAAA;QACQ,CAAA;OAGd,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SACE,UAAU,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;SAC5B,WAAW;SACX,UAAU,MAAqB,WAAW,CAAC,IAAS,CAAC;SACrD,SAAS,YAAY;AACnB,cAAI;WACF,IAAM,IACJ,EAAqB,OAAO,EAAE,CAAC,aAAa,GAAG,EAAqB,MAAM,EAAE,EAKxE,IACJ,MAAqB,gBACjB,KAAA,IACA,IACE,EAAE,WAAQ,GACV,KAAA,GACF,IACJ,MAAqB,gBAAgB,IAAe,KAAA;AAwBtD,WAtBI,IACF,MAAM,EACJ;YACE,MAAM;YACN,MAAM,EAAe,EAAqB;YAC1C,cAAc;YACd;YACD,EACD,EACD,GAED,MAAM,EAAkB;YACtB,MAAM;YACN,MAAM,EAAe,EAAqB;YAC1C,cAAc;YACd;YACD,CAAC,EAGJ,EAAU,GAAG,EACb,EAAgB,GAAG,EACnB,EAAqB,KAAK,EAC1B,MAAM,GAAkB;WACxB,IAAM,IACJ,EAAqB,OAAO,EAAE,CAAC,aAAa,GAAG,EAAqB,MAAM,EAAE;AAC9E,aAAM,QACJ,IACI,GAAG,EAAc,kCACjB,GAAG,EAAc,8BACtB;mBACM,GAAc;WACrB,IAAM,IAAU,aAAe,QAAQ,EAAI,UAAU;AACrD,aAAM,MAAM,EAAQ;;;mBAIvB,IAAoB,oBAAoB;SAClC,CAAA,EACR,KACC,kBAAC,GAAD;SACE,SAAQ;SACR,eAAe;AAKb,UAJA,EAAqB,KAAK,EAC1B,EAAU,GAAG,EACb,EAAgB,GAAG,EACnB,EAAoB,SAAS,EAC7B,EAAwB,SAAS;;mBAEpC;SAEQ,CAAA,CAEP;;OACM;QACT;;IACH;;EACK,CAAA"}
1
+ {"version":3,"file":"SettingsPage.js","names":[],"sources":["../../../src/botlit/pages/SettingsPage.tsx"],"sourcesContent":["/**\n * Settings Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Key, Save, Brain, Link2, ExternalLink } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { PagePurpose } 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, FormField } from '../components/Input';\nimport { Badge } from '../components/Badge';\nimport { useLLMProviders, useConfigureLLMProvider, useLLMModels } from '../hooks/useLLMProviders';\nimport { cn } from '../utils/cn';\nimport { toUnion } from '../utils/unions';\n\n/** Provider kinds the form offers, in the casing the service stores. */\nconst PROVIDER_TYPES = [\n 'OPENAI',\n 'ANTHROPIC',\n 'GOOGLE',\n 'AZURE_OPENAI',\n 'AWS_BEDROCK',\n 'CUSTOM',\n] as const;\n\n/** The `<option>` values are lowercase; the column is the uppercase enum. */\nfunction toProviderType(value: string): (typeof PROVIDER_TYPES)[number] {\n return toUnion(value.toUpperCase(), PROVIDER_TYPES, 'CUSTOM');\n}\n\nexport const SettingsPage: FC = () => {\n const t = useTr();\n const { data: providers, refetch: refetchProviders } = useLLMProviders();\n const { configureProvider, isConfiguring } = useConfigureLLMProvider();\n const { data: llmModels } = useLLMModels();\n const [apiKey, setApiKey] = useState('');\n const [selectedProviderType, setSelectedProviderType] = useState('openai');\n const [editingProviderId, setEditingProviderId] = useState<string | null>(null);\n // Credential method: 'integration' (preferred) or 'apikey' (legacy)\n const [credentialMethod, setCredentialMethod] = useState<'integration' | 'apikey'>('apikey');\n const [connectionId, setConnectionId] = useState('');\n\n return (\n <PageLayout\n title={t('botlit.settings.title', 'Settings')}\n description={t('botlit.settings.description', 'Configure your BotManor workspace settings')}\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Key size={18} />}>\n {t(\n 'botlit.settings.purpose',\n 'Workspace-wide settings for LLM Providers — connect at least one model provider (OpenAI, Anthropic, Google and others) so your agents have a brain to think with.'\n )}\n </PagePurpose>\n\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>{t('botlit.settings.providers.title', 'LLM Providers')}</CardTitle>\n <CardDescription>\n {t(\n 'botlit.settings.providers.description',\n 'Configure API keys for AI model providers'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {providers?.map(\n (provider: {\n id: string;\n name: string;\n type: string;\n isActive: boolean;\n connectionId?: string | null;\n credentialsHash?: string | null;\n }) => (\n <div\n key={provider.id}\n className=\"flex items-center justify-between p-4 border border-border-subtle rounded-lg\"\n >\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-lg\">\n {provider.connectionId ? (\n <Link2 className=\"h-5 w-5 text-primary\" />\n ) : (\n <Key className=\"h-5 w-5 text-primary\" />\n )}\n </div>\n <div>\n <p className=\"font-medium\">{provider.name}</p>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.settings.providers.type', 'Type: {{type}}', {\n type: provider.type,\n })}\n </p>\n {provider.connectionId && (\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {t(\n 'botlit.settings.providers.connectedViaIntegrations',\n 'Connected via Integrations'\n )}\n </p>\n )}\n {!provider.connectionId && provider.credentialsHash && (\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {t('botlit.settings.providers.apiKeyStored', 'API key stored locally')}\n </p>\n )}\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n {provider.connectionId && (\n <Badge variant=\"default\">\n {t('botlit.settings.providers.integrationBadge', 'Integration')}\n </Badge>\n )}\n <Badge variant={provider.isActive ? 'success' : 'secondary'}>\n {provider.isActive\n ? t('botlit.settings.providers.active', 'Active')\n : t('botlit.settings.providers.inactive', 'Inactive')}\n </Badge>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setEditingProviderId(provider.id);\n setSelectedProviderType(provider.type.toLowerCase());\n setApiKey('');\n setConnectionId(provider.connectionId || '');\n setCredentialMethod(provider.connectionId ? 'integration' : 'apikey');\n // Scroll to the Add Provider form\n document\n .getElementById('provider-form')\n ?.scrollIntoView({ behavior: 'smooth' });\n }}\n >\n {t('botlit.settings.actions.configure', 'Configure')}\n </Button>\n </div>\n </div>\n )\n )}\n </CardContent>\n </Card>\n\n {/* LLM Models List */}\n <Card>\n <CardHeader>\n <CardTitle>{t('botlit.settings.models.title', 'LLM Models')}</CardTitle>\n <CardDescription>\n {t('botlit.settings.models.description', 'Registered models across your providers')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {llmModels && llmModels.length > 0 ? (\n llmModels.map(\n (model: {\n id: string;\n name: string;\n modelId: string;\n providerId: string;\n isActive: boolean;\n contextWindow?: number;\n maxOutputTokens?: number;\n inputPricePerMToken?: number;\n outputPricePerMToken?: number;\n }) => {\n const providerName = providers?.find(\n (p: { id: string; name: string }) => p.id === model.providerId\n )?.name;\n return (\n <div\n key={model.id}\n className=\"flex items-center justify-between p-4 border border-border-subtle rounded-lg\"\n >\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 bg-purple-500/10 rounded-lg\">\n <Brain className=\"h-5 w-5 text-purple-500\" />\n </div>\n <div>\n <p className=\"font-medium\">{model.name}</p>\n <p className=\"text-sm text-text-secondary\">\n {model.modelId}\n {providerName && ` · ${providerName}`}\n </p>\n <div className=\"flex gap-3 mt-1 text-xs text-text-secondary\">\n {model.contextWindow != null && (\n <span>\n {t('botlit.settings.models.context', 'Context: {{value}}K', {\n value: (model.contextWindow / 1000).toFixed(0),\n })}\n </span>\n )}\n {model.maxOutputTokens != null && (\n <span>\n {t('botlit.settings.models.maxOut', 'Max out: {{value}}K', {\n value: (model.maxOutputTokens / 1000).toFixed(0),\n })}\n </span>\n )}\n {model.inputPricePerMToken != null && (\n <span>\n {t('botlit.settings.models.priceIn', '${{value}}/M in', {\n value: model.inputPricePerMToken,\n })}\n </span>\n )}\n {model.outputPricePerMToken != null && (\n <span>\n {t('botlit.settings.models.priceOut', '${{value}}/M out', {\n value: model.outputPricePerMToken,\n })}\n </span>\n )}\n </div>\n </div>\n </div>\n <Badge variant={model.isActive ? 'success' : 'secondary'}>\n {model.isActive\n ? t('botlit.settings.providers.active', 'Active')\n : t('botlit.settings.providers.inactive', 'Inactive')}\n </Badge>\n </div>\n );\n }\n )\n ) : (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n {t('botlit.settings.models.empty', 'No models registered yet.')}\n </p>\n )}\n </CardContent>\n </Card>\n\n <Card id=\"provider-form\">\n <CardHeader>\n <CardTitle>\n {editingProviderId\n ? t('botlit.settings.form.updateTitle', 'Update Provider')\n : t('botlit.settings.form.addTitle', 'Add Provider')}\n </CardTitle>\n <CardDescription>\n {editingProviderId\n ? t(\n 'botlit.settings.form.updateDescription',\n 'Update credentials for this provider'\n )\n : t('botlit.settings.form.addDescription', 'Configure a new LLM provider')}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label={t('botlit.settings.form.providerLabel', 'Provider')}>\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={selectedProviderType}\n onChange={(e) => setSelectedProviderType(e.target.value)}\n >\n <option value=\"openai\">OpenAI</option>\n <option value=\"anthropic\">Anthropic</option>\n <option value=\"google\">Google AI</option>\n <option value=\"azure_openai\">Azure OpenAI</option>\n <option value=\"aws_bedrock\">AWS Bedrock</option>\n <option value=\"custom\">Custom</option>\n </select>\n </FormField>\n\n {/* Credential method selector */}\n <FormField label={t('botlit.settings.form.credentialMethod', 'Credential Method')}>\n <div className=\"flex gap-3\">\n <label\n className={cn(\n 'flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1',\n credentialMethod === 'integration'\n ? 'border-primary bg-action-primary-bg/5'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n <input\n type=\"radio\"\n name=\"credentialMethod\"\n value=\"integration\"\n checked={credentialMethod === 'integration'}\n onChange={() => setCredentialMethod('integration')}\n className=\"h-4 w-4\"\n />\n <div>\n <p className=\"font-medium text-sm\">\n {t('botlit.settings.form.integrationOption', 'Connect via Integrations')}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {t(\n 'botlit.settings.form.integrationHint',\n 'Managed credentials (recommended)'\n )}\n </p>\n </div>\n </label>\n <label\n className={cn(\n 'flex items-center gap-2 px-4 py-3 border rounded-lg cursor-pointer transition-colors flex-1',\n credentialMethod === 'apikey'\n ? 'border-primary bg-action-primary-bg/5'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n <input\n type=\"radio\"\n name=\"credentialMethod\"\n value=\"apikey\"\n checked={credentialMethod === 'apikey'}\n onChange={() => setCredentialMethod('apikey')}\n className=\"h-4 w-4\"\n />\n <div>\n <p className=\"font-medium text-sm\">\n {t('botlit.settings.form.apiKeyOption', 'Enter API Key')}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {t('botlit.settings.form.apiKeyHint', 'Paste key directly (legacy)')}\n </p>\n </div>\n </label>\n </div>\n </FormField>\n\n {/* Integration connection method */}\n {credentialMethod === 'integration' && (\n <div className=\"space-y-3\">\n <div className=\"p-4 bg-bg-sunken/50 border border-border-subtle rounded-lg\">\n <div className=\"flex items-start gap-3\">\n <Link2 className=\"h-5 w-5 text-primary mt-0.5 flex-shrink-0\" />\n <div className=\"space-y-2 flex-1\">\n <p className=\"text-sm font-medium\">\n {t('botlit.settings.form.integrationTitle', 'Integration Connection')}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {t(\n 'botlit.settings.form.integrationDescription',\n 'Create a connection in the Integrations module, then paste the Connection ID here. This stores your API key securely in the Integrations vault.'\n )}\n </p>\n <div className=\"flex gap-2 mt-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n window.open('/integrations/connections', '_blank');\n }}\n >\n <ExternalLink size={14} className=\"mr-1.5\" />\n {t('botlit.settings.form.openIntegrations', 'Open Integrations')}\n </Button>\n </div>\n </div>\n </div>\n </div>\n <FormField\n label={t('botlit.settings.form.connectionIdPlaceholder', 'Connection ID')}\n >\n <Input\n placeholder={t(\n 'botlit.settings.form.connectionIdPlaceholder',\n 'Paste connection ID from Integrations...'\n )}\n value={connectionId}\n onChange={(e) => setConnectionId(e.target.value)}\n />\n </FormField>\n </div>\n )}\n\n {/* Legacy API key method */}\n {credentialMethod === 'apikey' && (\n <FormField label={t('botlit.settings.form.apiKeyLabel', 'API Key')}>\n <Input\n type=\"password\"\n placeholder={t('botlit.settings.form.apiKeyPlaceholder', 'sk-...')}\n value={apiKey}\n onChange={(e) => setApiKey(e.target.value)}\n />\n </FormField>\n )}\n\n <div className=\"flex gap-2\">\n <Button\n leftIcon={<Save size={16} />}\n isLoading={isConfiguring}\n disabled={credentialMethod === 'apikey' ? !apiKey : !connectionId}\n onClick={async () => {\n try {\n const providerName =\n selectedProviderType.charAt(0).toUpperCase() + selectedProviderType.slice(1);\n\n // `useConfigureLLMProvider` projects each payload\n // onto the fields its input type declares and adds\n // the workspace id, so only real fields go here.\n const credentials =\n credentialMethod === 'integration'\n ? undefined\n : apiKey\n ? { apiKey }\n : undefined;\n const linkedConnectionId =\n credentialMethod === 'integration' ? connectionId : undefined;\n\n if (editingProviderId) {\n await configureProvider(\n {\n name: providerName,\n type: toProviderType(selectedProviderType),\n connectionId: linkedConnectionId,\n credentials,\n },\n editingProviderId\n );\n } else {\n await configureProvider({\n name: providerName,\n type: toProviderType(selectedProviderType),\n connectionId: linkedConnectionId,\n credentials,\n });\n }\n\n setApiKey('');\n setConnectionId('');\n setEditingProviderId(null);\n await refetchProviders();\n const providerLabel =\n selectedProviderType.charAt(0).toUpperCase() + selectedProviderType.slice(1);\n toast.success(\n editingProviderId\n ? t(\n 'botlit.settings.form.updateSuccess',\n '{{provider}} provider updated successfully',\n { provider: providerLabel }\n )\n : t(\n 'botlit.settings.form.addSuccess',\n '{{provider}} provider added successfully',\n { provider: providerLabel }\n )\n );\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.settings.form.saveError', 'Failed to save provider');\n toast.error(message);\n }\n }}\n >\n {editingProviderId\n ? t('botlit.settings.form.updateProvider', 'Update Provider')\n : t('botlit.settings.form.saveProvider', 'Save Provider')}\n </Button>\n {editingProviderId && (\n <Button\n variant=\"outline\"\n onClick={() => {\n setEditingProviderId(null);\n setApiKey('');\n setConnectionId('');\n setCredentialMethod('apikey');\n setSelectedProviderType('openai');\n }}\n >\n {t('botlit.settings.form.cancel', 'Cancel')}\n </Button>\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}