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(""); // Busca token e embeddedId (UUID) do backend const fetchTokenData = useCallback(async (): Promise<{ token: string; embeddedId: string }> => { 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}`); } return resp.json(); }, [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; } // Resolve embeddedId (UUID) e obtém token inicial const { embeddedId } = await fetchTokenData(); // 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: embeddedId, // UUID do embedded config (não o slug) supersetDomain: "https://bi.onboardbi.com.br", mountPoint: containerRef.current, fetchGuestToken: async () => { const { token } = await fetchTokenData(); return token; }, dashboardUiConfig: { hideTitle: true, hideChartControls: false, filters: { visible: true, expanded: false }, }, }); setStatus("ready"); } catch (err: any) { console.error("[SupersetDashboard] Erro:", err.message, err); setErrorMsg(err.message || "Erro desconhecido"); setStatus("error"); } }, [dashboardId, fetchTokenData]); useEffect(() => { loadDashboard(); return () => { if (containerRef.current) containerRef.current.innerHTML = ""; }; }, [loadDashboard]); const heightStyle = typeof height === "number" ? `${height}px` : height; if (status === "unavailable") { return ( Arcádia Insights indisponível O serviço de BI está iniciando. Tente novamente em alguns segundos. Tentar novamente Abrir em nova aba ); } if (status === "error") { return ( Erro ao carregar dashboard {errorMsg} Tentar novamente ); } return ( {status === "loading" && ( Carregando Arcádia Insights... )} {showOpenLink && status === "ready" && ( Abrir completo )} ); }
Arcádia Insights indisponível
O serviço de BI está iniciando. Tente novamente em alguns segundos.
Erro ao carregar dashboard
{errorMsg}
Carregando Arcádia Insights...