// Findings pane — three groups of rows for one kind (assumption / risk / // inconsistency): // // 1. Kept — status="accepted". Top of the pane, scrollable. // 2. Pending — status in {suggested, deprecated}. Drawer below kept. // 3. Discarded — status in {dismissed, resolved}. Collapsed drawer at the // bottom, hidden when empty. // // Clicking a row pushes a FindingColumn to the right (full detail + Socrates // thread + decision actions). Decisions also work inline from the row. "use client"; import { useMemo } from "react"; import { PaneFrame } from "../PaneFrame"; import { PaneEmpty } from "../PaneEmpty"; import { PaneDrawer } from "../PaneDrawer"; import { StatusChip } from "../StatusChip"; import { useAnalysis, type ClientFinding } from "../../../lib/workspace/analysisStore"; import { useOpenPanes } from "../../../lib/workspace/openPanesStore"; interface FindingsPaneProps { kind: "assumption" | "risk" | "inconsistency"; index: number; projectId: string; onClose: () => void; } const TITLES: Record = { assumption: "Assumptions", risk: "Risks", inconsistency: "Inconsistencies", }; const SECTION_TO_ANALYZE = { assumption: "assumptions", risk: "risks", inconsistency: "inconsistencies", } as const; const PENDING_STATUSES = new Set(["suggested", "deprecated"]); const DISCARDED_STATUSES = new Set(["dismissed", "resolved"]); export function FindingsPane({ kind, index, onClose }: FindingsPaneProps) { const { findings, analyze, inFlight } = useAnalysis(); const { pushFrom, columns } = useOpenPanes(); const items = useMemo(() => findings.filter(f => f.kind === kind), [findings, kind]); const kept = useMemo(() => items.filter(f => f.status === "accepted"), [items]); const pending = useMemo(() => items.filter(f => PENDING_STATUSES.has(f.status)), [items]); const discarded = useMemo(() => items.filter(f => DISCARDED_STATUSES.has(f.status)), [items]); const section = SECTION_TO_ANALYZE[kind]; const running = inFlight.has(section) || inFlight.has("all"); const activeId = columns[index + 1]?.kind === "finding" ? columns[index + 1]!.id : null; const subtitle = pending.length > 0 ? `${kept.length} kept · ${pending.length} pending` : `${kept.length} kept`; const right = (
); const renderRow = (f: ClientFinding) => ( pushFrom(index, { kind: "finding", id: f.id })} /> ); return (
{items.length === 0 ? ( void analyze(section), disabled: running, }} /> ) : kept.length === 0 ? ( ) : (
    {kept.map(renderRow)}
)}
{pending.length > 0 ? (
    {pending.map(renderRow)}
) : null}
    {discarded.map(renderRow)}
); } function FindingRow({ finding, active, onOpen, }: { finding: ClientFinding; active: boolean; onOpen: () => void; }) { const { decideFinding } = useAnalysis(); const isPending = PENDING_STATUSES.has(finding.status); const isDiscarded = DISCARDED_STATUSES.has(finding.status); return (
  • { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onOpen(); } }} >
    {finding.text} {finding.status === "suggested" ? : null} {finding.status === "deprecated" ? : null} {finding.status === "dismissed" ? : null} {finding.status === "resolved" ? : null} {finding.validationCode ? ( ) : null} {finding.severity ? ( ) : null}
    {isPending ? (
    e.stopPropagation()}> {finding.status === "suggested" ? ( ) : null}
    ) : isDiscarded ? (
    e.stopPropagation()}>
    ) : null}
  • ); }