54 lines
2.7 KiB
TypeScript
54 lines
2.7 KiB
TypeScript
import { useQuery } from '@tanstack/react-query';
|
||
import { useSearchParams } from 'react-router-dom';
|
||
import { api, type HarnessRunRecord } from '../lib/api';
|
||
import { Card, StatusBadge } from '../components/ui/Card';
|
||
import { TraceExplorer } from '../components/trace/TraceExplorer';
|
||
|
||
export function Runs() {
|
||
const { data, isLoading } = useQuery({ queryKey: ['runs'], queryFn: () => api.runs(100) });
|
||
const [searchParams, setSearchParams] = useSearchParams();
|
||
const selectedTrace = searchParams.get('trace') ?? '';
|
||
|
||
if (isLoading || !data) return <div className="text-slate-500">Loading…</div>;
|
||
return (
|
||
<div className="space-y-5">
|
||
{selectedTrace && <TraceExplorer traceId={selectedTrace} onClose={() => setSearchParams({})} />}
|
||
<Card
|
||
title={`Recent runs (${data.count})`}
|
||
right={<span className="text-xs font-normal normal-case tracking-normal text-slate-400">Select a run to inspect H1–H7</span>}
|
||
>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-sm">
|
||
<thead><tr className="border-b border-slate-200 text-left text-slate-500">
|
||
<th className="py-2">time</th><th>step</th><th>status</th><th>latency</th><th>tokens</th><th>cost</th><th className="text-right">trace</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
{data.runs.map((run: HarnessRunRecord, index: number) => (
|
||
<tr key={`${run.trace_id ?? 'run'}-${index}`} className="border-b border-slate-100 transition-colors hover:bg-slate-50/80">
|
||
<td className="py-2 text-slate-500">{run.timestamp?.replace('T', ' ').replace('Z', '')}</td>
|
||
<td className="text-slate-700">{run.step ?? run.harness}</td>
|
||
<td><StatusBadge value={run.status ?? '—'} /></td>
|
||
<td>{run.latency_ms ?? '—'} ms</td>
|
||
<td>{run.total_tokens ?? '—'}</td>
|
||
<td>{run.cost_estimate == null ? <span className="font-medium text-amber-600">Unavailable</span> : `$${Number(run.cost_estimate).toFixed(5)}`}</td>
|
||
<td className="py-2 text-right">
|
||
{run.trace_id ? (
|
||
<button
|
||
type="button"
|
||
onClick={() => setSearchParams({ trace: run.trace_id ?? '' })}
|
||
className="rounded-lg border border-blue-200 bg-blue-50 px-3 py-1.5 text-xs font-semibold text-blue-700 transition-colors hover:bg-blue-100"
|
||
>
|
||
Open H1–H7
|
||
</button>
|
||
) : <span className="text-slate-300">—</span>}
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|