@concepttocloud/saiku-embed 3.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -0
- package/package.json +31 -0
- package/saiku-embed.js +82 -0
- package/saiku-embed.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# `<saiku-embed>` — Saiku Web Component
|
|
2
|
+
|
|
3
|
+
Drop a saved Saiku query or dashboard into any page on the open web. Same
|
|
4
|
+
tag works in React, Vue, Svelte, and vanilla HTML — it's a real
|
|
5
|
+
[Custom Element](https://developer.mozilla.org/docs/Web/API/Web_components),
|
|
6
|
+
so the host page doesn't have to know anything about Saiku internals.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<script src="https://YOUR-SAIKU.example.com/ui/saiku-embed.js"></script>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or via npm (for React / Vue / SPA projects that bundle their own JS):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @concepttocloud/saiku-embed
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import "@concepttocloud/saiku-embed";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The import has the side effect of registering the `saiku-embed` tag
|
|
25
|
+
globally — no further setup.
|
|
26
|
+
|
|
27
|
+
## Use
|
|
28
|
+
|
|
29
|
+
### A saved query, rendered as a table
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<saiku-embed
|
|
33
|
+
server="https://YOUR-SAIKU.example.com"
|
|
34
|
+
token="..."
|
|
35
|
+
path="homes/admin/Examples/Trend.saiku"
|
|
36
|
+
height="400px"
|
|
37
|
+
></saiku-embed>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### A saved query, rendered as a bar / line / pie chart
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<saiku-embed
|
|
44
|
+
server="..."
|
|
45
|
+
token="..."
|
|
46
|
+
path="homes/admin/Examples/Sales.saiku"
|
|
47
|
+
render="chart"
|
|
48
|
+
mode="bar"
|
|
49
|
+
height="500px"
|
|
50
|
+
></saiku-embed>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### A saved dashboard
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<saiku-embed
|
|
57
|
+
server="..."
|
|
58
|
+
token="..."
|
|
59
|
+
kind="dashboard"
|
|
60
|
+
path="homes/admin/exec.saikudash"
|
|
61
|
+
height="700px"
|
|
62
|
+
></saiku-embed>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Anonymous public embed
|
|
66
|
+
|
|
67
|
+
If the resource is marked publicly embeddable on the server
|
|
68
|
+
(see "Public grants" below), omit the token entirely:
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<saiku-embed
|
|
72
|
+
server="..."
|
|
73
|
+
path="shared/public-chart.saiku"
|
|
74
|
+
render="chart"
|
|
75
|
+
></saiku-embed>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Attributes
|
|
79
|
+
|
|
80
|
+
| Attribute | Default | Notes |
|
|
81
|
+
|-----------|-------------|------------------------------------------------------------------------|
|
|
82
|
+
| `server` | _(required)_| Origin of the Saiku launcher, e.g. `https://demo.saiku.bi` |
|
|
83
|
+
| `path` | _(required)_| Repository path of the saved query (`.saiku`) or dashboard (`.saikudash`) |
|
|
84
|
+
| `kind` | `query` | `query` or `dashboard` |
|
|
85
|
+
| `token` | _(none)_ | Embed token from `POST /saiku/api/embed/tokens`. Omit for public reads |
|
|
86
|
+
| `render` | `table` | For `kind=query`: `table` or `chart` |
|
|
87
|
+
| `mode` | `bar` | For `render=chart`: `bar`, `line`, or `pie` |
|
|
88
|
+
| `height` | `400px` | CSS height of the rendered surface |
|
|
89
|
+
|
|
90
|
+
The component re-renders whenever an attribute changes, so frameworks
|
|
91
|
+
binding state to attrs (React's JSX, Vue's `:server="..."`, etc.) just
|
|
92
|
+
work.
|
|
93
|
+
|
|
94
|
+
## Server-side: minting a token
|
|
95
|
+
|
|
96
|
+
Authenticated as a user who has GRANT on the saved query / dashboard:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
curl -X POST 'https://YOUR-SAIKU/rest/saiku/api/embed/tokens' \
|
|
100
|
+
-u admin:admin \
|
|
101
|
+
-H 'Content-Type: application/json' \
|
|
102
|
+
-d '{
|
|
103
|
+
"resourceKind": "query",
|
|
104
|
+
"resourcePath": "homes/admin/Examples/Trend.saiku",
|
|
105
|
+
"ttlHours": 72,
|
|
106
|
+
"label": "Marketing landing page"
|
|
107
|
+
}'
|
|
108
|
+
# → { "status": "OK", "token": "tx-...", "expiresAt": ... }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Paste the `token` into the host page's `<saiku-embed token="...">`.
|
|
112
|
+
Tokens are server-authoritative — revoke any time via:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
curl -X DELETE 'https://YOUR-SAIKU/rest/saiku/api/embed/tokens/<token>' \
|
|
116
|
+
-u admin:admin
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Server-side: public grants
|
|
120
|
+
|
|
121
|
+
To make a resource readable WITHOUT a token (e.g. for a public blog post):
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
curl -X POST 'https://YOUR-SAIKU/rest/saiku/api/embed/public' \
|
|
125
|
+
-u admin:admin \
|
|
126
|
+
-H 'Content-Type: application/json' \
|
|
127
|
+
-d '{
|
|
128
|
+
"resourceKind": "query",
|
|
129
|
+
"resourcePath": "shared/public-chart.saiku",
|
|
130
|
+
"label": "Homepage chart"
|
|
131
|
+
}'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Public reads still run under the grantor's data scope, so any
|
|
135
|
+
session-injected filters render from the grantor's perspective.
|
|
136
|
+
Revoke:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
curl -X DELETE 'https://YOUR-SAIKU/rest/saiku/api/embed/public?kind=query&path=shared/public-chart.saiku' \
|
|
140
|
+
-u admin:admin
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Styling
|
|
144
|
+
|
|
145
|
+
The embed lives inside an
|
|
146
|
+
[open shadow root](https://developer.mozilla.org/docs/Web/API/ShadowRoot),
|
|
147
|
+
so host page CSS can't leak in and vice versa. To recolour the embed,
|
|
148
|
+
set CSS variables on the host page:
|
|
149
|
+
|
|
150
|
+
```css
|
|
151
|
+
saiku-embed {
|
|
152
|
+
--saiku-embed-fg: #0f172a;
|
|
153
|
+
--saiku-embed-bg: transparent;
|
|
154
|
+
--saiku-embed-border: #cbd5e1;
|
|
155
|
+
--saiku-embed-header-bg: #f1f5f9;
|
|
156
|
+
--saiku-embed-tile-bg: #ffffff;
|
|
157
|
+
--saiku-embed-row-hover: #e2e8f0;
|
|
158
|
+
--saiku-embed-negative: #b91c1c;
|
|
159
|
+
--saiku-embed-error: #b91c1c;
|
|
160
|
+
--saiku-embed-muted: #64748b;
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Security model
|
|
165
|
+
|
|
166
|
+
- **Header-only token transport.** The token travels as
|
|
167
|
+
`X-Saiku-Embed-Token`. Never a `?token=` query parameter — those leak
|
|
168
|
+
into access logs, proxy logs, browser history, and outbound
|
|
169
|
+
`Referer`.
|
|
170
|
+
- **Server-side authoritative.** Tokens are opaque random 256-bit ids
|
|
171
|
+
with no embedded claims; the server looks them up on every request.
|
|
172
|
+
Revocation takes effect on the very next request.
|
|
173
|
+
- **Per-resource scope.** A token pins exactly one query or dashboard.
|
|
174
|
+
Replaying it against any other resource (or any other endpoint)
|
|
175
|
+
returns the same opaque `EMBED_INVALID` 401, regardless of whether
|
|
176
|
+
the request used the wrong kind, the wrong path, an expired token,
|
|
177
|
+
or a revoked one. Probes can't enumerate.
|
|
178
|
+
- **Cross-origin cookie isolation.** The embed sends
|
|
179
|
+
`credentials: "omit"`, so the host page's Saiku session cookie (if
|
|
180
|
+
the user happens to be logged in) doesn't flow with embed reads.
|
|
181
|
+
The token IS the only auth carrier on this surface.
|
|
182
|
+
|
|
183
|
+
## Bundle size
|
|
184
|
+
|
|
185
|
+
Around **213 KB gzipped** at the time of writing — Svelte 5 custom
|
|
186
|
+
element runtime + ECharts (core + bar / line / pie + four common
|
|
187
|
+
components, modular tree-shaken) + the embed renderers.
|
|
188
|
+
|
|
189
|
+
## Limitations
|
|
190
|
+
|
|
191
|
+
- Records-format only. The matrix format isn't rendered in v1.
|
|
192
|
+
- Dashboard `filter` tiles are skipped — the embed renders the
|
|
193
|
+
authored data as-is without an interactive filter bar.
|
|
194
|
+
- Markdown in `text` tiles renders as plain text (no `marked`
|
|
195
|
+
dependency to keep the bundle tight).
|
|
196
|
+
- AI Query results (`/ai/query`) aren't wired as an `<saiku-embed>`
|
|
197
|
+
source yet — coming in a follow-up.
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@concepttocloud/saiku-embed",
|
|
3
|
+
"version": "3.18.2",
|
|
4
|
+
"description": "<saiku-embed> Web Component — drop a saved Saiku query or dashboard into any page.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./saiku-embed.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"saiku-embed.js",
|
|
10
|
+
"saiku-embed.js.map",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"saiku",
|
|
15
|
+
"olap",
|
|
16
|
+
"embed",
|
|
17
|
+
"web-component",
|
|
18
|
+
"custom-element",
|
|
19
|
+
"dashboard",
|
|
20
|
+
"chart"
|
|
21
|
+
],
|
|
22
|
+
"homepage": "https://github.com/spiculedata/saiku",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/spiculedata/saiku.git",
|
|
26
|
+
"directory": "saiku-ui/src/embed"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/spiculedata/saiku/issues"
|
|
30
|
+
}
|
|
31
|
+
}
|