import { useEffect, useRef, useState, useCallback } from "react"; import { Loader2, AlertTriangle, ExternalLink, RefreshCw } from "lucide-react"; interface SupersetDashboardProps { dashboardId: string; height?: string | number; className?: string; showOpenLink?: boolean; } /** * Componente reutilizável para embedar dashboards do Apache Superset (Arcádia Insights) * em QUALQUER tela do Arcádia Suite via Guest Token JWT. * * Uso: * * */ export function SupersetDashboard({ dashboardId, height = "calc(100vh - 320px)", className = "", showOpenLink = true, }: SupersetDashboardProps) { const containerRef = useRef(null); const sdkRef = useRef(null); const [status, setStatus] = useState<"loading" | "ready" | "error" | "unavailable">("loading"); const [errorMsg, setErrorMsg] = useState(""); const fetchGuestToken = useCallback(async (): Promise => { const resp = await fetch("/api/superset/guest-token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ dashboardId }), credentials: "include", }); if (!resp.ok) { const err = await resp.json().catch(() => ({ error: "Erro desconhecido" })); throw new Error(err.error || `HTTP ${resp.status}`); } const { token } = await resp.json(); return token; }, [dashboardId]); const loadDashboard = useCallback(async () => { if (!containerRef.current) return; setStatus("loading"); setErrorMsg(""); try { // Verifica se Superset está disponível const health = await fetch("/api/superset/health", { credentials: "include" }); const healthData = await health.json(); if (!healthData.online) { setStatus("unavailable"); return; } // Importa SDK dinamicamente (só quando necessário) const { embedDashboard } = await import("@superset-ui/embedded-sdk"); // Limpa embedding anterior se houver if (sdkRef.current) { containerRef.current.innerHTML = ""; } sdkRef.current = await embedDashboard({ id: dashboardId, supersetDomain: window.location.origin + "/superset", mountPoint: containerRef.current, fetchGuestToken, dashboardUiConfig: { hideTitle: true, hideChartControls: false, filters: { visible: true, expanded: false }, }, }); setStatus("ready"); } catch (err: any) { console.error("[SupersetDashboard] Erro:", err.message); // Se SDK não estiver instalado, usa iframe como fallback if (err.message?.includes("Cannot find module") || err.message?.includes("embedDashboard")) { setStatus("unavailable"); } else { setErrorMsg(err.message); setStatus("error"); } } }, [dashboardId, fetchGuestToken]); useEffect(() => { loadDashboard(); return () => { if (containerRef.current) containerRef.current.innerHTML = ""; }; }, [loadDashboard]); const heightStyle = typeof height === "number" ? `${height}px` : height; if (status === "unavailable") { return (