Make the trace pane overflow neater. Closes #270.

This commit is contained in:
Jack Kingsman
2026-06-01 18:22:41 -07:00
parent 4e195f0dd1
commit 50af30f3bb
+43 -31
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'; import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
import { ArrowDown, ArrowUp, Plus, X } from 'lucide-react'; import { ArrowDown, ArrowUp, ChevronDown, ChevronRight, Plus, X } from 'lucide-react';
import type { import type {
Contact, Contact,
@@ -199,6 +199,7 @@ export function TracePane({ contacts, config, onRunTracePath }: TracePaneProps)
const [customHopHexDraft, setCustomHopHexDraft] = useState(''); const [customHopHexDraft, setCustomHopHexDraft] = useState('');
const [customHopError, setCustomHopError] = useState<string | null>(null); const [customHopError, setCustomHopError] = useState<string | null>(null);
const [recentTraces, setRecentTraces] = useState<SavedTrace[]>(loadRecentTraces); const [recentTraces, setRecentTraces] = useState<SavedTrace[]>(loadRecentTraces);
const [recentTracesOpen, setRecentTracesOpen] = useState(false);
const activeRunTokenRef = useRef(0); const activeRunTokenRef = useRef(0);
const repeaters = useMemo(() => { const repeaters = useMemo(() => {
@@ -562,7 +563,7 @@ export function TracePane({ contacts, config, onRunTracePath }: TracePaneProps)
</section> </section>
<section className="flex flex-1 flex-col gap-4 lg:min-h-0 lg:overflow-hidden"> <section className="flex flex-1 flex-col gap-4 lg:min-h-0 lg:overflow-hidden">
<div className="flex flex-col rounded-lg border border-border bg-card lg:min-h-0 lg:max-h-[50%]"> <div className="flex flex-col rounded-lg border border-border bg-card lg:min-h-0 lg:flex-1 lg:overflow-hidden">
<div className="shrink-0 flex items-start justify-between gap-3 border-b border-border px-4 py-3"> <div className="shrink-0 flex items-start justify-between gap-3 border-b border-border px-4 py-3">
<div> <div>
<h3 className="text-sm font-semibold">Trace Path</h3> <h3 className="text-sm font-semibold">Trace Path</h3>
@@ -571,35 +572,46 @@ export function TracePane({ contacts, config, onRunTracePath }: TracePaneProps)
</p> </p>
{recentTraces.length > 0 && ( {recentTraces.length > 0 && (
<div className="mt-2"> <div className="mt-2">
<div className="text-[0.625rem] uppercase tracking-wider text-muted-foreground font-medium mb-1"> <button
Rerun a recent trace: type="button"
</div> className="flex items-center gap-1 text-[0.625rem] uppercase tracking-wider text-muted-foreground font-medium hover:text-foreground transition-colors"
<div className="flex flex-wrap gap-1.5"> onClick={() => setRecentTracesOpen((o) => !o)}
{recentTraces.map((trace, i) => { >
const label = trace.hops {recentTracesOpen ? (
.map((h) => { <ChevronDown className="h-3 w-3" />
if (h.kind === 'repeater' && h.publicKey) { ) : (
const shortKey = h.publicKey.slice(0, 12); <ChevronRight className="h-3 w-3" />
return h.displayName !== shortKey )}
? `${h.displayName} (${shortKey})` Recent traces ({recentTraces.length})
: shortKey; </button>
} {recentTracesOpen && (
return h.displayName; <div className="mt-1.5 flex flex-wrap gap-1.5 max-h-20 overflow-y-auto">
}) {recentTraces.map((trace, i) => {
.join(' → '); const label = trace.hops
return ( .map((h) => {
<button if (h.kind === 'repeater' && h.publicKey) {
key={i} const shortKey = h.publicKey.slice(0, 12);
type="button" return h.displayName !== shortKey
className="rounded-md border border-border px-2.5 py-1.5 text-xs hover:bg-accent transition-colors truncate max-w-full disabled:opacity-50 disabled:cursor-not-allowed" ? `${h.displayName} (${shortKey})`
disabled={loading} : shortKey;
onClick={() => handleLoadRecentTrace(trace)} }
> return h.displayName;
{label} })
</button> .join(' → ');
); return (
})} <button
</div> key={i}
type="button"
className="rounded-md border border-border px-2.5 py-1.5 text-xs hover:bg-accent transition-colors truncate max-w-full disabled:opacity-50 disabled:cursor-not-allowed"
disabled={loading}
onClick={() => handleLoadRecentTrace(trace)}
>
{label}
</button>
);
})}
</div>
)}
</div> </div>
)} )}
</div> </div>