@scenetest/dashboard 0.11.0 → 0.12.0
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 +87 -35
- package/dist/app.d.ts +10 -7
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +12 -130
- package/dist/app.js.map +1 -1
- package/dist/collections/index.d.ts +19 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/collections/index.js +18 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/options.d.ts +29 -0
- package/dist/collections/options.d.ts.map +1 -0
- package/dist/collections/options.js +68 -0
- package/dist/collections/options.js.map +1 -0
- package/dist/collections/projections.d.ts +117 -0
- package/dist/collections/projections.d.ts.map +1 -0
- package/dist/collections/projections.js +228 -0
- package/dist/collections/projections.js.map +1 -0
- package/dist/collections/source.d.ts +32 -0
- package/dist/collections/source.d.ts.map +1 -0
- package/dist/collections/source.js +84 -0
- package/dist/collections/source.js.map +1 -0
- package/dist/collections/types.d.ts +87 -0
- package/dist/collections/types.d.ts.map +1 -0
- package/dist/collections/types.js +2 -0
- package/dist/collections/types.js.map +1 -0
- package/dist/dashboard.d.ts +20 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +114 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/dev-transport.d.ts +3 -3
- package/dist/dev-transport.d.ts.map +1 -1
- package/dist/dev-transport.js +3 -7
- package/dist/dev-transport.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/runner.d.ts +8 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +249 -0
- package/dist/runner.js.map +1 -0
- package/dist/select-helpers.d.ts +50 -0
- package/dist/select-helpers.d.ts.map +1 -0
- package/dist/select-helpers.js +48 -0
- package/dist/select-helpers.js.map +1 -0
- package/dist/select-runner.d.ts +55 -0
- package/dist/select-runner.d.ts.map +1 -0
- package/dist/select-runner.js +108 -0
- package/dist/select-runner.js.map +1 -0
- package/dist/select-waterfall.d.ts +12 -0
- package/dist/select-waterfall.d.ts.map +1 -0
- package/dist/select-waterfall.js +79 -0
- package/dist/select-waterfall.js.map +1 -0
- package/dist/style.css +878 -0
- package/dist/types.d.ts +6 -20
- package/dist/types.d.ts.map +1 -1
- package/dist/use-live-query.d.ts +28 -0
- package/dist/use-live-query.d.ts.map +1 -0
- package/dist/use-live-query.js +25 -0
- package/dist/use-live-query.js.map +1 -0
- package/dist/use-run-slice.d.ts +25 -0
- package/dist/use-run-slice.d.ts.map +1 -0
- package/dist/use-run-slice.js +48 -0
- package/dist/use-run-slice.js.map +1 -0
- package/package.json +10 -5
- package/dist/mount.d.ts +0 -14
- package/dist/mount.d.ts.map +0 -1
- package/dist/mount.js +0 -50
- package/dist/mount.js.map +0 -1
- package/dist/store.d.ts +0 -19
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -164
- package/dist/store.js.map +0 -1
- package/dist/styles.d.ts +0 -10
- package/dist/styles.d.ts.map +0 -1
- package/dist/styles.js +0 -152
- package/dist/styles.js.map +0 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useMemo } from 'preact/hooks';
|
|
3
|
+
import { createCollection } from '@tanstack/db';
|
|
4
|
+
import { createRunSource, runCollectionOptions, scenesProjection, assertionsProjection, actionsProjection, runsProjection, } from './collections/index.js';
|
|
5
|
+
import { Waterfall } from './app.js';
|
|
6
|
+
import { selectWaterfall } from './select-waterfall.js';
|
|
7
|
+
import { RunnerView } from './runner.js';
|
|
8
|
+
import { useRunSlice } from './use-run-slice.js';
|
|
9
|
+
/** Build the inline `--st-*` custom properties for the theming surface. */
|
|
10
|
+
function themeVars(theme) {
|
|
11
|
+
const vars = {};
|
|
12
|
+
if (theme?.bg)
|
|
13
|
+
vars['--st-bg'] = theme.bg;
|
|
14
|
+
if (theme?.accent)
|
|
15
|
+
vars['--st-accent'] = theme.accent;
|
|
16
|
+
if (theme?.font)
|
|
17
|
+
vars['--st-font'] = theme.font;
|
|
18
|
+
if (theme?.fontSize)
|
|
19
|
+
vars['--st-font-size'] = theme.fontSize;
|
|
20
|
+
return vars;
|
|
21
|
+
}
|
|
22
|
+
function useDashboardStore(transport) {
|
|
23
|
+
const store = useMemo(() => {
|
|
24
|
+
const source = createRunSource(transport);
|
|
25
|
+
return {
|
|
26
|
+
source,
|
|
27
|
+
scenes: createCollection(runCollectionOptions({ source, projection: scenesProjection() })),
|
|
28
|
+
assertions: createCollection(runCollectionOptions({ source, projection: assertionsProjection() })),
|
|
29
|
+
actions: createCollection(runCollectionOptions({ source, projection: actionsProjection() })),
|
|
30
|
+
runs: createCollection(runCollectionOptions({ source, projection: runsProjection() })),
|
|
31
|
+
};
|
|
32
|
+
}, [transport]);
|
|
33
|
+
const [connection, setConnection] = useState('connecting');
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const stopStatus = store.source.subscribe(() => { }, setConnection);
|
|
36
|
+
return () => {
|
|
37
|
+
stopStatus();
|
|
38
|
+
store.source.close();
|
|
39
|
+
};
|
|
40
|
+
}, [store]);
|
|
41
|
+
return { store, connection };
|
|
42
|
+
}
|
|
43
|
+
// Both hosts mount the dashboard (and its dev middleware endpoints) here. It's
|
|
44
|
+
// a single constant rather than a prop: the routing and the Runner's data
|
|
45
|
+
// fetches must agree, and nothing in-tree mounts it anywhere else.
|
|
46
|
+
const BASE = '/__scenetest';
|
|
47
|
+
function tabForPath(pathname) {
|
|
48
|
+
if (pathname.startsWith(`${BASE}/runner`))
|
|
49
|
+
return 'runner';
|
|
50
|
+
if (pathname.startsWith(`${BASE}/waterfall`))
|
|
51
|
+
return 'waterfall';
|
|
52
|
+
return 'home';
|
|
53
|
+
}
|
|
54
|
+
const PATH_FOR_TAB = {
|
|
55
|
+
home: BASE,
|
|
56
|
+
runner: `${BASE}/runner`,
|
|
57
|
+
waterfall: `${BASE}/waterfall`,
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* The Dashboard app — Home / Runner / Waterfall views over one read-only
|
|
61
|
+
* `@tanstack/db` read model, routed on `location.pathname`. A plain Preact
|
|
62
|
+
* component rendering into the light DOM under a single `.scenetest-dashboard`
|
|
63
|
+
* root class; the shipped stylesheet scopes everything to it. Dev and cloud
|
|
64
|
+
* render the same component — only the injected `transport` differs.
|
|
65
|
+
*
|
|
66
|
+
* /__scenetest → Home
|
|
67
|
+
* /__scenetest/runner → Runner (filterable scene log)
|
|
68
|
+
* /__scenetest/waterfall → Waterfall (live timeline)
|
|
69
|
+
*
|
|
70
|
+
* The collections are the single store: the component builds them from the run
|
|
71
|
+
* stream and every view reads from them (`selectWaterfall`, `selectSnapshot`).
|
|
72
|
+
*/
|
|
73
|
+
export function Dashboard({ transport, theme, }) {
|
|
74
|
+
const { store, connection } = useDashboardStore(transport);
|
|
75
|
+
const [tab, setTab] = useState(() => tabForPath(location.pathname));
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const onPop = () => setTab(tabForPath(location.pathname));
|
|
78
|
+
window.addEventListener('popstate', onPop);
|
|
79
|
+
return () => window.removeEventListener('popstate', onPop);
|
|
80
|
+
}, []);
|
|
81
|
+
// Client-side navigation via real <a> links, delegated on the app root.
|
|
82
|
+
// Modifier-clicks fall through to the browser as normal links.
|
|
83
|
+
const onNavigate = (e) => {
|
|
84
|
+
const a = e.target?.closest('a');
|
|
85
|
+
const href = a?.getAttribute('href');
|
|
86
|
+
if (!href || !href.startsWith(BASE))
|
|
87
|
+
return;
|
|
88
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0)
|
|
89
|
+
return;
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
history.pushState(null, '', href + location.search);
|
|
92
|
+
setTab(tabForPath(href));
|
|
93
|
+
};
|
|
94
|
+
const send = (command) => {
|
|
95
|
+
void transport.sendCommand(command);
|
|
96
|
+
};
|
|
97
|
+
const tabClass = (t) => 'tab' + (tab === t ? ' active' : '');
|
|
98
|
+
return (_jsxs("div", { class: "scenetest-dashboard", style: themeVars(theme), onClick: onNavigate, children: [_jsxs("nav", { class: "dashboard-nav", children: [_jsxs("h1", { children: [_jsx("span", { class: "logo", children: "\uD83C\uDFAC" }), " Scenetest"] }), _jsxs("div", { class: "tabs", children: [_jsx("a", { class: tabClass('home'), href: PATH_FOR_TAB.home, children: "Home" }), _jsx("a", { class: tabClass('runner'), href: PATH_FOR_TAB.runner, children: "Runner" }), _jsx("a", { class: tabClass('waterfall'), href: PATH_FOR_TAB.waterfall, children: "Waterfall" })] })] }), _jsx("div", { class: "view", children: tab === 'home' ? (_jsx(Home, {})) : tab === 'runner' ? (_jsx(RunnerView, { collections: store, connection: connection, base: BASE })) : (_jsx(WaterfallHost, { collections: store, connection: connection, send: send })) })] }));
|
|
99
|
+
}
|
|
100
|
+
// ── Home ──────────────────────────────────────────────────────────
|
|
101
|
+
function Home() {
|
|
102
|
+
return (_jsxs("div", { class: "index", children: [_jsxs("h1", { children: [_jsx("span", { class: "logo", children: "\uD83C\uDFAC" }), " Scenetest"] }), _jsx("p", { class: "lede", children: "Pick a view." }), _jsxs("div", { class: "cards", children: [_jsxs("a", { class: "card", href: PATH_FOR_TAB.runner, children: [_jsx("div", { class: "name", children: "Scene runner \u2192" }), _jsx("div", { class: "desc", children: "Live and past runs: scene tree, status, failure log, spec snippets." })] }), _jsxs("a", { class: "card", href: PATH_FOR_TAB.waterfall, children: [_jsx("div", { class: "name", children: "Waterfall \u2192" }), _jsx("div", { class: "desc", children: "Live timeline of actors and inline check() / should() assertions." })] })] })] }));
|
|
103
|
+
}
|
|
104
|
+
// ── Waterfall view ─────────────────────────────────────────────────
|
|
105
|
+
// A pure Preact subtree now — its widget styles are scoped to `.waterfall-host`
|
|
106
|
+
// by the stylesheet, so it no longer needs a nested shadow root. Reads the
|
|
107
|
+
// shared store reactively; `selectWaterfall` folds it into the Waterfall shape.
|
|
108
|
+
function WaterfallHost({ collections, connection, send, }) {
|
|
109
|
+
const slice = useRunSlice(collections);
|
|
110
|
+
const view = useMemo(() => selectWaterfall(slice), [slice.runId, slice.run, slice.scenes, slice.assertions, slice.actions]);
|
|
111
|
+
const state = { ...view, connection };
|
|
112
|
+
return (_jsx("div", { class: "waterfall-host", children: _jsx(Waterfall, { state: state, send: send }) }));
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.tsx"],"names":[],"mappings":"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"}
|
package/dist/dev-transport.d.ts
CHANGED
|
@@ -10,9 +10,9 @@ export interface DevTransportOptions {
|
|
|
10
10
|
/**
|
|
11
11
|
* Transport adapter for dev mode: the Vite middleware, same-origin.
|
|
12
12
|
*
|
|
13
|
-
* -
|
|
14
|
-
* replays the buffered events for the current run on connect
|
|
15
|
-
*
|
|
13
|
+
* - History + live events both arrive over the SSE stream at `<base>/events`,
|
|
14
|
+
* which replays the buffered events for the current run on connect and then
|
|
15
|
+
* streams live ones — all through `subscribe`.
|
|
16
16
|
* - Commands map onto the middleware's existing endpoints:
|
|
17
17
|
* `run:replay` → POST `<base>/replay` (`{ file?, team? }`),
|
|
18
18
|
* `run:stop` → POST `<base>/stop`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-transport.d.ts","sourceRoot":"","sources":["../src/dev-transport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,SAAS,EAAE,MAAM,YAAY,CAAA;AAE7D,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"dev-transport.d.ts","sourceRoot":"","sources":["../src/dev-transport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,SAAS,EAAE,MAAM,YAAY,CAAA;AAE7D,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,SAAS,CAqD/E"}
|
package/dist/dev-transport.js
CHANGED
|
@@ -2,9 +2,9 @@ import { isEventShaped } from '@scenetest/protocol';
|
|
|
2
2
|
/**
|
|
3
3
|
* Transport adapter for dev mode: the Vite middleware, same-origin.
|
|
4
4
|
*
|
|
5
|
-
* -
|
|
6
|
-
* replays the buffered events for the current run on connect
|
|
7
|
-
*
|
|
5
|
+
* - History + live events both arrive over the SSE stream at `<base>/events`,
|
|
6
|
+
* which replays the buffered events for the current run on connect and then
|
|
7
|
+
* streams live ones — all through `subscribe`.
|
|
8
8
|
* - Commands map onto the middleware's existing endpoints:
|
|
9
9
|
* `run:replay` → POST `<base>/replay` (`{ file?, team? }`),
|
|
10
10
|
* `run:stop` → POST `<base>/stop`,
|
|
@@ -13,10 +13,6 @@ import { isEventShaped } from '@scenetest/protocol';
|
|
|
13
13
|
export function createDevTransport(options = {}) {
|
|
14
14
|
const base = (options.base ?? '/__scenetest').replace(/\/+$/, '');
|
|
15
15
|
return {
|
|
16
|
-
// SSE replays the run buffer on connect, so there is no separate snapshot.
|
|
17
|
-
async fetchState() {
|
|
18
|
-
return [];
|
|
19
|
-
},
|
|
20
16
|
subscribe(onEvent, onStatus) {
|
|
21
17
|
const source = new EventSource(`${base}/events`);
|
|
22
18
|
const status = (s) => onStatus?.(s);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-transport.js","sourceRoot":"","sources":["../src/dev-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAanD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAA+B,EAAE;IAClE,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,cAAc,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAEjE,OAAO;QACL,
|
|
1
|
+
{"version":3,"file":"dev-transport.js","sourceRoot":"","sources":["../src/dev-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAanD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAA+B,EAAE;IAClE,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,cAAc,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAEjE,OAAO;QACL,SAAS,CAAC,OAAO,EAAE,QAAQ;YACzB,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,IAAI,SAAS,CAAC,CAAA;YAChD,MAAM,MAAM,GAAG,CAAC,CAAmB,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAA;YACrD,MAAM,CAAC,YAAY,CAAC,CAAA;YAEpB,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;YACzC,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;YAC7C,MAAM,CAAC,SAAS,GAAG,CAAC,CAAe,EAAE,EAAE;gBACrC,IAAI,MAAe,CAAA;gBACnB,IAAI,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;gBAC7B,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAM;gBACR,CAAC;gBACD,kEAAkE;gBAClE,sDAAsD;gBACtD,IAAI,aAAa,CAAC,MAAM,CAAC;oBAAE,OAAO,CAAC,MAAkB,CAAC,CAAA;YACxD,CAAC,CAAA;YAED,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;QAC7B,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,OAAgB;YAChC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,IAAc,EAAE,EAAE,CAC5C,KAAK,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE;gBACtB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC5D,CAAC,CAAA;YAEJ,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;gBACrB,KAAK,YAAY,CAAC,CAAC,CAAC;oBAClB,MAAM,IAAI,GAAqC,EAAE,CAAA;oBACjD,IAAI,OAAO,CAAC,IAAI;wBAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;oBAC1C,IAAI,OAAO,CAAC,IAAI;wBAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;oBAC1C,MAAM,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;oBAC3B,OAAM;gBACR,CAAC;gBACD,KAAK,UAAU;oBACb,MAAM,IAAI,CAAC,OAAO,CAAC,CAAA;oBACnB,OAAM;gBACR,mEAAmE;gBACnE,KAAK,WAAW,CAAC;gBACjB,KAAK,YAAY;oBACf,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAA;oBACpB,OAAM;YACV,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { Dashboard } from './dashboard.js';
|
|
2
2
|
export { createDevTransport, type DevTransportOptions } from './dev-transport.js';
|
|
3
|
-
export {
|
|
3
|
+
export { selectWaterfall, completedSceneCount } from './select-waterfall.js';
|
|
4
|
+
export { selectSnapshot, mapReportToSnapshot } from './select-runner.js';
|
|
4
5
|
export { sceneSummary } from './app.js';
|
|
5
|
-
export
|
|
6
|
+
export { useLiveQuery, type ObservableRows } from './use-live-query.js';
|
|
7
|
+
export type { DashboardCollections } from './select-helpers.js';
|
|
8
|
+
export type { Transport, ConnectionStatus, DashboardState, DashboardTheme, Scene, Lane, ActionItem, AssertionRow, } from './types.js';
|
|
6
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACjF,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACvE,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,KAAK,EACL,IAAI,EACJ,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { Dashboard } from './dashboard.js';
|
|
2
2
|
export { createDevTransport } from './dev-transport.js';
|
|
3
|
-
export {
|
|
3
|
+
export { selectWaterfall, completedSceneCount } from './select-waterfall.js';
|
|
4
|
+
export { selectSnapshot, mapReportToSnapshot } from './select-runner.js';
|
|
4
5
|
export { sceneSummary } from './app.js';
|
|
6
|
+
export { useLiveQuery } from './use-live-query.js';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAA4B,MAAM,oBAAoB,CAAA;AACjF,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,YAAY,EAAuB,MAAM,qBAAqB,CAAA"}
|
package/dist/runner.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DashboardCollections } from './select-helpers.js';
|
|
2
|
+
import type { ConnectionStatus } from './types.js';
|
|
3
|
+
export declare function RunnerView({ collections, connection: liveConnection, base, }: {
|
|
4
|
+
collections: DashboardCollections;
|
|
5
|
+
connection: ConnectionStatus;
|
|
6
|
+
base: string;
|
|
7
|
+
}): import("preact").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAmElD,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,UAAU,EAAE,cAAc,EAC1B,IAAI,GACL,EAAE;IACD,WAAW,EAAE,oBAAoB,CAAA;IACjC,UAAU,EAAE,gBAAgB,CAAA;IAC5B,IAAI,EAAE,MAAM,CAAA;CACb,gCAkDA"}
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useMemo, useCallback, useRef } from 'preact/hooks';
|
|
3
|
+
import { selectSnapshot, mapReportToSnapshot, EMPTY_SNAPSHOT, } from './select-runner.js';
|
|
4
|
+
import { useRunSlice } from './use-run-slice.js';
|
|
5
|
+
const STATUSES = ['failed', 'timeout', 'running', 'completed'];
|
|
6
|
+
// ── Helpers ───────────────────────────────────────────────────────
|
|
7
|
+
function shortFile(f) {
|
|
8
|
+
if (!f)
|
|
9
|
+
return '';
|
|
10
|
+
const parts = f.replace(/\\/g, '/').split('/');
|
|
11
|
+
return parts.length > 2 ? '…/' + parts.slice(-2).join('/') : f;
|
|
12
|
+
}
|
|
13
|
+
function statusIcon(s) {
|
|
14
|
+
return s === 'completed' ? '✓' : s === 'running' ? '◐' : s === 'timeout' ? '⏱' : '✗';
|
|
15
|
+
}
|
|
16
|
+
function teamLabel(s) {
|
|
17
|
+
return s.team?.name || 'team ' + s.teamIndex;
|
|
18
|
+
}
|
|
19
|
+
// ── Data: live reads the shared read model; past fetches a report ──
|
|
20
|
+
function useRunner(collections, liveConnection, runId, base) {
|
|
21
|
+
// Read the store reactively (live mode): the latest-run slice is maintained
|
|
22
|
+
// by live-query collections (`where runId = latest`, ordered); the selector
|
|
23
|
+
// attributes assertions/actions to scenes and rolls up the summary.
|
|
24
|
+
const slice = useRunSlice(collections);
|
|
25
|
+
const live = useMemo(() => selectSnapshot(slice), [slice.runId, slice.run, slice.scenes, slice.assertions, slice.actions]);
|
|
26
|
+
const [past, setPast] = useState(EMPTY_SNAPSHOT);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (runId === 'live')
|
|
29
|
+
return;
|
|
30
|
+
setPast(EMPTY_SNAPSHOT);
|
|
31
|
+
let alive = true;
|
|
32
|
+
fetch(`${base}/runs/${encodeURIComponent(runId)}`)
|
|
33
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
34
|
+
.then((data) => {
|
|
35
|
+
if (alive && data)
|
|
36
|
+
setPast(mapReportToSnapshot(data));
|
|
37
|
+
})
|
|
38
|
+
.catch(() => { });
|
|
39
|
+
return () => {
|
|
40
|
+
alive = false;
|
|
41
|
+
};
|
|
42
|
+
}, [runId, base]);
|
|
43
|
+
if (runId === 'live')
|
|
44
|
+
return { snap: live, connection: liveConnection };
|
|
45
|
+
return { snap: past, connection: 'idle' };
|
|
46
|
+
}
|
|
47
|
+
// ── Runner view root ──────────────────────────────────────────────
|
|
48
|
+
export function RunnerView({ collections, connection: liveConnection, base, }) {
|
|
49
|
+
const [runId, setRunId] = useState(() => new URLSearchParams(location.search).get('run') || 'live');
|
|
50
|
+
const [runs, setRuns] = useState([]);
|
|
51
|
+
const [filters, setFilters] = useState({ text: '', statuses: new Set(STATUSES), groupBy: 'status' });
|
|
52
|
+
const [selected, setSelected] = useState(null);
|
|
53
|
+
const { snap, connection } = useRunner(collections, liveConnection, runId, base);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
fetch(`${base}/runs`)
|
|
56
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
57
|
+
.then((data) => {
|
|
58
|
+
if (data)
|
|
59
|
+
setRuns(data.runs || []);
|
|
60
|
+
})
|
|
61
|
+
.catch(() => { });
|
|
62
|
+
}, [base]);
|
|
63
|
+
// Reflect the chosen run in the URL, preserving the route path.
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const p = new URLSearchParams(location.search);
|
|
66
|
+
p.set('run', runId);
|
|
67
|
+
history.replaceState(null, '', location.pathname + '?' + p.toString());
|
|
68
|
+
setSelected(null);
|
|
69
|
+
}, [runId]);
|
|
70
|
+
const scene = snap.scenes.find((s) => s.id === selected);
|
|
71
|
+
return (_jsxs("div", { class: "runner", children: [_jsx(RunnerHeader, { runs: runs, runId: runId, onRunChange: setRunId, connection: connection, summary: snap.summary, scenes: snap.scenes }), _jsxs("main", { children: [_jsx(Tree, { scenes: snap.scenes, selected: selected, onSelect: setSelected }), _jsx(ListPane, { scenes: snap.scenes, filters: filters, onFilters: setFilters, selected: selected, onSelect: setSelected, runId: runId }), _jsx(Detail, { scene: scene, base: base })] })] }));
|
|
72
|
+
}
|
|
73
|
+
// ── Header (run picker + status) ──────────────────────────────────
|
|
74
|
+
function RunnerHeader({ runs, runId, onRunChange, connection, summary, scenes, }) {
|
|
75
|
+
const completed = scenes.filter((s) => s.status === 'completed').length;
|
|
76
|
+
const a = summary.assertions;
|
|
77
|
+
return (_jsxs("div", { class: "runner-bar", children: [_jsxs("div", { class: "run-picker", children: [_jsx("label", { for: "run-select", children: "Run" }), _jsxs("select", { id: "run-select", value: runId, onChange: (e) => onRunChange(e.target.value), children: [_jsx("option", { value: "live", children: "Live (current run)" }), runs.map((r) => (_jsxs("option", { value: r.id, children: [new Date(r.mtime).toLocaleString(), " \u2014 ", r.id] }, r.id)))] }), _jsx("span", { class: 'conn ' + connection, title: connection })] }), _jsxs("div", { class: "status-bar", children: [_jsxs("span", { children: ["scenes ", completed, "/", summary.scenes || scenes.length] }), _jsxs("span", { class: "ok", children: ["\u2713 ", a.passed] }), _jsxs("span", { class: "fail", children: ["\u2717 ", a.failed] })] })] }));
|
|
78
|
+
}
|
|
79
|
+
// ── Tree (scenes grouped by file) ─────────────────────────────────
|
|
80
|
+
function Tree({ scenes, selected, onSelect, }) {
|
|
81
|
+
const byFile = useMemo(() => {
|
|
82
|
+
const m = new Map();
|
|
83
|
+
for (const s of scenes) {
|
|
84
|
+
const f = s.file || '(no file)';
|
|
85
|
+
if (!m.has(f))
|
|
86
|
+
m.set(f, []);
|
|
87
|
+
m.get(f).push(s);
|
|
88
|
+
}
|
|
89
|
+
return m;
|
|
90
|
+
}, [scenes]);
|
|
91
|
+
return (_jsx("aside", { class: "tree", children: [...byFile.entries()].map(([file, group]) => {
|
|
92
|
+
const fails = group.filter((s) => s.status !== 'completed' && s.status !== 'running').length;
|
|
93
|
+
return (_jsxs("div", { children: [_jsxs("div", { class: "tree-file", title: file, children: [_jsx("span", { children: shortFile(file) }), fails ? _jsx("span", { class: "fail", children: fails }) : null] }), group.map((s) => (_jsx("div", { class: 'tree-scene ' + s.status + (s.id === selected ? ' selected' : ''), onClick: () => onSelect(s.id), children: s.name }, s.id)))] }, file));
|
|
94
|
+
}) }));
|
|
95
|
+
}
|
|
96
|
+
// ── List pane (filters + grouped list) ────────────────────────────
|
|
97
|
+
function ListPane({ scenes, filters, onFilters, selected, onSelect, runId, }) {
|
|
98
|
+
const filtered = useMemo(() => {
|
|
99
|
+
const text = filters.text.toLowerCase();
|
|
100
|
+
return scenes.filter((s) => {
|
|
101
|
+
if (!filters.statuses.has(s.status))
|
|
102
|
+
return false;
|
|
103
|
+
if (!text)
|
|
104
|
+
return true;
|
|
105
|
+
const hay = [s.name, s.file, ...s.assertions.map((a) => a.description), s.error || ''].join(' ').toLowerCase();
|
|
106
|
+
return hay.includes(text);
|
|
107
|
+
});
|
|
108
|
+
}, [scenes, filters]);
|
|
109
|
+
const groups = useMemo(() => groupScenes(filtered, filters.groupBy), [filtered, filters.groupBy]);
|
|
110
|
+
const toggleStatus = useCallback((s) => {
|
|
111
|
+
const next = new Set(filters.statuses);
|
|
112
|
+
next.has(s) ? next.delete(s) : next.add(s);
|
|
113
|
+
onFilters({ ...filters, statuses: next });
|
|
114
|
+
}, [filters, onFilters]);
|
|
115
|
+
return (_jsxs("section", { class: "list-pane", children: [_jsxs("div", { class: "filters", children: [_jsx("input", { type: "search", placeholder: "Filter by scene, file, or assertion\u2026", value: filters.text, onInput: (e) => onFilters({ ...filters, text: e.target.value }) }), _jsx("div", { class: "chips", children: STATUSES.map((s) => (_jsx("button", { class: 'chip' + (filters.statuses.has(s) ? ' on' : ''), "data-status": s, onClick: () => toggleStatus(s), children: s[0].toUpperCase() + s.slice(1) }, s))) }), _jsxs("select", { class: "group-by", value: filters.groupBy, onChange: (e) => onFilters({ ...filters, groupBy: e.target.value }), children: [_jsx("option", { value: "none", children: "No grouping" }), _jsx("option", { value: "file", children: "Group by file" }), _jsx("option", { value: "status", children: "Group by status" }), _jsx("option", { value: "team", children: "Group by team" })] }), _jsx(CopyButton, { label: "Copy all failures", getText: () => formatFailureReport(scenes, runId) }), _jsx(CopyButton, { label: "Copy all", subtle: true, getText: () => formatReport(scenes, runId) })] }), _jsx("div", { class: "list", children: groups.length === 0 ? (_jsx("div", { class: "group-header", children: "No scenes match the current filters." })) : (groups.map((g) => (_jsxs("div", { children: [filters.groupBy !== 'none' ? (_jsxs("div", { class: "group-header", children: [g.key || '', " \u00B7 ", g.items.length] })) : null, g.items.map((s) => (_jsxs("div", { class: 'row' + (s.id === selected ? ' selected' : ''), onClick: () => onSelect(s.id), children: [_jsx("span", { class: 'icon ' + s.status, children: statusIcon(s.status) }), _jsx("span", { class: "name", children: s.name }), _jsx("span", { class: "row-team", title: "Team running this scene", children: teamLabel(s) }), _jsxs("span", { class: "meta", children: [s.assertions.filter((a) => !a.result).length > 0 ? _jsx("span", { class: "icon failed", children: "\u2717" }) : null, ' ', s.assertions.length, " check", s.assertions.length === 1 ? '' : 's', s.duration ? ' · ' + s.duration + 'ms' : ''] }), _jsx("span", { class: "file", children: shortFile(s.file) })] }, s.id)))] }, g.key)))) })] }));
|
|
116
|
+
}
|
|
117
|
+
function groupScenes(scenes, groupBy) {
|
|
118
|
+
if (groupBy === 'none')
|
|
119
|
+
return [{ key: '', items: scenes }];
|
|
120
|
+
const m = new Map();
|
|
121
|
+
for (const s of scenes) {
|
|
122
|
+
let key = '';
|
|
123
|
+
if (groupBy === 'file')
|
|
124
|
+
key = s.file || '(no file)';
|
|
125
|
+
else if (groupBy === 'status')
|
|
126
|
+
key = s.status;
|
|
127
|
+
else if (groupBy === 'team')
|
|
128
|
+
key = teamLabel(s);
|
|
129
|
+
if (!m.has(key))
|
|
130
|
+
m.set(key, []);
|
|
131
|
+
m.get(key).push(s);
|
|
132
|
+
}
|
|
133
|
+
const keys = [...m.keys()];
|
|
134
|
+
if (groupBy === 'status') {
|
|
135
|
+
const order = { failed: 0, timeout: 1, running: 2, completed: 3 };
|
|
136
|
+
keys.sort((a, b) => (order[a] ?? 99) - (order[b] ?? 99));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
keys.sort();
|
|
140
|
+
}
|
|
141
|
+
return keys.map((k) => ({ key: k, items: m.get(k) }));
|
|
142
|
+
}
|
|
143
|
+
// ── Detail pane (scene + spec snippet) ────────────────────────────
|
|
144
|
+
function Detail({ scene, base }) {
|
|
145
|
+
if (!scene) {
|
|
146
|
+
return (_jsx("aside", { class: "detail", children: _jsx("div", { class: "empty", children: "Select a scene on the left to see error details, timeline, and the spec snippet for reproducing it manually." }) }));
|
|
147
|
+
}
|
|
148
|
+
const failed = scene.status !== 'completed' && scene.status !== 'running';
|
|
149
|
+
const pills = ['team ' + teamLabel(scene), scene.duration ? scene.duration + 'ms' : '', scene.status].filter(Boolean);
|
|
150
|
+
const editorHref = `${base.replace(/__scenetest$/, '')}__open-in-editor?file=` +
|
|
151
|
+
encodeURIComponent(scene.file) +
|
|
152
|
+
(scene.line ? '&line=' + scene.line : '');
|
|
153
|
+
return (_jsxs("aside", { class: "detail", children: [_jsxs("div", { class: "actions", children: [_jsx(CopyButton, { label: "Copy", getText: () => formatScene(scene) }), scene.file ? (_jsx("a", { class: "btn subtle", href: editorHref, children: "Open in editor" })) : null] }), _jsxs("h3", { children: [failed ? _jsx("span", { class: "icon failed", children: "\u2717" }) : null, " ", scene.name] }), _jsxs("div", { class: "meta-row", children: [pills.map((t, i) => (_jsx("span", { class: "pill", children: t }, i))), scene.file ? (_jsxs("span", { class: "pill", title: scene.file, children: [shortFile(scene.file), scene.line ? ':' + scene.line : ''] })) : null] }), scene.error ? _jsx("div", { class: "err", children: scene.error }) : null, _jsx("h4", { children: "Assertions" }), _jsx("ul", { class: "alist", children: scene.assertions.length === 0 ? (_jsx("li", { children: "No assertions recorded." })) : (scene.assertions.map((a, i) => (_jsxs("li", { class: a.result ? 'pass' : 'fail', children: [a.result ? '✓' : '✗', " ", a.description] }, i)))) }), _jsx("h4", { children: "Timeline" }), _jsx("ul", { class: "timeline", children: scene.timeline.length === 0 ? (_jsx("li", { children: "(no timeline)" })) : (scene.timeline.map((t, i) => (_jsxs("li", { class: t.error ? 'err-step' : '', children: [t.actor, ": ", t.action, t.target ? ' ' + t.target : '', t.duration != null ? ' (' + t.duration + 'ms)' : '', t.error ? ' — ' + t.error : ''] }, i)))) }), _jsx("h4", { children: "Spec snippet" }), _jsx(SpecSnippet, { file: scene.file, line: scene.line, base: base })] }));
|
|
154
|
+
}
|
|
155
|
+
function SpecSnippet({ file, line, base }) {
|
|
156
|
+
const [state, setState] = useState({ status: 'idle' });
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
if (!file) {
|
|
159
|
+
setState({ status: 'no-file' });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const ctrl = new AbortController();
|
|
163
|
+
setState({ status: 'loading' });
|
|
164
|
+
const url = `${base}/source?file=` + encodeURIComponent(file) + '&line=' + (line || 1) + '&context=20';
|
|
165
|
+
fetch(url, { signal: ctrl.signal })
|
|
166
|
+
.then(async (r) => {
|
|
167
|
+
if (r.ok)
|
|
168
|
+
return { status: 'loaded', data: await r.json() };
|
|
169
|
+
return { status: 'missing', code: r.status };
|
|
170
|
+
})
|
|
171
|
+
.then((next) => setState(next))
|
|
172
|
+
.catch((err) => {
|
|
173
|
+
if (err.name !== 'AbortError')
|
|
174
|
+
setState({ status: 'error' });
|
|
175
|
+
});
|
|
176
|
+
return () => ctrl.abort();
|
|
177
|
+
}, [file, line, base]);
|
|
178
|
+
if (state.status === 'no-file')
|
|
179
|
+
return _jsx("div", { class: "empty", children: "No source file recorded." });
|
|
180
|
+
if (state.status === 'loading')
|
|
181
|
+
return _jsx("div", { class: "empty", children: "Loading\u2026" });
|
|
182
|
+
if (state.status === 'missing')
|
|
183
|
+
return _jsxs("div", { class: "empty", children: ["Source not available (", state.code, ")."] });
|
|
184
|
+
if (state.status === 'error')
|
|
185
|
+
return _jsx("div", { class: "empty", children: "Could not load source." });
|
|
186
|
+
if (state.status !== 'loaded')
|
|
187
|
+
return null;
|
|
188
|
+
const { start, lines } = state.data;
|
|
189
|
+
const target = line || start;
|
|
190
|
+
return (_jsx("pre", { class: "snippet", children: lines.map((ln, i) => {
|
|
191
|
+
const n = start + i;
|
|
192
|
+
return (_jsxs("div", { class: 'row-line' + (n === target ? ' hl' : ''), children: [_jsx("span", { class: "ln", children: n }), ln] }, n));
|
|
193
|
+
}) }));
|
|
194
|
+
}
|
|
195
|
+
// ── Copy button ───────────────────────────────────────────────────
|
|
196
|
+
function CopyButton({ label, getText, subtle }) {
|
|
197
|
+
const [copied, setCopied] = useState(false);
|
|
198
|
+
const tRef = useRef(null);
|
|
199
|
+
useEffect(() => () => {
|
|
200
|
+
if (tRef.current)
|
|
201
|
+
clearTimeout(tRef.current);
|
|
202
|
+
}, []);
|
|
203
|
+
const onClick = () => {
|
|
204
|
+
navigator.clipboard.writeText(getText()).then(() => {
|
|
205
|
+
setCopied(true);
|
|
206
|
+
tRef.current = setTimeout(() => setCopied(false), 1500);
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
const cls = 'btn' + (subtle ? ' subtle' : '') + (copied ? ' copied' : '');
|
|
210
|
+
return (_jsx("button", { class: cls, onClick: onClick, children: copied ? 'Copied!' : label }));
|
|
211
|
+
}
|
|
212
|
+
// ── Plain-text formatters (clipboard payload) ─────────────────────
|
|
213
|
+
function formatScene(s) {
|
|
214
|
+
const status = s.status === 'completed' ? 'PASSED' : s.status === 'timeout' ? 'TIMEOUT' : s.status === 'running' ? 'RUNNING' : 'FAILED';
|
|
215
|
+
const lines = [];
|
|
216
|
+
lines.push(statusIcon(s.status) + ' ' + s.name + ' — ' + status);
|
|
217
|
+
lines.push(' File: ' + s.file + (s.line ? ':' + s.line : ''));
|
|
218
|
+
lines.push(' Team: ' + teamLabel(s) + (s.duration ? ' · ' + s.duration + 'ms' : ''));
|
|
219
|
+
if (s.error)
|
|
220
|
+
lines.push(' Error: ' + s.error);
|
|
221
|
+
if (s.assertions.length) {
|
|
222
|
+
lines.push(' Assertions:');
|
|
223
|
+
for (const a of s.assertions)
|
|
224
|
+
lines.push(' ' + (a.result ? '✓' : '✗') + ' ' + a.description);
|
|
225
|
+
}
|
|
226
|
+
if (s.timeline.length) {
|
|
227
|
+
lines.push(' Timeline:');
|
|
228
|
+
for (const t of s.timeline) {
|
|
229
|
+
lines.push(' ' +
|
|
230
|
+
t.actor +
|
|
231
|
+
': ' +
|
|
232
|
+
t.action +
|
|
233
|
+
(t.target ? ' ' + t.target : '') +
|
|
234
|
+
(t.duration != null ? ' (' + t.duration + 'ms)' : '') +
|
|
235
|
+
(t.error ? ' — ' + t.error : ''));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return lines.join('\n');
|
|
239
|
+
}
|
|
240
|
+
function formatReport(scenes, runId) {
|
|
241
|
+
const failures = scenes.filter((s) => s.status !== 'completed' && s.status !== 'running');
|
|
242
|
+
const header = ['Scenetest — ' + (runId || 'live'), failures.length + ' failing scene(s)', ''];
|
|
243
|
+
return header.join('\n') + '\n' + scenes.map((s) => formatScene(s)).join('\n\n');
|
|
244
|
+
}
|
|
245
|
+
function formatFailureReport(scenes, runId) {
|
|
246
|
+
const failures = scenes.filter((s) => s.status !== 'completed' && s.status !== 'running');
|
|
247
|
+
return formatReport(failures.length ? failures : scenes, runId);
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { SceneRow, AssertionRecord, ActionRecord, RunRow } from './collections/projections.js';
|
|
2
|
+
import type { ObservableRows } from './use-live-query.js';
|
|
3
|
+
/**
|
|
4
|
+
* The read model's collections, created once at the Dashboard root and passed
|
|
5
|
+
* to every view. Each view reads the tables it needs reactively with
|
|
6
|
+
* `useLiveQuery`, then selects (`selectWaterfall`, `selectSnapshot`). Typed
|
|
7
|
+
* structurally ({@link ObservableRows}) so the concrete `@tanstack/db`
|
|
8
|
+
* `Collection`s satisfy it without leaking their generics.
|
|
9
|
+
*/
|
|
10
|
+
export interface DashboardCollections {
|
|
11
|
+
scenes: ObservableRows<SceneRow>;
|
|
12
|
+
assertions: ObservableRows<AssertionRecord>;
|
|
13
|
+
actions: ObservableRows<ActionRecord>;
|
|
14
|
+
runs: ObservableRows<RunRow>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The read model is multi-run — the collections accumulate every run of the
|
|
18
|
+
* session — so the live views (Waterfall, Runner) render the **latest** run:
|
|
19
|
+
* the `where runId = latest` slice. `RunSlice` is that slice, shared by both
|
|
20
|
+
* selectors so they agree on the "current run". Built incrementally by
|
|
21
|
+
* `useRunSlice` (live), or by `latestRunSlice` (the pure reference, for tests).
|
|
22
|
+
*/
|
|
23
|
+
export interface RunSlice {
|
|
24
|
+
runId: string | undefined;
|
|
25
|
+
run: RunRow | undefined;
|
|
26
|
+
scenes: SceneRow[];
|
|
27
|
+
assertions: AssertionRecord[];
|
|
28
|
+
actions: ActionRecord[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The latest run's id — the newest `run:start` (max `startTime`). Falls back to
|
|
32
|
+
* the most-recent scene's `runId` only when no run row exists yet (a window that
|
|
33
|
+
* doesn't occur in practice, since `run:start` precedes the first scene).
|
|
34
|
+
*/
|
|
35
|
+
export declare function latestRunId(runs: RunRow[], scenes?: SceneRow[]): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Bucket assertion/action rows by the scene they attribute to, in **one pass**
|
|
38
|
+
* over the rows. Both selectors then read each scene's rows by id instead of
|
|
39
|
+
* re-filtering the whole list per scene through `attributeToScene` (which itself
|
|
40
|
+
* scans the scenes) — turning the O(scenes² × rows) per-scene filter into one
|
|
41
|
+
* O(rows × scenes) pass. Rows that attribute to no scene are dropped.
|
|
42
|
+
*/
|
|
43
|
+
export declare function groupByScene<T extends {
|
|
44
|
+
sceneId: string | null;
|
|
45
|
+
runId: string;
|
|
46
|
+
actor: string | null;
|
|
47
|
+
timestamp: number;
|
|
48
|
+
}>(rows: T[], scenes: SceneRow[]): Map<string, T[]>;
|
|
49
|
+
export declare function latestRunSlice(scenes: SceneRow[], assertions: AssertionRecord[], actions: ActionRecord[], runs: RunRow[]): RunSlice;
|
|
50
|
+
//# sourceMappingURL=select-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-helpers.d.ts","sourceRoot":"","sources":["../src/select-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAA;AAEnG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;IAChC,UAAU,EAAE,cAAc,CAAC,eAAe,CAAC,CAAA;IAC3C,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAA;IACrC,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAA;CAC7B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;IACvB,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,QAAQ,EAAO,GAAG,MAAM,GAAG,SAAS,CAKvF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EACvH,IAAI,EAAE,CAAC,EAAE,EACT,MAAM,EAAE,QAAQ,EAAE,GACjB,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAUlB;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,QAAQ,EAAE,EAClB,UAAU,EAAE,eAAe,EAAE,EAC7B,OAAO,EAAE,YAAY,EAAE,EACvB,IAAI,EAAE,MAAM,EAAE,GACb,QAAQ,CAWV"}
|