Przejdź do głównej zawartości

Osadzanie Saiku

Komponent Web Component <saiku-embed/> pozwala osadzić zapisane zapytanie lub dashboard Saiku w dowolnej stronie HTML — na stronie marketingowej, w artykule blogowym, w portalu klienta, na wiki albo w dashboardzie React / Vue. Ten sam element niestandardowy działa w każdym hoście: React JSX, szablonach Vue, Svelte, czystym HTML.

To prawdziwy Web Component, a nie opakowanie frameworkowe, więc strona hostująca nie musi nic wiedzieć o wnętrznościach Saiku.

Instalacja

Dwa równoważne sposoby załadowania bundla. Wybierz ten, który pasuje do strony hostującej.

Bez kroku budowania — wskaż tagiem <script> bundle, który już serwuje Twoje Saiku:

<script src="https://YOUR-WORKSPACE.saiku.bi/ui/saiku-embed.js"></script>

Pobranie to około 213 KB po gzipie. Przeglądarki buforują go, więc druga strona na tym samym origin dostaje go natychmiast.

Działający przykład

Minimalny żywotny embed — zapisane zapytanie wyrenderowane jako tabela:

<saiku-embed
server="https://YOUR-WORKSPACE.saiku.bi"
token="tx-..."
path="homes/admin/Examples/Trend.saiku"
height="400px"
></saiku-embed>

Trzy nośne atrybuty to server (origin Twojego Saiku), path (ścieżka zasobu zapisanego zapytania w repozytorium) i token (token osadzania — zobacz Generowanie tokenu poniżej). Reszta ma sensowne wartości domyślne.

Generowanie tokenu

Tokeny generuje uwierzytelniony użytkownik, który ma prawo odczytu zasobu. Token jest nieprzezroczysty i wąsko zakresowany: daje dostęp tylko do odczytu jednego zapisanego zapytania lub dashboarda, wygasa po określonym przez Ciebie TTL i może zostać unieważniony w dowolnej chwili.

Wygeneruj token
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"
}'
# Odpowiedź:
# {
# "status": "OK",
# "token": "tx-...",
# "resourceKind": "query",
# "resourcePath": "homes/admin/Examples/Trend.saiku",
# "expiresAt": 1739102400000
# }

Wklej token do <saiku-embed token="..."> na stronie hostującej.

Granice TTL. Wartość domyślna to 72 godziny. Maksimum to 30 dni (720 godzin). Krótki TTL to najbezpieczniejsza wartość domyślna dla tokenu, który podróżuje przez arbitralne strony hostujące.

Limit na użytkownika. Każdy użytkownik może trzymać do 200 aktywnych tokenów jednocześnie. Unieważnij nieużywane tokeny, by zwolnić budżet.

Lista Twoich tokenów

Okno terminala
curl 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/tokens' \
-u admin:admin

Admini mogą wylistować wszystkie tokeny w systemie z ?all=true.

Unieważnienie tokenu

Okno terminala
curl -X DELETE 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/tokens/<token>' \
-u admin:admin

Unieważnienie wchodzi w życie przy najbliższym żądaniu — nie ma sesji gościa, którą można by porwać.

Publiczne (anonimowe) embedy

Jeśli zasób powinien być czytelny bez tokenu — publiczny wykres na stronie głównej, otwarty dashboard na blogu — przełącz go w tryb publicznego osadzania:

Okno terminala
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"
}'

Wtedy strona hostująca pomija token całkowicie:

<saiku-embed
server="https://YOUR-WORKSPACE.saiku.bi"
path="shared/public-chart.saiku"
render="chart"
></saiku-embed>

Lista i unieważnianie publicznych grantów

Okno terminala
# Lista Twoich publicznych grantów
curl 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/public' \
-u admin:admin
# Unieważnienie
curl -X DELETE 'https://YOUR-WORKSPACE.saiku.bi/rest/saiku/api/embed/public?kind=query&path=shared/public-chart.saiku' \
-u admin:admin

Referencja atrybutów

AtrybutDomyślnieUwagi
serverwymaganeOrigin Twojego launchera Saiku, np. https://YOUR-WORKSPACE.saiku.bi
pathwymaganeŚcieżka w repozytorium. Kończy się .saiku dla zapytań, .saikudash dla dashboardów
kindqueryquery lub dashboard
token(brak)Token osadzania z POST /saiku/api/embed/tokens. Pomiń dla anonimowych odczytów publicznych
rendertableDla kind="query": table lub chart
modebarDla render="chart": bar, line lub pie
height400pxWysokość CSS (min-height na renderowanej powierzchni)

Atrybuty są reaktywne — komponent ponownie się renderuje, kiedy którykolwiek z nich się zmieni. W React, Vue lub Svelte powiązanie stanu z tymi propsami działa bez żadnych zabiegów.

Przykłady

Zapisane zapytanie jako tabela

<saiku-embed
server="https://YOUR-WORKSPACE.saiku.bi"
token="tx-..."
path="homes/admin/Examples/Trend.saiku"
></saiku-embed>

Zapisane zapytanie jako wykres

<saiku-embed
server="https://YOUR-WORKSPACE.saiku.bi"
token="tx-..."
path="homes/admin/Examples/Sales.saiku"
render="chart"
mode="bar"
height="500px"
></saiku-embed>

Tryby wykresu:

  • bar (domyślny) — słupki kategorialne; pierwsza nie-liczbowa kolumna to kategoria, każda liczbowa kolumna staje się własną serią
  • line — ten sam układ, serie liniowe
  • pie — tylko pierwsza liczbowa kolumna; spada do „Brak serii liczbowych”, jeśli wynik jest wyłącznie tekstowy

Tooltipy pokazują sformatowane przez serwer napisy komórek ($1,234, 12.3% itd.), więc strona hostująca widzi te same podpisy, które pokazałby workbench Saiku.

Zapisany dashboard

<saiku-embed
server="https://YOUR-WORKSPACE.saiku.bi"
token="tx-..."
kind="dashboard"
path="homes/admin/exec.saikudash"
height="700px"
></saiku-embed>

Komponent pobiera układ dashboarda raz, a potem uruchamia jedno zapytanie na kafelek wykresu / KPI równolegle pod zakresem danych właściciela dashboarda. Typy kafelków w v1:

Typ kafelkaCo się renderuje
textTekst kafelka, jako akapit
chartWykres ECharts (używa tile.chartType jako trybu)
kpiJedna duża liczba z miary kafelka
filterPomijany — widżety filtrów są tylko w workbenchu w v1
innePlaceholder „Niewspierany kafelek”

Anonimowy publiczny embed

Gdy zasób ma publiczny grant, pomiń token:

<saiku-embed
server="https://YOUR-WORKSPACE.saiku.bi"
path="shared/public.saiku"
render="chart"
mode="pie"
></saiku-embed>

Wewnątrz 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"
/>
);
}

Wewnątrz 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>

Motywowanie

Embed renderuje się wewnątrz otwartego shadow root, więc CSS strony hostującej nie może wyciec do środka, a CSS embeda nie może wyciec na zewnątrz. Aby zmienić kolory, ustaw zmienne CSS na selektorze saiku-embed strony hostującej:

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;
}

Tryb ciemny to po prostu media query, które przełącza te same zmienne:

@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;
}
}

Model bezpieczeństwa

Powierzchnia osadzania jest zaprojektowana z myślą o wrogich stronach hostujących — Twoje zapisane zapytanie może wylądować na stronie trzeciej, której nie kontrolujesz. Wartości domyślne to odzwierciedlają.

Tokeny są nieprzezroczyste, autorytatywne po stronie serwera, unieważnialne

  • Tokeny to 256-bitowe losowe identyfikatory, kodowane Base64-URL — nie do odgadnięcia.
  • Nie niosą żadnych osadzonych claimów: serwer trzyma autorytatywny rekord (rodzaj i ścieżka zasobu, migawka właściciela, wygaśnięcie, flaga unieważnienia) i sprawdza go przy każdym żądaniu. Unieważnienie wchodzi w życie przy najbliższym żądaniu — bez czekania na wygaśnięcie podpisu w stylu JWT.
  • Każdy token przypina dokładnie jeden zasób. Odtworzenie tokenu na dowolnym innym zasobie (zła ścieżka, zły rodzaj, wygasły, unieważniony) zwraca ten sam nieprzezroczysty 401 EMBED_INVALID — sondy nie mogą się enumerować.

Transport tylko przez nagłówek

Token podróżuje jako nagłówek HTTP X-Saiku-Embed-Token. Celowo nie akceptujemy parametrów zapytania ?token=…, ponieważ parametry URL wyciekają do:

  • logów dostępu serwleta
  • logów proxy przed serwerem
  • historii przeglądarki
  • nagłówka Referer wysyłanego na każdy wychodzący asset na stronie hostującej

Bundlowany JS odczytuje token z atrybutu <saiku-embed token="…"> i wysyła go jako nagłówek na każdym fetchu.

Izolacja ciasteczek cross-origin

Embed pobiera z credentials: "omit". Jeśli użytkownik strony hostującej akurat jest zalogowany do Saiku w innej karcie, to ciasteczko sesyjne nie płynie z odczytami embeda. Tokenem JEST jedyny nośnik uwierzytelnienia na tej powierzchni.

Zakres danych właściciela

Zarówno tokeny, jak i publiczne granty zapisują migawkę listy ról właściciela w momencie wystawienia tokenu/grantu i uruchamiają zapytanie embeda pod tą tożsamością przez sessionService.runAs. Publicznie osadzone zapytanie używające filtrów wstrzykiwanych z sesji renderuje się z perspektywy udzielającego, a nie (pustego) anonimowego domyślnego — to, co autoryzowałeś w momencie grantu, to dokładnie to, co widzi publika.

Nagłówki odpowiedzi typu obrona w głąb

Każda odpowiedź embeda niesie:

  • X-Content-Type-Options: nosniff — przeglądarki nie mogą MIME-sniffować ciała JSON (które może nieść HTML kafelka tekstowego lub podpisy członków) i wykonywać go jako HTML
  • Referrer-Policy: no-referrer — nigdy nie ujawniaj tokenu przez Referer na wychodzących assetach
  • Cache-Control: no-store, max-age=0 — osadzone dane biznesowe nie są nigdy buforowane przez proxy ani historię przeglądarki

Przyjazne błędy

Gdy fetch zawiedzie (wygasły token, unieważniony token, zła ścieżka, brakujący publiczny grant), strona hostująca widzi ogólne „Ten embed jest niedostępny.” — a nie surowe ciało EMBED_INVALID. Strona hostująca to strona trzecia i nie musi wiedzieć, czy awaria to wygasły token czy unieważnienie.

Rozmiar bundla

Około 213 KB po gzipie w chwili pisania — runtime custom element Svelte 5 + ECharts (rdzeń + bar / line / pie + cztery typowe komponenty, modularnie tree-shaken) + renderery embeda. Bundle jest agresywnie buforowany przez przeglądarkę; drugi embed na tym samym origin dostaje go natychmiast.

Ograniczenia

  • Tylko format records. Format cellset matrix nie jest renderowany w v1.
  • Kafelki filtrów są pomijane na dashboardach. Embed renderuje autorskie dane jak są, bez interaktywnego paska filtrów.
  • Markdown w kafelkach tekstowych renderuje się jako zwykły tekst. Nie bundlujemy marked, by ograniczyć rozmiar.
  • Wyniki AI Query (/ai/query) nie są jeszcze podłączone jako źródło embeda. Śledź w saiku — kolejny PR doda kind="ai".

Zobacz też

  • Uwierzytelnianie — generowanie kluczy API do programistycznego dostępu Saiku Cloud (inne niż tokeny osadzania)
  • MCP — podłączanie LLM-ów do Twoich kostek