@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
package/dist/types.d.ts
CHANGED
|
@@ -15,16 +15,12 @@ export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected';
|
|
|
15
15
|
*/
|
|
16
16
|
export interface Transport {
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Subscribe to live events. `onEvent` receives every event after the
|
|
26
|
-
* snapshot; `onStatus`, if given, receives connection-liveness changes.
|
|
27
|
-
* Returns an unsubscribe function that tears down the underlying stream.
|
|
18
|
+
* Subscribe to the run stream. The transport replays the run history so far
|
|
19
|
+
* (SSE replays the buffer on connect; the cloud WebSocket replays from a
|
|
20
|
+
* `sinceSeq`) and then delivers live events through the same `onEvent`, so
|
|
21
|
+
* the read model folds history and live the same way. `onStatus`, if given,
|
|
22
|
+
* receives connection-liveness changes. Returns an unsubscribe function that
|
|
23
|
+
* tears down the underlying stream.
|
|
28
24
|
*/
|
|
29
25
|
subscribe(onEvent: (event: RunEvent) => void, onStatus?: (status: ConnectionStatus) => void): () => void;
|
|
30
26
|
/** Send a command toward the runner (replay, stop, pause, resume). */
|
|
@@ -99,14 +95,4 @@ export interface DashboardTheme {
|
|
|
99
95
|
/** Base font size (e.g. `'13px'`). */
|
|
100
96
|
fontSize?: string;
|
|
101
97
|
}
|
|
102
|
-
export interface MountOptions {
|
|
103
|
-
transport: Transport;
|
|
104
|
-
/** Optional theme overrides applied as `--st-*` custom properties. */
|
|
105
|
-
theme?: DashboardTheme;
|
|
106
|
-
}
|
|
107
|
-
/** Handle returned by `mountDashboard`. */
|
|
108
|
-
export interface DashboardHandle {
|
|
109
|
-
/** Tear down the widget, its subscription, and its shadow root contents. */
|
|
110
|
-
unmount(): void;
|
|
111
|
-
}
|
|
112
98
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEtE;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAA;AAE1E;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEtE;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAA;AAE1E;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;;OAOG;IACH,SAAS,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;IAExG,sEAAsE;IACtE,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7C;AAED,+CAA+C;AAC/C,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;CACjD;AAED,kDAAkD;AAClD,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,OAAO,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,gDAAgD;AAChD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,IAAI,EAAE,CAAA;IACb,UAAU,EAAE,YAAY,EAAE,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAA;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,QAAQ,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,wEAAwE;IACxE,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,4DAA4D;IAC5D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1D,UAAU,EAAE,gBAAgB,CAAA;CAC7B;AAED,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The minimal shape this hook needs from a TanStack DB collection: read its
|
|
3
|
+
* rows and subscribe to changes. Both base collections (`createCollection`) and
|
|
4
|
+
* derived ones (`createLiveQueryCollection`) satisfy it, so a view can read a
|
|
5
|
+
* raw table or a `.where(...).orderBy(...)` query through the same hook.
|
|
6
|
+
*/
|
|
7
|
+
export interface ObservableRows<T> {
|
|
8
|
+
readonly toArray: T[];
|
|
9
|
+
subscribeChanges(callback: (changes: unknown) => void): {
|
|
10
|
+
unsubscribe: () => void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Read a TanStack DB collection reactively: subscribe to its changes, re-render
|
|
15
|
+
* on each, and return the current rows. This is the Preact analogue of
|
|
16
|
+
* `@tanstack/react-db`'s `useLiveQuery` — the pattern to reach for, rather than
|
|
17
|
+
* a hand-rolled `subscribeChanges` + force-update in every component. Pass a
|
|
18
|
+
* stable collection (created once, e.g. via `useMemo` or at the app root); a
|
|
19
|
+
* fresh collection each render would resubscribe every time.
|
|
20
|
+
*
|
|
21
|
+
* The returned array keeps a **stable identity between changes** (`collection.toArray`
|
|
22
|
+
* builds a fresh array on every access, so we snapshot it only when a change
|
|
23
|
+
* actually fires). That's what lets downstream `useMemo`s over these rows
|
|
24
|
+
* (`selectSnapshot`, the Runner's filter/group memos) hit instead of recomputing
|
|
25
|
+
* every render.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useLiveQuery<T>(collection: ObservableRows<T>): T[];
|
|
28
|
+
//# sourceMappingURL=use-live-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-live-query.d.ts","sourceRoot":"","sources":["../src/use-live-query.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAA;IACrB,gBAAgB,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG;QAAE,WAAW,EAAE,MAAM,IAAI,CAAA;KAAE,CAAA;CACpF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAQlE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect, useState } from 'preact/hooks';
|
|
2
|
+
/**
|
|
3
|
+
* Read a TanStack DB collection reactively: subscribe to its changes, re-render
|
|
4
|
+
* on each, and return the current rows. This is the Preact analogue of
|
|
5
|
+
* `@tanstack/react-db`'s `useLiveQuery` — the pattern to reach for, rather than
|
|
6
|
+
* a hand-rolled `subscribeChanges` + force-update in every component. Pass a
|
|
7
|
+
* stable collection (created once, e.g. via `useMemo` or at the app root); a
|
|
8
|
+
* fresh collection each render would resubscribe every time.
|
|
9
|
+
*
|
|
10
|
+
* The returned array keeps a **stable identity between changes** (`collection.toArray`
|
|
11
|
+
* builds a fresh array on every access, so we snapshot it only when a change
|
|
12
|
+
* actually fires). That's what lets downstream `useMemo`s over these rows
|
|
13
|
+
* (`selectSnapshot`, the Runner's filter/group memos) hit instead of recomputing
|
|
14
|
+
* every render.
|
|
15
|
+
*/
|
|
16
|
+
export function useLiveQuery(collection) {
|
|
17
|
+
const [rows, setRows] = useState(() => collection.toArray);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
setRows(collection.toArray); // resync in case it changed before we subscribed
|
|
20
|
+
const sub = collection.subscribeChanges(() => setRows(collection.toArray));
|
|
21
|
+
return () => sub.unsubscribe();
|
|
22
|
+
}, [collection]);
|
|
23
|
+
return rows;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=use-live-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-live-query.js","sourceRoot":"","sources":["../src/use-live-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAalD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAI,UAA6B;IAC3D,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAM,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;IAC/D,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA,CAAC,iDAAiD;QAC7E,MAAM,GAAG,GAAG,UAAU,CAAC,gBAAgB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA;QAC1E,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAA;IAChC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAChB,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ObservableRows } from './use-live-query.js';
|
|
2
|
+
import { type DashboardCollections, type RunSlice } from './select-helpers.js';
|
|
3
|
+
import type { SceneRow, AssertionRecord, ActionRecord } from './collections/projections.js';
|
|
4
|
+
/** The live-query collections of one run's rows, the heart of {@link useRunSlice}. */
|
|
5
|
+
export interface RunSliceCollections {
|
|
6
|
+
scenes: ObservableRows<SceneRow>;
|
|
7
|
+
assertions: ObservableRows<AssertionRecord>;
|
|
8
|
+
actions: ObservableRows<ActionRecord>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build the three derived live-query collections for `runId` (`where runId = …`,
|
|
12
|
+
* scenes/actions `orderBy startTime`). A pure builder (no hooks) so it can be
|
|
13
|
+
* tested against `latestRunSlice` directly. Before the first run `runId` is
|
|
14
|
+
* undefined, so we filter on a sentinel that matches no real row (ids are
|
|
15
|
+
* timestamps) and the slice comes back empty.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runSliceCollections(collections: DashboardCollections, runId: string | undefined): RunSliceCollections;
|
|
18
|
+
/**
|
|
19
|
+
* The latest-run slice the live views render, maintained incrementally by
|
|
20
|
+
* `@tanstack/db` rather than re-scanned in JS each render. Picks the latest run
|
|
21
|
+
* from the small `runs` table and rebuilds the derived collections only when a
|
|
22
|
+
* new run starts; the views hand the result to the pure selectors.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useRunSlice(collections: DashboardCollections): RunSlice;
|
|
25
|
+
//# sourceMappingURL=use-run-slice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-run-slice.d.ts","sourceRoot":"","sources":["../src/use-run-slice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACvE,OAAO,EAAe,KAAK,oBAAoB,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC3F,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAE3F,sFAAsF;AACtF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;IAChC,UAAU,EAAE,cAAc,CAAC,eAAe,CAAC,CAAA;IAC3C,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,CAAA;CACtC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,oBAAoB,EACjC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,mBAAmB,CAsBrB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,oBAAoB,GAAG,QAAQ,CAiBvE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useMemo } from 'preact/hooks';
|
|
2
|
+
import { createLiveQueryCollection, eq } from '@tanstack/db';
|
|
3
|
+
import { useLiveQuery } from './use-live-query.js';
|
|
4
|
+
import { latestRunId } from './select-helpers.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build the three derived live-query collections for `runId` (`where runId = …`,
|
|
7
|
+
* scenes/actions `orderBy startTime`). A pure builder (no hooks) so it can be
|
|
8
|
+
* tested against `latestRunSlice` directly. Before the first run `runId` is
|
|
9
|
+
* undefined, so we filter on a sentinel that matches no real row (ids are
|
|
10
|
+
* timestamps) and the slice comes back empty.
|
|
11
|
+
*/
|
|
12
|
+
export function runSliceCollections(collections, runId) {
|
|
13
|
+
const key = runId ?? ' no-run';
|
|
14
|
+
const scenes = collections.scenes;
|
|
15
|
+
const assertions = collections.assertions;
|
|
16
|
+
const actions = collections.actions;
|
|
17
|
+
return {
|
|
18
|
+
scenes: createLiveQueryCollection((q) => q
|
|
19
|
+
.from({ scene: scenes })
|
|
20
|
+
.where(({ scene }) => eq(scene.runId, key))
|
|
21
|
+
.orderBy(({ scene }) => scene.startTime)),
|
|
22
|
+
assertions: createLiveQueryCollection((q) => q.from({ assertion: assertions }).where(({ assertion }) => eq(assertion.runId, key))),
|
|
23
|
+
actions: createLiveQueryCollection((q) => q
|
|
24
|
+
.from({ action: actions })
|
|
25
|
+
.where(({ action }) => eq(action.runId, key))
|
|
26
|
+
.orderBy(({ action }) => action.startTime)),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The latest-run slice the live views render, maintained incrementally by
|
|
31
|
+
* `@tanstack/db` rather than re-scanned in JS each render. Picks the latest run
|
|
32
|
+
* from the small `runs` table and rebuilds the derived collections only when a
|
|
33
|
+
* new run starts; the views hand the result to the pure selectors.
|
|
34
|
+
*/
|
|
35
|
+
export function useRunSlice(collections) {
|
|
36
|
+
const runs = useLiveQuery(collections.runs);
|
|
37
|
+
const runId = latestRunId(runs);
|
|
38
|
+
const run = runId ? runs.find((r) => r.id === runId) : undefined;
|
|
39
|
+
// Rebuild only when a new run starts (runId changes), not on every event.
|
|
40
|
+
const queries = useMemo(() => runSliceCollections(collections, runId),
|
|
41
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- collections are stable; rebuild only when the run changes
|
|
42
|
+
[collections.scenes, collections.assertions, collections.actions, runId]);
|
|
43
|
+
const scenes = useLiveQuery(queries.scenes);
|
|
44
|
+
const assertions = useLiveQuery(queries.assertions);
|
|
45
|
+
const actions = useLiveQuery(queries.actions);
|
|
46
|
+
return { runId, run, scenes, assertions, actions };
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=use-run-slice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-run-slice.js","sourceRoot":"","sources":["../src/use-run-slice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,yBAAyB,EAAE,EAAE,EAAmB,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAE,YAAY,EAAuB,MAAM,qBAAqB,CAAA;AACvE,OAAO,EAAE,WAAW,EAA4C,MAAM,qBAAqB,CAAA;AAU3F;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAiC,EACjC,KAAyB;IAEzB,MAAM,GAAG,GAAG,KAAK,IAAI,SAAS,CAAA;IAC9B,MAAM,MAAM,GAAG,WAAW,CAAC,MAAyC,CAAA;IACpE,MAAM,UAAU,GAAG,WAAW,CAAC,UAAoD,CAAA;IACnF,MAAM,OAAO,GAAG,WAAW,CAAC,OAA8C,CAAA;IAC1E,OAAO;QACL,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC,EAAE,EAAE,CACtC,CAAC;aACE,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;aACvB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;aAC1C,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAC3C;QACD,UAAU,EAAE,yBAAyB,CAAC,CAAC,CAAC,EAAE,EAAE,CAC1C,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CACrF;QACD,OAAO,EAAE,yBAAyB,CAAC,CAAC,CAAC,EAAE,EAAE,CACvC,CAAC;aACE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;aACzB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;aAC5C,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAC7C;KACF,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,WAAiC;IAC3D,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAC3C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAEhE,0EAA0E;IAC1E,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,KAAK,CAAC;IAC7C,oHAAoH;IACpH,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CACzE,CAAA;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACnD,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAE7C,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAA;AACpD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scenetest/dashboard",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.12.0",
|
|
4
|
+
"description": "Embeddable Preact dashboard component for scenetest — Home/Runner/Waterfall views over a read-only read model, fed by a pluggable transport adapter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"playwright",
|
|
16
16
|
"dashboard",
|
|
17
17
|
"preact",
|
|
18
|
-
"
|
|
18
|
+
"component"
|
|
19
19
|
],
|
|
20
20
|
"main": "./dist/index.js",
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"import": "./dist/index.js"
|
|
26
26
|
},
|
|
27
|
+
"./collections": {
|
|
28
|
+
"types": "./dist/collections/index.d.ts",
|
|
29
|
+
"import": "./dist/collections/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./style.css": "./dist/style.css",
|
|
27
32
|
"./package.json": "./package.json"
|
|
28
33
|
},
|
|
29
34
|
"files": [
|
|
@@ -33,7 +38,7 @@
|
|
|
33
38
|
"access": "public"
|
|
34
39
|
},
|
|
35
40
|
"dependencies": {
|
|
36
|
-
"
|
|
41
|
+
"@tanstack/db": "^0.6.0",
|
|
37
42
|
"preact": "^10.22.0",
|
|
38
43
|
"@scenetest/protocol": "0.11.0"
|
|
39
44
|
},
|
|
@@ -43,7 +48,7 @@
|
|
|
43
48
|
"vitest": "^4.1.4"
|
|
44
49
|
},
|
|
45
50
|
"scripts": {
|
|
46
|
-
"build": "tsc",
|
|
51
|
+
"build": "tsc && cp src/style.css dist/style.css",
|
|
47
52
|
"typecheck": "tsc --noEmit",
|
|
48
53
|
"test": "vitest run",
|
|
49
54
|
"test:watch": "vitest"
|
package/dist/mount.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { DashboardHandle, MountOptions } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Mount the dashboard widget into `element`. The widget renders into a shadow
|
|
4
|
-
* root with its own styles and fonts, so it can drop into any host — the
|
|
5
|
-
* `/__scenetest` page, a worker-served page, a docs island — without leaking
|
|
6
|
-
* styles in either direction and without the host needing to use Preact.
|
|
7
|
-
*
|
|
8
|
-
* The host supplies only a transport adapter (the dev/cloud seam) and an
|
|
9
|
-
* optional theme; everything else is internal. Returns a handle whose
|
|
10
|
-
* `unmount()` tears down Preact, the transport subscription, and the shadow
|
|
11
|
-
* content.
|
|
12
|
-
*/
|
|
13
|
-
export declare function mountDashboard(element: HTMLElement, options: MountOptions): DashboardHandle;
|
|
14
|
-
//# sourceMappingURL=mount.d.ts.map
|
package/dist/mount.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAkB,YAAY,EAAE,MAAM,YAAY,CAAA;AAE/E;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,eAAe,CAqB3F"}
|
package/dist/mount.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { h, render } from 'preact';
|
|
2
|
-
import { Dashboard } from './app.js';
|
|
3
|
-
import { STYLES } from './styles.js';
|
|
4
|
-
/**
|
|
5
|
-
* Mount the dashboard widget into `element`. The widget renders into a shadow
|
|
6
|
-
* root with its own styles and fonts, so it can drop into any host — the
|
|
7
|
-
* `/__scenetest` page, a worker-served page, a docs island — without leaking
|
|
8
|
-
* styles in either direction and without the host needing to use Preact.
|
|
9
|
-
*
|
|
10
|
-
* The host supplies only a transport adapter (the dev/cloud seam) and an
|
|
11
|
-
* optional theme; everything else is internal. Returns a handle whose
|
|
12
|
-
* `unmount()` tears down Preact, the transport subscription, and the shadow
|
|
13
|
-
* content.
|
|
14
|
-
*/
|
|
15
|
-
export function mountDashboard(element, options) {
|
|
16
|
-
const root = element.shadowRoot ?? element.attachShadow({ mode: 'open' });
|
|
17
|
-
root.innerHTML = '';
|
|
18
|
-
const style = document.createElement('style');
|
|
19
|
-
style.textContent = STYLES;
|
|
20
|
-
root.appendChild(style);
|
|
21
|
-
if (options.theme)
|
|
22
|
-
applyTheme(root, options.theme);
|
|
23
|
-
const container = document.createElement('div');
|
|
24
|
-
root.appendChild(container);
|
|
25
|
-
render(h(Dashboard, { transport: options.transport }), container);
|
|
26
|
-
return {
|
|
27
|
-
unmount() {
|
|
28
|
-
render(null, container);
|
|
29
|
-
root.innerHTML = '';
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Apply the small `--st-*` theming surface to the shadow host. A
|
|
35
|
-
* `:host { ... }` block can't be set imperatively, so the custom properties
|
|
36
|
-
* are written onto the host element's inline style, where `:host` rules in the
|
|
37
|
-
* stylesheet pick them up as overrides.
|
|
38
|
-
*/
|
|
39
|
-
function applyTheme(root, theme) {
|
|
40
|
-
const host = root.host;
|
|
41
|
-
if (theme.bg)
|
|
42
|
-
host.style.setProperty('--st-bg', theme.bg);
|
|
43
|
-
if (theme.accent)
|
|
44
|
-
host.style.setProperty('--st-accent', theme.accent);
|
|
45
|
-
if (theme.font)
|
|
46
|
-
host.style.setProperty('--st-font', theme.font);
|
|
47
|
-
if (theme.fontSize)
|
|
48
|
-
host.style.setProperty('--st-font-size', theme.fontSize);
|
|
49
|
-
}
|
|
50
|
-
//# sourceMappingURL=mount.js.map
|
package/dist/mount.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,OAAoB,EAAE,OAAqB;IACxE,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IACzE,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IAEnB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IAC7C,KAAK,CAAC,WAAW,GAAG,MAAM,CAAA;IAC1B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IAEvB,IAAI,OAAO,CAAC,KAAK;QAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IAElD,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC/C,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;IAE3B,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,SAAS,CAAC,CAAA;IAEjE,OAAO;QACL,OAAO;YACL,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;YACvB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,IAAgB,EAAE,KAAqB;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAmB,CAAA;IACrC,IAAI,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,CAAA;IACzD,IAAI,KAAK,CAAC,MAAM;QAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;IACrE,IAAI,KAAK,CAAC,IAAI;QAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;IAC/D,IAAI,KAAK,CAAC,QAAQ;QAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAC9E,CAAC"}
|
package/dist/store.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { RunEvent } from '@scenetest/protocol';
|
|
2
|
-
import type { ConnectionStatus, DashboardState } from './types.js';
|
|
3
|
-
/** The empty state, before any events. */
|
|
4
|
-
export declare function initialState(): DashboardState;
|
|
5
|
-
/**
|
|
6
|
-
* Fold one protocol event into the state, returning a new state object (and
|
|
7
|
-
* new objects for the scenes/scene that changed) so Preact re-renders. This
|
|
8
|
-
* is the same reduction the original inline dashboard did imperatively, made
|
|
9
|
-
* pure. Unknown event types are ignored — a newer producer can add events
|
|
10
|
-
* without breaking an older widget.
|
|
11
|
-
*/
|
|
12
|
-
export declare function applyEvent(state: DashboardState, event: RunEvent): DashboardState;
|
|
13
|
-
/** Fold a snapshot of events into a fresh state, in order. */
|
|
14
|
-
export declare function foldEvents(events: RunEvent[]): DashboardState;
|
|
15
|
-
/** Return a new state with the connection liveness updated. */
|
|
16
|
-
export declare function withConnection(state: DashboardState, connection: ConnectionStatus): DashboardState;
|
|
17
|
-
/** Number of scenes that have finished (not currently running). */
|
|
18
|
-
export declare function completedSceneCount(state: DashboardState): number;
|
|
19
|
-
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAe,MAAM,YAAY,CAAA;AAE/E,0CAA0C;AAC1C,wBAAgB,YAAY,IAAI,cAAc,CAa7C;AAqBD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,GAAG,cAAc,CA2GjF;AAYD,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,cAAc,CAE7D;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,GAAG,cAAc,CAElG;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAEjE"}
|
package/dist/store.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/** The empty state, before any events. */
|
|
2
|
-
export function initialState() {
|
|
3
|
-
return {
|
|
4
|
-
scenes: [],
|
|
5
|
-
currentSceneIndex: null,
|
|
6
|
-
runStartTime: null,
|
|
7
|
-
passCount: 0,
|
|
8
|
-
failCount: 0,
|
|
9
|
-
sceneCount: 0,
|
|
10
|
-
teams: [],
|
|
11
|
-
running: false,
|
|
12
|
-
endDurationMs: null,
|
|
13
|
-
connection: 'connecting',
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function cloneScene(scene) {
|
|
17
|
-
return {
|
|
18
|
-
...scene,
|
|
19
|
-
actors: scene.actors.slice(),
|
|
20
|
-
lanes: scene.lanes.map((lane) => ({ actor: lane.actor, items: lane.items.slice() })),
|
|
21
|
-
assertions: scene.assertions.slice(),
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function laneFor(scene, actor) {
|
|
25
|
-
let lane = scene.lanes.find((l) => l.actor === actor);
|
|
26
|
-
if (!lane) {
|
|
27
|
-
lane = { actor, items: [] };
|
|
28
|
-
scene.lanes.push(lane);
|
|
29
|
-
if (!scene.actors.includes(actor))
|
|
30
|
-
scene.actors.push(actor);
|
|
31
|
-
}
|
|
32
|
-
return lane;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Fold one protocol event into the state, returning a new state object (and
|
|
36
|
-
* new objects for the scenes/scene that changed) so Preact re-renders. This
|
|
37
|
-
* is the same reduction the original inline dashboard did imperatively, made
|
|
38
|
-
* pure. Unknown event types are ignored — a newer producer can add events
|
|
39
|
-
* without breaking an older widget.
|
|
40
|
-
*/
|
|
41
|
-
export function applyEvent(state, event) {
|
|
42
|
-
switch (event.type) {
|
|
43
|
-
case 'run:start':
|
|
44
|
-
return {
|
|
45
|
-
...initialState(),
|
|
46
|
-
connection: state.connection,
|
|
47
|
-
runStartTime: event.timestamp,
|
|
48
|
-
sceneCount: event.sceneCount,
|
|
49
|
-
running: true,
|
|
50
|
-
};
|
|
51
|
-
case 'scene:start': {
|
|
52
|
-
const scene = {
|
|
53
|
-
name: event.name,
|
|
54
|
-
file: event.file,
|
|
55
|
-
actors: (event.actors ?? []).slice(),
|
|
56
|
-
lanes: (event.actors ?? []).map((actor) => ({ actor, items: [] })),
|
|
57
|
-
assertions: [],
|
|
58
|
-
startTime: event.timestamp,
|
|
59
|
-
endTime: null,
|
|
60
|
-
status: 'running',
|
|
61
|
-
team: event.team ?? {},
|
|
62
|
-
teamIndex: event.teamIndex ?? 0,
|
|
63
|
-
};
|
|
64
|
-
const scenes = state.scenes.concat(scene);
|
|
65
|
-
const teamName = scene.team?.name;
|
|
66
|
-
const teams = teamName && !state.teams.includes(teamName) ? state.teams.concat(teamName) : state.teams;
|
|
67
|
-
return { ...state, scenes, currentSceneIndex: scenes.length - 1, teams };
|
|
68
|
-
}
|
|
69
|
-
case 'action:start': {
|
|
70
|
-
return updateCurrentScene(state, (scene) => {
|
|
71
|
-
const lane = laneFor(scene, event.actor);
|
|
72
|
-
lane.items.push({
|
|
73
|
-
action: event.action,
|
|
74
|
-
target: event.target,
|
|
75
|
-
startTime: event.timestamp,
|
|
76
|
-
endTime: null,
|
|
77
|
-
duration: null,
|
|
78
|
-
error: null,
|
|
79
|
-
status: 'running',
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
case 'action:end': {
|
|
84
|
-
return updateCurrentScene(state, (scene) => {
|
|
85
|
-
const lane = scene.lanes.find((l) => l.actor === event.actor);
|
|
86
|
-
if (!lane)
|
|
87
|
-
return;
|
|
88
|
-
for (let i = lane.items.length - 1; i >= 0; i--) {
|
|
89
|
-
const item = lane.items[i];
|
|
90
|
-
if (item.status === 'running' && item.action === event.action) {
|
|
91
|
-
item.endTime = event.timestamp;
|
|
92
|
-
item.duration = event.duration;
|
|
93
|
-
item.error = event.error ?? null;
|
|
94
|
-
item.status = event.error ? 'error' : event.duration > 500 ? 'slow' : 'success';
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
case 'assertion': {
|
|
101
|
-
return updateCurrentScene(state, (scene) => {
|
|
102
|
-
scene.assertions.push({
|
|
103
|
-
actor: event.actor,
|
|
104
|
-
description: event.description,
|
|
105
|
-
result: event.result,
|
|
106
|
-
timestamp: event.timestamp,
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
case 'scene:end': {
|
|
111
|
-
if (state.currentSceneIndex == null)
|
|
112
|
-
return state;
|
|
113
|
-
const next = updateCurrentScene(state, (scene) => {
|
|
114
|
-
scene.endTime = event.timestamp;
|
|
115
|
-
scene.status = event.status;
|
|
116
|
-
scene.duration = event.duration;
|
|
117
|
-
scene.error = event.error;
|
|
118
|
-
});
|
|
119
|
-
const passed = event.status === 'completed';
|
|
120
|
-
return {
|
|
121
|
-
...next,
|
|
122
|
-
currentSceneIndex: null,
|
|
123
|
-
passCount: next.passCount + (passed ? 1 : 0),
|
|
124
|
-
failCount: next.failCount + (passed ? 0 : 1),
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
case 'run:progress':
|
|
128
|
-
return { ...state, progress: { pct: event.pct, failing: event.failing, flaky: event.flaky } };
|
|
129
|
-
case 'run:end':
|
|
130
|
-
return {
|
|
131
|
-
...state,
|
|
132
|
-
running: false,
|
|
133
|
-
sceneCount: event.summary?.scenes ?? state.sceneCount,
|
|
134
|
-
passCount: event.summary?.completed ?? state.passCount,
|
|
135
|
-
failCount: event.summary?.failed ?? state.failCount,
|
|
136
|
-
endDurationMs: event.duration,
|
|
137
|
-
};
|
|
138
|
-
default:
|
|
139
|
-
return state;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
function updateCurrentScene(state, mutate) {
|
|
143
|
-
const idx = state.currentSceneIndex;
|
|
144
|
-
if (idx == null || idx < 0 || idx >= state.scenes.length)
|
|
145
|
-
return state;
|
|
146
|
-
const scene = cloneScene(state.scenes[idx]);
|
|
147
|
-
mutate(scene);
|
|
148
|
-
const scenes = state.scenes.slice();
|
|
149
|
-
scenes[idx] = scene;
|
|
150
|
-
return { ...state, scenes };
|
|
151
|
-
}
|
|
152
|
-
/** Fold a snapshot of events into a fresh state, in order. */
|
|
153
|
-
export function foldEvents(events) {
|
|
154
|
-
return events.reduce(applyEvent, initialState());
|
|
155
|
-
}
|
|
156
|
-
/** Return a new state with the connection liveness updated. */
|
|
157
|
-
export function withConnection(state, connection) {
|
|
158
|
-
return { ...state, connection };
|
|
159
|
-
}
|
|
160
|
-
/** Number of scenes that have finished (not currently running). */
|
|
161
|
-
export function completedSceneCount(state) {
|
|
162
|
-
return state.scenes.filter((s) => s.status !== 'running').length;
|
|
163
|
-
}
|
|
164
|
-
//# sourceMappingURL=store.js.map
|
package/dist/store.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/styles.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The widget's stylesheet, injected into its shadow root. The only theming
|
|
3
|
-
* surface is the small set of `--st-*` custom properties on `:host`; every
|
|
4
|
-
* internal color derives from them or from a fixed terminal palette. A host
|
|
5
|
-
* may set `--st-bg`, `--st-accent`, `--st-font`, `--st-font-size` (and nothing
|
|
6
|
-
* else) to retheme the pane. These are versioned with the widget, like the
|
|
7
|
-
* wire protocol.
|
|
8
|
-
*/
|
|
9
|
-
export declare const STYLES = "\n:host {\n /* \u2500\u2500 Theming surface (host may override these four) \u2500\u2500 */\n --st-bg: #0f1117;\n --st-accent: #3b82f6;\n --st-font: 'SF Mono', 'Cascadia Code', 'Fira Code', ui-monospace, monospace;\n --st-font-size: 13px;\n\n /* \u2500\u2500 Internal palette (derived; not a public surface) \u2500\u2500 */\n --bg: var(--st-bg);\n --bg2: #1a1d27;\n --bg3: #252833;\n --border: #2e3140;\n --text: #e1e4ed;\n --text2: #8b8fa3;\n --green: #22c55e;\n --red: #ef4444;\n --amber: #f59e0b;\n --blue: var(--st-accent);\n\n display: block;\n font-family: var(--st-font);\n font-size: var(--st-font-size);\n color: var(--text);\n background: var(--bg);\n}\n\n* { margin: 0; padding: 0; box-sizing: border-box; }\n\n.root { min-height: 100%; background: var(--bg); }\n\nheader {\n position: sticky;\n top: 0;\n z-index: 10;\n padding: 12px 20px;\n border-bottom: 1px solid var(--border);\n background: var(--bg2);\n display: flex;\n align-items: center;\n gap: 14px;\n flex-wrap: wrap;\n}\nheader.running .logo { animation: pulse 1.2s ease-in-out infinite; }\n\nh1 { font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 8px; }\n.logo {\n display: inline-flex; align-items: center; justify-content: center;\n width: 22px; height: 22px; border-radius: 5px;\n background: var(--blue); color: #fff; font-weight: 700;\n}\n\nbutton {\n font-family: inherit; font-size: 12px; cursor: pointer;\n border: 1px solid var(--border); background: var(--bg3); color: var(--text);\n padding: 5px 10px; border-radius: 5px; display: inline-flex; align-items: center; gap: 6px;\n}\nbutton:hover:not(:disabled) { border-color: var(--blue); }\nbutton:disabled { opacity: 0.5; cursor: default; }\n.replay-all-btn { color: var(--green); }\n.stop-btn { color: var(--red); }\n\n.team-select-wrap { font-size: 12px; color: var(--text2); display: flex; align-items: center; gap: 6px; }\nselect {\n font-family: inherit; font-size: 12px; background: var(--bg3); color: var(--text);\n border: 1px solid var(--border); border-radius: 5px; padding: 4px 6px;\n}\n\n.spacer { flex: 1; }\n\n.stats { display: flex; align-items: center; gap: 14px; font-size: 12px; }\n.stat { display: flex; align-items: center; gap: 5px; }\n.stat .label { color: var(--text2); }\n.stat .value { font-weight: 600; }\n.stat.pass .value { color: var(--green); }\n.stat.fail .value { color: var(--red); }\n\n.conn { width: 9px; height: 9px; border-radius: 50%; background: var(--text2); }\n.conn.connected { background: var(--green); }\n.conn.disconnected { background: var(--red); }\n\n.progress { flex-basis: 100%; height: 3px; background: var(--bg3); border-radius: 2px; overflow: hidden; }\n.progress-fill { height: 100%; width: 0; background: var(--blue); transition: width 0.2s ease; }\n.progress.done .progress-fill { background: var(--green); }\n.progress.has-failures .progress-fill { background: var(--red); }\n\nmain { padding: 16px 20px; }\n.waiting { text-align: center; color: var(--text2); padding: 60px 20px; }\n.waiting h2 { font-size: 16px; font-weight: 500; margin-bottom: 8px; color: var(--text); }\n.waiting code { background: var(--bg3); padding: 2px 6px; border-radius: 4px; }\n\n.scene {\n border: 1px solid var(--border); border-radius: 8px; background: var(--bg2);\n margin-bottom: 14px; overflow: hidden;\n}\n.scene.failed { border-color: var(--red); }\n.scene-head {\n display: flex; align-items: center; gap: 10px; padding: 10px 14px;\n border-bottom: 1px solid var(--border); background: var(--bg3);\n}\n.scene-status { font-weight: 700; }\n.scene-status.completed { color: var(--green); }\n.scene-status.failed, .scene-status.timeout { color: var(--red); }\n.scene-status.running { color: var(--amber); }\n.scene-name { font-weight: 600; }\n.scene-file { color: var(--text2); font-size: 11px; }\n.scene-team {\n font-size: 11px; color: var(--blue); border: 1px solid var(--border);\n padding: 1px 6px; border-radius: 10px;\n}\n.scene-dur { color: var(--text2); font-size: 11px; margin-left: auto; }\n.copy-btn { padding: 3px 7px; font-size: 11px; }\n.copy-btn.copied { color: var(--green); border-color: var(--green); }\n\n.lanes { padding: 8px 14px; display: flex; flex-direction: column; gap: 6px; }\n.lane { display: flex; align-items: flex-start; gap: 8px; }\n.lane-actor { color: var(--text2); min-width: 90px; font-size: 11px; padding-top: 3px; }\n.lane-items { display: flex; flex-wrap: wrap; gap: 4px; }\n.pill {\n font-size: 11px; padding: 2px 7px; border-radius: 4px;\n border: 1px solid var(--border); background: var(--bg3); color: var(--text);\n}\n.pill.running { border-color: var(--amber); color: var(--amber); }\n.pill.success { border-color: var(--green); }\n.pill.slow { border-color: var(--amber); }\n.pill.error { border-color: var(--red); color: var(--red); }\n.pill .tgt { color: var(--text2); }\n\n.assertions { padding: 0 14px 10px; display: flex; flex-direction: column; gap: 3px; }\n.assert { font-size: 12px; display: flex; gap: 6px; align-items: baseline; }\n.assert .mark { font-weight: 700; }\n.assert.ok .mark { color: var(--green); }\n.assert.bad .mark { color: var(--red); }\n.assert .who { color: var(--text2); }\n\n.scene-error {\n margin: 0 14px 12px; padding: 8px 10px; border-radius: 6px;\n background: rgba(239, 68, 68, 0.1); border: 1px solid var(--red);\n color: var(--red); font-size: 12px; white-space: pre-wrap; cursor: pointer;\n}\n\n@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }\n";
|
|
10
|
-
//# sourceMappingURL=styles.d.ts.map
|
package/dist/styles.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,o4KA8IlB,CAAA"}
|