@burdenoff/microfe-botmanor 2026.821.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/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/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/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":"BotWorkflowTab.js","names":[],"sources":["../../../src/botlit/pages/BotWorkflowTab.tsx"],"sourcesContent":["/**\n * BotWorkflowTab\n * @module botlit/pages\n *\n * Shown inside BotDetailPage → \"Workflow\" tab.\n *\n * A bot's behaviour is designed as a FluidGrids workflow. `BotApp.workflowId`\n * holds the binding (validated server-side by `assertWorkflowBindingsResolvable`\n * on wspace-botlit-svc), and the FluidGrids builder is already mounted INSIDE\n * Botlit at `workflows/workflow/:id/:version` — so this tab never leaves the\n * product.\n *\n * Flow:\n * 1. Bound → resolve the definition by id (`useWorkflowDefinition`), show\n * name / key / version / status, \"Open in builder\", \"Unbind\".\n * A binding that no longer resolves falls back to the raw id so\n * the user can still clear it.\n * 2. Not bound → zero state whose primary action creates a seeded workflow\n * definition, binds it via `updateBotApp(workflowId)` and drops\n * the user straight into the embedded builder.\n *\n * IMPORTANT — seed graph shape. `BotlitFluidGridsBridge.extractTriggerNodeIds`\n * reads nodes from `definitionJson.data.nodes` (NOT the top level) and treats a\n * node as a trigger when its `type` is `trigger`/`trigger:*`/`*_trigger`, OR its\n * `kind[]` / `data.nodeData.kind[]` contains `trigger`. The seed below uses the\n * workflow service's own BUILTIN manual trigger (`internal:api`, \"Trigger\n * Manually\") — the node the executor resolves as the entry point — and carries\n * `kind: ['trigger', ...]` in both places, so a freshly designed bot is\n * immediately runnable instead of failing with `WORKFLOW_NO_TRIGGER_NODE`.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useState } from 'react';\nimport { ExternalLink, Sparkles, Unlink, Workflow } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useCreateWorkflow, useWorkflowDefinition } from '@burdenoff/fluidgrids-fe-sdk';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useUpdateBot } from '../hooks/useBots';\nimport { useBotlit } from '../providers/BotlitProvider';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Seed graph\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** First version minted for a bot's workflow — matches the builder's own default. */\nconst INITIAL_VERSION = 'v1';\n\n/**\n * BUILTIN \"Trigger Manually\" node (`MANUAL_TRIGGER_MANIFEST` in\n * wspace-workflow-svc). The executor resolves this type as a workflow's entry\n * node, and the builder renders it from the seeded node registry.\n */\nconst MANUAL_TRIGGER_NODE_TYPE = 'internal:api';\nconst MANUAL_TRIGGER_NODE_VERSION = '1.0.0';\nconst MANUAL_TRIGGER_OPERATION = 'onManualTrigger';\nconst MANUAL_TRIGGER_NAME = 'Trigger Manually';\nconst MANUAL_TRIGGER_DESCRIPTION =\n \"Runs the flow when you click 'Test workflow', or when this bot is invoked.\";\n\n/** `kind[]` the Botlit bridge scans for when classifying a node as a trigger. */\nconst MANUAL_TRIGGER_KIND = ['trigger', 'manual', 'entry'];\n\n/** Node shape written into `definitionJson.data.nodes`. */\ntype SeedNode = {\n id: string;\n type: string;\n position: { x: number; y: number };\n /** Top-level kind — the bridge's second trigger-detection path. */\n kind: string[];\n data: {\n operation_name: string;\n operation_type: string;\n version: string;\n nodeData: {\n nodeType: string;\n name: string;\n description: string;\n version: string;\n /** The bridge's third trigger-detection path. */\n kind: string[];\n operations: { name: string; type: string; role: string; description: string }[];\n };\n args: {\n context: { node: { id: string; type: string; kind: string[] } };\n state: Record<string, never>;\n credentials: never[];\n };\n };\n};\n\n/**\n * `definitionJson` document. Mirrors what the builder itself persists\n * (`useSaveWorkflow`) so the graph round-trips through the builder unchanged.\n */\ntype SeedDefinition = {\n key: string;\n name: string;\n description: string;\n workflow_type: string;\n data: {\n id: string;\n workflowKey: string;\n version: string;\n name: string;\n nodes: SeedNode[];\n edges: never[];\n sidebar: { active: string; panels: { nodeProperties: { selectedNode: null } } };\n stickyNotes: never[];\n };\n meta: { creator: string; version: string };\n tags: string[];\n};\n\n/**\n * Generate an opaque id. `crypto.randomUUID` is unavailable on insecure origins\n * and in some test environments, so fall back to a time+random token rather than\n * throwing mid-create.\n */\nfunction generateId(): string {\n const webCrypto = globalThis.crypto as Crypto | undefined;\n if (webCrypto && typeof webCrypto.randomUUID === 'function') {\n return webCrypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Build the starter graph: one manual trigger, nothing else. */\nfunction buildSeedDefinition(workflowKey: string, name: string): SeedDefinition {\n const triggerNode: SeedNode = {\n id: generateId(),\n type: MANUAL_TRIGGER_NODE_TYPE,\n position: { x: 160, y: 160 },\n kind: MANUAL_TRIGGER_KIND,\n data: {\n operation_name: MANUAL_TRIGGER_OPERATION,\n operation_type: 'trigger',\n version: MANUAL_TRIGGER_NODE_VERSION,\n nodeData: {\n nodeType: MANUAL_TRIGGER_NODE_TYPE,\n name: MANUAL_TRIGGER_NAME,\n description: MANUAL_TRIGGER_DESCRIPTION,\n version: MANUAL_TRIGGER_NODE_VERSION,\n kind: MANUAL_TRIGGER_KIND,\n operations: [\n {\n name: MANUAL_TRIGGER_OPERATION,\n type: 'trigger',\n role: 'trigger',\n description: MANUAL_TRIGGER_DESCRIPTION,\n },\n ],\n },\n args: {\n context: {\n node: {\n id: MANUAL_TRIGGER_NODE_TYPE,\n type: MANUAL_TRIGGER_NODE_TYPE,\n kind: MANUAL_TRIGGER_KIND,\n },\n },\n state: {},\n credentials: [],\n },\n },\n };\n\n return {\n key: workflowKey,\n name,\n description: name,\n workflow_type: 'query-conditional',\n data: {\n id: workflowKey,\n workflowKey,\n version: INITIAL_VERSION,\n name,\n nodes: [triggerNode],\n edges: [],\n sidebar: { active: 'store-browse', panels: { nodeProperties: { selectedNode: null } } },\n stickyNotes: [],\n },\n meta: { creator: 'botlit_bot_design', version: INITIAL_VERSION },\n tags: [],\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface BotWorkflowTabProps {\n botId: string;\n botName: string;\n /** `BotApp.workflowId` — the bound workflow definition id, if any. */\n workflowId: string | null | undefined;\n /** Refetch the bot so the tab reflects the new binding. */\n onWorkflowChanged: () => Promise<void> | void;\n}\n\nexport const BotWorkflowTab: FC<BotWorkflowTabProps> = ({\n botId,\n botName,\n workflowId,\n onWorkflowChanged,\n}) => {\n const { t: translate } = useI18n();\n // Stable identity: the create/unbind callbacks below close over `t`, so a new\n // function every render would invalidate them (and their consumers) each time.\n const t = useCallback(\n (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n const { navigateTo } = useBotlit();\n const { createWorkflow } = useCreateWorkflow();\n const [updateBot] = useUpdateBot();\n const [busy, setBusy] = useState(false);\n\n // Resolve by id — `BotApp.workflowId` stores the definition's opaque id, not\n // its workflowKey (which is what the builder route takes). The hook refetches\n // on its own when the bound id changes, so binding/unbinding only has to\n // refresh the bot.\n const { workflow, loading: workflowLoading } = useWorkflowDefinition(\n undefined,\n workflowId ?? undefined\n );\n\n const openBuilder = useCallback(\n (workflowKey: string, version: string) => {\n navigateTo(`workflows/workflow/${workflowKey}/${version || INITIAL_VERSION}`);\n },\n [navigateTo]\n );\n\n const handleDesign = useCallback(async () => {\n setBusy(true);\n try {\n const workflowKey = generateId();\n const name = `${botName} workflow`;\n const created = await createWorkflow({\n workflowKey,\n version: INITIAL_VERSION,\n name,\n description: t(\n 'botlit.botDetail.workflow.createdDescription',\n 'Behaviour designed for this Botlit bot.'\n ),\n definitionJson: buildSeedDefinition(workflowKey, name),\n });\n\n if (!created) {\n throw new Error(\n t('botlit.botDetail.workflow.createError', 'Failed to create the workflow')\n );\n }\n\n await updateBot({ botId, input: { workflowId: created.id } });\n await onWorkflowChanged();\n toast.success(\n t('botlit.botDetail.workflow.createSuccess', 'Workflow created and bound to this bot')\n );\n openBuilder(created.workflowKey, created.version);\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.createError', 'Failed to create the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, botName, createWorkflow, onWorkflowChanged, openBuilder, t, updateBot]);\n\n const handleUnbind = useCallback(async () => {\n if (\n !confirm(\n t(\n 'botlit.botDetail.workflow.unbindConfirm',\n 'Unbind this workflow from the bot? The workflow itself is not deleted.'\n )\n )\n ) {\n return;\n }\n setBusy(true);\n try {\n await updateBot({ botId, input: { workflowId: null } });\n await onWorkflowChanged();\n toast.success(t('botlit.botDetail.workflow.unbindSuccess', 'Workflow unbound'));\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.unbindError', 'Failed to unbind the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, onWorkflowChanged, t, updateBot]);\n\n // ── Not bound ─────────────────────────────────────────────────────────────\n if (!workflowId) {\n return (\n <Card>\n <CardContent className=\"pt-6\">\n <EmptyState\n illustration=\"empty-generic\"\n title={t('botlit.botDetail.workflow.empty.title', 'Design this bot as a workflow')}\n description={t(\n 'botlit.botDetail.workflow.empty.description',\n \"A bot's behaviour is designed as a FluidGrids workflow — the visual canvas where you wire triggers, agents, tools and conditions together. Start one and we will create it, bind it to this bot and open the builder for you.\"\n )}\n action={\n <Button\n leftIcon={<Sparkles size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleDesign()}\n >\n {t('botlit.botDetail.workflow.empty.action', 'Design in workflow builder')}\n </Button>\n }\n />\n </CardContent>\n </Card>\n );\n }\n\n // ── Bound ─────────────────────────────────────────────────────────────────\n return (\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Workflow size={18} />\n {t('botlit.botDetail.workflow.bound.title', 'Bound workflow')}\n </CardTitle>\n <CardDescription>\n {t(\n 'botlit.botDetail.workflow.bound.description',\n 'This workflow defines what the bot does when it is invoked.'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {workflowLoading ? (\n <div className=\"h-24 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ) : workflow ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.name', 'Name')}\n </p>\n <p className=\"font-medium text-text-primary\">{workflow.name}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.key', 'Key')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">\n {workflow.workflowKey}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.version', 'Version')}\n </p>\n <Badge variant=\"outline\" className=\"mt-1\">\n {workflow.version}\n </Badge>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.status', 'Status')}\n </p>\n <div className=\"mt-1\">\n <StatusBadge status={workflow.status} />\n </div>\n </div>\n </div>\n ) : (\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.workflowId', 'Workflow ID')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">{workflowId}</p>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {t(\n 'botlit.botDetail.workflow.unresolved',\n 'This workflow could not be loaded — it may have been deleted. Unbind it and design a new one.'\n )}\n </p>\n </div>\n )}\n\n <div className=\"flex flex-wrap gap-2\">\n {workflow && (\n <Button\n leftIcon={<ExternalLink size={16} />}\n disabled={busy}\n onClick={() => openBuilder(workflow.workflowKey, workflow.version)}\n >\n {t('botlit.botDetail.workflow.actions.openBuilder', 'Open in builder')}\n </Button>\n )}\n <Button\n variant=\"outline\"\n leftIcon={<Unlink size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleUnbind()}\n >\n {t('botlit.botDetail.workflow.actions.unbind', 'Unbind')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BotWorkflowTab.js","names":[],"sources":["../../../src/botlit/pages/BotWorkflowTab.tsx"],"sourcesContent":["/**\n * BotWorkflowTab\n * @module botlit/pages\n *\n * Shown inside BotDetailPage → \"Workflow\" tab.\n *\n * A bot's behaviour is designed as a FluidGrids workflow. `BotApp.workflowId`\n * holds the binding (validated server-side by `assertWorkflowBindingsResolvable`\n * on wspace-botlit-svc), and the FluidGrids builder is already mounted INSIDE\n * BotManor at `workflows/workflow/:id/:version` — so this tab never leaves the\n * product.\n *\n * Flow:\n * 1. Bound → resolve the definition by id (`useWorkflowDefinition`), show\n * name / key / version / status, \"Open in builder\", \"Unbind\".\n * A binding that no longer resolves falls back to the raw id so\n * the user can still clear it.\n * 2. Not bound → zero state whose primary action creates a seeded workflow\n * definition, binds it via `updateBotApp(workflowId)` and drops\n * the user straight into the embedded builder.\n *\n * IMPORTANT — seed graph shape. `BotlitFluidGridsBridge.extractTriggerNodeIds`\n * reads nodes from `definitionJson.data.nodes` (NOT the top level) and treats a\n * node as a trigger when its `type` is `trigger`/`trigger:*`/`*_trigger`, OR its\n * `kind[]` / `data.nodeData.kind[]` contains `trigger`. The seed below uses the\n * workflow service's own BUILTIN manual trigger (`internal:api`, \"Trigger\n * Manually\") — the node the executor resolves as the entry point — and carries\n * `kind: ['trigger', ...]` in both places, so a freshly designed bot is\n * immediately runnable instead of failing with `WORKFLOW_NO_TRIGGER_NODE`.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useState } from 'react';\nimport { ExternalLink, Sparkles, Unlink, Workflow } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useCreateWorkflow, useWorkflowDefinition } from '@burdenoff/fluidgrids-fe-sdk';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useUpdateBot } from '../hooks/useBots';\nimport { useBotlit } from '../providers/BotlitProvider';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Seed graph\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** First version minted for a bot's workflow — matches the builder's own default. */\nconst INITIAL_VERSION = 'v1';\n\n/**\n * BUILTIN \"Trigger Manually\" node (`MANUAL_TRIGGER_MANIFEST` in\n * wspace-workflow-svc). The executor resolves this type as a workflow's entry\n * node, and the builder renders it from the seeded node registry.\n */\nconst MANUAL_TRIGGER_NODE_TYPE = 'internal:api';\nconst MANUAL_TRIGGER_NODE_VERSION = '1.0.0';\nconst MANUAL_TRIGGER_OPERATION = 'onManualTrigger';\nconst MANUAL_TRIGGER_NAME = 'Trigger Manually';\nconst MANUAL_TRIGGER_DESCRIPTION =\n \"Runs the flow when you click 'Test workflow', or when this bot is invoked.\";\n\n/** `kind[]` the BotManor bridge scans for when classifying a node as a trigger. */\nconst MANUAL_TRIGGER_KIND = ['trigger', 'manual', 'entry'];\n\n/** Node shape written into `definitionJson.data.nodes`. */\ntype SeedNode = {\n id: string;\n type: string;\n position: { x: number; y: number };\n /** Top-level kind — the bridge's second trigger-detection path. */\n kind: string[];\n data: {\n operation_name: string;\n operation_type: string;\n version: string;\n nodeData: {\n nodeType: string;\n name: string;\n description: string;\n version: string;\n /** The bridge's third trigger-detection path. */\n kind: string[];\n operations: { name: string; type: string; role: string; description: string }[];\n };\n args: {\n context: { node: { id: string; type: string; kind: string[] } };\n state: Record<string, never>;\n credentials: never[];\n };\n };\n};\n\n/**\n * `definitionJson` document. Mirrors what the builder itself persists\n * (`useSaveWorkflow`) so the graph round-trips through the builder unchanged.\n */\ntype SeedDefinition = {\n key: string;\n name: string;\n description: string;\n workflow_type: string;\n data: {\n id: string;\n workflowKey: string;\n version: string;\n name: string;\n nodes: SeedNode[];\n edges: never[];\n sidebar: { active: string; panels: { nodeProperties: { selectedNode: null } } };\n stickyNotes: never[];\n };\n meta: { creator: string; version: string };\n tags: string[];\n};\n\n/**\n * Generate an opaque id. `crypto.randomUUID` is unavailable on insecure origins\n * and in some test environments, so fall back to a time+random token rather than\n * throwing mid-create.\n */\nfunction generateId(): string {\n const webCrypto = globalThis.crypto as Crypto | undefined;\n if (webCrypto && typeof webCrypto.randomUUID === 'function') {\n return webCrypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Build the starter graph: one manual trigger, nothing else. */\nfunction buildSeedDefinition(workflowKey: string, name: string): SeedDefinition {\n const triggerNode: SeedNode = {\n id: generateId(),\n type: MANUAL_TRIGGER_NODE_TYPE,\n position: { x: 160, y: 160 },\n kind: MANUAL_TRIGGER_KIND,\n data: {\n operation_name: MANUAL_TRIGGER_OPERATION,\n operation_type: 'trigger',\n version: MANUAL_TRIGGER_NODE_VERSION,\n nodeData: {\n nodeType: MANUAL_TRIGGER_NODE_TYPE,\n name: MANUAL_TRIGGER_NAME,\n description: MANUAL_TRIGGER_DESCRIPTION,\n version: MANUAL_TRIGGER_NODE_VERSION,\n kind: MANUAL_TRIGGER_KIND,\n operations: [\n {\n name: MANUAL_TRIGGER_OPERATION,\n type: 'trigger',\n role: 'trigger',\n description: MANUAL_TRIGGER_DESCRIPTION,\n },\n ],\n },\n args: {\n context: {\n node: {\n id: MANUAL_TRIGGER_NODE_TYPE,\n type: MANUAL_TRIGGER_NODE_TYPE,\n kind: MANUAL_TRIGGER_KIND,\n },\n },\n state: {},\n credentials: [],\n },\n },\n };\n\n return {\n key: workflowKey,\n name,\n description: name,\n workflow_type: 'query-conditional',\n data: {\n id: workflowKey,\n workflowKey,\n version: INITIAL_VERSION,\n name,\n nodes: [triggerNode],\n edges: [],\n sidebar: { active: 'store-browse', panels: { nodeProperties: { selectedNode: null } } },\n stickyNotes: [],\n },\n meta: { creator: 'botlit_bot_design', version: INITIAL_VERSION },\n tags: [],\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface BotWorkflowTabProps {\n botId: string;\n botName: string;\n /** `BotApp.workflowId` — the bound workflow definition id, if any. */\n workflowId: string | null | undefined;\n /** Refetch the bot so the tab reflects the new binding. */\n onWorkflowChanged: () => Promise<void> | void;\n}\n\nexport const BotWorkflowTab: FC<BotWorkflowTabProps> = ({\n botId,\n botName,\n workflowId,\n onWorkflowChanged,\n}) => {\n const t = useTr();\n const { navigateTo } = useBotlit();\n const { createWorkflow } = useCreateWorkflow();\n const [updateBot] = useUpdateBot();\n const [busy, setBusy] = useState(false);\n\n // Resolve by id — `BotApp.workflowId` stores the definition's opaque id, not\n // its workflowKey (which is what the builder route takes). The hook refetches\n // on its own when the bound id changes, so binding/unbinding only has to\n // refresh the bot.\n const { workflow, loading: workflowLoading } = useWorkflowDefinition(\n undefined,\n workflowId ?? undefined\n );\n\n const openBuilder = useCallback(\n (workflowKey: string, version: string) => {\n navigateTo(`workflows/workflow/${workflowKey}/${version || INITIAL_VERSION}`);\n },\n [navigateTo]\n );\n\n const handleDesign = useCallback(async () => {\n setBusy(true);\n try {\n const workflowKey = generateId();\n const name = `${botName} workflow`;\n const created = await createWorkflow({\n workflowKey,\n version: INITIAL_VERSION,\n name,\n description: t(\n 'botlit.botDetail.workflow.createdDescription',\n 'Behaviour designed for this BotManor bot.'\n ),\n definitionJson: buildSeedDefinition(workflowKey, name),\n });\n\n if (!created) {\n throw new Error(\n t('botlit.botDetail.workflow.createError', 'Failed to create the workflow')\n );\n }\n\n await updateBot({ botId, input: { workflowId: created.id } });\n await onWorkflowChanged();\n toast.success(\n t('botlit.botDetail.workflow.createSuccess', 'Workflow created and bound to this bot')\n );\n openBuilder(created.workflowKey, created.version);\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.createError', 'Failed to create the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, botName, createWorkflow, onWorkflowChanged, openBuilder, t, updateBot]);\n\n const handleUnbind = useCallback(async () => {\n if (\n !confirm(\n t(\n 'botlit.botDetail.workflow.unbindConfirm',\n 'Unbind this workflow from the bot? The workflow itself is not deleted.'\n )\n )\n ) {\n return;\n }\n setBusy(true);\n try {\n await updateBot({ botId, input: { workflowId: null } });\n await onWorkflowChanged();\n toast.success(t('botlit.botDetail.workflow.unbindSuccess', 'Workflow unbound'));\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.unbindError', 'Failed to unbind the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, onWorkflowChanged, t, updateBot]);\n\n // ── Not bound ─────────────────────────────────────────────────────────────\n if (!workflowId) {\n return (\n <Card>\n <CardContent className=\"pt-6\">\n <EmptyState\n illustration=\"empty-generic\"\n title={t('botlit.botDetail.workflow.empty.title', 'Design this bot as a workflow')}\n description={t(\n 'botlit.botDetail.workflow.empty.description',\n \"A bot's behaviour is designed as a FluidGrids workflow — the visual canvas where you wire triggers, agents, tools and conditions together. Start one and we will create it, bind it to this bot and open the builder for you.\"\n )}\n action={\n <Button\n leftIcon={<Sparkles size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleDesign()}\n >\n {t('botlit.botDetail.workflow.empty.action', 'Design in workflow builder')}\n </Button>\n }\n />\n </CardContent>\n </Card>\n );\n }\n\n // ── Bound ─────────────────────────────────────────────────────────────────\n return (\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Workflow size={18} />\n {t('botlit.botDetail.workflow.bound.title', 'Bound workflow')}\n </CardTitle>\n <CardDescription>\n {t(\n 'botlit.botDetail.workflow.bound.description',\n 'This workflow defines what the bot does when it is invoked.'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {workflowLoading ? (\n <div className=\"h-24 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ) : workflow ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.name', 'Name')}\n </p>\n <p className=\"font-medium text-text-primary\">{workflow.name}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.key', 'Key')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">\n {workflow.workflowKey}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.version', 'Version')}\n </p>\n <Badge variant=\"outline\" className=\"mt-1\">\n {workflow.version}\n </Badge>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.status', 'Status')}\n </p>\n <div className=\"mt-1\">\n <StatusBadge status={workflow.status} />\n </div>\n </div>\n </div>\n ) : (\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.workflowId', 'Workflow ID')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">{workflowId}</p>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {t(\n 'botlit.botDetail.workflow.unresolved',\n 'This workflow could not be loaded — it may have been deleted. Unbind it and design a new one.'\n )}\n </p>\n </div>\n )}\n\n <div className=\"flex flex-wrap gap-2\">\n {workflow && (\n <Button\n leftIcon={<ExternalLink size={16} />}\n disabled={busy}\n onClick={() => openBuilder(workflow.workflowKey, workflow.version)}\n >\n {t('botlit.botDetail.workflow.actions.openBuilder', 'Open in builder')}\n </Button>\n )}\n <Button\n variant=\"outline\"\n leftIcon={<Unlink size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleUnbind()}\n >\n {t('botlit.botDetail.workflow.actions.unbind', 'Unbind')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,134 +1,131 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { useBotlit as t } from "../providers/BotlitProvider.js";
|
|
3
|
+
import { useBotlitStore as n } from "../store/botlitStore.js";
|
|
4
|
+
import { useBots as r, useDeleteBot as i } from "../hooks/useBots.js";
|
|
5
|
+
import { cn as a } from "../utils/cn.js";
|
|
6
|
+
import { formatNumber as o, formatRelativeTime as s } from "../utils/formatters.js";
|
|
7
|
+
import { PageLayout as c } from "../components/PageLayout.js";
|
|
8
|
+
import { Card as l, CardContent as u } from "../components/Card.js";
|
|
9
|
+
import { Button as d } from "../components/Button.js";
|
|
10
|
+
import { StatusBadge as f } from "../components/Badge.js";
|
|
11
|
+
import { isNative as p, nativeConfirm as m, nativeImpact as h, nativeNotify as g } from "../../utils/nativeBridge.js";
|
|
12
|
+
import { EmptyState as _ } from "../components/EmptyState.js";
|
|
13
|
+
import { Input as v } from "../components/Input.js";
|
|
14
|
+
import { useState as y } from "react";
|
|
15
|
+
import { GlassCard as b, PagePurpose as x } from "@burdenoff/fe-libs/ui";
|
|
16
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
17
|
+
import { Link as w } from "react-router";
|
|
18
|
+
import { Bot as T, Edit as E, Grid3X3 as D, List as O, MoreVertical as k, Plus as A, Search as j, Trash2 as M, Workflow as N } from "lucide-react";
|
|
19
19
|
import { toast as P } from "sonner";
|
|
20
20
|
//#region src/botlit/pages/BotsListPage.tsx
|
|
21
21
|
var F = () => {
|
|
22
|
-
let { t:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
G({ search: e.target.value });
|
|
27
|
-
}, Y = async (e) => {
|
|
28
|
-
let t = `${I("botlit.botsList.delete.confirmPrefix", "Are you sure you want to delete")} "${e.name}"?`, n = await p({
|
|
22
|
+
let F = e(), { navigateTo: I, getPath: L } = t(), { data: R, loading: z } = r(), [B] = i(), { viewMode: V, setViewMode: H, botFilter: U, updateBotFilter: W } = n(), [G, K] = y(null), q = (e) => {
|
|
23
|
+
W({ search: e.target.value });
|
|
24
|
+
}, J = async (e) => {
|
|
25
|
+
let t = `${F("botlit.botsList.delete.confirmPrefix", "Are you sure you want to delete")} "${e.name}"?`, n = await m({
|
|
29
26
|
title: "Delete bot?",
|
|
30
27
|
message: t,
|
|
31
28
|
okButtonTitle: "Delete",
|
|
32
29
|
cancelButtonTitle: "Cancel"
|
|
33
30
|
});
|
|
34
31
|
if (n === null ? confirm(t) : n) {
|
|
35
|
-
|
|
32
|
+
h("medium");
|
|
36
33
|
try {
|
|
37
|
-
await
|
|
34
|
+
await B(e.id), P.success(`${F("botlit.botsList.delete.successPrefix", "Bot")} "${e.name}" ${F("botlit.botsList.delete.successSuffix", "deleted successfully")}`), p() && g("success");
|
|
38
35
|
} catch (e) {
|
|
39
|
-
let t = e instanceof Error ? e.message :
|
|
40
|
-
P.error(t),
|
|
36
|
+
let t = e instanceof Error ? e.message : F("botlit.botsList.delete.error", "Failed to delete bot");
|
|
37
|
+
P.error(t), p() && g("error");
|
|
41
38
|
}
|
|
42
39
|
}
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
if (
|
|
46
|
-
let t =
|
|
40
|
+
K(null);
|
|
41
|
+
}, Y = R?.filter((e) => {
|
|
42
|
+
if (U.search) {
|
|
43
|
+
let t = U.search.toLowerCase();
|
|
47
44
|
return e.name.toLowerCase().includes(t) || (e.description?.toLowerCase().includes(t) ?? !1);
|
|
48
45
|
}
|
|
49
46
|
return !0;
|
|
50
47
|
});
|
|
51
|
-
return /* @__PURE__ */
|
|
52
|
-
title:
|
|
53
|
-
description:
|
|
54
|
-
actions: /* @__PURE__ */
|
|
55
|
-
leftIcon: /* @__PURE__ */
|
|
56
|
-
onClick: () =>
|
|
57
|
-
children:
|
|
48
|
+
return /* @__PURE__ */ S(c, {
|
|
49
|
+
title: F("botlit.botsList.title", "Bots"),
|
|
50
|
+
description: F("botlit.botsList.description", "Manage your AI-powered bots"),
|
|
51
|
+
actions: /* @__PURE__ */ S(d, {
|
|
52
|
+
leftIcon: /* @__PURE__ */ S(A, { size: 16 }),
|
|
53
|
+
onClick: () => I("bots/new"),
|
|
54
|
+
children: F("botlit.botsList.actions.createBot", "Create Bot")
|
|
58
55
|
}),
|
|
59
|
-
children: /* @__PURE__ */
|
|
56
|
+
children: /* @__PURE__ */ C("div", {
|
|
60
57
|
className: "space-y-6",
|
|
61
58
|
children: [
|
|
62
|
-
/* @__PURE__ */ x
|
|
63
|
-
icon: /* @__PURE__ */
|
|
64
|
-
children:
|
|
59
|
+
/* @__PURE__ */ S(x, {
|
|
60
|
+
icon: /* @__PURE__ */ S(T, { size: 18 }),
|
|
61
|
+
children: F("botlit.botsList.purpose", "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.")
|
|
65
62
|
}),
|
|
66
|
-
|
|
63
|
+
R && R.length > 0 ? /* @__PURE__ */ C("div", {
|
|
67
64
|
className: "grid grid-cols-2 gap-4 sm:grid-cols-3",
|
|
68
65
|
children: [
|
|
69
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ C(b, {
|
|
70
67
|
treatment: "glass",
|
|
71
68
|
glow: !0,
|
|
72
69
|
className: "p-4",
|
|
73
|
-
children: [/* @__PURE__ */
|
|
70
|
+
children: [/* @__PURE__ */ S("p", {
|
|
74
71
|
className: "text-sm text-text-secondary",
|
|
75
|
-
children:
|
|
76
|
-
}), /* @__PURE__ */
|
|
72
|
+
children: F("botlit.botsList.summary.total", "Total bots")
|
|
73
|
+
}), /* @__PURE__ */ S("p", {
|
|
77
74
|
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
78
|
-
children:
|
|
75
|
+
children: R.length
|
|
79
76
|
})]
|
|
80
77
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
78
|
+
/* @__PURE__ */ C(b, {
|
|
82
79
|
treatment: "metric",
|
|
83
80
|
className: "p-4",
|
|
84
|
-
children: [/* @__PURE__ */
|
|
81
|
+
children: [/* @__PURE__ */ S("p", {
|
|
85
82
|
className: "text-sm text-text-secondary",
|
|
86
|
-
children:
|
|
87
|
-
}), /* @__PURE__ */
|
|
83
|
+
children: F("botlit.botsList.summary.active", "Active")
|
|
84
|
+
}), /* @__PURE__ */ S("p", {
|
|
88
85
|
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
89
|
-
children:
|
|
86
|
+
children: R.filter((e) => e.status === "ACTIVE").length
|
|
90
87
|
})]
|
|
91
88
|
}),
|
|
92
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ C(b, {
|
|
93
90
|
treatment: "metric",
|
|
94
91
|
className: "col-span-2 p-4 sm:col-span-1",
|
|
95
|
-
children: [/* @__PURE__ */
|
|
92
|
+
children: [/* @__PURE__ */ S("p", {
|
|
96
93
|
className: "text-sm text-text-secondary",
|
|
97
|
-
children:
|
|
98
|
-
}), /* @__PURE__ */
|
|
94
|
+
children: F("botlit.botsList.summary.executions", "Total executions")
|
|
95
|
+
}), /* @__PURE__ */ S("p", {
|
|
99
96
|
className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
|
|
100
|
-
children:
|
|
97
|
+
children: o(R.reduce((e, t) => e + (t.executionCount ?? 0), 0))
|
|
101
98
|
})]
|
|
102
99
|
})
|
|
103
100
|
]
|
|
104
101
|
}) : null,
|
|
105
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ C("div", {
|
|
106
103
|
className: "flex items-center justify-between gap-4",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
104
|
+
children: [/* @__PURE__ */ C("div", {
|
|
108
105
|
className: "relative flex-1 max-w-md",
|
|
109
|
-
children: [/* @__PURE__ */
|
|
110
|
-
placeholder:
|
|
111
|
-
value:
|
|
112
|
-
onChange:
|
|
106
|
+
children: [/* @__PURE__ */ S(j, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ S(v, {
|
|
107
|
+
placeholder: F("botlit.botsList.searchPlaceholder", "Search bots..."),
|
|
108
|
+
value: U.search || "",
|
|
109
|
+
onChange: q,
|
|
113
110
|
className: "pl-9"
|
|
114
111
|
})]
|
|
115
|
-
}), /* @__PURE__ */
|
|
112
|
+
}), /* @__PURE__ */ C("div", {
|
|
116
113
|
className: "flex items-center gap-2",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
118
|
-
variant:
|
|
114
|
+
children: [/* @__PURE__ */ S(d, {
|
|
115
|
+
variant: V === "grid" ? "secondary" : "ghost",
|
|
119
116
|
size: "icon",
|
|
120
|
-
onClick: () =>
|
|
121
|
-
children: /* @__PURE__ */
|
|
122
|
-
}), /* @__PURE__ */
|
|
123
|
-
variant:
|
|
117
|
+
onClick: () => H("grid"),
|
|
118
|
+
children: /* @__PURE__ */ S(D, { size: 18 })
|
|
119
|
+
}), /* @__PURE__ */ S(d, {
|
|
120
|
+
variant: V === "list" ? "secondary" : "ghost",
|
|
124
121
|
size: "icon",
|
|
125
|
-
onClick: () =>
|
|
126
|
-
children: /* @__PURE__ */
|
|
122
|
+
onClick: () => H("list"),
|
|
123
|
+
children: /* @__PURE__ */ S(O, { size: 18 })
|
|
127
124
|
})]
|
|
128
125
|
})]
|
|
129
126
|
}),
|
|
130
|
-
|
|
131
|
-
className:
|
|
127
|
+
z ? /* @__PURE__ */ S("div", {
|
|
128
|
+
className: a("gap-4", V === "grid" ? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3" : "flex flex-col"),
|
|
132
129
|
children: [
|
|
133
130
|
1,
|
|
134
131
|
2,
|
|
@@ -136,156 +133,156 @@ var F = () => {
|
|
|
136
133
|
4,
|
|
137
134
|
5,
|
|
138
135
|
6
|
|
139
|
-
].map((e) => /* @__PURE__ */
|
|
140
|
-
}) :
|
|
136
|
+
].map((e) => /* @__PURE__ */ S("div", { className: "h-48 bg-bg-sunken motion-safe:animate-vc-shimmer rounded-lg" }, e))
|
|
137
|
+
}) : Y && Y.length > 0 ? V === "grid" ? /* @__PURE__ */ S("div", {
|
|
141
138
|
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
|
|
142
|
-
children:
|
|
139
|
+
children: Y.map((e) => /* @__PURE__ */ S(l, {
|
|
143
140
|
className: "group hover:shadow-md transition-shadow cursor-pointer relative",
|
|
144
|
-
onClick: () =>
|
|
145
|
-
children: /* @__PURE__ */
|
|
141
|
+
onClick: () => I(`bots/${e.id}`),
|
|
142
|
+
children: /* @__PURE__ */ C(u, {
|
|
146
143
|
className: "pt-6",
|
|
147
144
|
children: [
|
|
148
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ C("div", {
|
|
149
146
|
className: "flex items-start justify-between",
|
|
150
|
-
children: [/* @__PURE__ */
|
|
147
|
+
children: [/* @__PURE__ */ C("div", {
|
|
151
148
|
className: "flex items-center gap-3",
|
|
152
|
-
children: [/* @__PURE__ */
|
|
149
|
+
children: [/* @__PURE__ */ S("span", {
|
|
153
150
|
className: "text-4xl",
|
|
154
151
|
children: e.icon || "🤖"
|
|
155
|
-
}), /* @__PURE__ */
|
|
152
|
+
}), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("h3", {
|
|
156
153
|
className: "font-semibold text-text-primary",
|
|
157
154
|
children: e.name
|
|
158
|
-
}), /* @__PURE__ */
|
|
159
|
-
}), /* @__PURE__ */
|
|
155
|
+
}), /* @__PURE__ */ S(f, { status: e.status })] })]
|
|
156
|
+
}), /* @__PURE__ */ C("div", {
|
|
160
157
|
className: "relative",
|
|
161
|
-
children: [/* @__PURE__ */
|
|
158
|
+
children: [/* @__PURE__ */ S(d, {
|
|
162
159
|
variant: "ghost",
|
|
163
160
|
size: "icon",
|
|
164
161
|
className: "opacity-0 group-hover:opacity-100 transition-opacity",
|
|
165
162
|
onClick: (t) => {
|
|
166
|
-
t.stopPropagation(),
|
|
163
|
+
t.stopPropagation(), K(G === e.id ? null : e.id);
|
|
167
164
|
},
|
|
168
|
-
children: /* @__PURE__ */
|
|
169
|
-
}),
|
|
165
|
+
children: /* @__PURE__ */ S(k, { size: 16 })
|
|
166
|
+
}), G === e.id && /* @__PURE__ */ C("div", {
|
|
170
167
|
className: "absolute right-0 top-full mt-1 w-48 bg-popover border border-border-subtle rounded-md shadow-lg z-10",
|
|
171
168
|
children: [
|
|
172
|
-
/* @__PURE__ */
|
|
169
|
+
/* @__PURE__ */ C("button", {
|
|
173
170
|
className: "w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2",
|
|
174
171
|
onClick: (t) => {
|
|
175
|
-
t.stopPropagation(),
|
|
172
|
+
t.stopPropagation(), I(`bots/${e.id}/edit`), K(null);
|
|
176
173
|
},
|
|
177
|
-
children: [/* @__PURE__ */
|
|
174
|
+
children: [/* @__PURE__ */ S(E, { size: 16 }), F("botlit.botsList.menu.editBot", "Edit Bot")]
|
|
178
175
|
}),
|
|
179
|
-
/* @__PURE__ */
|
|
176
|
+
/* @__PURE__ */ C("button", {
|
|
180
177
|
className: "w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2",
|
|
181
178
|
onClick: (t) => {
|
|
182
|
-
t.stopPropagation(),
|
|
179
|
+
t.stopPropagation(), I(`bots/${e.id}?tab=workflow`), K(null);
|
|
183
180
|
},
|
|
184
|
-
children: [/* @__PURE__ */
|
|
181
|
+
children: [/* @__PURE__ */ S(N, { size: 16 }), F("botlit.botsList.menu.design", "Design workflow")]
|
|
185
182
|
}),
|
|
186
|
-
/* @__PURE__ */
|
|
183
|
+
/* @__PURE__ */ C("button", {
|
|
187
184
|
className: "w-full px-4 py-2 text-left text-sm hover:bg-accent flex items-center gap-2",
|
|
188
185
|
onClick: (t) => {
|
|
189
|
-
t.stopPropagation(),
|
|
186
|
+
t.stopPropagation(), I(`bots/${e.id}/agents`), K(null);
|
|
190
187
|
},
|
|
191
|
-
children: [/* @__PURE__ */
|
|
188
|
+
children: [/* @__PURE__ */ S(T, { size: 16 }), F("botlit.botsList.menu.viewAgents", "View Agents")]
|
|
192
189
|
}),
|
|
193
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ C("button", {
|
|
194
191
|
className: "w-full px-4 py-2 text-left text-sm hover:bg-accent text-status-error-text flex items-center gap-2",
|
|
195
192
|
onClick: (t) => {
|
|
196
|
-
t.stopPropagation(),
|
|
193
|
+
t.stopPropagation(), J(e);
|
|
197
194
|
},
|
|
198
|
-
children: [/* @__PURE__ */
|
|
195
|
+
children: [/* @__PURE__ */ S(M, { size: 16 }), F("botlit.common.delete", "Delete")]
|
|
199
196
|
})
|
|
200
197
|
]
|
|
201
198
|
})]
|
|
202
199
|
})]
|
|
203
200
|
}),
|
|
204
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ S("p", {
|
|
205
202
|
className: "mt-3 text-sm text-text-secondary line-clamp-2",
|
|
206
203
|
children: e.description
|
|
207
204
|
}),
|
|
208
|
-
/* @__PURE__ */
|
|
205
|
+
/* @__PURE__ */ S("div", {
|
|
209
206
|
className: "mt-4 flex items-center gap-4 text-xs text-text-secondary",
|
|
210
|
-
children: /* @__PURE__ */
|
|
207
|
+
children: /* @__PURE__ */ C("span", {
|
|
211
208
|
className: "flex items-center gap-1",
|
|
212
209
|
children: [
|
|
213
|
-
/* @__PURE__ */
|
|
210
|
+
/* @__PURE__ */ S(T, { size: 14 }),
|
|
214
211
|
e.executionCount || 0,
|
|
215
212
|
" ",
|
|
216
|
-
|
|
213
|
+
F("botlit.common.executions", "executions")
|
|
217
214
|
]
|
|
218
215
|
})
|
|
219
216
|
}),
|
|
220
|
-
/* @__PURE__ */
|
|
217
|
+
/* @__PURE__ */ C("div", {
|
|
221
218
|
className: "mt-3 pt-3 border-t border-border-subtle flex items-center justify-between gap-2",
|
|
222
|
-
children: [/* @__PURE__ */
|
|
219
|
+
children: [/* @__PURE__ */ C("span", {
|
|
223
220
|
className: "text-xs text-text-secondary",
|
|
224
221
|
children: [
|
|
225
|
-
|
|
222
|
+
F("botlit.botsList.createdLabel", "Created"),
|
|
226
223
|
" ",
|
|
227
|
-
|
|
224
|
+
s(e.createdAt)
|
|
228
225
|
]
|
|
229
|
-
}), /* @__PURE__ */
|
|
226
|
+
}), /* @__PURE__ */ S(d, {
|
|
230
227
|
variant: "ghost",
|
|
231
228
|
size: "sm",
|
|
232
|
-
leftIcon: /* @__PURE__ */
|
|
229
|
+
leftIcon: /* @__PURE__ */ S(N, { size: 14 }),
|
|
233
230
|
onClick: (t) => {
|
|
234
|
-
t.stopPropagation(),
|
|
231
|
+
t.stopPropagation(), I(`bots/${e.id}?tab=workflow`);
|
|
235
232
|
},
|
|
236
|
-
children:
|
|
233
|
+
children: F("botlit.botsList.actions.design", "Design")
|
|
237
234
|
})]
|
|
238
235
|
})
|
|
239
236
|
]
|
|
240
237
|
})
|
|
241
238
|
}, e.id))
|
|
242
|
-
}) : /* @__PURE__ */
|
|
239
|
+
}) : /* @__PURE__ */ S("div", {
|
|
243
240
|
className: "space-y-2",
|
|
244
|
-
children:
|
|
241
|
+
children: Y.map((e) => /* @__PURE__ */ S(l, {
|
|
245
242
|
className: "hover:shadow-md transition-shadow cursor-pointer",
|
|
246
|
-
onClick: () =>
|
|
247
|
-
children: /* @__PURE__ */
|
|
243
|
+
onClick: () => I(`bots/${e.id}`),
|
|
244
|
+
children: /* @__PURE__ */ S(u, {
|
|
248
245
|
className: "py-4",
|
|
249
|
-
children: /* @__PURE__ */
|
|
246
|
+
children: /* @__PURE__ */ C("div", {
|
|
250
247
|
className: "flex items-center justify-between",
|
|
251
|
-
children: [/* @__PURE__ */
|
|
248
|
+
children: [/* @__PURE__ */ C("div", {
|
|
252
249
|
className: "flex items-center gap-4",
|
|
253
|
-
children: [/* @__PURE__ */
|
|
250
|
+
children: [/* @__PURE__ */ S("span", {
|
|
254
251
|
className: "text-3xl",
|
|
255
252
|
children: e.icon || "🤖"
|
|
256
|
-
}), /* @__PURE__ */
|
|
253
|
+
}), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ C("div", {
|
|
257
254
|
className: "flex items-center gap-2",
|
|
258
|
-
children: [/* @__PURE__ */
|
|
255
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
259
256
|
className: "font-semibold text-text-primary",
|
|
260
257
|
children: e.name
|
|
261
|
-
}), /* @__PURE__ */
|
|
262
|
-
}), /* @__PURE__ */
|
|
258
|
+
}), /* @__PURE__ */ S(f, { status: e.status })]
|
|
259
|
+
}), /* @__PURE__ */ S("p", {
|
|
263
260
|
className: "text-sm text-text-secondary line-clamp-1",
|
|
264
261
|
children: e.description
|
|
265
262
|
})] })]
|
|
266
|
-
}), /* @__PURE__ */
|
|
263
|
+
}), /* @__PURE__ */ C("div", {
|
|
267
264
|
className: "flex items-center gap-6 text-sm text-text-secondary",
|
|
268
265
|
children: [
|
|
269
|
-
/* @__PURE__ */
|
|
270
|
-
|
|
266
|
+
/* @__PURE__ */ C("span", { children: [
|
|
267
|
+
o(e.executionCount),
|
|
271
268
|
" ",
|
|
272
|
-
|
|
269
|
+
F("botlit.common.executions", "executions")
|
|
273
270
|
] }),
|
|
274
|
-
/* @__PURE__ */
|
|
271
|
+
/* @__PURE__ */ S(d, {
|
|
275
272
|
variant: "ghost",
|
|
276
273
|
size: "sm",
|
|
277
|
-
leftIcon: /* @__PURE__ */
|
|
274
|
+
leftIcon: /* @__PURE__ */ S(N, { size: 14 }),
|
|
278
275
|
onClick: (t) => {
|
|
279
|
-
t.stopPropagation(),
|
|
276
|
+
t.stopPropagation(), I(`bots/${e.id}?tab=workflow`);
|
|
280
277
|
},
|
|
281
|
-
children:
|
|
278
|
+
children: F("botlit.botsList.actions.design", "Design")
|
|
282
279
|
}),
|
|
283
|
-
/* @__PURE__ */
|
|
280
|
+
/* @__PURE__ */ S(d, {
|
|
284
281
|
variant: "ghost",
|
|
285
282
|
size: "sm",
|
|
286
|
-
children: /* @__PURE__ */
|
|
287
|
-
to:
|
|
288
|
-
children:
|
|
283
|
+
children: /* @__PURE__ */ S(w, {
|
|
284
|
+
to: L(`bots/${e.id}`),
|
|
285
|
+
children: F("botlit.common.view", "View")
|
|
289
286
|
})
|
|
290
287
|
})
|
|
291
288
|
]
|
|
@@ -293,14 +290,14 @@ var F = () => {
|
|
|
293
290
|
})
|
|
294
291
|
})
|
|
295
292
|
}, e.id))
|
|
296
|
-
}) : /* @__PURE__ */
|
|
293
|
+
}) : /* @__PURE__ */ S(_, {
|
|
297
294
|
illustration: "empty-agents",
|
|
298
|
-
title:
|
|
299
|
-
description:
|
|
300
|
-
action: /* @__PURE__ */
|
|
301
|
-
leftIcon: /* @__PURE__ */
|
|
302
|
-
onClick: () =>
|
|
303
|
-
children:
|
|
295
|
+
title: F("botlit.botsList.empty.title", "No bots yet"),
|
|
296
|
+
description: F("botlit.botsList.empty.description", "Create your first AI-powered bot to get started with building agents and automations."),
|
|
297
|
+
action: /* @__PURE__ */ S(d, {
|
|
298
|
+
leftIcon: /* @__PURE__ */ S(A, { size: 16 }),
|
|
299
|
+
onClick: () => I("bots/new"),
|
|
300
|
+
children: F("botlit.botsList.actions.createBot", "Create Bot")
|
|
304
301
|
})
|
|
305
302
|
})
|
|
306
303
|
]
|