fix(superset): resolver slug → UUID antes de gerar guest token e embeddar
O SDK do Superset exige o UUID do embedded config (não o slug) tanto no
embedDashboard quanto no guest token. Agora o backend resolve:
slug → dashboard ID → embedded UUID → guest token com UUID
E retorna { token, embeddedId } para o frontend usar no embedDashboard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6e8a3261bb
commit
023451e000
|
|
@ -27,7 +27,8 @@ export function SupersetDashboard({
|
||||||
const [status, setStatus] = useState<"loading" | "ready" | "error" | "unavailable">("loading");
|
const [status, setStatus] = useState<"loading" | "ready" | "error" | "unavailable">("loading");
|
||||||
const [errorMsg, setErrorMsg] = useState<string>("");
|
const [errorMsg, setErrorMsg] = useState<string>("");
|
||||||
|
|
||||||
const fetchGuestToken = useCallback(async (): Promise<string> => {
|
// Busca token e embeddedId (UUID) do backend
|
||||||
|
const fetchTokenData = useCallback(async (): Promise<{ token: string; embeddedId: string }> => {
|
||||||
const resp = await fetch("/api/superset/guest-token", {
|
const resp = await fetch("/api/superset/guest-token", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
|
|
@ -38,8 +39,7 @@ export function SupersetDashboard({
|
||||||
const err = await resp.json().catch(() => ({ error: "Erro desconhecido" }));
|
const err = await resp.json().catch(() => ({ error: "Erro desconhecido" }));
|
||||||
throw new Error(err.error || `HTTP ${resp.status}`);
|
throw new Error(err.error || `HTTP ${resp.status}`);
|
||||||
}
|
}
|
||||||
const { token } = await resp.json();
|
return resp.json();
|
||||||
return token;
|
|
||||||
}, [dashboardId]);
|
}, [dashboardId]);
|
||||||
|
|
||||||
const loadDashboard = useCallback(async () => {
|
const loadDashboard = useCallback(async () => {
|
||||||
|
|
@ -56,6 +56,9 @@ export function SupersetDashboard({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve embeddedId (UUID) e obtém token inicial
|
||||||
|
const { embeddedId } = await fetchTokenData();
|
||||||
|
|
||||||
// Importa SDK dinamicamente (só quando necessário)
|
// Importa SDK dinamicamente (só quando necessário)
|
||||||
const { embedDashboard } = await import("@superset-ui/embedded-sdk");
|
const { embedDashboard } = await import("@superset-ui/embedded-sdk");
|
||||||
|
|
||||||
|
|
@ -65,10 +68,13 @@ export function SupersetDashboard({
|
||||||
}
|
}
|
||||||
|
|
||||||
sdkRef.current = await embedDashboard({
|
sdkRef.current = await embedDashboard({
|
||||||
id: dashboardId,
|
id: embeddedId, // UUID do embedded config (não o slug)
|
||||||
supersetDomain: window.location.origin + "/superset",
|
supersetDomain: window.location.origin + "/superset",
|
||||||
mountPoint: containerRef.current,
|
mountPoint: containerRef.current,
|
||||||
fetchGuestToken,
|
fetchGuestToken: async () => {
|
||||||
|
const { token } = await fetchTokenData();
|
||||||
|
return token;
|
||||||
|
},
|
||||||
dashboardUiConfig: {
|
dashboardUiConfig: {
|
||||||
hideTitle: true,
|
hideTitle: true,
|
||||||
hideChartControls: false,
|
hideChartControls: false,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,29 @@ export function registerSupersetRoutes(app: Express): void {
|
||||||
const token = await getServiceToken();
|
const token = await getServiceToken();
|
||||||
const user = req.user as any;
|
const user = req.user as any;
|
||||||
|
|
||||||
|
// Resolve slug → dashboard ID → embedded UUID
|
||||||
|
const dashResp = await fetch(`${SUPERSET_URL}/api/v1/dashboard/${dashboardId}`, {
|
||||||
|
headers: { "Authorization": `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
if (!dashResp.ok) {
|
||||||
|
return res.status(404).json({ error: `Dashboard '${dashboardId}' não encontrado no Superset` });
|
||||||
|
}
|
||||||
|
const dashData = await dashResp.json();
|
||||||
|
const dbNumericId = dashData.result?.id;
|
||||||
|
|
||||||
|
const embeddedResp = await fetch(`${SUPERSET_URL}/api/v1/dashboard/${dbNumericId}/embedded`, {
|
||||||
|
headers: { "Authorization": `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
if (!embeddedResp.ok) {
|
||||||
|
return res.status(404).json({ error: `Dashboard '${dashboardId}' não tem embedding habilitado` });
|
||||||
|
}
|
||||||
|
const embeddedData = await embeddedResp.json();
|
||||||
|
const embeddedUuid = embeddedData.result?.uuid;
|
||||||
|
|
||||||
|
if (!embeddedUuid) {
|
||||||
|
return res.status(404).json({ error: `UUID de embedding não encontrado para '${dashboardId}'` });
|
||||||
|
}
|
||||||
|
|
||||||
const guestResp = await fetch(`${SUPERSET_URL}/api/v1/security/guest_token/`, {
|
const guestResp = await fetch(`${SUPERSET_URL}/api/v1/security/guest_token/`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -51,7 +74,7 @@ export function registerSupersetRoutes(app: Express): void {
|
||||||
first_name: user?.name?.split(" ")[0] || "Arcádia",
|
first_name: user?.name?.split(" ")[0] || "Arcádia",
|
||||||
last_name: user?.name?.split(" ").slice(1).join(" ") || "User",
|
last_name: user?.name?.split(" ").slice(1).join(" ") || "User",
|
||||||
},
|
},
|
||||||
resources: [{ type: "dashboard", id: dashboardId }],
|
resources: [{ type: "dashboard", id: embeddedUuid }],
|
||||||
rls: user?.tenantId ? [{ clause: `tenant_id = ${user.tenantId}` }] : [],
|
rls: user?.tenantId ? [{ clause: `tenant_id = ${user.tenantId}` }] : [],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
@ -62,7 +85,7 @@ export function registerSupersetRoutes(app: Express): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { token: guestToken } = await guestResp.json();
|
const { token: guestToken } = await guestResp.json();
|
||||||
res.json({ token: guestToken, supersetUrl: "/superset" });
|
res.json({ token: guestToken, embeddedId: embeddedUuid, supersetUrl: "/superset" });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("[Superset] guest-token error:", err.message);
|
console.error("[Superset] guest-token error:", err.message);
|
||||||
res.status(502).json({ error: err.message });
|
res.status(502).json({ error: err.message });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue