@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,304 @@
|
|
|
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, CardDescription as a, CardHeader as o, CardTitle as s } from "../components/Card.js";
|
|
5
|
+
import { Button as c } from "../components/Button.js";
|
|
6
|
+
import { Badge as l, StatusBadge as u } from "../components/Badge.js";
|
|
7
|
+
import { EmptyState as d } from "../components/EmptyState.js";
|
|
8
|
+
import { Input as f } from "../components/Input.js";
|
|
9
|
+
import { ErrorState as p } from "../components/ErrorState.js";
|
|
10
|
+
import { routeMetadataString as m, useChannelConnectors as h, useChannelRoutes as g } from "../hooks/useChannels.js";
|
|
11
|
+
import "../hooks/index.js";
|
|
12
|
+
import { useMemo as _, useState as v } from "react";
|
|
13
|
+
import { GlassCard as y, PagePurpose as b } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
15
|
+
import { Link as w } from "react-router";
|
|
16
|
+
import { ArrowRight as T, Filter as E, Globe as D, Hash as O, MessageSquare as k, Plus as A, Search as j, Settings as M, Slack as N, Webhook as P } from "lucide-react";
|
|
17
|
+
//#region src/botlit/pages/ChannelsPage.tsx
|
|
18
|
+
var F = ({ type: e, className: t }) => {
|
|
19
|
+
switch (e) {
|
|
20
|
+
case "SLACK": return /* @__PURE__ */ S(N, { className: t });
|
|
21
|
+
case "DISCORD": return /* @__PURE__ */ S(O, { className: t });
|
|
22
|
+
case "TEAMS": return /* @__PURE__ */ S(k, { className: t });
|
|
23
|
+
case "WEB_WIDGET": return /* @__PURE__ */ S(D, { className: t });
|
|
24
|
+
case "WEBHOOK": return /* @__PURE__ */ S(P, { className: t });
|
|
25
|
+
default: return /* @__PURE__ */ S(k, { className: t });
|
|
26
|
+
}
|
|
27
|
+
}, I = () => {
|
|
28
|
+
let { getPath: D } = e(), [O, N] = v(""), [P, I] = v("connectors"), { data: L, loading: R, error: z, refetch: B } = h(_(() => ({ search: O }), [O])), { data: V, loading: H, error: U, refetch: W } = g(), G = _(() => {
|
|
29
|
+
let e = /* @__PURE__ */ new Map();
|
|
30
|
+
for (let t of V) e.set(t.connectorId, (e.get(t.connectorId) ?? 0) + 1);
|
|
31
|
+
return e;
|
|
32
|
+
}, [V]);
|
|
33
|
+
return /* @__PURE__ */ S(n, {
|
|
34
|
+
title: "Channels",
|
|
35
|
+
description: "Connect agents to messaging platforms and configure routing",
|
|
36
|
+
actions: /* @__PURE__ */ C("div", {
|
|
37
|
+
className: "flex gap-2",
|
|
38
|
+
children: [/* @__PURE__ */ S(c, {
|
|
39
|
+
variant: "outline",
|
|
40
|
+
children: /* @__PURE__ */ S(w, {
|
|
41
|
+
to: D("channels/routes"),
|
|
42
|
+
children: "View Routes"
|
|
43
|
+
})
|
|
44
|
+
}), /* @__PURE__ */ S(c, {
|
|
45
|
+
leftIcon: /* @__PURE__ */ S(A, { size: 16 }),
|
|
46
|
+
children: /* @__PURE__ */ S(w, {
|
|
47
|
+
to: D("channels/new"),
|
|
48
|
+
children: "Add Channel"
|
|
49
|
+
})
|
|
50
|
+
})]
|
|
51
|
+
}),
|
|
52
|
+
children: /* @__PURE__ */ C("div", {
|
|
53
|
+
className: "space-y-6",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ S(b, {
|
|
56
|
+
icon: /* @__PURE__ */ S(k, { size: 18 }),
|
|
57
|
+
children: "Channels are where your bots actually talk to people. Connect a messaging platform — a website chat widget, Slack, Microsoft Teams, Discord, WhatsApp or a custom webhook — then add a route that points an incoming location at the bot that should answer. Use this page to manage those connectors and routing rules in one place."
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ C("div", {
|
|
60
|
+
className: "flex gap-1 border-b border-border-subtle",
|
|
61
|
+
children: [/* @__PURE__ */ C("button", {
|
|
62
|
+
onClick: () => I("connectors"),
|
|
63
|
+
className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${P === "connectors" ? "border-primary text-primary" : "border-transparent text-text-secondary hover:text-text-primary"}`,
|
|
64
|
+
children: [
|
|
65
|
+
"Connectors (",
|
|
66
|
+
L.length,
|
|
67
|
+
")"
|
|
68
|
+
]
|
|
69
|
+
}), /* @__PURE__ */ C("button", {
|
|
70
|
+
onClick: () => I("routes"),
|
|
71
|
+
className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${P === "routes" ? "border-primary text-primary" : "border-transparent text-text-secondary hover:text-text-primary"}`,
|
|
72
|
+
children: [
|
|
73
|
+
"Routes (",
|
|
74
|
+
V.length,
|
|
75
|
+
")"
|
|
76
|
+
]
|
|
77
|
+
})]
|
|
78
|
+
}),
|
|
79
|
+
/* @__PURE__ */ C("div", {
|
|
80
|
+
className: "flex items-center gap-4",
|
|
81
|
+
children: [/* @__PURE__ */ C("div", {
|
|
82
|
+
className: "relative flex-1 max-w-md",
|
|
83
|
+
children: [/* @__PURE__ */ S(j, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ S(f, {
|
|
84
|
+
placeholder: `Search ${P}...`,
|
|
85
|
+
value: O,
|
|
86
|
+
onChange: (e) => N(e.target.value),
|
|
87
|
+
className: "pl-9"
|
|
88
|
+
})]
|
|
89
|
+
}), /* @__PURE__ */ S(c, {
|
|
90
|
+
variant: "outline",
|
|
91
|
+
leftIcon: /* @__PURE__ */ S(E, { size: 16 }),
|
|
92
|
+
children: "Filters"
|
|
93
|
+
})]
|
|
94
|
+
}),
|
|
95
|
+
P === "connectors" && /* @__PURE__ */ S(x, { children: R ? /* @__PURE__ */ S("div", {
|
|
96
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
97
|
+
children: [
|
|
98
|
+
1,
|
|
99
|
+
2,
|
|
100
|
+
3
|
|
101
|
+
].map((e) => /* @__PURE__ */ S("div", { className: "h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
|
|
102
|
+
}) : z ? /* @__PURE__ */ S(p, {
|
|
103
|
+
resource: "channel connectors",
|
|
104
|
+
error: z,
|
|
105
|
+
onRetry: () => void B()
|
|
106
|
+
}) : L.length > 0 ? /* @__PURE__ */ S("div", {
|
|
107
|
+
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
108
|
+
children: L.map((e) => /* @__PURE__ */ S(w, {
|
|
109
|
+
to: D(`channels/${e.id}`),
|
|
110
|
+
children: /* @__PURE__ */ C(r, {
|
|
111
|
+
className: "h-full hover:border-primary/50 transition-colors cursor-pointer",
|
|
112
|
+
children: [/* @__PURE__ */ S(o, { children: /* @__PURE__ */ C("div", {
|
|
113
|
+
className: "flex items-start justify-between",
|
|
114
|
+
children: [/* @__PURE__ */ C("div", {
|
|
115
|
+
className: "flex items-center gap-3",
|
|
116
|
+
children: [/* @__PURE__ */ S("div", {
|
|
117
|
+
className: "p-2 bg-action-primary-bg/10 rounded-lg",
|
|
118
|
+
children: /* @__PURE__ */ S(F, {
|
|
119
|
+
type: e.type,
|
|
120
|
+
className: "h-5 w-5 text-primary"
|
|
121
|
+
})
|
|
122
|
+
}), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S(s, {
|
|
123
|
+
className: "text-base",
|
|
124
|
+
children: e.name
|
|
125
|
+
}), /* @__PURE__ */ S(a, {
|
|
126
|
+
className: "text-xs",
|
|
127
|
+
children: e.description
|
|
128
|
+
})] })]
|
|
129
|
+
}), /* @__PURE__ */ S(u, { status: e.status })]
|
|
130
|
+
}) }), /* @__PURE__ */ S(i, { children: /* @__PURE__ */ C("div", {
|
|
131
|
+
className: "space-y-3",
|
|
132
|
+
children: [
|
|
133
|
+
/* @__PURE__ */ C("div", {
|
|
134
|
+
className: "flex items-center justify-between",
|
|
135
|
+
children: [/* @__PURE__ */ S("span", {
|
|
136
|
+
className: "text-sm text-text-secondary",
|
|
137
|
+
children: "Type"
|
|
138
|
+
}), /* @__PURE__ */ S(l, {
|
|
139
|
+
variant: "outline",
|
|
140
|
+
className: "capitalize",
|
|
141
|
+
children: e.type.toLowerCase().replace("_", " ")
|
|
142
|
+
})]
|
|
143
|
+
}),
|
|
144
|
+
/* @__PURE__ */ C("div", {
|
|
145
|
+
className: "flex items-center justify-between",
|
|
146
|
+
children: [/* @__PURE__ */ S("span", {
|
|
147
|
+
className: "text-sm text-text-secondary",
|
|
148
|
+
children: "Active Routes"
|
|
149
|
+
}), /* @__PURE__ */ S(l, {
|
|
150
|
+
variant: "secondary",
|
|
151
|
+
children: G.get(e.id) ?? 0
|
|
152
|
+
})]
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ C("div", {
|
|
155
|
+
className: "pt-3 border-t border-border-subtle text-xs text-text-secondary",
|
|
156
|
+
children: ["Created ", t(e.createdAt)]
|
|
157
|
+
})
|
|
158
|
+
]
|
|
159
|
+
}) })]
|
|
160
|
+
})
|
|
161
|
+
}, e.id))
|
|
162
|
+
}) : /* @__PURE__ */ S(d, {
|
|
163
|
+
illustration: "empty-notifications",
|
|
164
|
+
title: "No channel connectors",
|
|
165
|
+
description: "Connect messaging platforms to deploy agents across multiple channels.",
|
|
166
|
+
action: /* @__PURE__ */ S(c, {
|
|
167
|
+
leftIcon: /* @__PURE__ */ S(A, { size: 16 }),
|
|
168
|
+
children: /* @__PURE__ */ S(w, {
|
|
169
|
+
to: D("channels/new"),
|
|
170
|
+
children: "Add Channel"
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
}) }),
|
|
174
|
+
P === "routes" && /* @__PURE__ */ S(x, { children: H ? /* @__PURE__ */ S("div", {
|
|
175
|
+
className: "space-y-4",
|
|
176
|
+
children: [
|
|
177
|
+
1,
|
|
178
|
+
2,
|
|
179
|
+
3
|
|
180
|
+
].map((e) => /* @__PURE__ */ S("div", { className: "h-20 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
|
|
181
|
+
}) : U ? /* @__PURE__ */ S(p, {
|
|
182
|
+
resource: "channel routes",
|
|
183
|
+
error: U,
|
|
184
|
+
onRetry: () => void W()
|
|
185
|
+
}) : V.length > 0 ? /* @__PURE__ */ S("div", {
|
|
186
|
+
className: "space-y-4",
|
|
187
|
+
children: V.map((e) => /* @__PURE__ */ S(r, { children: /* @__PURE__ */ S(i, {
|
|
188
|
+
className: "py-4",
|
|
189
|
+
children: /* @__PURE__ */ C("div", {
|
|
190
|
+
className: "flex items-center justify-between",
|
|
191
|
+
children: [/* @__PURE__ */ S("div", {
|
|
192
|
+
className: "flex items-center gap-4",
|
|
193
|
+
children: /* @__PURE__ */ C("div", {
|
|
194
|
+
className: "flex items-center gap-2 text-sm",
|
|
195
|
+
children: [
|
|
196
|
+
/* @__PURE__ */ S(l, {
|
|
197
|
+
variant: "outline",
|
|
198
|
+
children: m(e, "locationName") ?? e.locationId
|
|
199
|
+
}),
|
|
200
|
+
/* @__PURE__ */ S(T, {
|
|
201
|
+
size: 16,
|
|
202
|
+
className: "text-text-secondary"
|
|
203
|
+
}),
|
|
204
|
+
/* @__PURE__ */ S(l, {
|
|
205
|
+
variant: "secondary",
|
|
206
|
+
children: m(e, "appName") ?? e.appId ?? "—"
|
|
207
|
+
})
|
|
208
|
+
]
|
|
209
|
+
})
|
|
210
|
+
}), /* @__PURE__ */ C("div", {
|
|
211
|
+
className: "flex items-center gap-2",
|
|
212
|
+
children: [/* @__PURE__ */ S("span", {
|
|
213
|
+
className: "text-xs text-text-secondary",
|
|
214
|
+
children: t(e.createdAt)
|
|
215
|
+
}), /* @__PURE__ */ S(c, {
|
|
216
|
+
variant: "ghost",
|
|
217
|
+
size: "icon",
|
|
218
|
+
children: /* @__PURE__ */ S(M, { size: 16 })
|
|
219
|
+
})]
|
|
220
|
+
})]
|
|
221
|
+
})
|
|
222
|
+
}) }, e.id))
|
|
223
|
+
}) : /* @__PURE__ */ S(d, {
|
|
224
|
+
illustration: "empty-search",
|
|
225
|
+
title: "No routes configured",
|
|
226
|
+
description: "Create routes to connect channel locations to specific bots.",
|
|
227
|
+
action: /* @__PURE__ */ S(c, {
|
|
228
|
+
leftIcon: /* @__PURE__ */ S(A, { size: 16 }),
|
|
229
|
+
children: "Create Route"
|
|
230
|
+
})
|
|
231
|
+
}) }),
|
|
232
|
+
/* @__PURE__ */ C(y, {
|
|
233
|
+
treatment: "glass",
|
|
234
|
+
glow: !0,
|
|
235
|
+
className: "p-6",
|
|
236
|
+
children: [/* @__PURE__ */ C("div", {
|
|
237
|
+
className: "mb-4",
|
|
238
|
+
children: [/* @__PURE__ */ S("h2", {
|
|
239
|
+
className: "text-lg font-semibold tracking-tight text-text-primary",
|
|
240
|
+
children: "Available Integrations"
|
|
241
|
+
}), /* @__PURE__ */ S("p", {
|
|
242
|
+
className: "text-sm text-text-secondary",
|
|
243
|
+
children: "Connect to popular messaging platforms"
|
|
244
|
+
})]
|
|
245
|
+
}), /* @__PURE__ */ S("div", {
|
|
246
|
+
className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4",
|
|
247
|
+
children: [
|
|
248
|
+
{
|
|
249
|
+
type: "WEB_WIDGET",
|
|
250
|
+
name: "Web Widget",
|
|
251
|
+
desc: "Embed on websites"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
type: "SLACK",
|
|
255
|
+
name: "Slack",
|
|
256
|
+
desc: "Workspace integration"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
type: "TEAMS",
|
|
260
|
+
name: "MS Teams",
|
|
261
|
+
desc: "Teams app"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
type: "DISCORD",
|
|
265
|
+
name: "Discord",
|
|
266
|
+
desc: "Bot integration"
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
type: "WHATSAPP",
|
|
270
|
+
name: "WhatsApp",
|
|
271
|
+
desc: "Business API"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
type: "WEBHOOK",
|
|
275
|
+
name: "Webhook",
|
|
276
|
+
desc: "Custom integration"
|
|
277
|
+
}
|
|
278
|
+
].map((e) => /* @__PURE__ */ C("button", {
|
|
279
|
+
className: "p-4 text-center border border-border-subtle rounded-lg hover:bg-accent transition-colors",
|
|
280
|
+
children: [
|
|
281
|
+
/* @__PURE__ */ S(F, {
|
|
282
|
+
type: e.type,
|
|
283
|
+
className: "h-8 w-8 mx-auto text-text-secondary"
|
|
284
|
+
}),
|
|
285
|
+
/* @__PURE__ */ S("p", {
|
|
286
|
+
className: "mt-2 font-medium text-sm",
|
|
287
|
+
children: e.name
|
|
288
|
+
}),
|
|
289
|
+
/* @__PURE__ */ S("p", {
|
|
290
|
+
className: "text-xs text-text-secondary",
|
|
291
|
+
children: e.desc
|
|
292
|
+
})
|
|
293
|
+
]
|
|
294
|
+
}, e.type))
|
|
295
|
+
})]
|
|
296
|
+
})
|
|
297
|
+
]
|
|
298
|
+
})
|
|
299
|
+
});
|
|
300
|
+
};
|
|
301
|
+
//#endregion
|
|
302
|
+
export { I as ChannelsPage };
|
|
303
|
+
|
|
304
|
+
//# sourceMappingURL=ChannelsPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChannelsPage.js","names":[],"sources":["../../../src/botlit/pages/ChannelsPage.tsx"],"sourcesContent":["/**\n * Channels Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { Link } from 'react-router';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n Plus,\n Search as SearchIcon,\n Filter,\n MessageSquare,\n Globe,\n Slack,\n Hash,\n Webhook,\n ArrowRight,\n Settings,\n} from 'lucide-react';\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 } from '../components/Input';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport {\n useChannelConnectors,\n useChannelRoutes,\n routeMetadataString,\n type ChannelConnectorRecord,\n type ChannelRouteRecord,\n} from '../hooks';\nimport { formatRelativeTime, MISSING_VALUE } from '../utils/formatters';\nimport type { ChannelType } from '../types';\n\nconst ChannelIcon: FC<{ type: string; className?: string }> = ({ type, className }) => {\n switch (type) {\n case 'SLACK':\n return <Slack className={className} />;\n case 'DISCORD':\n return <Hash className={className} />;\n case 'TEAMS':\n return <MessageSquare className={className} />;\n case 'WEB_WIDGET':\n return <Globe className={className} />;\n case 'WEBHOOK':\n return <Webhook className={className} />;\n default:\n return <MessageSquare className={className} />;\n }\n};\n\nexport const ChannelsPage: FC = () => {\n const { getPath } = useBotlit();\n const [search, setSearch] = useState('');\n const [activeTab, setActiveTab] = useState<'connectors' | 'routes'>('connectors');\n const connectorFilter = useMemo(() => ({ search }), [search]);\n const {\n data: connectors,\n loading: loadingConnectors,\n error: connectorsError,\n refetch: refetchConnectors,\n } = useChannelConnectors(connectorFilter);\n const {\n data: routes,\n loading: loadingRoutes,\n error: routesError,\n refetch: refetchRoutes,\n } = useChannelRoutes();\n\n // Routes are keyed by connector, so the per-connector count is derived here\n // rather than assuming a field the service does not return.\n const routeCountByConnector = useMemo(() => {\n const counts = new Map<string, number>();\n for (const route of routes) {\n counts.set(route.connectorId, (counts.get(route.connectorId) ?? 0) + 1);\n }\n return counts;\n }, [routes]);\n\n return (\n <PageLayout\n title=\"Channels\"\n description=\"Connect agents to messaging platforms and configure routing\"\n actions={\n <div className=\"flex gap-2\">\n <Button variant=\"outline\">\n <Link to={getPath('channels/routes')}>View Routes</Link>\n </Button>\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('channels/new')}>Add Channel</Link>\n </Button>\n </div>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<MessageSquare size={18} />}>\n Channels are where your bots actually talk to people. Connect a messaging platform — a\n website chat widget, Slack, Microsoft Teams, Discord, WhatsApp or a custom webhook — then\n add a route that points an incoming location at the bot that should answer. Use this page\n to manage those connectors and routing rules in one place.\n </PagePurpose>\n\n {/* Tabs */}\n <div className=\"flex gap-1 border-b border-border-subtle\">\n <button\n onClick={() => setActiveTab('connectors')}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n activeTab === 'connectors'\n ? 'border-primary text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n Connectors ({connectors.length})\n </button>\n <button\n onClick={() => setActiveTab('routes')}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n activeTab === 'routes'\n ? 'border-primary text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n Routes ({routes.length})\n </button>\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 ${activeTab}...`}\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 Filters\n </Button>\n </div>\n\n {/* Connectors Tab */}\n {activeTab === 'connectors' && (\n <>\n {loadingConnectors ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 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 ) : connectorsError ? (\n <ErrorState\n resource=\"channel connectors\"\n error={connectorsError}\n onRetry={() => void refetchConnectors()}\n />\n ) : connectors.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {connectors.map((connector: ChannelConnectorRecord) => (\n <Link key={connector.id} to={getPath(`channels/${connector.id}`)}>\n <Card className=\"h-full hover:border-primary/50 transition-colors cursor-pointer\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-lg\">\n <ChannelIcon type={connector.type} className=\"h-5 w-5 text-primary\" />\n </div>\n <div>\n <CardTitle className=\"text-base\">{connector.name}</CardTitle>\n <CardDescription className=\"text-xs\">\n {connector.description}\n </CardDescription>\n </div>\n </div>\n <StatusBadge status={connector.status} />\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {/* Type */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-secondary\">Type</span>\n <Badge variant=\"outline\" className=\"capitalize\">\n {connector.type.toLowerCase().replace('_', ' ')}\n </Badge>\n </div>\n\n {/* Routes */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-secondary\">Active Routes</span>\n <Badge variant=\"secondary\">\n {routeCountByConnector.get(connector.id) ?? 0}\n </Badge>\n </div>\n\n {/* Footer */}\n <div className=\"pt-3 border-t border-border-subtle text-xs text-text-secondary\">\n Created {formatRelativeTime(connector.createdAt)}\n </div>\n </div>\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-notifications\"\n title=\"No channel connectors\"\n description=\"Connect messaging platforms to deploy agents across multiple channels.\"\n action={\n <Button leftIcon={<Plus size={16} />}>\n <Link to={getPath('channels/new')}>Add Channel</Link>\n </Button>\n }\n />\n )}\n </>\n )}\n\n {/* Routes Tab */}\n {activeTab === 'routes' && (\n <>\n {loadingRoutes ? (\n <div className=\"space-y-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-20 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : routesError ? (\n <ErrorState\n resource=\"channel routes\"\n error={routesError}\n onRetry={() => void refetchRoutes()}\n />\n ) : routes.length > 0 ? (\n <div className=\"space-y-4\">\n {routes.map((route: ChannelRouteRecord) => (\n <Card key={route.id}>\n <CardContent className=\"py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Badge variant=\"outline\">\n {routeMetadataString(route, 'locationName') ?? route.locationId}\n </Badge>\n <ArrowRight size={16} className=\"text-text-secondary\" />\n <Badge variant=\"secondary\">\n {routeMetadataString(route, 'appName') ??\n route.appId ??\n MISSING_VALUE}\n </Badge>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-text-secondary\">\n {formatRelativeTime(route.createdAt)}\n </span>\n <Button variant=\"ghost\" size=\"icon\">\n <Settings size={16} />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n title=\"No routes configured\"\n description=\"Create routes to connect channel locations to specific bots.\"\n action={<Button leftIcon={<Plus size={16} />}>Create Route</Button>}\n />\n )}\n </>\n )}\n\n {/* Available Integrations */}\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 Available Integrations\n </h2>\n <p className=\"text-sm text-text-secondary\">Connect to popular messaging platforms</p>\n </div>\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\n {[\n {\n type: 'WEB_WIDGET' as ChannelType,\n name: 'Web Widget',\n desc: 'Embed on websites',\n },\n { type: 'SLACK' as ChannelType, name: 'Slack', desc: 'Workspace integration' },\n { type: 'TEAMS' as ChannelType, name: 'MS Teams', desc: 'Teams app' },\n { type: 'DISCORD' as ChannelType, name: 'Discord', desc: 'Bot integration' },\n { type: 'WHATSAPP' as ChannelType, name: 'WhatsApp', desc: 'Business API' },\n { type: 'WEBHOOK' as ChannelType, name: 'Webhook', desc: 'Custom integration' },\n ].map((integration) => (\n <button\n key={integration.type}\n className=\"p-4 text-center border border-border-subtle rounded-lg hover:bg-accent transition-colors\"\n >\n <ChannelIcon\n type={integration.type}\n className=\"h-8 w-8 mx-auto text-text-secondary\"\n />\n <p className=\"mt-2 font-medium text-sm\">{integration.name}</p>\n <p className=\"text-xs text-text-secondary\">{integration.desc}</p>\n </button>\n ))}\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { useBotlit as e } from "../providers/BotlitProvider.js";
|
|
2
|
+
import { useAgents as t } from "../hooks/useAgents.js";
|
|
3
|
+
import { useSendMessage as n } from "../hooks/useConversations.js";
|
|
4
|
+
import { cn as r } from "../utils/cn.js";
|
|
5
|
+
import { PageLayout as i } from "../components/PageLayout.js";
|
|
6
|
+
import { Card as a, CardContent as o } from "../components/Card.js";
|
|
7
|
+
import { Button as s } from "../components/Button.js";
|
|
8
|
+
import { Badge as c } from "../components/Badge.js";
|
|
9
|
+
import { Textarea as l } from "../components/Input.js";
|
|
10
|
+
import { QuotaExhaustedDialog as u } from "../components/QuotaExhaustedDialog.js";
|
|
11
|
+
import { useEffect as d, useRef as f, useState as p } from "react";
|
|
12
|
+
import { IllustratedEmptyState as m, PagePurpose as h } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
14
|
+
import { useNavigate as v, useParams as y } from "react-router";
|
|
15
|
+
import { isQuotaExhaustedError as b } from "@burdenoff/fe-libs/shared/utils";
|
|
16
|
+
import { ArrowLeft as x, Bot as S, Loader2 as C, RefreshCw as w, Send as T, Settings as E, User as D } from "lucide-react";
|
|
17
|
+
import { useI18n as O } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
18
|
+
//#region src/botlit/pages/ChatPage.tsx
|
|
19
|
+
var k = () => {
|
|
20
|
+
let { t: k } = O(), A = (e, t) => {
|
|
21
|
+
let n = k(e);
|
|
22
|
+
return n === e ? t : n;
|
|
23
|
+
}, { agentId: j } = y(), M = v(), { navigate: N } = e(), { data: P } = t(), { sendMessage: F, isSending: I } = n(), [L, R] = p(j || ""), [z, B] = p(""), [V, H] = p([]), [U, W] = p(), [G, K] = p(!1), q = f(null), J = () => {
|
|
24
|
+
if (N) {
|
|
25
|
+
N("/billing");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
window.location.assign("/billing");
|
|
29
|
+
}, Y = () => {
|
|
30
|
+
q.current?.scrollIntoView({ behavior: "smooth" });
|
|
31
|
+
};
|
|
32
|
+
d(() => {
|
|
33
|
+
Y();
|
|
34
|
+
}, [V]), d(() => {
|
|
35
|
+
j && R(j);
|
|
36
|
+
}, [j]);
|
|
37
|
+
let X = async () => {
|
|
38
|
+
if (!z.trim() || !L) return;
|
|
39
|
+
let e = {
|
|
40
|
+
id: `user-${Date.now()}`,
|
|
41
|
+
role: "user",
|
|
42
|
+
content: z,
|
|
43
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
44
|
+
};
|
|
45
|
+
H((t) => [...t, e]), B("");
|
|
46
|
+
try {
|
|
47
|
+
let e = await F({
|
|
48
|
+
conversationId: U,
|
|
49
|
+
agentId: L,
|
|
50
|
+
content: z
|
|
51
|
+
});
|
|
52
|
+
e.conversationId && W(e.conversationId);
|
|
53
|
+
let t = {
|
|
54
|
+
id: `assistant-${e.executionId}`,
|
|
55
|
+
role: "assistant",
|
|
56
|
+
content: e.message,
|
|
57
|
+
tokensUsed: e.tokensUsed ?? void 0,
|
|
58
|
+
model: e.model ?? void 0,
|
|
59
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
60
|
+
};
|
|
61
|
+
H((e) => [...e, t]);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
if (b(e)) {
|
|
64
|
+
K(!0);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let t = {
|
|
68
|
+
id: `error-${Date.now()}`,
|
|
69
|
+
role: "assistant",
|
|
70
|
+
content: `${A("botlit.chat.send.errorPrefix", "Error")}: ${e instanceof Error ? e.message : A("botlit.chat.send.errorFallback", "Failed to send message")}`,
|
|
71
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
72
|
+
};
|
|
73
|
+
H((e) => [...e, t]), console.error("Failed to send message:", e);
|
|
74
|
+
}
|
|
75
|
+
}, Z = (e) => {
|
|
76
|
+
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), X());
|
|
77
|
+
}, Q = () => {
|
|
78
|
+
H([]), W(void 0);
|
|
79
|
+
}, $ = P?.find((e) => e.id === L);
|
|
80
|
+
return /* @__PURE__ */ g(i, {
|
|
81
|
+
title: /* @__PURE__ */ _("div", {
|
|
82
|
+
className: "flex items-center gap-3",
|
|
83
|
+
children: [/* @__PURE__ */ g(s, {
|
|
84
|
+
variant: "ghost",
|
|
85
|
+
size: "icon",
|
|
86
|
+
onClick: () => M(-1),
|
|
87
|
+
children: /* @__PURE__ */ g(x, { size: 20 })
|
|
88
|
+
}), $ ? /* @__PURE__ */ _("span", { children: [
|
|
89
|
+
A("botlit.chat.title.withAgent", "Chat with"),
|
|
90
|
+
" ",
|
|
91
|
+
$.name
|
|
92
|
+
] }) : /* @__PURE__ */ g("span", { children: A("botlit.chat.title.default", "AI Chat") })]
|
|
93
|
+
}),
|
|
94
|
+
actions: /* @__PURE__ */ _("div", {
|
|
95
|
+
className: "flex gap-2",
|
|
96
|
+
children: [/* @__PURE__ */ g(s, {
|
|
97
|
+
variant: "outline",
|
|
98
|
+
size: "sm",
|
|
99
|
+
leftIcon: /* @__PURE__ */ g(w, { size: 14 }),
|
|
100
|
+
onClick: Q,
|
|
101
|
+
children: A("botlit.chat.actions.newChat", "New Chat")
|
|
102
|
+
}), L && /* @__PURE__ */ g(s, {
|
|
103
|
+
variant: "outline",
|
|
104
|
+
size: "sm",
|
|
105
|
+
leftIcon: /* @__PURE__ */ g(E, { size: 14 }),
|
|
106
|
+
children: /* @__PURE__ */ g("a", {
|
|
107
|
+
href: `/agents/${L}`,
|
|
108
|
+
children: A("botlit.chat.actions.agentSettings", "Agent Settings")
|
|
109
|
+
})
|
|
110
|
+
})]
|
|
111
|
+
}),
|
|
112
|
+
children: /* @__PURE__ */ _("div", {
|
|
113
|
+
className: "flex flex-col h-[calc(100vh-220px)] max-w-4xl mx-auto",
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ g(h, {
|
|
116
|
+
className: "mb-4",
|
|
117
|
+
icon: /* @__PURE__ */ g(S, { size: 18 }),
|
|
118
|
+
children: A("botlit.chat.purpose", "This is a live playground for talking to your agents. Pick an agent and chat with it exactly as a real user would — to sanity-check its answers, tone and tool use before you connect it to a bot or channel. Conversations here are throwaway tests, so experiment freely.")
|
|
119
|
+
}),
|
|
120
|
+
!j && /* @__PURE__ */ g(a, {
|
|
121
|
+
className: "mb-4",
|
|
122
|
+
children: /* @__PURE__ */ g(o, {
|
|
123
|
+
className: "py-4",
|
|
124
|
+
children: /* @__PURE__ */ _("div", {
|
|
125
|
+
className: "flex items-center gap-4",
|
|
126
|
+
children: [/* @__PURE__ */ g("label", {
|
|
127
|
+
className: "text-sm font-medium",
|
|
128
|
+
children: A("botlit.chat.selector.label", "Select Agent:")
|
|
129
|
+
}), /* @__PURE__ */ _("select", {
|
|
130
|
+
className: "flex h-10 flex-1 max-w-md rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm",
|
|
131
|
+
value: L,
|
|
132
|
+
onChange: (e) => R(e.target.value),
|
|
133
|
+
children: [/* @__PURE__ */ g("option", {
|
|
134
|
+
value: "",
|
|
135
|
+
children: A("botlit.chat.selector.placeholder", "Choose an agent...")
|
|
136
|
+
}), P?.filter((e) => e.status === "ACTIVE").map((e) => /* @__PURE__ */ g("option", {
|
|
137
|
+
value: e.id,
|
|
138
|
+
children: e.name
|
|
139
|
+
}, e.id))]
|
|
140
|
+
})]
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
}),
|
|
144
|
+
/* @__PURE__ */ g(a, {
|
|
145
|
+
treatment: "glass",
|
|
146
|
+
glow: !0,
|
|
147
|
+
className: "flex-1 overflow-hidden",
|
|
148
|
+
children: /* @__PURE__ */ _(o, {
|
|
149
|
+
className: "h-full flex flex-col p-0",
|
|
150
|
+
children: [/* @__PURE__ */ _("div", {
|
|
151
|
+
className: "flex-1 overflow-y-auto p-4 space-y-4",
|
|
152
|
+
children: [
|
|
153
|
+
V.length === 0 ? /* @__PURE__ */ g("div", {
|
|
154
|
+
className: "flex h-full items-center justify-center",
|
|
155
|
+
children: /* @__PURE__ */ g(m, {
|
|
156
|
+
illustration: "onboarding",
|
|
157
|
+
title: A("botlit.chat.empty.title", "Start a Conversation"),
|
|
158
|
+
description: L ? `${A("botlit.chat.empty.withAgentPrefix", "Type a message below to start chatting with")} ${$?.name || A("botlit.chat.empty.withAgentFallbackName", "the agent")}.` : A("botlit.chat.empty.noAgent", "Select an agent above to start chatting.")
|
|
159
|
+
})
|
|
160
|
+
}) : V.map((e) => /* @__PURE__ */ _("div", {
|
|
161
|
+
className: r("flex gap-3", e.role === "user" ? "justify-end" : "justify-start"),
|
|
162
|
+
children: [
|
|
163
|
+
e.role !== "user" && /* @__PURE__ */ g("div", {
|
|
164
|
+
className: "w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center flex-shrink-0",
|
|
165
|
+
children: /* @__PURE__ */ g(S, { size: 16 })
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ _("div", {
|
|
168
|
+
className: r("max-w-[80%] rounded-lg px-4 py-3", e.role === "user" ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken"),
|
|
169
|
+
children: [/* @__PURE__ */ g("div", {
|
|
170
|
+
className: "whitespace-pre-wrap text-sm",
|
|
171
|
+
children: e.content
|
|
172
|
+
}), e.tokensUsed != null && e.tokensUsed > 0 && /* @__PURE__ */ _("div", {
|
|
173
|
+
className: "mt-2 flex items-center gap-2 text-xs opacity-70",
|
|
174
|
+
children: [/* @__PURE__ */ _(c, {
|
|
175
|
+
variant: "outline",
|
|
176
|
+
className: "text-[10px]",
|
|
177
|
+
children: [
|
|
178
|
+
e.tokensUsed,
|
|
179
|
+
" ",
|
|
180
|
+
A("botlit.chat.tokensLabel", "tokens")
|
|
181
|
+
]
|
|
182
|
+
}), e.model && /* @__PURE__ */ g(c, {
|
|
183
|
+
variant: "outline",
|
|
184
|
+
className: "text-[10px]",
|
|
185
|
+
children: e.model
|
|
186
|
+
})]
|
|
187
|
+
})]
|
|
188
|
+
}),
|
|
189
|
+
e.role === "user" && /* @__PURE__ */ g("div", {
|
|
190
|
+
className: "w-8 h-8 rounded-full bg-secondary flex items-center justify-center flex-shrink-0",
|
|
191
|
+
children: /* @__PURE__ */ g(D, { size: 16 })
|
|
192
|
+
})
|
|
193
|
+
]
|
|
194
|
+
}, e.id)),
|
|
195
|
+
I && /* @__PURE__ */ _("div", {
|
|
196
|
+
className: "flex gap-3",
|
|
197
|
+
children: [/* @__PURE__ */ g("div", {
|
|
198
|
+
className: "w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center",
|
|
199
|
+
children: /* @__PURE__ */ g(S, { size: 16 })
|
|
200
|
+
}), /* @__PURE__ */ g("div", {
|
|
201
|
+
className: "bg-bg-sunken rounded-lg px-4 py-3",
|
|
202
|
+
children: /* @__PURE__ */ g(C, { className: "h-5 w-5 animate-spin text-text-secondary" })
|
|
203
|
+
})]
|
|
204
|
+
}),
|
|
205
|
+
/* @__PURE__ */ g("div", { ref: q })
|
|
206
|
+
]
|
|
207
|
+
}), /* @__PURE__ */ _("div", {
|
|
208
|
+
className: "border-t border-border-subtle p-4",
|
|
209
|
+
children: [/* @__PURE__ */ _("div", {
|
|
210
|
+
className: "flex gap-2",
|
|
211
|
+
children: [/* @__PURE__ */ g(l, {
|
|
212
|
+
placeholder: L ? A("botlit.chat.input.placeholder", "Type your message...") : A("botlit.chat.input.disabledPlaceholder", "Select an agent to start chatting"),
|
|
213
|
+
value: z,
|
|
214
|
+
onChange: (e) => B(e.target.value),
|
|
215
|
+
onKeyDown: Z,
|
|
216
|
+
disabled: !L || I,
|
|
217
|
+
className: "min-h-[48px] max-h-[200px] resize-none",
|
|
218
|
+
rows: 1
|
|
219
|
+
}), /* @__PURE__ */ g(s, {
|
|
220
|
+
onClick: X,
|
|
221
|
+
disabled: !z.trim() || !L || I,
|
|
222
|
+
size: "icon",
|
|
223
|
+
className: "h-12 w-12",
|
|
224
|
+
children: I ? /* @__PURE__ */ g(C, { className: "h-5 w-5 animate-spin" }) : /* @__PURE__ */ g(T, { size: 20 })
|
|
225
|
+
})]
|
|
226
|
+
}), /* @__PURE__ */ g("p", {
|
|
227
|
+
className: "text-xs text-text-secondary mt-2",
|
|
228
|
+
children: A("botlit.chat.input.helper", "Press Enter to send, Shift+Enter for new line")
|
|
229
|
+
})]
|
|
230
|
+
})]
|
|
231
|
+
})
|
|
232
|
+
}),
|
|
233
|
+
/* @__PURE__ */ g(u, {
|
|
234
|
+
open: G,
|
|
235
|
+
title: A("botlit.usage.runQuota.title", "Bot Run Limit Reached"),
|
|
236
|
+
description: A("botlit.usage.runQuota.description", "You have reached your bot run limit for this month."),
|
|
237
|
+
onClose: () => K(!1),
|
|
238
|
+
onViewBilling: J
|
|
239
|
+
})
|
|
240
|
+
]
|
|
241
|
+
})
|
|
242
|
+
});
|
|
243
|
+
};
|
|
244
|
+
//#endregion
|
|
245
|
+
export { k as ChatPage };
|
|
246
|
+
|
|
247
|
+
//# sourceMappingURL=ChatPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatPage.js","names":[],"sources":["../../../src/botlit/pages/ChatPage.tsx"],"sourcesContent":["/**\n * Chat Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState, useRef, useEffect } from 'react';\nimport { isQuotaExhaustedError } from '@burdenoff/fe-libs/shared/utils';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useParams, useNavigate } from 'react-router';\nimport { ArrowLeft, Send, Bot, User, Loader2, RefreshCw, Settings } from 'lucide-react';\nimport { PagePurpose, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Textarea } from '../components/Input';\nimport { Badge } from '../components/Badge';\nimport { QuotaExhaustedDialog } from '../components/QuotaExhaustedDialog';\nimport { useAgents } from '../hooks/useAgents';\nimport { useSendMessage } from '../hooks/useConversations';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { cn } from '../utils/cn';\n\ninterface ChatMessage {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n tokensUsed?: number;\n model?: string;\n createdAt: string;\n}\n\nexport const ChatPage: FC = () => {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { agentId } = useParams();\n const navigate = useNavigate();\n const { navigate: shellNavigate } = useBotlit();\n const { data: agents } = useAgents();\n const { sendMessage, isSending } = useSendMessage();\n\n const [selectedAgentId, setSelectedAgentId] = useState(agentId || '');\n const [inputValue, setInputValue] = useState('');\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [conversationId, setConversationId] = useState<string | undefined>();\n const [showQuotaDialog, setShowQuotaDialog] = useState(false);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n const handleViewBilling = () => {\n if (shellNavigate) {\n shellNavigate('/billing');\n return;\n }\n window.location.assign('/billing');\n };\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n useEffect(() => {\n if (agentId) {\n setSelectedAgentId(agentId);\n }\n }, [agentId]);\n\n const handleSend = async () => {\n if (!inputValue.trim() || !selectedAgentId) return;\n\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n role: 'user',\n content: inputValue,\n createdAt: new Date().toISOString(),\n };\n\n setMessages((prev) => [...prev, userMessage]);\n setInputValue('');\n\n try {\n const result = await sendMessage({\n conversationId,\n agentId: selectedAgentId,\n content: inputValue,\n });\n\n // Track conversation ID for follow-up messages\n if (result.conversationId) {\n setConversationId(result.conversationId);\n }\n\n const assistantMessage: ChatMessage = {\n id: `assistant-${result.executionId}`,\n role: 'assistant',\n content: result.message,\n tokensUsed: result.tokensUsed ?? undefined,\n model: result.model ?? undefined,\n createdAt: new Date().toISOString(),\n };\n\n setMessages((prev) => [...prev, assistantMessage]);\n } catch (error) {\n if (isQuotaExhaustedError(error)) {\n setShowQuotaDialog(true);\n return;\n }\n // Add error message to chat\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n role: 'assistant',\n content: `${t('botlit.chat.send.errorPrefix', 'Error')}: ${error instanceof Error ? error.message : t('botlit.chat.send.errorFallback', 'Failed to send message')}`,\n createdAt: new Date().toISOString(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n console.error('Failed to send message:', error);\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const handleReset = () => {\n setMessages([]);\n setConversationId(undefined);\n };\n\n const selectedAgent = agents?.find((a: { id: string }) => a.id === selectedAgentId);\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigate(-1)}>\n <ArrowLeft size={20} />\n </Button>\n {selectedAgent ? (\n <span>\n {t('botlit.chat.title.withAgent', 'Chat with')} {selectedAgent.name}\n </span>\n ) : (\n <span>{t('botlit.chat.title.default', 'AI Chat')}</span>\n )}\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={<RefreshCw size={14} />}\n onClick={handleReset}\n >\n {t('botlit.chat.actions.newChat', 'New Chat')}\n </Button>\n {selectedAgentId && (\n <Button variant=\"outline\" size=\"sm\" leftIcon={<Settings size={14} />}>\n <a href={`/agents/${selectedAgentId}`}>\n {t('botlit.chat.actions.agentSettings', 'Agent Settings')}\n </a>\n </Button>\n )}\n </div>\n }\n >\n <div className=\"flex flex-col h-[calc(100vh-220px)] max-w-4xl mx-auto\">\n <PagePurpose className=\"mb-4\" icon={<Bot size={18} />}>\n {t(\n 'botlit.chat.purpose',\n 'This is a live playground for talking to your agents. Pick an agent and chat with it exactly as a real user would — to sanity-check its answers, tone and tool use before you connect it to a bot or channel. Conversations here are throwaway tests, so experiment freely.'\n )}\n </PagePurpose>\n\n {/* Agent Selector */}\n {!agentId && (\n <Card className=\"mb-4\">\n <CardContent className=\"py-4\">\n <div className=\"flex items-center gap-4\">\n <label className=\"text-sm font-medium\">\n {t('botlit.chat.selector.label', 'Select Agent:')}\n </label>\n <select\n className=\"flex h-10 flex-1 max-w-md rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={selectedAgentId}\n onChange={(e) => setSelectedAgentId(e.target.value)}\n >\n <option value=\"\">\n {t('botlit.chat.selector.placeholder', 'Choose an agent...')}\n </option>\n {agents\n ?.filter((a: { status: string }) => a.status === 'ACTIVE')\n .map((a: { id: string; name: string }) => (\n <option key={a.id} value={a.id}>\n {a.name}\n </option>\n ))}\n </select>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Messages */}\n <Card treatment=\"glass\" glow className=\"flex-1 overflow-hidden\">\n <CardContent className=\"h-full flex flex-col p-0\">\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {messages.length === 0 ? (\n <div className=\"flex h-full items-center justify-center\">\n <IllustratedEmptyState\n illustration=\"onboarding\"\n title={t('botlit.chat.empty.title', 'Start a Conversation')}\n description={\n selectedAgentId\n ? `${t('botlit.chat.empty.withAgentPrefix', 'Type a message below to start chatting with')} ${selectedAgent?.name || t('botlit.chat.empty.withAgentFallbackName', 'the agent')}.`\n : t('botlit.chat.empty.noAgent', 'Select an agent above to start chatting.')\n }\n />\n </div>\n ) : (\n messages.map((message) => (\n <div\n key={message.id}\n className={cn(\n 'flex gap-3',\n message.role === 'user' ? 'justify-end' : 'justify-start'\n )}\n >\n {message.role !== 'user' && (\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center flex-shrink-0\">\n <Bot size={16} />\n </div>\n )}\n <div\n className={cn(\n 'max-w-[80%] rounded-lg px-4 py-3',\n message.role === 'user'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken'\n )}\n >\n <div className=\"whitespace-pre-wrap text-sm\">{message.content}</div>\n {message.tokensUsed != null && message.tokensUsed > 0 && (\n <div className=\"mt-2 flex items-center gap-2 text-xs opacity-70\">\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {message.tokensUsed} {t('botlit.chat.tokensLabel', 'tokens')}\n </Badge>\n {message.model && (\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {message.model}\n </Badge>\n )}\n </div>\n )}\n </div>\n {message.role === 'user' && (\n <div className=\"w-8 h-8 rounded-full bg-secondary flex items-center justify-center flex-shrink-0\">\n <User size={16} />\n </div>\n )}\n </div>\n ))\n )}\n\n {isSending && (\n <div className=\"flex gap-3\">\n <div className=\"w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center\">\n <Bot size={16} />\n </div>\n <div className=\"bg-bg-sunken rounded-lg px-4 py-3\">\n <Loader2 className=\"h-5 w-5 animate-spin text-text-secondary\" />\n </div>\n </div>\n )}\n\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div className=\"border-t border-border-subtle p-4\">\n <div className=\"flex gap-2\">\n <Textarea\n placeholder={\n selectedAgentId\n ? t('botlit.chat.input.placeholder', 'Type your message...')\n : t(\n 'botlit.chat.input.disabledPlaceholder',\n 'Select an agent to start chatting'\n )\n }\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n disabled={!selectedAgentId || isSending}\n className=\"min-h-[48px] max-h-[200px] resize-none\"\n rows={1}\n />\n <Button\n onClick={handleSend}\n disabled={!inputValue.trim() || !selectedAgentId || isSending}\n size=\"icon\"\n className=\"h-12 w-12\"\n >\n {isSending ? <Loader2 className=\"h-5 w-5 animate-spin\" /> : <Send size={20} />}\n </Button>\n </div>\n <p className=\"text-xs text-text-secondary mt-2\">\n {t('botlit.chat.input.helper', 'Press Enter to send, Shift+Enter for new line')}\n </p>\n </div>\n </CardContent>\n </Card>\n <QuotaExhaustedDialog\n open={showQuotaDialog}\n title={t('botlit.usage.runQuota.title', 'Bot Run Limit Reached')}\n description={t(\n 'botlit.usage.runQuota.description',\n 'You have reached your bot run limit for this month.'\n )}\n onClose={() => setShowQuotaDialog(false)}\n onViewBilling={handleViewBilling}\n />\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|