"use client"; import { useEffect, useRef, useState } from "react"; import { ArrowLeft, BookOpen, FileText, GitCompareArrows, X } from "lucide-react"; import type { CanvasItem, CardBusinessData, InspectorDetailProjection, InspectorTab, InspectorWorkbenchProjection, RetrievalActivity } from "@/lib/types"; import { StatusBadge } from "@/components/ui/Badges"; import { InspectorComparison } from "@/components/inspector/InspectorComparison"; import { LegacyInspector } from "@/components/inspector/LegacyInspector"; interface Props { item: CanvasItem; mode?: "business" | "lineage"; onModeChange?: (mode: "business" | "lineage") => void; onClose: () => void; onBack?: () => void; backLabel?: string; onNavigate?: (activity: RetrievalActivity) => void; onPrompt?: (promptRef: string) => void; onArtifact?: () => void; workbench?: InspectorWorkbenchProjection; workbenchLoading?: boolean; workbenchError?: string; topOverlayOpen?: boolean; // Kept only so old isolated callers still compile while the formal path uses workbench. tab?: InspectorTab; onTab?: (tab: InspectorTab) => void; detail?: unknown; detailLoading?: boolean; detailError?: string; cardData?: CardBusinessData; cardDataLoading?: boolean; cardDataError?: string; cardDataMissingRef?: boolean; } export function Inspector(props: Props) { const [internalTab, setInternalTab] = useState("business"); useEffect(() => setInternalTab("business"), [props.item.id]); const tab = props.tab || internalTab; const onTab = props.onTab || setInternalTab; const mode = props.mode || (props.tab && props.onTab ? "business" : "lineage"); if (mode === "business") return props.onModeChange?.("lineage") : undefined} />; return props.onModeChange?.("business") : undefined} />; } function ComparisonInspector({ item, onClose, onBack, backLabel, onNavigate, onPrompt, onArtifact, onBusiness, workbench, workbenchLoading, workbenchError, detailLoading, detailError, topOverlayOpen = false }: Props & { onBusiness?: () => void }) { const dialog = useRef(null); const topOverlayOpenRef = useRef(topOverlayOpen); topOverlayOpenRef.current = topOverlayOpen; const [activeBindingId, setActiveBindingId] = useState(); const [clearActiveSignal, setClearActiveSignal] = useState(0); const promptRef = promptRefFor(item); useEffect(() => setActiveBindingId(undefined), [item.id]); useEffect(() => { const keepFocusInside = (event: FocusEvent) => { const panel = dialog.current; if (topOverlayOpenRef.current || !panel || panel.contains(event.target as Node)) return; panel.querySelector('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), summary, [tabindex]:not([tabindex="-1"])')?.focus(); }; document.addEventListener("focusin", keepFocusInside); return () => document.removeEventListener("focusin", keepFocusInside); }, []); const trapFocus = (event: React.KeyboardEvent) => { if (topOverlayOpen) return; if (event.key === "Escape") { if (activeBindingId) { event.preventDefault(); event.stopPropagation(); setActiveBindingId(undefined); setClearActiveSignal((value) => value + 1); return; } event.preventDefault(); event.stopPropagation(); onClose(); return; } if (event.key !== "Tab") return; const focusable = [...(dialog.current?.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), summary, [tabindex]:not([tabindex="-1"])') || [])]; if (!focusable.length) return; const first = focusable[0]; const last = focusable[focusable.length - 1]; if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); } else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); } }; const effectiveError = workbenchError || (!workbench && !workbenchLoading && detailError ? detailError : undefined); const effectiveLoading = workbenchLoading || (!workbench && !workbenchError && detailLoading); return <>