import { useCallback, useEffect, useMemo, useState } from "react" import { AnimatePresence, motion } from "framer-motion" import { ArrowRight, ArrowsClockwise, Lightning, Plus, Robot, Trash, X } from "@phosphor-icons/react" import type { AutomationAction, AutomationRuleRecord, AutomationStatus, AutomationTrigger, WorkflowPipelineRecord } from "@shared/types" import { ActionButton, Select } from "../ui" import { useT } from "../../i18n" import { ACCENT, LINE, triggerConfig, actionConfig, statusColors, type AutomationLogEntry } from "./automation-config" import { timeAgo } from "../../lib/formatters" import { RuleCard } from "./RuleCard" import { RuleFormModal } from "./RuleEditor" import { WorkflowCard } from "./WorkflowList" import { WorkflowFormModal } from "./WorkflowEditor" function DeleteConfirmDialog({ open, entityName, onConfirm, onCancel }: { open: boolean; entityName: string; onConfirm: () => void; onCancel: () => void }) { if (!open) return null return ( e.stopPropagation()}>

Delete

Are you sure you want to delete {entityName}? This action cannot be undone.

) } function AutomationActivityLog({ entries }: { entries: AutomationLogEntry[] }) { if (entries.length === 0) return
No activity yet
return (
{entries.map((entry, idx) => { const ti = triggerConfig[entry.trigger as AutomationTrigger]; const ai = actionConfig[entry.action as AutomationAction]; const TIcon = ti?.icon ?? Lightning return
{entry.ruleName}
{ti?.label ?? entry.trigger}{ai?.label ?? entry.action}
{timeAgo(entry.executedAt)}
})}
) } function RulesPanel({ rules, companyId, onRefresh }: { rules: AutomationRuleRecord[]; companyId: string; onRefresh: () => void }) { const [showCreate, setShowCreate] = useState(false); const [editRule, setEditRule] = useState(null); const [delTarget, setDelTarget] = useState(null) const [actLog, setActLog] = useState([]); const [activeTab, setActiveTab] = useState<"rules"|"activity">("rules"); const [filterStatus, setFilterStatus] = useState("all") const [actionError, setActionError] = useState(null) useEffect(() => { void window.agentCompany.getAutomationLog(companyId).then((r) => { if (r.ok) setActLog(r.data) }) }, [companyId, rules]) const filtered = useMemo(() => filterStatus === "all" ? rules : rules.filter((r) => r.status === filterStatus), [rules, filterStatus]) const counts = useMemo(() => { let active = 0, paused = 0, error = 0; for (const r of rules) { if (r.status === "active") active++; else if (r.status === "paused") paused++; else if (r.status === "error") error++; } return { total: rules.length, active, paused, error } }, [rules]) const handleToggle = useCallback(async (rule: AutomationRuleRecord) => { setActionError(null); try { const r = await window.agentCompany.toggleAutomationRule({ id: rule.id, companyId, status: (rule.status === "active" ? "paused" : "active") as "active"|"paused" }); if (!r.ok) { setActionError(r.error.message); return }; onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : "Failed") } }, [companyId, onRefresh]) const handleDelete = useCallback(async () => { if (!delTarget) return; setActionError(null); try { const r = await window.agentCompany.deleteAutomationRule({ id: delTarget.id, companyId }); if (!r.ok) { setActionError(r.error.message); setDelTarget(null); return }; setDelTarget(null); onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : "Failed"); setDelTarget(null) } }, [delTarget, companyId, onRefresh]) return (
{actionError ?
{actionError}
: null}

Automation Rules

{counts.active} active, {counts.paused} paused{counts.error > 0 ? `, ${counts.error} errored` : ""}

setShowCreate(true)} icon={Plus} tone="accent" />
{rules.length > 0 ?
{[{ l: "Total Rules", v: counts.total, c: undefined }, { l: "Total Executions", v: rules.reduce((s, r) => s + r.executionCount, 0), c: ACCENT }, { l: "Recent Activity", v: actLog.length, c: "var(--primary)" }].map((s) =>
{s.l}
{s.v}
)}
: null}
{activeTab === "rules" ? <> {rules.length > 0 ?
{(["all","active","paused","error"] as const).map((s) => )}
: null} {filtered.length === 0 && rules.length === 0 ?
No automation rules
Create your first rule to make the company autonomous.
setShowCreate(true)} icon={Lightning} tone="accent" />
: filtered.length === 0 ?
No rules match the current filter.
:
{filtered.map((r) => void handleToggle(r)} onDelete={() => setDelTarget(r)} onEdit={() => setEditRule(r)} />)}
} : } {showCreate ? setShowCreate(false)} onSaved={onRefresh} /> : null}{editRule ? setEditRule(null)} onSaved={onRefresh} /> : null} {delTarget ? void handleDelete()} onCancel={() => setDelTarget(null)} /> : null}
) } function WorkflowsPanel({ workflows, companyId, onRefresh }: { workflows: WorkflowPipelineRecord[]; companyId: string; onRefresh: () => void }) { const [showCreate, setShowCreate] = useState(false); const [editWf, setEditWf] = useState(null); const [delTarget, setDelTarget] = useState(null) const [actionError, setActionError] = useState(null); const [runningId, setRunningId] = useState(null) const handleDelete = useCallback(async () => { if (!delTarget) return; setActionError(null); try { const r = await window.agentCompany.deleteWorkflow({ id: delTarget.id, companyId }); if (!r.ok) { setActionError(r.error.message); setDelTarget(null); return }; setDelTarget(null); onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : "Failed"); setDelTarget(null) } }, [delTarget, companyId, onRefresh]) const handleRun = useCallback(async (wf: WorkflowPipelineRecord) => { setActionError(null); setRunningId(wf.id); try { const r = await window.agentCompany.runWorkflow({ id: wf.id, companyId }); if (!r.ok) { setActionError(r.error.message); return }; onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : "Failed") } finally { setRunningId(null) } }, [companyId, onRefresh]) const counts = useMemo(() => ({ total: workflows.length, active: workflows.filter((w) => w.status === "active").length, draft: workflows.filter((w) => w.status === "draft").length }), [workflows]) return (
{actionError ?
{actionError}
: null}

Workflow Pipelines

{counts.active} active, {counts.draft} draft{counts.total > counts.active + counts.draft ? `, ${counts.total - counts.active - counts.draft} other` : ""}

setShowCreate(true)} icon={Plus} tone="accent" />
{workflows.length === 0 ?
No workflow pipelines
Workflows chain actions into multi-step pipelines.
setShowCreate(true)} icon={ArrowsClockwise} tone="accent" />
:
{workflows.map((wf) => setDelTarget(wf)} onEdit={() => setEditWf(wf)} onRun={() => void handleRun(wf)} />)}
} {showCreate ? setShowCreate(false)} onSaved={onRefresh} /> : null}{editWf ? setEditWf(null)} onSaved={onRefresh} /> : null} {delTarget ? void handleDelete()} onCancel={() => setDelTarget(null)} /> : null}
) } export function AutomationPanel({ rules, workflows, companyId, onRefresh }: { rules: AutomationRuleRecord[]; workflows: WorkflowPipelineRecord[]; companyId: string; onRefresh: () => void }) { const t = useT(); const [activeSection, setActiveSection] = useState<"rules"|"workflows">("rules") return (
{t("auto.automationEngine")}
Rules trigger actions based on company events. Workflows chain multiple steps into pipelines. Together, they let your AI company run fully autonomously.
{activeSection === "rules" ? : }
) }