SDK React
@concepttocloud/saiku-embed-react est un wrapper React typé autour
de l’élément personnalisé <saiku-embed> existant.
L’élément fonctionne déjà dans React — React 18+ transmet les attributs
inconnus directement au DOM — mais les équipes React évaluent à partir de
npm install + imports typés, pas de balises <script>. Ce SDK comble cet
écart sans changer le runtime sous-jacent.
Livré dans saiku v4.7 comme saiku#1432.
Installation
npm install @concepttocloud/saiku-embed-react reactLe paquet a une peer-dependency sur React 18+. Le paquet de base
@concepttocloud/saiku-embed est une dépendance runtime et est tiré
automatiquement.
Utilisation
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" /> );}Importer le paquet a pour effet de bord d’enregistrer l’élément
personnalisé sous-jacent — vous n’avez pas besoin d’un
import "@concepttocloud/saiku-embed" séparé sauf si vous voulez aussi
que la balise soit disponible en dehors de l’arbre React.
Props
| Prop | Type | Défaut | Notes |
|---|---|---|---|
server | string | optionnel | Origine du launcher Saiku. À omettre pour les embeds same-origin. |
path | string | requis | Chemin de requête / chemin de dashboard / référence de cube selon kind. |
kind | "query" | "dashboard" | "ai" | "query" | Sélectionne la variante d’embed. |
token | string | optionnel | Token d’embed frappé côté serveur. À omettre pour les autorisations publiques. |
render | "table" | "matrix" | "chart" | "table" | Significatif uniquement pour kind="query". |
mode | "bar" | "line" | "pie" | "bar" | Significatif uniquement pour render="chart". |
height | string | "400px" | Hauteur CSS de la surface rendue. |
style | React.CSSProperties | optionnel | Prop style React standard. |
className | string | optionnel | Prop className React standard. |
id | string | optionnel | Transmise pour les sélecteurs e2e. |
data-testid | string | optionnel | Transmise au nœud du DOM. |
Les déclarations de types complètes sont livrées dans l’index.d.ts du
paquet.
Kinds
Requête sauvegardée sous forme de table
<SaikuEmbed server="https://saiku.example.com" token={token} path="homes/admin/Sales.saiku" height="400px"/>Graphique
<SaikuEmbed server="https://saiku.example.com" token={token} path="homes/admin/Sales.saiku" render="chart" mode="bar" height="500px"/>Matrice
Le mode matrice préserve la structure d’axes lignes / colonnes — mesures
sur les colonnes, membres de dimension sur les lignes — au lieu d’aplatir
vers une seule map de clés de ligne comme le fait render="table". Utile
pour les rapports de style pivot.
<SaikuEmbed server="https://saiku.example.com" token={token} path="homes/admin/Sales.saiku" render="matrix" height="500px"/>Widget AI ask
Pointez le token vers un cube (plutôt que vers une requête sauvegardée) et insérez une zone de question en langage naturel. Nécessite un token d’embed de type AI et un launcher avec un fournisseur LLM configuré.
<SaikuEmbed server="https://saiku.example.com" token={aiToken} kind="ai" path="foodmart/FoodMart/FoodMart/Sales" height="240px"/>Dashboard sauvegardé
<SaikuEmbed server="https://saiku.example.com" token={token} kind="dashboard" path="homes/admin/exec.saikudash" height="700px"/>Embed public anonyme
Si la ressource est marquée comme publiquement embarquable sur le serveur (voir Embeds publics), omettez le token entièrement :
<SaikuEmbed server="https://saiku.example.com" path="shared/public-chart.saiku" render="chart"/>Frapper un token depuis votre serveur
mintEmbedToken() est un helper Node / edge-function pour le cas très
courant de la frappe d’un token d’embed au nom d’un utilisateur final avant
le rendu de <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 }); },};Côté client, le token atterrit dans 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" />;}Options de mintEmbedToken
| Option | Type | Notes |
|---|---|---|
server | string | URL de base du launcher. |
authorization | string | Valeur pour l’en-tête Authorization (Basic … ou Bearer …). |
resourceKind | "query" | "dashboard" | "ai" | Type de ressource que le token épingle. |
resourcePath | string | Chemin (pour query/dashboard) ou référence de cube (pour ai). |
ttlHours | number (optionnel) | Durée de vie du token ; le défaut serveur est 72h. |
label | string (optionnel) | Libellé lisible que l’UI admin affiche à côté du token. |
fetch | typeof fetch (optionnel) | Surchargeable pour les tests + runtimes non navigateurs (par ex. Cloudflare Workers). |
Retourne { token, expiresAt }. Lève une exception si le serveur retourne
un code non-2xx ou si le corps de la réponse n’est pas une enveloppe de
token.
Autocomplétion sur la balise brute
Le paquet augmente à la fois le JSX.IntrinsicElements global
(React 17/18) et React.JSX.IntrinsicElements (React 19+) pour que
l’élément personnalisé brut obtienne le même jeu de props typées que
<SaikuEmbed>. Utilisez celui que vous préférez :
// 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" />Thématisation
L’embed vit à l’intérieur d’un shadow root, donc le CSS de la page hôte ne peut pas s’y infiltrer. Recolorez via des propriétés CSS personnalisées sur le wrapper :
<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 liste complète des variables thématisables est sur la page de l’embed de base.
Épinglage de version
La version du SDK React suit la release du paquet de base
@concepttocloud/saiku-embed un pour un. La 3.19.0 du SDK utilise la
3.19.0 du runtime de base — la dépendance runtime est épinglée au moment
de la release pour qu’un consommateur ne puisse jamais accidentellement
mélanger des versions majeures entre les deux.
Taille du bundle
- Wrapper : ~1 Ko gzippé (tout le runtime est un seul appel
React.createElement). - Élément personnalisé de base : ~213 Ko gzippé (runtime Svelte 5 CE + ECharts + les renderers d’embed).
- React : peer dep — non comptée contre l’un ou l’autre paquet.
Non-objectifs pour la v1
- Hooks React pour les résultats de requête (
useSaikuQuery) — l’élément personnalisé gère son propre état ; un hook de données typé duplique la surface de l’AI Query API. Suivi si quelqu’un le demande. - Variante server-component —
<SaikuEmbed>est réservé au navigateur (il rend un shadow root). Les données initiales rendues côté serveur pour l’hydratation sont un suivi si le pattern se révèle pénible. - Découpage de bundle par kind — le wrapper actuel tire toujours le bundle de base complet. Le tree-shaking par kind est un changement du paquet de base, pas du wrapper.