@burdenoff/microfe-botmanor 2026.813.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.
- package/README.md +12 -0
- package/dist/botlit/BotlitRoutes.js +357 -0
- package/dist/botlit/BotlitRoutes.js.map +1 -0
- package/dist/botlit/BotmanorRoot.js +12 -0
- package/dist/botlit/BotmanorRoot.js.map +1 -0
- package/dist/botlit/BotmanorRootInner.js +101 -0
- package/dist/botlit/BotmanorRootInner.js.map +1 -0
- package/dist/botlit/components/Badge.js +39 -0
- package/dist/botlit/components/Badge.js.map +1 -0
- package/dist/botlit/components/Button.js +46 -0
- package/dist/botlit/components/Button.js.map +1 -0
- package/dist/botlit/components/Card.js +31 -0
- package/dist/botlit/components/Card.js.map +1 -0
- package/dist/botlit/components/ChannelSelectorSheet.js +130 -0
- package/dist/botlit/components/ChannelSelectorSheet.js.map +1 -0
- package/dist/botlit/components/EmptyState.js +35 -0
- package/dist/botlit/components/EmptyState.js.map +1 -0
- package/dist/botlit/components/ErrorState.js +33 -0
- package/dist/botlit/components/ErrorState.js.map +1 -0
- package/dist/botlit/components/Input.js +59 -0
- package/dist/botlit/components/Input.js.map +1 -0
- package/dist/botlit/components/PageLayout.js +34 -0
- package/dist/botlit/components/PageLayout.js.map +1 -0
- package/dist/botlit/components/QuotaExhaustedDialog.js +20 -0
- package/dist/botlit/components/QuotaExhaustedDialog.js.map +1 -0
- package/dist/botlit/components/RouteLoader.js +52 -0
- package/dist/botlit/components/RouteLoader.js.map +1 -0
- package/dist/botlit/components/VersionHistoryPanel.js +144 -0
- package/dist/botlit/components/VersionHistoryPanel.js.map +1 -0
- package/dist/botlit/components/WorkspaceRequired.js +70 -0
- package/dist/botlit/components/WorkspaceRequired.js.map +1 -0
- package/dist/botlit/hooks/index.js +16 -0
- package/dist/botlit/hooks/internal/mutationInput.js +16 -0
- package/dist/botlit/hooks/internal/mutationInput.js.map +1 -0
- package/dist/botlit/hooks/internal/workspaceGateway.js +99 -0
- package/dist/botlit/hooks/internal/workspaceGateway.js.map +1 -0
- package/dist/botlit/hooks/useA2A.js +184 -0
- package/dist/botlit/hooks/useA2A.js.map +1 -0
- package/dist/botlit/hooks/useAgents.js +469 -0
- package/dist/botlit/hooks/useAgents.js.map +1 -0
- package/dist/botlit/hooks/useBots.js +306 -0
- package/dist/botlit/hooks/useBots.js.map +1 -0
- package/dist/botlit/hooks/useBuckets.js +119 -0
- package/dist/botlit/hooks/useBuckets.js.map +1 -0
- package/dist/botlit/hooks/useChannels.js +213 -0
- package/dist/botlit/hooks/useChannels.js.map +1 -0
- package/dist/botlit/hooks/useConversations.js +64 -0
- package/dist/botlit/hooks/useConversations.js.map +1 -0
- package/dist/botlit/hooks/useExecutions.js +86 -0
- package/dist/botlit/hooks/useExecutions.js.map +1 -0
- package/dist/botlit/hooks/useKnowledgeBases.js +113 -0
- package/dist/botlit/hooks/useKnowledgeBases.js.map +1 -0
- package/dist/botlit/hooks/useLLMProviders.js +83 -0
- package/dist/botlit/hooks/useLLMProviders.js.map +1 -0
- package/dist/botlit/hooks/useMCPServers.js +134 -0
- package/dist/botlit/hooks/useMCPServers.js.map +1 -0
- package/dist/botlit/hooks/usePolicies.js +120 -0
- package/dist/botlit/hooks/usePolicies.js.map +1 -0
- package/dist/botlit/hooks/usePromptTemplates.js +161 -0
- package/dist/botlit/hooks/usePromptTemplates.js.map +1 -0
- package/dist/botlit/hooks/useRetrievalProfiles.js +146 -0
- package/dist/botlit/hooks/useRetrievalProfiles.js.map +1 -0
- package/dist/botlit/hooks/useSkills.js +132 -0
- package/dist/botlit/hooks/useSkills.js.map +1 -0
- package/dist/botlit/hooks/useStore.js +167 -0
- package/dist/botlit/hooks/useStore.js.map +1 -0
- package/dist/botlit/hooks/useUserPlatformConnection.js +172 -0
- package/dist/botlit/hooks/useUserPlatformConnection.js.map +1 -0
- package/dist/botlit/index.js +11 -0
- package/dist/botlit/pages/A2AAgentDetailPage.js +589 -0
- package/dist/botlit/pages/A2AAgentDetailPage.js.map +1 -0
- package/dist/botlit/pages/A2ARegistryPage.js +240 -0
- package/dist/botlit/pages/A2ARegistryPage.js.map +1 -0
- package/dist/botlit/pages/AgentBuilderPage.js +486 -0
- package/dist/botlit/pages/AgentBuilderPage.js.map +1 -0
- package/dist/botlit/pages/AgentDetailPage.js +517 -0
- package/dist/botlit/pages/AgentDetailPage.js.map +1 -0
- package/dist/botlit/pages/AgentsListPage.js +294 -0
- package/dist/botlit/pages/AgentsListPage.js.map +1 -0
- package/dist/botlit/pages/BotChannelsTab.js +530 -0
- package/dist/botlit/pages/BotChannelsTab.js.map +1 -0
- package/dist/botlit/pages/BotDetailPage.js +872 -0
- package/dist/botlit/pages/BotDetailPage.js.map +1 -0
- package/dist/botlit/pages/BotWorkflowTab.js +229 -0
- package/dist/botlit/pages/BotWorkflowTab.js.map +1 -0
- package/dist/botlit/pages/BotsListPage.js +313 -0
- package/dist/botlit/pages/BotsListPage.js.map +1 -0
- package/dist/botlit/pages/BucketsPage.js +604 -0
- package/dist/botlit/pages/BucketsPage.js.map +1 -0
- package/dist/botlit/pages/ChannelDetailPage.js +955 -0
- package/dist/botlit/pages/ChannelDetailPage.js.map +1 -0
- package/dist/botlit/pages/ChannelRoutesPage.js +218 -0
- package/dist/botlit/pages/ChannelRoutesPage.js.map +1 -0
- package/dist/botlit/pages/ChannelsPage.js +304 -0
- package/dist/botlit/pages/ChannelsPage.js.map +1 -0
- package/dist/botlit/pages/ChatPage.js +247 -0
- package/dist/botlit/pages/ChatPage.js.map +1 -0
- package/dist/botlit/pages/DashboardPage.js +318 -0
- package/dist/botlit/pages/DashboardPage.js.map +1 -0
- package/dist/botlit/pages/ExecutionDetailPage.js +313 -0
- package/dist/botlit/pages/ExecutionDetailPage.js.map +1 -0
- package/dist/botlit/pages/ExecutionsPage.js +294 -0
- package/dist/botlit/pages/ExecutionsPage.js.map +1 -0
- package/dist/botlit/pages/InstalledPackagesPage.js +619 -0
- package/dist/botlit/pages/InstalledPackagesPage.js.map +1 -0
- package/dist/botlit/pages/KnowledgeBaseDetailPage.js +473 -0
- package/dist/botlit/pages/KnowledgeBaseDetailPage.js.map +1 -0
- package/dist/botlit/pages/KnowledgeBasesPage.js +150 -0
- package/dist/botlit/pages/KnowledgeBasesPage.js.map +1 -0
- package/dist/botlit/pages/MCPServerDetailPage.js +550 -0
- package/dist/botlit/pages/MCPServerDetailPage.js.map +1 -0
- package/dist/botlit/pages/MCPServersPage.js +321 -0
- package/dist/botlit/pages/MCPServersPage.js.map +1 -0
- package/dist/botlit/pages/PoliciesPage.js +224 -0
- package/dist/botlit/pages/PoliciesPage.js.map +1 -0
- package/dist/botlit/pages/PolicyDetailPage.js +861 -0
- package/dist/botlit/pages/PolicyDetailPage.js.map +1 -0
- package/dist/botlit/pages/PromptStudioPage.js +236 -0
- package/dist/botlit/pages/PromptStudioPage.js.map +1 -0
- package/dist/botlit/pages/PromptTemplateDetailPage.js +812 -0
- package/dist/botlit/pages/PromptTemplateDetailPage.js.map +1 -0
- package/dist/botlit/pages/PromptTemplatesPage.js +269 -0
- package/dist/botlit/pages/PromptTemplatesPage.js.map +1 -0
- package/dist/botlit/pages/RetrievalProfileDetailPage.js +559 -0
- package/dist/botlit/pages/RetrievalProfileDetailPage.js.map +1 -0
- package/dist/botlit/pages/RetrievalProfilesPage.js +219 -0
- package/dist/botlit/pages/RetrievalProfilesPage.js.map +1 -0
- package/dist/botlit/pages/SettingsPage.js +655 -0
- package/dist/botlit/pages/SettingsPage.js.map +1 -0
- package/dist/botlit/pages/SkillDetailPage.js +778 -0
- package/dist/botlit/pages/SkillDetailPage.js.map +1 -0
- package/dist/botlit/pages/SkillsPage.js +206 -0
- package/dist/botlit/pages/SkillsPage.js.map +1 -0
- package/dist/botlit/pages/StorePackageDetailPage.js +462 -0
- package/dist/botlit/pages/StorePackageDetailPage.js.map +1 -0
- package/dist/botlit/pages/StorePage.js +315 -0
- package/dist/botlit/pages/StorePage.js.map +1 -0
- package/dist/botlit/providers/BotlitProvider.js +93 -0
- package/dist/botlit/providers/BotlitProvider.js.map +1 -0
- package/dist/botlit/store/botlitStore.js +101 -0
- package/dist/botlit/store/botlitStore.js.map +1 -0
- package/dist/botlit/utils/cn.js +10 -0
- package/dist/botlit/utils/cn.js.map +1 -0
- package/dist/botlit/utils/formatters.js +37 -0
- package/dist/botlit/utils/formatters.js.map +1 -0
- package/dist/botlit/utils/navigation.js +9 -0
- package/dist/botlit/utils/navigation.js.map +1 -0
- package/dist/botlit/utils/unions.js +14 -0
- package/dist/botlit/utils/unions.js.map +1 -0
- package/dist/generated/global-operations.js +66 -0
- package/dist/generated/global-operations.js.map +1 -0
- package/dist/generated/global-types.js +8 -0
- package/dist/generated/global-types.js.map +1 -0
- package/dist/generated/wspace-operations.js +1591 -0
- package/dist/generated/wspace-operations.js.map +1 -0
- package/dist/generated/wspace-types.js +12 -0
- package/dist/generated/wspace-types.js.map +1 -0
- package/dist/index.js +13 -0
- package/dist/utils/nativeBridge.js +2 -0
- package/package.json +133 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { useBotlit as e } from "../providers/BotlitProvider.js";
|
|
2
|
+
import { isMCPServerHealthy as t, mcpServerDescription as n, mcpServerEndpoint as r, useCreateMCPServer as i, useDeleteMCPServer as a, useMCPServers as o, useTestMCPConnection as s } from "../hooks/useMCPServers.js";
|
|
3
|
+
import { formatRelativeTime as c } from "../utils/formatters.js";
|
|
4
|
+
import { PageLayout as l } from "../components/PageLayout.js";
|
|
5
|
+
import { Card as u, CardContent as d, CardDescription as f, CardHeader as p, CardTitle as m } from "../components/Card.js";
|
|
6
|
+
import { Button as h } from "../components/Button.js";
|
|
7
|
+
import { Badge as g, StatusBadge as _ } from "../components/Badge.js";
|
|
8
|
+
import { EmptyState as v } from "../components/EmptyState.js";
|
|
9
|
+
import { FormField as y, Input as b } from "../components/Input.js";
|
|
10
|
+
import { ErrorState as x } from "../components/ErrorState.js";
|
|
11
|
+
import { useState as S } from "react";
|
|
12
|
+
import { GlassCard as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
14
|
+
import { Plug as D, PlugZap as O, Plus as k, Settings as A, Trash2 as j } from "lucide-react";
|
|
15
|
+
import { toast as M } from "sonner";
|
|
16
|
+
//#region src/botlit/pages/MCPServersPage.tsx
|
|
17
|
+
var N = () => {
|
|
18
|
+
let { navigateTo: N } = e(), { data: P, loading: F, error: I, refetch: L } = o(), [R, z] = i(), [B, V] = a(), [H, U] = s(), [W, G] = S(!1), [K, q] = S({
|
|
19
|
+
name: "",
|
|
20
|
+
description: "",
|
|
21
|
+
transport: "HTTP_JSON",
|
|
22
|
+
baseUrl: ""
|
|
23
|
+
}), J = async () => {
|
|
24
|
+
if (!(!K.name || !K.baseUrl)) {
|
|
25
|
+
try {
|
|
26
|
+
await R({
|
|
27
|
+
name: K.name,
|
|
28
|
+
type: K.transport,
|
|
29
|
+
config: {
|
|
30
|
+
url: K.baseUrl,
|
|
31
|
+
description: K.description
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
} catch (e) {
|
|
35
|
+
M.error(e instanceof Error ? e.message : "Failed to connect MCP server");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
M.success(`Connected "${K.name}"`), L(), q({
|
|
39
|
+
name: "",
|
|
40
|
+
description: "",
|
|
41
|
+
transport: "HTTP_JSON",
|
|
42
|
+
baseUrl: ""
|
|
43
|
+
}), G(!1);
|
|
44
|
+
}
|
|
45
|
+
}, Y = async (e) => {
|
|
46
|
+
try {
|
|
47
|
+
await B(e.id), M.success(`Disconnected "${e.name}"`), L();
|
|
48
|
+
} catch (e) {
|
|
49
|
+
M.error(e instanceof Error ? e.message : "Failed to disconnect MCP server");
|
|
50
|
+
}
|
|
51
|
+
}, X = async (e) => {
|
|
52
|
+
try {
|
|
53
|
+
await H(e.id) ? M.success(`"${e.name}" is reachable`) : M.error(`"${e.name}" did not respond`), L();
|
|
54
|
+
} catch (e) {
|
|
55
|
+
M.error(e instanceof Error ? e.message : "Failed to test MCP connection");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return /* @__PURE__ */ T(l, {
|
|
59
|
+
title: "MCP Servers",
|
|
60
|
+
description: "Connect Model Context Protocol servers to extend agent capabilities",
|
|
61
|
+
actions: /* @__PURE__ */ T(h, {
|
|
62
|
+
leftIcon: /* @__PURE__ */ T(k, { size: 16 }),
|
|
63
|
+
onClick: () => G(!0),
|
|
64
|
+
children: "Add MCP Server"
|
|
65
|
+
}),
|
|
66
|
+
children: /* @__PURE__ */ E("div", {
|
|
67
|
+
className: "space-y-6",
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ T(w, {
|
|
70
|
+
icon: /* @__PURE__ */ T(D, { size: 18 }),
|
|
71
|
+
children: "MCP (Model Context Protocol) servers are how your agents reach the outside world — they expose real tools an agent can call, like searching the web, reading a GitHub repo, querying a database or posting to Slack. Connect a server here and its tools become available to your agents (gated by your tool policies), turning a chatbot into something that can take action."
|
|
72
|
+
}),
|
|
73
|
+
F ? /* @__PURE__ */ T("div", {
|
|
74
|
+
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
75
|
+
children: [
|
|
76
|
+
1,
|
|
77
|
+
2,
|
|
78
|
+
3
|
|
79
|
+
].map((e) => /* @__PURE__ */ T("div", { className: "h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
|
|
80
|
+
}) : I ? /* @__PURE__ */ T(x, {
|
|
81
|
+
resource: "MCP servers",
|
|
82
|
+
error: I,
|
|
83
|
+
onRetry: () => void L()
|
|
84
|
+
}) : P.length > 0 ? /* @__PURE__ */ T("div", {
|
|
85
|
+
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
86
|
+
children: P.map((e) => /* @__PURE__ */ E(u, { children: [/* @__PURE__ */ E(p, {
|
|
87
|
+
className: "flex flex-row items-start justify-between",
|
|
88
|
+
children: [/* @__PURE__ */ E("div", {
|
|
89
|
+
className: "flex items-start gap-3",
|
|
90
|
+
children: [/* @__PURE__ */ T("div", {
|
|
91
|
+
className: `p-2 rounded-lg ${t(e.status) ? "bg-status-success-bg-subtle" : "bg-bg-sunken"}`,
|
|
92
|
+
children: t(e.status) ? /* @__PURE__ */ T(O, { className: "h-5 w-5 text-status-success-text" }) : /* @__PURE__ */ T(D, { className: "h-5 w-5 text-text-secondary" })
|
|
93
|
+
}), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T(m, {
|
|
94
|
+
className: "text-base",
|
|
95
|
+
children: e.name
|
|
96
|
+
}), /* @__PURE__ */ T(f, { children: n(e) })] })]
|
|
97
|
+
}), /* @__PURE__ */ T(_, { status: e.status })]
|
|
98
|
+
}), /* @__PURE__ */ T(d, { children: /* @__PURE__ */ E("div", {
|
|
99
|
+
className: "space-y-4",
|
|
100
|
+
children: [
|
|
101
|
+
/* @__PURE__ */ E("div", {
|
|
102
|
+
className: "flex flex-wrap items-center gap-4 text-sm",
|
|
103
|
+
children: [/* @__PURE__ */ T(g, {
|
|
104
|
+
variant: "outline",
|
|
105
|
+
className: "capitalize",
|
|
106
|
+
children: e.type.toLowerCase().replace("_", " ")
|
|
107
|
+
}), e.lastConnectedAt && /* @__PURE__ */ E("span", {
|
|
108
|
+
className: "text-text-secondary",
|
|
109
|
+
children: ["Last connected ", c(e.lastConnectedAt)]
|
|
110
|
+
})]
|
|
111
|
+
}),
|
|
112
|
+
r(e) && /* @__PURE__ */ T("p", {
|
|
113
|
+
className: "truncate text-sm text-text-secondary",
|
|
114
|
+
children: r(e)
|
|
115
|
+
}),
|
|
116
|
+
e.errorMessage && /* @__PURE__ */ T("p", {
|
|
117
|
+
className: "text-sm text-status-error-text",
|
|
118
|
+
children: e.errorMessage
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ E("div", {
|
|
121
|
+
className: "flex items-center gap-2 pt-2 border-t border-border-subtle",
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ T(h, {
|
|
124
|
+
variant: "outline",
|
|
125
|
+
size: "sm",
|
|
126
|
+
onClick: () => void X(e),
|
|
127
|
+
isLoading: U.loading,
|
|
128
|
+
children: "Test connection"
|
|
129
|
+
}),
|
|
130
|
+
/* @__PURE__ */ T(h, {
|
|
131
|
+
variant: "ghost",
|
|
132
|
+
size: "sm",
|
|
133
|
+
leftIcon: /* @__PURE__ */ T(A, { size: 14 }),
|
|
134
|
+
onClick: () => N(`mcp/${e.id}`),
|
|
135
|
+
children: "Configure"
|
|
136
|
+
}),
|
|
137
|
+
/* @__PURE__ */ T(h, {
|
|
138
|
+
variant: "ghost",
|
|
139
|
+
size: "icon",
|
|
140
|
+
className: "ml-auto",
|
|
141
|
+
"aria-label": `Disconnect ${e.name}`,
|
|
142
|
+
onClick: () => void Y(e),
|
|
143
|
+
isLoading: V.loading,
|
|
144
|
+
children: /* @__PURE__ */ T(j, { size: 16 })
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
})
|
|
148
|
+
]
|
|
149
|
+
}) })] }, e.id))
|
|
150
|
+
}) : /* @__PURE__ */ T(v, {
|
|
151
|
+
illustration: "empty-generic",
|
|
152
|
+
title: "No MCP servers connected",
|
|
153
|
+
description: "Connect MCP servers to give your agents access to external tools and resources.",
|
|
154
|
+
action: /* @__PURE__ */ T(h, {
|
|
155
|
+
leftIcon: /* @__PURE__ */ T(k, { size: 16 }),
|
|
156
|
+
onClick: () => G(!0),
|
|
157
|
+
children: "Add MCP Server"
|
|
158
|
+
})
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ E(C, {
|
|
161
|
+
treatment: "glass",
|
|
162
|
+
glow: !0,
|
|
163
|
+
className: "p-6",
|
|
164
|
+
children: [/* @__PURE__ */ E("div", {
|
|
165
|
+
className: "mb-4",
|
|
166
|
+
children: [/* @__PURE__ */ T("h2", {
|
|
167
|
+
className: "text-lg font-semibold tracking-tight text-text-primary",
|
|
168
|
+
children: "Popular MCP Servers"
|
|
169
|
+
}), /* @__PURE__ */ T("p", {
|
|
170
|
+
className: "text-sm text-text-secondary",
|
|
171
|
+
children: "Quick-add common MCP servers"
|
|
172
|
+
})]
|
|
173
|
+
}), /* @__PURE__ */ T("div", {
|
|
174
|
+
className: "grid grid-cols-1 md:grid-cols-3 gap-4",
|
|
175
|
+
children: [
|
|
176
|
+
{
|
|
177
|
+
name: "GitHub",
|
|
178
|
+
description: "Repository management and code operations",
|
|
179
|
+
baseUrl: "https://mcp.github.com"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: "Filesystem",
|
|
183
|
+
description: "Local file system access",
|
|
184
|
+
baseUrl: "http://localhost:3001"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: "Brave Search",
|
|
188
|
+
description: "Web search capabilities",
|
|
189
|
+
baseUrl: "https://mcp.search.brave.com"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "PostgreSQL",
|
|
193
|
+
description: "Database queries and management",
|
|
194
|
+
baseUrl: "http://localhost:3002"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "Slack",
|
|
198
|
+
description: "Slack messaging integration",
|
|
199
|
+
baseUrl: "https://mcp.slack.com"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: "Puppeteer",
|
|
203
|
+
description: "Browser automation",
|
|
204
|
+
baseUrl: "http://localhost:3003"
|
|
205
|
+
}
|
|
206
|
+
].map((e) => /* @__PURE__ */ E("button", {
|
|
207
|
+
className: "p-4 text-left border border-border-subtle rounded-lg hover:bg-accent transition-colors",
|
|
208
|
+
onClick: () => {
|
|
209
|
+
q({
|
|
210
|
+
name: e.name,
|
|
211
|
+
description: e.description,
|
|
212
|
+
transport: "HTTP_JSON",
|
|
213
|
+
baseUrl: e.baseUrl
|
|
214
|
+
}), G(!0);
|
|
215
|
+
},
|
|
216
|
+
children: [/* @__PURE__ */ T("p", {
|
|
217
|
+
className: "font-medium",
|
|
218
|
+
children: e.name
|
|
219
|
+
}), /* @__PURE__ */ T("p", {
|
|
220
|
+
className: "text-sm text-text-secondary mt-1",
|
|
221
|
+
children: e.description
|
|
222
|
+
})]
|
|
223
|
+
}, e.name))
|
|
224
|
+
})]
|
|
225
|
+
}),
|
|
226
|
+
W && /* @__PURE__ */ T("div", {
|
|
227
|
+
className: "fixed inset-0 bg-black/50 flex items-center justify-center z-50",
|
|
228
|
+
children: /* @__PURE__ */ E(u, {
|
|
229
|
+
className: "w-full max-w-lg",
|
|
230
|
+
children: [/* @__PURE__ */ E(p, { children: [/* @__PURE__ */ T(m, { children: "Add MCP Server" }), /* @__PURE__ */ T(f, { children: "Connect a new MCP server" })] }), /* @__PURE__ */ E(d, {
|
|
231
|
+
className: "space-y-4",
|
|
232
|
+
children: [
|
|
233
|
+
/* @__PURE__ */ T(y, {
|
|
234
|
+
label: "Server Name",
|
|
235
|
+
required: !0,
|
|
236
|
+
children: /* @__PURE__ */ T(b, {
|
|
237
|
+
placeholder: "e.g., GitHub",
|
|
238
|
+
value: K.name,
|
|
239
|
+
onChange: (e) => q({
|
|
240
|
+
...K,
|
|
241
|
+
name: e.target.value
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
}),
|
|
245
|
+
/* @__PURE__ */ T(y, {
|
|
246
|
+
label: "Description",
|
|
247
|
+
children: /* @__PURE__ */ T(b, {
|
|
248
|
+
placeholder: "What does this server do?",
|
|
249
|
+
value: K.description,
|
|
250
|
+
onChange: (e) => q({
|
|
251
|
+
...K,
|
|
252
|
+
description: e.target.value
|
|
253
|
+
})
|
|
254
|
+
})
|
|
255
|
+
}),
|
|
256
|
+
/* @__PURE__ */ T(y, {
|
|
257
|
+
label: "Transport",
|
|
258
|
+
children: /* @__PURE__ */ E("select", {
|
|
259
|
+
className: "flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm",
|
|
260
|
+
value: K.transport,
|
|
261
|
+
onChange: (e) => q({
|
|
262
|
+
...K,
|
|
263
|
+
transport: e.target.value
|
|
264
|
+
}),
|
|
265
|
+
children: [
|
|
266
|
+
/* @__PURE__ */ T("option", {
|
|
267
|
+
value: "HTTP_JSON",
|
|
268
|
+
children: "HTTP JSON"
|
|
269
|
+
}),
|
|
270
|
+
/* @__PURE__ */ T("option", {
|
|
271
|
+
value: "JSON_RPC",
|
|
272
|
+
children: "JSON RPC"
|
|
273
|
+
}),
|
|
274
|
+
/* @__PURE__ */ T("option", {
|
|
275
|
+
value: "SSE",
|
|
276
|
+
children: "Server-Sent Events"
|
|
277
|
+
}),
|
|
278
|
+
/* @__PURE__ */ T("option", {
|
|
279
|
+
value: "CUSTOM",
|
|
280
|
+
children: "Custom"
|
|
281
|
+
})
|
|
282
|
+
]
|
|
283
|
+
})
|
|
284
|
+
}),
|
|
285
|
+
/* @__PURE__ */ T(y, {
|
|
286
|
+
label: "Base URL",
|
|
287
|
+
required: !0,
|
|
288
|
+
children: /* @__PURE__ */ T(b, {
|
|
289
|
+
placeholder: "e.g., https://mcp.example.com",
|
|
290
|
+
value: K.baseUrl,
|
|
291
|
+
onChange: (e) => q({
|
|
292
|
+
...K,
|
|
293
|
+
baseUrl: e.target.value
|
|
294
|
+
})
|
|
295
|
+
})
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ E("div", {
|
|
298
|
+
className: "flex justify-end gap-2 pt-4",
|
|
299
|
+
children: [/* @__PURE__ */ T(h, {
|
|
300
|
+
variant: "outline",
|
|
301
|
+
onClick: () => G(!1),
|
|
302
|
+
children: "Cancel"
|
|
303
|
+
}), /* @__PURE__ */ T(h, {
|
|
304
|
+
onClick: J,
|
|
305
|
+
isLoading: z.loading,
|
|
306
|
+
disabled: !K.name || !K.baseUrl,
|
|
307
|
+
children: "Connect"
|
|
308
|
+
})]
|
|
309
|
+
})
|
|
310
|
+
]
|
|
311
|
+
})]
|
|
312
|
+
})
|
|
313
|
+
})
|
|
314
|
+
]
|
|
315
|
+
})
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
//#endregion
|
|
319
|
+
export { N as MCPServersPage };
|
|
320
|
+
|
|
321
|
+
//# sourceMappingURL=MCPServersPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MCPServersPage.js","names":[],"sources":["../../../src/botlit/pages/MCPServersPage.tsx"],"sourcesContent":["/**\n * MCP Servers Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { Plus, Plug, PlugZap, Settings, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, FormField } from '../components/Input';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport {\n useMCPServers,\n useCreateMCPServer,\n useDeleteMCPServer,\n useTestMCPConnection,\n isMCPServerHealthy,\n mcpServerDescription,\n mcpServerEndpoint,\n type MCPServerRecord,\n} from '../hooks/useMCPServers';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { MCPTransport } from '../types';\n\nexport const MCPServersPage: FC = () => {\n const { navigateTo } = useBotlit();\n const { data: servers, loading, error, refetch } = useMCPServers();\n const [connectServer, connectResult] = useCreateMCPServer();\n const [deleteServer, deleteResult] = useDeleteMCPServer();\n const [testConnection, testResult] = useTestMCPConnection();\n const [showAddModal, setShowAddModal] = useState(false);\n const [newServer, setNewServer] = useState({\n name: '',\n description: '',\n transport: 'HTTP_JSON' as MCPTransport,\n baseUrl: '',\n });\n\n const handleConnect = async () => {\n if (!newServer.name || !newServer.baseUrl) return;\n\n try {\n await connectServer({\n name: newServer.name,\n type: newServer.transport,\n config: {\n url: newServer.baseUrl,\n description: newServer.description,\n },\n });\n } catch (err) {\n // Keep the dialog open so the operator can correct and retry — closing it\n // here is what made failed writes look like successes.\n toast.error(err instanceof Error ? err.message : 'Failed to connect MCP server');\n return;\n }\n\n toast.success(`Connected \"${newServer.name}\"`);\n void refetch();\n setNewServer({ name: '', description: '', transport: 'HTTP_JSON', baseUrl: '' });\n setShowAddModal(false);\n };\n\n const handleDisconnect = async (server: MCPServerRecord) => {\n try {\n await deleteServer(server.id);\n toast.success(`Disconnected \"${server.name}\"`);\n void refetch();\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to disconnect MCP server');\n }\n };\n\n const handleTest = async (server: MCPServerRecord) => {\n try {\n const ok = await testConnection(server.id);\n if (ok) {\n toast.success(`\"${server.name}\" is reachable`);\n } else {\n toast.error(`\"${server.name}\" did not respond`);\n }\n void refetch();\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to test MCP connection');\n }\n };\n\n return (\n <PageLayout\n title=\"MCP Servers\"\n description=\"Connect Model Context Protocol servers to extend agent capabilities\"\n actions={\n <Button leftIcon={<Plus size={16} />} onClick={() => setShowAddModal(true)}>\n Add MCP Server\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Plug size={18} />}>\n MCP (Model Context Protocol) servers are how your agents reach the outside world — they\n expose real tools an agent can call, like searching the web, reading a GitHub repo,\n querying a database or posting to Slack. Connect a server here and its tools become\n available to your agents (gated by your tool policies), turning a chatbot into something\n that can take action.\n </PagePurpose>\n\n {/* Server List */}\n {loading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState resource=\"MCP servers\" error={error} onRetry={() => void refetch()} />\n ) : servers.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {servers.map((server: MCPServerRecord) => (\n <Card key={server.id}>\n <CardHeader className=\"flex flex-row items-start justify-between\">\n <div className=\"flex items-start gap-3\">\n <div\n className={`p-2 rounded-lg ${\n isMCPServerHealthy(server.status)\n ? 'bg-status-success-bg-subtle'\n : 'bg-bg-sunken'\n }`}\n >\n {isMCPServerHealthy(server.status) ? (\n <PlugZap className=\"h-5 w-5 text-status-success-text\" />\n ) : (\n <Plug className=\"h-5 w-5 text-text-secondary\" />\n )}\n </div>\n <div>\n <CardTitle className=\"text-base\">{server.name}</CardTitle>\n <CardDescription>{mcpServerDescription(server)}</CardDescription>\n </div>\n </div>\n <StatusBadge status={server.status} />\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {/* Transport Info */}\n <div className=\"flex flex-wrap items-center gap-4 text-sm\">\n <Badge variant=\"outline\" className=\"capitalize\">\n {server.type.toLowerCase().replace('_', ' ')}\n </Badge>\n {server.lastConnectedAt && (\n <span className=\"text-text-secondary\">\n Last connected {formatRelativeTime(server.lastConnectedAt)}\n </span>\n )}\n </div>\n\n {/* Endpoint */}\n {mcpServerEndpoint(server) && (\n <p className=\"truncate text-sm text-text-secondary\">\n {mcpServerEndpoint(server)}\n </p>\n )}\n\n {server.errorMessage && (\n <p className=\"text-sm text-status-error-text\">{server.errorMessage}</p>\n )}\n\n {/* Actions */}\n <div className=\"flex items-center gap-2 pt-2 border-t border-border-subtle\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void handleTest(server)}\n isLoading={testResult.loading}\n >\n Test connection\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n leftIcon={<Settings size={14} />}\n onClick={() => navigateTo(`mcp/${server.id}`)}\n >\n Configure\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"ml-auto\"\n aria-label={`Disconnect ${server.name}`}\n onClick={() => void handleDisconnect(server)}\n isLoading={deleteResult.loading}\n >\n <Trash2 size={16} />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No MCP servers connected\"\n description=\"Connect MCP servers to give your agents access to external tools and resources.\"\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => setShowAddModal(true)}>\n Add MCP Server\n </Button>\n }\n />\n )}\n\n {/* Available MCP Servers */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n Popular MCP Servers\n </h2>\n <p className=\"text-sm text-text-secondary\">Quick-add common MCP servers</p>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n {[\n {\n name: 'GitHub',\n description: 'Repository management and code operations',\n baseUrl: 'https://mcp.github.com',\n },\n {\n name: 'Filesystem',\n description: 'Local file system access',\n baseUrl: 'http://localhost:3001',\n },\n {\n name: 'Brave Search',\n description: 'Web search capabilities',\n baseUrl: 'https://mcp.search.brave.com',\n },\n {\n name: 'PostgreSQL',\n description: 'Database queries and management',\n baseUrl: 'http://localhost:3002',\n },\n {\n name: 'Slack',\n description: 'Slack messaging integration',\n baseUrl: 'https://mcp.slack.com',\n },\n {\n name: 'Puppeteer',\n description: 'Browser automation',\n baseUrl: 'http://localhost:3003',\n },\n ].map((preset) => (\n <button\n key={preset.name}\n className=\"p-4 text-left border border-border-subtle rounded-lg hover:bg-accent transition-colors\"\n onClick={() => {\n setNewServer({\n name: preset.name,\n description: preset.description,\n transport: 'HTTP_JSON',\n baseUrl: preset.baseUrl,\n });\n setShowAddModal(true);\n }}\n >\n <p className=\"font-medium\">{preset.name}</p>\n <p className=\"text-sm text-text-secondary mt-1\">{preset.description}</p>\n </button>\n ))}\n </div>\n </GlassCard>\n\n {/* Add Server Modal */}\n {showAddModal && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-lg\">\n <CardHeader>\n <CardTitle>Add MCP Server</CardTitle>\n <CardDescription>Connect a new MCP server</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Server Name\" required>\n <Input\n placeholder=\"e.g., GitHub\"\n value={newServer.name}\n onChange={(e) => setNewServer({ ...newServer, name: e.target.value })}\n />\n </FormField>\n <FormField label=\"Description\">\n <Input\n placeholder=\"What does this server do?\"\n value={newServer.description}\n onChange={(e) => setNewServer({ ...newServer, description: e.target.value })}\n />\n </FormField>\n <FormField label=\"Transport\">\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={newServer.transport}\n onChange={(e) =>\n setNewServer({ ...newServer, transport: e.target.value as MCPTransport })\n }\n >\n <option value=\"HTTP_JSON\">HTTP JSON</option>\n <option value=\"JSON_RPC\">JSON RPC</option>\n <option value=\"SSE\">Server-Sent Events</option>\n <option value=\"CUSTOM\">Custom</option>\n </select>\n </FormField>\n <FormField label=\"Base URL\" required>\n <Input\n placeholder=\"e.g., https://mcp.example.com\"\n value={newServer.baseUrl}\n onChange={(e) => setNewServer({ ...newServer, baseUrl: e.target.value })}\n />\n </FormField>\n <div className=\"flex justify-end gap-2 pt-4\">\n <Button variant=\"outline\" onClick={() => setShowAddModal(false)}>\n Cancel\n </Button>\n <Button\n onClick={handleConnect}\n isLoading={connectResult.loading}\n disabled={!newServer.name || !newServer.baseUrl}\n >\n Connect\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { useBotlit as e } from "../providers/BotlitProvider.js";
|
|
2
|
+
import { formatRelativeTime as t } from "../utils/formatters.js";
|
|
3
|
+
import { PageLayout as n } from "../components/PageLayout.js";
|
|
4
|
+
import { Card as r, CardContent as i, CardHeader as a, CardTitle as o } from "../components/Card.js";
|
|
5
|
+
import { Button as s } from "../components/Button.js";
|
|
6
|
+
import { Badge as c, StatusBadge as l } from "../components/Badge.js";
|
|
7
|
+
import { EmptyState as u } from "../components/EmptyState.js";
|
|
8
|
+
import { Input as d } from "../components/Input.js";
|
|
9
|
+
import { ErrorState as f } from "../components/ErrorState.js";
|
|
10
|
+
import { usePolicies as p } from "../hooks/usePolicies.js";
|
|
11
|
+
import "../hooks/index.js";
|
|
12
|
+
import { useState as m } from "react";
|
|
13
|
+
import { GlassCard as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
15
|
+
import { Link as y } from "react-router";
|
|
16
|
+
import { AlertTriangle as b, Clock as x, Database as S, DollarSign as C, Filter as w, MessageSquare as T, Plus as E, Search as D, Shield as O, Trash2 as k, Wrench as A } from "lucide-react";
|
|
17
|
+
//#region src/botlit/pages/PoliciesPage.tsx
|
|
18
|
+
var j = ({ type: e, className: t }) => {
|
|
19
|
+
switch (e) {
|
|
20
|
+
case "CONTENT": return /* @__PURE__ */ _(b, { className: t });
|
|
21
|
+
case "TOOL": return /* @__PURE__ */ _(A, { className: t });
|
|
22
|
+
case "DATA": return /* @__PURE__ */ _(S, { className: t });
|
|
23
|
+
case "RESPONSE": return /* @__PURE__ */ _(T, { className: t });
|
|
24
|
+
case "BUDGET": return /* @__PURE__ */ _(C, { className: t });
|
|
25
|
+
case "RATE_LIMIT": return /* @__PURE__ */ _(x, { className: t });
|
|
26
|
+
case "RETENTION": return /* @__PURE__ */ _(k, { className: t });
|
|
27
|
+
default: return /* @__PURE__ */ _(O, { className: t });
|
|
28
|
+
}
|
|
29
|
+
}, M = {
|
|
30
|
+
CONTENT: "Content Safety",
|
|
31
|
+
TOOL: "Tool Access",
|
|
32
|
+
DATA: "Data Access",
|
|
33
|
+
RESPONSE: "Response Format",
|
|
34
|
+
BUDGET: "Budget Limits",
|
|
35
|
+
RATE_LIMIT: "Rate Limiting",
|
|
36
|
+
RETENTION: "Data Retention"
|
|
37
|
+
}, N = () => {
|
|
38
|
+
let { getPath: b } = e(), [x, S] = m(""), [C, T] = m(null), { data: k, loading: A, error: N, refetch: P } = p({ search: x }), F = C ? k.filter((e) => e.type === C) : k;
|
|
39
|
+
return /* @__PURE__ */ _(n, {
|
|
40
|
+
title: "Policies & Guardrails",
|
|
41
|
+
description: "Configure safety rules, access controls, and operational limits",
|
|
42
|
+
actions: /* @__PURE__ */ _(s, {
|
|
43
|
+
leftIcon: /* @__PURE__ */ _(E, { size: 16 }),
|
|
44
|
+
children: /* @__PURE__ */ _(y, {
|
|
45
|
+
to: b("policies/new"),
|
|
46
|
+
children: "Create Policy"
|
|
47
|
+
})
|
|
48
|
+
}),
|
|
49
|
+
children: /* @__PURE__ */ v("div", {
|
|
50
|
+
className: "space-y-6",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ _(g, {
|
|
53
|
+
icon: /* @__PURE__ */ _(O, { size: 18 }),
|
|
54
|
+
children: "Policies are the guardrails that keep your agents safe and within budget. Each policy enforces one kind of rule — blocking harmful content or PII, restricting which tools an agent may call, capping token spend, or rate-limiting requests. Define policies here and attach them to agents so every execution stays compliant and predictable."
|
|
55
|
+
}),
|
|
56
|
+
/* @__PURE__ */ v("div", {
|
|
57
|
+
className: "flex flex-wrap gap-2",
|
|
58
|
+
children: [/* @__PURE__ */ _(s, {
|
|
59
|
+
variant: C === null ? "default" : "outline",
|
|
60
|
+
size: "sm",
|
|
61
|
+
onClick: () => T(null),
|
|
62
|
+
children: "All"
|
|
63
|
+
}), [
|
|
64
|
+
"CONTENT",
|
|
65
|
+
"TOOL",
|
|
66
|
+
"DATA",
|
|
67
|
+
"RESPONSE",
|
|
68
|
+
"BUDGET",
|
|
69
|
+
"RATE_LIMIT",
|
|
70
|
+
"RETENTION"
|
|
71
|
+
].map((e) => /* @__PURE__ */ _(s, {
|
|
72
|
+
variant: C === e ? "default" : "outline",
|
|
73
|
+
size: "sm",
|
|
74
|
+
onClick: () => T(e),
|
|
75
|
+
leftIcon: /* @__PURE__ */ _(j, {
|
|
76
|
+
type: e,
|
|
77
|
+
className: "h-4 w-4"
|
|
78
|
+
}),
|
|
79
|
+
children: M[e]
|
|
80
|
+
}, e))]
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ v("div", {
|
|
83
|
+
className: "flex items-center gap-4",
|
|
84
|
+
children: [/* @__PURE__ */ v("div", {
|
|
85
|
+
className: "relative flex-1 max-w-md",
|
|
86
|
+
children: [/* @__PURE__ */ _(D, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ _(d, {
|
|
87
|
+
placeholder: "Search policies...",
|
|
88
|
+
value: x,
|
|
89
|
+
onChange: (e) => S(e.target.value),
|
|
90
|
+
className: "pl-9"
|
|
91
|
+
})]
|
|
92
|
+
}), /* @__PURE__ */ _(s, {
|
|
93
|
+
variant: "outline",
|
|
94
|
+
leftIcon: /* @__PURE__ */ _(w, { size: 16 }),
|
|
95
|
+
children: "More Filters"
|
|
96
|
+
})]
|
|
97
|
+
}),
|
|
98
|
+
A ? /* @__PURE__ */ _("div", {
|
|
99
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
100
|
+
children: [
|
|
101
|
+
1,
|
|
102
|
+
2,
|
|
103
|
+
3,
|
|
104
|
+
4,
|
|
105
|
+
5,
|
|
106
|
+
6
|
|
107
|
+
].map((e) => /* @__PURE__ */ _("div", { className: "h-40 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
|
|
108
|
+
}) : N ? /* @__PURE__ */ _(f, {
|
|
109
|
+
resource: "policies",
|
|
110
|
+
error: N,
|
|
111
|
+
onRetry: () => void P()
|
|
112
|
+
}) : F.length > 0 ? /* @__PURE__ */ _("div", {
|
|
113
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
114
|
+
children: F.map((e) => /* @__PURE__ */ _(y, {
|
|
115
|
+
to: b(`policies/${e.id}`),
|
|
116
|
+
children: /* @__PURE__ */ v(r, {
|
|
117
|
+
className: "h-full hover:border-primary/50 transition-colors cursor-pointer",
|
|
118
|
+
children: [/* @__PURE__ */ _(a, {
|
|
119
|
+
className: "pb-2",
|
|
120
|
+
children: /* @__PURE__ */ v("div", {
|
|
121
|
+
className: "flex items-start justify-between",
|
|
122
|
+
children: [/* @__PURE__ */ v("div", {
|
|
123
|
+
className: "flex items-center gap-3",
|
|
124
|
+
children: [/* @__PURE__ */ _("div", {
|
|
125
|
+
className: `p-2 rounded-lg ${e.type === "CONTENT" ? "bg-status-error-bg-subtle" : e.type === "TOOL" ? "bg-status-info-bg-subtle" : e.type === "BUDGET" ? "bg-status-warning-bg-subtle" : "bg-action-primary-bg/10"}`,
|
|
126
|
+
children: /* @__PURE__ */ _(j, {
|
|
127
|
+
type: e.type,
|
|
128
|
+
className: `h-5 w-5 ${e.type === "CONTENT" ? "text-status-error-text" : e.type === "TOOL" ? "text-status-info-text" : e.type === "BUDGET" ? "text-status-warning-text" : "text-primary"}`
|
|
129
|
+
})
|
|
130
|
+
}), /* @__PURE__ */ _("div", { children: /* @__PURE__ */ _(o, {
|
|
131
|
+
className: "text-base",
|
|
132
|
+
children: e.name
|
|
133
|
+
}) })]
|
|
134
|
+
}), /* @__PURE__ */ _(l, { status: e.status })]
|
|
135
|
+
})
|
|
136
|
+
}), /* @__PURE__ */ _(i, { children: /* @__PURE__ */ v("div", {
|
|
137
|
+
className: "space-y-3",
|
|
138
|
+
children: [/* @__PURE__ */ _("p", {
|
|
139
|
+
className: "text-sm text-text-secondary line-clamp-2",
|
|
140
|
+
children: e.description
|
|
141
|
+
}), /* @__PURE__ */ v("div", {
|
|
142
|
+
className: "flex items-center justify-between",
|
|
143
|
+
children: [/* @__PURE__ */ _(c, {
|
|
144
|
+
variant: "outline",
|
|
145
|
+
className: "text-xs",
|
|
146
|
+
children: M[e.type]
|
|
147
|
+
}), /* @__PURE__ */ _("span", {
|
|
148
|
+
className: "text-xs text-text-secondary",
|
|
149
|
+
children: t(e.createdAt)
|
|
150
|
+
})]
|
|
151
|
+
})]
|
|
152
|
+
}) })]
|
|
153
|
+
})
|
|
154
|
+
}, e.id))
|
|
155
|
+
}) : /* @__PURE__ */ _(u, {
|
|
156
|
+
illustration: "empty-generic",
|
|
157
|
+
title: C ? `No ${M[C]} policies` : "No policies",
|
|
158
|
+
description: "Create policies to enforce safety rules and operational limits across your agents.",
|
|
159
|
+
action: /* @__PURE__ */ _(s, {
|
|
160
|
+
leftIcon: /* @__PURE__ */ _(E, { size: 16 }),
|
|
161
|
+
children: /* @__PURE__ */ _(y, {
|
|
162
|
+
to: b("policies/new"),
|
|
163
|
+
children: "Create Policy"
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ v(h, {
|
|
168
|
+
treatment: "glass",
|
|
169
|
+
glow: !0,
|
|
170
|
+
className: "p-6",
|
|
171
|
+
children: [/* @__PURE__ */ v("div", {
|
|
172
|
+
className: "mb-4",
|
|
173
|
+
children: [/* @__PURE__ */ _("h2", {
|
|
174
|
+
className: "text-lg font-semibold tracking-tight text-text-primary",
|
|
175
|
+
children: "Policy Types"
|
|
176
|
+
}), /* @__PURE__ */ _("p", {
|
|
177
|
+
className: "text-sm text-text-secondary",
|
|
178
|
+
children: "Different policy types control different aspects of agent behavior"
|
|
179
|
+
})]
|
|
180
|
+
}), /* @__PURE__ */ _("div", {
|
|
181
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4",
|
|
182
|
+
children: [
|
|
183
|
+
{
|
|
184
|
+
type: "CONTENT",
|
|
185
|
+
desc: "Detect and block harmful content, jailbreaks, and PII"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
type: "TOOL",
|
|
189
|
+
desc: "Control which tools agents can access and use"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
type: "BUDGET",
|
|
193
|
+
desc: "Set token limits and cost caps per execution"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
type: "RATE_LIMIT",
|
|
197
|
+
desc: "Limit request frequency to prevent abuse"
|
|
198
|
+
}
|
|
199
|
+
].map((e) => /* @__PURE__ */ v("div", {
|
|
200
|
+
className: "p-4 border border-border-subtle rounded-lg",
|
|
201
|
+
children: [/* @__PURE__ */ v("div", {
|
|
202
|
+
className: "flex items-center gap-2 mb-2",
|
|
203
|
+
children: [/* @__PURE__ */ _(j, {
|
|
204
|
+
type: e.type,
|
|
205
|
+
className: "h-5 w-5 text-primary"
|
|
206
|
+
}), /* @__PURE__ */ _("span", {
|
|
207
|
+
className: "font-medium",
|
|
208
|
+
children: M[e.type]
|
|
209
|
+
})]
|
|
210
|
+
}), /* @__PURE__ */ _("p", {
|
|
211
|
+
className: "text-sm text-text-secondary",
|
|
212
|
+
children: e.desc
|
|
213
|
+
})]
|
|
214
|
+
}, e.type))
|
|
215
|
+
})]
|
|
216
|
+
})
|
|
217
|
+
]
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
//#endregion
|
|
222
|
+
export { N as PoliciesPage };
|
|
223
|
+
|
|
224
|
+
//# sourceMappingURL=PoliciesPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PoliciesPage.js","names":[],"sources":["../../../src/botlit/pages/PoliciesPage.tsx"],"sourcesContent":["/**\n * Policies Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Link } from 'react-router';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n Plus,\n Search as SearchIcon,\n Filter,\n Shield,\n Wrench,\n Database,\n MessageSquare,\n DollarSign,\n Clock,\n Trash2,\n AlertTriangle,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input } from '../components/Input';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport { usePolicies, type PolicyRecord } from '../hooks';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { PolicyType } from '../types';\n\nconst PolicyTypeIcon: FC<{ type: string; className?: string }> = ({ type, className }) => {\n switch (type) {\n case 'CONTENT':\n return <AlertTriangle className={className} />;\n case 'TOOL':\n return <Wrench className={className} />;\n case 'DATA':\n return <Database className={className} />;\n case 'RESPONSE':\n return <MessageSquare className={className} />;\n case 'BUDGET':\n return <DollarSign className={className} />;\n case 'RATE_LIMIT':\n return <Clock className={className} />;\n case 'RETENTION':\n return <Trash2 className={className} />;\n default:\n return <Shield className={className} />;\n }\n};\n\nconst PolicyTypeLabel: Record<string, string> = {\n CONTENT: 'Content Safety',\n TOOL: 'Tool Access',\n DATA: 'Data Access',\n RESPONSE: 'Response Format',\n BUDGET: 'Budget Limits',\n RATE_LIMIT: 'Rate Limiting',\n RETENTION: 'Data Retention',\n};\n\nexport const PoliciesPage: FC = () => {\n const { getPath } = useBotlit();\n const [search, setSearch] = useState('');\n const [selectedType, setSelectedType] = useState<PolicyType | null>(null);\n const { data: policies, loading, error, refetch } = usePolicies({ search });\n\n const filteredPolicies = selectedType\n ? policies.filter((policy) => policy.type === selectedType)\n : policies;\n\n const policyTypes: PolicyType[] = [\n 'CONTENT',\n 'TOOL',\n 'DATA',\n 'RESPONSE',\n 'BUDGET',\n 'RATE_LIMIT',\n 'RETENTION',\n ];\n\n return (\n <PageLayout\n title=\"Policies & Guardrails\"\n description=\"Configure safety rules, access controls, and operational limits\"\n actions={\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('policies/new')}>Create Policy</Link>\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Shield size={18} />}>\n Policies are the guardrails that keep your agents safe and within budget. Each policy\n enforces one kind of rule — blocking harmful content or PII, restricting which tools an\n agent may call, capping token spend, or rate-limiting requests. Define policies here and\n attach them to agents so every execution stays compliant and predictable.\n </PagePurpose>\n\n {/* Policy Type Filters */}\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant={selectedType === null ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedType(null)}\n >\n All\n </Button>\n {policyTypes.map((type) => (\n <Button\n key={type}\n variant={selectedType === type ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setSelectedType(type)}\n leftIcon={<PolicyTypeIcon type={type} className=\"h-4 w-4\" />}\n >\n {PolicyTypeLabel[type]}\n </Button>\n ))}\n </div>\n\n {/* Search */}\n <div className=\"flex items-center gap-4\">\n <div className=\"relative flex-1 max-w-md\">\n <SearchIcon className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search policies...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Button variant=\"outline\" leftIcon={<Filter size={16} />}>\n More Filters\n </Button>\n </div>\n\n {/* Policies List */}\n {loading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[1, 2, 3, 4, 5, 6].map((i) => (\n <div\n key={i}\n className=\"h-40 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState resource=\"policies\" error={error} onRetry={() => void refetch()} />\n ) : filteredPolicies.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredPolicies.map((policy: PolicyRecord) => (\n <Link key={policy.id} to={getPath(`policies/${policy.id}`)}>\n <Card className=\"h-full hover:border-primary/50 transition-colors cursor-pointer\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div\n className={`p-2 rounded-lg ${\n policy.type === 'CONTENT'\n ? 'bg-status-error-bg-subtle'\n : policy.type === 'TOOL'\n ? 'bg-status-info-bg-subtle'\n : policy.type === 'BUDGET'\n ? 'bg-status-warning-bg-subtle'\n : 'bg-action-primary-bg/10'\n }`}\n >\n <PolicyTypeIcon\n type={policy.type}\n className={`h-5 w-5 ${\n policy.type === 'CONTENT'\n ? 'text-status-error-text'\n : policy.type === 'TOOL'\n ? 'text-status-info-text'\n : policy.type === 'BUDGET'\n ? 'text-status-warning-text'\n : 'text-primary'\n }`}\n />\n </div>\n <div>\n <CardTitle className=\"text-base\">{policy.name}</CardTitle>\n </div>\n </div>\n <StatusBadge status={policy.status} />\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary line-clamp-2\">\n {policy.description}\n </p>\n\n {/* Type Badge */}\n <div className=\"flex items-center justify-between\">\n <Badge variant=\"outline\" className=\"text-xs\">\n {PolicyTypeLabel[policy.type]}\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n {formatRelativeTime(policy.createdAt)}\n </span>\n </div>\n </div>\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n title={selectedType ? `No ${PolicyTypeLabel[selectedType]} policies` : 'No policies'}\n description=\"Create policies to enforce safety rules and operational limits across your agents.\"\n action={\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('policies/new')}>Create Policy</Link>\n </Button>\n }\n />\n )}\n\n {/* Policy Types Guide */}\n <GlassCard treatment=\"glass\" glow className=\"p-6\">\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">Policy Types</h2>\n <p className=\"text-sm text-text-secondary\">\n Different policy types control different aspects of agent behavior\n </p>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4\">\n {[\n {\n type: 'CONTENT' as PolicyType,\n desc: 'Detect and block harmful content, jailbreaks, and PII',\n },\n {\n type: 'TOOL' as PolicyType,\n desc: 'Control which tools agents can access and use',\n },\n {\n type: 'BUDGET' as PolicyType,\n desc: 'Set token limits and cost caps per execution',\n },\n {\n type: 'RATE_LIMIT' as PolicyType,\n desc: 'Limit request frequency to prevent abuse',\n },\n ].map((item) => (\n <div key={item.type} className=\"p-4 border border-border-subtle rounded-lg\">\n <div className=\"flex items-center gap-2 mb-2\">\n <PolicyTypeIcon type={item.type} className=\"h-5 w-5 text-primary\" />\n <span className=\"font-medium\">{PolicyTypeLabel[item.type]}</span>\n </div>\n <p className=\"text-sm text-text-secondary\">{item.desc}</p>\n </div>\n ))}\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|