feat: initial commit
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useHarnessState } from "../assistant/HarnessContext";
|
||||
import type { HarnessEvent } from "@agent-studio/shared";
|
||||
|
||||
type Filter = "all" | "run" | "skill" | "tool" | "approval" | "model";
|
||||
export function TimelinePanel() {
|
||||
const { events } = useHarnessState(); const [filter, setFilter] = useState<Filter>("all"); const viewport = useRef<HTMLDivElement>(null); const atBottom = useRef(true);
|
||||
const visible = events.filter((event) => filter === "all" || event.type.startsWith(`${filter}.`) || (filter === "tool" && event.type.startsWith("attachment.")));
|
||||
useEffect(() => { if (atBottom.current) viewport.current?.scrollTo({ top: viewport.current.scrollHeight }); }, [visible.length]);
|
||||
return <aside className="side-panel timeline-panel" aria-label="Event Timeline"><div className="panel-heading"><span className="eyebrow">HARNESS FACTS</span><h2>Event Timeline</h2><p>Pi 事件、推导 Skill 事件与审批事实,按 Session sequence 排序。</p></div><div className="filters" role="group" aria-label="事件筛选">{(["all", "run", "skill", "tool", "approval", "model"] as Filter[]).map((item) => <button key={item} className={filter === item ? "selected" : ""} onClick={() => setFilter(item)}>{item}</button>)}</div><div className="timeline" ref={viewport} onScroll={(event) => { const node = event.currentTarget; atBottom.current = node.scrollHeight - node.scrollTop - node.clientHeight < 48; }}>{visible.length === 0 && <div className="panel-state">等待 Harness 事件…</div>}{visible.map((event) => <EventRow key={event.eventId} event={event}/>)}</div></aside>;
|
||||
}
|
||||
function EventRow({ event }: { event: HarnessEvent }) { const [open, setOpen] = useState(false); return <article className={`event-row ${event.type.startsWith("approval.") ? "risk" : ""}`}><button onClick={() => setOpen(!open)} aria-expanded={open}><span className="sequence">#{event.sequence}</span><span><strong>{event.type}</strong><small>{new Date(event.timestamp).toLocaleTimeString()}</small></span></button>{open && <pre>{JSON.stringify(event.payload, null, 2)}</pre>}</article>; }
|
||||
Reference in New Issue
Block a user