@burdenoff/microfe-subscriberbot 2026.1029.1 → 2026.1030.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/subscriberbot/SubscriberBotRoutes.d.ts.map +1 -1
  2. package/dist/subscriberbot/SubscriberBotRoutes.js +18 -10
  3. package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
  4. package/dist/subscriberbot/components/StatusBadge.d.ts.map +1 -1
  5. package/dist/subscriberbot/components/StatusBadge.js +6 -1
  6. package/dist/subscriberbot/components/StatusBadge.js.map +1 -1
  7. package/dist/subscriberbot/components/decisions/DecisionBanners.d.ts +11 -0
  8. package/dist/subscriberbot/components/decisions/DecisionBanners.d.ts.map +1 -0
  9. package/dist/subscriberbot/components/decisions/DecisionBanners.js +62 -0
  10. package/dist/subscriberbot/components/decisions/DecisionBanners.js.map +1 -0
  11. package/dist/subscriberbot/components/decisions/DecisionCard.d.ts +22 -0
  12. package/dist/subscriberbot/components/decisions/DecisionCard.d.ts.map +1 -0
  13. package/dist/subscriberbot/components/decisions/DecisionCard.js +316 -0
  14. package/dist/subscriberbot/components/decisions/DecisionCard.js.map +1 -0
  15. package/dist/subscriberbot/components/decisions/decisionModel.d.ts +51 -0
  16. package/dist/subscriberbot/components/decisions/decisionModel.d.ts.map +1 -0
  17. package/dist/subscriberbot/components/decisions/decisionModel.js +139 -0
  18. package/dist/subscriberbot/components/decisions/decisionModel.js.map +1 -0
  19. package/dist/subscriberbot/components/decisions/index.d.ts +9 -0
  20. package/dist/subscriberbot/components/decisions/index.d.ts.map +1 -0
  21. package/dist/subscriberbot/components/decisions/index.js +3 -0
  22. package/dist/subscriberbot/hooks/index.d.ts +3 -1
  23. package/dist/subscriberbot/hooks/index.d.ts.map +1 -1
  24. package/dist/subscriberbot/hooks/index.js +1 -0
  25. package/dist/subscriberbot/hooks/useRouteSelection.d.ts +15 -0
  26. package/dist/subscriberbot/hooks/useRouteSelection.d.ts.map +1 -0
  27. package/dist/subscriberbot/hooks/useRouteSelection.js +18 -0
  28. package/dist/subscriberbot/hooks/useRouteSelection.js.map +1 -0
  29. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts +16 -1
  30. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -1
  31. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +99 -26
  32. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  33. package/dist/subscriberbot/pages/InboxPage.d.ts.map +1 -1
  34. package/dist/subscriberbot/pages/InboxPage.js +211 -210
  35. package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
  36. package/dist/subscriberbot/pages/WorkflowsPage.d.ts.map +1 -1
  37. package/dist/subscriberbot/pages/WorkflowsPage.js +166 -165
  38. package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
  39. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts +7 -0
  40. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts.map +1 -1
  41. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +280 -175
  42. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
  43. package/dist/subscriberbot/pages/decisions/DecisionDetailPage.d.ts +12 -0
  44. package/dist/subscriberbot/pages/decisions/DecisionDetailPage.d.ts.map +1 -0
  45. package/dist/subscriberbot/pages/decisions/DecisionDetailPage.js +180 -0
  46. package/dist/subscriberbot/pages/decisions/DecisionDetailPage.js.map +1 -0
  47. package/dist/subscriberbot/pages/decisions/DecisionsPage.d.ts +13 -0
  48. package/dist/subscriberbot/pages/decisions/DecisionsPage.d.ts.map +1 -0
  49. package/dist/subscriberbot/pages/decisions/DecisionsPage.js +154 -0
  50. package/dist/subscriberbot/pages/decisions/DecisionsPage.js.map +1 -0
  51. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -1
  52. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +330 -314
  53. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  54. package/dist/subscriberbot/types/index.d.ts +66 -0
  55. package/dist/subscriberbot/types/index.d.ts.map +1 -1
  56. package/dist/subscriberbot/utils/pageContext.d.ts +44 -11
  57. package/dist/subscriberbot/utils/pageContext.d.ts.map +1 -1
  58. package/dist/subscriberbot/utils/pageContext.js +44 -37
  59. package/dist/subscriberbot/utils/pageContext.js.map +1 -1
  60. package/package.json +4 -2
@@ -1 +1 @@
1
- {"version":3,"file":"WorkflowsPage.js","names":[],"sources":["../../../src/subscriberbot/pages/WorkflowsPage.tsx"],"sourcesContent":["/**\n * Workflows (Automation)\n * @module subscriberbot/pages\n *\n * The Workflow Engine — event-driven automation (\"when invoice arrives →\n * classify → update relationship → notify finance\"). List + create + activate.\n * Reads `subListWorkflows`; writes `subCreateWorkflow` / `subActivateWorkflow`.\n *\n * Opening a workflow renders a READ-ONLY horizontal step-flow derived from the\n * workflow's real `triggerEvent`, `name` and `status` (the svc contract does\n * not expose an editable step array — this is a truthful visualisation, not a\n * builder).\n */\n\nimport { useState } from 'react';\nimport {\n Plus,\n Workflow as WorkflowIcon,\n Play,\n Zap,\n Sparkles,\n CheckCircle2,\n ArrowRight,\n Clock,\n X,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n EmptyState,\n Modal,\n MetricsCard,\n LoadingView,\n ErrorView,\n} from '../components';\nimport { useWorkflows, useCreateWorkflow, useActivateWorkflow } from '../hooks/useSubscriberBotApi';\nimport { useTr } from '../hooks/useTr';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { SubCreateWorkflowInput, SubWorkflow, SubWorkflowStatus } from '../types';\n\nconst STATUS_OPTIONS: Array<{ value: '' | SubWorkflowStatus; labelKey: string; fallback: string }> =\n [\n { value: '', labelKey: 'workflows.filters.allStatuses', fallback: 'All statuses' },\n { value: 'ACTIVE', labelKey: 'workflows.filters.active', fallback: 'Active' },\n { value: 'DRAFT', labelKey: 'workflows.filters.draft', fallback: 'Draft' },\n { value: 'PAUSED', labelKey: 'workflows.filters.paused', fallback: 'Paused' },\n { value: 'ARCHIVED', labelKey: 'workflows.filters.archived', fallback: 'Archived' },\n ];\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\n// ---------------------------------------------------------------------------\n// A single node in the read-only step flow.\n// ---------------------------------------------------------------------------\nfunction FlowNode({\n icon,\n kicker,\n title,\n sub,\n accent,\n}: {\n icon: React.ReactNode;\n kicker: string;\n title: string;\n sub?: string;\n /** Top accent bar tone. */\n accent: 'trigger' | 'run' | 'done';\n}) {\n const bar =\n accent === 'done'\n ? 'bg-status-success-text'\n : accent === 'run'\n ? 'bg-status-warning-text'\n : 'bg-[var(--color-accent-indigo)]';\n return (\n <div className=\"w-48 shrink-0 overflow-hidden rounded-xl border border-border-subtle bg-bg-surface shadow-sm\">\n <div className={`h-1 w-full ${bar}`} aria-hidden />\n <div className=\"p-3\">\n <span className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {icon}\n </span>\n <p className=\"mt-2 text-[10px] font-medium uppercase tracking-wide text-text-secondary\">\n {kicker}\n </p>\n <p className=\"truncate text-sm font-semibold text-text-primary\" title={title}>\n {title}\n </p>\n {sub && <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{sub}</p>}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Read-only flow panel for the selected workflow.\n// ---------------------------------------------------------------------------\nfunction WorkflowFlowPanel({\n workflow,\n onClose,\n onActivate,\n activating,\n}: {\n workflow: SubWorkflow;\n onClose: () => void;\n onActivate: () => void;\n activating: boolean;\n}) {\n const tr = useTr();\n const connector = (\n <div className=\"flex shrink-0 items-center px-1 text-text-secondary\" aria-hidden>\n <span className=\"h-px w-4 bg-border-seam sm:w-6\" />\n <ArrowRight className=\"h-4 w-4\" />\n </div>\n );\n\n const statusLabel = workflow.status.charAt(0) + workflow.status.slice(1).toLowerCase();\n\n return (\n <GlassCard treatment=\"glass\" glow className=\"mt-6 p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"text-base font-semibold text-text-primary\">{workflow.name}</p>\n <StatusBadge status={workflow.status} />\n </div>\n <p className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span className=\"tabular-nums\">\n {tr('workflows.flow.ran', 'Ran {{count}}×', { count: workflow.runCount })}\n </span>\n {workflow.lastRunAt && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" aria-hidden />{' '}\n {tr('workflows.flow.lastRun', 'last {{when}}', {\n when: formatRelativeTime(workflow.lastRunAt),\n })}\n </span>\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label={tr('workflows.flow.closeAriaLabel', 'Close flow')}\n className=\"rounded-lg border border-border-subtle p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n {workflow.description && (\n <p className=\"mt-2 max-w-3xl text-sm text-text-secondary\">{workflow.description}</p>\n )}\n\n {/* Horizontal read-only step flow (scrolls on small screens) */}\n <div className=\"mt-4 overflow-x-auto pb-2\">\n <div className=\"flex min-w-max items-stretch\">\n <FlowNode\n accent=\"trigger\"\n kicker={tr('workflows.flow.trigger', 'When')}\n icon={<Zap className=\"h-4 w-4\" />}\n title={workflow.triggerEvent}\n sub={tr('workflows.flow.triggerEvent', 'Trigger event')}\n />\n {connector}\n <FlowNode\n accent=\"run\"\n kicker={tr('workflows.flow.run', 'Run')}\n icon={<Sparkles className=\"h-4 w-4\" />}\n title={workflow.name}\n sub={tr('workflows.flow.automation', 'Automation')}\n />\n {connector}\n <FlowNode\n accent=\"done\"\n kicker={tr('workflows.flow.then', 'Then')}\n icon={<CheckCircle2 className=\"h-4 w-4\" />}\n title={\n workflow.status === 'ACTIVE'\n ? tr('workflows.flow.live', 'Live')\n : tr('workflows.flow.awaitingActivation', 'Awaiting activation')\n }\n sub={tr('workflows.flow.status', 'Status: {{status}}', { status: statusLabel })}\n />\n </div>\n </div>\n\n {workflow.status !== 'ACTIVE' && (\n <div className=\"mt-3 flex justify-end\">\n <button\n type=\"button\"\n disabled={activating}\n onClick={onActivate}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n <Play className=\"h-4 w-4\" />{' '}\n {activating\n ? tr('common.activating', 'Activating…')\n : tr('workflows.flow.activate', 'Activate workflow')}\n </button>\n </div>\n )}\n </GlassCard>\n );\n}\n\nexport function WorkflowsPage() {\n const [statusFilter, setStatusFilter] = useState<'' | SubWorkflowStatus>('');\n const [showCreate, setShowCreate] = useState(false);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const tr = useTr();\n\n const { data, isLoading, isError, refetch } = useWorkflows(statusFilter || undefined);\n const create = useCreateWorkflow();\n const activate = useActivateWorkflow();\n\n const [name, setName] = useState('');\n const [triggerEvent, setTriggerEvent] = useState('');\n const [description, setDescription] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const workflows = data ?? [];\n const selected = workflows.find((w) => w.id === selectedId) ?? null;\n\n // --- Real, computed aggregates -------------------------------------------\n const activeCount = workflows.filter((w) => w.status === 'ACTIVE').length;\n const totalRuns = workflows.reduce((s, w) => s + (w.runCount || 0), 0);\n\n const resetForm = () => {\n setName('');\n setTriggerEvent('');\n setDescription('');\n setFormError(null);\n };\n\n const closeCreate = () => {\n setShowCreate(false);\n resetForm();\n };\n\n const handleCreate = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim() || !triggerEvent.trim()) {\n setFormError(tr('workflows.form.nameRequired', 'Name and trigger event are required.'));\n return;\n }\n const input: SubCreateWorkflowInput = {\n name: name.trim(),\n triggerEvent: triggerEvent.trim(),\n ...(description.trim() ? { description: description.trim() } : {}),\n };\n create.mutate(input, {\n onSuccess: () => {\n resetForm();\n setShowCreate(false);\n },\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : tr('common.error', 'An error occurred')),\n });\n };\n\n return (\n <PageLayout\n title={tr('workflows.title', 'Workflows')}\n description={tr('workflows.description', 'Event-driven automation across your portfolio')}\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> {tr('workflows.newWorkflow', 'New workflow')}\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n {tr(\n 'workflows.purpose',\n \"Workflows react to domain events — a new invoice, a detected renewal, a cancelled relationship — and run multi-step automations. Draft a workflow, then activate it when you're ready.\"\n )}\n </PagePurpose>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n aria-label={tr('common.filter', 'Filter')}\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as '' | SubWorkflowStatus)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {STATUS_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {tr(o.labelKey, o.fallback)}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingView label={tr('workflows.loading', 'Loading workflows…')} />\n ) : isError ? (\n <ErrorView\n message={tr('workflows.error', 'Could not load workflows.')}\n onRetry={() => void refetch()}\n />\n ) : workflows.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<WorkflowIcon className=\"h-12 w-12\" />}\n title={tr('workflows.empty.title', 'No workflows yet')}\n description={tr(\n 'workflows.empty.description',\n 'Create your first event-driven workflow to automate your recurring portfolio.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n {tr('workflows.newWorkflow', 'New workflow')}\n </button>\n }\n />\n </div>\n ) : (\n <>\n {/* Overview (computed) */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<WorkflowIcon className=\"h-5 w-5\" />}\n value={workflows.length}\n label={tr('workflows.metrics.workflows', 'Workflows')}\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={activeCount}\n label={tr('workflows.metrics.active', 'Active')}\n />\n <MetricsCard\n icon={<Play className=\"h-5 w-5\" />}\n value={totalRuns}\n label={tr('workflows.metrics.totalRuns', 'Total runs')}\n />\n </div>\n\n {/* Selected workflow flow */}\n {selected && (\n <WorkflowFlowPanel\n workflow={selected}\n onClose={() => setSelectedId(null)}\n onActivate={() => activate.mutate(selected.id)}\n activating={activate.isPending}\n />\n )}\n\n {/* Workflow cards */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {workflows.map((wf) => {\n const isSelected = wf.id === selectedId;\n return (\n <GlassCard\n key={wf.id}\n treatment=\"metric\"\n glow={isSelected || wf.status === 'ACTIVE'}\n role=\"button\"\n tabIndex={0}\n aria-pressed={isSelected}\n aria-label={tr('workflows.card.viewAriaLabel', 'View flow for {{name}}', {\n name: wf.name,\n })}\n onClick={() => setSelectedId(isSelected ? null : wf.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelectedId(isSelected ? null : wf.id);\n }\n }}\n className=\"flex cursor-pointer flex-col p-5 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <WorkflowIcon className=\"h-5 w-5\" />\n </span>\n <StatusBadge status={wf.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">{wf.name}</p>\n <p className=\"flex items-center gap-1 truncate text-xs text-text-secondary\">\n <Zap className=\"h-3 w-3 shrink-0\" aria-hidden />{' '}\n {tr('workflows.card.onTrigger', 'on {{trigger}}', { trigger: wf.triggerEvent })}\n </p>\n {wf.description && (\n <p className=\"mt-2 line-clamp-2 min-h-[2rem] text-xs text-text-secondary\">\n {wf.description}\n </p>\n )}\n <p className=\"mt-3 flex items-center gap-1.5 text-xs text-text-secondary tabular-nums\">\n <Play className=\"h-3.5 w-3.5\" aria-hidden />{' '}\n {tr('workflows.flow.ran', 'Ran {{count}}×', { count: wf.runCount })}\n {wf.lastRunAt\n ? ` · ${tr('workflows.flow.lastRun', 'last {{when}}', { when: formatRelativeTime(wf.lastRunAt) })}`\n : ''}\n </p>\n {wf.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n disabled={activate.isPending}\n onClick={(e) => {\n e.stopPropagation();\n activate.mutate(wf.id);\n }}\n className=\"mt-4 inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50\"\n >\n <Play className=\"h-3.5 w-3.5\" /> {tr('common.activate', 'Activate')}\n </button>\n )}\n </GlassCard>\n );\n })}\n </div>\n </>\n )}\n\n {/* Create modal */}\n {showCreate && (\n <Modal title={tr('workflows.newWorkflow', 'New workflow')} onClose={closeCreate}>\n <form onSubmit={handleCreate} className=\"space-y-4\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n <div>\n <label htmlFor=\"wf-name\" className={labelCls}>\n {tr('workflows.form.nameLabel', 'Name')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={tr('workflows.form.namePlaceholder', 'e.g. Invoice → notify finance')}\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-trigger\" className={labelCls}>\n {tr('workflows.form.triggerLabel', 'Trigger event')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-trigger\"\n type=\"text\"\n value={triggerEvent}\n onChange={(e) => setTriggerEvent(e.target.value)}\n placeholder={tr(\n 'workflows.form.triggerPlaceholder',\n 'e.g. InvoiceReceived, RenewalDetected'\n )}\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-desc\" className={labelCls}>\n {tr('workflows.form.descriptionLabel', 'Description')}\n </label>\n <textarea\n id=\"wf-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={3}\n placeholder={tr(\n 'workflows.form.descriptionPlaceholder',\n 'What should this workflow do when the event fires?'\n )}\n className={inputCls}\n />\n </div>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={closeCreate}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending\n ? tr('workflows.creating', 'Creating…')\n : tr('workflows.createWorkflow', 'Create workflow')}\n </button>\n </div>\n </form>\n </Modal>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WorkflowsPage.js","names":[],"sources":["../../../src/subscriberbot/pages/WorkflowsPage.tsx"],"sourcesContent":["/**\n * Workflows (Automation)\n * @module subscriberbot/pages\n *\n * The Workflow Engine — event-driven automation (\"when invoice arrives →\n * classify → update relationship → notify finance\"). List + create + activate.\n * Reads `subListWorkflows`; writes `subCreateWorkflow` / `subActivateWorkflow`.\n *\n * Opening a workflow renders a READ-ONLY horizontal step-flow derived from the\n * workflow's real `triggerEvent`, `name` and `status` (the svc contract does\n * not expose an editable step array — this is a truthful visualisation, not a\n * builder).\n */\n\nimport { useState } from 'react';\nimport {\n Plus,\n Workflow as WorkflowIcon,\n Play,\n Zap,\n Sparkles,\n CheckCircle2,\n ArrowRight,\n Clock,\n X,\n} from 'lucide-react';\nimport { PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n EmptyState,\n Modal,\n MetricsCard,\n LoadingView,\n ErrorView,\n} from '../components';\nimport { useWorkflows, useCreateWorkflow, useActivateWorkflow } from '../hooks/useSubscriberBotApi';\nimport { useTr } from '../hooks/useTr';\nimport { useRouteSelection } from '../hooks/useRouteSelection';\nimport { formatRelativeTime } from '../utils/formatters';\nimport type { SubCreateWorkflowInput, SubWorkflow, SubWorkflowStatus } from '../types';\n\nconst STATUS_OPTIONS: Array<{ value: '' | SubWorkflowStatus; labelKey: string; fallback: string }> =\n [\n { value: '', labelKey: 'workflows.filters.allStatuses', fallback: 'All statuses' },\n { value: 'ACTIVE', labelKey: 'workflows.filters.active', fallback: 'Active' },\n { value: 'DRAFT', labelKey: 'workflows.filters.draft', fallback: 'Draft' },\n { value: 'PAUSED', labelKey: 'workflows.filters.paused', fallback: 'Paused' },\n { value: 'ARCHIVED', labelKey: 'workflows.filters.archived', fallback: 'Archived' },\n ];\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\n// ---------------------------------------------------------------------------\n// A single node in the read-only step flow.\n// ---------------------------------------------------------------------------\nfunction FlowNode({\n icon,\n kicker,\n title,\n sub,\n accent,\n}: {\n icon: React.ReactNode;\n kicker: string;\n title: string;\n sub?: string;\n /** Top accent bar tone. */\n accent: 'trigger' | 'run' | 'done';\n}) {\n const bar =\n accent === 'done'\n ? 'bg-status-success-text'\n : accent === 'run'\n ? 'bg-status-warning-text'\n : 'bg-[var(--color-accent-indigo)]';\n return (\n <div className=\"w-48 shrink-0 overflow-hidden rounded-xl border border-border-subtle bg-bg-surface shadow-sm\">\n <div className={`h-1 w-full ${bar}`} aria-hidden />\n <div className=\"p-3\">\n <span className=\"flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n {icon}\n </span>\n <p className=\"mt-2 text-[10px] font-medium uppercase tracking-wide text-text-secondary\">\n {kicker}\n </p>\n <p className=\"truncate text-sm font-semibold text-text-primary\" title={title}>\n {title}\n </p>\n {sub && <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{sub}</p>}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Read-only flow panel for the selected workflow.\n// ---------------------------------------------------------------------------\nfunction WorkflowFlowPanel({\n workflow,\n onClose,\n onActivate,\n activating,\n}: {\n workflow: SubWorkflow;\n onClose: () => void;\n onActivate: () => void;\n activating: boolean;\n}) {\n const tr = useTr();\n const connector = (\n <div className=\"flex shrink-0 items-center px-1 text-text-secondary\" aria-hidden>\n <span className=\"h-px w-4 bg-border-seam sm:w-6\" />\n <ArrowRight className=\"h-4 w-4\" />\n </div>\n );\n\n const statusLabel = workflow.status.charAt(0) + workflow.status.slice(1).toLowerCase();\n\n return (\n <GlassCard treatment=\"glass\" glow className=\"mt-6 p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"text-base font-semibold text-text-primary\">{workflow.name}</p>\n <StatusBadge status={workflow.status} />\n </div>\n <p className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span className=\"tabular-nums\">\n {tr('workflows.flow.ran', 'Ran {{count}}×', { count: workflow.runCount })}\n </span>\n {workflow.lastRunAt && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" aria-hidden />{' '}\n {tr('workflows.flow.lastRun', 'last {{when}}', {\n when: formatRelativeTime(workflow.lastRunAt),\n })}\n </span>\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label={tr('workflows.flow.closeAriaLabel', 'Close flow')}\n className=\"rounded-lg border border-border-subtle p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n\n {workflow.description && (\n <p className=\"mt-2 max-w-3xl text-sm text-text-secondary\">{workflow.description}</p>\n )}\n\n {/* Horizontal read-only step flow (scrolls on small screens) */}\n <div className=\"mt-4 overflow-x-auto pb-2\">\n <div className=\"flex min-w-max items-stretch\">\n <FlowNode\n accent=\"trigger\"\n kicker={tr('workflows.flow.trigger', 'When')}\n icon={<Zap className=\"h-4 w-4\" />}\n title={workflow.triggerEvent}\n sub={tr('workflows.flow.triggerEvent', 'Trigger event')}\n />\n {connector}\n <FlowNode\n accent=\"run\"\n kicker={tr('workflows.flow.run', 'Run')}\n icon={<Sparkles className=\"h-4 w-4\" />}\n title={workflow.name}\n sub={tr('workflows.flow.automation', 'Automation')}\n />\n {connector}\n <FlowNode\n accent=\"done\"\n kicker={tr('workflows.flow.then', 'Then')}\n icon={<CheckCircle2 className=\"h-4 w-4\" />}\n title={\n workflow.status === 'ACTIVE'\n ? tr('workflows.flow.live', 'Live')\n : tr('workflows.flow.awaitingActivation', 'Awaiting activation')\n }\n sub={tr('workflows.flow.status', 'Status: {{status}}', { status: statusLabel })}\n />\n </div>\n </div>\n\n {workflow.status !== 'ACTIVE' && (\n <div className=\"mt-3 flex justify-end\">\n <button\n type=\"button\"\n disabled={activating}\n onClick={onActivate}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n <Play className=\"h-4 w-4\" />{' '}\n {activating\n ? tr('common.activating', 'Activating…')\n : tr('workflows.flow.activate', 'Activate workflow')}\n </button>\n </div>\n )}\n </GlassCard>\n );\n}\n\nexport function WorkflowsPage() {\n const [statusFilter, setStatusFilter] = useState<'' | SubWorkflowStatus>('');\n const [showCreate, setShowCreate] = useState(false);\n // The selected workflow lives in the URL (/workflows/:selectedId) so it can be\n // deep-linked and the assistant can resolve \"this workflow\".\n const [selectedId, setSelectedId] = useRouteSelection('workflows');\n const tr = useTr();\n\n const { data, isLoading, isError, refetch } = useWorkflows(statusFilter || undefined);\n const create = useCreateWorkflow();\n const activate = useActivateWorkflow();\n\n const [name, setName] = useState('');\n const [triggerEvent, setTriggerEvent] = useState('');\n const [description, setDescription] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const workflows = data ?? [];\n const selected = workflows.find((w) => w.id === selectedId) ?? null;\n\n // --- Real, computed aggregates -------------------------------------------\n const activeCount = workflows.filter((w) => w.status === 'ACTIVE').length;\n const totalRuns = workflows.reduce((s, w) => s + (w.runCount || 0), 0);\n\n const resetForm = () => {\n setName('');\n setTriggerEvent('');\n setDescription('');\n setFormError(null);\n };\n\n const closeCreate = () => {\n setShowCreate(false);\n resetForm();\n };\n\n const handleCreate = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim() || !triggerEvent.trim()) {\n setFormError(tr('workflows.form.nameRequired', 'Name and trigger event are required.'));\n return;\n }\n const input: SubCreateWorkflowInput = {\n name: name.trim(),\n triggerEvent: triggerEvent.trim(),\n ...(description.trim() ? { description: description.trim() } : {}),\n };\n create.mutate(input, {\n onSuccess: () => {\n resetForm();\n setShowCreate(false);\n },\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : tr('common.error', 'An error occurred')),\n });\n };\n\n return (\n <PageLayout\n title={tr('workflows.title', 'Workflows')}\n description={tr('workflows.description', 'Event-driven automation across your portfolio')}\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> {tr('workflows.newWorkflow', 'New workflow')}\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n {tr(\n 'workflows.purpose',\n \"Workflows react to domain events — a new invoice, a detected renewal, a cancelled relationship — and run multi-step automations. Draft a workflow, then activate it when you're ready.\"\n )}\n </PagePurpose>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n aria-label={tr('common.filter', 'Filter')}\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as '' | SubWorkflowStatus)}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {STATUS_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {tr(o.labelKey, o.fallback)}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingView label={tr('workflows.loading', 'Loading workflows…')} />\n ) : isError ? (\n <ErrorView\n message={tr('workflows.error', 'Could not load workflows.')}\n onRetry={() => void refetch()}\n />\n ) : workflows.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<WorkflowIcon className=\"h-12 w-12\" />}\n title={tr('workflows.empty.title', 'No workflows yet')}\n description={tr(\n 'workflows.empty.description',\n 'Create your first event-driven workflow to automate your recurring portfolio.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n {tr('workflows.newWorkflow', 'New workflow')}\n </button>\n }\n />\n </div>\n ) : (\n <>\n {/* Overview (computed) */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<WorkflowIcon className=\"h-5 w-5\" />}\n value={workflows.length}\n label={tr('workflows.metrics.workflows', 'Workflows')}\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={activeCount}\n label={tr('workflows.metrics.active', 'Active')}\n />\n <MetricsCard\n icon={<Play className=\"h-5 w-5\" />}\n value={totalRuns}\n label={tr('workflows.metrics.totalRuns', 'Total runs')}\n />\n </div>\n\n {/* Selected workflow flow */}\n {selected && (\n <WorkflowFlowPanel\n workflow={selected}\n onClose={() => setSelectedId(null)}\n onActivate={() => activate.mutate(selected.id)}\n activating={activate.isPending}\n />\n )}\n\n {/* Workflow cards */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {workflows.map((wf) => {\n const isSelected = wf.id === selectedId;\n return (\n <GlassCard\n key={wf.id}\n treatment=\"metric\"\n glow={isSelected || wf.status === 'ACTIVE'}\n role=\"button\"\n tabIndex={0}\n aria-pressed={isSelected}\n aria-label={tr('workflows.card.viewAriaLabel', 'View flow for {{name}}', {\n name: wf.name,\n })}\n onClick={() => setSelectedId(isSelected ? null : wf.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setSelectedId(isSelected ? null : wf.id);\n }\n }}\n className=\"flex cursor-pointer flex-col p-5 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"flex size-10 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <WorkflowIcon className=\"h-5 w-5\" />\n </span>\n <StatusBadge status={wf.status} />\n </div>\n <p className=\"mt-3 truncate text-sm font-semibold text-text-primary\">{wf.name}</p>\n <p className=\"flex items-center gap-1 truncate text-xs text-text-secondary\">\n <Zap className=\"h-3 w-3 shrink-0\" aria-hidden />{' '}\n {tr('workflows.card.onTrigger', 'on {{trigger}}', { trigger: wf.triggerEvent })}\n </p>\n {wf.description && (\n <p className=\"mt-2 line-clamp-2 min-h-[2rem] text-xs text-text-secondary\">\n {wf.description}\n </p>\n )}\n <p className=\"mt-3 flex items-center gap-1.5 text-xs text-text-secondary tabular-nums\">\n <Play className=\"h-3.5 w-3.5\" aria-hidden />{' '}\n {tr('workflows.flow.ran', 'Ran {{count}}×', { count: wf.runCount })}\n {wf.lastRunAt\n ? ` · ${tr('workflows.flow.lastRun', 'last {{when}}', { when: formatRelativeTime(wf.lastRunAt) })}`\n : ''}\n </p>\n {wf.status !== 'ACTIVE' && (\n <button\n type=\"button\"\n disabled={activate.isPending}\n onClick={(e) => {\n e.stopPropagation();\n activate.mutate(wf.id);\n }}\n className=\"mt-4 inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50\"\n >\n <Play className=\"h-3.5 w-3.5\" /> {tr('common.activate', 'Activate')}\n </button>\n )}\n </GlassCard>\n );\n })}\n </div>\n </>\n )}\n\n {/* Create modal */}\n {showCreate && (\n <Modal title={tr('workflows.newWorkflow', 'New workflow')} onClose={closeCreate}>\n <form onSubmit={handleCreate} className=\"space-y-4\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n <div>\n <label htmlFor=\"wf-name\" className={labelCls}>\n {tr('workflows.form.nameLabel', 'Name')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={tr('workflows.form.namePlaceholder', 'e.g. Invoice → notify finance')}\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-trigger\" className={labelCls}>\n {tr('workflows.form.triggerLabel', 'Trigger event')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"wf-trigger\"\n type=\"text\"\n value={triggerEvent}\n onChange={(e) => setTriggerEvent(e.target.value)}\n placeholder={tr(\n 'workflows.form.triggerPlaceholder',\n 'e.g. InvoiceReceived, RenewalDetected'\n )}\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"wf-desc\" className={labelCls}>\n {tr('workflows.form.descriptionLabel', 'Description')}\n </label>\n <textarea\n id=\"wf-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={3}\n placeholder={tr(\n 'workflows.form.descriptionPlaceholder',\n 'What should this workflow do when the event fires?'\n )}\n className={inputCls}\n />\n </div>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={closeCreate}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending\n ? tr('workflows.creating', 'Creating…')\n : tr('workflows.createWorkflow', 'Create workflow')}\n </button>\n </div>\n </form>\n </Modal>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -8,6 +8,13 @@
8
8
  * each policy's real `lastTriggeredAt` — never mocked. Each policy card also
9
9
  * renders its stored `condition` JSON (the rule the agent evaluates before it
10
10
  * acts), so a condition entered in "Add policy" is visible after it is saved.
11
+ *
12
+ * BOFF-3663: the page is also the agent's operations view. "Run agent" calls
13
+ * `subRunAgent` as a dry run (decisions are proposed for review, nothing
14
+ * changes), the run history includes each real decision run, and the agent's
15
+ * decisions are listed as cards that can be applied or dismissed. If the
16
+ * decision engine is unreachable, only that section degrades to a banner; the
17
+ * posture and policy management above it keep working.
11
18
  */
12
19
  export declare function AgentDetailPage(): import("react").JSX.Element;
13
20
  //# sourceMappingURL=AgentDetailPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/pages/agents/AgentDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA6XH,wBAAgB,eAAe,gCAmR9B"}
1
+ {"version":3,"file":"AgentDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/pages/agents/AgentDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA8aH,wBAAgB,eAAe,gCAua9B"}