Incrustar Saiku
El Web Component <saiku-embed/> permite incrustar una consulta o un
dashboard guardado de Saiku dentro de cualquier página HTML — su sitio
de marketing, una entrada de blog, un portal de cliente, un wiki, o un
dashboard React / Vue. El mismo custom element funciona en cualquier
host: JSX de React, plantillas de Vue, Svelte, HTML plano.
Es un auténtico Web Component, no un wrapper de framework, por lo que la página host no necesita saber nada sobre los detalles internos de Saiku.
Instalación
Dos formas equivalentes de cargar el bundle. Elija la que mejor se adapte a su página host.
Sin paso de build — apunte una etiqueta <script> al bundle que
su Saiku ya sirve:
<script src="https://YOUR-WORKSPACE.saiku.bi/ui/saiku-embed.js"></script>La descarga ocupa unos 213 KB en gzip. Los navegadores la almacenan en caché, así que la segunda página del mismo origen la obtiene al instante.
Para proyectos React / Vue / SPA que empaquetan su propio JS:
npm install @concepttocloud/saiku-embedimport "@concepttocloud/saiku-embed";El import tiene el efecto colateral de registrar la etiqueta
saiku-embed globalmente — sin configuración adicional. La
publicación en npm sigue a la publicación de Saiku una a una.
Un ejemplo trabajado
El embed mínimo viable — una consulta guardada, renderizada como tabla:
<saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" token="tx-..." path="homes/admin/Examples/Trend.saiku" height="400px"></saiku-embed>Los tres atributos esenciales son server (origen de su Saiku),
path (ruta del repositorio de la consulta guardada) y token (el
token de embed — consulte Generar un token más
abajo). Todo lo demás tiene valores por defecto razonables.
Generar un token
Los tokens los genera un usuario autenticado que pueda leer el recurso. El token es opaco y está acotado: otorga acceso de solo lectura a una consulta o dashboard guardado, expira después del TTL que especifique y puede revocarse en cualquier momento.
curl -X POST 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/tokens' \ -u admin:admin \ -H 'Content-Type: application/json' \ -d '{ "resourceKind": "query", "resourcePath": "homes/admin/Examples/Trend.saiku", "ttlHours": 72, "label": "Marketing landing page" }'
# Response:# {# "status": "OK",# "token": "tx-...",# "resourceKind": "query",# "resourcePath": "homes/admin/Examples/Trend.saiku",# "expiresAt": 1739102400000# }Pegue el token en el <saiku-embed token="..."> de su página host.
Límites del TTL. Por defecto son 72 horas. El máximo es de 30 días (720 horas). Un TTL corto es el valor por defecto más seguro para un token que viaja a través de páginas host arbitrarias.
Límite por usuario. Cada usuario puede mantener hasta 200 tokens activos a la vez. Revoque los tokens no usados para liberar el cupo.
Listar sus tokens
curl 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/tokens' \ -u admin:adminLos administradores pueden listar todos los tokens del sistema con
?all=true.
Revocar un token
curl -X DELETE 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/tokens/<token>' \ -u admin:adminLa revocación surte efecto en la próxima petición — no hay sesión de invitado que secuestrar.
Embeds públicos (anónimos)
Si un recurso debe ser legible sin un token — un gráfico público en su página de aterrizaje, un dashboard abierto en un blog — márquelo como incrustable públicamente:
curl -X POST 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/public' \ -u admin:admin \ -H 'Content-Type: application/json' \ -d '{ "resourceKind": "query", "resourcePath": "shared/public-chart.saiku", "label": "Homepage chart" }'Después, la página host omite el token por completo:
<saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" path="shared/public-chart.saiku" render="chart"></saiku-embed>Listar + revocar concesiones públicas
# List your public grantscurl 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/public' \ -u admin:admin
# Revokecurl -X DELETE 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/public?kind=query&path=shared/public-chart.saiku' \ -u admin:adminReferencia de atributos
| Atributo | Por defecto | Notas |
|---|---|---|
server | requerido | Origen de su launcher de Saiku, por ejemplo https://YOUR-WORKSPACE.saiku.bi |
path | requerido | Ruta del repositorio. Termina en .saiku para consultas, .saikudash para dashboards |
kind | query | query o dashboard |
token | (ninguno) | Token de embed de POST /saiku/api/embed/tokens. Omítalo para lecturas públicas anónimas |
render | table | Para kind="query": table o chart |
mode | bar | Para render="chart": bar, line o pie |
height | 400px | Altura CSS (un min-height en la superficie renderizada) |
Los atributos son reactivos — el componente se vuelve a renderizar siempre que cambia cualquiera de ellos. En React, Vue o Svelte, vincular el estado a estas props funciona sin más.
Ejemplos
Consulta guardada como tabla
<saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" token="tx-..." path="homes/admin/Examples/Trend.saiku"></saiku-embed>Consulta guardada como gráfico
<saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" token="tx-..." path="homes/admin/Examples/Sales.saiku" render="chart" mode="bar" height="500px"></saiku-embed>Modos de gráfico:
bar(por defecto) — barras categóricas; la primera columna no numérica es la categoría, cada columna numérica se convierte en su propia serieline— mismo diseño, series de líneaspie— solo la primera columna numérica; cae a “No numeric series” si el resultado es solo texto
Los tooltips muestran las cadenas de celda formateadas por el servidor
($1,234, 12.3%, etc.) para que la página host vea las mismas
leyendas que mostraría el workbench de Saiku.
Dashboard guardado
<saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" token="tx-..." kind="dashboard" path="homes/admin/exec.saikudash" height="700px"></saiku-embed>El componente obtiene el diseño del dashboard una vez y luego ejecuta una consulta por mosaico de gráfico / KPI en paralelo bajo el ámbito de datos del propietario del dashboard. Tipos de mosaico en v1:
| Tipo de mosaico | Qué renderiza |
|---|---|
text | El texto del mosaico, como párrafo |
chart | Un gráfico ECharts (usa tile.chartType como modo) |
kpi | Un único número grande de la medida del mosaico |
filter | Omitido — los widgets de filtro son solo workbench en v1 |
| otros | Marcador “Unsupported tile” |
Embed público anónimo
Cuando el recurso tiene una concesión pública, omita el token:
<saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" path="shared/public.saiku" render="chart" mode="pie"></saiku-embed>Dentro de React
import "@concepttocloud/saiku-embed";
export function SalesEmbed({ token }: { token: string }) { return ( <saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" token={token} path="homes/admin/Examples/Sales.saiku" render="chart" mode="line" height="500px" /> );}Dentro de Vue
<template> <saiku-embed server="https://YOUR-WORKSPACE.saiku.bi" :token="token" path="homes/admin/Examples/Sales.saiku" render="chart" /></template>
<script setup lang="ts">import "@concepttocloud/saiku-embed";defineProps<{ token: string }>();</script>Temas
El embed se renderiza dentro de un
shadow root abierto,
por lo que el CSS de la página host no puede filtrarse hacia dentro y
el CSS del embed no puede filtrarse hacia fuera. Para recolorear,
defina variables CSS en el selector saiku-embed de la página host:
saiku-embed { --saiku-embed-fg: #0f172a; --saiku-embed-bg: transparent; --saiku-embed-border: #cbd5e1; --saiku-embed-header-bg: #f1f5f9; --saiku-embed-tile-bg: #ffffff; --saiku-embed-row-hover: #e2e8f0; --saiku-embed-negative: #b91c1c; --saiku-embed-error: #b91c1c; --saiku-embed-muted: #64748b;}El modo oscuro es solo una media query que cambia las mismas variables:
@media (prefers-color-scheme: dark) { saiku-embed { --saiku-embed-fg: #f1f5f9; --saiku-embed-bg: #0f172a; --saiku-embed-border: #334155; --saiku-embed-header-bg: #1e293b; --saiku-embed-tile-bg: #1e293b; --saiku-embed-row-hover: #334155; }}Modelo de seguridad
La superficie de embed está diseñada para páginas host hostiles — su consulta guardada podría acabar en un sitio de terceros que usted no controla. Los valores por defecto lo reflejan.
Los tokens son opacos, autoritativos en el servidor y revocables
- Los tokens son IDs aleatorios de 256 bits, codificados en Base64-URL — no se pueden adivinar.
- No llevan claims incrustados: el servidor conserva el registro autoritativo (tipo y ruta del recurso, snapshot del propietario, expiración, indicador de revocado) y lo consulta en cada petición. La revocación surte efecto en la próxima petición — no hay un “espere a que expire la firma” estilo JWT.
- Cada token fija exactamente un recurso. Reproducir un token
contra cualquier otro recurso (ruta incorrecta, tipo incorrecto,
expirado, revocado) devuelve el mismo
EMBED_INVALID401 opaco — las sondas no pueden enumerar.
Transporte solo por encabezado
El token viaja en el encabezado HTTP X-Saiku-Embed-Token.
Deliberadamente no aceptamos parámetros de query ?token=… porque
los parámetros de URL se filtran a:
- logs de acceso del servlet
- logs del proxy frontal
- historial del navegador
- el encabezado
Refererenviado en cada recurso saliente de la página host
El JS empaquetado lee el token del atributo
<saiku-embed token="…"> y lo envía como encabezado en cada fetch.
Aislamiento de cookies cross-origin
El embed hace fetch con credentials: "omit". Si el usuario de la
página host está logueado en Saiku en otra pestaña, esa cookie de
sesión no fluye con las lecturas del embed. El token ES el único
portador de auth en esta superficie.
Ámbito de datos del propietario
Tanto los tokens como las concesiones públicas capturan la lista de
roles del propietario en el momento de generar / conceder y ejecutan
la consulta del embed bajo esa identidad mediante
sessionService.runAs. Una consulta incrustada públicamente que usa
filtros inyectados por sesión se renderiza contra la perspectiva del
otorgante, no contra el (vacío) valor por defecto anónimo — lo que
autorizó al conceder es exactamente lo que ve el público.
Encabezados de respuesta de defensa en profundidad
Toda respuesta de embed lleva:
X-Content-Type-Options: nosniff— los navegadores no deben hacer MIME-sniff de un cuerpo JSON (que podría contener HTML de mosaico de texto o leyendas de miembros) y ejecutarlo como HTMLReferrer-Policy: no-referrer— nunca filtrar el token medianteRefereren recursos salientesCache-Control: no-store, max-age=0— los datos de negocio incrustados nunca se cachean en proxies ni en el historial del navegador
Errores amigables
Cuando un fetch falla (token expirado, token revocado, ruta
incorrecta, falta concesión pública), la página host ve un mensaje
genérico “This embed is unavailable.” — no el cuerpo crudo
EMBED_INVALID. La página host es un tercero y no necesita saber si
el fallo fue un token expirado o una revocación.
Tamaño del bundle
Alrededor de 213 KB en gzip en el momento de escribir esto — runtime de custom element de Svelte 5 + ECharts (core + bar / line / pie + cuatro componentes comunes, con tree-shake modular) + los renderizadores del embed. El bundle se cachea de forma agresiva en el navegador; el segundo embed en el mismo origen lo obtiene al instante.
Limitaciones
- Solo formato records. El formato de cellset matrix no se renderiza en v1.
- Los mosaicos de filtro se omiten en los dashboards. El embed renderiza los datos creados tal cual sin una barra de filtros interactiva.
- Markdown en mosaicos de texto se renderiza como texto plano. No
empaquetamos
markedpara mantener el tamaño bajo. - Los resultados AI Query (
/ai/query) aún no están conectados como fuente de embed. Sígalo ensaiku— un PR de seguimiento añadirákind="ai".
Véase también
- Autenticación — generar API keys para acceso programático a Saiku Cloud (diferente de los tokens de embed)
- MCP — conectar LLMs a sus cubos