@definite-app/data-apps 1.0.0 → 1.0.1
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/package.json +1 -1
- package/runtime/definite-runtime.tsx +85 -8
package/package.json
CHANGED
|
@@ -8,10 +8,39 @@ type DatasetKind = "table" | "database";
|
|
|
8
8
|
type DataAppErrorSeverity = "warning" | "error" | "fatal";
|
|
9
9
|
type DataAppErrorPhase = "bridge" | "resolve" | "fetch" | "duckdb" | "perspective" | "render" | "uncaught";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Logged-in viewer. Null in publicMode (no authenticated session).
|
|
13
|
+
* Mirrors BridgeUser in wax/src/utils/fi/dataBridge.ts.
|
|
14
|
+
*/
|
|
15
|
+
export type DefiniteUser = {
|
|
16
|
+
id: string;
|
|
17
|
+
email: string;
|
|
18
|
+
role: "guest" | "viewer" | "analyst" | "admin" | "embedded_viewer" | null;
|
|
19
|
+
avatar: string | null;
|
|
20
|
+
createdAt: string | null;
|
|
21
|
+
updatedAt: string | null;
|
|
22
|
+
lastSignInAt: string | null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Active team. Null in publicMode.
|
|
27
|
+
* Mirrors BridgeTeam in wax/src/utils/fi/dataBridge.ts.
|
|
28
|
+
*/
|
|
29
|
+
export type DefiniteTeam = {
|
|
30
|
+
id: string;
|
|
31
|
+
domain: string;
|
|
32
|
+
plan: "trial" | "free" | "standard" | "enterprise" | null;
|
|
33
|
+
createdAt: string | null;
|
|
34
|
+
updatedAt: string | null;
|
|
35
|
+
trialEndAt: string | null;
|
|
36
|
+
};
|
|
37
|
+
|
|
11
38
|
type DefiniteContext = {
|
|
12
39
|
publicMode: boolean;
|
|
13
40
|
driveFile: string | null;
|
|
14
41
|
appVersion: "v1" | "v2";
|
|
42
|
+
user: DefiniteUser | null;
|
|
43
|
+
team: DefiniteTeam | null;
|
|
15
44
|
};
|
|
16
45
|
|
|
17
46
|
type ResourceCacheDetails = {
|
|
@@ -235,10 +264,15 @@ function getEmbeddedBridge(): DefiniteBridge | null {
|
|
|
235
264
|
return { ...resolved, kind: "json" };
|
|
236
265
|
},
|
|
237
266
|
async getContext() {
|
|
267
|
+
// Embedded mode resolves identity server-side via the Bearer token; the
|
|
268
|
+
// runtime doesn't have direct access to those fields, so we surface null
|
|
269
|
+
// until the embed endpoint widens its handshake.
|
|
238
270
|
return {
|
|
239
271
|
publicMode: false,
|
|
240
272
|
driveFile: ctx.driveFile,
|
|
241
273
|
appVersion: "v2",
|
|
274
|
+
user: null,
|
|
275
|
+
team: null,
|
|
242
276
|
} satisfies DefiniteContext;
|
|
243
277
|
},
|
|
244
278
|
reportError(error) {
|
|
@@ -486,6 +520,8 @@ function getPreviewBridge(): DefiniteBridge | null {
|
|
|
486
520
|
publicMode: false,
|
|
487
521
|
driveFile: "preview://data-apps-v2",
|
|
488
522
|
appVersion: "v2",
|
|
523
|
+
user: null,
|
|
524
|
+
team: null,
|
|
489
525
|
...(previewData.context ?? {}),
|
|
490
526
|
} satisfies DefiniteContext;
|
|
491
527
|
},
|
|
@@ -1383,6 +1419,36 @@ async function loadJsonResource<T>(
|
|
|
1383
1419
|
return { data: value, cache };
|
|
1384
1420
|
}
|
|
1385
1421
|
|
|
1422
|
+
// React hook for reading the host-injected viewer context. Returns null until
|
|
1423
|
+
// the bridge resolves; in the wax-injected case (the common path) this is
|
|
1424
|
+
// effectively synchronous because `window.Definite._context` is already set
|
|
1425
|
+
// when the iframe script runs, so the initial render already has a value.
|
|
1426
|
+
export function useDefiniteContext(): DefiniteContext | null {
|
|
1427
|
+
const [ctx, setCtx] = useState<DefiniteContext | null>(() => {
|
|
1428
|
+
// Synchronous fast path: wax injects `_context` into `window.Definite`
|
|
1429
|
+
// before any app code runs, so we can read it on first render.
|
|
1430
|
+
const injected = (window as unknown as { Definite?: { _context?: DefiniteContext } }).Definite?._context;
|
|
1431
|
+
return injected ?? null;
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
useEffect(() => {
|
|
1435
|
+
let cancelled = false;
|
|
1436
|
+
getBridge()
|
|
1437
|
+
.getContext()
|
|
1438
|
+
.then((next) => {
|
|
1439
|
+
if (!cancelled) setCtx(next);
|
|
1440
|
+
})
|
|
1441
|
+
.catch((err) => {
|
|
1442
|
+
console.error("[data-apps] useDefiniteContext: getContext() failed", err);
|
|
1443
|
+
});
|
|
1444
|
+
return () => {
|
|
1445
|
+
cancelled = true;
|
|
1446
|
+
};
|
|
1447
|
+
}, []);
|
|
1448
|
+
|
|
1449
|
+
return ctx;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1386
1452
|
export function useDataset(key: string, opts?: { mode?: DataAppMode }): DatasetHandle {
|
|
1387
1453
|
const mode = opts?.mode ?? "auto";
|
|
1388
1454
|
const [state, setState] = useState<DatasetHandle>({
|
|
@@ -3117,9 +3183,24 @@ export function EChart(props: {
|
|
|
3117
3183
|
const instanceRef = useRef<any>(null);
|
|
3118
3184
|
const onClickRef = useRef(props.onClick);
|
|
3119
3185
|
onClickRef.current = props.onClick;
|
|
3120
|
-
|
|
3186
|
+
// Change-detection key ONLY. JSON.stringify drops function values, so the
|
|
3187
|
+
// serialized string must never be parsed back into the object handed to
|
|
3188
|
+
// ECharts -- a JSON round-trip silently deletes every axisLabel/tooltip/
|
|
3189
|
+
// label `formatter` function, leaving only string-template formatters.
|
|
3190
|
+
const optionKey = useMemo(() => JSON.stringify(props.option), [props.option]);
|
|
3191
|
+
const optionRef = useRef(props.option);
|
|
3192
|
+
optionRef.current = props.option;
|
|
3121
3193
|
const echartsTheme = (props.theme ?? "dark") === "light" ? "light" : "dark";
|
|
3122
3194
|
|
|
3195
|
+
// Apply the live option object (functions intact) to an ECharts instance.
|
|
3196
|
+
const applyOption = (instance: any) => {
|
|
3197
|
+
const opt = optionRef.current;
|
|
3198
|
+
instance.setOption(
|
|
3199
|
+
opt.backgroundColor ? opt : { ...opt, backgroundColor: "transparent" },
|
|
3200
|
+
true,
|
|
3201
|
+
);
|
|
3202
|
+
};
|
|
3203
|
+
|
|
3123
3204
|
// Init / re-init on theme change
|
|
3124
3205
|
useEffect(() => {
|
|
3125
3206
|
const el = containerRef.current;
|
|
@@ -3134,9 +3215,7 @@ export function EChart(props: {
|
|
|
3134
3215
|
instanceRef.current = instance;
|
|
3135
3216
|
|
|
3136
3217
|
try {
|
|
3137
|
-
|
|
3138
|
-
if (!opt.backgroundColor) opt.backgroundColor = "transparent";
|
|
3139
|
-
instance.setOption(opt, true);
|
|
3218
|
+
applyOption(instance);
|
|
3140
3219
|
} catch (e) {
|
|
3141
3220
|
console.error("[EChart] setOption failed", e);
|
|
3142
3221
|
}
|
|
@@ -3159,13 +3238,11 @@ export function EChart(props: {
|
|
|
3159
3238
|
useEffect(() => {
|
|
3160
3239
|
if (!instanceRef.current) return;
|
|
3161
3240
|
try {
|
|
3162
|
-
|
|
3163
|
-
if (!opt.backgroundColor) opt.backgroundColor = "transparent";
|
|
3164
|
-
instanceRef.current.setOption(opt, true);
|
|
3241
|
+
applyOption(instanceRef.current);
|
|
3165
3242
|
} catch (e) {
|
|
3166
3243
|
console.error("[EChart] setOption update failed", e);
|
|
3167
3244
|
}
|
|
3168
|
-
}, [
|
|
3245
|
+
}, [optionKey]);
|
|
3169
3246
|
|
|
3170
3247
|
return (
|
|
3171
3248
|
<div
|