@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.
Files changed (160) hide show
  1. package/README.md +12 -0
  2. package/dist/botlit/BotlitRoutes.js +357 -0
  3. package/dist/botlit/BotlitRoutes.js.map +1 -0
  4. package/dist/botlit/BotmanorRoot.js +12 -0
  5. package/dist/botlit/BotmanorRoot.js.map +1 -0
  6. package/dist/botlit/BotmanorRootInner.js +101 -0
  7. package/dist/botlit/BotmanorRootInner.js.map +1 -0
  8. package/dist/botlit/components/Badge.js +39 -0
  9. package/dist/botlit/components/Badge.js.map +1 -0
  10. package/dist/botlit/components/Button.js +46 -0
  11. package/dist/botlit/components/Button.js.map +1 -0
  12. package/dist/botlit/components/Card.js +31 -0
  13. package/dist/botlit/components/Card.js.map +1 -0
  14. package/dist/botlit/components/ChannelSelectorSheet.js +130 -0
  15. package/dist/botlit/components/ChannelSelectorSheet.js.map +1 -0
  16. package/dist/botlit/components/EmptyState.js +35 -0
  17. package/dist/botlit/components/EmptyState.js.map +1 -0
  18. package/dist/botlit/components/ErrorState.js +33 -0
  19. package/dist/botlit/components/ErrorState.js.map +1 -0
  20. package/dist/botlit/components/Input.js +59 -0
  21. package/dist/botlit/components/Input.js.map +1 -0
  22. package/dist/botlit/components/PageLayout.js +34 -0
  23. package/dist/botlit/components/PageLayout.js.map +1 -0
  24. package/dist/botlit/components/QuotaExhaustedDialog.js +20 -0
  25. package/dist/botlit/components/QuotaExhaustedDialog.js.map +1 -0
  26. package/dist/botlit/components/RouteLoader.js +52 -0
  27. package/dist/botlit/components/RouteLoader.js.map +1 -0
  28. package/dist/botlit/components/VersionHistoryPanel.js +144 -0
  29. package/dist/botlit/components/VersionHistoryPanel.js.map +1 -0
  30. package/dist/botlit/components/WorkspaceRequired.js +70 -0
  31. package/dist/botlit/components/WorkspaceRequired.js.map +1 -0
  32. package/dist/botlit/hooks/index.js +16 -0
  33. package/dist/botlit/hooks/internal/mutationInput.js +16 -0
  34. package/dist/botlit/hooks/internal/mutationInput.js.map +1 -0
  35. package/dist/botlit/hooks/internal/workspaceGateway.js +99 -0
  36. package/dist/botlit/hooks/internal/workspaceGateway.js.map +1 -0
  37. package/dist/botlit/hooks/useA2A.js +184 -0
  38. package/dist/botlit/hooks/useA2A.js.map +1 -0
  39. package/dist/botlit/hooks/useAgents.js +469 -0
  40. package/dist/botlit/hooks/useAgents.js.map +1 -0
  41. package/dist/botlit/hooks/useBots.js +306 -0
  42. package/dist/botlit/hooks/useBots.js.map +1 -0
  43. package/dist/botlit/hooks/useBuckets.js +119 -0
  44. package/dist/botlit/hooks/useBuckets.js.map +1 -0
  45. package/dist/botlit/hooks/useChannels.js +213 -0
  46. package/dist/botlit/hooks/useChannels.js.map +1 -0
  47. package/dist/botlit/hooks/useConversations.js +64 -0
  48. package/dist/botlit/hooks/useConversations.js.map +1 -0
  49. package/dist/botlit/hooks/useExecutions.js +86 -0
  50. package/dist/botlit/hooks/useExecutions.js.map +1 -0
  51. package/dist/botlit/hooks/useKnowledgeBases.js +113 -0
  52. package/dist/botlit/hooks/useKnowledgeBases.js.map +1 -0
  53. package/dist/botlit/hooks/useLLMProviders.js +83 -0
  54. package/dist/botlit/hooks/useLLMProviders.js.map +1 -0
  55. package/dist/botlit/hooks/useMCPServers.js +134 -0
  56. package/dist/botlit/hooks/useMCPServers.js.map +1 -0
  57. package/dist/botlit/hooks/usePolicies.js +120 -0
  58. package/dist/botlit/hooks/usePolicies.js.map +1 -0
  59. package/dist/botlit/hooks/usePromptTemplates.js +161 -0
  60. package/dist/botlit/hooks/usePromptTemplates.js.map +1 -0
  61. package/dist/botlit/hooks/useRetrievalProfiles.js +146 -0
  62. package/dist/botlit/hooks/useRetrievalProfiles.js.map +1 -0
  63. package/dist/botlit/hooks/useSkills.js +132 -0
  64. package/dist/botlit/hooks/useSkills.js.map +1 -0
  65. package/dist/botlit/hooks/useStore.js +167 -0
  66. package/dist/botlit/hooks/useStore.js.map +1 -0
  67. package/dist/botlit/hooks/useUserPlatformConnection.js +172 -0
  68. package/dist/botlit/hooks/useUserPlatformConnection.js.map +1 -0
  69. package/dist/botlit/index.js +11 -0
  70. package/dist/botlit/pages/A2AAgentDetailPage.js +589 -0
  71. package/dist/botlit/pages/A2AAgentDetailPage.js.map +1 -0
  72. package/dist/botlit/pages/A2ARegistryPage.js +240 -0
  73. package/dist/botlit/pages/A2ARegistryPage.js.map +1 -0
  74. package/dist/botlit/pages/AgentBuilderPage.js +486 -0
  75. package/dist/botlit/pages/AgentBuilderPage.js.map +1 -0
  76. package/dist/botlit/pages/AgentDetailPage.js +517 -0
  77. package/dist/botlit/pages/AgentDetailPage.js.map +1 -0
  78. package/dist/botlit/pages/AgentsListPage.js +294 -0
  79. package/dist/botlit/pages/AgentsListPage.js.map +1 -0
  80. package/dist/botlit/pages/BotChannelsTab.js +530 -0
  81. package/dist/botlit/pages/BotChannelsTab.js.map +1 -0
  82. package/dist/botlit/pages/BotDetailPage.js +872 -0
  83. package/dist/botlit/pages/BotDetailPage.js.map +1 -0
  84. package/dist/botlit/pages/BotWorkflowTab.js +229 -0
  85. package/dist/botlit/pages/BotWorkflowTab.js.map +1 -0
  86. package/dist/botlit/pages/BotsListPage.js +313 -0
  87. package/dist/botlit/pages/BotsListPage.js.map +1 -0
  88. package/dist/botlit/pages/BucketsPage.js +604 -0
  89. package/dist/botlit/pages/BucketsPage.js.map +1 -0
  90. package/dist/botlit/pages/ChannelDetailPage.js +955 -0
  91. package/dist/botlit/pages/ChannelDetailPage.js.map +1 -0
  92. package/dist/botlit/pages/ChannelRoutesPage.js +218 -0
  93. package/dist/botlit/pages/ChannelRoutesPage.js.map +1 -0
  94. package/dist/botlit/pages/ChannelsPage.js +304 -0
  95. package/dist/botlit/pages/ChannelsPage.js.map +1 -0
  96. package/dist/botlit/pages/ChatPage.js +247 -0
  97. package/dist/botlit/pages/ChatPage.js.map +1 -0
  98. package/dist/botlit/pages/DashboardPage.js +318 -0
  99. package/dist/botlit/pages/DashboardPage.js.map +1 -0
  100. package/dist/botlit/pages/ExecutionDetailPage.js +313 -0
  101. package/dist/botlit/pages/ExecutionDetailPage.js.map +1 -0
  102. package/dist/botlit/pages/ExecutionsPage.js +294 -0
  103. package/dist/botlit/pages/ExecutionsPage.js.map +1 -0
  104. package/dist/botlit/pages/InstalledPackagesPage.js +619 -0
  105. package/dist/botlit/pages/InstalledPackagesPage.js.map +1 -0
  106. package/dist/botlit/pages/KnowledgeBaseDetailPage.js +473 -0
  107. package/dist/botlit/pages/KnowledgeBaseDetailPage.js.map +1 -0
  108. package/dist/botlit/pages/KnowledgeBasesPage.js +150 -0
  109. package/dist/botlit/pages/KnowledgeBasesPage.js.map +1 -0
  110. package/dist/botlit/pages/MCPServerDetailPage.js +550 -0
  111. package/dist/botlit/pages/MCPServerDetailPage.js.map +1 -0
  112. package/dist/botlit/pages/MCPServersPage.js +321 -0
  113. package/dist/botlit/pages/MCPServersPage.js.map +1 -0
  114. package/dist/botlit/pages/PoliciesPage.js +224 -0
  115. package/dist/botlit/pages/PoliciesPage.js.map +1 -0
  116. package/dist/botlit/pages/PolicyDetailPage.js +861 -0
  117. package/dist/botlit/pages/PolicyDetailPage.js.map +1 -0
  118. package/dist/botlit/pages/PromptStudioPage.js +236 -0
  119. package/dist/botlit/pages/PromptStudioPage.js.map +1 -0
  120. package/dist/botlit/pages/PromptTemplateDetailPage.js +812 -0
  121. package/dist/botlit/pages/PromptTemplateDetailPage.js.map +1 -0
  122. package/dist/botlit/pages/PromptTemplatesPage.js +269 -0
  123. package/dist/botlit/pages/PromptTemplatesPage.js.map +1 -0
  124. package/dist/botlit/pages/RetrievalProfileDetailPage.js +559 -0
  125. package/dist/botlit/pages/RetrievalProfileDetailPage.js.map +1 -0
  126. package/dist/botlit/pages/RetrievalProfilesPage.js +219 -0
  127. package/dist/botlit/pages/RetrievalProfilesPage.js.map +1 -0
  128. package/dist/botlit/pages/SettingsPage.js +655 -0
  129. package/dist/botlit/pages/SettingsPage.js.map +1 -0
  130. package/dist/botlit/pages/SkillDetailPage.js +778 -0
  131. package/dist/botlit/pages/SkillDetailPage.js.map +1 -0
  132. package/dist/botlit/pages/SkillsPage.js +206 -0
  133. package/dist/botlit/pages/SkillsPage.js.map +1 -0
  134. package/dist/botlit/pages/StorePackageDetailPage.js +462 -0
  135. package/dist/botlit/pages/StorePackageDetailPage.js.map +1 -0
  136. package/dist/botlit/pages/StorePage.js +315 -0
  137. package/dist/botlit/pages/StorePage.js.map +1 -0
  138. package/dist/botlit/providers/BotlitProvider.js +93 -0
  139. package/dist/botlit/providers/BotlitProvider.js.map +1 -0
  140. package/dist/botlit/store/botlitStore.js +101 -0
  141. package/dist/botlit/store/botlitStore.js.map +1 -0
  142. package/dist/botlit/utils/cn.js +10 -0
  143. package/dist/botlit/utils/cn.js.map +1 -0
  144. package/dist/botlit/utils/formatters.js +37 -0
  145. package/dist/botlit/utils/formatters.js.map +1 -0
  146. package/dist/botlit/utils/navigation.js +9 -0
  147. package/dist/botlit/utils/navigation.js.map +1 -0
  148. package/dist/botlit/utils/unions.js +14 -0
  149. package/dist/botlit/utils/unions.js.map +1 -0
  150. package/dist/generated/global-operations.js +66 -0
  151. package/dist/generated/global-operations.js.map +1 -0
  152. package/dist/generated/global-types.js +8 -0
  153. package/dist/generated/global-types.js.map +1 -0
  154. package/dist/generated/wspace-operations.js +1591 -0
  155. package/dist/generated/wspace-operations.js.map +1 -0
  156. package/dist/generated/wspace-types.js +12 -0
  157. package/dist/generated/wspace-types.js.map +1 -0
  158. package/dist/index.js +13 -0
  159. package/dist/utils/nativeBridge.js +2 -0
  160. package/package.json +133 -0
@@ -0,0 +1,530 @@
1
+ import { useBotlit as e } from "../providers/BotlitProvider.js";
2
+ import { Card as t, CardContent as n, CardHeader as r, CardTitle as i } from "../components/Card.js";
3
+ import { Button as a } from "../components/Button.js";
4
+ import { Badge as o } from "../components/Badge.js";
5
+ import { isNative as s, nativeCopyText as c, nativeNotify as l, nativeOpenUrl as u, nativeToast as d } from "../../utils/nativeBridge.js";
6
+ import { EmptyState as f } from "../components/EmptyState.js";
7
+ import { Input as p } from "../components/Input.js";
8
+ import { useBotChannelRoutes as m, useChannelConnector as h, useCreateChannelRoute as g, useDeleteChannelRoute as _ } from "../hooks/useChannels.js";
9
+ import { useGlobalChannels as v, useLinkIntegrationConnection as y, useMyUserPlatformConnection as b, useRevokeSlackConnection as x, useToggleSlackNotifications as S } from "../hooks/useUserPlatformConnection.js";
10
+ import "../hooks/index.js";
11
+ import { ChannelSelectorSheet as C } from "../components/ChannelSelectorSheet.js";
12
+ import { useCallback as w, useState as T } from "react";
13
+ import { Fragment as E, jsx as D, jsxs as O } from "react/jsx-runtime";
14
+ import { Bell as k, BellOff as A, CheckCircle2 as j, Loader2 as M, Mail as N, MessageCircle as P, MessageSquare as F, Plus as I, Radio as L, Slack as R, Trash2 as z, Unlink as B, Users as V } from "lucide-react";
15
+ import { toast as H } from "sonner";
16
+ //#region src/botlit/pages/BotChannelsTab.tsx
17
+ var U = {
18
+ SLACK: "slack-user",
19
+ TEAMS: "teams-user",
20
+ DISCORD: "discord-user",
21
+ WHATSAPP: "whatsapp-user"
22
+ }, W = new Set([
23
+ "SLACK",
24
+ "TEAMS",
25
+ "DISCORD"
26
+ ]);
27
+ function G(e) {
28
+ return e ? {
29
+ SLACK_BOT: "Slack Bot",
30
+ SLACK_WEBHOOK: "Slack Webhook",
31
+ AWS_SES: "AWS SES",
32
+ AZURE_ACS: "Azure ACS",
33
+ SENDGRID: "SendGrid",
34
+ MAILGUN: "Mailgun",
35
+ MAILJET: "Mailjet",
36
+ POSTMARK: "Postmark",
37
+ RESEND: "Resend",
38
+ SMTP: "SMTP",
39
+ TWILIO_SMS: "Twilio SMS",
40
+ AWS_SNS: "AWS SNS",
41
+ SINCH: "Sinch",
42
+ VONAGE: "Vonage",
43
+ PLIVO: "Plivo",
44
+ DISCORD_BOT: "Discord Bot",
45
+ DISCORD_WEBHOOK: "Discord Webhook",
46
+ TEAMS_BOT: "Teams Bot",
47
+ TEAMS_WEBHOOK: "Teams Webhook",
48
+ FCM: "Firebase Cloud Messaging",
49
+ APNS: "Apple Push (APNs)",
50
+ WEBHOOK_HTTP: "HTTP Webhook"
51
+ }[e] ?? e.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (e) => e.toUpperCase()) : null;
52
+ }
53
+ function K(e) {
54
+ switch (e) {
55
+ case "SLACK": return {
56
+ label: "Slack",
57
+ badgeClass: "bg-pink-100 text-pink-700",
58
+ icon: /* @__PURE__ */ D(R, { size: 18 }),
59
+ accentBg: "bg-[#611f69]/10",
60
+ accentText: "text-[#611f69]"
61
+ };
62
+ case "TEAMS": return {
63
+ label: "Teams",
64
+ badgeClass: "bg-indigo-100 text-indigo-700",
65
+ icon: /* @__PURE__ */ D(V, { size: 18 }),
66
+ accentBg: "bg-indigo-500/10",
67
+ accentText: "text-indigo-600"
68
+ };
69
+ case "DISCORD": return {
70
+ label: "Discord",
71
+ badgeClass: "bg-violet-100 text-violet-700",
72
+ icon: /* @__PURE__ */ D(P, { size: 18 }),
73
+ accentBg: "bg-violet-500/10",
74
+ accentText: "text-violet-600"
75
+ };
76
+ case "WHATSAPP": return {
77
+ label: "WhatsApp",
78
+ badgeClass: "bg-green-100 text-green-700",
79
+ icon: /* @__PURE__ */ D(F, { size: 18 }),
80
+ accentBg: "bg-green-500/10",
81
+ accentText: "text-green-700"
82
+ };
83
+ case "EMAIL": return {
84
+ label: "Email",
85
+ badgeClass: "bg-blue-100 text-blue-700",
86
+ icon: /* @__PURE__ */ D(N, { size: 18 }),
87
+ accentBg: "bg-blue-500/10",
88
+ accentText: "text-blue-600"
89
+ };
90
+ case "SMS": return {
91
+ label: "SMS",
92
+ badgeClass: "bg-green-100 text-green-700",
93
+ icon: /* @__PURE__ */ D(F, { size: 18 }),
94
+ accentBg: "bg-green-500/10",
95
+ accentText: "text-green-600"
96
+ };
97
+ default: return {
98
+ label: e,
99
+ badgeClass: "bg-gray-100 text-gray-700",
100
+ icon: /* @__PURE__ */ D(L, { size: 18 }),
101
+ accentBg: "bg-gray-500/10",
102
+ accentText: "text-gray-600"
103
+ };
104
+ }
105
+ }
106
+ var q = ({ routeId: e, connectorId: t, channelId: n, platform: r, onRemoved: i, onReconnect: u }) => {
107
+ let { data: f, loading: m } = h(t), g = f?.credentialsRefId ?? n, { data: v, loading: C, refetch: w } = b(g), { toggle: E, loading: N } = S(), { revoke: P, loading: F } = x(), { link: I } = y(), [L] = _(), [R, V] = T(""), [U, W] = T(!1), G = K(r);
108
+ return m ? /* @__PURE__ */ D("div", { className: "h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }) : /* @__PURE__ */ O("div", {
109
+ className: "rounded-lg border border-border-subtle bg-bg-sunken/30 p-4 space-y-3",
110
+ children: [/* @__PURE__ */ O("div", {
111
+ className: "flex items-center justify-between",
112
+ children: [/* @__PURE__ */ D("span", {
113
+ className: "text-xs text-text-secondary font-medium uppercase tracking-wide",
114
+ children: "Connected workspace"
115
+ }), /* @__PURE__ */ D(a, {
116
+ variant: "ghost",
117
+ size: "icon",
118
+ onClick: async () => {
119
+ if (confirm(`Remove this ${G.label} channel from the bot?`)) try {
120
+ await L(e), i(), H.success(`${G.label} channel removed`), s() && l("success");
121
+ } catch (e) {
122
+ H.error(e instanceof Error ? e.message : "Failed to remove"), s() && l("error");
123
+ }
124
+ },
125
+ className: "h-7 w-7 text-text-secondary hover:text-status-error-text",
126
+ title: "Remove channel",
127
+ children: /* @__PURE__ */ D(z, { size: 13 })
128
+ })]
129
+ }), C ? /* @__PURE__ */ O("div", {
130
+ className: "flex items-center gap-2 py-2 text-text-secondary",
131
+ children: [/* @__PURE__ */ D(M, {
132
+ size: 14,
133
+ className: "animate-spin"
134
+ }), /* @__PURE__ */ O("span", {
135
+ className: "text-xs",
136
+ children: [
137
+ "Checking ",
138
+ G.label,
139
+ " connection…"
140
+ ]
141
+ })]
142
+ }) : v?.dmAllowed ? /* @__PURE__ */ O("div", {
143
+ className: "space-y-2",
144
+ children: [
145
+ /* @__PURE__ */ O("div", {
146
+ className: "flex items-center gap-3 p-3 rounded-lg bg-bg-surface border border-border-subtle",
147
+ children: [
148
+ /* @__PURE__ */ D(j, {
149
+ size: 16,
150
+ className: "text-green-600 shrink-0"
151
+ }),
152
+ /* @__PURE__ */ O("div", {
153
+ className: "min-w-0 flex-1",
154
+ children: [
155
+ /* @__PURE__ */ D("p", {
156
+ className: "font-medium text-sm",
157
+ children: v.externalDisplayName || v.externalUsername || v.externalUserId
158
+ }),
159
+ v.externalUsername && /* @__PURE__ */ O("p", {
160
+ className: "text-xs text-text-secondary",
161
+ children: ["@", v.externalUsername]
162
+ }),
163
+ v.connectedAt && /* @__PURE__ */ O("p", {
164
+ className: "text-xs text-text-secondary",
165
+ children: ["Connected ", new Date(v.connectedAt).toLocaleDateString()]
166
+ })
167
+ ]
168
+ }),
169
+ v.isTokenExpired && /* @__PURE__ */ D(o, {
170
+ variant: "outline",
171
+ className: "text-xs text-amber-600 border-amber-400",
172
+ children: "Token expired"
173
+ })
174
+ ]
175
+ }),
176
+ v.integrationConnectionId && /* @__PURE__ */ O("div", {
177
+ className: "space-y-1.5",
178
+ children: [/* @__PURE__ */ D("label", {
179
+ className: "text-xs font-medium text-text-secondary",
180
+ children: "Integration Connection ID"
181
+ }), /* @__PURE__ */ D(p, {
182
+ value: v.integrationConnectionId,
183
+ readOnly: !0,
184
+ className: "text-xs font-mono bg-bg-sunken/50 cursor-default",
185
+ onClick: (e) => {
186
+ e.currentTarget.select(), c(v.integrationConnectionId), H.success("Connection ID copied to clipboard"), s() && d("Copied");
187
+ },
188
+ title: "Click to copy"
189
+ })]
190
+ }),
191
+ /* @__PURE__ */ O("div", {
192
+ className: "flex items-center justify-between p-3 border border-border-subtle rounded-lg bg-bg-surface",
193
+ children: [/* @__PURE__ */ O("div", {
194
+ className: "flex items-center gap-2",
195
+ children: [v.notificationsEnabled ? /* @__PURE__ */ D(k, {
196
+ size: 14,
197
+ className: "text-primary"
198
+ }) : /* @__PURE__ */ D(A, {
199
+ size: 14,
200
+ className: "text-text-secondary"
201
+ }), /* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D("p", {
202
+ className: "text-sm font-medium",
203
+ children: "DM Notifications"
204
+ }), /* @__PURE__ */ D("p", {
205
+ className: "text-xs text-text-secondary",
206
+ children: v.notificationsEnabled ? `Bot will DM you on ${G.label}` : "DM notifications paused"
207
+ })] })]
208
+ }), /* @__PURE__ */ D(a, {
209
+ variant: "outline",
210
+ size: "sm",
211
+ isLoading: N,
212
+ onClick: async () => {
213
+ await E(v.id, !v.notificationsEnabled) && await w();
214
+ },
215
+ children: v.notificationsEnabled ? "Disable" : "Enable"
216
+ })]
217
+ }),
218
+ /* @__PURE__ */ O("div", {
219
+ className: "flex gap-2 justify-end pt-1",
220
+ children: [v.isTokenExpired && /* @__PURE__ */ D(a, {
221
+ variant: "outline",
222
+ size: "sm",
223
+ leftIcon: G.icon,
224
+ onClick: u,
225
+ children: "Reconnect"
226
+ }), /* @__PURE__ */ D(a, {
227
+ variant: "destructive",
228
+ size: "sm",
229
+ leftIcon: /* @__PURE__ */ D(B, { size: 13 }),
230
+ isLoading: F,
231
+ onClick: async () => {
232
+ await P(v.id) && await w();
233
+ },
234
+ children: "Disconnect"
235
+ })]
236
+ })
237
+ ]
238
+ }) : /* @__PURE__ */ O("div", {
239
+ className: "space-y-3 py-2",
240
+ children: [
241
+ /* @__PURE__ */ O("div", {
242
+ className: "flex items-center gap-2 p-3 rounded-lg bg-bg-surface border border-border-subtle",
243
+ children: [/* @__PURE__ */ D("div", {
244
+ className: "p-2 rounded-full bg-bg-sunken shrink-0",
245
+ children: /* @__PURE__ */ D("span", {
246
+ className: "text-text-secondary",
247
+ children: G.icon
248
+ })
249
+ }), /* @__PURE__ */ O("div", {
250
+ className: "flex-1 min-w-0",
251
+ children: [/* @__PURE__ */ D("p", {
252
+ className: "font-medium text-sm",
253
+ children: "No personal account connected"
254
+ }), /* @__PURE__ */ O("p", {
255
+ className: "text-xs text-text-secondary mt-0.5",
256
+ children: [
257
+ "Connect your ",
258
+ G.label,
259
+ " account to receive bot DMs"
260
+ ]
261
+ })]
262
+ })]
263
+ }),
264
+ /* @__PURE__ */ O("div", {
265
+ className: "p-3 rounded-lg bg-bg-sunken/50 space-y-2",
266
+ children: [/* @__PURE__ */ D("p", {
267
+ className: "text-xs font-medium text-text-secondary",
268
+ children: "Connect your account:"
269
+ }), /* @__PURE__ */ O("ol", {
270
+ className: "list-decimal list-inside space-y-1 text-xs text-text-secondary",
271
+ children: [
272
+ /* @__PURE__ */ D("li", { children: "Click \"Open Integrations\" below (opens in new tab)" }),
273
+ /* @__PURE__ */ O("li", { children: [
274
+ "Connect your ",
275
+ G.label,
276
+ " account via OAuth"
277
+ ] }),
278
+ /* @__PURE__ */ D("li", { children: "Copy the Connection ID from the integrations page" }),
279
+ /* @__PURE__ */ D("li", { children: "Paste it below and click \"Link Connection\"" })
280
+ ]
281
+ })]
282
+ }),
283
+ /* @__PURE__ */ D(a, {
284
+ variant: "outline",
285
+ size: "sm",
286
+ leftIcon: G.icon,
287
+ onClick: u,
288
+ className: "w-full",
289
+ children: "Open Integrations →"
290
+ }),
291
+ /* @__PURE__ */ O("div", {
292
+ className: "flex gap-2",
293
+ children: [/* @__PURE__ */ D(p, {
294
+ placeholder: "Paste integration connection ID...",
295
+ value: R,
296
+ onChange: (e) => V(e.target.value),
297
+ className: "flex-1 text-sm"
298
+ }), /* @__PURE__ */ D(a, {
299
+ size: "sm",
300
+ onClick: async () => {
301
+ if (!R.trim()) {
302
+ H.error("Please enter an integration connection ID");
303
+ return;
304
+ }
305
+ W(!0);
306
+ try {
307
+ let e = await I(R.trim(), g);
308
+ e ? (H.success(`${e.externalDisplayName ?? e.externalUsername ?? "Account"} connected! The bot can now send you direct messages.`), await w(), V("")) : H.error("Failed to link connection. Please verify the ID and try again.");
309
+ } catch (e) {
310
+ H.error(e instanceof Error ? e.message : "Failed to link connection");
311
+ } finally {
312
+ W(!1);
313
+ }
314
+ },
315
+ isLoading: U,
316
+ disabled: !R.trim() || U,
317
+ children: "Link Connection"
318
+ })]
319
+ })
320
+ ]
321
+ })]
322
+ });
323
+ }, J = ({ channel: c, routes: l, botId: d, botName: f, onRoutesChanged: p }) => {
324
+ let { basePath: m } = e(), [h] = g(), [_, v] = T(!1), y = c.platform, b = K(y), x = G(c.adapterType), S = _, C = w((e) => {
325
+ let t = U[y];
326
+ if (!t) return;
327
+ let n = window.location.origin + window.location.pathname + window.location.search, r = `${m ? m.replace(/\/botlit(\/.*)?$/, "/integrations") : "/integrations"}/connections/add?${new URLSearchParams({
328
+ providerKey: t,
329
+ returnTo: n,
330
+ channelId: e
331
+ }).toString()}`;
332
+ s() && /^https?:\/\//.test(r) ? u(r) : window.open(r, "_blank");
333
+ }, [y, m]), E = w(async () => {
334
+ v(!0);
335
+ try {
336
+ await h({
337
+ connectorId: c.id,
338
+ appId: d,
339
+ locationId: "*",
340
+ metadata: {
341
+ locationName: "All channels & DMs",
342
+ appName: f
343
+ }
344
+ }), await p(), C(c.id);
345
+ } catch (e) {
346
+ H.error(e instanceof Error ? e.message : `Failed to connect ${b.label}`), v(!1);
347
+ }
348
+ }, [
349
+ d,
350
+ f,
351
+ c.id,
352
+ h,
353
+ b.label,
354
+ C,
355
+ p
356
+ ]), k = w(() => {
357
+ C(c.id);
358
+ }, [c.id, C]);
359
+ return /* @__PURE__ */ O(t, { children: [/* @__PURE__ */ O(r, {
360
+ className: "flex flex-row items-center justify-between pb-3",
361
+ children: [/* @__PURE__ */ O("div", {
362
+ className: "flex items-center gap-2.5",
363
+ children: [/* @__PURE__ */ D("div", {
364
+ className: `p-1.5 rounded-md ${b.accentBg}`,
365
+ children: /* @__PURE__ */ D("span", {
366
+ className: b.accentText,
367
+ children: b.icon
368
+ })
369
+ }), /* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D(i, {
370
+ className: "text-base",
371
+ children: c.name
372
+ }), x && /* @__PURE__ */ D("p", {
373
+ className: "text-xs text-text-secondary mt-0.5",
374
+ children: x
375
+ })] })]
376
+ }), /* @__PURE__ */ O("div", {
377
+ className: "flex items-center gap-1.5",
378
+ children: [/* @__PURE__ */ D("span", {
379
+ className: `px-2 py-0.5 text-xs font-semibold rounded-full ${b.badgeClass}`,
380
+ children: b.label
381
+ }), l.length > 0 && /* @__PURE__ */ D(o, {
382
+ variant: "outline",
383
+ className: "text-xs text-green-600 border-green-400 bg-green-50",
384
+ children: "Active"
385
+ })]
386
+ })]
387
+ }), /* @__PURE__ */ D(n, { children: l.length > 0 ? /* @__PURE__ */ D("div", {
388
+ className: "space-y-3",
389
+ children: l.map((e) => /* @__PURE__ */ D(q, {
390
+ routeId: e.id,
391
+ connectorId: e.connectorId,
392
+ channelId: c.id,
393
+ platform: y,
394
+ onRemoved: p,
395
+ onReconnect: k
396
+ }, e.id))
397
+ }) : /* @__PURE__ */ O("div", {
398
+ className: "flex flex-col items-center gap-4 py-8 text-center",
399
+ children: [
400
+ /* @__PURE__ */ D("div", {
401
+ className: "p-4 rounded-full bg-bg-sunken",
402
+ children: /* @__PURE__ */ D("span", {
403
+ className: "text-text-secondary",
404
+ children: b.icon
405
+ })
406
+ }),
407
+ /* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D("p", {
408
+ className: "font-medium text-sm",
409
+ children: "Not connected to this bot"
410
+ }), /* @__PURE__ */ O("p", {
411
+ className: "text-xs text-text-secondary mt-1",
412
+ children: [
413
+ "Enable ",
414
+ b.label,
415
+ " for this bot. Users will connect their personal accounts separately."
416
+ ]
417
+ })] }),
418
+ /* @__PURE__ */ O(a, {
419
+ leftIcon: b.icon,
420
+ onClick: E,
421
+ isLoading: S,
422
+ children: [
423
+ "Set up ",
424
+ b.label,
425
+ " channel"
426
+ ]
427
+ })
428
+ ]
429
+ }) })] });
430
+ }, Y = ({ route: e, oauthChannels: t, botId: n, botName: r, onRoutesChanged: i }) => {
431
+ let { data: a } = h(e.connectorId), o = t.find((e) => e.id === a?.credentialsRefId);
432
+ return !a || !o || !W.has(o.platform) ? null : /* @__PURE__ */ D(J, {
433
+ channel: o,
434
+ routes: [e],
435
+ botId: n,
436
+ botName: r,
437
+ onRoutesChanged: i
438
+ });
439
+ }, X = ({ botId: e, botName: r }) => {
440
+ let { data: i, loading: o, error: s } = v(), { data: c, loading: l, refetch: u } = m(e), [d, p] = T(!1), [h, g] = T(null), _ = w(async () => {
441
+ await u();
442
+ }, [u]), y = i.filter((e) => W.has(e.platform)), b = new Set(c.map((e) => y.find((e) => c.some((e) => e.connectorId))?.platform).filter(Boolean)), x = y.filter((e) => !b.has(e.platform)), S = {
443
+ SLACK: /* @__PURE__ */ D(R, { size: 18 }),
444
+ TEAMS: /* @__PURE__ */ D(V, { size: 18 }),
445
+ DISCORD: /* @__PURE__ */ D(P, { size: 18 })
446
+ }, k = {};
447
+ y.forEach((e) => {
448
+ let t = e.platform;
449
+ k[t] = K(t);
450
+ });
451
+ let A = w((e, t) => {
452
+ g(e);
453
+ }, []);
454
+ if (o || l) return /* @__PURE__ */ O("div", {
455
+ className: "space-y-4",
456
+ children: [
457
+ /* @__PURE__ */ D("div", { className: "h-10 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg w-52" }),
458
+ /* @__PURE__ */ D("div", { className: "h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }),
459
+ /* @__PURE__ */ D("div", { className: "h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" })
460
+ ]
461
+ });
462
+ let j = c.length > 0;
463
+ return /* @__PURE__ */ O("div", {
464
+ className: "space-y-4",
465
+ children: [
466
+ /* @__PURE__ */ O("div", { children: [/* @__PURE__ */ D("h3", {
467
+ className: "font-semibold text-base",
468
+ children: "Channel Connections"
469
+ }), /* @__PURE__ */ D("p", {
470
+ className: "text-sm text-text-secondary mt-0.5",
471
+ children: "Communication platforms available for this bot"
472
+ })] }),
473
+ s && /* @__PURE__ */ D("div", {
474
+ className: "flex items-start gap-2 rounded-lg border border-status-error-border/40 bg-status-error-bg/10 px-3 py-2 text-sm text-status-error-text",
475
+ children: /* @__PURE__ */ O("span", { children: ["Failed to load channels: ", s.message] })
476
+ }),
477
+ !s && y.length === 0 && /* @__PURE__ */ D(t, { children: /* @__PURE__ */ D(n, {
478
+ className: "py-12",
479
+ children: /* @__PURE__ */ D(f, {
480
+ illustration: "empty-notifications",
481
+ title: "No channels available",
482
+ description: "No active communication channels have been configured yet. Contact your administrator to set up channels."
483
+ })
484
+ }) }),
485
+ !s && y.length > 0 && !j && !h && /* @__PURE__ */ D(t, { children: /* @__PURE__ */ D(n, {
486
+ className: "py-12",
487
+ children: /* @__PURE__ */ D(f, {
488
+ illustration: "empty-notifications",
489
+ title: "No channels connected",
490
+ description: "Connect a communication channel to enable bot conversations on platforms like Slack, Teams, or Discord.",
491
+ action: /* @__PURE__ */ D(a, {
492
+ leftIcon: /* @__PURE__ */ D(I, { size: 16 }),
493
+ onClick: () => p(!0),
494
+ children: "Connect Channel"
495
+ })
496
+ })
497
+ }) }),
498
+ y.length > 0 && (j || h) && /* @__PURE__ */ O("div", {
499
+ className: "space-y-4",
500
+ children: [c.map((t) => /* @__PURE__ */ D(Y, {
501
+ route: t,
502
+ oauthChannels: y,
503
+ botId: e,
504
+ botName: r,
505
+ onRoutesChanged: _
506
+ }, t.id)), h && /* @__PURE__ */ D(E, { children: y.filter((e) => e.id === h).map((t) => /* @__PURE__ */ D(J, {
507
+ channel: t,
508
+ routes: c.filter((e) => !1),
509
+ botId: e,
510
+ botName: r,
511
+ onRoutesChanged: async () => {
512
+ await _(), g(null);
513
+ }
514
+ }, t.id)) })]
515
+ }),
516
+ /* @__PURE__ */ D(C, {
517
+ open: d,
518
+ onClose: () => p(!1),
519
+ onSelectChannel: A,
520
+ availableChannels: x,
521
+ platformIcons: S,
522
+ platformMeta: k
523
+ })
524
+ ]
525
+ });
526
+ };
527
+ //#endregion
528
+ export { X as BotChannelsTab };
529
+
530
+ //# sourceMappingURL=BotChannelsTab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BotChannelsTab.js","names":[],"sources":["../../../src/botlit/pages/BotChannelsTab.tsx"],"sourcesContent":["/**\n * BotChannelsTab\n * @module botlit/pages\n *\n * Shown inside BotDetailPage → \"Channels\" tab.\n *\n * Flow:\n * 1. Fetches all ACTIVE COMMUNICATION channels from global-channel-svc via useGlobalChannels()\n * 2. Filters to show only channelType = COMMUNICATION (bi-directional platforms)\n * 3. OAuth platforms (SLACK, TEAMS, DISCORD):\n * - No bot route → \"Set up channel\" button\n * → creates ChannelRoute + ChannelRoute, then opens integrations in new tab\n * - Route exists → PlatformRouteCard (manual link flow + connected state + toggle / disconnect)\n * - Manual link → User pastes integrationConnectionId → clicks \"Link Connection\"\n * → calls linkIntegrationConnection mutation → toast success\n * 4. WhatsApp: pairing code flow (coming soon / handled by wspace-integrations CUSTOM auth)\n * 5. NOTIFICATION channels (EMAIL/SMS): hidden (not shown for bots)\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { useState, useCallback } from 'react';\nimport {\n Slack,\n Mail,\n MessageSquare,\n Radio,\n CheckCircle2,\n Bell,\n BellOff,\n Loader2,\n Trash2,\n Unlink,\n MessageCircle,\n Users,\n Plus,\n} from 'lucide-react';\nimport { toast } from 'sonner';\nimport { Card, CardHeader, CardTitle, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Badge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { Input } from '../components/Input';\nimport { ChannelSelectorSheet } from '../components/ChannelSelectorSheet';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n isNative,\n nativeCopyText,\n nativeNotify,\n nativeOpenUrl,\n nativeToast,\n} from '../../utils/nativeBridge';\nimport {\n useBotChannelRoutes,\n useChannelConnector,\n useCreateChannelRoute,\n useDeleteChannelRoute,\n} from '../hooks';\nimport {\n useMyUserPlatformConnection,\n useLinkIntegrationConnection,\n useToggleSlackNotifications,\n useRevokeSlackConnection,\n useGlobalChannels,\n} from '../hooks/useUserPlatformConnection';\nimport type { GlobalChannelData } from '../hooks/useUserPlatformConnection';\nimport type { ChannelRouteRecord } from '../hooks/useChannels';\n// `listChannelRoutes` is published — routes carry the real record shape.\ntype ChannelRoute = ChannelRouteRecord;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Platform → provider key mapping (must match keys seeded in wspace-integrations-svc)\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst PLATFORM_PROVIDER_KEY: Record<string, string> = {\n SLACK: 'slack-user',\n TEAMS: 'teams-user',\n DISCORD: 'discord-user',\n WHATSAPP: 'whatsapp-user',\n};\n\n/** Platforms that use the OAuth flow via microfe-integrations */\nconst OAUTH_PLATFORMS = new Set(['SLACK', 'TEAMS', 'DISCORD']);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Human-readable label for an AdapterType enum value */\nfunction getAdapterLabel(adapterType: string | null | undefined): string | null {\n if (!adapterType) return null;\n const labels: Record<string, string> = {\n SLACK_BOT: 'Slack Bot',\n SLACK_WEBHOOK: 'Slack Webhook',\n AWS_SES: 'AWS SES',\n AZURE_ACS: 'Azure ACS',\n SENDGRID: 'SendGrid',\n MAILGUN: 'Mailgun',\n MAILJET: 'Mailjet',\n POSTMARK: 'Postmark',\n RESEND: 'Resend',\n SMTP: 'SMTP',\n TWILIO_SMS: 'Twilio SMS',\n AWS_SNS: 'AWS SNS',\n SINCH: 'Sinch',\n VONAGE: 'Vonage',\n PLIVO: 'Plivo',\n DISCORD_BOT: 'Discord Bot',\n DISCORD_WEBHOOK: 'Discord Webhook',\n TEAMS_BOT: 'Teams Bot',\n TEAMS_WEBHOOK: 'Teams Webhook',\n FCM: 'Firebase Cloud Messaging',\n APNS: 'Apple Push (APNs)',\n WEBHOOK_HTTP: 'HTTP Webhook',\n };\n return (\n labels[adapterType] ??\n adapterType\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (c) => c.toUpperCase())\n );\n}\n\n/** Platform display config — icon element, badge colours, accent colour */\ninterface PlatformMeta {\n label: string;\n badgeClass: string;\n icon: ReactNode;\n accentBg: string;\n accentText: string;\n}\n\nfunction getPlatformMeta(platform: string): PlatformMeta {\n switch (platform) {\n case 'SLACK':\n return {\n label: 'Slack',\n badgeClass: 'bg-pink-100 text-pink-700',\n icon: <Slack size={18} />,\n accentBg: 'bg-[#611f69]/10',\n accentText: 'text-[#611f69]',\n };\n case 'TEAMS':\n return {\n label: 'Teams',\n badgeClass: 'bg-indigo-100 text-indigo-700',\n icon: <Users size={18} />,\n accentBg: 'bg-indigo-500/10',\n accentText: 'text-indigo-600',\n };\n case 'DISCORD':\n return {\n label: 'Discord',\n badgeClass: 'bg-violet-100 text-violet-700',\n icon: <MessageCircle size={18} />,\n accentBg: 'bg-violet-500/10',\n accentText: 'text-violet-600',\n };\n case 'WHATSAPP':\n return {\n label: 'WhatsApp',\n badgeClass: 'bg-green-100 text-green-700',\n icon: <MessageSquare size={18} />,\n accentBg: 'bg-green-500/10',\n accentText: 'text-green-700',\n };\n case 'EMAIL':\n return {\n label: 'Email',\n badgeClass: 'bg-blue-100 text-blue-700',\n icon: <Mail size={18} />,\n accentBg: 'bg-blue-500/10',\n accentText: 'text-blue-600',\n };\n case 'SMS':\n return {\n label: 'SMS',\n badgeClass: 'bg-green-100 text-green-700',\n icon: <MessageSquare size={18} />,\n accentBg: 'bg-green-500/10',\n accentText: 'text-green-600',\n };\n default:\n return {\n label: platform,\n badgeClass: 'bg-gray-100 text-gray-700',\n icon: <Radio size={18} />,\n accentBg: 'bg-gray-500/10',\n accentText: 'text-gray-600',\n };\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// PlatformRouteCard — one connected OAuth platform route + personal connection UI\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface PlatformRouteCardProps {\n routeId: string;\n connectorId: string;\n /** The global channel ID (credentialsRefId) stored on the connector */\n channelId: string;\n platform: string;\n onRemoved: () => void;\n /** Navigate to microfe-integrations to reconnect */\n onReconnect: () => void;\n}\n\nconst PlatformRouteCard: FC<PlatformRouteCardProps> = ({\n routeId,\n connectorId,\n channelId,\n platform,\n onRemoved,\n onReconnect,\n}) => {\n const { data: connector, loading: connectorLoading } = useChannelConnector(connectorId);\n // The channel ID for the UPC lookup is stored on connector.credentialsRefId\n const upcChannelId = connector?.credentialsRefId ?? channelId;\n\n const {\n data: platformConnection,\n loading: connectionLoading,\n refetch: refetchConnection,\n } = useMyUserPlatformConnection(upcChannelId);\n\n const { toggle: toggleNotifications, loading: togglingNotifications } =\n useToggleSlackNotifications();\n const { revoke: revokeConnection, loading: revoking } = useRevokeSlackConnection();\n const { link: linkIntegration } = useLinkIntegrationConnection();\n const [deleteRoute] = useDeleteChannelRoute();\n\n // Manual linking state\n const [integrationConnId, setIntegrationConnId] = useState('');\n const [linking, setLinking] = useState(false);\n\n const meta = getPlatformMeta(platform);\n\n const handleLinkConnection = async () => {\n if (!integrationConnId.trim()) {\n toast.error('Please enter an integration connection ID');\n return;\n }\n setLinking(true);\n try {\n const conn = await linkIntegration(integrationConnId.trim(), upcChannelId);\n if (conn) {\n toast.success(\n `${conn.externalDisplayName ?? conn.externalUsername ?? 'Account'} connected! The bot can now send you direct messages.`\n );\n await refetchConnection();\n setIntegrationConnId('');\n } else {\n toast.error('Failed to link connection. Please verify the ID and try again.');\n }\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to link connection');\n } finally {\n setLinking(false);\n }\n };\n\n const handleRemove = async () => {\n if (!confirm(`Remove this ${meta.label} channel from the bot?`)) return;\n try {\n await deleteRoute(routeId);\n onRemoved();\n toast.success(`${meta.label} channel removed`);\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to remove');\n if (isNative()) void nativeNotify('error');\n }\n };\n\n if (connectorLoading) {\n return <div className=\"h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />;\n }\n\n return (\n <div className=\"rounded-lg border border-border-subtle bg-bg-sunken/30 p-4 space-y-3\">\n {/* Route header */}\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary font-medium uppercase tracking-wide\">\n Connected workspace\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleRemove}\n className=\"h-7 w-7 text-text-secondary hover:text-status-error-text\"\n title=\"Remove channel\"\n >\n <Trash2 size={13} />\n </Button>\n </div>\n\n {connectionLoading ? (\n <div className=\"flex items-center gap-2 py-2 text-text-secondary\">\n <Loader2 size={14} className=\"animate-spin\" />\n <span className=\"text-xs\">Checking {meta.label} connection…</span>\n </div>\n ) : platformConnection?.dmAllowed ? (\n /* ── Personal account connected ── */\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-3 p-3 rounded-lg bg-bg-surface border border-border-subtle\">\n <CheckCircle2 size={16} className=\"text-green-600 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-sm\">\n {platformConnection.externalDisplayName ||\n platformConnection.externalUsername ||\n platformConnection.externalUserId}\n </p>\n {platformConnection.externalUsername && (\n <p className=\"text-xs text-text-secondary\">\n @{platformConnection.externalUsername}\n </p>\n )}\n {platformConnection.connectedAt && (\n <p className=\"text-xs text-text-secondary\">\n Connected {new Date(platformConnection.connectedAt).toLocaleDateString()}\n </p>\n )}\n </div>\n {platformConnection.isTokenExpired && (\n <Badge variant=\"outline\" className=\"text-xs text-amber-600 border-amber-400\">\n Token expired\n </Badge>\n )}\n </div>\n\n {/* Integration Connection ID (read-only) */}\n {platformConnection.integrationConnectionId && (\n <div className=\"space-y-1.5\">\n <label className=\"text-xs font-medium text-text-secondary\">\n Integration Connection ID\n </label>\n <Input\n value={platformConnection.integrationConnectionId}\n readOnly\n className=\"text-xs font-mono bg-bg-sunken/50 cursor-default\"\n onClick={(e) => {\n e.currentTarget.select();\n void nativeCopyText(platformConnection.integrationConnectionId!);\n toast.success('Connection ID copied to clipboard');\n if (isNative()) void nativeToast('Copied');\n }}\n title=\"Click to copy\"\n />\n </div>\n )}\n\n {/* Notification toggle */}\n <div className=\"flex items-center justify-between p-3 border border-border-subtle rounded-lg bg-bg-surface\">\n <div className=\"flex items-center gap-2\">\n {platformConnection.notificationsEnabled ? (\n <Bell size={14} className=\"text-primary\" />\n ) : (\n <BellOff size={14} className=\"text-text-secondary\" />\n )}\n <div>\n <p className=\"text-sm font-medium\">DM Notifications</p>\n <p className=\"text-xs text-text-secondary\">\n {platformConnection.notificationsEnabled\n ? `Bot will DM you on ${meta.label}`\n : 'DM notifications paused'}\n </p>\n </div>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n isLoading={togglingNotifications}\n onClick={async () => {\n const updated = await toggleNotifications(\n platformConnection.id,\n !platformConnection.notificationsEnabled\n );\n if (updated) await refetchConnection();\n }}\n >\n {platformConnection.notificationsEnabled ? 'Disable' : 'Enable'}\n </Button>\n </div>\n\n <div className=\"flex gap-2 justify-end pt-1\">\n {platformConnection.isTokenExpired && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={meta.icon as React.ReactElement}\n onClick={onReconnect}\n >\n Reconnect\n </Button>\n )}\n <Button\n variant=\"destructive\"\n size=\"sm\"\n leftIcon={<Unlink size={13} />}\n isLoading={revoking}\n onClick={async () => {\n const ok = await revokeConnection(platformConnection.id);\n if (ok) await refetchConnection();\n }}\n >\n Disconnect\n </Button>\n </div>\n </div>\n ) : (\n /* ── Personal account not connected - Manual linking flow ── */\n <div className=\"space-y-3 py-2\">\n <div className=\"flex items-center gap-2 p-3 rounded-lg bg-bg-surface border border-border-subtle\">\n <div className=\"p-2 rounded-full bg-bg-sunken shrink-0\">\n <span className=\"text-text-secondary\">{meta.icon}</span>\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium text-sm\">No personal account connected</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n Connect your {meta.label} account to receive bot DMs\n </p>\n </div>\n </div>\n\n <div className=\"p-3 rounded-lg bg-bg-sunken/50 space-y-2\">\n <p className=\"text-xs font-medium text-text-secondary\">Connect your account:</p>\n <ol className=\"list-decimal list-inside space-y-1 text-xs text-text-secondary\">\n <li>Click \"Open Integrations\" below (opens in new tab)</li>\n <li>Connect your {meta.label} account via OAuth</li>\n <li>Copy the Connection ID from the integrations page</li>\n <li>Paste it below and click \"Link Connection\"</li>\n </ol>\n </div>\n\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={meta.icon as React.ReactElement}\n onClick={onReconnect}\n className=\"w-full\"\n >\n Open Integrations →\n </Button>\n\n <div className=\"flex gap-2\">\n <Input\n placeholder=\"Paste integration connection ID...\"\n value={integrationConnId}\n onChange={(e) => setIntegrationConnId(e.target.value)}\n className=\"flex-1 text-sm\"\n />\n <Button\n size=\"sm\"\n onClick={handleLinkConnection}\n isLoading={linking}\n disabled={!integrationConnId.trim() || linking}\n >\n Link Connection\n </Button>\n </div>\n </div>\n )}\n </div>\n );\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// OAuthGlobalChannelCard\n// Generic card for OAuth platforms (Slack, Teams, Discord).\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface OAuthGlobalChannelCardProps {\n channel: GlobalChannelData;\n routes: ChannelRoute[];\n botId: string;\n botName: string;\n onRoutesChanged: () => void;\n}\n\nconst OAuthGlobalChannelCard: FC<OAuthGlobalChannelCardProps> = ({\n channel,\n routes,\n botId,\n botName,\n onRoutesChanged,\n}) => {\n const { basePath } = useBotlit();\n const [createRoute] = useCreateChannelRoute();\n const [connecting, setConnecting] = useState(false);\n\n const platform = channel.platform as string;\n const meta = getPlatformMeta(platform);\n const adapterLabel = getAdapterLabel(channel.adapterType as string | null);\n const isCreating = connecting;\n\n /**\n * Navigate to microfe-integrations wizard pre-configured for this platform.\n * The integrations wizard will OAuth the user, then redirect back here with\n * ?integrationConnectionId=<id>&channelId=<id> appended to the returnTo URL.\n *\n * returnTo MUST be an absolute URL so the backend's new URL(returnTo) doesn't throw.\n */\n const navigateToIntegrations = useCallback(\n (currentChannelId: string) => {\n const providerKey = PLATFORM_PROVIDER_KEY[platform];\n if (!providerKey) return;\n\n // Absolute URL so the backend oauth-callback can do new URL(returnTo) without error.\n const returnTo = window.location.origin + window.location.pathname + window.location.search;\n\n // Integrations MFE base path — shell mounts it at /integrations by convention.\n // Derive it by replacing the /botlit segment of basePath.\n const integrationsBase = basePath\n ? basePath.replace(/\\/botlit(\\/.*)?$/, '/integrations')\n : '/integrations';\n\n const params = new URLSearchParams({\n providerKey,\n returnTo,\n channelId: currentChannelId,\n });\n\n const targetPath = `${integrationsBase}/connections/add?${params.toString()}`;\n\n // Always open in new tab for manual copy-paste workflow\n if (isNative() && /^https?:\\/\\//.test(targetPath)) {\n void nativeOpenUrl(targetPath);\n } else {\n window.open(targetPath, '_blank');\n }\n },\n [platform, basePath]\n );\n\n const handleConnect = useCallback(async () => {\n setConnecting(true);\n try {\n // Route the global channel at this bot. `workspaceId` is supplied by the\n // hook from the Botlit context — never pass an empty string here.\n await createRoute({\n connectorId: channel.id, // Global channel id doubles as the connector reference\n appId: botId,\n locationId: '*',\n metadata: { locationName: 'All channels & DMs', appName: botName },\n });\n\n await onRoutesChanged();\n\n // Navigate to microfe-integrations for OAuth\n navigateToIntegrations(channel.id);\n // page will navigate away — don't setConnecting(false)\n } catch (err) {\n toast.error(err instanceof Error ? err.message : `Failed to connect ${meta.label}`);\n setConnecting(false);\n }\n }, [\n botId,\n botName,\n channel.id,\n createRoute,\n meta.label,\n navigateToIntegrations,\n onRoutesChanged,\n ]);\n\n const handleReconnect = useCallback(() => {\n navigateToIntegrations(channel.id);\n }, [channel.id, navigateToIntegrations]);\n\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between pb-3\">\n <div className=\"flex items-center gap-2.5\">\n <div className={`p-1.5 rounded-md ${meta.accentBg}`}>\n <span className={meta.accentText}>{meta.icon}</span>\n </div>\n <div>\n <CardTitle className=\"text-base\">{channel.name}</CardTitle>\n {adapterLabel && <p className=\"text-xs text-text-secondary mt-0.5\">{adapterLabel}</p>}\n </div>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <span className={`px-2 py-0.5 text-xs font-semibold rounded-full ${meta.badgeClass}`}>\n {meta.label}\n </span>\n {routes.length > 0 && (\n <Badge\n variant=\"outline\"\n className=\"text-xs text-green-600 border-green-400 bg-green-50\"\n >\n Active\n </Badge>\n )}\n </div>\n </CardHeader>\n\n <CardContent>\n {routes.length > 0 ? (\n <div className=\"space-y-3\">\n {routes.map((route: ChannelRoute) => (\n <PlatformRouteCard\n key={route.id}\n routeId={route.id}\n connectorId={route.connectorId}\n channelId={channel.id}\n platform={platform}\n onRemoved={onRoutesChanged}\n onReconnect={handleReconnect}\n />\n ))}\n </div>\n ) : (\n <div className=\"flex flex-col items-center gap-4 py-8 text-center\">\n <div className=\"p-4 rounded-full bg-bg-sunken\">\n <span className=\"text-text-secondary\">{meta.icon}</span>\n </div>\n <div>\n <p className=\"font-medium text-sm\">Not connected to this bot</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n Enable {meta.label} for this bot. Users will connect their personal accounts\n separately.\n </p>\n </div>\n <Button\n leftIcon={meta.icon as React.ReactElement}\n onClick={handleConnect}\n isLoading={isCreating}\n >\n Set up {meta.label} channel\n </Button>\n </div>\n )}\n </CardContent>\n </Card>\n );\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ComingSoonChannelCard\n// EMAIL and SMS channels shown in the UI — connect functionality coming later\n// NOTE: This component is currently unused - we now only show OAuth platforms\n// ─────────────────────────────────────────────────────────────────────────────\n\n// Commented out - not needed for OAuth-only flow\n// interface ComingSoonChannelCardProps {\n// channel: GlobalChannelData;\n// }\n//\n// const ComingSoonChannelCard: FC<ComingSoonChannelCardProps> = ({ channel }) => {\n// const meta = getPlatformMeta(channel.platform as string);\n// const adapterLabel = getAdapterLabel(channel.adapterType as string | null);\n//\n// return (\n// <Card className=\"opacity-80\">\n// <CardHeader className=\"flex flex-row items-center justify-between pb-3\">\n// <div className=\"flex items-center gap-2.5\">\n// <div className={`p-1.5 rounded-md ${meta.accentBg}`}>\n// <span className={meta.accentText}>{meta.icon}</span>\n// </div>\n// <div>\n// <CardTitle className=\"text-base\">{channel.name}</CardTitle>\n// {adapterLabel && <p className=\"text-xs text-text-secondary mt-0.5\">{adapterLabel}</p>}\n// </div>\n// </div>\n// <div className=\"flex items-center gap-1.5\">\n// <span className={`px-2 py-0.5 text-xs font-semibold rounded-full ${meta.badgeClass}`}>\n// {meta.label}\n// </span>\n// <Badge variant=\"outline\" className=\"text-xs text-text-secondary\">\n// <Clock size={10} className=\"mr-1\" />\n// Coming soon\n// </Badge>\n// </div>\n// </CardHeader>\n// <CardContent>\n// <p className=\"text-sm text-text-secondary text-center py-4\">\n// Bot integration for <strong>{meta.label}</strong> channels is coming soon. This channel is\n// available for notification delivery — two-way bot communication will be enabled in a\n// future update.\n// </p>\n// </CardContent>\n// </Card>\n// );\n// };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ConfiguredChannelCard - Wrapper that fetches connector and matches channel\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface ConfiguredChannelCardProps {\n route: ChannelRoute;\n oauthChannels: GlobalChannelData[];\n botId: string;\n botName: string;\n onRoutesChanged: () => void;\n}\n\nconst ConfiguredChannelCard: FC<ConfiguredChannelCardProps> = ({\n route,\n oauthChannels,\n botId,\n botName,\n onRoutesChanged,\n}) => {\n // Fetch the connector to get credentialsRefId\n const { data: connector } = useChannelConnector(route.connectorId);\n\n // Find the matching channel by credentialsRefId\n const channel = oauthChannels.find((ch) => ch.id === connector?.credentialsRefId);\n\n // If connector is still loading or channel not found, don't render\n if (!connector || !channel) return null;\n\n // Only show OAuth channels\n if (!OAUTH_PLATFORMS.has(channel.platform as string)) return null;\n\n return (\n <OAuthGlobalChannelCard\n channel={channel}\n routes={[route]}\n botId={botId}\n botName={botName}\n onRoutesChanged={onRoutesChanged}\n />\n );\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// BotChannelsTab - Main component\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface BotChannelsTabProps {\n botId: string;\n botName: string;\n}\n\nexport const BotChannelsTab: FC<BotChannelsTabProps> = ({ botId, botName }) => {\n const {\n data: globalChannels,\n loading: channelsLoading,\n error: channelsError,\n } = useGlobalChannels();\n\n const {\n data: routes,\n loading: routesLoading,\n refetch: refetchRoutes,\n } = useBotChannelRoutes(botId);\n\n // State for channel selector sheet\n const [showChannelSelector, setShowChannelSelector] = useState(false);\n const [selectedChannelForSetup, setSelectedChannelForSetup] = useState<string | null>(null);\n\n const handleRoutesChanged = useCallback(async () => {\n await refetchRoutes();\n }, [refetchRoutes]);\n\n // Filter to show only OAuth platforms (Slack, Teams, Discord)\n const oauthChannels = globalChannels.filter((ch) => OAUTH_PLATFORMS.has(ch.platform as string));\n\n // Calculate which platforms are already configured for this bot\n const configuredPlatforms = new Set(\n routes\n .map((_route: ChannelRoute) => {\n // Find the channel for this route to get its platform\n const channel = oauthChannels.find((_ch) => {\n // Match by checking if any route uses this channel\n return routes.some((r: ChannelRoute) => r.connectorId);\n });\n return channel?.platform as string;\n })\n .filter(Boolean)\n );\n\n // Get available channels (OAuth platforms not yet configured)\n const availableChannels = oauthChannels.filter(\n (ch) => !configuredPlatforms.has(ch.platform as string)\n );\n\n // Platform icons mapping for ChannelSelectorSheet\n const platformIcons: Record<string, ReactNode> = {\n SLACK: <Slack size={18} />,\n TEAMS: <Users size={18} />,\n DISCORD: <MessageCircle size={18} />,\n };\n\n // Platform metadata mapping for ChannelSelectorSheet\n const platformMetaMap: Record<string, PlatformMeta> = {};\n oauthChannels.forEach((ch) => {\n const platform = ch.platform as string;\n platformMetaMap[platform] = getPlatformMeta(platform);\n });\n\n const handleSelectChannel = useCallback((channelId: string, _platform: string) => {\n setSelectedChannelForSetup(channelId);\n }, []);\n\n const isLoading = channelsLoading || routesLoading;\n\n if (isLoading) {\n return (\n <div className=\"space-y-4\">\n <div className=\"h-10 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg w-52\" />\n <div className=\"h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n <div className=\"h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n </div>\n );\n }\n\n // Empty state: no channels configured yet\n const hasConfiguredChannels = routes.length > 0;\n\n return (\n <div className=\"space-y-4\">\n {/* Header */}\n <div>\n <h3 className=\"font-semibold text-base\">Channel Connections</h3>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n Communication platforms available for this bot\n </p>\n </div>\n\n {/* Channel error banner */}\n {channelsError && (\n <div className=\"flex items-start gap-2 rounded-lg border border-status-error-border/40 bg-status-error-bg/10 px-3 py-2 text-sm text-status-error-text\">\n <span>Failed to load channels: {channelsError.message}</span>\n </div>\n )}\n\n {/* Empty state: no OAuth channels available from backend */}\n {!channelsError && oauthChannels.length === 0 && (\n <Card>\n <CardContent className=\"py-12\">\n <EmptyState\n illustration=\"empty-notifications\"\n title=\"No channels available\"\n description=\"No active communication channels have been configured yet. Contact your administrator to set up channels.\"\n />\n </CardContent>\n </Card>\n )}\n\n {/* Empty state: channels available but none configured yet */}\n {!channelsError &&\n oauthChannels.length > 0 &&\n !hasConfiguredChannels &&\n !selectedChannelForSetup && (\n <Card>\n <CardContent className=\"py-12\">\n <EmptyState\n illustration=\"empty-notifications\"\n title=\"No channels connected\"\n description=\"Connect a communication channel to enable bot conversations on platforms like Slack, Teams, or Discord.\"\n action={\n <Button\n leftIcon={<Plus size={16} />}\n onClick={() => setShowChannelSelector(true)}\n >\n Connect Channel\n </Button>\n }\n />\n </CardContent>\n </Card>\n )}\n\n {/* Configured channels + channel in setup */}\n {oauthChannels.length > 0 && (hasConfiguredChannels || selectedChannelForSetup) && (\n <div className=\"space-y-4\">\n {/* Show configured channels */}\n {routes.map((route: ChannelRoute) => {\n return (\n <ConfiguredChannelCard\n key={route.id}\n route={route}\n oauthChannels={oauthChannels}\n botId={botId}\n botName={botName}\n onRoutesChanged={handleRoutesChanged}\n />\n );\n })}\n\n {/* Show channel currently being set up */}\n {selectedChannelForSetup && (\n <>\n {oauthChannels\n .filter((ch) => ch.id === selectedChannelForSetup)\n .map((channel) => (\n <OAuthGlobalChannelCard\n key={channel.id}\n channel={channel}\n routes={routes.filter((_r: ChannelRoute) => {\n // Only show routes for this specific channel\n return false; // Initially no routes exist\n })}\n botId={botId}\n botName={botName}\n onRoutesChanged={async () => {\n await handleRoutesChanged();\n setSelectedChannelForSetup(null);\n }}\n />\n ))}\n </>\n )}\n </div>\n )}\n\n {/* Channel Selector Sheet */}\n <ChannelSelectorSheet\n open={showChannelSelector}\n onClose={() => setShowChannelSelector(false)}\n onSelectChannel={handleSelectChannel}\n availableChannels={availableChannels}\n platformIcons={platformIcons}\n platformMeta={platformMetaMap}\n />\n </div>\n );\n};\n"],"mappings":"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"}