Zayne Rea Sprague
Initial deploy: aggregate trace visualizer
8b41737
import type { GroupedInstance } from "../types";
interface Props {
instances: GroupedInstance[];
currentId: string;
onSelect: (id: string) => void;
}
export function InstanceNav({ instances, currentId, onSelect }: Props) {
const currentIdx = instances.findIndex((g) => g.instance_id === currentId);
return (
<div className="bg-gray-900 border-t border-gray-800 px-4 py-2 flex items-center justify-between">
<button
onClick={() => currentIdx > 0 && onSelect(instances[currentIdx - 1].instance_id)}
disabled={currentIdx <= 0}
className="px-3 py-1 rounded text-xs bg-gray-800 text-gray-300 hover:bg-gray-700 disabled:opacity-30 disabled:cursor-not-allowed"
>
&larr; Prev (k)
</button>
<div className="flex items-center gap-2">
<span className="text-xs text-gray-500">
{currentIdx + 1} / {instances.length}
</span>
{/* Dot navigation for nearby instances */}
<div className="flex gap-0.5">
{instances.slice(Math.max(0, currentIdx - 5), currentIdx + 6).map((g) => (
<button
key={g.instance_id}
onClick={() => onSelect(g.instance_id)}
className={`w-2 h-2 rounded-full ${
g.instance_id === currentId
? "bg-blue-400"
: g.datasets.every((d) => d.summary.resolved)
? "bg-emerald-600"
: "bg-gray-600"
}`}
title={g.instance_id}
/>
))}
</div>
</div>
<button
onClick={() =>
currentIdx < instances.length - 1 &&
onSelect(instances[currentIdx + 1].instance_id)
}
disabled={currentIdx >= instances.length - 1}
className="px-3 py-1 rounded text-xs bg-gray-800 text-gray-300 hover:bg-gray-700 disabled:opacity-30 disabled:cursor-not-allowed"
>
Next (j) &rarr;
</button>
</div>
);
}