Zayne Rea Sprague
Initial deploy: aggregate trace visualizer
8b41737
import { useState } from "react";
import type { InstanceRawLogs } from "../types";
import * as api from "../api";
interface Props {
dsId: string;
instanceId: string;
}
export function StepDetail({ dsId, instanceId }: Props) {
const [logs, setLogs] = useState<InstanceRawLogs | null>(null);
const [loading, setLoading] = useState(false);
const [activeTab, setActiveTab] = useState<
"agent_stdout" | "setup_stderr" | "verifier_report" | "verifier_stdout"
>("agent_stdout");
const loadLogs = async () => {
setLoading(true);
try {
const data = await api.getInstanceRaw(dsId, instanceId);
setLogs(data);
} catch {
// ignore
}
setLoading(false);
};
if (!logs) {
return (
<div className="p-4 border-t border-gray-800">
<button
onClick={loadLogs}
disabled={loading}
className="px-3 py-1.5 bg-gray-800 rounded text-xs text-gray-300 hover:bg-gray-700 disabled:opacity-50"
>
{loading ? "Loading..." : "Load Raw Logs"}
</button>
</div>
);
}
const tabs = [
{ key: "agent_stdout" as const, label: "Agent Stdout", content: logs.agent_stdout },
{ key: "setup_stderr" as const, label: "Setup Stderr", content: logs.setup_stderr },
{ key: "verifier_report" as const, label: "Verifier Report", content: logs.verifier_report },
{ key: "verifier_stdout" as const, label: "Verifier Stdout", content: logs.verifier_stdout },
].filter((t) => t.content);
return (
<div className="border-t border-gray-800">
<div className="flex border-b border-gray-800">
{tabs.map((tab) => (
<button
key={tab.key}
onClick={() => setActiveTab(tab.key)}
className={`px-3 py-2 text-xs font-medium ${
activeTab === tab.key
? "text-blue-400 border-b-2 border-blue-400"
: "text-gray-500 hover:text-gray-300"
}`}
>
{tab.label}
</button>
))}
</div>
<div className="max-h-96 overflow-y-auto p-3">
<pre className="code-block text-gray-300 whitespace-pre-wrap break-words">
{tabs.find((t) => t.key === activeTab)?.content || "No content"}
</pre>
</div>
</div>
);
}