From 08896d23eeeba34b489dcb9f6e01e6ed5772a1f4 Mon Sep 17 00:00:00 2001 From: Jiayuan Zhang Date: Fri, 10 Apr 2026 02:43:18 +0800 Subject: [PATCH] feat(views): add Gantt chart and token consumption curve to transcript dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an "Analytics" view mode toggle to the transcript dialog header: - **Execution Gantt Chart**: Horizontal bar chart showing tool call spans by sequence number. Color-coded by tool type (Bash, Read, Edit, etc.) and event type (thinking, text, error). Clicking a bar navigates to the corresponding event in timeline view. - **Token Consumption Curve**: Area chart showing estimated cumulative token usage across events. Red dashed reference lines mark error events. Displays total and per-event average token estimates. Clicking a point navigates to that event. Both charts use the existing recharts + shadcn ChartContainer setup. Charts are interactive — clicking elements switches back to timeline mode and selects the corresponding event. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../components/agent-transcript-dialog.tsx | 144 ++++-- .../issues/components/transcript-charts.tsx | 409 ++++++++++++++++++ 2 files changed, 507 insertions(+), 46 deletions(-) create mode 100644 packages/views/issues/components/transcript-charts.tsx diff --git a/packages/views/issues/components/agent-transcript-dialog.tsx b/packages/views/issues/components/agent-transcript-dialog.tsx index 59a3324dd..fa1e5c9e1 100644 --- a/packages/views/issues/components/agent-transcript-dialog.tsx +++ b/packages/views/issues/components/agent-transcript-dialog.tsx @@ -18,6 +18,8 @@ import { Cpu, FileCode, Search, + List, + BarChart3, } from "lucide-react"; import { cn } from "@multica/ui/lib/utils"; import { Dialog, DialogContent, DialogTitle } from "@multica/ui/components/ui/dialog"; @@ -27,6 +29,7 @@ import { Markdown } from "../../common/markdown"; import { api } from "@multica/core/api"; import type { AgentTask, Agent, AgentRuntime } from "@multica/core/types/agent"; import { redactSecrets } from "../utils/redact"; +import { TranscriptGanttChart, TranscriptTokenChart } from "./transcript-charts"; // ─── Types ────────────────────────────────────────────────────────────────── @@ -167,6 +170,7 @@ export function AgentTranscriptDialog({ isLive = false, }: AgentTranscriptDialogProps) { const [selectedIdx, setSelectedIdx] = useState(null); + const [viewMode, setViewMode] = useState<"timeline" | "analytics">("timeline"); const [elapsed, setElapsed] = useState(""); const [copied, setCopied] = useState(false); const [agentInfo, setAgentInfo] = useState(null); @@ -209,12 +213,26 @@ export function AgentTranscriptDialog({ // Click a timeline segment → scroll to event and select it const handleSegmentClick = useCallback((idx: number) => { setSelectedIdx(idx); + setViewMode("timeline"); const el = eventRefs.current.get(idx); if (el) { el.scrollIntoView({ behavior: "smooth", block: "center" }); } }, []); + // Click chart element → switch to timeline and select by seq number + const handleChartEventClick = useCallback((seq: number) => { + const idx = items.findIndex((item) => item.seq === seq); + if (idx >= 0) { + setSelectedIdx(idx); + setViewMode("timeline"); + setTimeout(() => { + const el = eventRefs.current.get(idx); + if (el) el.scrollIntoView({ behavior: "smooth", block: "center" }); + }, 100); + } + }, [items]); + // Copy all events as text const handleCopyAll = useCallback(() => { const text = items @@ -291,6 +309,33 @@ export function AgentTranscriptDialog({ {statusBadge}
+ {/* View mode toggle */} +
+ + +