@burdenoff/microfe-botmanor 2026.1110.2 → 2026.1110.4
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/dist/botlit/BotlitRoutes.js +130 -126
- package/dist/botlit/BotlitRoutes.js.map +1 -1
- package/dist/botlit/components/HandoffConfigPanel.d.ts +4 -0
- package/dist/botlit/components/HandoffConfigPanel.js +286 -0
- package/dist/botlit/components/HandoffConfigPanel.js.map +1 -0
- package/dist/botlit/hooks/index.d.ts +2 -0
- package/dist/botlit/hooks/index.js +2 -1
- package/dist/botlit/hooks/useHandoffs.d.ts +78 -0
- package/dist/botlit/hooks/useHandoffs.js +78 -0
- package/dist/botlit/hooks/useHandoffs.js.map +1 -0
- package/dist/botlit/pages/AgentDetailPage.js +281 -271
- package/dist/botlit/pages/AgentDetailPage.js.map +1 -1
- package/dist/botlit/pages/DashboardPage.js +58 -50
- package/dist/botlit/pages/DashboardPage.js.map +1 -1
- package/dist/botlit/pages/HandoffsPage.d.ts +2 -0
- package/dist/botlit/pages/HandoffsPage.js +212 -0
- package/dist/botlit/pages/HandoffsPage.js.map +1 -0
- package/dist/generated/wspace-operations.d.ts +484 -8
- package/dist/generated/wspace-operations.js +223 -49
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.d.ts +47941 -9371
- package/dist/generated/wspace-types.js +7 -3
- package/dist/generated/wspace-types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage.js","names":["_Fragment","DashboardPage","t","useTr","useBotlit","bots","botsLoading","useBots","agents","agentsLoading","useAgents","stats","AppWindow","a","Bot","firstName","currentUser","PageLayout","Fragment","GradientText","BotmanorPermissionGate","BOTMANOR_PERMISSIONS","Button","Plus","navigateTo","PagePurpose","Zap","Card","stat","CardContent","CardHeader","CardTitle","ArrowRight","i","Link","getPath","bot","StatusBadge","agent","formatNumber","GlassCard","BookOpen"],"sources":["../../../src/botlit/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { Link } from 'react-router';\nimport { AppWindow, Bot, BookOpen, Zap, ArrowRight, Plus } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { GradientText, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { StatusBadge } from '../components/Badge';\nimport { useBots } from '../hooks/useBots';\nimport { useAgents } from '../hooks/useAgents';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { formatNumber } from '../utils/formatters';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\nexport const DashboardPage: FC = () => {\n const t = useTr();\n const { currentUser, navigateTo, getPath } = useBotlit();\n const { data: bots, loading: botsLoading } = useBots();\n const { data: agents, loading: agentsLoading } = useAgents();\n\n const stats = [\n {\n label: t('botlit.dashboard.stats.totalBots', 'Total Bots'),\n value: bots?.length || 0,\n icon: <AppWindow className=\"h-5 w-5\" />,\n hero: true,\n },\n {\n label: t('botlit.dashboard.stats.activeAgents', 'Active Agents'),\n value: agents?.filter((a: { status: string }) => a.status === 'ACTIVE').length || 0,\n icon: <Bot className=\"h-5 w-5\" />,\n hero: false,\n },\n ];\n\n const firstName = currentUser?.name ? currentUser.name.split(' ')[0] : '';\n\n return (\n <PageLayout\n hero\n title={\n <>\n {t('botlit.dashboard.title', 'Welcome back')}\n {firstName ? (\n <>\n , <GradientText>{firstName}</GradientText>\n </>\n ) : null}\n </>\n }\n description={t(\n 'botlit.dashboard.description',\n \"Here's an overview of your AI agents and bots\"\n )}\n actions={\n <div className=\"flex gap-2\">\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.APP_CREATE}>\n <Button\n variant=\"outline\"\n leftIcon={<Plus size={16} />}\n onClick={() => navigateTo('bots/new')}\n >\n {t('botlit.dashboard.actions.newBot', 'New Bot')}\n </Button>\n </BotmanorPermissionGate>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.AGENT_CREATE}>\n <Button leftIcon={<Bot size={16} />} onClick={() => navigateTo('agents/new')}>\n {t('botlit.dashboard.actions.createAgent', 'Create Agent')}\n </Button>\n </BotmanorPermissionGate>\n </div>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Zap size={18} />}>\n {t(\n 'botlit.dashboard.purpose',\n 'This is your home base — a quick pulse on every bot and agent in your workspace. Glance at the headline numbers, jump back into recent work, and use the quick actions below to start something new. If you are just getting started, create your first agent and connect it to a bot.'\n )}\n </PagePurpose>\n\n {/* Stats Grid */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {stats.map((stat) => (\n <Card key={stat.label} treatment={stat.hero ? 'glass' : 'metric'} glow={stat.hero}>\n <CardContent className=\"pt-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-3 rounded-lg bg-[var(--color-accent-soft)] text-text-primary [&>svg]:text-text-primary\">\n {stat.icon}\n </div>\n <div>\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">\n {stat.value}\n </p>\n <p className=\"text-sm text-text-secondary\">{stat.label}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n {/* Main Content Grid */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Recent Bots */}\n <Card treatment=\"insight\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>{t('botlit.dashboard.recentBots.title', 'Recent Bots')}</CardTitle>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n rightIcon={<ArrowRight size={16} />}\n onClick={() => navigateTo('bots')}\n >\n {t('botlit.common.viewAll', 'View All')}\n </Button>\n </CardHeader>\n <CardContent>\n {botsLoading ? (\n <div className=\"space-y-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-16 bg-bg-sunken rounded-lg motion-safe:animate-vc-shimmer\"\n />\n ))}\n </div>\n ) : bots && bots.length > 0 ? (\n <div className=\"space-y-3\">\n {bots.slice(0, 4).map((bot) => (\n <Link\n key={bot.id}\n to={getPath(`bots/${bot.id}`)}\n className=\"flex items-center justify-between p-3 rounded-lg border border-border-seam hover:border-border-strong hover:bg-accent transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"text-2xl\">{bot.icon || '🤖'}</span>\n <div>\n <p className=\"font-medium text-text-primary\">{bot.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {bot.executionCount || 0} {t('botlit.common.executions', 'executions')}\n </p>\n </div>\n </div>\n <StatusBadge status={bot.status} />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-8 text-text-secondary\">\n <AppWindow className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>{t('botlit.dashboard.recentBots.emptyTitle', 'No bots yet')}</p>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.APP_CREATE}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => navigateTo('bots/new')}\n >\n {t('botlit.dashboard.recentBots.emptyAction', 'Create your first bot')}\n </Button>\n </BotmanorPermissionGate>\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Active Agents */}\n <Card treatment=\"insight\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>{t('botlit.dashboard.activeAgents.title', 'Active Agents')}</CardTitle>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n rightIcon={<ArrowRight size={16} />}\n onClick={() => navigateTo('agents')}\n >\n {t('botlit.common.viewAll', 'View All')}\n </Button>\n </CardHeader>\n <CardContent>\n {agentsLoading ? (\n <div className=\"space-y-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-16 bg-bg-sunken rounded-lg motion-safe:animate-vc-shimmer\"\n />\n ))}\n </div>\n ) : agents && agents.length > 0 ? (\n <div className=\"space-y-3\">\n {agents\n .filter((a) => a.status === 'ACTIVE')\n .slice(0, 4)\n .map((agent) => (\n <Link\n key={agent.id}\n to={getPath(`agents/${agent.id}`)}\n className=\"flex items-center justify-between p-3 rounded-lg border border-border-seam hover:border-border-strong hover:bg-accent transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"relative text-2xl\">\n 🤖\n <span className=\"absolute -right-0.5 -top-0.5 size-2 rounded-full bg-status-success-text motion-safe:animate-vc-glow-pulse\" />\n </span>\n <div>\n <p className=\"font-medium text-text-primary\">{agent.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {formatNumber(agent.executionCount ?? 0)}{' '}\n {t('botlit.common.executions', 'executions')}\n </p>\n </div>\n </div>\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-8 text-text-secondary\">\n <Bot className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>{t('botlit.dashboard.activeAgents.emptyTitle', 'No active agents')}</p>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.AGENT_CREATE}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => navigateTo('agents/new')}\n >\n {t('botlit.dashboard.activeAgents.emptyAction', 'Create your first agent')}\n </Button>\n </BotmanorPermissionGate>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* Quick Actions */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n {t('botlit.dashboard.quickActions.title', 'Quick Actions')}\n </h2>\n <div className=\"mt-4 grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Link\n to={getPath('bots/new')}\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <AppWindow className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.createBot', 'Create Bot')}\n </span>\n </Link>\n <Link\n to={getPath('agents/new')}\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <Bot className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.buildAgent', 'Build Agent')}\n </span>\n </Link>\n <Link\n to={getPath('knowledge/new')}\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <BookOpen className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.addKnowledge', 'Add Knowledge')}\n </span>\n </Link>\n <a\n href=\"/conversations\"\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <Zap className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.quickChat', 'Quick Chat')}\n </span>\n </a>\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage.js","names":["_Fragment","DashboardPage","t","useTr","useBotlit","bots","botsLoading","useBots","agents","agentsLoading","useAgents","stats","AppWindow","a","Bot","firstName","currentUser","PageLayout","Fragment","GradientText","BotmanorPermissionGate","BOTMANOR_PERMISSIONS","Button","Plus","navigateTo","PagePurpose","Zap","Card","stat","CardContent","CardHeader","CardTitle","ArrowRight","i","Link","getPath","bot","StatusBadge","agent","formatNumber","GlassCard","BookOpen","Headset"],"sources":["../../../src/botlit/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { Link } from 'react-router';\nimport { AppWindow, Bot, BookOpen, Zap, ArrowRight, Plus, Headset } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { GradientText, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { StatusBadge } from '../components/Badge';\nimport { useBots } from '../hooks/useBots';\nimport { useAgents } from '../hooks/useAgents';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { formatNumber } from '../utils/formatters';\nimport { BOTMANOR_PERMISSIONS, BotmanorPermissionGate } from '../permissions';\n\nexport const DashboardPage: FC = () => {\n const t = useTr();\n const { currentUser, navigateTo, getPath } = useBotlit();\n const { data: bots, loading: botsLoading } = useBots();\n const { data: agents, loading: agentsLoading } = useAgents();\n\n const stats = [\n {\n label: t('botlit.dashboard.stats.totalBots', 'Total Bots'),\n value: bots?.length || 0,\n icon: <AppWindow className=\"h-5 w-5\" />,\n hero: true,\n },\n {\n label: t('botlit.dashboard.stats.activeAgents', 'Active Agents'),\n value: agents?.filter((a: { status: string }) => a.status === 'ACTIVE').length || 0,\n icon: <Bot className=\"h-5 w-5\" />,\n hero: false,\n },\n ];\n\n const firstName = currentUser?.name ? currentUser.name.split(' ')[0] : '';\n\n return (\n <PageLayout\n hero\n title={\n <>\n {t('botlit.dashboard.title', 'Welcome back')}\n {firstName ? (\n <>\n , <GradientText>{firstName}</GradientText>\n </>\n ) : null}\n </>\n }\n description={t(\n 'botlit.dashboard.description',\n \"Here's an overview of your AI agents and bots\"\n )}\n actions={\n <div className=\"flex gap-2\">\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.APP_CREATE}>\n <Button\n variant=\"outline\"\n leftIcon={<Plus size={16} />}\n onClick={() => navigateTo('bots/new')}\n >\n {t('botlit.dashboard.actions.newBot', 'New Bot')}\n </Button>\n </BotmanorPermissionGate>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.AGENT_CREATE}>\n <Button leftIcon={<Bot size={16} />} onClick={() => navigateTo('agents/new')}>\n {t('botlit.dashboard.actions.createAgent', 'Create Agent')}\n </Button>\n </BotmanorPermissionGate>\n </div>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Zap size={18} />}>\n {t(\n 'botlit.dashboard.purpose',\n 'This is your home base — a quick pulse on every bot and agent in your workspace. Glance at the headline numbers, jump back into recent work, and use the quick actions below to start something new. If you are just getting started, create your first agent and connect it to a bot.'\n )}\n </PagePurpose>\n\n {/* Stats Grid */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {stats.map((stat) => (\n <Card key={stat.label} treatment={stat.hero ? 'glass' : 'metric'} glow={stat.hero}>\n <CardContent className=\"pt-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"p-3 rounded-lg bg-[var(--color-accent-soft)] text-text-primary [&>svg]:text-text-primary\">\n {stat.icon}\n </div>\n <div>\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">\n {stat.value}\n </p>\n <p className=\"text-sm text-text-secondary\">{stat.label}</p>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n {/* Main Content Grid */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Recent Bots */}\n <Card treatment=\"insight\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>{t('botlit.dashboard.recentBots.title', 'Recent Bots')}</CardTitle>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n rightIcon={<ArrowRight size={16} />}\n onClick={() => navigateTo('bots')}\n >\n {t('botlit.common.viewAll', 'View All')}\n </Button>\n </CardHeader>\n <CardContent>\n {botsLoading ? (\n <div className=\"space-y-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-16 bg-bg-sunken rounded-lg motion-safe:animate-vc-shimmer\"\n />\n ))}\n </div>\n ) : bots && bots.length > 0 ? (\n <div className=\"space-y-3\">\n {bots.slice(0, 4).map((bot) => (\n <Link\n key={bot.id}\n to={getPath(`bots/${bot.id}`)}\n className=\"flex items-center justify-between p-3 rounded-lg border border-border-seam hover:border-border-strong hover:bg-accent transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"text-2xl\">{bot.icon || '🤖'}</span>\n <div>\n <p className=\"font-medium text-text-primary\">{bot.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {bot.executionCount || 0} {t('botlit.common.executions', 'executions')}\n </p>\n </div>\n </div>\n <StatusBadge status={bot.status} />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-8 text-text-secondary\">\n <AppWindow className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>{t('botlit.dashboard.recentBots.emptyTitle', 'No bots yet')}</p>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.APP_CREATE}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => navigateTo('bots/new')}\n >\n {t('botlit.dashboard.recentBots.emptyAction', 'Create your first bot')}\n </Button>\n </BotmanorPermissionGate>\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Active Agents */}\n <Card treatment=\"insight\">\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>{t('botlit.dashboard.activeAgents.title', 'Active Agents')}</CardTitle>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n rightIcon={<ArrowRight size={16} />}\n onClick={() => navigateTo('agents')}\n >\n {t('botlit.common.viewAll', 'View All')}\n </Button>\n </CardHeader>\n <CardContent>\n {agentsLoading ? (\n <div className=\"space-y-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-16 bg-bg-sunken rounded-lg motion-safe:animate-vc-shimmer\"\n />\n ))}\n </div>\n ) : agents && agents.length > 0 ? (\n <div className=\"space-y-3\">\n {agents\n .filter((a) => a.status === 'ACTIVE')\n .slice(0, 4)\n .map((agent) => (\n <Link\n key={agent.id}\n to={getPath(`agents/${agent.id}`)}\n className=\"flex items-center justify-between p-3 rounded-lg border border-border-seam hover:border-border-strong hover:bg-accent transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"relative text-2xl\">\n 🤖\n <span className=\"absolute -right-0.5 -top-0.5 size-2 rounded-full bg-status-success-text motion-safe:animate-vc-glow-pulse\" />\n </span>\n <div>\n <p className=\"font-medium text-text-primary\">{agent.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {formatNumber(agent.executionCount ?? 0)}{' '}\n {t('botlit.common.executions', 'executions')}\n </p>\n </div>\n </div>\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-8 text-text-secondary\">\n <Bot className=\"h-8 w-8 mx-auto mb-2 opacity-50\" />\n <p>{t('botlit.dashboard.activeAgents.emptyTitle', 'No active agents')}</p>\n <BotmanorPermissionGate permission={BOTMANOR_PERMISSIONS.AGENT_CREATE}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-3\"\n onClick={() => navigateTo('agents/new')}\n >\n {t('botlit.dashboard.activeAgents.emptyAction', 'Create your first agent')}\n </Button>\n </BotmanorPermissionGate>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n\n {/* Quick Actions */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n {t('botlit.dashboard.quickActions.title', 'Quick Actions')}\n </h2>\n <div className=\"mt-4 grid grid-cols-2 md:grid-cols-4 gap-4\">\n <Link\n to={getPath('bots/new')}\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <AppWindow className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.createBot', 'Create Bot')}\n </span>\n </Link>\n <Link\n to={getPath('agents/new')}\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <Bot className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.buildAgent', 'Build Agent')}\n </span>\n </Link>\n <Link\n to={getPath('knowledge/new')}\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <BookOpen className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.addKnowledge', 'Add Knowledge')}\n </span>\n </Link>\n <a\n href=\"/conversations\"\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <Zap className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.quickChat', 'Quick Chat')}\n </span>\n </a>\n <Link\n to={getPath('handoffs')}\n className=\"flex flex-col items-center gap-2 p-4 rounded-card border border-border-seam bg-bg-surface hover:border-border-strong hover:shadow-elevation-2 transition-[box-shadow,border-color]\"\n >\n <Headset className=\"h-8 w-8 text-text-secondary\" />\n <span className=\"text-sm font-medium\">\n {t('botlit.dashboard.quickActions.handoffs', 'Human Handoffs')}\n </span>\n </Link>\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { useAgents as t } from "../hooks/useAgents.js";
|
|
3
|
+
import { PageLayout as n } from "../components/PageLayout.js";
|
|
4
|
+
import { Card as r, CardContent as i, CardDescription as a, CardHeader as o, CardTitle as s } from "../components/Card.js";
|
|
5
|
+
import { Button as c } from "../components/Button.js";
|
|
6
|
+
import { Badge as l } from "../components/Badge.js";
|
|
7
|
+
import { EmptyState as u } from "../components/EmptyState.js";
|
|
8
|
+
import { ErrorState as d } from "../components/ErrorState.js";
|
|
9
|
+
import "../hooks/index.js";
|
|
10
|
+
import { BotmanorHandoffStatus as f } from "../../generated/wspace-types.js";
|
|
11
|
+
import { useAcceptHandoff as p, useHandoffQueue as m, useRejectHandoff as h, useReleaseHandoff as g, useResolveHandoff as _ } from "../hooks/useHandoffs.js";
|
|
12
|
+
import { formatRelativeTime as v } from "../utils/formatters.js";
|
|
13
|
+
import { useMemo as y, useState as b } from "react";
|
|
14
|
+
import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
15
|
+
// src/botlit/pages/HandoffsPage.tsx
|
|
16
|
+
var w = [
|
|
17
|
+
{
|
|
18
|
+
id: "active",
|
|
19
|
+
statuses: [
|
|
20
|
+
f.Requested,
|
|
21
|
+
f.Assigned,
|
|
22
|
+
f.Accepted
|
|
23
|
+
],
|
|
24
|
+
labelKey: "botlit.handoffs.filter.active",
|
|
25
|
+
label: "Active"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "resolved",
|
|
29
|
+
statuses: [
|
|
30
|
+
f.Resolved,
|
|
31
|
+
f.Released,
|
|
32
|
+
f.Rejected
|
|
33
|
+
],
|
|
34
|
+
labelKey: "botlit.handoffs.filter.resolved",
|
|
35
|
+
label: "Closed"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "all",
|
|
39
|
+
statuses: null,
|
|
40
|
+
labelKey: "botlit.handoffs.filter.all",
|
|
41
|
+
label: "All"
|
|
42
|
+
}
|
|
43
|
+
], T = ({ handoff: t }) => {
|
|
44
|
+
let n = e(), r = {
|
|
45
|
+
EXPLICIT_REQUEST: n("botlit.handoffs.trigger.explicitRequest", "Explicit request"),
|
|
46
|
+
CUSTOM_INTENT: n("botlit.handoffs.trigger.customIntent", "Custom intent"),
|
|
47
|
+
LOW_CONFIDENCE: n("botlit.handoffs.trigger.lowConfidence", "Low confidence"),
|
|
48
|
+
REPEATED_FAILURES: n("botlit.handoffs.trigger.repeatedFailures", "Repeated failures"),
|
|
49
|
+
POLICY_REFUSAL: n("botlit.handoffs.trigger.policyRefusal", "Policy refusal"),
|
|
50
|
+
MANUAL: n("botlit.handoffs.trigger.manual", "Manual")
|
|
51
|
+
};
|
|
52
|
+
return /* @__PURE__ */ S(l, {
|
|
53
|
+
variant: "outline",
|
|
54
|
+
children: r[t.trigger] ?? t.trigger
|
|
55
|
+
});
|
|
56
|
+
}, E = ({ status: t }) => {
|
|
57
|
+
let n = e(), r = {
|
|
58
|
+
[f.Requested]: {
|
|
59
|
+
text: n("botlit.handoffs.status.requested", "Requested"),
|
|
60
|
+
variant: "warning"
|
|
61
|
+
},
|
|
62
|
+
[f.Assigned]: {
|
|
63
|
+
text: n("botlit.handoffs.status.assigned", "Assigned"),
|
|
64
|
+
variant: "warning"
|
|
65
|
+
},
|
|
66
|
+
[f.Accepted]: {
|
|
67
|
+
text: n("botlit.handoffs.status.accepted", "Accepted"),
|
|
68
|
+
variant: "success"
|
|
69
|
+
},
|
|
70
|
+
[f.Resolved]: {
|
|
71
|
+
text: n("botlit.handoffs.status.resolved", "Resolved"),
|
|
72
|
+
variant: "outline"
|
|
73
|
+
},
|
|
74
|
+
[f.Released]: {
|
|
75
|
+
text: n("botlit.handoffs.status.released", "Released to bot"),
|
|
76
|
+
variant: "outline"
|
|
77
|
+
},
|
|
78
|
+
[f.Rejected]: {
|
|
79
|
+
text: n("botlit.handoffs.status.rejected", "Rejected"),
|
|
80
|
+
variant: "destructive"
|
|
81
|
+
},
|
|
82
|
+
[f.Expired]: {
|
|
83
|
+
text: n("botlit.handoffs.status.expired", "Expired"),
|
|
84
|
+
variant: "outline"
|
|
85
|
+
}
|
|
86
|
+
}[t] ?? {
|
|
87
|
+
text: String(t),
|
|
88
|
+
variant: "outline"
|
|
89
|
+
};
|
|
90
|
+
return /* @__PURE__ */ S(l, {
|
|
91
|
+
variant: r.variant,
|
|
92
|
+
children: r.text
|
|
93
|
+
});
|
|
94
|
+
}, D = ({ handoff: t, agents: n, onChanged: r }) => {
|
|
95
|
+
let i = e(), [a, o] = p(), [s, l] = g(), [u, d] = _(), [m, y] = h(), b = o.loading || l.loading || d.loading || y.loading, w = o.error ?? l.error ?? d.error ?? y.error, D = async (e) => {
|
|
96
|
+
try {
|
|
97
|
+
await e(t.id), r();
|
|
98
|
+
} catch {}
|
|
99
|
+
};
|
|
100
|
+
return /* @__PURE__ */ C("li", {
|
|
101
|
+
className: "grid gap-3 rounded-card border border-border-seam bg-bg-surface p-4",
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ C("div", {
|
|
104
|
+
className: "flex flex-wrap items-center gap-2",
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ S(E, { status: t.status }),
|
|
107
|
+
/* @__PURE__ */ S(T, { handoff: t }),
|
|
108
|
+
/* @__PURE__ */ S("span", {
|
|
109
|
+
className: "text-xs text-text-secondary",
|
|
110
|
+
children: i("botlit.handoffs.opened", "Opened {{time}}", { time: v(t.createdAt) })
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
}),
|
|
114
|
+
/* @__PURE__ */ S("p", {
|
|
115
|
+
className: "text-sm text-text-primary",
|
|
116
|
+
children: t.reason
|
|
117
|
+
}),
|
|
118
|
+
t.userMessage ? /* @__PURE__ */ S("blockquote", {
|
|
119
|
+
className: "border-l-2 border-border-seam pl-3 text-sm text-text-secondary italic",
|
|
120
|
+
children: t.userMessage
|
|
121
|
+
}) : null,
|
|
122
|
+
/* @__PURE__ */ C("div", {
|
|
123
|
+
className: "flex flex-wrap items-center gap-2 text-xs text-text-secondary",
|
|
124
|
+
children: [/* @__PURE__ */ S("span", { children: n.get(t.agentId) ? i("botlit.handoffs.agent", "Agent {{name}}", { name: n.get(t.agentId) }) : i("botlit.handoffs.conversation", "Conversation {{key}}", { key: t.conversationKey }) }), t.assignedToId ? /* @__PURE__ */ S("span", { children: i("botlit.handoffs.assignedTo", "· with {{who}}", { who: t.assignedToId }) }) : null]
|
|
125
|
+
}),
|
|
126
|
+
w ? /* @__PURE__ */ S("p", {
|
|
127
|
+
role: "alert",
|
|
128
|
+
className: "text-sm text-status-danger-text",
|
|
129
|
+
children: w.message
|
|
130
|
+
}) : null,
|
|
131
|
+
/* @__PURE__ */ C("div", {
|
|
132
|
+
className: "flex flex-wrap gap-2",
|
|
133
|
+
children: [t.status === f.Requested || t.status === f.Assigned ? /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ S(c, {
|
|
134
|
+
size: "sm",
|
|
135
|
+
disabled: b,
|
|
136
|
+
onClick: () => void D(a),
|
|
137
|
+
children: i("botlit.handoffs.actions.accept", "Accept")
|
|
138
|
+
}), /* @__PURE__ */ S(c, {
|
|
139
|
+
size: "sm",
|
|
140
|
+
variant: "outline",
|
|
141
|
+
disabled: b,
|
|
142
|
+
onClick: () => void D(m),
|
|
143
|
+
children: i("botlit.handoffs.actions.reject", "Reject")
|
|
144
|
+
})] }) : null, t.status === f.Accepted ? /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ S(c, {
|
|
145
|
+
size: "sm",
|
|
146
|
+
variant: "outline",
|
|
147
|
+
disabled: b,
|
|
148
|
+
onClick: () => void D(s),
|
|
149
|
+
children: i("botlit.handoffs.actions.release", "Release to bot")
|
|
150
|
+
}), /* @__PURE__ */ S(c, {
|
|
151
|
+
size: "sm",
|
|
152
|
+
disabled: b,
|
|
153
|
+
onClick: () => void D(u),
|
|
154
|
+
children: i("botlit.handoffs.actions.resolve", "Resolve")
|
|
155
|
+
})] }) : null]
|
|
156
|
+
})
|
|
157
|
+
]
|
|
158
|
+
});
|
|
159
|
+
}, O = () => {
|
|
160
|
+
let l = e(), [f, p] = b("active"), h = w.find((e) => e.id === f) ?? w[0], g = m({ statuses: h.statuses ?? void 0 }), _ = t(), v = y(() => new Map((_.data ?? []).map((e) => [e.id, e.name])), [_.data]);
|
|
161
|
+
return /* @__PURE__ */ S(n, {
|
|
162
|
+
title: l("botlit.handoffs.title", "Human Handoffs"),
|
|
163
|
+
description: l("botlit.handoffs.description", "Conversations the runtime handed to your team. Accepting a handoff stops the bot from replying on that conversation."),
|
|
164
|
+
children: /* @__PURE__ */ C("div", {
|
|
165
|
+
className: "mx-auto flex w-full max-w-4xl flex-col gap-4 p-4",
|
|
166
|
+
children: [
|
|
167
|
+
/* @__PURE__ */ C("div", {
|
|
168
|
+
className: "flex flex-wrap items-center gap-2",
|
|
169
|
+
children: [w.map((e) => /* @__PURE__ */ S(c, {
|
|
170
|
+
size: "sm",
|
|
171
|
+
variant: f === e.id ? "primary" : "outline",
|
|
172
|
+
onClick: () => p(e.id),
|
|
173
|
+
children: l(e.labelKey, e.label)
|
|
174
|
+
}, e.id)), /* @__PURE__ */ S(c, {
|
|
175
|
+
size: "sm",
|
|
176
|
+
variant: "outline",
|
|
177
|
+
onClick: () => void g.refetch(),
|
|
178
|
+
children: l("botlit.handoffs.refresh", "Refresh")
|
|
179
|
+
})]
|
|
180
|
+
}),
|
|
181
|
+
g.loading ? /* @__PURE__ */ S("p", {
|
|
182
|
+
role: "status",
|
|
183
|
+
children: l("botlit.handoffs.loading", "Loading handoffs…")
|
|
184
|
+
}) : g.error ? /* @__PURE__ */ S(d, {
|
|
185
|
+
resource: l("botlit.handoffs.errorResource", "handoffs"),
|
|
186
|
+
error: g.error,
|
|
187
|
+
onRetry: () => void g.refetch()
|
|
188
|
+
}) : g.data && g.data.items.length > 0 ? /* @__PURE__ */ C(r, { children: [/* @__PURE__ */ C(o, { children: [/* @__PURE__ */ S(s, { children: l("botlit.handoffs.queue", "Team inbox") }), /* @__PURE__ */ S(a, { children: l("botlit.handoffs.queueDescription", "Newest first — accept a conversation to take it over.") })] }), /* @__PURE__ */ S(i, { children: /* @__PURE__ */ S("ul", {
|
|
189
|
+
className: "grid gap-3",
|
|
190
|
+
children: g.data.items.map((e) => /* @__PURE__ */ S(D, {
|
|
191
|
+
handoff: e,
|
|
192
|
+
agents: v,
|
|
193
|
+
onChanged: () => void g.refetch()
|
|
194
|
+
}, e.id))
|
|
195
|
+
}) })] }) : /* @__PURE__ */ S(u, {
|
|
196
|
+
title: l("botlit.handoffs.empty", "No handoffs"),
|
|
197
|
+
description: l("botlit.handoffs.emptyDescription", "Nothing needs a human right now. Triggered handoffs from your agents land here.")
|
|
198
|
+
}),
|
|
199
|
+
g.data && g.data.hasMore ? /* @__PURE__ */ S("p", {
|
|
200
|
+
className: "text-sm text-text-secondary",
|
|
201
|
+
children: l("botlit.handoffs.truncated", "Showing the {{shown}} most recent of {{total}} handoffs — narrow the filter to see the rest.", {
|
|
202
|
+
shown: g.data.items.length,
|
|
203
|
+
total: g.data.total
|
|
204
|
+
})
|
|
205
|
+
}) : null
|
|
206
|
+
]
|
|
207
|
+
})
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
export { O as HandoffsPage };
|
|
211
|
+
|
|
212
|
+
//# sourceMappingURL=HandoffsPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HandoffsPage.js","names":["_Fragment","FILTERS","BotmanorHandoffStatus","TriggerBadge","t","useTr","labels","Badge","handoff","StatusBadge","entry","status","HandoffRow","accept","acceptState","useAcceptHandoff","release","releaseState","useReleaseHandoff","resolve","resolveState","useResolveHandoff","reject","rejectState","useRejectHandoff","busy","transitionError","run","action","onChanged","formatRelativeTime","agents","Fragment","Button","HandoffsPage","filter","setFilter","useState","active","queue","useHandoffQueue","useAgents","agentNames","useMemo","agent","PageLayout","ErrorState","Card","CardHeader","CardTitle","CardDescription","CardContent","EmptyState"],"sources":["../../../src/botlit/pages/HandoffsPage.tsx"],"sourcesContent":["/**\n * Handoffs Page (BOFF-5813)\n * @module botlit/pages\n *\n * The shared team inbox: every handoff of a live conversation from an agent\n * to a human operator. Operators accept a handoff to take the conversation\n * (the bot stops autonomous replies), release it back to the bot, resolve it,\n * or reject it. Filters narrow the queue by status and agent.\n */\nimport type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Badge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport {\n useAgents,\n useHandoffQueue,\n useAcceptHandoff,\n useReleaseHandoff,\n useResolveHandoff,\n useRejectHandoff,\n isActiveHandoff,\n type HandoffRecord,\n} from '../hooks';\nimport { BotmanorHandoffStatus } from '../../generated/wspace-types';\nimport { formatRelativeTime } from '../utils/formatters';\n\ntype QueueFilter = 'active' | 'resolved' | 'all';\n\nconst FILTERS: Array<{\n id: QueueFilter;\n statuses: BotmanorHandoffStatus[] | null;\n labelKey: string;\n label: string;\n}> = [\n {\n id: 'active',\n statuses: [\n BotmanorHandoffStatus.Requested,\n BotmanorHandoffStatus.Assigned,\n BotmanorHandoffStatus.Accepted,\n ],\n labelKey: 'botlit.handoffs.filter.active',\n label: 'Active',\n },\n {\n id: 'resolved',\n statuses: [\n BotmanorHandoffStatus.Resolved,\n BotmanorHandoffStatus.Released,\n BotmanorHandoffStatus.Rejected,\n ],\n labelKey: 'botlit.handoffs.filter.resolved',\n label: 'Closed',\n },\n { id: 'all', statuses: null, labelKey: 'botlit.handoffs.filter.all', label: 'All' },\n];\n\nconst TriggerBadge: FC<{ handoff: HandoffRecord }> = ({ handoff }) => {\n const t = useTr();\n const labels: Record<string, string> = {\n EXPLICIT_REQUEST: t('botlit.handoffs.trigger.explicitRequest', 'Explicit request'),\n CUSTOM_INTENT: t('botlit.handoffs.trigger.customIntent', 'Custom intent'),\n LOW_CONFIDENCE: t('botlit.handoffs.trigger.lowConfidence', 'Low confidence'),\n REPEATED_FAILURES: t('botlit.handoffs.trigger.repeatedFailures', 'Repeated failures'),\n POLICY_REFUSAL: t('botlit.handoffs.trigger.policyRefusal', 'Policy refusal'),\n MANUAL: t('botlit.handoffs.trigger.manual', 'Manual'),\n };\n return <Badge variant=\"outline\">{labels[handoff.trigger] ?? handoff.trigger}</Badge>;\n};\n\nconst StatusBadge: FC<{ status: BotmanorHandoffStatus }> = ({ status }) => {\n const t = useTr();\n const labels: Record<\n BotmanorHandoffStatus,\n { text: string; variant: 'success' | 'warning' | 'outline' | 'destructive' }\n > = {\n [BotmanorHandoffStatus.Requested]: {\n text: t('botlit.handoffs.status.requested', 'Requested'),\n variant: 'warning',\n },\n [BotmanorHandoffStatus.Assigned]: {\n text: t('botlit.handoffs.status.assigned', 'Assigned'),\n variant: 'warning',\n },\n [BotmanorHandoffStatus.Accepted]: {\n text: t('botlit.handoffs.status.accepted', 'Accepted'),\n variant: 'success',\n },\n [BotmanorHandoffStatus.Resolved]: {\n text: t('botlit.handoffs.status.resolved', 'Resolved'),\n variant: 'outline',\n },\n [BotmanorHandoffStatus.Released]: {\n text: t('botlit.handoffs.status.released', 'Released to bot'),\n variant: 'outline',\n },\n [BotmanorHandoffStatus.Rejected]: {\n text: t('botlit.handoffs.status.rejected', 'Rejected'),\n variant: 'destructive',\n },\n [BotmanorHandoffStatus.Expired]: {\n text: t('botlit.handoffs.status.expired', 'Expired'),\n variant: 'outline',\n },\n };\n // Unknown enum values (a newer server variant) must not crash the page.\n const entry = labels[status] ?? { text: String(status), variant: 'outline' as const };\n return <Badge variant={entry.variant}>{entry.text}</Badge>;\n};\n\nconst HandoffRow: FC<{\n handoff: HandoffRecord;\n agents: Map<string, string>;\n onChanged: () => void;\n}> = ({ handoff, agents, onChanged }) => {\n const t = useTr();\n const [accept, acceptState] = useAcceptHandoff();\n const [release, releaseState] = useReleaseHandoff();\n const [resolve, resolveState] = useResolveHandoff();\n const [reject, rejectState] = useRejectHandoff();\n const busy =\n acceptState.loading || releaseState.loading || resolveState.loading || rejectState.loading;\n const transitionError =\n acceptState.error ?? releaseState.error ?? resolveState.error ?? rejectState.error;\n\n const run = async (action: (id: string) => Promise<unknown>) => {\n try {\n await action(handoff.id);\n onChanged();\n } catch {\n /* the hook state already carries the message */\n }\n };\n\n return (\n <li className=\"grid gap-3 rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={handoff.status} />\n <TriggerBadge handoff={handoff} />\n <span className=\"text-xs text-text-secondary\">\n {t('botlit.handoffs.opened', 'Opened {{time}}', {\n time: formatRelativeTime(handoff.createdAt),\n })}\n </span>\n </div>\n <p className=\"text-sm text-text-primary\">{handoff.reason}</p>\n {handoff.userMessage ? (\n <blockquote className=\"border-l-2 border-border-seam pl-3 text-sm text-text-secondary italic\">\n {handoff.userMessage}\n </blockquote>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n <span>\n {agents.get(handoff.agentId)\n ? t('botlit.handoffs.agent', 'Agent {{name}}', {\n name: agents.get(handoff.agentId) as string,\n })\n : t('botlit.handoffs.conversation', 'Conversation {{key}}', {\n key: handoff.conversationKey,\n })}\n </span>\n {handoff.assignedToId ? (\n <span>\n {t('botlit.handoffs.assignedTo', '· with {{who}}', { who: handoff.assignedToId })}\n </span>\n ) : null}\n </div>\n {transitionError ? (\n <p role=\"alert\" className=\"text-sm text-status-danger-text\">\n {transitionError.message}\n </p>\n ) : null}\n <div className=\"flex flex-wrap gap-2\">\n {handoff.status === BotmanorHandoffStatus.Requested ||\n handoff.status === BotmanorHandoffStatus.Assigned ? (\n <>\n <Button size=\"sm\" disabled={busy} onClick={() => void run(accept)}>\n {t('botlit.handoffs.actions.accept', 'Accept')}\n </Button>\n <Button size=\"sm\" variant=\"outline\" disabled={busy} onClick={() => void run(reject)}>\n {t('botlit.handoffs.actions.reject', 'Reject')}\n </Button>\n </>\n ) : null}\n {handoff.status === BotmanorHandoffStatus.Accepted ? (\n <>\n <Button size=\"sm\" variant=\"outline\" disabled={busy} onClick={() => void run(release)}>\n {t('botlit.handoffs.actions.release', 'Release to bot')}\n </Button>\n <Button size=\"sm\" disabled={busy} onClick={() => void run(resolve)}>\n {t('botlit.handoffs.actions.resolve', 'Resolve')}\n </Button>\n </>\n ) : null}\n </div>\n </li>\n );\n};\n\nexport const HandoffsPage: FC = () => {\n const t = useTr();\n const [filter, setFilter] = useState<QueueFilter>('active');\n const active = FILTERS.find((entry) => entry.id === filter) ?? FILTERS[0];\n const queue = useHandoffQueue({ statuses: active.statuses ?? undefined });\n const agents = useAgents();\n const agentNames = useMemo(\n () => new Map((agents.data ?? []).map((agent) => [agent.id, agent.name])),\n [agents.data]\n );\n\n return (\n <PageLayout\n title={t('botlit.handoffs.title', 'Human Handoffs')}\n description={t(\n 'botlit.handoffs.description',\n 'Conversations the runtime handed to your team. Accepting a handoff stops the bot from replying on that conversation.'\n )}\n >\n <div className=\"mx-auto flex w-full max-w-4xl flex-col gap-4 p-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {FILTERS.map((entry) => (\n <Button\n key={entry.id}\n size=\"sm\"\n variant={filter === entry.id ? 'primary' : 'outline'}\n onClick={() => setFilter(entry.id)}\n >\n {t(entry.labelKey, entry.label)}\n </Button>\n ))}\n <Button size=\"sm\" variant=\"outline\" onClick={() => void queue.refetch()}>\n {t('botlit.handoffs.refresh', 'Refresh')}\n </Button>\n </div>\n\n {queue.loading ? (\n <p role=\"status\">{t('botlit.handoffs.loading', 'Loading handoffs…')}</p>\n ) : queue.error ? (\n <ErrorState\n resource={t('botlit.handoffs.errorResource', 'handoffs')}\n error={queue.error}\n onRetry={() => void queue.refetch()}\n />\n ) : queue.data && queue.data.items.length > 0 ? (\n <Card>\n <CardHeader>\n <CardTitle>{t('botlit.handoffs.queue', 'Team inbox')}</CardTitle>\n <CardDescription>\n {t(\n 'botlit.handoffs.queueDescription',\n 'Newest first — accept a conversation to take it over.'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <ul className=\"grid gap-3\">\n {queue.data.items.map((handoff) => (\n <HandoffRow\n key={handoff.id}\n handoff={handoff}\n agents={agentNames}\n onChanged={() => void queue.refetch()}\n />\n ))}\n </ul>\n </CardContent>\n </Card>\n ) : (\n <EmptyState\n title={t('botlit.handoffs.empty', 'No handoffs')}\n description={t(\n 'botlit.handoffs.emptyDescription',\n 'Nothing needs a human right now. Triggered handoffs from your agents land here.'\n )}\n />\n )}\n {queue.data && queue.data.hasMore ? (\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'botlit.handoffs.truncated',\n 'Showing the {{shown}} most recent of {{total}} handoffs — narrow the filter to see the rest.',\n { shown: queue.data.items.length, total: queue.data.total }\n )}\n </p>\n ) : null}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AAiCA,IAAMC,IAKD;CACH;EACE,IAAI;EACJ,UAAU;GACRC,EAAsB;GACtBA,EAAsB;GACtBA,EAAsB;EACxB;EACA,UAAU;EACV,OAAO;CACT;CACA;EACE,IAAI;EACJ,UAAU;GACRA,EAAsB;GACtBA,EAAsB;GACtBA,EAAsB;EACxB;EACA,UAAU;EACV,OAAO;CACT;CACA;EAAE,IAAI;EAAO,UAAU;EAAM,UAAU;EAA8B,OAAO;CAAM;AACpF,GAEMC,KAAgD,EAAE,iBAAc;CACpE,IAAMC,IAAIC,EAAM,GACVC,IAAiC;EACrC,kBAAkBF,EAAE,2CAA2C,kBAAkB;EACjF,eAAeA,EAAE,wCAAwC,eAAe;EACxE,gBAAgBA,EAAE,yCAAyC,gBAAgB;EAC3E,mBAAmBA,EAAE,4CAA4C,mBAAmB;EACpF,gBAAgBA,EAAE,yCAAyC,gBAAgB;EAC3E,QAAQA,EAAE,kCAAkC,QAAQ;CACtD;CACA,OAAO,kBAACG,GAAD;EAAO,SAAQ;EAAW,UAAAD,EAAOE,EAAQ,YAAYA,EAAQ;CAAe,CAAA;AACrF,GAEMC,KAAsD,EAAE,gBAAa;CACzE,IAAML,IAAIC,EAAM,GAmCVK,IAAQ;GA9BXR,EAAsB,YAAY;GACjC,MAAME,EAAE,oCAAoC,WAAW;GACvD,SAAS;EACX;GACCF,EAAsB,WAAW;GAChC,MAAME,EAAE,mCAAmC,UAAU;GACrD,SAAS;EACX;GACCF,EAAsB,WAAW;GAChC,MAAME,EAAE,mCAAmC,UAAU;GACrD,SAAS;EACX;GACCF,EAAsB,WAAW;GAChC,MAAME,EAAE,mCAAmC,UAAU;GACrD,SAAS;EACX;GACCF,EAAsB,WAAW;GAChC,MAAME,EAAE,mCAAmC,iBAAiB;GAC5D,SAAS;EACX;GACCF,EAAsB,WAAW;GAChC,MAAME,EAAE,mCAAmC,UAAU;GACrD,SAAS;EACX;GACCF,EAAsB,UAAU;GAC/B,MAAME,EAAE,kCAAkC,SAAS;GACnD,SAAS;EACX;CAGY,EAAOO,MAAW;EAAE,MAAM,OAAOA,CAAM;EAAG,SAAS;CAAmB;CACpF,OAAO,kBAACJ,GAAD;EAAO,SAASG,EAAM;EAAU,UAAAA,EAAM;CAAY,CAAA;AAC3D,GAEME,KAIA,EAAE,YAAS,WAAQ,mBAAgB;CACvC,IAAMR,IAAIC,EAAM,GACV,CAACQ,GAAQC,KAAeC,EAAiB,GACzC,CAACC,GAASC,KAAgBC,EAAkB,GAC5C,CAACC,GAASC,KAAgBC,EAAkB,GAC5C,CAACC,GAAQC,KAAeC,EAAiB,GACzCC,IACJX,EAAY,WAAWG,EAAa,WAAWG,EAAa,WAAWG,EAAY,SAC/EG,IACJZ,EAAY,SAASG,EAAa,SAASG,EAAa,SAASG,EAAY,OAEzEI,IAAM,OAAO,MAA6C;EAC9D,IAAI;GAEF,AADA,MAAMC,EAAOpB,EAAQ,EAAE,GACvBqB,EAAU;EACZ,QAAQ,CAER;CACF;CAEA,OACE,kBAAC,MAAD;EAAI,WAAU;EAAd,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAACpB,GAAD,EAAa,QAAQD,EAAQ,OAAS,CAAA;KACtC,kBAACL,GAAD,EAAuB,WAAU,CAAA;KACjC,kBAAC,QAAD;MAAM,WAAU;MACb,UAAAC,EAAE,0BAA0B,mBAAmB,EAC9C,MAAM0B,EAAmBtB,EAAQ,SAAS,EAC5C,CAAC;KACG,CAAA;IACH;;GACL,kBAAC,KAAD;IAAG,WAAU;IAA6B,UAAAA,EAAQ;GAAU,CAAA;GAC3DA,EAAQ,cACP,kBAAC,cAAD;IAAY,WAAU;IACnB,UAAAA,EAAQ;GACC,CAAA,IACV;GACJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD,EAAA,UACGuB,EAAO,IAAIvB,EAAQ,OAAO,IACvBJ,EAAE,yBAAyB,kBAAkB,EAC3C,MAAM2B,EAAO,IAAIvB,EAAQ,OAAO,EAClC,CAAC,IACDJ,EAAE,gCAAgC,wBAAwB,EACxD,KAAKI,EAAQ,gBACf,CAAC,EACD,CAAA,GACLA,EAAQ,eACP,kBAAC,QAAD,EAAA,UACGJ,EAAE,8BAA8B,kBAAkB,EAAE,KAAKI,EAAQ,aAAa,CAAC,EAC5E,CAAA,IACJ,IACD;;GACJkB,IACC,kBAAC,KAAD;IAAG,MAAK;IAAQ,WAAU;IACvB,UAAAA,EAAgB;GAChB,CAAA,IACD;GACJ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACGlB,EAAQ,WAAWN,EAAsB,aAC1CM,EAAQ,WAAWN,EAAsB,WACvC,kBAAAF,GAAA,EAAA,UAAA,CACE,kBAACiC,GAAD;KAAQ,MAAK;KAAK,UAAUR;KAAM,eAAe,KAAKE,EAAId,CAAM;KAC7D,UAAAT,EAAE,kCAAkC,QAAQ;IACvC,CAAA,GACR,kBAAC6B,GAAD;KAAQ,MAAK;KAAK,SAAQ;KAAU,UAAUR;KAAM,eAAe,KAAKE,EAAIL,CAAM;KAC/E,UAAAlB,EAAE,kCAAkC,QAAQ;IACvC,CAAA,CACR,EAAA,CAAA,IACA,MACHI,EAAQ,WAAWN,EAAsB,WACxC,kBAAAF,GAAA,EAAA,UAAA,CACE,kBAACiC,GAAD;KAAQ,MAAK;KAAK,SAAQ;KAAU,UAAUR;KAAM,eAAe,KAAKE,EAAIX,CAAO;KAChF,UAAAZ,EAAE,mCAAmC,gBAAgB;IAChD,CAAA,GACR,kBAAC6B,GAAD;KAAQ,MAAK;KAAK,UAAUR;KAAM,eAAe,KAAKE,EAAIR,CAAO;KAC9D,UAAAf,EAAE,mCAAmC,SAAS;IACzC,CAAA,CACR,EAAA,CAAA,IACA,IACD;;EACH;;AAER,GAEa8B,UAAyB;CACpC,IAAM9B,IAAIC,EAAM,GACV,CAAC8B,GAAQC,KAAaC,EAAsB,QAAQ,GACpDC,IAASrC,EAAQ,MAAM,MAAUS,EAAM,OAAOyB,CAAM,KAAKlC,EAAQ,IACjEsC,IAAQC,EAAgB,EAAE,UAAUF,EAAO,YAAY,KAAA,EAAU,CAAC,GAClEP,IAASU,EAAU,GACnBC,IAAaC,QACX,IAAI,KAAKZ,EAAO,QAAQ,CAAC,EAAA,CAAG,KAAK,MAAU,CAACa,EAAM,IAAIA,EAAM,IAAI,CAAC,CAAC,GACxE,CAACb,EAAO,IAAI,CACd;CAEA,OACE,kBAACc,GAAD;EACE,OAAOzC,EAAE,yBAAyB,gBAAgB;EAClD,aAAaA,EACX,+BACA,sHACF;EAEA,UAAA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACGH,EAAQ,KAAK,MACZ,kBAACgC,GAAD;MAEE,MAAK;MACL,SAASE,MAAWzB,EAAM,KAAK,YAAY;MAC3C,eAAe0B,EAAU1B,EAAM,EAAE;MAEhC,UAAAN,EAAEM,EAAM,UAAUA,EAAM,KAAK;KACxB,GANDA,EAAM,EAML,CACT,GACD,kBAACuB,GAAD;MAAQ,MAAK;MAAK,SAAQ;MAAU,eAAe,KAAKM,EAAM,QAAQ;MACnE,UAAAnC,EAAE,2BAA2B,SAAS;KACjC,CAAA,CACL;;IAEJmC,EAAM,UACL,kBAAC,KAAD;KAAG,MAAK;KAAU,UAAAnC,EAAE,2BAA2B,mBAAmB;IAAK,CAAA,IACrEmC,EAAM,QACR,kBAACO,GAAD;KACE,UAAU1C,EAAE,iCAAiC,UAAU;KACvD,OAAOmC,EAAM;KACb,eAAe,KAAKA,EAAM,QAAQ;IACnC,CAAA,IACCA,EAAM,QAAQA,EAAM,KAAK,MAAM,SAAS,IAC1C,kBAACQ,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD,EAAA,UAAA,CACE,kBAACC,GAAD,EAAA,UAAY7C,EAAE,yBAAyB,YAAY,EAAa,CAAA,GAChE,kBAAC8C,GAAD,EAAA,UACG9C,EACC,oCACA,uDACF,EACe,CAAA,CACP,EAAA,CAAA,GACZ,kBAAC+C,GAAD,EAAA,UACE,kBAAC,MAAD;KAAI,WAAU;KACX,UAAAZ,EAAM,KAAK,MAAM,KAAK,MACrB,kBAAC3B,GAAD;MAEW;MACT,QAAQ8B;MACR,iBAAiB,KAAKH,EAAM,QAAQ;KACrC,GAJM/B,EAAQ,EAId,CACF;IACC,CAAA,EACO,CAAA,CACT,EAAA,CAAA,IAEN,kBAAC4C,GAAD;KACE,OAAOhD,EAAE,yBAAyB,aAAa;KAC/C,aAAaA,EACX,oCACA,iFACF;IACD,CAAA;IAEFmC,EAAM,QAAQA,EAAM,KAAK,UACxB,kBAAC,KAAD;KAAG,WAAU;KACV,UAAAnC,EACC,6BACA,gGACA;MAAE,OAAOmC,EAAM,KAAK,MAAM;MAAQ,OAAOA,EAAM,KAAK;KAAM,CAC5D;IACC,CAAA,IACD;GACD;;CACK,CAAA;AAEhB"}
|