diff --git a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx index cc3b75d1..4a9dbe57 100644 --- a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx @@ -4,14 +4,16 @@ import { TopbarActions } from "../shared/TopbarActions"; import type { AgentRecord, ApprovalRecord, + ChatMessageRecord, EmployeeRecord, GoalRecord, ProviderRecord, TaskRecord, + TaskRunRecord, } from "../../../shared/domain"; import { NewTaskDialog } from "./NewTaskDialog"; import type { PageProps } from "./types"; -import { activeOrgId, formatTime, money, requireActiveEmployee, requireActiveOrganization } from "./types"; +import { activeOrgId, formatRelative, formatTime, money, requireActiveEmployee, requireActiveOrganization } from "./types"; export function HomePage({ snapshot, actions, navigate }: PageProps) { const orgId = activeOrgId(snapshot); @@ -32,6 +34,9 @@ export function HomePage({ snapshot, actions, navigate }: PageProps) { .reduce((sum, policy) => sum + policy.monthlyBudgetLimitCents, 0), [snapshot.hiringPolicies, orgId], ); + const taskRuns = useMemo(() => snapshot.taskRuns.filter((run) => run.orgId === orgId), [snapshot.taskRuns, orgId]); + const chatMessages = useMemo(() => snapshot.chatMessages.filter((m) => m.orgId === orgId), [snapshot.chatMessages, orgId]); + const chatSpaces = useMemo(() => snapshot.chatSpaces.filter((s) => s.orgId === orgId), [snapshot.chatSpaces, orgId]); const [newTaskOpen, setNewTaskOpen] = useState(false); const pendingApprovals = approvals.filter((approval) => approval.state === "pending"); @@ -77,6 +82,11 @@ export function HomePage({ snapshot, actions, navigate }: PageProps) { +
+ navigate("work")} /> + navigate("chat")} /> +
+ setNewTaskOpen(false)} /> ); @@ -366,3 +376,115 @@ function resolveRequester(approval: ApprovalRecord, employees: EmployeeRecord[], } return "System"; } + +function RunActivityCard({ + taskRuns, + tasks, + agents, + onViewAll, +}: { + taskRuns: TaskRunRecord[]; + tasks: TaskRecord[]; + agents: AgentRecord[]; + onViewAll: () => void; +}) { + const recent = taskRuns.slice(0, 8); + return ( +
+
+ Agent runs + +
+
+ {recent.map((run) => { + const task = tasks.find((t) => t.id === run.taskId); + const agent = agents.find((a) => a.id === run.agentId); + return ( +
+ {agent && } +
+
+ {task?.title ?? run.taskId} +
+
+ {agent?.name ?? "Agent"} · {run.trigger} +
+
+ {runStateLabel(run.state)} + {formatRelative(run.createdAt)} +
+ ); + })} + {recent.length === 0 &&
No runs yet
} +
+
+ ); +} + +function RecentMessagesCard({ + messages, + agents, + employees, + spaces, + onViewAll, +}: { + messages: ChatMessageRecord[]; + agents: AgentRecord[]; + employees: EmployeeRecord[]; + spaces: Array<{ id: string; name: string }>; + onViewAll: () => void; +}) { + const recent = messages.slice(-8).reverse(); + return ( +
+
+ Recent messages + +
+
+ {recent.map((msg) => { + const senderAgent = msg.senderType === "agent" ? agents.find((a) => a.id === msg.senderId) : null; + const senderEmployee = msg.senderType === "employee" ? employees.find((e) => e.id === msg.senderId) : null; + const name = senderAgent?.name ?? senderEmployee?.displayName ?? msg.senderType; + const space = spaces.find((s) => s.id === msg.spaceId); + const preview = msg.bodyMd.length > 80 ? `${msg.bodyMd.slice(0, 77)}...` : msg.bodyMd; + return ( +
+ +
+
+ {name} + {space && #{space.name}} + {formatTime(msg.createdAt)} +
+
+ {preview} +
+
+
+ ); + })} + {recent.length === 0 &&
No messages yet
} +
+
+ ); +} + +function runStateTone(state: string): "red" | "amber" | "violet" | undefined { + if (state === "failed") return "red"; + if (state === "running") return "violet"; + if (state === "queued") return "amber"; + return undefined; +} + +function runStateLabel(state: string): string { + if (state === "queued") return "Queued"; + if (state === "running") return "Running"; + if (state === "completed") return "Done"; + if (state === "failed") return "Failed"; + return state; +}