import { useMemo } from "react"; import { ArrowRight, Briefcase, CurrencyCircleDollar, Robot, ShieldCheck, Warning, XCircle, } from "@phosphor-icons/react"; import type { ActivityRecord, AgentRecord, AgentMessageRecord, ApprovalRecord, CostRecord, GoalRecord, ProjectRecord, RunRecord, SectionId, TaskRecord, } from "@shared/types"; import { formatMoney } from "../../lib/formatters"; import { useT } from "../../i18n"; import { MetricCard } from "./MetricsGrid"; import { ActivityFeed } from "./ActivityFeed"; import { RecoveryBanner } from "./RecoveryBanner"; import { BudgetAlertBanner } from "./BudgetAlertBanner"; import { ChartSection } from "./ChartSection"; import { AttentionRow } from "../ui"; export interface DashboardProps { companyName?: string; companyId?: string; agents: AgentRecord[]; tasks: TaskRecord[]; runs: RunRecord[]; approvals: ApprovalRecord[]; goals: GoalRecord[]; projects: ProjectRecord[]; activity: ActivityRecord[]; costs: CostRecord[]; messages?: AgentMessageRecord[]; onNavigate: (section: SectionId, entityId?: string) => void; } export function Dashboard(props: DashboardProps) { const t = useT(); const { companyName, companyId, agents, tasks, runs, approvals, activity, costs, messages = [], onNavigate } = props; const agentMap = useMemo(() => new Map(agents.map((a) => [a.id, a])), [agents]); const taskMap = useMemo(() => new Map(tasks.map((t) => [t.id, t])), [tasks]); const activeAgents = useMemo(() => agents.filter((a) => a.status !== "terminated" && a.status !== "pending_approval"), [agents]); const activeTasks = useMemo(() => tasks.filter((t) => t.status === "in_progress" || t.status === "in_review"), [tasks]); const pendingApprovals = useMemo(() => approvals.filter((a) => a.state === "pending"), [approvals]); const totalSpend = useMemo(() => costs.reduce((sum, c) => sum + (c.amountUsd ?? 0), 0), [costs]); // Attention items const failedRuns = useMemo(() => runs.filter((r) => (r.status === "failed" || r.status === "timed_out") || (r.status === "interrupted" && r.summary !== "Application shut down." && r.summary !== "Worker process crashed.") ), [runs]); const urgentMessages = useMemo(() => messages.filter((m) => !m.readAt && (m.priority === "urgent" || m.channel === "incident")), [messages]); const hasAttentionItems = pendingApprovals.length > 0 || failedRuns.length > 0 || urgentMessages.length > 0; // Active work — agents currently running tasks const activeWork = useMemo(() => { return runs .filter((r) => r.status === "running" || r.status === "queued") .map((run) => { const agent = agentMap.get(run.agentId); const task = taskMap.get(run.taskId); return { run, agent, task }; }) .slice(0, 8); }, [runs, agentMap, taskMap]); return (
{/* Company status line */} {companyName ? (

{companyName}

{activeAgents.length} {activeAgents.length === 1 ? t("dash.agentActive") : t("dash.agentsActive")} {activeTasks.length} {activeTasks.length === 1 ? t("dash.taskInProgress") : t("dash.tasksInProgress")} {tasks.filter((tk) => tk.status === "done").length} {t("dash.completedCount")}
) : null} {/* Conditional banners */} {/* Key Metrics — 4 cards */}
0 ? "accent" : "default"} onClick={() => onNavigate("tasks")} subtitle={`${tasks.filter((t) => t.status === "todo").length} ${t("dash.queued")}`} /> 0 ? "warn" : "default"} onClick={() => onNavigate("approvals")} subtitle={pendingApprovals.length > 0 ? t("dash.needsAttention") : t("dash.allClear")} /> a.status === "running").length > 0 ? "success" : "default"} onClick={() => onNavigate("agents")} subtitle={`${activeAgents.filter((a) => a.status === "running").length} ${t("dash.running")}`} /> onNavigate("settings")} />
{/* Performance Charts */} {companyId ? : null} {/* Needs Attention — moved to top, only shows when items exist */} {hasAttentionItems ? (
{t("dash.needsAttentionSection")}
{pendingApprovals.slice(0, 5).map((approval, i) => { const requester = approval.requestedByAgentId ? agentMap.get(approval.requestedByAgentId) : undefined; return ( {approval.type.replaceAll("_", " ")} {requester ? by {requester.name} : null} } onClick={() => onNavigate("approvals", approval.id)} /> ); })} {failedRuns.slice(0, 3).map((run, i) => { const agent = agentMap.get(run.agentId); return ( onNavigate("runs", run.id)} /> ); })} {urgentMessages.slice(0, 3).map((msg, i) => { const sender = agentMap.get(msg.fromAgentId); return ( onNavigate("communication", msg.id)} /> ); })}
) : null} {/* Active Work — what's running right now */}
{t("dash.activeWork")}
{activeWork.length > 0 ? (
{activeWork.map(({ run, agent, task }, i) => ( ))}
) : (
{t("dash.allQuiet")}
{t("dash.noTasksRunning")}
)}
{/* Recent Activity */}
{t("dash.recentActivity")}
); }