@burdenoff/microfe-botmanor 2026.819.1 → 2026.925.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/dist/botlit/BotlitRoutes.js.map +1 -1
- package/dist/botlit/BotmanorRoot.js.map +1 -1
- package/dist/botlit/BotmanorRootInner.js +4 -4
- package/dist/botlit/BotmanorRootInner.js.map +1 -1
- package/dist/botlit/components/ErrorState.js +33 -29
- package/dist/botlit/components/ErrorState.js.map +1 -1
- package/dist/botlit/components/RouteLoader.js +52 -48
- package/dist/botlit/components/RouteLoader.js.map +1 -1
- package/dist/botlit/components/VersionHistoryPanel.js +74 -77
- package/dist/botlit/components/VersionHistoryPanel.js.map +1 -1
- package/dist/botlit/components/WorkspaceRequired.js +31 -30
- package/dist/botlit/components/WorkspaceRequired.js.map +1 -1
- package/dist/botlit/hooks/internal/workspaceGateway.js.map +1 -1
- package/dist/botlit/hooks/useConversations.js.map +1 -1
- package/dist/botlit/hooks/useLLMProviders.js.map +1 -1
- package/dist/botlit/hooks/useMCPServers.js +60 -49
- package/dist/botlit/hooks/useMCPServers.js.map +1 -1
- package/dist/botlit/pages/A2AAgentDetailPage.js +1 -1
- package/dist/botlit/pages/A2AAgentDetailPage.js.map +1 -1
- package/dist/botlit/pages/A2ARegistryPage.js +116 -124
- package/dist/botlit/pages/A2ARegistryPage.js.map +1 -1
- package/dist/botlit/pages/AgentDetailPage.js +169 -172
- package/dist/botlit/pages/AgentDetailPage.js.map +1 -1
- package/dist/botlit/pages/AgentsListPage.js +96 -90
- package/dist/botlit/pages/AgentsListPage.js.map +1 -1
- package/dist/botlit/pages/BotChannelsTab.js.map +1 -1
- package/dist/botlit/pages/BotDetailPage.js +228 -231
- package/dist/botlit/pages/BotDetailPage.js.map +1 -1
- package/dist/botlit/pages/BotWorkflowTab.js +84 -87
- package/dist/botlit/pages/BotWorkflowTab.js.map +1 -1
- package/dist/botlit/pages/BotsListPage.js +144 -147
- package/dist/botlit/pages/BotsListPage.js.map +1 -1
- package/dist/botlit/pages/BucketsPage.js +3 -3
- package/dist/botlit/pages/BucketsPage.js.map +1 -1
- package/dist/botlit/pages/ChannelDetailPage.js +1 -1
- package/dist/botlit/pages/ChannelDetailPage.js.map +1 -1
- package/dist/botlit/pages/ChannelsPage.js +156 -149
- package/dist/botlit/pages/ChannelsPage.js.map +1 -1
- package/dist/botlit/pages/ChatPage.js +126 -129
- package/dist/botlit/pages/ChatPage.js.map +1 -1
- package/dist/botlit/pages/DashboardPage.js +111 -114
- package/dist/botlit/pages/DashboardPage.js.map +1 -1
- package/dist/botlit/pages/ExecutionsPage.js +163 -159
- package/dist/botlit/pages/ExecutionsPage.js.map +1 -1
- package/dist/botlit/pages/InstalledPackagesPage.js +3 -3
- package/dist/botlit/pages/InstalledPackagesPage.js.map +1 -1
- package/dist/botlit/pages/KnowledgeBasesPage.js +84 -78
- package/dist/botlit/pages/KnowledgeBasesPage.js.map +1 -1
- package/dist/botlit/pages/MCPServerDetailPage.js +295 -238
- package/dist/botlit/pages/MCPServerDetailPage.js.map +1 -1
- package/dist/botlit/pages/MCPServersPage.js +159 -154
- package/dist/botlit/pages/MCPServersPage.js.map +1 -1
- package/dist/botlit/pages/PoliciesPage.js +119 -114
- package/dist/botlit/pages/PoliciesPage.js.map +1 -1
- package/dist/botlit/pages/RetrievalProfilesPage.js +102 -109
- package/dist/botlit/pages/RetrievalProfilesPage.js.map +1 -1
- package/dist/botlit/pages/SettingsPage.js +144 -159
- package/dist/botlit/pages/SettingsPage.js.map +1 -1
- package/dist/botlit/pages/SkillsPage.js +122 -105
- package/dist/botlit/pages/SkillsPage.js.map +1 -1
- package/dist/botlit/pages/StorePage.js +176 -175
- package/dist/botlit/pages/StorePage.js.map +1 -1
- package/dist/botlit/providers/BotlitProvider.js.map +1 -1
- package/dist/botlit/store/botlitStore.js +1 -1
- package/dist/botlit/store/botlitStore.js.map +1 -1
- package/dist/botlit/utils/navigation.js.map +1 -1
- package/dist/generated/wspace-operations.js +45 -29
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/shared/hooks/useTr.js +14 -0
- package/dist/shared/hooks/useTr.js.map +1 -0
- package/package.json +33 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BotsListPage.js","names":[],"sources":["../../../src/botlit/pages/BotsListPage.tsx"],"sourcesContent":["/**\n * Bots List Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Link } from 'react-router';\nimport {\n Plus,\n Search,\n Grid3X3,\n List,\n MoreVertical,\n Bot,\n Trash2,\n Edit,\n Workflow,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { toast } from 'sonner';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\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 { StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useBots, useDeleteBot } from '../hooks/useBots';\nimport { useBotlitStore } from '../store/botlitStore';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { formatRelativeTime, formatNumber } from '../utils/formatters';\nimport { cn } from '../utils/cn';\n// Real GraphQL BotApp fields: id, name, slug, description, type, status, visibility, icon, routingStrategy, defaultAgentId, executionCount, createdAt, tagIds\n\nexport const BotsListPage: FC = () => {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { navigateTo, getPath } = useBotlit();\n const { data: bots, loading } = useBots();\n const [deleteBot] = useDeleteBot();\n const { viewMode, setViewMode, botFilter, updateBotFilter } = useBotlitStore();\n const [menuOpen, setMenuOpen] = useState<string | null>(null);\n\n const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {\n updateBotFilter({ search: e.target.value });\n };\n\n const handleDelete = async (bot: { id: string; name: string }) => {\n const confirmMsg = `${t('botlit.botsList.delete.confirmPrefix', 'Are you sure you want to delete')} \"${bot.name}\"?`;\n const native = await nativeConfirm({\n title: 'Delete bot?',\n message: confirmMsg,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? confirm(confirmMsg) : native;\n if (ok) {\n nativeImpact('medium');\n try {\n await deleteBot(bot.id);\n toast.success(\n `${t('botlit.botsList.delete.successPrefix', 'Bot')} \"${bot.name}\" ${t('botlit.botsList.delete.successSuffix', 'deleted successfully')}`\n );\n if (isNative()) void nativeNotify('success');\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botsList.delete.error', 'Failed to delete bot');\n toast.error(message);\n if (isNative()) void nativeNotify('error');\n }\n }\n setMenuOpen(null);\n };\n\n const filteredBots = bots?.filter((bot) => {\n if (botFilter.search) {\n const search = botFilter.search.toLowerCase();\n return (\n bot.name.toLowerCase().includes(search) ||\n (bot.description?.toLowerCase().includes(search) ?? false)\n );\n }\n return true;\n });\n\n return (\n <PageLayout\n title={t('botlit.botsList.title', 'Bots')}\n description={t('botlit.botsList.description', 'Manage your AI-powered bots')}\n actions={\n <Button leftIcon={<Plus size={16} />} onClick={() => navigateTo('bots/new')}>\n {t('botlit.botsList.actions.createBot', 'Create Bot')}\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Bot size={18} />}>\n {t(\n 'botlit.botsList.purpose',\n 'A bot is the deployable, user-facing surface for your AI — it wraps one or more agents and exposes them to people through chat, channels (Slack, web widget, WhatsApp) and APIs. Create a bot here when you are ready to put an agent in front of real users, then connect channels and watch its executions.'\n )}\n </PagePurpose>\n\n {/* Summary */}\n {bots && bots.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\">\n {t('botlit.botsList.summary.total', 'Total bots')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {bots.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botsList.summary.active', 'Active')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {bots.filter((b: { status?: string }) => b.status === 'ACTIVE').length}\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\">\n {t('botlit.botsList.summary.executions', 'Total executions')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {formatNumber(bots.reduce((sum, bot) => sum + (bot.executionCount ?? 0), 0))}\n </p>\n </GlassCard>\n </div>\n ) : null}\n\n {/* Toolbar */}\n <div className=\"flex items-center justify-between 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={t('botlit.botsList.searchPlaceholder', 'Search bots...')}\n value={botFilter.search || ''}\n onChange={handleSearch}\n className=\"pl-9\"\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Button\n variant={viewMode === 'grid' ? 'secondary' : 'ghost'}\n size=\"icon\"\n onClick={() => setViewMode('grid')}\n >\n <Grid3X3 size={18} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'secondary' : 'ghost'}\n size=\"icon\"\n onClick={() => setViewMode('list')}\n >\n <List size={18} />\n </Button>\n </div>\n </div>\n\n {/* Content */}\n {loading ? (\n <div\n className={cn(\n 'gap-4',\n viewMode === 'grid'\n ? 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3'\n : 'flex flex-col'\n )}\n >\n {[1, 2, 3, 4, 5, 6].map((i) => (\n <div\n key={i}\n className=\"h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : filteredBots && filteredBots.length > 0 ? (\n viewMode === 'grid' ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredBots.map((bot) => (\n <Card\n key={bot.id}\n className=\"group hover:shadow-md transition-shadow cursor-pointer relative\"\n onClick={() => navigateTo(`bots/${bot.id}`)}\n >\n <CardContent className=\"pt-6\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <span className=\"text-4xl\">{bot.icon || '🤖'}</span>\n <div>\n <h3 className=\"font-semibold text-text-primary\">{bot.name}</h3>\n <StatusBadge status={bot.status} />\n </div>\n </div>\n <div className=\"relative\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"opacity-0 group-hover:opacity-100 transition-opacity\"\n onClick={(e) => {\n e.stopPropagation();\n setMenuOpen(menuOpen === bot.id ? null : bot.id);\n }}\n >\n <MoreVertical size={16} />\n </Button>\n {menuOpen === bot.id && (\n <div className=\"absolute right-0 top-full mt-1 w-48 bg-popover border border-border-subtle rounded-md shadow-lg z-10\">\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}/edit`);\n setMenuOpen(null);\n }}\n >\n <Edit size={16} />\n {t('botlit.botsList.menu.editBot', 'Edit Bot')}\n </button>\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}?tab=workflow`);\n setMenuOpen(null);\n }}\n >\n <Workflow size={16} />\n {t('botlit.botsList.menu.design', 'Design workflow')}\n </button>\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}/agents`);\n setMenuOpen(null);\n }}\n >\n <Bot size={16} />\n {t('botlit.botsList.menu.viewAgents', 'View Agents')}\n </button>\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent text-status-error-text flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(bot);\n }}\n >\n <Trash2 size={16} />\n {t('botlit.common.delete', 'Delete')}\n </button>\n </div>\n )}\n </div>\n </div>\n <p className=\"mt-3 text-sm text-text-secondary line-clamp-2\">\n {bot.description}\n </p>\n <div className=\"mt-4 flex items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Bot size={14} />\n {bot.executionCount || 0} {t('botlit.common.executions', 'executions')}\n </span>\n </div>\n <div className=\"mt-3 pt-3 border-t border-border-subtle flex items-center justify-between gap-2\">\n <span className=\"text-xs text-text-secondary\">\n {t('botlit.botsList.createdLabel', 'Created')}{' '}\n {formatRelativeTime(bot.createdAt)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n leftIcon={<Workflow size={14} />}\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}?tab=workflow`);\n }}\n >\n {t('botlit.botsList.actions.design', 'Design')}\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredBots.map((bot) => (\n <Card\n key={bot.id}\n className=\"hover:shadow-md transition-shadow cursor-pointer\"\n onClick={() => navigateTo(`bots/${bot.id}`)}\n >\n <CardContent className=\"py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <span className=\"text-3xl\">{bot.icon || '🤖'}</span>\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold text-text-primary\">{bot.name}</h3>\n <StatusBadge status={bot.status} />\n </div>\n <p className=\"text-sm text-text-secondary line-clamp-1\">\n {bot.description}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-6 text-sm text-text-secondary\">\n <span>\n {formatNumber(bot.executionCount)}{' '}\n {t('botlit.common.executions', 'executions')}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n leftIcon={<Workflow size={14} />}\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}?tab=workflow`);\n }}\n >\n {t('botlit.botsList.actions.design', 'Design')}\n </Button>\n <Button variant=\"ghost\" size=\"sm\">\n <Link to={getPath(`bots/${bot.id}`)}>\n {t('botlit.common.view', 'View')}\n </Link>\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )\n ) : (\n <EmptyState\n illustration=\"empty-agents\"\n title={t('botlit.botsList.empty.title', 'No bots yet')}\n description={t(\n 'botlit.botsList.empty.description',\n 'Create your first AI-powered bot to get started with building agents and automations.'\n )}\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => navigateTo('bots/new')}>\n {t('botlit.botsList.actions.createBot', 'Create Bot')}\n </Button>\n }\n />\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BotsListPage.js","names":[],"sources":["../../../src/botlit/pages/BotsListPage.tsx"],"sourcesContent":["/**\n * Bots List Page\n * @module botlit/pages\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { Link } from 'react-router';\nimport {\n Plus,\n Search,\n Grid3X3,\n List,\n MoreVertical,\n Bot,\n Trash2,\n Edit,\n Workflow,\n} from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { toast } from 'sonner';\nimport { isNative, nativeConfirm, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\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 { StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useBots, useDeleteBot } from '../hooks/useBots';\nimport { useBotlitStore } from '../store/botlitStore';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { formatRelativeTime, formatNumber } from '../utils/formatters';\nimport { cn } from '../utils/cn';\n// Real GraphQL BotApp fields: id, name, slug, description, type, status, visibility, icon, routingStrategy, defaultAgentId, executionCount, createdAt, tagIds\n\nexport const BotsListPage: FC = () => {\n const t = useTr();\n const { navigateTo, getPath } = useBotlit();\n const { data: bots, loading } = useBots();\n const [deleteBot] = useDeleteBot();\n const { viewMode, setViewMode, botFilter, updateBotFilter } = useBotlitStore();\n const [menuOpen, setMenuOpen] = useState<string | null>(null);\n\n const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {\n updateBotFilter({ search: e.target.value });\n };\n\n const handleDelete = async (bot: { id: string; name: string }) => {\n const confirmMsg = `${t('botlit.botsList.delete.confirmPrefix', 'Are you sure you want to delete')} \"${bot.name}\"?`;\n const native = await nativeConfirm({\n title: 'Delete bot?',\n message: confirmMsg,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok = native === null ? confirm(confirmMsg) : native;\n if (ok) {\n nativeImpact('medium');\n try {\n await deleteBot(bot.id);\n toast.success(\n `${t('botlit.botsList.delete.successPrefix', 'Bot')} \"${bot.name}\" ${t('botlit.botsList.delete.successSuffix', 'deleted successfully')}`\n );\n if (isNative()) void nativeNotify('success');\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botsList.delete.error', 'Failed to delete bot');\n toast.error(message);\n if (isNative()) void nativeNotify('error');\n }\n }\n setMenuOpen(null);\n };\n\n const filteredBots = bots?.filter((bot) => {\n if (botFilter.search) {\n const search = botFilter.search.toLowerCase();\n return (\n bot.name.toLowerCase().includes(search) ||\n (bot.description?.toLowerCase().includes(search) ?? false)\n );\n }\n return true;\n });\n\n return (\n <PageLayout\n title={t('botlit.botsList.title', 'Bots')}\n description={t('botlit.botsList.description', 'Manage your AI-powered bots')}\n actions={\n <Button leftIcon={<Plus size={16} />} onClick={() => navigateTo('bots/new')}>\n {t('botlit.botsList.actions.createBot', 'Create Bot')}\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<Bot size={18} />}>\n {t(\n 'botlit.botsList.purpose',\n 'A bot is the deployable, user-facing surface for your AI — it wraps one or more agents and exposes them to people through chat, channels (Slack, web widget, WhatsApp) and APIs. Create a bot here when you are ready to put an agent in front of real users, then connect channels and watch its executions.'\n )}\n </PagePurpose>\n\n {/* Summary */}\n {bots && bots.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\">\n {t('botlit.botsList.summary.total', 'Total bots')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {bots.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botsList.summary.active', 'Active')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {bots.filter((b: { status?: string }) => b.status === 'ACTIVE').length}\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\">\n {t('botlit.botsList.summary.executions', 'Total executions')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {formatNumber(bots.reduce((sum, bot) => sum + (bot.executionCount ?? 0), 0))}\n </p>\n </GlassCard>\n </div>\n ) : null}\n\n {/* Toolbar */}\n <div className=\"flex items-center justify-between 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={t('botlit.botsList.searchPlaceholder', 'Search bots...')}\n value={botFilter.search || ''}\n onChange={handleSearch}\n className=\"pl-9\"\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Button\n variant={viewMode === 'grid' ? 'secondary' : 'ghost'}\n size=\"icon\"\n onClick={() => setViewMode('grid')}\n >\n <Grid3X3 size={18} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'secondary' : 'ghost'}\n size=\"icon\"\n onClick={() => setViewMode('list')}\n >\n <List size={18} />\n </Button>\n </div>\n </div>\n\n {/* Content */}\n {loading ? (\n <div\n className={cn(\n 'gap-4',\n viewMode === 'grid'\n ? 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3'\n : 'flex flex-col'\n )}\n >\n {[1, 2, 3, 4, 5, 6].map((i) => (\n <div\n key={i}\n className=\"h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : filteredBots && filteredBots.length > 0 ? (\n viewMode === 'grid' ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {filteredBots.map((bot) => (\n <Card\n key={bot.id}\n className=\"group hover:shadow-md transition-shadow cursor-pointer relative\"\n onClick={() => navigateTo(`bots/${bot.id}`)}\n >\n <CardContent className=\"pt-6\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <span className=\"text-4xl\">{bot.icon || '🤖'}</span>\n <div>\n <h3 className=\"font-semibold text-text-primary\">{bot.name}</h3>\n <StatusBadge status={bot.status} />\n </div>\n </div>\n <div className=\"relative\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"opacity-0 group-hover:opacity-100 transition-opacity\"\n onClick={(e) => {\n e.stopPropagation();\n setMenuOpen(menuOpen === bot.id ? null : bot.id);\n }}\n >\n <MoreVertical size={16} />\n </Button>\n {menuOpen === bot.id && (\n <div className=\"absolute right-0 top-full mt-1 w-48 bg-popover border border-border-subtle rounded-md shadow-lg z-10\">\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}/edit`);\n setMenuOpen(null);\n }}\n >\n <Edit size={16} />\n {t('botlit.botsList.menu.editBot', 'Edit Bot')}\n </button>\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}?tab=workflow`);\n setMenuOpen(null);\n }}\n >\n <Workflow size={16} />\n {t('botlit.botsList.menu.design', 'Design workflow')}\n </button>\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}/agents`);\n setMenuOpen(null);\n }}\n >\n <Bot size={16} />\n {t('botlit.botsList.menu.viewAgents', 'View Agents')}\n </button>\n <button\n className=\"w-full px-4 py-2 text-left text-sm hover:bg-accent text-status-error-text flex items-center gap-2\"\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(bot);\n }}\n >\n <Trash2 size={16} />\n {t('botlit.common.delete', 'Delete')}\n </button>\n </div>\n )}\n </div>\n </div>\n <p className=\"mt-3 text-sm text-text-secondary line-clamp-2\">\n {bot.description}\n </p>\n <div className=\"mt-4 flex items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Bot size={14} />\n {bot.executionCount || 0} {t('botlit.common.executions', 'executions')}\n </span>\n </div>\n <div className=\"mt-3 pt-3 border-t border-border-subtle flex items-center justify-between gap-2\">\n <span className=\"text-xs text-text-secondary\">\n {t('botlit.botsList.createdLabel', 'Created')}{' '}\n {formatRelativeTime(bot.createdAt)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n leftIcon={<Workflow size={14} />}\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}?tab=workflow`);\n }}\n >\n {t('botlit.botsList.actions.design', 'Design')}\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {filteredBots.map((bot) => (\n <Card\n key={bot.id}\n className=\"hover:shadow-md transition-shadow cursor-pointer\"\n onClick={() => navigateTo(`bots/${bot.id}`)}\n >\n <CardContent className=\"py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <span className=\"text-3xl\">{bot.icon || '🤖'}</span>\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold text-text-primary\">{bot.name}</h3>\n <StatusBadge status={bot.status} />\n </div>\n <p className=\"text-sm text-text-secondary line-clamp-1\">\n {bot.description}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-6 text-sm text-text-secondary\">\n <span>\n {formatNumber(bot.executionCount)}{' '}\n {t('botlit.common.executions', 'executions')}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n leftIcon={<Workflow size={14} />}\n onClick={(e) => {\n e.stopPropagation();\n navigateTo(`bots/${bot.id}?tab=workflow`);\n }}\n >\n {t('botlit.botsList.actions.design', 'Design')}\n </Button>\n <Button variant=\"ghost\" size=\"sm\">\n <Link to={getPath(`bots/${bot.id}`)}>\n {t('botlit.common.view', 'View')}\n </Link>\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )\n ) : (\n <EmptyState\n illustration=\"empty-agents\"\n title={t('botlit.botsList.empty.title', 'No bots yet')}\n description={t(\n 'botlit.botsList.empty.description',\n 'Create your first AI-powered bot to get started with building agents and automations.'\n )}\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => navigateTo('bots/new')}>\n {t('botlit.botsList.actions.createBot', 'Create Bot')}\n </Button>\n }\n />\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -189,7 +189,7 @@ var F = ({ bucket: e, level: t, expanded: n, onToggle: r, getPath: i, onEdit: a,
|
|
|
189
189
|
children: [
|
|
190
190
|
/* @__PURE__ */ b(ae, {
|
|
191
191
|
icon: /* @__PURE__ */ b(O, { size: 18 }),
|
|
192
|
-
children: "Buckets are folders for everything you build in
|
|
192
|
+
children: "Buckets are folders for everything you build in BotManor — agents, bots, skills, knowledge and more — arranged in a hierarchy that mirrors how your team works. Group resources by team, project or environment so they stay organised, easy to find and simple to share as your account grows. Browse the tree or list view to manage that structure."
|
|
193
193
|
}),
|
|
194
194
|
K.length > 0 ? /* @__PURE__ */ x("div", {
|
|
195
195
|
className: "grid grid-cols-2 gap-4 sm:grid-cols-2",
|
|
@@ -292,7 +292,7 @@ var F = ({ bucket: e, level: t, expanded: n, onToggle: r, getPath: i, onEdit: a,
|
|
|
292
292
|
}) : /* @__PURE__ */ b(f, {
|
|
293
293
|
illustration: "empty-files",
|
|
294
294
|
title: "No buckets created",
|
|
295
|
-
description: "Create buckets to organize your
|
|
295
|
+
description: "Create buckets to organize your BotManor resources.",
|
|
296
296
|
action: /* @__PURE__ */ b(c, {
|
|
297
297
|
leftIcon: /* @__PURE__ */ b(A, { size: 16 }),
|
|
298
298
|
onClick: () => $(),
|
|
@@ -347,7 +347,7 @@ var F = ({ bucket: e, level: t, expanded: n, onToggle: r, getPath: i, onEdit: a,
|
|
|
347
347
|
}) : /* @__PURE__ */ b(f, {
|
|
348
348
|
illustration: "empty-search",
|
|
349
349
|
title: "No buckets found",
|
|
350
|
-
description: "Create buckets to organize your
|
|
350
|
+
description: "Create buckets to organize your BotManor resources.",
|
|
351
351
|
action: /* @__PURE__ */ b(c, {
|
|
352
352
|
leftIcon: /* @__PURE__ */ b(A, { size: 16 }),
|
|
353
353
|
onClick: () => $(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BucketsPage.js","names":[],"sources":["../../../src/botlit/pages/BucketsPage.tsx"],"sourcesContent":["/**\n * Buckets 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 { toast } from 'sonner';\nimport { isNative, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport {\n Plus,\n Search as SearchIcon,\n FolderTree,\n Folder,\n FolderOpen,\n ChevronRight,\n ChevronDown,\n MoreHorizontal,\n Settings,\n Edit,\n Trash2,\n X,\n Save,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport {\n useBuckets,\n useBucketTree,\n useCreateBucket,\n useDeleteBucket,\n useUpdateBucket,\n type BucketRecord,\n type BucketTreeNode,\n} from '../hooks';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { Visibility } from '../types';\n\ntype BucketNode = BucketTreeNode;\n\nconst BucketTreeItem: FC<{\n bucket: BucketNode;\n level: number;\n expanded: Set<string>;\n onToggle: (id: string) => void;\n getPath: (path: string) => string;\n onEdit: (bucket: BucketNode) => void;\n onDelete: (bucketId: string) => void;\n onCreateChild: (parentId: string) => void;\n activeMenu: string | null;\n setActiveMenu: (id: string | null) => void;\n}> = ({\n bucket,\n level,\n expanded,\n onToggle,\n getPath,\n onEdit,\n onDelete,\n onCreateChild,\n activeMenu,\n setActiveMenu,\n}) => {\n const isExpanded = expanded.has(bucket.id);\n const hasChildren = bucket.children.length > 0;\n const isMenuOpen = activeMenu === bucket.id;\n\n return (\n <div>\n <Link to={getPath(`buckets/${bucket.id}`)}>\n <div\n className=\"flex items-center gap-2 px-3 py-2 hover:bg-accent rounded-md transition-colors cursor-pointer group\"\n style={{ paddingLeft: `${level * 24 + 12}px` }}\n >\n {hasChildren ? (\n <button\n onClick={(e) => {\n e.preventDefault();\n onToggle(bucket.id);\n }}\n className=\"p-0.5 hover:bg-bg-sunken rounded\"\n >\n {isExpanded ? (\n <ChevronDown size={16} className=\"text-text-secondary\" />\n ) : (\n <ChevronRight size={16} className=\"text-text-secondary\" />\n )}\n </button>\n ) : (\n <div className=\"w-5\" />\n )}\n\n {isExpanded ? (\n <FolderOpen size={18} className=\"text-primary\" />\n ) : (\n <Folder size={18} className=\"text-text-secondary\" />\n )}\n\n <span className=\"flex-1 font-medium\">{bucket.name}</span>\n\n <div className=\"relative\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7 opacity-0 group-hover:opacity-100 transition-opacity\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n setActiveMenu(isMenuOpen ? null : bucket.id);\n }}\n >\n <MoreHorizontal size={14} />\n </Button>\n {isMenuOpen && (\n <div className=\"absolute right-0 top-8 bg-popover border rounded-md shadow-lg z-50 py-1 min-w-[160px]\">\n <button\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent text-left\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onCreateChild(bucket.id);\n }}\n >\n <Plus size={14} />\n Add Sub-Bucket\n </button>\n <button\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent text-left\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onEdit(bucket);\n }}\n >\n <Edit size={14} />\n Edit\n </button>\n <button\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent text-status-error-text text-left\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onDelete(bucket.id);\n }}\n >\n <Trash2 size={14} />\n Delete\n </button>\n </div>\n )}\n </div>\n </div>\n </Link>\n\n {isExpanded &&\n bucket.children.map((child) => (\n <BucketTreeItem\n key={child.id}\n bucket={child}\n level={level + 1}\n expanded={expanded}\n onToggle={onToggle}\n getPath={getPath}\n onEdit={onEdit}\n onDelete={onDelete}\n onCreateChild={onCreateChild}\n activeMenu={activeMenu}\n setActiveMenu={setActiveMenu}\n />\n ))}\n </div>\n );\n};\n\nexport const BucketsPage: FC = () => {\n const { getPath } = useBotlit();\n const [search, setSearch] = useState('');\n const [viewMode, setViewMode] = useState<'tree' | 'list'>('tree');\n const [expanded, setExpanded] = useState<Set<string>>(new Set(['bucket-1']));\n\n // Modal states\n const [showCreateModal, setShowCreateModal] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState<string | null>(null);\n const [editingBucket, setEditingBucket] = useState<BucketNode | null>(null);\n const [actionMenuBucket, setActionMenuBucket] = useState<string | null>(null);\n\n // Form state\n const [formData, setFormData] = useState({\n name: '',\n description: '',\n visibility: 'PRIVATE' as Visibility,\n parentBucketId: undefined as string | undefined,\n });\n\n const {\n data: buckets,\n loading: loadingBuckets,\n error: bucketsError,\n refetch: refetchBuckets,\n } = useBuckets({ search });\n const {\n data: bucketTree,\n loading: loadingTree,\n error: treeError,\n refetch: refetchTree,\n } = useBucketTree();\n const [createBucket, createBucketResult] = useCreateBucket();\n const [updateBucket, updateBucketResult] = useUpdateBucket();\n const [deleteBucket, deleteBucketResult] = useDeleteBucket();\n\n const handleToggle = (id: string) => {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n };\n\n const expandAll = () => {\n if (bucketTree) {\n const allIds = new Set<string>();\n const collectIds = (nodes: BucketNode[]) => {\n for (const node of nodes) {\n allIds.add(node.id);\n if (node.children) collectIds(node.children);\n }\n };\n collectIds(bucketTree);\n setExpanded(allIds);\n }\n };\n\n const collapseAll = () => {\n setExpanded(new Set());\n };\n\n const isLoading = viewMode === 'tree' ? loadingTree : loadingBuckets;\n const loadError = viewMode === 'tree' ? treeError : bucketsError;\n const retryLoad = viewMode === 'tree' ? refetchTree : refetchBuckets;\n\n const handleCreate = async () => {\n if (!formData.name) return;\n try {\n await createBucket({\n name: formData.name,\n slug: formData.name.toLowerCase().replace(/\\s+/g, '-'),\n description: formData.description,\n parentBucketId: formData.parentBucketId,\n metadata: { visibility: formData.visibility },\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to create bucket');\n return;\n }\n toast.success(`Bucket \"${formData.name}\" created`);\n void refetchBuckets();\n void refetchTree();\n setShowCreateModal(false);\n setFormData({ name: '', description: '', visibility: 'PRIVATE', parentBucketId: undefined });\n };\n\n const handleUpdate = async () => {\n if (!editingBucket || !formData.name) return;\n try {\n await updateBucket({\n bucketId: editingBucket.id,\n input: {\n name: formData.name,\n description: formData.description,\n },\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to update bucket');\n return;\n }\n toast.success('Bucket updated');\n void refetchBuckets();\n void refetchTree();\n setEditingBucket(null);\n };\n\n const handleDelete = async (bucketId: string) => {\n try {\n await deleteBucket(bucketId);\n if (isNative()) void nativeNotify('success');\n toast.success('Bucket deleted');\n void refetchBuckets();\n void refetchTree();\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n toast.error(err instanceof Error ? err.message : 'Failed to delete bucket');\n return;\n }\n setShowDeleteConfirm(null);\n };\n\n const startEditing = (bucket: BucketNode) => {\n setFormData({\n name: bucket.name,\n description: bucket.description ?? '',\n visibility: 'PRIVATE' as Visibility,\n parentBucketId: undefined,\n });\n setEditingBucket(bucket);\n setActionMenuBucket(null);\n };\n\n const openCreateModal = (parentId?: string) => {\n setFormData({\n name: '',\n description: '',\n visibility: 'PRIVATE',\n parentBucketId: parentId,\n });\n setShowCreateModal(true);\n };\n\n return (\n <PageLayout\n title=\"Buckets\"\n description=\"Organize your agents, apps, and resources into hierarchical folders\"\n actions={\n <Button leftIcon={<Plus size={16} />} onClick={() => openCreateModal()}>\n Create Bucket\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<FolderTree size={18} />}>\n Buckets are folders for everything you build in Botlit — agents, bots, skills, knowledge\n and more — arranged in a hierarchy that mirrors how your team works. Group resources by\n team, project or environment so they stay organised, easy to find and simple to share as\n your account grows. Browse the tree or list view to manage that structure.\n </PagePurpose>\n\n {/* Summary */}\n {buckets.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-2\">\n <GlassCard treatment=\"glass\" glow className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">Total buckets</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {buckets.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">Top-level buckets</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {bucketTree.length}\n </p>\n </GlassCard>\n </div>\n ) : null}\n\n {/* Controls */}\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"relative flex-1 max-w-md\">\n <SearchIcon className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search buckets...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={expandAll}>\n Expand All\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={collapseAll}>\n Collapse All\n </Button>\n <div className=\"flex border border-border-subtle rounded-md overflow-hidden\">\n <Button\n variant={viewMode === 'tree' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"rounded-none\"\n onClick={() => setViewMode('tree')}\n >\n <FolderTree size={16} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"rounded-none\"\n onClick={() => setViewMode('list')}\n >\n <Settings size={16} />\n </Button>\n </div>\n </div>\n </div>\n\n {/* Tree View */}\n {viewMode === 'tree' && (\n <Card>\n <CardContent className=\"p-2\">\n {isLoading ? (\n <div className=\"space-y-2 p-4\">\n {[1, 2, 3, 4].map((i) => (\n <div\n key={i}\n className=\"h-10 bg-bg-sunken motion-safe:animate-vc-shimmer rounded\"\n />\n ))}\n </div>\n ) : loadError ? (\n <ErrorState resource=\"buckets\" error={loadError} onRetry={() => void retryLoad()} />\n ) : bucketTree.length > 0 ? (\n <div className=\"py-2\" onClick={() => setActionMenuBucket(null)}>\n {bucketTree.map((bucket) => (\n <BucketTreeItem\n key={bucket.id}\n bucket={bucket}\n level={0}\n expanded={expanded}\n onToggle={handleToggle}\n getPath={getPath}\n onEdit={startEditing}\n onDelete={(id) => setShowDeleteConfirm(id)}\n onCreateChild={(parentId) => openCreateModal(parentId)}\n activeMenu={actionMenuBucket}\n setActiveMenu={setActionMenuBucket}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-files\"\n title=\"No buckets created\"\n description=\"Create buckets to organize your Botlit resources.\"\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => openCreateModal()}>\n Create Bucket\n </Button>\n }\n />\n )}\n </CardContent>\n </Card>\n )}\n\n {/* List View */}\n {viewMode === 'list' && (\n <>\n {isLoading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : loadError ? (\n <ErrorState resource=\"buckets\" error={loadError} onRetry={() => void retryLoad()} />\n ) : buckets.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {buckets.map((bucket: BucketRecord) => (\n <Link key={bucket.id} to={getPath(`buckets/${bucket.id}`)}>\n <Card className=\"h-full hover:border-primary/50 transition-colors cursor-pointer\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <Folder className=\"h-5 w-5 text-primary\" />\n <div>\n <CardTitle className=\"text-base\">{bucket.name}</CardTitle>\n <CardDescription className=\"text-xs\">{bucket.path}</CardDescription>\n </div>\n </div>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">{bucket.slug}</span>\n <span className=\"text-xs text-text-secondary\">\n {formatRelativeTime(bucket.createdAt)}\n </span>\n </div>\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n title=\"No buckets found\"\n description=\"Create buckets to organize your Botlit resources.\"\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => openCreateModal()}>\n Create Bucket\n </Button>\n }\n />\n )}\n </>\n )}\n\n {/* Info Card */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <FolderTree size={18} />\n Organizing with Buckets\n </CardTitle>\n <CardDescription>\n Buckets help you organize and manage permissions for your resources\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n <div className=\"space-y-2\">\n <h4 className=\"font-medium\">Hierarchical Organization</h4>\n <p className=\"text-sm text-text-secondary\">\n Create nested folder structures to organize apps, agents, and other resources by\n team, project, or domain.\n </p>\n </div>\n <div className=\"space-y-2\">\n <h4 className=\"font-medium\">Inherited Permissions</h4>\n <p className=\"text-sm text-text-secondary\">\n Set owners, editors, and viewers at the bucket level. Permissions cascade to all\n items within.\n </p>\n </div>\n <div className=\"space-y-2\">\n <h4 className=\"font-medium\">Default Policies</h4>\n <p className=\"text-sm text-text-secondary\">\n Configure default policy bindings for buckets. All new items inherit these\n policies automatically.\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Create Bucket Modal */}\n {showCreateModal && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-md mx-4\">\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Create Bucket</span>\n <Button variant=\"ghost\" size=\"icon\" onClick={() => setShowCreateModal(false)}>\n <X size={16} />\n </Button>\n </CardTitle>\n <CardDescription>\n {formData.parentBucketId ? 'Create a new sub-bucket' : 'Create a new root bucket'}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Bucket Name\" required>\n <Input\n placeholder=\"e.g., Marketing Team\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this bucket for?\"\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 <div className=\"flex justify-end gap-2 p-4 border-t\">\n <Button variant=\"outline\" onClick={() => setShowCreateModal(false)}>\n Cancel\n </Button>\n <Button\n onClick={handleCreate}\n isLoading={createBucketResult.loading}\n disabled={!formData.name}\n leftIcon={<Save size={16} />}\n >\n Create Bucket\n </Button>\n </div>\n </Card>\n </div>\n )}\n\n {/* Edit Bucket Modal */}\n {editingBucket && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-md mx-4\">\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Edit Bucket</span>\n <Button variant=\"ghost\" size=\"icon\" onClick={() => setEditingBucket(null)}>\n <X size={16} />\n </Button>\n </CardTitle>\n <CardDescription>Update bucket details</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Bucket Name\" required>\n <Input\n placeholder=\"e.g., Marketing Team\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this bucket for?\"\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 <div className=\"flex justify-end gap-2 p-4 border-t\">\n <Button variant=\"outline\" onClick={() => setEditingBucket(null)}>\n Cancel\n </Button>\n <Button\n onClick={handleUpdate}\n isLoading={updateBucketResult.loading}\n disabled={!formData.name}\n leftIcon={<Save size={16} />}\n >\n Save Changes\n </Button>\n </div>\n </Card>\n </div>\n )}\n\n {/* Delete Confirmation Modal */}\n {showDeleteConfirm && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-md mx-4\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-status-error-text\">\n <Trash2 size={18} />\n Delete Bucket\n </CardTitle>\n <CardDescription>\n Are you sure you want to delete this bucket? This action cannot be undone.\n </CardDescription>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary\">\n Note: Buckets with children or items cannot be deleted. You must delete or move\n all contents first.\n </p>\n </CardContent>\n <div className=\"flex justify-end gap-2 p-4 border-t\">\n <Button variant=\"outline\" onClick={() => setShowDeleteConfirm(null)}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n onClick={() => {\n nativeImpact('medium');\n void handleDelete(showDeleteConfirm);\n }}\n isLoading={deleteBucketResult.loading}\n leftIcon={<Trash2 size={16} />}\n >\n Delete Bucket\n </Button>\n </div>\n </Card>\n </div>\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BucketsPage.js","names":[],"sources":["../../../src/botlit/pages/BucketsPage.tsx"],"sourcesContent":["/**\n * Buckets 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 { toast } from 'sonner';\nimport { isNative, nativeImpact, nativeNotify } from '../../utils/nativeBridge';\nimport {\n Plus,\n Search as SearchIcon,\n FolderTree,\n Folder,\n FolderOpen,\n ChevronRight,\n ChevronDown,\n MoreHorizontal,\n Settings,\n Edit,\n Trash2,\n X,\n Save,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { EmptyState } from '../components/EmptyState';\nimport { ErrorState } from '../components/ErrorState';\nimport {\n useBuckets,\n useBucketTree,\n useCreateBucket,\n useDeleteBucket,\n useUpdateBucket,\n type BucketRecord,\n type BucketTreeNode,\n} from '../hooks';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { Visibility } from '../types';\n\ntype BucketNode = BucketTreeNode;\n\nconst BucketTreeItem: FC<{\n bucket: BucketNode;\n level: number;\n expanded: Set<string>;\n onToggle: (id: string) => void;\n getPath: (path: string) => string;\n onEdit: (bucket: BucketNode) => void;\n onDelete: (bucketId: string) => void;\n onCreateChild: (parentId: string) => void;\n activeMenu: string | null;\n setActiveMenu: (id: string | null) => void;\n}> = ({\n bucket,\n level,\n expanded,\n onToggle,\n getPath,\n onEdit,\n onDelete,\n onCreateChild,\n activeMenu,\n setActiveMenu,\n}) => {\n const isExpanded = expanded.has(bucket.id);\n const hasChildren = bucket.children.length > 0;\n const isMenuOpen = activeMenu === bucket.id;\n\n return (\n <div>\n <Link to={getPath(`buckets/${bucket.id}`)}>\n <div\n className=\"flex items-center gap-2 px-3 py-2 hover:bg-accent rounded-md transition-colors cursor-pointer group\"\n style={{ paddingLeft: `${level * 24 + 12}px` }}\n >\n {hasChildren ? (\n <button\n onClick={(e) => {\n e.preventDefault();\n onToggle(bucket.id);\n }}\n className=\"p-0.5 hover:bg-bg-sunken rounded\"\n >\n {isExpanded ? (\n <ChevronDown size={16} className=\"text-text-secondary\" />\n ) : (\n <ChevronRight size={16} className=\"text-text-secondary\" />\n )}\n </button>\n ) : (\n <div className=\"w-5\" />\n )}\n\n {isExpanded ? (\n <FolderOpen size={18} className=\"text-primary\" />\n ) : (\n <Folder size={18} className=\"text-text-secondary\" />\n )}\n\n <span className=\"flex-1 font-medium\">{bucket.name}</span>\n\n <div className=\"relative\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7 opacity-0 group-hover:opacity-100 transition-opacity\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n setActiveMenu(isMenuOpen ? null : bucket.id);\n }}\n >\n <MoreHorizontal size={14} />\n </Button>\n {isMenuOpen && (\n <div className=\"absolute right-0 top-8 bg-popover border rounded-md shadow-lg z-50 py-1 min-w-[160px]\">\n <button\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent text-left\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onCreateChild(bucket.id);\n }}\n >\n <Plus size={14} />\n Add Sub-Bucket\n </button>\n <button\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent text-left\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onEdit(bucket);\n }}\n >\n <Edit size={14} />\n Edit\n </button>\n <button\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent text-status-error-text text-left\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onDelete(bucket.id);\n }}\n >\n <Trash2 size={14} />\n Delete\n </button>\n </div>\n )}\n </div>\n </div>\n </Link>\n\n {isExpanded &&\n bucket.children.map((child) => (\n <BucketTreeItem\n key={child.id}\n bucket={child}\n level={level + 1}\n expanded={expanded}\n onToggle={onToggle}\n getPath={getPath}\n onEdit={onEdit}\n onDelete={onDelete}\n onCreateChild={onCreateChild}\n activeMenu={activeMenu}\n setActiveMenu={setActiveMenu}\n />\n ))}\n </div>\n );\n};\n\nexport const BucketsPage: FC = () => {\n const { getPath } = useBotlit();\n const [search, setSearch] = useState('');\n const [viewMode, setViewMode] = useState<'tree' | 'list'>('tree');\n const [expanded, setExpanded] = useState<Set<string>>(new Set(['bucket-1']));\n\n // Modal states\n const [showCreateModal, setShowCreateModal] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState<string | null>(null);\n const [editingBucket, setEditingBucket] = useState<BucketNode | null>(null);\n const [actionMenuBucket, setActionMenuBucket] = useState<string | null>(null);\n\n // Form state\n const [formData, setFormData] = useState({\n name: '',\n description: '',\n visibility: 'PRIVATE' as Visibility,\n parentBucketId: undefined as string | undefined,\n });\n\n const {\n data: buckets,\n loading: loadingBuckets,\n error: bucketsError,\n refetch: refetchBuckets,\n } = useBuckets({ search });\n const {\n data: bucketTree,\n loading: loadingTree,\n error: treeError,\n refetch: refetchTree,\n } = useBucketTree();\n const [createBucket, createBucketResult] = useCreateBucket();\n const [updateBucket, updateBucketResult] = useUpdateBucket();\n const [deleteBucket, deleteBucketResult] = useDeleteBucket();\n\n const handleToggle = (id: string) => {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n };\n\n const expandAll = () => {\n if (bucketTree) {\n const allIds = new Set<string>();\n const collectIds = (nodes: BucketNode[]) => {\n for (const node of nodes) {\n allIds.add(node.id);\n if (node.children) collectIds(node.children);\n }\n };\n collectIds(bucketTree);\n setExpanded(allIds);\n }\n };\n\n const collapseAll = () => {\n setExpanded(new Set());\n };\n\n const isLoading = viewMode === 'tree' ? loadingTree : loadingBuckets;\n const loadError = viewMode === 'tree' ? treeError : bucketsError;\n const retryLoad = viewMode === 'tree' ? refetchTree : refetchBuckets;\n\n const handleCreate = async () => {\n if (!formData.name) return;\n try {\n await createBucket({\n name: formData.name,\n slug: formData.name.toLowerCase().replace(/\\s+/g, '-'),\n description: formData.description,\n parentBucketId: formData.parentBucketId,\n metadata: { visibility: formData.visibility },\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to create bucket');\n return;\n }\n toast.success(`Bucket \"${formData.name}\" created`);\n void refetchBuckets();\n void refetchTree();\n setShowCreateModal(false);\n setFormData({ name: '', description: '', visibility: 'PRIVATE', parentBucketId: undefined });\n };\n\n const handleUpdate = async () => {\n if (!editingBucket || !formData.name) return;\n try {\n await updateBucket({\n bucketId: editingBucket.id,\n input: {\n name: formData.name,\n description: formData.description,\n },\n });\n } catch (err) {\n toast.error(err instanceof Error ? err.message : 'Failed to update bucket');\n return;\n }\n toast.success('Bucket updated');\n void refetchBuckets();\n void refetchTree();\n setEditingBucket(null);\n };\n\n const handleDelete = async (bucketId: string) => {\n try {\n await deleteBucket(bucketId);\n if (isNative()) void nativeNotify('success');\n toast.success('Bucket deleted');\n void refetchBuckets();\n void refetchTree();\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n toast.error(err instanceof Error ? err.message : 'Failed to delete bucket');\n return;\n }\n setShowDeleteConfirm(null);\n };\n\n const startEditing = (bucket: BucketNode) => {\n setFormData({\n name: bucket.name,\n description: bucket.description ?? '',\n visibility: 'PRIVATE' as Visibility,\n parentBucketId: undefined,\n });\n setEditingBucket(bucket);\n setActionMenuBucket(null);\n };\n\n const openCreateModal = (parentId?: string) => {\n setFormData({\n name: '',\n description: '',\n visibility: 'PRIVATE',\n parentBucketId: parentId,\n });\n setShowCreateModal(true);\n };\n\n return (\n <PageLayout\n title=\"Buckets\"\n description=\"Organize your agents, apps, and resources into hierarchical folders\"\n actions={\n <Button leftIcon={<Plus size={16} />} onClick={() => openCreateModal()}>\n Create Bucket\n </Button>\n }\n >\n <div className=\"space-y-6\">\n <PagePurpose icon={<FolderTree size={18} />}>\n Buckets are folders for everything you build in BotManor — agents, bots, skills, knowledge\n and more — arranged in a hierarchy that mirrors how your team works. Group resources by\n team, project or environment so they stay organised, easy to find and simple to share as\n your account grows. Browse the tree or list view to manage that structure.\n </PagePurpose>\n\n {/* Summary */}\n {buckets.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-2\">\n <GlassCard treatment=\"glass\" glow className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">Total buckets</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {buckets.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">Top-level buckets</p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {bucketTree.length}\n </p>\n </GlassCard>\n </div>\n ) : null}\n\n {/* Controls */}\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"relative flex-1 max-w-md\">\n <SearchIcon className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search buckets...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={expandAll}>\n Expand All\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={collapseAll}>\n Collapse All\n </Button>\n <div className=\"flex border border-border-subtle rounded-md overflow-hidden\">\n <Button\n variant={viewMode === 'tree' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"rounded-none\"\n onClick={() => setViewMode('tree')}\n >\n <FolderTree size={16} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'ghost'}\n size=\"sm\"\n className=\"rounded-none\"\n onClick={() => setViewMode('list')}\n >\n <Settings size={16} />\n </Button>\n </div>\n </div>\n </div>\n\n {/* Tree View */}\n {viewMode === 'tree' && (\n <Card>\n <CardContent className=\"p-2\">\n {isLoading ? (\n <div className=\"space-y-2 p-4\">\n {[1, 2, 3, 4].map((i) => (\n <div\n key={i}\n className=\"h-10 bg-bg-sunken motion-safe:animate-vc-shimmer rounded\"\n />\n ))}\n </div>\n ) : loadError ? (\n <ErrorState resource=\"buckets\" error={loadError} onRetry={() => void retryLoad()} />\n ) : bucketTree.length > 0 ? (\n <div className=\"py-2\" onClick={() => setActionMenuBucket(null)}>\n {bucketTree.map((bucket) => (\n <BucketTreeItem\n key={bucket.id}\n bucket={bucket}\n level={0}\n expanded={expanded}\n onToggle={handleToggle}\n getPath={getPath}\n onEdit={startEditing}\n onDelete={(id) => setShowDeleteConfirm(id)}\n onCreateChild={(parentId) => openCreateModal(parentId)}\n activeMenu={actionMenuBucket}\n setActiveMenu={setActionMenuBucket}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-files\"\n title=\"No buckets created\"\n description=\"Create buckets to organize your BotManor resources.\"\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => openCreateModal()}>\n Create Bucket\n </Button>\n }\n />\n )}\n </CardContent>\n </Card>\n )}\n\n {/* List View */}\n {viewMode === 'list' && (\n <>\n {isLoading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-32 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg\"\n />\n ))}\n </div>\n ) : loadError ? (\n <ErrorState resource=\"buckets\" error={loadError} onRetry={() => void retryLoad()} />\n ) : buckets.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {buckets.map((bucket: BucketRecord) => (\n <Link key={bucket.id} to={getPath(`buckets/${bucket.id}`)}>\n <Card className=\"h-full hover:border-primary/50 transition-colors cursor-pointer\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <Folder className=\"h-5 w-5 text-primary\" />\n <div>\n <CardTitle className=\"text-base\">{bucket.name}</CardTitle>\n <CardDescription className=\"text-xs\">{bucket.path}</CardDescription>\n </div>\n </div>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">{bucket.slug}</span>\n <span className=\"text-xs text-text-secondary\">\n {formatRelativeTime(bucket.createdAt)}\n </span>\n </div>\n </CardContent>\n </Card>\n </Link>\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n title=\"No buckets found\"\n description=\"Create buckets to organize your BotManor resources.\"\n action={\n <Button leftIcon={<Plus size={16} />} onClick={() => openCreateModal()}>\n Create Bucket\n </Button>\n }\n />\n )}\n </>\n )}\n\n {/* Info Card */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <FolderTree size={18} />\n Organizing with Buckets\n </CardTitle>\n <CardDescription>\n Buckets help you organize and manage permissions for your resources\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n <div className=\"space-y-2\">\n <h4 className=\"font-medium\">Hierarchical Organization</h4>\n <p className=\"text-sm text-text-secondary\">\n Create nested folder structures to organize apps, agents, and other resources by\n team, project, or domain.\n </p>\n </div>\n <div className=\"space-y-2\">\n <h4 className=\"font-medium\">Inherited Permissions</h4>\n <p className=\"text-sm text-text-secondary\">\n Set owners, editors, and viewers at the bucket level. Permissions cascade to all\n items within.\n </p>\n </div>\n <div className=\"space-y-2\">\n <h4 className=\"font-medium\">Default Policies</h4>\n <p className=\"text-sm text-text-secondary\">\n Configure default policy bindings for buckets. All new items inherit these\n policies automatically.\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Create Bucket Modal */}\n {showCreateModal && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-md mx-4\">\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Create Bucket</span>\n <Button variant=\"ghost\" size=\"icon\" onClick={() => setShowCreateModal(false)}>\n <X size={16} />\n </Button>\n </CardTitle>\n <CardDescription>\n {formData.parentBucketId ? 'Create a new sub-bucket' : 'Create a new root bucket'}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Bucket Name\" required>\n <Input\n placeholder=\"e.g., Marketing Team\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this bucket for?\"\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 <div className=\"flex justify-end gap-2 p-4 border-t\">\n <Button variant=\"outline\" onClick={() => setShowCreateModal(false)}>\n Cancel\n </Button>\n <Button\n onClick={handleCreate}\n isLoading={createBucketResult.loading}\n disabled={!formData.name}\n leftIcon={<Save size={16} />}\n >\n Create Bucket\n </Button>\n </div>\n </Card>\n </div>\n )}\n\n {/* Edit Bucket Modal */}\n {editingBucket && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-md mx-4\">\n <CardHeader>\n <CardTitle className=\"flex items-center justify-between\">\n <span>Edit Bucket</span>\n <Button variant=\"ghost\" size=\"icon\" onClick={() => setEditingBucket(null)}>\n <X size={16} />\n </Button>\n </CardTitle>\n <CardDescription>Update bucket details</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <FormField label=\"Bucket Name\" required>\n <Input\n placeholder=\"e.g., Marketing Team\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"What is this bucket for?\"\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 <div className=\"flex justify-end gap-2 p-4 border-t\">\n <Button variant=\"outline\" onClick={() => setEditingBucket(null)}>\n Cancel\n </Button>\n <Button\n onClick={handleUpdate}\n isLoading={updateBucketResult.loading}\n disabled={!formData.name}\n leftIcon={<Save size={16} />}\n >\n Save Changes\n </Button>\n </div>\n </Card>\n </div>\n )}\n\n {/* Delete Confirmation Modal */}\n {showDeleteConfirm && (\n <div className=\"fixed inset-0 bg-black/50 flex items-center justify-center z-50\">\n <Card className=\"w-full max-w-md mx-4\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-status-error-text\">\n <Trash2 size={18} />\n Delete Bucket\n </CardTitle>\n <CardDescription>\n Are you sure you want to delete this bucket? This action cannot be undone.\n </CardDescription>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary\">\n Note: Buckets with children or items cannot be deleted. You must delete or move\n all contents first.\n </p>\n </CardContent>\n <div className=\"flex justify-end gap-2 p-4 border-t\">\n <Button variant=\"outline\" onClick={() => setShowDeleteConfirm(null)}>\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n onClick={() => {\n nativeImpact('medium');\n void handleDelete(showDeleteConfirm);\n }}\n isLoading={deleteBucketResult.loading}\n leftIcon={<Trash2 size={16} />}\n >\n Delete Bucket\n </Button>\n </div>\n </Card>\n </div>\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -445,7 +445,7 @@ var N = ({ type: e }) => {
|
|
|
445
445
|
children: [
|
|
446
446
|
/* @__PURE__ */ y(be, {
|
|
447
447
|
icon: /* @__PURE__ */ y(T, { size: 18 }),
|
|
448
|
-
children: "This connector links
|
|
448
|
+
children: "This connector links BotManor to one messaging platform. From here you add routes — each mapping a specific location on the channel (a Slack channel, a widget, a number) to the bot that should answer there — tweak the connector’s settings, and manage its connection. Set up at least one route so messages on this channel reach a bot."
|
|
449
449
|
}),
|
|
450
450
|
/* @__PURE__ */ y(ye, {
|
|
451
451
|
storageKey: `botlit-channel-${L.id}`,
|