File size: 3,406 Bytes
7c5ed63 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | import { useState } from 'react';
import type { AgentRecord, WireEntry } from '../../types';
import { CopyButton } from '../shared/CopyButton';
import { JsonViewer } from '../shared/JsonViewer';
import { GenericDetail } from './parts';
import { rendererFor } from './renderers';
interface WireRowDetailProps {
entry: WireEntry;
/** Scroll to + expand a given line. */
onJumpTo?: (lineNo: number) => void;
}
type JsonView = 'none' | 'raw' | 'projected';
export function WireRowDetail({ entry }: WireRowDetailProps) {
const [view, setView] = useState<JsonView>('none');
// Only offer the dual view when migration actually changed something.
// For records on the current protocol, `raw` and `data` are identical
// and the toggle would just be visual noise.
const migrated = !sameJson(entry.raw, entry.data);
return (
<div className="pl-[120px] pr-2 py-1 font-mono text-[12px]">
{renderFriendly(entry.data)}
<div className="mt-2 flex items-center justify-end gap-3">
<CopyButton
value={JSON.stringify(entry.raw, null, 2)}
label="copy raw"
/>
{migrated ? (
<CopyButton
value={JSON.stringify(entry.data, null, 2)}
label="copy projected"
/>
) : null}
<button
onClick={() => {
setView((v) => (v === 'raw' ? 'none' : 'raw'));
}}
className={`font-mono text-[10px] ${
view === 'raw' ? 'text-fg-0' : 'text-fg-3 hover:text-fg-1'
}`}
title="What this line looks like on disk (no vis-side transforms)"
>
{view === 'raw' ? '[ hide raw ]' : '[ {…} raw ]'}
</button>
{migrated ? (
<button
onClick={() => {
setView((v) => (v === 'projected' ? 'none' : 'projected'));
}}
className={`font-mono text-[10px] ${
view === 'projected' ? 'text-fg-0' : 'text-fg-3 hover:text-fg-1'
}`}
title="Same line after vis applied the engine's wire migration chain"
>
{view === 'projected' ? '[ hide projected ]' : '[ {…} projected ]'}
</button>
) : null}
</div>
{view !== 'none' ? (
<div className="mt-2 border border-border bg-surface-0 p-2">
<div className="mb-1 font-mono text-[10px] uppercase tracking-[0.08em] text-fg-3">
{view === 'raw' ? 'as written on disk' : 'after vis migration'}
{migrated && view === 'raw' ? (
<span className="ml-2 text-[var(--color-sev-warning)]">
— differs from projected
</span>
) : null}
</div>
<JsonViewer
value={view === 'raw' ? entry.raw : entry.data}
defaultOpenDepth={2}
/>
</div>
) : null}
</div>
);
}
function sameJson(a: unknown, b: unknown): boolean {
try {
return JSON.stringify(a) === JSON.stringify(b);
} catch {
return false;
}
}
/** Render the expanded detail for a wire record. Thin dispatch to the per-kind
* registry's `detail`; kinds without one fall back to a structured JSON dump. */
function renderFriendly(record: AgentRecord) {
const renderer = rendererFor(record.type);
if (renderer?.detail !== undefined) return renderer.detail(record);
return <GenericDetail value={record} />;
}
|