"use client"; import { useEffect, useMemo, useState } from "react"; import { Braces, Database, FileCheck2, X } from "lucide-react"; import { fetchArtifact } from "@/lib/api"; import type { JourneyStep, JourneyView, RunSummary } from "@/lib/types"; export function EvidencePanel({ journey, run, step, onClose, }: { journey: JourneyView; run: RunSummary | null; step: JourneyStep | null; onClose: () => void; }) { const [artifact, setArtifact] = useState | null>(null); const [artifactError, setArtifactError] = useState(null); const artifactId = useMemo(() => firstArtifactId(step), [step]); useEffect(() => { setArtifact(null); setArtifactError(null); }, [step?.step_id]); if (!step) { return ( ); } async function loadArtifact() { if (artifactId === null) return; try { setArtifact(await fetchArtifact(journey.script_build_id, artifactId)); } catch (reason) { setArtifactError(reason instanceof Error ? reason.message : "无法读取 Artifact"); } } return ( ); } function PanelHeader({ title, onClose }: { title: string; onClose: () => void }) { return (
原始证据

{title}

); } function EvidenceBlock({ icon: Icon, title, value }: { icon: typeof FileCheck2; title: string; value: unknown }) { return (
{title}
{JSON.stringify(value, null, 2)}
); } function firstArtifactId(step: JourneyStep | null): number | null { for (const item of step?.evidence.artifact_refs ?? []) { const uri = typeof item.uri === "string" ? item.uri : ""; const match = uri.match(/^script-build:\/\/artifact-versions\/(\d+)$/); if (match) return Number(match[1]); } return null; }