@midscene/visualizer 0.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.
Files changed (92) hide show
  1. package/.eslintrc.js +9 -0
  2. package/README.md +24 -0
  3. package/dist/es/assets/logo-plain.16842bbc.svg +70 -0
  4. package/dist/es/assets/logo-plain2.16842bbc.svg +70 -0
  5. package/dist/es/component/blackboard.css +25 -0
  6. package/dist/es/component/blackboard.js +256 -0
  7. package/dist/es/component/color.js +34 -0
  8. package/dist/es/component/common.css +0 -0
  9. package/dist/es/component/detail-panel.css +34 -0
  10. package/dist/es/component/detail-panel.js +106 -0
  11. package/dist/es/component/detail-side.css +99 -0
  12. package/dist/es/component/detail-side.js +285 -0
  13. package/dist/es/component/global-hover-preview.css +19 -0
  14. package/dist/es/component/global-hover-preview.js +44 -0
  15. package/dist/es/component/misc.js +24 -0
  16. package/dist/es/component/panel-title.css +8 -0
  17. package/dist/es/component/panel-title.js +9 -0
  18. package/dist/es/component/side-item.js +0 -0
  19. package/dist/es/component/sidebar.css +87 -0
  20. package/dist/es/component/sidebar.js +175 -0
  21. package/dist/es/component/store.js +128 -0
  22. package/dist/es/component/timeline.css +18 -0
  23. package/dist/es/component/timeline.js +438 -0
  24. package/dist/es/index.css +89 -0
  25. package/dist/es/index.js +174 -0
  26. package/dist/es/utils.js +76 -0
  27. package/dist/lib/assets/logo-plain.16842bbc.svg +70 -0
  28. package/dist/lib/assets/logo-plain2.16842bbc.svg +70 -0
  29. package/dist/lib/component/blackboard.css +25 -0
  30. package/dist/lib/component/blackboard.js +286 -0
  31. package/dist/lib/component/color.js +59 -0
  32. package/dist/lib/component/common.css +0 -0
  33. package/dist/lib/component/detail-panel.css +34 -0
  34. package/dist/lib/component/detail-panel.js +136 -0
  35. package/dist/lib/component/detail-side.css +99 -0
  36. package/dist/lib/component/detail-side.js +313 -0
  37. package/dist/lib/component/global-hover-preview.css +19 -0
  38. package/dist/lib/component/global-hover-preview.js +64 -0
  39. package/dist/lib/component/misc.js +48 -0
  40. package/dist/lib/component/panel-title.css +8 -0
  41. package/dist/lib/component/panel-title.js +29 -0
  42. package/dist/lib/component/side-item.js +1 -0
  43. package/dist/lib/component/sidebar.css +87 -0
  44. package/dist/lib/component/sidebar.js +198 -0
  45. package/dist/lib/component/store.js +153 -0
  46. package/dist/lib/component/timeline.css +18 -0
  47. package/dist/lib/component/timeline.js +466 -0
  48. package/dist/lib/index.css +89 -0
  49. package/dist/lib/index.js +202 -0
  50. package/dist/lib/utils.js +111 -0
  51. package/dist/types/component/blackboard.d.ts +4 -0
  52. package/dist/types/component/color.d.ts +2 -0
  53. package/dist/types/component/detail-panel.d.ts +4 -0
  54. package/dist/types/component/detail-side.d.ts +4 -0
  55. package/dist/types/component/global-hover-preview.d.ts +4 -0
  56. package/dist/types/component/misc.d.ts +2 -0
  57. package/dist/types/component/panel-title.d.ts +6 -0
  58. package/dist/types/component/side-item.d.ts +0 -0
  59. package/dist/types/component/sidebar.d.ts +4 -0
  60. package/dist/types/component/store.d.ts +35 -0
  61. package/dist/types/component/timeline.d.ts +4 -0
  62. package/dist/types/index.d.ts +4 -0
  63. package/dist/types/utils.d.ts +5 -0
  64. package/docs/index.tsx +6 -0
  65. package/modern.config.ts +15 -0
  66. package/package.json +46 -0
  67. package/src/component/assets/logo-plain.svg +70 -0
  68. package/src/component/assets/logo-plain2.svg +70 -0
  69. package/src/component/blackboard.less +37 -0
  70. package/src/component/blackboard.tsx +293 -0
  71. package/src/component/color.tsx +34 -0
  72. package/src/component/common.less +21 -0
  73. package/src/component/detail-panel.less +47 -0
  74. package/src/component/detail-panel.tsx +124 -0
  75. package/src/component/detail-side.less +131 -0
  76. package/src/component/detail-side.tsx +361 -0
  77. package/src/component/global-hover-preview.less +23 -0
  78. package/src/component/global-hover-preview.tsx +50 -0
  79. package/src/component/misc.tsx +20 -0
  80. package/src/component/panel-title.less +11 -0
  81. package/src/component/panel-title.tsx +11 -0
  82. package/src/component/side-item.tsx +0 -0
  83. package/src/component/sidebar.less +122 -0
  84. package/src/component/sidebar.tsx +205 -0
  85. package/src/component/store.tsx +151 -0
  86. package/src/component/timeline.less +25 -0
  87. package/src/component/timeline.tsx +486 -0
  88. package/src/global.d.ts +11 -0
  89. package/src/index.less +113 -0
  90. package/src/index.tsx +210 -0
  91. package/src/utils.ts +58 -0
  92. package/tsconfig.json +24 -0
@@ -0,0 +1,438 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __async = (__this, __arguments, generator) => {
21
+ return new Promise((resolve, reject) => {
22
+ var fulfilled = (value) => {
23
+ try {
24
+ step(generator.next(value));
25
+ } catch (e) {
26
+ reject(e);
27
+ }
28
+ };
29
+ var rejected = (value) => {
30
+ try {
31
+ step(generator.throw(value));
32
+ } catch (e) {
33
+ reject(e);
34
+ }
35
+ };
36
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
37
+ step((generator = generator.apply(__this, __arguments)).next());
38
+ });
39
+ };
40
+ import { jsx } from "react/jsx-runtime";
41
+ import { useEffect, useMemo, useRef } from "react";
42
+ import * as PIXI from "pixi.js";
43
+ import "./timeline.css";
44
+ import { useAllCurrentTasks, useExecutionDump } from "./store";
45
+ function cloneSprite(sprite) {
46
+ const clonedSprite = new PIXI.Sprite(sprite.texture);
47
+ clonedSprite.position.copyFrom(sprite.position);
48
+ clonedSprite.scale.copyFrom(sprite.scale);
49
+ clonedSprite.rotation = sprite.rotation;
50
+ clonedSprite.alpha = sprite.alpha;
51
+ clonedSprite.visible = sprite.visible;
52
+ return clonedSprite;
53
+ }
54
+ const TimelineWidget = (props) => {
55
+ var _a, _b, _c, _d;
56
+ const domRef = useRef(null);
57
+ const app = useMemo(() => new PIXI.Application(), []);
58
+ const gridsContainer = useMemo(() => new PIXI.Container(), []);
59
+ const screenshotsContainer = useMemo(() => new PIXI.Container(), []);
60
+ const highlightMaskContainer = useMemo(() => new PIXI.Container(), []);
61
+ const containerUpdaterRef = useRef(
62
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
63
+ (_s, _e, _hs, _he) => {
64
+ }
65
+ );
66
+ const indicatorContainer = useMemo(() => new PIXI.Container(), []);
67
+ const allScreenshots = props.screenshots || [];
68
+ const maxTime = allScreenshots[allScreenshots.length - 1].timeOffset;
69
+ const sizeRatio = 2;
70
+ const titleBg = 14540253;
71
+ const sideBg = 15527148;
72
+ const gridTextColor = 0;
73
+ const shotBorderColor = 7829367;
74
+ const gridLineColor = 13421772;
75
+ const gridHighlightColor = 438699;
76
+ const timeContentFontSize = 20;
77
+ const commonPadding = 12;
78
+ const timeTextTop = commonPadding;
79
+ const timeTitleBottom = timeTextTop * 2 + timeContentFontSize;
80
+ const highlightMaskAlpha = 0.6;
81
+ const hoverMaskAlpha = 0.3;
82
+ const closestScreenshotItemOnXY = (x, _y) => {
83
+ let closestScreenshot;
84
+ let closestIndex = -1;
85
+ for (let i = 0; i < allScreenshots.length; i++) {
86
+ const shot = allScreenshots[i];
87
+ if (shot.x <= x) {
88
+ closestScreenshot = allScreenshots[i];
89
+ closestIndex = i;
90
+ } else {
91
+ break;
92
+ }
93
+ }
94
+ return {
95
+ closestScreenshot,
96
+ closestIndex
97
+ };
98
+ };
99
+ useMemo(() => {
100
+ const { startMs, endMs } = props.highlightMask || {};
101
+ const { startMs: hoverStartMs, endMs: hoverEndMs } = props.hoverMask || {};
102
+ const fn = containerUpdaterRef.current;
103
+ fn(startMs, endMs, hoverStartMs, hoverEndMs);
104
+ }, [
105
+ (_a = props.highlightMask) == null ? void 0 : _a.startMs,
106
+ (_b = props.highlightMask) == null ? void 0 : _b.endMs,
107
+ (_c = props.hoverMask) == null ? void 0 : _c.startMs,
108
+ (_d = props.hoverMask) == null ? void 0 : _d.endMs
109
+ ]);
110
+ useEffect(() => {
111
+ Promise.resolve(
112
+ (() => __async(void 0, null, function* () {
113
+ var _a2, _b2;
114
+ if (!domRef.current) {
115
+ return;
116
+ }
117
+ const { clientWidth, clientHeight } = domRef.current;
118
+ const canvasWidth = clientWidth * sizeRatio;
119
+ const canvasHeight = clientHeight * sizeRatio;
120
+ let singleGridWidth = 100 * sizeRatio;
121
+ let gridCount = Math.floor(canvasWidth / singleGridWidth);
122
+ const stepCandidate = [
123
+ 50,
124
+ 100,
125
+ 200,
126
+ 300,
127
+ 500,
128
+ 1e3,
129
+ 2e3,
130
+ 3e3,
131
+ 5e3,
132
+ 6e3,
133
+ 8e3,
134
+ 9e3,
135
+ 1e4,
136
+ 2e4,
137
+ 3e4,
138
+ 4e4,
139
+ 6e4,
140
+ 9e4,
141
+ 12e3,
142
+ 3e5
143
+ ];
144
+ let timeStep = stepCandidate[0];
145
+ for (let i = stepCandidate.length - 1; i >= 0; i--) {
146
+ if (gridCount * stepCandidate[i] >= maxTime) {
147
+ timeStep = stepCandidate[i];
148
+ }
149
+ }
150
+ const gridRatio = maxTime / (gridCount * timeStep);
151
+ if (gridRatio <= 0.8) {
152
+ singleGridWidth = Math.floor(singleGridWidth * (1 / gridRatio) * 0.9);
153
+ gridCount = Math.floor(canvasWidth / singleGridWidth);
154
+ }
155
+ const leftForTimeOffset = (timeOffset) => {
156
+ return Math.floor(singleGridWidth * timeOffset / timeStep);
157
+ };
158
+ const timeOffsetForLeft = (left) => {
159
+ return Math.floor(left * timeStep / singleGridWidth);
160
+ };
161
+ yield app.init({
162
+ width: canvasWidth,
163
+ height: canvasHeight,
164
+ backgroundColor: sideBg
165
+ });
166
+ if (!domRef.current) {
167
+ app.destroy();
168
+ return;
169
+ }
170
+ domRef.current.replaceChildren(app.canvas);
171
+ const pixiTextForNumber = (num) => {
172
+ const textContent = `${num}ms`;
173
+ const text = new PIXI.Text(`${textContent}`, {
174
+ fontSize: timeContentFontSize,
175
+ fill: gridTextColor
176
+ });
177
+ return text;
178
+ };
179
+ gridsContainer.removeChildren();
180
+ const titleBgSection = new PIXI.Graphics();
181
+ titleBgSection.beginFill(titleBg);
182
+ titleBgSection.drawRect(0, 0, canvasWidth, timeTitleBottom);
183
+ titleBgSection.endFill();
184
+ gridsContainer.addChild(titleBgSection);
185
+ const gridHeight = canvasHeight;
186
+ for (let i = 1; i <= gridCount; i++) {
187
+ const gridLine = new PIXI.Graphics();
188
+ const gridLineLeft = leftForTimeOffset(i * timeStep);
189
+ gridLine.beginFill(gridLineColor);
190
+ gridLine.drawRect(gridLineLeft, 0, sizeRatio, gridHeight);
191
+ gridLine.endFill();
192
+ gridsContainer.addChild(gridLine);
193
+ const text = pixiTextForNumber(i * timeStep);
194
+ const textLeft = gridLineLeft - text.width - commonPadding;
195
+ text.x = textLeft;
196
+ text.y = timeTextTop;
197
+ gridsContainer.addChild(text);
198
+ }
199
+ app.stage.addChild(gridsContainer);
200
+ if (!allScreenshots.length) {
201
+ console.warn("No screenshots found");
202
+ return;
203
+ }
204
+ const shotContainers = [];
205
+ screenshotsContainer.removeChildren();
206
+ const screenshotTop = timeTitleBottom + commonPadding * 1.5;
207
+ const screenshotMaxHeight = canvasHeight - screenshotTop - commonPadding * 1.5;
208
+ allScreenshots.forEach((screenshot, index) => {
209
+ const container = new PIXI.Container();
210
+ shotContainers.push(container);
211
+ app.stage.addChild(container);
212
+ const img = new Image();
213
+ img.src = screenshot.img;
214
+ img.onload = () => {
215
+ const screenshotTexture = PIXI.Texture.from(img);
216
+ const screenshotSprite = new PIXI.Sprite(screenshotTexture);
217
+ const originalWidth = img.width;
218
+ const originalHeight = img.height;
219
+ const screenshotHeight = screenshotMaxHeight;
220
+ const screenshotWidth = Math.floor(screenshotHeight / originalHeight * originalWidth);
221
+ const screenshotX = leftForTimeOffset(screenshot.timeOffset);
222
+ allScreenshots[index].x = screenshotX;
223
+ allScreenshots[index].y = screenshotTop;
224
+ allScreenshots[index].width = screenshotWidth;
225
+ allScreenshots[index].height = screenshotMaxHeight;
226
+ const border = new PIXI.Graphics();
227
+ border.lineStyle(sizeRatio, shotBorderColor, 1);
228
+ border.drawRect(screenshotX, screenshotTop, screenshotWidth, screenshotMaxHeight);
229
+ border.endFill();
230
+ container.addChild(border);
231
+ screenshotSprite.x = screenshotX;
232
+ screenshotSprite.y = screenshotTop;
233
+ screenshotSprite.width = screenshotWidth;
234
+ screenshotSprite.height = screenshotMaxHeight;
235
+ container.addChild(screenshotSprite);
236
+ };
237
+ });
238
+ const highlightMaskUpdater = (start, end, hoverStart, hoverEnd) => {
239
+ highlightMaskContainer.removeChildren();
240
+ const mask = (start2, end2, alpha) => {
241
+ if (typeof start2 === "undefined" || typeof end2 === "undefined" || end2 === 0) {
242
+ return;
243
+ }
244
+ const leftBorder = new PIXI.Graphics();
245
+ leftBorder.beginFill(gridHighlightColor, 1);
246
+ leftBorder.drawRect(leftForTimeOffset(start2), 0, sizeRatio, canvasHeight);
247
+ leftBorder.endFill();
248
+ highlightMaskContainer.addChild(leftBorder);
249
+ const rightBorder = new PIXI.Graphics();
250
+ rightBorder.beginFill(gridHighlightColor, 1);
251
+ rightBorder.drawRect(leftForTimeOffset(end2), 0, sizeRatio, canvasHeight);
252
+ rightBorder.endFill();
253
+ highlightMaskContainer.addChild(rightBorder);
254
+ const mask2 = new PIXI.Graphics();
255
+ mask2.beginFill(gridHighlightColor, alpha);
256
+ mask2.drawRect(
257
+ leftForTimeOffset(start2),
258
+ 0,
259
+ leftForTimeOffset(end2) - leftForTimeOffset(start2),
260
+ canvasHeight
261
+ );
262
+ mask2.endFill();
263
+ highlightMaskContainer.addChild(mask2);
264
+ };
265
+ mask(start, end, highlightMaskAlpha);
266
+ mask(hoverStart, hoverEnd, hoverMaskAlpha);
267
+ };
268
+ highlightMaskUpdater((_a2 = props.highlightMask) == null ? void 0 : _a2.startMs, (_b2 = props.highlightMask) == null ? void 0 : _b2.endMs, 0, 0);
269
+ containerUpdaterRef.current = highlightMaskUpdater;
270
+ app.stage.interactive = true;
271
+ const onPointerMove = (event) => {
272
+ var _a3, _b3;
273
+ const x = event.offsetX * sizeRatio;
274
+ const y = event.offsetY * sizeRatio;
275
+ indicatorContainer.removeChildren();
276
+ const { closestScreenshot, closestIndex } = closestScreenshotItemOnXY(x, y);
277
+ if (closestIndex < 0) {
278
+ (_a3 = props.onUnhighlight) == null ? void 0 : _a3.call(props);
279
+ return;
280
+ }
281
+ const closestContainer = shotContainers[closestIndex];
282
+ closestContainer.children.forEach((child) => {
283
+ if (child instanceof PIXI.Sprite) {
284
+ const newSpirit = new PIXI.Graphics();
285
+ newSpirit.lineStyle(2, gridHighlightColor, 1);
286
+ newSpirit.drawRect(
287
+ x,
288
+ // follow mouse
289
+ closestScreenshot.y,
290
+ closestScreenshot.width,
291
+ closestScreenshot.height
292
+ );
293
+ newSpirit.endFill();
294
+ indicatorContainer.addChild(newSpirit);
295
+ const screenshotSpirit = cloneSprite(child);
296
+ screenshotSpirit.x = x;
297
+ indicatorContainer.addChild(screenshotSpirit);
298
+ }
299
+ });
300
+ const indicator = new PIXI.Graphics();
301
+ indicator.beginFill(gridHighlightColor, 1);
302
+ indicator.drawRect(x - 1, 0, 3, canvasHeight);
303
+ indicator.endFill();
304
+ indicatorContainer.addChild(indicator);
305
+ const text = pixiTextForNumber(timeOffsetForLeft(x));
306
+ text.x = x + 5;
307
+ text.y = timeTextTop;
308
+ const textBg = new PIXI.Graphics();
309
+ textBg.beginFill(titleBg, 1);
310
+ textBg.drawRect(text.x, text.y, text.width + 10, text.height);
311
+ textBg.endFill();
312
+ indicatorContainer.addChild(textBg);
313
+ indicatorContainer.addChild(text);
314
+ (_b3 = props.onHighlight) == null ? void 0 : _b3.call(props, {
315
+ mouseX: x / sizeRatio,
316
+ mouseY: y / sizeRatio,
317
+ item: closestScreenshot
318
+ });
319
+ };
320
+ const onPointerOut = () => {
321
+ var _a3;
322
+ indicatorContainer.removeChildren();
323
+ (_a3 = props.onUnhighlight) == null ? void 0 : _a3.call(props);
324
+ };
325
+ const onPointerTap = (event) => {
326
+ var _a3;
327
+ const x = event.offsetX * sizeRatio;
328
+ const y = event.offsetY * sizeRatio;
329
+ const { closestScreenshot } = closestScreenshotItemOnXY(x, y);
330
+ if (closestScreenshot) {
331
+ (_a3 = props.onTap) == null ? void 0 : _a3.call(props, closestScreenshot);
332
+ }
333
+ };
334
+ app.stage.addChild(screenshotsContainer);
335
+ app.stage.addChild(highlightMaskContainer);
336
+ app.stage.addChild(indicatorContainer);
337
+ const canvas = app.view;
338
+ canvas.addEventListener("pointermove", onPointerMove);
339
+ canvas.addEventListener("pointerout", onPointerOut);
340
+ canvas.addEventListener("pointerdown", onPointerTap);
341
+ }))()
342
+ );
343
+ }, []);
344
+ return /* @__PURE__ */ jsx("div", { className: "timeline-canvas-wrapper", ref: domRef });
345
+ };
346
+ const Timeline = () => {
347
+ const allTasks = useAllCurrentTasks();
348
+ const wrapper = useRef(null);
349
+ const setActiveTask = useExecutionDump((store) => store.setActiveTask);
350
+ const activeTask = useExecutionDump((store) => store.activeTask);
351
+ const hoverTask = useExecutionDump((store) => store.hoverTask);
352
+ const setHoverTask = useExecutionDump((store) => store.setHoverTask);
353
+ const setHoverPreviewConfig = useExecutionDump((store) => store.setHoverPreviewConfig);
354
+ let startingTime = -1;
355
+ let idCount = 1;
356
+ const idTaskMap = {};
357
+ const allScreenshots = allTasks.reduce((acc, current) => {
358
+ var _a;
359
+ const recorders = current.recorder || [];
360
+ recorders.forEach((item) => {
361
+ if (startingTime === -1 || startingTime > item.ts) {
362
+ startingTime = item.ts;
363
+ }
364
+ });
365
+ if (((_a = current.timing) == null ? void 0 : _a.start) && (startingTime === -1 || startingTime > current.timing.start)) {
366
+ startingTime = current.timing.start;
367
+ }
368
+ const recorderItemWithId = recorders.map((item) => {
369
+ const idStr = `id_${idCount++}`;
370
+ idTaskMap[idStr] = current;
371
+ return __spreadProps(__spreadValues({}, item), {
372
+ id: idStr
373
+ });
374
+ });
375
+ return acc.concat(recorderItemWithId || []);
376
+ }, []).filter((item) => {
377
+ return item.screenshot;
378
+ }).map((recorderItem) => {
379
+ return {
380
+ id: recorderItem.id,
381
+ img: recorderItem.screenshot,
382
+ timeOffset: recorderItem.ts - startingTime
383
+ };
384
+ }).sort((a, b) => a.timeOffset - b.timeOffset);
385
+ const itemOnTap = (item) => {
386
+ const task = idTaskMap[item.id];
387
+ if (task) {
388
+ setActiveTask(task);
389
+ }
390
+ };
391
+ const onHighlightItem = (param) => {
392
+ var _a;
393
+ const { mouseX, item } = param;
394
+ const refBounding = (_a = wrapper.current) == null ? void 0 : _a.getBoundingClientRect();
395
+ const task = idTaskMap[item.id];
396
+ if (task) {
397
+ setHoverTask(task);
398
+ setHoverPreviewConfig({
399
+ x: mouseX + ((refBounding == null ? void 0 : refBounding.left) || 0),
400
+ y: ((refBounding == null ? void 0 : refBounding.bottom) || 1) - 1
401
+ });
402
+ } else {
403
+ setHoverTask(null);
404
+ setHoverPreviewConfig(null);
405
+ }
406
+ };
407
+ const unhighlight = () => {
408
+ setHoverTask(null);
409
+ setHoverPreviewConfig(null);
410
+ };
411
+ const maskConfigForTask = (task) => {
412
+ var _a, _b;
413
+ if (!task) {
414
+ return void 0;
415
+ }
416
+ return ((_a = task.timing) == null ? void 0 : _a.start) && ((_b = task.timing) == null ? void 0 : _b.end) ? {
417
+ startMs: task.timing.start - startingTime || 0,
418
+ endMs: task.timing.end - startingTime || 0
419
+ } : void 0;
420
+ };
421
+ const highlightMaskConfig = maskConfigForTask(activeTask);
422
+ const hoverMaskConfig = maskConfigForTask(hoverTask);
423
+ return /* @__PURE__ */ jsx("div", { className: "timeline-wrapper", ref: wrapper, children: /* @__PURE__ */ jsx(
424
+ TimelineWidget,
425
+ {
426
+ screenshots: allScreenshots,
427
+ onTap: itemOnTap,
428
+ onHighlight: onHighlightItem,
429
+ onUnhighlight: unhighlight,
430
+ highlightMask: highlightMaskConfig,
431
+ hoverMask: hoverMaskConfig
432
+ }
433
+ ) });
434
+ };
435
+ var timeline_default = Timeline;
436
+ export {
437
+ timeline_default as default
438
+ };
@@ -0,0 +1,89 @@
1
+ html,
2
+ body {
3
+ padding: 0;
4
+ margin: 0;
5
+ font-family:
6
+ PingFang SC,
7
+ Hiragino Sans GB,
8
+ Microsoft YaHei,
9
+ Arial,
10
+ sans-serif;
11
+ font-size: 14px;
12
+ }
13
+ :root {
14
+ --modern-sidebar-width: 0 !important;
15
+ --modern-aside-width: 0 !important;
16
+ --modern-preview-padding: 0 !important;
17
+ }
18
+ .modern-doc-layout,
19
+ .modern-doc {
20
+ width: 100% !important;
21
+ margin: 0 !important;
22
+ padding: 0 !important;
23
+ height: 100vh;
24
+ }
25
+ .modern-sidebar,
26
+ header.w-full {
27
+ display: none !important;
28
+ }
29
+ .modern-doc-container {
30
+ padding: 0 !important;
31
+ }
32
+ footer.mt-8 {
33
+ display: none;
34
+ }
35
+ .page-container {
36
+ display: flex;
37
+ flex-direction: column;
38
+ height: 100%;
39
+ color: #000;
40
+ }
41
+ .ant-layout {
42
+ flex-grow: 1;
43
+ height: 100%;
44
+ }
45
+ .main-right {
46
+ display: flex;
47
+ flex-direction: column;
48
+ width: 100%;
49
+ height: 100%;
50
+ box-sizing: border-box;
51
+ }
52
+ .main-right .main-content {
53
+ display: flex;
54
+ flex-direction: row;
55
+ flex-grow: 1;
56
+ overflow: hidden;
57
+ background: #ECECEC;
58
+ }
59
+ .main-right.uploader-wrapper {
60
+ box-sizing: border-box;
61
+ margin: auto;
62
+ max-width: 800px;
63
+ flex-direction: column;
64
+ justify-content: center;
65
+ }
66
+ .main-right.uploader-wrapper .uploader {
67
+ width: 100%;
68
+ }
69
+ .main-right.uploader-wrapper .demo-loader {
70
+ width: 100%;
71
+ text-align: center;
72
+ margin-top: 10px;
73
+ }
74
+ .main-right .main-canvas-container {
75
+ flex-grow: 1;
76
+ height: 100%;
77
+ background: #F5F5F5;
78
+ overflow-x: hidden;
79
+ overflow-y: scroll;
80
+ border-left: 1px solid #CCCCCC;
81
+ }
82
+ .main-right .main-side {
83
+ box-sizing: border-box;
84
+ overflow-y: scroll;
85
+ }
86
+ .main-right .json-content {
87
+ word-wrap: break-word;
88
+ white-space: pre-wrap;
89
+ }
@@ -0,0 +1,174 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ import "./index.css";
22
+ import { ConfigProvider, message, Upload, Button } from "antd";
23
+ import { useEffect, useRef, useState } from "react";
24
+ import { Helmet } from "@modern-js/runtime/head";
25
+ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
26
+ import Timeline from "./component/timeline";
27
+ import DetailPanel from "./component/detail-panel";
28
+ import logo from "./assets/logo-plain.16842bbc.svg";
29
+ import GlobalHoverPreview from "./component/global-hover-preview";
30
+ import { useExecutionDump } from "./component/store";
31
+ import DetailSide from "./component/detail-side";
32
+ import Sidebar from "./component/sidebar";
33
+ const { Dragger } = Upload;
34
+ const Index = () => {
35
+ const executionDump = useExecutionDump((store) => store.dump);
36
+ const setGroupedDump = useExecutionDump((store) => store.setGroupedDump);
37
+ const reset = useExecutionDump((store) => store.reset);
38
+ const [mainLayoutChangeFlag, setMainLayoutChangeFlag] = useState(0);
39
+ const mainLayoutChangedRef = useRef(false);
40
+ useEffect(() => {
41
+ return () => {
42
+ reset();
43
+ };
44
+ }, []);
45
+ useEffect(() => {
46
+ const onResize = () => {
47
+ setMainLayoutChangeFlag((prev) => prev + 1);
48
+ };
49
+ window.addEventListener("resize", onResize);
50
+ return () => {
51
+ window.removeEventListener("resize", onResize);
52
+ };
53
+ }, []);
54
+ const uploadProps = {
55
+ name: "file",
56
+ multiple: false,
57
+ capture: false,
58
+ customRequest: () => {
59
+ },
60
+ beforeUpload(file) {
61
+ const ifValidFile = file.name.endsWith("web-dump.json");
62
+ if (!ifValidFile) {
63
+ message.error("invalid file extension");
64
+ return false;
65
+ }
66
+ const reader = new FileReader();
67
+ reader.readAsText(file);
68
+ reader.onload = (e) => {
69
+ var _a;
70
+ const result = (_a = e.target) == null ? void 0 : _a.result;
71
+ if (typeof result === "string") {
72
+ try {
73
+ const data = JSON.parse(result);
74
+ setGroupedDump(data);
75
+ } catch (e2) {
76
+ console.error(e2);
77
+ message.error("failed to parse dump data", e2.message);
78
+ }
79
+ } else {
80
+ message.error("Invalid dump file");
81
+ }
82
+ };
83
+ return false;
84
+ }
85
+ };
86
+ const loadTasksDemo = () => {
87
+ };
88
+ const loadInsightDemo = () => {
89
+ };
90
+ let mainContent;
91
+ if (!executionDump) {
92
+ mainContent = /* @__PURE__ */ jsxs("div", { className: "main-right uploader-wrapper", children: [
93
+ /* @__PURE__ */ jsxs(Dragger, __spreadProps(__spreadValues({ className: "uploader" }, uploadProps), { children: [
94
+ /* @__PURE__ */ jsx("p", { className: "ant-upload-drag-icon", children: /* @__PURE__ */ jsx("img", { src: logo, alt: "Logo", style: { width: 100, height: 100, margin: "auto" } }) }),
95
+ /* @__PURE__ */ jsxs("p", { className: "ant-upload-text", children: [
96
+ "Click or drag the",
97
+ " ",
98
+ /* @__PURE__ */ jsx("b", { children: /* @__PURE__ */ jsx("i", { children: ".web-dump.json" }) }),
99
+ " ",
100
+ "file into this area."
101
+ ] }),
102
+ /* @__PURE__ */ jsxs("p", { className: "ant-upload-text", children: [
103
+ "The latest dump file is usually placed in",
104
+ " ",
105
+ /* @__PURE__ */ jsx("b", { children: /* @__PURE__ */ jsx("i", { children: "./midscene_run/" }) })
106
+ ] }),
107
+ /* @__PURE__ */ jsx("p", { className: "ant-upload-text", children: "All data will be processed locally by the browser. No data will be sent to the server." })
108
+ ] })),
109
+ /* @__PURE__ */ jsxs("div", { className: "demo-loader", children: [
110
+ /* @__PURE__ */ jsx(Button, { type: "link", onClick: loadTasksDemo, children: "Load Tasks Demo" }),
111
+ /* @__PURE__ */ jsx(Button, { type: "link", onClick: loadInsightDemo, children: "Load Insight Demo" })
112
+ ] })
113
+ ] });
114
+ } else {
115
+ mainContent = /* @__PURE__ */ jsxs(
116
+ PanelGroup,
117
+ {
118
+ autoSaveId: "main-page-layout",
119
+ direction: "horizontal",
120
+ onLayout: () => {
121
+ if (!mainLayoutChangedRef.current) {
122
+ setMainLayoutChangeFlag((prev) => prev + 1);
123
+ }
124
+ },
125
+ children: [
126
+ /* @__PURE__ */ jsx(Panel, { maxSize: 95, children: /* @__PURE__ */ jsx(Sidebar, {}) }),
127
+ /* @__PURE__ */ jsx(
128
+ PanelResizeHandle,
129
+ {
130
+ onDragging: (isChanging) => {
131
+ if (mainLayoutChangedRef.current && !isChanging) {
132
+ setMainLayoutChangeFlag((prev) => prev + 1);
133
+ }
134
+ mainLayoutChangedRef.current = isChanging;
135
+ }
136
+ }
137
+ ),
138
+ /* @__PURE__ */ jsx(Panel, { defaultSize: 80, maxSize: 95, children: /* @__PURE__ */ jsxs("div", { className: "main-right", children: [
139
+ /* @__PURE__ */ jsx(Timeline, {}, mainLayoutChangeFlag),
140
+ /* @__PURE__ */ jsx("div", { className: "main-content", children: /* @__PURE__ */ jsxs(PanelGroup, { autoSaveId: "page-detail-layout", direction: "horizontal", children: [
141
+ /* @__PURE__ */ jsx(Panel, { maxSize: 95, children: /* @__PURE__ */ jsx("div", { className: "main-side", children: /* @__PURE__ */ jsx(DetailSide, {}) }) }),
142
+ /* @__PURE__ */ jsx(PanelResizeHandle, {}),
143
+ /* @__PURE__ */ jsx(Panel, { defaultSize: 75, maxSize: 95, children: /* @__PURE__ */ jsx("div", { className: "main-canvas-container", children: /* @__PURE__ */ jsx(DetailPanel, {}) }) })
144
+ ] }) })
145
+ ] }) })
146
+ ]
147
+ }
148
+ );
149
+ }
150
+ return /* @__PURE__ */ jsxs(
151
+ ConfigProvider,
152
+ {
153
+ theme: {
154
+ components: {
155
+ Layout: {
156
+ headerHeight: 60,
157
+ headerPadding: "0 30px",
158
+ headerBg: "#FFF",
159
+ bodyBg: "#FFF"
160
+ }
161
+ }
162
+ },
163
+ children: [
164
+ /* @__PURE__ */ jsx(Helmet, { children: /* @__PURE__ */ jsx("title", { children: "MidScene.js - Visualization Tool" }) }),
165
+ /* @__PURE__ */ jsx("div", { className: "page-container", children: mainContent }),
166
+ /* @__PURE__ */ jsx(GlobalHoverPreview, {})
167
+ ]
168
+ }
169
+ );
170
+ };
171
+ var src_default = Index;
172
+ export {
173
+ src_default as default
174
+ };