@malloydata/malloyyo 0.2.9 → 0.2.10
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/dist/index.js +52 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2262,7 +2262,8 @@ function makeBundler() {
|
|
|
2262
2262
|
};
|
|
2263
2263
|
}
|
|
2264
2264
|
var html = (body, title) => `<!doctype html><html><head><meta charset="utf-8"><title>${title}</title><meta name="viewport" content="width=device-width,initial-scale=1"></head><body style="margin:0">${body}</body></html>`;
|
|
2265
|
-
function parentShell(dash, frameBase, all) {
|
|
2265
|
+
function parentShell(dash, frameBase, all, initialGivens) {
|
|
2266
|
+
const givensQs = Object.entries(initialGivens).map(([k, v]) => `&${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("");
|
|
2266
2267
|
const d = JSON.stringify(dash.name);
|
|
2267
2268
|
const fb = JSON.stringify(frameBase);
|
|
2268
2269
|
const nav = all.length > 1 ? `<nav style="display:flex;gap:4px;align-items:center;padding:8px 12px;background:#f6f7f9;border-bottom:1px solid #e2e4e8;font:13px system-ui,sans-serif"><span style="color:#888;margin-right:8px">Dashboards</span>` + all.map((x) => {
|
|
@@ -2270,11 +2271,20 @@ function parentShell(dash, frameBase, all) {
|
|
|
2270
2271
|
return `<a href="/?d=${encodeURIComponent(x.name)}" style="padding:4px 10px;border-radius:6px;text-decoration:none;${on ? "background:#1a1a1a;color:#fff" : "color:#333"}">${esc(x.manifest.title || x.name)}</a>`;
|
|
2271
2272
|
}).join("") + `</nav>` : "";
|
|
2272
2273
|
return html(
|
|
2273
|
-
`<div style="display:flex;flex-direction:column;height:100vh">` + nav + `<iframe id="f" sandbox="allow-scripts allow-same-origin" src="${frameBase}/frame?d=${encodeURIComponent(dash.name)}" style="border:0;flex:1;width:100%"></iframe></div><script>
|
|
2274
|
+
`<div style="display:flex;flex-direction:column;height:100vh">` + nav + `<iframe id="f" sandbox="allow-scripts allow-same-origin" src="${frameBase}/frame?d=${encodeURIComponent(dash.name)}${givensQs}" style="border:0;flex:1;width:100%"></iframe></div><script>
|
|
2274
2275
|
const f=document.getElementById('f');
|
|
2276
|
+
try{new EventSource('/events').onmessage=()=>location.reload();}catch(e){}
|
|
2275
2277
|
window.addEventListener('message',async(e)=>{
|
|
2276
2278
|
if(e.source!==f.contentWindow||e.origin!==${fb})return;
|
|
2277
|
-
const m=e.data;
|
|
2279
|
+
const m=e.data;
|
|
2280
|
+
if(m&&m.type==='givens'){
|
|
2281
|
+
const u=new URL(location.href); u.search='';
|
|
2282
|
+
u.searchParams.set('d',${d});
|
|
2283
|
+
for(const [k,v] of Object.entries(m.givens)) u.searchParams.set(k,String(v));
|
|
2284
|
+
history.replaceState(null,'',u.pathname+u.search);
|
|
2285
|
+
return;
|
|
2286
|
+
}
|
|
2287
|
+
if(!m||m.type!=='run')return;
|
|
2278
2288
|
let out;
|
|
2279
2289
|
try{
|
|
2280
2290
|
const res=await fetch('/api/run',{method:'POST',headers:{'content-type':'application/json'},
|
|
@@ -2287,9 +2297,14 @@ window.addEventListener('message',async(e)=>{
|
|
|
2287
2297
|
dash.manifest.title
|
|
2288
2298
|
);
|
|
2289
2299
|
}
|
|
2290
|
-
function
|
|
2300
|
+
function givensFromUrl(url4) {
|
|
2301
|
+
const g = {};
|
|
2302
|
+
for (const [k, v] of url4.searchParams) if (k !== "d") g[k] = v;
|
|
2303
|
+
return g;
|
|
2304
|
+
}
|
|
2305
|
+
function frameDoc(dash, initialGivens) {
|
|
2291
2306
|
return html(
|
|
2292
|
-
`<div id="root"></div><script>window.__MANIFEST__=${JSON.stringify(dash.manifest)}</script><script src="/bundle.js?d=${encodeURIComponent(dash.name)}"></script>`,
|
|
2307
|
+
`<div id="root"></div><script>window.__MANIFEST__=${JSON.stringify(dash.manifest)};window.__INITIAL_GIVENS__=${JSON.stringify(initialGivens)}</script><script src="/bundle.js?d=${encodeURIComponent(dash.name)}"></script>`,
|
|
2293
2308
|
dash.manifest.title
|
|
2294
2309
|
);
|
|
2295
2310
|
}
|
|
@@ -2304,17 +2319,37 @@ async function serveDashboard(opts) {
|
|
|
2304
2319
|
const port = opts.port ?? 4173;
|
|
2305
2320
|
const framePort = port + 1;
|
|
2306
2321
|
const frameBase = `http://localhost:${framePort}`;
|
|
2307
|
-
|
|
2322
|
+
let dashboards = discoverDashboards(root);
|
|
2308
2323
|
if (dashboards.length === 0) {
|
|
2309
2324
|
throw new Error(`No dashboards found under ${path4.join(root, "dashboards")}/`);
|
|
2310
2325
|
}
|
|
2311
|
-
|
|
2326
|
+
let byName = new Map(dashboards.map((d) => [d.name, d]));
|
|
2312
2327
|
const runner = await makeRunner(root);
|
|
2313
2328
|
if (!runner.entryExists()) {
|
|
2314
2329
|
throw new Error(`No index.malloy at ${root} \u2014 run this from a Malloy model repo.`);
|
|
2315
2330
|
}
|
|
2316
2331
|
const bundle = makeBundler();
|
|
2317
2332
|
const pick = (url4) => byName.get(url4.searchParams.get("d") ?? dashboards[0].name) ?? dashboards[0];
|
|
2333
|
+
const sseClients = /* @__PURE__ */ new Set();
|
|
2334
|
+
const notifyReload = () => {
|
|
2335
|
+
for (const c of sseClients) c.write("data: reload\n\n");
|
|
2336
|
+
};
|
|
2337
|
+
let debounce;
|
|
2338
|
+
try {
|
|
2339
|
+
fs3.watch(root, { recursive: true }, (_evt, filename) => {
|
|
2340
|
+
const f = filename?.toString() ?? "";
|
|
2341
|
+
if (!f.endsWith(".malloy") && !f.includes("dashboards")) return;
|
|
2342
|
+
clearTimeout(debounce);
|
|
2343
|
+
debounce = setTimeout(() => {
|
|
2344
|
+
dashboards = discoverDashboards(root);
|
|
2345
|
+
byName = new Map(dashboards.map((d) => [d.name, d]));
|
|
2346
|
+
console.error(` \u21BB ${f} changed \u2014 reloading`);
|
|
2347
|
+
notifyReload();
|
|
2348
|
+
}, 150);
|
|
2349
|
+
});
|
|
2350
|
+
} catch (e) {
|
|
2351
|
+
console.error(` (file watch unavailable: ${e.message} \u2014 edits won't auto-reload)`);
|
|
2352
|
+
}
|
|
2318
2353
|
const handler = async (req, res) => {
|
|
2319
2354
|
const onFramePort = (req.socket.localPort ?? port) === framePort;
|
|
2320
2355
|
const url4 = new URL(req.url ?? "/", `http://localhost:${onFramePort ? framePort : port}`);
|
|
@@ -2325,15 +2360,22 @@ async function serveDashboard(opts) {
|
|
|
2325
2360
|
try {
|
|
2326
2361
|
if (onFramePort) {
|
|
2327
2362
|
if (url4.pathname === "/frame") {
|
|
2328
|
-
return send(200, "text/html; charset=utf-8", frameDoc(pick(url4)));
|
|
2363
|
+
return send(200, "text/html; charset=utf-8", frameDoc(pick(url4), givensFromUrl(url4)));
|
|
2329
2364
|
}
|
|
2330
2365
|
if (url4.pathname === "/bundle.js") {
|
|
2331
2366
|
return send(200, "application/javascript; charset=utf-8", await bundle(pick(url4)));
|
|
2332
2367
|
}
|
|
2333
2368
|
return send(404, "text/plain", "not found");
|
|
2334
2369
|
}
|
|
2370
|
+
if (url4.pathname === "/events") {
|
|
2371
|
+
res.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache", connection: "keep-alive" });
|
|
2372
|
+
res.write("retry: 1000\n\n");
|
|
2373
|
+
sseClients.add(res);
|
|
2374
|
+
req.on("close", () => sseClients.delete(res));
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
2335
2377
|
if (url4.pathname === "/") {
|
|
2336
|
-
return send(200, "text/html; charset=utf-8", parentShell(pick(url4), frameBase, dashboards));
|
|
2378
|
+
return send(200, "text/html; charset=utf-8", parentShell(pick(url4), frameBase, dashboards, givensFromUrl(url4)));
|
|
2337
2379
|
}
|
|
2338
2380
|
if (url4.pathname === "/api/run" && req.method === "POST") {
|
|
2339
2381
|
const { d, query, givens } = JSON.parse(await readBody(req));
|
|
@@ -2367,7 +2409,7 @@ async function serveDashboard(opts) {
|
|
|
2367
2409
|
}
|
|
2368
2410
|
|
|
2369
2411
|
// package.json
|
|
2370
|
-
var version = "0.2.
|
|
2412
|
+
var version = "0.2.10";
|
|
2371
2413
|
|
|
2372
2414
|
// src/index.ts
|
|
2373
2415
|
function shortSha(sha) {
|