SDK de React
@concepttocloud/saiku-embed-react es un envoltorio tipado de React
alrededor del elemento personalizado existente
<saiku-embed>. El elemento ya funciona en React —
React 18+ reenvía atributos desconocidos directamente al DOM — pero los
equipos React evalúan contra npm install + imports tipados, no
etiquetas <script>. Este SDK cierra esa brecha sin cambiar el runtime
subyacente.
Se entrega en saiku v4.7 como saiku#1432.
Instalar
npm install @concepttocloud/saiku-embed-react reactEl paquete tiene una peer-dependency de React 18+. El base
@concepttocloud/saiku-embed es una dependencia de runtime y se trae
automáticamente.
Uso
import { SaikuEmbed } from "@concepttocloud/saiku-embed-react";
function Dashboard({ token }: { token: string }) { return ( <SaikuEmbed server="https://YOUR-WORKSPACE.saiku.bi" token={token} path="homes/admin/Sales.saiku" render="chart" mode="bar" height="480px" /> );}Importar el paquete tiene el efecto secundario de registrar el elemento
personalizado subyacente — no necesita un
import "@concepttocloud/saiku-embed" separado a menos que también quiera
la etiqueta disponible fuera del árbol de React.
Props
| Prop | Tipo | Por defecto | Notas |
|---|---|---|---|
server | string | opcional | Origen del launcher de Saiku. Omitir para embeds del mismo origen. |
path | string | requerido | Ruta de consulta / ruta de dashboard / ref de cubo según kind. |
kind | "query" | "dashboard" | "ai" | "query" | Selecciona el sabor del embed. |
token | string | opcional | Token de embed acuñado en el servidor. Omitir para grants públicos. |
render | "table" | "matrix" | "chart" | "table" | Solo significativo para kind="query". |
mode | "bar" | "line" | "pie" | "bar" | Solo significativo para render="chart". |
height | string | "400px" | Altura CSS de la superficie renderizada. |
style | React.CSSProperties | opcional | Prop de estilo estándar de React. |
className | string | opcional | Prop className estándar de React. |
id | string | opcional | Trasladado para selectores e2e. |
data-testid | string | opcional | Trasladado al nodo del DOM. |
Las declaraciones de tipo completas se entregan en el index.d.ts del
paquete.
Kinds
Consulta guardada como tabla
<SaikuEmbed server="https://saiku.example.com" token={token} path="homes/admin/Sales.saiku" height="400px"/>Gráfico
<SaikuEmbed server="https://saiku.example.com" token={token} path="homes/admin/Sales.saiku" render="chart" mode="bar" height="500px"/>Matrix
El modo matrix preserva la estructura del eje de fila / columna —
medidas en columnas, miembros de dimensión en filas — en lugar de
aplanar a un único mapa de clave-fila como hace render="table". Útil
para informes estilo pivote.
<SaikuEmbed server="https://saiku.example.com" token={token} path="homes/admin/Sales.saiku" render="matrix" height="500px"/>Widget de ask de IA
Apunte el token a un cubo (en lugar de a una consulta guardada) y coloque una caja de ask en inglés llano. Requiere un token de embed de tipo AI y un launcher con un proveedor LLM configurado.
<SaikuEmbed server="https://saiku.example.com" token={aiToken} kind="ai" path="foodmart/FoodMart/FoodMart/Sales" height="240px"/>Dashboard guardado
<SaikuEmbed server="https://saiku.example.com" token={token} kind="dashboard" path="homes/admin/exec.saikudash" height="700px"/>Embed público anónimo
Si el recurso está marcado como públicamente incrustable en el servidor (vea Embeds públicos), omita el token por completo:
<SaikuEmbed server="https://saiku.example.com" path="shared/public-chart.saiku" render="chart"/>Acuñar un token desde su servidor
mintEmbedToken() es un helper de Node / edge-function para el caso muy
común de acuñar un token de embed en nombre de un usuario final antes de
renderizar <SaikuEmbed>.
import { mintEmbedToken } from "@concepttocloud/saiku-embed-react";
export async function POST(request: Request) { const auth = "Basic " + Buffer.from( `${process.env.SAIKU_USER}:${process.env.SAIKU_PASS}`, ).toString("base64");
const { token, expiresAt } = await mintEmbedToken({ server: process.env.SAIKU_URL!, authorization: auth, resourceKind: "query", resourcePath: "homes/admin/Sales.saiku", ttlHours: 24, label: "Public marketing page", });
return Response.json({ token, expiresAt });}import { mintEmbedToken } from "@concepttocloud/saiku-embed-react";
export async function loader() { const auth = "Basic " + Buffer.from( `${process.env.SAIKU_USER}:${process.env.SAIKU_PASS}`, ).toString("base64");
const { token } = await mintEmbedToken({ server: process.env.SAIKU_URL!, authorization: auth, resourceKind: "query", resourcePath: "homes/admin/Sales.saiku", });
return { token };}import { mintEmbedToken } from "@concepttocloud/saiku-embed-react";
export default { async fetch(request: Request, env: Env) { const auth = "Basic " + btoa(`${env.SAIKU_USER}:${env.SAIKU_PASS}`); const { token } = await mintEmbedToken({ server: env.SAIKU_URL, authorization: auth, resourceKind: "query", resourcePath: "homes/admin/Sales.saiku", fetch: fetch.bind(globalThis), }); return Response.json({ token }); },};En el lado del cliente el token aterriza en la prop token:
"use client";import useSWR from "swr";import { SaikuEmbed } from "@concepttocloud/saiku-embed-react";
export default function EmbedTile() { const { data } = useSWR("/api/embed-token", (u) => fetch(u, { method: "POST" }).then((r) => r.json())); if (!data?.token) return <div>Loading…</div>; return <SaikuEmbed server="…" token={data.token} path="homes/admin/Sales.saiku" />;}Opciones de mintEmbedToken
| Opción | Tipo | Notas |
|---|---|---|
server | string | URL base del launcher. |
authorization | string | Valor para la cabecera Authorization (Basic … o Bearer …). |
resourceKind | "query" | "dashboard" | "ai" | Tipo de recurso que el token fija. |
resourcePath | string | Ruta (para query/dashboard) o ref de cubo (para ai). |
ttlHours | number (opcional) | Tiempo de vida del token; el por defecto del servidor es 72h. |
label | string (opcional) | Etiqueta humana que la UI de admin muestra junto al token. |
fetch | typeof fetch (opcional) | Sobrescribible para tests + runtimes no de navegador (p. ej. Cloudflare Workers). |
Devuelve { token, expiresAt }. Lanza si el servidor devuelve un no-2xx
o el cuerpo de la respuesta no es un sobre de token.
Autocompletado en la etiqueta cruda
El paquete aumenta tanto el global JSX.IntrinsicElements
(React 17/18) como React.JSX.IntrinsicElements (React 19+) para que el
elemento personalizado crudo obtenga el mismo conjunto de props tipadas
que <SaikuEmbed>. Use la que prefiera:
// Typed React component<SaikuEmbed server="…" token={token} path="…" render="chart" />
// Or the raw custom element (also typed)<saiku-embed server="…" token={token} path="…" render="chart" />Theming
El embed vive dentro de un shadow root, así que el CSS de la página anfitriona no puede filtrarse. Recoloree mediante propiedades CSS personalizadas en el envoltorio:
<SaikuEmbed server="…" token={token} path="…" style={{ "--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", } as React.CSSProperties}/>La lista completa de variables personalizables está en la página del embed base.
Fijado de versión
La versión del SDK de React sigue la release base de
@concepttocloud/saiku-embed uno a uno. El 3.19.0 del SDK usa el
3.19.0 del runtime base — la dependencia de runtime se fija en tiempo
de release para que un consumidor nunca pueda mezclar accidentalmente
majors entre los dos.
Tamaño del bundle
- Envoltorio: ~1 KB gzipped (todo el runtime es una única llamada a
React.createElement). - Elemento personalizado base: ~213 KB gzipped (runtime CE de Svelte 5 + ECharts + los renderizadores del embed).
- React: peer dep — no contabilizado contra ninguno de los paquetes.
No-objetivos para v1
- Hooks de React para resultados de consulta (
useSaikuQuery) — el elemento personalizado maneja su propio estado; un hook de datos tipado duplica la superficie de la API AI Query. Seguimiento si alguien lo pide. - Variante de componente de servidor —
<SaikuEmbed>es solo de navegador (renderiza un shadow root). Los datos iniciales renderizados en servidor para hidratación son un seguimiento si el patrón resulta doloroso. - División de bundle por kind — el envoltorio actual siempre trae el bundle base completo. El tree-shaking por kind es un cambio del paquete base, no del envoltorio.