@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 @@
|
|
|
1
|
+
{"version":3,"file":"ChannelDetailPage.js","names":[],"sources":["../../../src/botlit/pages/ChannelDetailPage.tsx"],"sourcesContent":["/**\n * Channel Detail Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { useParams, useSearchParams } from 'react-router';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { isNative, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport {\n ArrowLeft,\n Radio,\n MessageSquare,\n Globe,\n Hash,\n Shield,\n Settings,\n Save,\n Plus,\n ExternalLink,\n Palette,\n Edit,\n Trash2,\n X,\n Slack,\n Bell,\n BellOff,\n CheckCircle2,\n Unlink,\n Loader2,\n} from 'lucide-react';\nimport { PagePurpose, NextSteps, 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, Textarea, FormField } from '../components/Input';\nimport { StatusBadge, Badge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport {\n useChannelConnector,\n useChannelRoutes,\n useCreateChannelConnector,\n useUpdateChannelConnector,\n useDeleteChannelConnector,\n useCreateChannelRoute,\n routeMetadataString,\n useBots,\n useMyUserPlatformConnection,\n useInitiateSlackConnect,\n useLinkIntegrationConnection,\n useToggleSlackNotifications,\n useRevokeSlackConnection,\n} from '../hooks';\nimport { readWidgetConfig, WIDGET_METADATA_KEY } from '../hooks/useChannels';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { toUnion } from '../utils/unions';\nimport type { ChannelType, Visibility } from '../types';\n\n/** Channel types the UI can render icons/labels for. */\nconst CHANNEL_TYPES: ChannelType[] = [\n 'WEB_WIDGET',\n 'SLACK',\n 'TEAMS',\n 'DISCORD',\n 'WHATSAPP',\n 'WEBHOOK',\n 'CUSTOM',\n];\n\nconst VISIBILITIES: Visibility[] = ['PRIVATE', 'WORKSPACE', 'PUBLIC'];\n\n/** Splits a comma-separated form field into a trimmed, non-empty list. */\nfunction splitList(value: string): string[] {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n}\nimport { toast } from 'sonner';\n\ninterface ChannelDetailPageProps {\n isNew?: boolean;\n}\n\nconst ChannelIcon: FC<{ type: ChannelType }> = ({ type }) => {\n switch (type) {\n case 'SLACK':\n return <Hash size={18} />;\n case 'WEB_WIDGET':\n return <Globe size={18} />;\n case 'TEAMS':\n return <MessageSquare size={18} />;\n default:\n return <Radio size={18} />;\n }\n};\n\nexport const ChannelDetailPage: FC<ChannelDetailPageProps> = ({ isNew }) => {\n const { connectorId } = useParams();\n const { navigateTo } = useBotlit();\n const [searchParams, setSearchParams] = useSearchParams();\n const { data: connector, loading } = useChannelConnector(isNew ? undefined : connectorId);\n const { data: routes, refetch: refetchRoutes } = useChannelRoutes(connectorId);\n const { data: bots } = useBots();\n const [createConnector, createConnectorResult] = useCreateChannelConnector();\n const [updateConnector, updateConnectorResult] = useUpdateChannelConnector();\n const [deleteConnector, deleteConnectorResult] = useDeleteChannelConnector();\n const [createRoute, createRouteResult] = useCreateChannelRoute();\n\n // Phase 7: Slack personal account connect\n const slackChannelId =\n connector?.type === 'SLACK' && connector?.credentialsRefId\n ? connector.credentialsRefId\n : undefined;\n const {\n data: slackConnection,\n loading: slackConnectionLoading,\n refetch: refetchSlackConnection,\n } = useMyUserPlatformConnection(slackChannelId);\n const { initiate: initiateSlack } = useInitiateSlackConnect();\n const { link: linkIntegration, loading: linking } = useLinkIntegrationConnection();\n const { toggle: toggleNotifications, loading: togglingNotifications } =\n useToggleSlackNotifications();\n const { revoke: revokeConnection, loading: revoking } = useRevokeSlackConnection();\n const [oauthError, setOauthError] = useState<string | null>(null);\n\n // After integrations OAuth flow: link integration connection to channel\n // URL params: ?integrationConnectionId=<id>&channelId=<id>\n //\n // The ref — not an empty dependency list — is what makes this run once: the\n // params are consumed exactly once per visit, while the effect still declares\n // everything it reads.\n const oauthLinkConsumed = useRef(false);\n useEffect(() => {\n if (oauthLinkConsumed.current) return;\n\n const integrationConnectionId = searchParams.get('integrationConnectionId');\n const channelId = searchParams.get('channelId');\n if (!integrationConnectionId || !channelId) return;\n\n oauthLinkConsumed.current = true;\n\n // Clean the URL immediately so a refresh doesn't re-trigger\n const cleaned = new URLSearchParams(searchParams);\n cleaned.delete('integrationConnectionId');\n cleaned.delete('channelId');\n setSearchParams(cleaned, { replace: true });\n\n setOauthError(null);\n void linkIntegration(integrationConnectionId, channelId).then((connection) => {\n if (connection) {\n void refetchSlackConnection();\n } else {\n setOauthError('Failed to link Slack connection. Please try again.');\n }\n });\n }, [searchParams, setSearchParams, linkIntegration, refetchSlackConnection]);\n\n const handleSlackConnect = () => {\n if (!slackChannelId) return;\n // Slack appends ?code=...&state=... to the redirect_uri we supply\n const redirectUri = `${window.location.origin}${window.location.pathname}`;\n initiateSlack(slackChannelId, redirectUri);\n };\n\n const handleToggleNotifications = async () => {\n if (!slackConnection) return;\n const updated = await toggleNotifications(\n slackConnection.id,\n !slackConnection.notificationsEnabled\n );\n if (updated) {\n await refetchSlackConnection();\n }\n };\n\n const handleRevokeSlack = async () => {\n if (!slackConnection) return;\n const ok = await revokeConnection(slackConnection.id);\n if (ok) {\n await refetchSlackConnection();\n }\n };\n\n const [isEditing, setIsEditing] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [showAddRoute, setShowAddRoute] = useState(false);\n const [newRoute, setNewRoute] = useState({ locationId: '', locationName: '', botId: '' });\n\n const [formData, setFormData] = useState({\n name: '',\n description: '',\n type: 'WEB_WIDGET' as ChannelType,\n visibility: 'PRIVATE' as Visibility,\n credentialsRefId: '',\n });\n\n const [widgetConfig, setWidgetConfig] = useState({\n allowedOrigins: '',\n primaryColor: '#3b82f6',\n fontFamily: 'Inter, sans-serif',\n starterPrompts: '',\n });\n\n /**\n * The connector has no widget column — the appearance settings are stored\n * under `metadata.webWidget`, which is where the detail view reads them back.\n */\n const buildWidgetMetadata = (): Record<string, unknown> | undefined => {\n if (formData.type !== 'WEB_WIDGET') return undefined;\n return {\n [WIDGET_METADATA_KEY]: {\n allowedOrigins: splitList(widgetConfig.allowedOrigins),\n primaryColor: widgetConfig.primaryColor,\n fontFamily: widgetConfig.fontFamily,\n starterPrompts: splitList(widgetConfig.starterPrompts),\n },\n };\n };\n\n const handleCreate = async () => {\n if (!formData.name) return;\n try {\n const created = await createConnector({\n name: formData.name,\n type: formData.type,\n description: formData.description || undefined,\n visibility: formData.visibility,\n credentialsRefId: formData.credentialsRefId || undefined,\n metadata: buildWidgetMetadata(),\n });\n toast.success(`Channel \"${created.name}\" created`);\n navigateTo(`channels/${created.id}`);\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to create channel connector');\n }\n };\n\n const handleUpdate = async () => {\n if (!connectorId || !formData.name) return;\n try {\n await updateConnector({\n connectorId,\n input: {\n name: formData.name,\n description: formData.description || undefined,\n visibility: formData.visibility,\n credentialsRefId: formData.credentialsRefId || undefined,\n metadata: buildWidgetMetadata(),\n },\n });\n toast.success('Channel updated');\n setIsEditing(false);\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to update channel connector');\n }\n };\n\n const handleDelete = async () => {\n if (!connectorId) return;\n try {\n await deleteConnector(connectorId);\n if (isNative()) void nativeNotify('success');\n navigateTo('channels');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n };\n\n const handleAddRoute = async () => {\n if (!connectorId || !newRoute.locationId || !newRoute.botId) return;\n const selectedBot = bots?.find((a: { id: string; name: string }) => a.id === newRoute.botId);\n try {\n await createRoute({\n connectorId,\n locationId: newRoute.locationId,\n appId: newRoute.botId,\n metadata: {\n locationName: newRoute.locationName || newRoute.locationId,\n appName: selectedBot?.name,\n },\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to create route');\n return;\n }\n toast.success('Route created');\n void refetchRoutes();\n setNewRoute({ locationId: '', locationName: '', botId: '' });\n setShowAddRoute(false);\n };\n\n const startEditing = () => {\n if (!connector) return;\n setFormData({\n name: connector.name,\n description: connector.description || '',\n type: toUnion(connector.type, CHANNEL_TYPES, 'CUSTOM'),\n visibility: toUnion(connector.visibility, VISIBILITIES, 'PRIVATE'),\n credentialsRefId: connector.credentialsRefId || '',\n });\n const saved = readWidgetConfig(connector);\n if (saved) {\n setWidgetConfig({\n allowedOrigins: saved.allowedOrigins.join(', '),\n primaryColor: saved.primaryColor,\n fontFamily: saved.fontFamily,\n starterPrompts: saved.starterPrompts.join(', '),\n });\n }\n setIsEditing(true);\n };\n\n if (isNew) {\n return (\n <PageLayout\n title=\"Create Channel Connector\"\n description=\"Set up a new channel for your AI agents\"\n actions={\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" onClick={() => navigateTo('channels')}>\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleCreate}\n isLoading={createConnectorResult.loading || updateConnectorResult.loading}\n disabled={!formData.name}\n >\n Create\n </Button>\n </div>\n }\n >\n <div className=\"max-w-2xl space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Connector Name\" required>\n <Input\n placeholder=\"e.g., Production Web Widget\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this channel connector for?\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n />\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Channel Type\" required>\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.type}\n onChange={(e) =>\n setFormData({ ...formData, type: e.target.value as ChannelType })\n }\n >\n <option value=\"WEB_WIDGET\">Web Widget</option>\n <option value=\"SLACK\">Slack</option>\n <option value=\"TEAMS\">Microsoft Teams</option>\n <option value=\"DISCORD\">Discord</option>\n <option value=\"WHATSAPP\">WhatsApp</option>\n <option value=\"WEBHOOK\">Webhook</option>\n <option value=\"CUSTOM\">Custom</option>\n </select>\n </FormField>\n\n <FormField label=\"Visibility\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.visibility}\n onChange={(e) =>\n setFormData({ ...formData, visibility: e.target.value as Visibility })\n }\n >\n <option value=\"PRIVATE\">Private</option>\n <option value=\"WORKSPACE\">Workspace</option>\n <option value=\"PUBLIC\">Public</option>\n </select>\n </FormField>\n </div>\n\n {formData.type !== 'WEB_WIDGET' && (\n <FormField label=\"Credentials Reference\">\n <Input\n placeholder=\"e.g., secret-slack-token\"\n value={formData.credentialsRefId}\n onChange={(e) => setFormData({ ...formData, credentialsRefId: e.target.value })}\n />\n </FormField>\n )}\n </CardContent>\n </Card>\n\n {formData.type === 'WEB_WIDGET' && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Palette size={18} />\n Widget Configuration\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Allowed Origins\" description=\"Comma-separated list of domains\">\n <Input\n placeholder=\"e.g., https://example.com, https://app.example.com\"\n value={widgetConfig.allowedOrigins}\n onChange={(e) =>\n setWidgetConfig({ ...widgetConfig, allowedOrigins: e.target.value })\n }\n />\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Primary Color\">\n <div className=\"flex gap-2\">\n <input\n type=\"color\"\n value={widgetConfig.primaryColor}\n onChange={(e) =>\n setWidgetConfig({ ...widgetConfig, primaryColor: e.target.value })\n }\n className=\"h-10 w-16 rounded border border-border-default\"\n />\n <Input\n value={widgetConfig.primaryColor}\n onChange={(e) =>\n setWidgetConfig({ ...widgetConfig, primaryColor: e.target.value })\n }\n />\n </div>\n </FormField>\n\n <FormField label=\"Font Family\">\n <Input\n value={widgetConfig.fontFamily}\n onChange={(e) =>\n setWidgetConfig({ ...widgetConfig, fontFamily: e.target.value })\n }\n />\n </FormField>\n </div>\n\n <FormField label=\"Starter Prompts\" description=\"One per line\">\n <Textarea\n placeholder=\"What can you help me with?\"\n value={widgetConfig.starterPrompts}\n onChange={(e) =>\n setWidgetConfig({ ...widgetConfig, starterPrompts: e.target.value })\n }\n rows={3}\n />\n </FormField>\n </CardContent>\n </Card>\n )}\n </div>\n </PageLayout>\n );\n }\n\n if (loading) {\n return (\n <PageLayout title=\"Loading...\">\n <div className=\"h-96 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\" />\n </PageLayout>\n );\n }\n\n if (!connector) {\n return (\n <PageLayout title=\"Connector Not Found\">\n <EmptyState\n illustration=\"empty-notifications\"\n title=\"Connector Not Found\"\n description=\"This channel connector doesn't exist.\"\n action={<Button onClick={() => navigateTo('channels')}>Back to Channels</Button>}\n />\n </PageLayout>\n );\n }\n\n const connectorRoutes =\n routes?.filter((r: { connectorId: string }) => r.connectorId === connector.id) || [];\n const connectorType = toUnion(connector.type, CHANNEL_TYPES, 'CUSTOM');\n const savedWidgetConfig = readWidgetConfig(connector);\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigateTo('channels')}>\n <ArrowLeft size={20} />\n </Button>\n <div className=\"p-2 rounded-lg bg-action-primary-bg/10\">\n <ChannelIcon type={connectorType} />\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <span>{connector.name}</span>\n <StatusBadge status={connector.status} />\n </div>\n <p className=\"text-sm font-normal text-text-secondary\">{connector.description}</p>\n </div>\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n leftIcon={<Plus size={16} />}\n onClick={() => setShowAddRoute(true)}\n >\n Add Route\n </Button>\n {isEditing ? (\n <>\n <Button variant=\"outline\" onClick={() => setIsEditing(false)}>\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleUpdate}\n isLoading={updateConnectorResult.loading}\n >\n Save\n </Button>\n </>\n ) : (\n <>\n <Button variant=\"outline\" leftIcon={<Edit size={16} />} onClick={startEditing}>\n Edit\n </Button>\n {showDeleteConfirm ? (\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowDeleteConfirm(false)}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => {\n nativeImpact('medium');\n void handleDelete();\n }}\n isLoading={deleteConnectorResult.loading}\n >\n Confirm\n </Button>\n </div>\n ) : (\n <Button\n variant=\"destructive\"\n leftIcon={<Trash2 size={16} />}\n onClick={() => setShowDeleteConfirm(true)}\n >\n Delete\n </Button>\n )}\n </>\n )}\n </div>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Radio size={18} />}>\n This connector links Botlit to one messaging platform. From here you add routes — each\n mapping a specific location on the channel (a Slack channel, a widget, a number) to the\n bot that should answer there — tweak the connector’s settings, and manage its\n connection. Set up at least one route so messages on this channel reach a bot.\n </PagePurpose>\n\n <NextSteps\n storageKey={`botlit-channel-${connector.id}`}\n steps={[\n {\n id: 'route',\n label: 'Add a route',\n description: 'Point an incoming location on this channel at one of your bots.',\n icon: <Plus size={16} />,\n onClick: () => setShowAddRoute(true),\n done: connectorRoutes.length > 0,\n },\n {\n id: 'edit',\n label: 'Review connector settings',\n description: 'Confirm the name, visibility and channel-specific configuration.',\n icon: <Settings size={16} />,\n onClick: startEditing,\n },\n {\n id: 'bots',\n label: 'Check your bots',\n description: 'Make sure the bot you are routing to is active and configured.',\n icon: <MessageSquare size={16} />,\n onClick: () => navigateTo('bots'),\n },\n ]}\n />\n\n {/* Add Route Modal */}\n {showAddRoute && (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>Add Route</CardTitle>\n <Button variant=\"ghost\" size=\"icon\" onClick={() => setShowAddRoute(false)}>\n <X size={16} />\n </Button>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Location ID\" required>\n <Input\n placeholder=\"e.g., #general or channel ID\"\n value={newRoute.locationId}\n onChange={(e) => setNewRoute({ ...newRoute, locationId: e.target.value })}\n />\n </FormField>\n <FormField label=\"Location Name\">\n <Input\n placeholder=\"Friendly name (optional)\"\n value={newRoute.locationName}\n onChange={(e) => setNewRoute({ ...newRoute, locationName: e.target.value })}\n />\n </FormField>\n </div>\n <FormField label=\"Connect to Bot\" required>\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={newRoute.botId}\n onChange={(e) => setNewRoute({ ...newRoute, botId: e.target.value })}\n >\n <option value=\"\">Select a bot...</option>\n {bots?.map((bot: { id: string; name: string }) => (\n <option key={bot.id} value={bot.id}>\n {bot.name}\n </option>\n ))}\n </select>\n </FormField>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={() => setShowAddRoute(false)}>\n Cancel\n </Button>\n <Button\n onClick={handleAddRoute}\n isLoading={createRouteResult.loading}\n disabled={!newRoute.locationId || !newRoute.botId}\n >\n Add Route\n </Button>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Edit Form */}\n {isEditing && (\n <Card>\n <CardHeader>\n <CardTitle>Edit Channel</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Connector Name\" required>\n <Input\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n <FormField label=\"Description\">\n <Textarea\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={2}\n />\n </FormField>\n <FormField label=\"Visibility\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.visibility}\n onChange={(e) =>\n setFormData({ ...formData, visibility: e.target.value as Visibility })\n }\n >\n <option value=\"PRIVATE\">Private</option>\n <option value=\"WORKSPACE\">Workspace</option>\n <option value=\"PUBLIC\">Public</option>\n </select>\n </FormField>\n </CardContent>\n </Card>\n )}\n\n {/* Overview Cards */}\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <div className=\"p-3 rounded-full bg-action-primary-bg/10 w-fit mx-auto mb-2\">\n <ChannelIcon type={connectorType} />\n </div>\n <p className=\"text-lg font-bold capitalize\">\n {connector.type.toLowerCase().replace('_', ' ')}\n </p>\n <p className=\"text-sm text-text-secondary\">Channel Type</p>\n </CardContent>\n </Card>\n <GlassCard treatment=\"glass\" glow className=\"p-6 text-center\">\n <p className=\"text-3xl font-bold tabular-nums text-text-primary\">\n {connectorRoutes.length}\n </p>\n <p className=\"text-sm text-text-secondary\">Active Routes</p>\n </GlassCard>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary capitalize\">\n {connector.visibility.toLowerCase()}\n </p>\n <p className=\"text-sm text-text-secondary\">Visibility</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-6 text-center\">\n <p className=\"text-3xl font-bold text-text-primary\">{connector.revision}</p>\n <p className=\"text-sm text-text-secondary\">Revision</p>\n </CardContent>\n </Card>\n </div>\n\n {/* Web Widget Configuration */}\n {savedWidgetConfig && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Palette size={18} />\n Widget Configuration\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-6\">\n <div>\n <p className=\"text-sm text-text-secondary\">Allowed Origins</p>\n {savedWidgetConfig.allowedOrigins.length > 0 ? (\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {savedWidgetConfig.allowedOrigins.map((origin) => (\n <Badge key={origin} variant=\"outline\" className=\"font-mono text-xs\">\n {origin}\n </Badge>\n ))}\n </div>\n ) : (\n <p className=\"font-medium\">Any origin</p>\n )}\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Theme</p>\n <div className=\"flex items-center gap-2 mt-1\">\n <div\n className=\"w-6 h-6 rounded border border-border-subtle\"\n style={{ backgroundColor: savedWidgetConfig.primaryColor }}\n />\n <span className=\"font-mono text-sm\">{savedWidgetConfig.primaryColor}</span>\n </div>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Font Family</p>\n <p className=\"font-medium\">{savedWidgetConfig.fontFamily}</p>\n </div>\n </div>\n {savedWidgetConfig.starterPrompts.length > 0 && (\n <div className=\"mt-4 pt-4 border-t border-border-subtle\">\n <p className=\"text-sm text-text-secondary mb-2\">Starter Prompts</p>\n <div className=\"flex flex-wrap gap-2\">\n {savedWidgetConfig.starterPrompts.map((prompt, i) => (\n <Badge key={i} variant=\"secondary\">\n {prompt}\n </Badge>\n ))}\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n )}\n\n {/* Routes */}\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <div>\n <CardTitle>Routes</CardTitle>\n <CardDescription>Routes connect this channel to your bots</CardDescription>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={<Plus size={14} />}\n onClick={() => setShowAddRoute(true)}\n >\n Add Route\n </Button>\n </CardHeader>\n <CardContent>\n {connectorRoutes.length > 0 ? (\n <div className=\"space-y-3\">\n {connectorRoutes.map(\n (route: {\n id: string;\n locationId: string;\n appId: string;\n revision: number;\n metadata?: Record<string, unknown> | null;\n }) => (\n <div\n key={route.id}\n className=\"flex items-center justify-between p-4 border border-border-subtle rounded-lg\"\n >\n <div className=\"flex items-center gap-4\">\n <div className=\"p-2 rounded-lg bg-bg-sunken\">\n <MessageSquare size={18} className=\"text-text-secondary\" />\n </div>\n <div>\n <p className=\"font-medium\">\n {routeMetadataString(route, 'locationName') ?? route.locationId}\n </p>\n <p className=\"text-sm text-text-secondary\">\n Connected to: {routeMetadataString(route, 'appName') ?? route.appId}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"outline\">Rev {route.revision}</Badge>\n <Button variant=\"ghost\" size=\"sm\">\n <ExternalLink size={14} />\n </Button>\n </div>\n </div>\n )\n )}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No routes configured\"\n description=\"Add a route to connect this channel to a bot.\"\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => setShowAddRoute(true)}>\n Add Route\n </Button>\n }\n />\n )}\n </CardContent>\n </Card>\n\n {/* Slack Personal Account Connect (Phase 7) */}\n {connector.type === 'SLACK' && connector.credentialsRefId && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Slack size={18} />\n Your Slack Account\n </CardTitle>\n <CardDescription>\n Connect your personal Slack account to receive direct messages from this bot\n </CardDescription>\n </CardHeader>\n <CardContent>\n {/* OAuth error banner */}\n {oauthError && (\n <div className=\"mb-4 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>{oauthError}</span>\n <button\n onClick={() => setOauthError(null)}\n className=\"ml-auto cursor-pointer text-status-error-text/70 hover:text-status-error-text\"\n >\n <X size={14} />\n </button>\n </div>\n )}\n\n {/* Linking integration connection */}\n {linking ? (\n <div className=\"flex items-center gap-2 py-4 text-text-secondary\">\n <Loader2 size={16} className=\"animate-spin\" />\n <span className=\"text-sm\">Linking Slack connection...</span>\n </div>\n ) : slackConnectionLoading ? (\n <div className=\"flex items-center gap-2 py-4 text-text-secondary\">\n <Loader2 size={16} className=\"animate-spin\" />\n <span className=\"text-sm\">Checking connection...</span>\n </div>\n ) : slackConnection && slackConnection.dmAllowed ? (\n <div className=\"space-y-4\">\n {/* Connected state */}\n <div className=\"flex items-center gap-3 p-3 rounded-lg bg-bg-sunken\">\n <CheckCircle2 size={20} className=\"text-green-600 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-medium text-sm\">\n {slackConnection.externalDisplayName ||\n slackConnection.externalUsername ||\n slackConnection.externalUserId}\n </p>\n {slackConnection.externalUsername && slackConnection.externalDisplayName && (\n <p className=\"text-xs text-text-secondary\">\n @{slackConnection.externalUsername}\n </p>\n )}\n {slackConnection.connectedAt && (\n <p className=\"text-xs text-text-secondary\">\n Connected {new Date(slackConnection.connectedAt).toLocaleDateString()}\n </p>\n )}\n </div>\n <div className=\"flex items-center gap-1\">\n {slackConnection.isTokenExpired && (\n <Badge\n variant=\"outline\"\n className=\"text-xs text-amber-600 border-amber-400\"\n >\n Token expired\n </Badge>\n )}\n </div>\n </div>\n\n {/* Notification toggle */}\n <div className=\"flex items-center justify-between p-3 border border-border-subtle rounded-lg\">\n <div className=\"flex items-center gap-2\">\n {slackConnection.notificationsEnabled ? (\n <Bell size={16} className=\"text-primary\" />\n ) : (\n <BellOff size={16} 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 {slackConnection.notificationsEnabled\n ? 'You will receive bot DMs'\n : 'DM notifications are paused'}\n </p>\n </div>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleToggleNotifications}\n isLoading={togglingNotifications}\n >\n {slackConnection.notificationsEnabled ? 'Disable' : 'Enable'}\n </Button>\n </div>\n\n {/* Reconnect (if token expired) or Disconnect */}\n <div className=\"flex gap-2 justify-end pt-2\">\n {slackConnection.isTokenExpired && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n leftIcon={<Slack size={14} />}\n onClick={handleSlackConnect}\n >\n Reconnect\n </Button>\n )}\n <Button\n variant=\"destructive\"\n size=\"sm\"\n leftIcon={<Unlink size={14} />}\n onClick={handleRevokeSlack}\n isLoading={revoking}\n >\n Disconnect\n </Button>\n </div>\n </div>\n ) : (\n /* Not connected state */\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 <Slack size={32} className=\"text-text-secondary\" />\n </div>\n <div>\n <p className=\"font-medium\">No personal account connected</p>\n <p className=\"text-sm text-text-secondary mt-1\">\n Connect your Slack account so the bot can send you direct messages\n </p>\n </div>\n <Button leftIcon={<Slack size={16} />} onClick={handleSlackConnect}>\n Connect with Slack\n </Button>\n </div>\n )}\n </CardContent>\n </Card>\n )}\n\n {/* Policy Bindings */}\n {connector.defaultPolicyBindings && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Shield size={18} />\n Default Policy Bindings\n </CardTitle>\n <CardDescription>\n Default policies applied to all routes on this connector\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-4\">\n {Object.entries(connector.defaultPolicyBindings).map(([key, value]) =>\n value ? (\n <div key={key} className=\"p-3 bg-bg-sunken rounded-lg\">\n <p className=\"text-xs text-text-secondary capitalize\">\n {key.replace('PolicyId', '').replace(/([A-Z])/g, ' $1')}\n </p>\n <p className=\"font-medium text-sm truncate\">{String(value)}</p>\n </div>\n ) : null\n )}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Metadata */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Settings size={18} />\n Metadata\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-6 text-sm\">\n <div>\n <p className=\"text-text-secondary\">Created</p>\n <p className=\"font-medium\">{formatRelativeTime(connector.createdAt)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Updated</p>\n <p className=\"font-medium\">{formatRelativeTime(connector.updatedAt)}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Credentials</p>\n <p className=\"font-medium\">{connector.credentialsRefId || 'Not configured'}</p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Tags</p>\n <div className=\"flex gap-1\">\n {connector.tags.length > 0 ? (\n connector.tags.map((tag: string) => (\n <Badge key={tag} variant=\"secondary\" className=\"text-xs\">\n {tag}\n </Badge>\n ))\n ) : (\n <span className=\"text-text-secondary\">None</span>\n )}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { useBotlit as e } from "../providers/BotlitProvider.js";
|
|
2
|
+
import { useBots as t } from "../hooks/useBots.js";
|
|
3
|
+
import { formatRelativeTime as n } from "../utils/formatters.js";
|
|
4
|
+
import { PageLayout as r } from "../components/PageLayout.js";
|
|
5
|
+
import { Card as i, CardContent as a } from "../components/Card.js";
|
|
6
|
+
import { Button as o } from "../components/Button.js";
|
|
7
|
+
import { Badge as s } from "../components/Badge.js";
|
|
8
|
+
import { EmptyState as c } from "../components/EmptyState.js";
|
|
9
|
+
import { Input as l } from "../components/Input.js";
|
|
10
|
+
import { ErrorState as u } from "../components/ErrorState.js";
|
|
11
|
+
import { routeMetadataString as d, useChannelConnectors as f, useChannelRoutes as p } from "../hooks/useChannels.js";
|
|
12
|
+
import "../hooks/index.js";
|
|
13
|
+
import { useState as m } from "react";
|
|
14
|
+
import { GlassCard as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
|
|
15
|
+
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
16
|
+
import { Link as y } from "react-router";
|
|
17
|
+
import { AppWindow as b, ExternalLink as x, Filter as S, MessageSquare as C, Plus as w, Radio as T, Route as E, Search as D } from "lucide-react";
|
|
18
|
+
//#region src/botlit/pages/ChannelRoutesPage.tsx
|
|
19
|
+
var O = () => {
|
|
20
|
+
let { navigateTo: O, getPath: k } = e(), [A, j] = m(""), { data: M, loading: N, error: P, refetch: F } = p(), { data: I } = f(), { data: L } = t(), R = (e) => I?.find((t) => t.id === e)?.name || e, z = (e) => L?.find((t) => t.id === e)?.name || e, B = M.filter((e) => {
|
|
21
|
+
if (!A) return !0;
|
|
22
|
+
let t = A.toLowerCase(), n = d(e, "locationName");
|
|
23
|
+
return e.locationId.toLowerCase().includes(t) || (n?.toLowerCase().includes(t) ?? !1) || R(e.connectorId).toLowerCase().includes(t) || z(e.appId).toLowerCase().includes(t);
|
|
24
|
+
});
|
|
25
|
+
return /* @__PURE__ */ _(r, {
|
|
26
|
+
title: "Channel Routes",
|
|
27
|
+
description: "Manage connections between channels and bots",
|
|
28
|
+
actions: /* @__PURE__ */ v("div", {
|
|
29
|
+
className: "flex gap-2",
|
|
30
|
+
children: [/* @__PURE__ */ _(o, {
|
|
31
|
+
variant: "outline",
|
|
32
|
+
onClick: () => O("channels"),
|
|
33
|
+
children: "View Connectors"
|
|
34
|
+
}), /* @__PURE__ */ _(o, {
|
|
35
|
+
leftIcon: /* @__PURE__ */ _(w, { size: 16 }),
|
|
36
|
+
children: "Create Route"
|
|
37
|
+
})]
|
|
38
|
+
}),
|
|
39
|
+
children: /* @__PURE__ */ v("div", {
|
|
40
|
+
className: "space-y-6",
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ _(g, {
|
|
43
|
+
icon: /* @__PURE__ */ _(E, { size: 18 }),
|
|
44
|
+
children: "A route is the rule that decides which bot answers an incoming message. It maps a specific location on a channel connector — a Slack channel, a website widget, a WhatsApp number — to one of your bots, and can attach policy bindings and routing overrides. Manage those mappings here so the right conversation always reaches the right bot."
|
|
45
|
+
}),
|
|
46
|
+
M.length > 0 ? /* @__PURE__ */ v("div", {
|
|
47
|
+
className: "grid grid-cols-2 gap-4 sm:grid-cols-3",
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ v(h, {
|
|
50
|
+
treatment: "glass",
|
|
51
|
+
glow: !0,
|
|
52
|
+
className: "p-4",
|
|
53
|
+
children: [/* @__PURE__ */ _("p", {
|
|
54
|
+
className: "text-sm text-text-secondary",
|
|
55
|
+
children: "Active routes"
|
|
56
|
+
}), /* @__PURE__ */ _("p", {
|
|
57
|
+
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
58
|
+
children: M.length
|
|
59
|
+
})]
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ v(h, {
|
|
62
|
+
treatment: "metric",
|
|
63
|
+
className: "p-4",
|
|
64
|
+
children: [/* @__PURE__ */ _("p", {
|
|
65
|
+
className: "text-sm text-text-secondary",
|
|
66
|
+
children: "Connectors used"
|
|
67
|
+
}), /* @__PURE__ */ _("p", {
|
|
68
|
+
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
69
|
+
children: new Set(M.map((e) => e.connectorId)).size
|
|
70
|
+
})]
|
|
71
|
+
}),
|
|
72
|
+
/* @__PURE__ */ v(h, {
|
|
73
|
+
treatment: "metric",
|
|
74
|
+
className: "col-span-2 p-4 sm:col-span-1",
|
|
75
|
+
children: [/* @__PURE__ */ _("p", {
|
|
76
|
+
className: "text-sm text-text-secondary",
|
|
77
|
+
children: "Bots routed to"
|
|
78
|
+
}), /* @__PURE__ */ _("p", {
|
|
79
|
+
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
80
|
+
children: new Set(M.map((e) => e.appId)).size
|
|
81
|
+
})]
|
|
82
|
+
})
|
|
83
|
+
]
|
|
84
|
+
}) : null,
|
|
85
|
+
/* @__PURE__ */ v("div", {
|
|
86
|
+
className: "flex items-center gap-4",
|
|
87
|
+
children: [/* @__PURE__ */ v("div", {
|
|
88
|
+
className: "relative flex-1 max-w-md",
|
|
89
|
+
children: [/* @__PURE__ */ _(D, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ _(l, {
|
|
90
|
+
placeholder: "Search routes...",
|
|
91
|
+
value: A,
|
|
92
|
+
onChange: (e) => j(e.target.value),
|
|
93
|
+
className: "pl-9"
|
|
94
|
+
})]
|
|
95
|
+
}), /* @__PURE__ */ _(o, {
|
|
96
|
+
variant: "outline",
|
|
97
|
+
leftIcon: /* @__PURE__ */ _(S, { size: 16 }),
|
|
98
|
+
children: "Filters"
|
|
99
|
+
})]
|
|
100
|
+
}),
|
|
101
|
+
N ? /* @__PURE__ */ _("div", {
|
|
102
|
+
className: "space-y-3",
|
|
103
|
+
children: [
|
|
104
|
+
1,
|
|
105
|
+
2,
|
|
106
|
+
3,
|
|
107
|
+
4
|
|
108
|
+
].map((e) => /* @__PURE__ */ _("div", { className: "h-24 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
|
|
109
|
+
}) : P ? /* @__PURE__ */ _(u, {
|
|
110
|
+
resource: "channel routes",
|
|
111
|
+
error: P,
|
|
112
|
+
onRetry: () => void F()
|
|
113
|
+
}) : B.length > 0 ? /* @__PURE__ */ _("div", {
|
|
114
|
+
className: "space-y-3",
|
|
115
|
+
children: B.map((e) => /* @__PURE__ */ _(i, {
|
|
116
|
+
className: "hover:shadow-md transition-shadow",
|
|
117
|
+
children: /* @__PURE__ */ v(a, {
|
|
118
|
+
className: "py-4",
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ v("div", {
|
|
121
|
+
className: "flex items-center justify-between",
|
|
122
|
+
children: [/* @__PURE__ */ v("div", {
|
|
123
|
+
className: "flex items-center gap-4",
|
|
124
|
+
children: [/* @__PURE__ */ _("div", {
|
|
125
|
+
className: "p-3 rounded-lg bg-action-primary-bg/10",
|
|
126
|
+
children: /* @__PURE__ */ _(E, { className: "h-5 w-5 text-primary" })
|
|
127
|
+
}), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ v("div", {
|
|
128
|
+
className: "flex items-center gap-2",
|
|
129
|
+
children: [/* @__PURE__ */ _("h3", {
|
|
130
|
+
className: "font-medium text-text-primary",
|
|
131
|
+
children: d(e, "locationName") ?? e.locationId
|
|
132
|
+
}), /* @__PURE__ */ v(s, {
|
|
133
|
+
variant: "outline",
|
|
134
|
+
children: ["Rev ", e.revision]
|
|
135
|
+
})]
|
|
136
|
+
}), /* @__PURE__ */ v("div", {
|
|
137
|
+
className: "flex items-center gap-4 mt-1 text-sm text-text-secondary",
|
|
138
|
+
children: [
|
|
139
|
+
/* @__PURE__ */ v("span", {
|
|
140
|
+
className: "flex items-center gap-1",
|
|
141
|
+
children: [/* @__PURE__ */ _(T, { size: 14 }), R(e.connectorId)]
|
|
142
|
+
}),
|
|
143
|
+
/* @__PURE__ */ v("span", {
|
|
144
|
+
className: "flex items-center gap-1",
|
|
145
|
+
children: [/* @__PURE__ */ _(b, { size: 14 }), z(e.appId)]
|
|
146
|
+
}),
|
|
147
|
+
/* @__PURE__ */ v("span", {
|
|
148
|
+
className: "flex items-center gap-1",
|
|
149
|
+
children: [/* @__PURE__ */ _(C, { size: 14 }), e.locationId]
|
|
150
|
+
})
|
|
151
|
+
]
|
|
152
|
+
})] })]
|
|
153
|
+
}), /* @__PURE__ */ v("div", {
|
|
154
|
+
className: "flex items-center gap-3",
|
|
155
|
+
children: [/* @__PURE__ */ _("span", {
|
|
156
|
+
className: "text-sm text-text-secondary",
|
|
157
|
+
children: n(e.updatedAt)
|
|
158
|
+
}), /* @__PURE__ */ v("div", {
|
|
159
|
+
className: "flex gap-2",
|
|
160
|
+
children: [/* @__PURE__ */ _(y, {
|
|
161
|
+
to: k(`channels/${e.connectorId}`),
|
|
162
|
+
children: /* @__PURE__ */ _(o, {
|
|
163
|
+
variant: "ghost",
|
|
164
|
+
size: "sm",
|
|
165
|
+
children: /* @__PURE__ */ _(x, { size: 14 })
|
|
166
|
+
})
|
|
167
|
+
}), /* @__PURE__ */ _(y, {
|
|
168
|
+
to: k(`bots/${e.appId}`),
|
|
169
|
+
children: /* @__PURE__ */ _(o, {
|
|
170
|
+
variant: "ghost",
|
|
171
|
+
size: "sm",
|
|
172
|
+
children: "View Bot"
|
|
173
|
+
})
|
|
174
|
+
})]
|
|
175
|
+
})]
|
|
176
|
+
})]
|
|
177
|
+
}),
|
|
178
|
+
e.policyBindings && Object.values(e.policyBindings).some(Boolean) && /* @__PURE__ */ v("div", {
|
|
179
|
+
className: "mt-3 pt-3 border-t border-border-subtle",
|
|
180
|
+
children: [/* @__PURE__ */ _("p", {
|
|
181
|
+
className: "text-xs text-text-secondary mb-2",
|
|
182
|
+
children: "Policy Bindings"
|
|
183
|
+
}), /* @__PURE__ */ _("div", {
|
|
184
|
+
className: "flex gap-2",
|
|
185
|
+
children: Object.entries(e.policyBindings).map(([e, t]) => t ? /* @__PURE__ */ _(s, {
|
|
186
|
+
variant: "secondary",
|
|
187
|
+
className: "text-xs",
|
|
188
|
+
children: e.replace("PolicyId", "")
|
|
189
|
+
}, e) : null)
|
|
190
|
+
})]
|
|
191
|
+
}),
|
|
192
|
+
Array.isArray(e.routingOverrides) && e.routingOverrides.length > 0 && /* @__PURE__ */ _("div", {
|
|
193
|
+
className: "mt-3 pt-3 border-t border-border-subtle",
|
|
194
|
+
children: /* @__PURE__ */ v("p", {
|
|
195
|
+
className: "text-xs text-text-secondary mb-2",
|
|
196
|
+
children: [e.routingOverrides.length, " routing override(s)"]
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
]
|
|
200
|
+
})
|
|
201
|
+
}, e.id))
|
|
202
|
+
}) : /* @__PURE__ */ _(c, {
|
|
203
|
+
illustration: "empty-search",
|
|
204
|
+
title: "No routes found",
|
|
205
|
+
description: A ? "No routes match your search criteria." : "Create a route to connect a channel to a bot.",
|
|
206
|
+
action: /* @__PURE__ */ _(o, {
|
|
207
|
+
leftIcon: /* @__PURE__ */ _(w, { size: 16 }),
|
|
208
|
+
children: "Create Route"
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
]
|
|
212
|
+
})
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
//#endregion
|
|
216
|
+
export { O as ChannelRoutesPage };
|
|
217
|
+
|
|
218
|
+
//# sourceMappingURL=ChannelRoutesPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChannelRoutesPage.js","names":[],"sources":["../../../src/botlit/pages/ChannelRoutesPage.tsx"],"sourcesContent":["/**\n * Channel Routes Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Link } from 'react-router';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n Search,\n Plus,\n Route,\n MessageSquare,\n AppWindow,\n Radio,\n Filter,\n ExternalLink,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input } from '../components/Input';\nimport { Badge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useChannelConnectors, useChannelRoutes, useBots, routeMetadataString } from '../hooks';\nimport { ErrorState } from '../components/ErrorState';\nimport { formatRelativeTime } from '../utils/formatters';\n\nexport const ChannelRoutesPage: FC = () => {\n const { navigateTo, getPath } = useBotlit();\n const [search, setSearch] = useState('');\n const { data: routes, loading, error, refetch } = useChannelRoutes();\n const { data: connectors } = useChannelConnectors();\n const { data: bots } = useBots();\n\n const getConnectorName = (connectorId: string) =>\n connectors?.find((c: { id: string; name: string }) => c.id === connectorId)?.name ||\n connectorId;\n\n const getBotName = (botId: string) =>\n bots?.find((a: { id: string; name: string }) => a.id === botId)?.name || botId;\n\n const filteredRoutes = routes.filter((route) => {\n if (!search) return true;\n const searchLower = search.toLowerCase();\n const locationName = routeMetadataString(route, 'locationName');\n return (\n route.locationId.toLowerCase().includes(searchLower) ||\n (locationName?.toLowerCase().includes(searchLower) ?? false) ||\n getConnectorName(route.connectorId).toLowerCase().includes(searchLower) ||\n getBotName(route.appId).toLowerCase().includes(searchLower)\n );\n });\n\n return (\n <PageLayout\n title=\"Channel Routes\"\n description=\"Manage connections between channels and bots\"\n actions={\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" onClick={() => navigateTo('channels')}>\n View Connectors\n </Button>\n <Button leftIcon={<Plus size={16} />}>Create Route</Button>\n </div>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Route size={18} />}>\n A route is the rule that decides which bot answers an incoming message. It maps a specific\n location on a channel connector — a Slack channel, a website widget, a WhatsApp number —\n to one of your bots, and can attach policy bindings and routing overrides. Manage those\n mappings here so the right conversation always reaches the right bot.\n </PagePurpose>\n\n {/* Summary */}\n {routes.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <GlassCard treatment=\"glass\" glow className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">Active routes</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {routes.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">Connectors used</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {new Set(routes.map((r) => r.connectorId)).size}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"col-span-2 p-4 sm:col-span-1\">\n <p className=\"text-sm text-text-secondary\">Bots routed to</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {new Set(routes.map((r) => r.appId)).size}\n </p>\n </GlassCard>\n </div>\n ) : null}\n\n {/* Toolbar */}\n <div className=\"flex items-center gap-4\">\n <div className=\"relative flex-1 max-w-md\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search routes...\"\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 {/* Routes List */}\n {loading ? (\n <div className=\"space-y-3\">\n {[1, 2, 3, 4].map((i) => (\n <div\n key={i}\n className=\"h-24 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : error ? (\n <ErrorState resource=\"channel routes\" error={error} onRetry={() => void refetch()} />\n ) : filteredRoutes.length > 0 ? (\n <div className=\"space-y-3\">\n {filteredRoutes.map((route) => (\n <Card key={route.id} className=\"hover:shadow-md transition-shadow\">\n <CardContent className=\"py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-3 rounded-lg bg-action-primary-bg/10\">\n <Route className=\"h-5 w-5 text-primary\" />\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-medium text-text-primary\">\n {routeMetadataString(route, 'locationName') ?? route.locationId}\n </h3>\n <Badge variant=\"outline\">Rev {route.revision}</Badge>\n </div>\n <div className=\"flex items-center gap-4 mt-1 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Radio size={14} />\n {getConnectorName(route.connectorId)}\n </span>\n <span className=\"flex items-center gap-1\">\n <AppWindow size={14} />\n {getBotName(route.appId)}\n </span>\n <span className=\"flex items-center gap-1\">\n <MessageSquare size={14} />\n {route.locationId}\n </span>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <span className=\"text-sm text-text-secondary\">\n {formatRelativeTime(route.updatedAt)}\n </span>\n <div className=\"flex gap-2\">\n <Link to={getPath(`channels/${route.connectorId}`)}>\n <Button variant=\"ghost\" size=\"sm\">\n <ExternalLink size={14} />\n </Button>\n </Link>\n <Link to={getPath(`bots/${route.appId}`)}>\n <Button variant=\"ghost\" size=\"sm\">\n View Bot\n </Button>\n </Link>\n </div>\n </div>\n </div>\n\n {/* Policy Bindings */}\n {route.policyBindings && Object.values(route.policyBindings).some(Boolean) && (\n <div className=\"mt-3 pt-3 border-t border-border-subtle\">\n <p className=\"text-xs text-text-secondary mb-2\">Policy Bindings</p>\n <div className=\"flex gap-2\">\n {Object.entries(route.policyBindings).map(([key, value]) =>\n value ? (\n <Badge key={key} variant=\"secondary\" className=\"text-xs\">\n {key.replace('PolicyId', '')}\n </Badge>\n ) : null\n )}\n </div>\n </div>\n )}\n\n {/* Routing Overrides */}\n {Array.isArray(route.routingOverrides) && route.routingOverrides.length > 0 && (\n <div className=\"mt-3 pt-3 border-t border-border-subtle\">\n <p className=\"text-xs text-text-secondary mb-2\">\n {route.routingOverrides.length} routing override(s)\n </p>\n </div>\n )}\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n title=\"No routes found\"\n description={\n search\n ? 'No routes match your search criteria.'\n : 'Create a route to connect a channel to a bot.'\n }\n action={<Button leftIcon={<Plus size={16} />}>Create Route</Button>}\n />\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|