Files
ThothII/frontend/src/viewers/ResultsPanel.tsx
T
marcopanandClaude Fable 5 1c97289ed8 feat(frontend): v2 artifact viewers for cte_plan/cte_result/phase
Add CtePlanViewer, CteResultViewer, and PhaseSummaryViewer to render the
structured v2 payloads (schema_version: 2) the harness now emits for
artifact-gate widgets, per contracts.md. Extract PreviewGrid from
ResultsPanel as a reusable AG Grid component shared by CteResultViewer.
ArtifactView dispatches to the new viewers on a schema_version/shape
guard, falling back to the existing legacy renderers unchanged for
older sessions and replay fixtures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 00:57:20 +02:00

68 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { sqlPreview, sqlExport } from "../api/sql";
import { PreviewGrid } from "./PreviewGrid";
interface Props {
sessionId: string;
}
export function ResultsPanel({ sessionId }: Props) {
const [limit, setLimit] = useState<number>(10);
const { data, isLoading, error } = useQuery({
queryKey: ["preview", sessionId, limit],
queryFn: () => sqlPreview(sessionId, { limit, offset: 0 }),
});
async function handleExport() {
await sqlExport(sessionId);
}
const isScalar =
data != null && data.columns.length === 1 && data.rows.length === 1;
return (
<div>
{/* Limit selector */}
<div className="mb-2 flex items-center gap-2">
<select
className="rounded-lg border border-input bg-card px-2 py-1 text-sm shadow-xs outline-none transition-[border-color,box-shadow] focus:border-primary/50 focus:ring-2 focus:ring-ring/20"
value={limit}
onChange={(e) =>
setLimit(e.target.value === "all" ? 1_000_000 : Number(e.target.value))
}
aria-label="Rows to display"
>
<option value={10}>10</option>
<option value="all">all</option>
</select>
<button
className="rounded-md border border-border/70 px-3 py-1 text-sm shadow-xs transition-colors hover:bg-accent"
onClick={handleExport}
>
Export CSV
</button>
</div>
{/* Loading / error states */}
{isLoading && <div>Loading…</div>}
{error && <div>Error: {String(error)}</div>}
{/* Scalar result: 1 col × 1 row → bold value */}
{data && isScalar && (
<strong data-testid="scalar-value">{String(data.rows[0][0])}</strong>
)}
{/* Grid for everything else */}
{data && !isScalar && (
<>
<PreviewGrid columns={data.columns} rows={data.rows} />
{data.truncated && <div>(results truncated)</div>}
</>
)}
</div>
);
}