@lukekaalim/act-insight 1.0.0 → 2.0.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/InsightApp.module.css +36 -0
  3. package/InsightApp2.ts +82 -0
  4. package/TreeViewer.module.css +3 -8
  5. package/TreeViewer.ts +16 -12
  6. package/Virtual.ts +29 -11
  7. package/assets/icons/ancestor_column.png +0 -0
  8. package/assets/icons/ancestor_column.svg +26 -0
  9. package/assets/icons/ancestor_skip_row_column.png +0 -0
  10. package/assets/icons/ancestor_skip_row_column.svg +52 -0
  11. package/assets/icons/breakpoint.png +0 -0
  12. package/assets/icons/breakpoint.svg +33 -0
  13. package/assets/icons/breakpoint_arrow.png +0 -0
  14. package/assets/icons/breakpoint_arrow.svg +22 -0
  15. package/assets/icons/breakpoint_arrow_paused.png +0 -0
  16. package/assets/icons/breakpoint_arrow_paused.svg +38 -0
  17. package/assets/icons/breakpoint_panel.png +0 -0
  18. package/assets/icons/breakpoint_panel.svg +121 -0
  19. package/assets/icons/breakpoint_unset.png +0 -0
  20. package/assets/icons/breakpoint_unset.svg +26 -0
  21. package/assets/icons/bug.png +0 -0
  22. package/assets/icons/bug.svg +65 -0
  23. package/assets/icons/children.png +0 -0
  24. package/assets/icons/children.svg +38 -0
  25. package/assets/icons/collapse.png +0 -0
  26. package/assets/icons/collapse.svg +38 -0
  27. package/assets/icons/commit.png +0 -0
  28. package/assets/icons/commit.svg +30 -0
  29. package/assets/icons/commit_tree.png +0 -0
  30. package/assets/icons/commit_tree.svg +44 -0
  31. package/assets/icons/effect.png +0 -0
  32. package/assets/icons/effect.svg +28 -0
  33. package/assets/icons/expand.png +0 -0
  34. package/assets/icons/expand.svg +47 -0
  35. package/assets/icons/eye.png +0 -0
  36. package/assets/icons/eye.svg +36 -0
  37. package/assets/icons/eye_closed.png +0 -0
  38. package/assets/icons/eye_closed.svg +32 -0
  39. package/assets/icons/filter.png +0 -0
  40. package/assets/icons/filter.svg +22 -0
  41. package/assets/icons/graph.png +0 -0
  42. package/assets/icons/graph.svg +129 -0
  43. package/assets/icons/history_list.png +0 -0
  44. package/assets/icons/history_list.svg +60 -0
  45. package/assets/icons/hook.png +0 -0
  46. package/assets/icons/hook.svg +22 -0
  47. package/assets/icons/index.ts +76 -0
  48. package/assets/icons/inspector_panel.png +0 -0
  49. package/assets/icons/inspector_panel.svg +135 -0
  50. package/assets/icons/magnifying_glass.png +0 -0
  51. package/assets/icons/magnifying_glass.svg +39 -0
  52. package/assets/icons/pause.png +0 -0
  53. package/assets/icons/pause.svg +34 -0
  54. package/assets/icons/play.png +0 -0
  55. package/assets/icons/play.svg +23 -0
  56. package/assets/icons/reload.png +0 -0
  57. package/assets/icons/reload.svg +39 -0
  58. package/assets/icons/selection.png +0 -0
  59. package/assets/icons/selection.svg +22 -0
  60. package/assets/icons/side_effects.png +0 -0
  61. package/assets/icons/side_effects.svg +48 -0
  62. package/assets/icons/skip.png +0 -0
  63. package/assets/icons/skip.svg +22 -0
  64. package/assets/icons/source.svg +1366 -0
  65. package/assets/icons/step.png +0 -0
  66. package/assets/icons/step.svg +51 -0
  67. package/assets/icons/step_over_children.png +0 -0
  68. package/assets/icons/step_over_children.svg +57 -0
  69. package/assets/icons/thread.png +0 -0
  70. package/assets/icons/thread.svg +32 -0
  71. package/assets/icons/tree_column.png +0 -0
  72. package/assets/icons/tree_column.svg +26 -0
  73. package/assets/icons/tree_end.png +0 -0
  74. package/assets/icons/tree_end.svg +35 -0
  75. package/assets/icons/tree_junction.png +0 -0
  76. package/assets/icons/tree_junction.svg +35 -0
  77. package/assets/icons/vertical_grab_handle.png +0 -0
  78. package/assets/icons/vertical_grab_handle.svg +36 -0
  79. package/components/BreakpointPanel.ts +110 -0
  80. package/components/BreakpointToggle.ts +14 -0
  81. package/components/Button.ts +53 -0
  82. package/components/Checkbox.ts +17 -0
  83. package/components/CommitInspector.ts +161 -0
  84. package/components/CommitTree.ts +295 -0
  85. package/components/ControlBar.ts +60 -0
  86. package/components/EffectTable.ts +125 -0
  87. package/components/FiltersPanel.ts +45 -0
  88. package/components/HistoryList.ts +0 -0
  89. package/components/InspectorPanel.ts +54 -0
  90. package/components/PlaybackBar.ts +42 -0
  91. package/components/ThreadInspector.ts +26 -0
  92. package/components/index.module.css +414 -0
  93. package/lib/controller.ts +222 -0
  94. package/lib/list.ts +82 -0
  95. package/lib/selection.ts +32 -0
  96. package/package.json +4 -4
  97. package/public/icons/icons.svg +520 -0
  98. package/public/icons/icons__breakpoint.png +0 -0
  99. package/public/icons/icons__breakpoint.svg +30 -0
  100. package/public/icons/icons__breakpoint_panel.png +0 -0
  101. package/public/icons/icons__breakpoint_panel.svg +121 -0
  102. package/public/icons/icons__children.png +0 -0
  103. package/public/icons/icons__children.svg +38 -0
  104. package/public/icons/icons__eye.png +0 -0
  105. package/public/icons/icons__eye.svg +36 -0
  106. package/public/icons/icons__inspector_panel.png +0 -0
  107. package/public/icons/icons__inspector_panel.svg +131 -0
  108. package/public/icons/icons__magnifying_glass.png +0 -0
  109. package/public/icons/icons__magnifying_glass.svg +39 -0
  110. package/public/icons/icons__pause.png +0 -0
  111. package/public/icons/icons__pause.svg +34 -0
  112. package/public/icons/icons__play.png +0 -0
  113. package/public/icons/icons__play.svg +23 -0
  114. package/public/icons/icons__skip.png +0 -0
  115. package/public/icons/icons__skip.svg +22 -0
  116. package/public/icons/icons__step.png +0 -0
  117. package/public/icons/icons__step.svg +51 -0
  118. package/utils.ts +78 -11
  119. package/InsightApp.ts +0 -365
  120. package/MenuBar.module.css +0 -18
  121. package/MenuBar.ts +0 -39
  122. package/ScheduleControls.ts +0 -61
  123. package/lookup.ts +0 -185
Binary file
@@ -0,0 +1,51 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="5.8500004mm"
6
+ height="5.9899998mm"
7
+ viewBox="0 0 5.8500004 5.99"
8
+ version="1.1"
9
+ id="svg1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1">
14
+ <marker
15
+ style="overflow:visible"
16
+ id="Triangle"
17
+ refX="0"
18
+ refY="0"
19
+ orient="auto-start-reverse"
20
+ markerWidth="0.5"
21
+ markerHeight="0.5"
22
+ viewBox="0 0 1 1"
23
+ preserveAspectRatio="xMidYMid">
24
+ <path
25
+ transform="scale(0.5)"
26
+ style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
27
+ d="M 5.77,0 -2.88,5 V -5 Z"
28
+ id="path135" />
29
+ </marker>
30
+ </defs>
31
+ <g
32
+ id="layer1"
33
+ transform="translate(-28.952292,-16.774322)">
34
+ <circle
35
+ style="fill:#5d7388;fill-opacity:1;stroke-width:0.293366"
36
+ id="path7"
37
+ cx="30.252504"
38
+ cy="20.765179"
39
+ r="1.0245281" />
40
+ <circle
41
+ style="fill:none;fill-opacity:1;stroke:#5d7388;stroke-width:0.178757;stroke-linejoin:miter;stroke-dasharray:0.178757, 0.357514;stroke-dashoffset:0;stroke-opacity:1"
42
+ id="path7-0"
43
+ cx="33.435463"
44
+ cy="20.764971"
45
+ r="1.0010481" />
46
+ <path
47
+ style="fill:none;fill-opacity:1;stroke:#5d7388;stroke-width:0.265;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Triangle)"
48
+ d="m 30.291345,18.72896 c 0,-1.675316 3.032323,-1.625056 3.049075,-0.134029"
49
+ id="path8" />
50
+ </g>
51
+ </svg>
@@ -0,0 +1,57 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="5.8500004mm"
6
+ height="5.9899998mm"
7
+ viewBox="0 0 5.8500004 5.99"
8
+ version="1.1"
9
+ id="svg1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1">
14
+ <marker
15
+ style="overflow:visible"
16
+ id="marker20"
17
+ refX="0"
18
+ refY="0"
19
+ orient="auto-start-reverse"
20
+ markerWidth="0.40000001"
21
+ markerHeight="0.40000001"
22
+ viewBox="0 0 1 1"
23
+ preserveAspectRatio="xMidYMid">
24
+ <path
25
+ transform="scale(0.5)"
26
+ style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
27
+ d="M 5.77,0 -2.88,5 V -5 Z"
28
+ id="path20" />
29
+ </marker>
30
+ </defs>
31
+ <g
32
+ id="layer1"
33
+ transform="translate(-50.872714,-18.201318)">
34
+ <circle
35
+ style="fill:#5d7388;fill-opacity:1;stroke-width:0.293366"
36
+ id="path7-2"
37
+ cx="52.589622"
38
+ cy="19.577124"
39
+ r="1.0245281" />
40
+ <circle
41
+ style="fill:none;fill-opacity:1;stroke:#5d7388;stroke-width:0.178757;stroke-linejoin:miter;stroke-dasharray:0.178757, 0.357514;stroke-dashoffset:0;stroke-opacity:1"
42
+ id="path7-0-2"
43
+ cx="52.596684"
44
+ cy="22.512857"
45
+ r="1.0010481" />
46
+ <path
47
+ style="fill:none;stroke:#5d7388;stroke-width:0.309;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker20)"
48
+ d="m 52.495635,19.592386 h 2.800478 v 3.439583 h -0.898786"
49
+ id="path29" />
50
+ <circle
51
+ style="fill:#ffffff;fill-opacity:1;stroke:#5d7388;stroke-width:0.303;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
52
+ id="path7-0-2-3-3"
53
+ cx="55.275337"
54
+ cy="20.537638"
55
+ r="0.57445872" />
56
+ </g>
57
+ </svg>
Binary file
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="8mm"
6
+ height="7.9999995mm"
7
+ viewBox="0 0 8 7.9999998"
8
+ version="1.1"
9
+ id="svg1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1" />
14
+ <g
15
+ id="layer1"
16
+ transform="translate(24.71815,-42.68502)">
17
+ <rect
18
+ style="fill:#76c9ed;fill-opacity:1;stroke:#328ab0;stroke-width:0.432;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
19
+ id="rect22-3"
20
+ width="6.8986015"
21
+ height="2.1699133"
22
+ x="-24.247269"
23
+ y="45.683922"
24
+ ry="0.16047928" />
25
+ <circle
26
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.98822;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:0.494108, 0.494108;stroke-dashoffset:0;stroke-opacity:1"
27
+ id="path23-14"
28
+ cx="-23.132378"
29
+ cy="46.792686"
30
+ r="0.64924502" />
31
+ </g>
32
+ </svg>
Binary file
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="7.0000005mm"
6
+ height="6.9999995mm"
7
+ viewBox="0 0 7.0000005 6.9999998"
8
+ version="1.1"
9
+ id="svg1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1" />
14
+ <g
15
+ id="layer1"
16
+ transform="translate(-46.911243,-25.967027)">
17
+ <rect
18
+ style="fill:#303b47;stroke:none;stroke-width:0.658013"
19
+ id="rect9"
20
+ width="0.5"
21
+ height="7.2143836"
22
+ x="50.11124"
23
+ y="25.872257"
24
+ ry="0" />
25
+ </g>
26
+ </svg>
Binary file
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="7.0000005mm"
6
+ height="6.9999995mm"
7
+ viewBox="0 0 7.0000005 6.9999998"
8
+ version="1.1"
9
+ id="svg1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1" />
14
+ <g
15
+ id="layer1"
16
+ transform="translate(-54.871936,-25.895951)">
17
+ <rect
18
+ style="fill:#303b47;stroke:none;stroke-width:0.648216"
19
+ id="rect9-3"
20
+ width="0.5"
21
+ height="4.1817374"
22
+ x="58.071934"
23
+ y="25.718256"
24
+ ry="0" />
25
+ <rect
26
+ style="fill:#303b47;stroke:none;stroke-width:0.633772"
27
+ id="rect9-3-1"
28
+ width="0.5"
29
+ height="3.9974527"
30
+ x="29.39595"
31
+ y="-62.069386"
32
+ ry="0"
33
+ transform="rotate(90)" />
34
+ </g>
35
+ </svg>
Binary file
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="7.0000005mm"
6
+ height="6.9999995mm"
7
+ viewBox="0 0 7.0000005 6.9999998"
8
+ version="1.1"
9
+ id="svg1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1" />
14
+ <g
15
+ id="layer1"
16
+ transform="translate(-63.022171,-26.014413)">
17
+ <rect
18
+ style="fill:#303b47;stroke:none;stroke-width:0.854903"
19
+ id="rect9-3-3"
20
+ width="0.5"
21
+ height="7.2736144"
22
+ x="66.222168"
23
+ y="25.810398"
24
+ ry="0" />
25
+ <rect
26
+ style="fill:#303b47;stroke:none;stroke-width:0.633772"
27
+ id="rect9-3-1-6"
28
+ width="0.5"
29
+ height="3.9974527"
30
+ x="29.514414"
31
+ y="-70.21962"
32
+ ry="0"
33
+ transform="rotate(90)" />
34
+ </g>
35
+ </svg>
@@ -0,0 +1,36 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="6.8287368mm"
6
+ height="13.142978mm"
7
+ viewBox="0 0 6.8287368 13.142978"
8
+ version="1.1"
9
+ id="svg1"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ xmlns:svg="http://www.w3.org/2000/svg">
12
+ <defs
13
+ id="defs1" />
14
+ <g
15
+ id="layer1"
16
+ transform="translate(-27.994085,-37.773945)">
17
+ <circle
18
+ style="fill:none;fill-opacity:1;stroke:#767676;stroke-width:0.437;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
19
+ id="path42"
20
+ cx="31.501995"
21
+ cy="40.259155"
22
+ r="1.7168031" />
23
+ <circle
24
+ style="fill:none;fill-opacity:1;stroke:#767676;stroke-width:0.437;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
25
+ id="path42-6"
26
+ cx="31.501995"
27
+ cy="48.665573"
28
+ r="1.7168031" />
29
+ <circle
30
+ style="fill:none;fill-opacity:1;stroke:#767676;stroke-width:0.437;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
31
+ id="path42-6-5"
32
+ cx="31.501995"
33
+ cy="44.462364"
34
+ r="1.7168031" />
35
+ </g>
36
+ </svg>
@@ -0,0 +1,110 @@
1
+ import { Component, h, useState } from "@lukekaalim/act";
2
+ import { Breakpoints, DebugCache, toggleEffectBreakpoint } from "@lukekaalim/act-debug";
3
+
4
+ import classes from './index.module.css';
5
+ import { CommitPreview } from "../TreeViewer";
6
+ import { EffectButton, HookButton, IconButton } from "./Button";
7
+ import { InsightController, InsightState } from "../lib/controller";
8
+ import { icons } from "../assets/icons";
9
+ import { BreakpointToggle } from "./BreakpointToggle";
10
+
11
+ export type BreakpointPanelProps = {
12
+ state: InsightState,
13
+ controller: InsightController,
14
+ cache: DebugCache,
15
+
16
+ breakpoints: Readonly<Breakpoints>,
17
+
18
+ onBreakpointsChange(breakpoints: Breakpoints): void,
19
+ onStepPressed(): void,
20
+ onResumePressed(): void,
21
+ }
22
+
23
+ export const BreakpointPanel: Component<BreakpointPanelProps> = ({ breakpoints, state, onBreakpointsChange, cache, controller }) => {
24
+ type Toggles = "threadStart" | "threadPass" | "effectsStart" | "threadSubmit" | 'effectsEnd'
25
+
26
+ const setBreakpointToggle = (toggle: Toggles) => (event: InputEvent) => {
27
+ const input = event.target as HTMLInputElement;
28
+ const nextBreakpoints: Breakpoints = { ...breakpoints, [toggle]: input.checked }
29
+ onBreakpointsChange(nextBreakpoints);
30
+ }
31
+
32
+ const commitBreakpoints = [...breakpoints.commits.values()];
33
+ const effectBreakpoints = [...breakpoints.effects.values()];
34
+
35
+ const [width, setWidth] = useState(300);
36
+ const [dragging, setDragging] = useState(false);
37
+ const onPointerDown = (event: PointerEvent) => {
38
+ setDragging(true);
39
+ (event.target as HTMLButtonElement).setPointerCapture(event.pointerId);
40
+ }
41
+ const onPointerMove = (event: PointerEvent) => {
42
+ if (dragging) {
43
+ setWidth(w => w + event.movementX)
44
+ // do something about moving it
45
+ }
46
+ }
47
+ const onPointerUp = (event: PointerEvent) => {
48
+ setDragging(false);
49
+ (event.target as HTMLButtonElement).releasePointerCapture(event.pointerId);
50
+ }
51
+ // 'before-first-commit' | 'before-pass' | 'before-submit' | 'before-first-effect' | 'before-last-effect'
52
+
53
+ const start = state.thread && state.paused && !state.thread.started;
54
+ const submit = state.thread && state.paused && !state.thread.submitted && state.thread.pendingTasks.length === 0 && state.thread.missed.length === 0;
55
+ const pass = state.thread && state.paused && !state.thread.submitted && state.thread.pendingTasks.length === 0 && state.thread.missed.length !== 0;
56
+
57
+ return h('div', { className: classes.panelContainer, style: { width: `${width}px` } }, [
58
+ h('button', { classList: [classes.grabHandle, classes.right], onPointerDown, onPointerMove, onPointerUp }, h('img', { src: icons.vertical_grab_handle })),
59
+ h('div', { classList: [classes.panel] }, [
60
+ h('h4', {}, 'Breakpoint Controls'),
61
+ h('div', { className: classes.namedBreakpointList }, [
62
+ h('label', { className: start ? classes.hit : '' }, [
63
+ h('input', { type: 'checkbox', checked: breakpoints.threadStart, onInput: setBreakpointToggle('threadStart') }),
64
+ h('span', {}, 'Before First Commit'),
65
+ ]),
66
+ h('label', { className: pass ? classes.hit : '' }, [
67
+ h('input', { type: 'checkbox', checked: breakpoints.threadPass, onInput: setBreakpointToggle('threadPass') }),
68
+ h('span', {}, 'On Before New Thread Pass'),
69
+ ]),
70
+ h('label', { className: submit ? classes.hit : '' }, [
71
+ h('input', { type: 'checkbox', checked: breakpoints.threadSubmit, onInput: setBreakpointToggle('threadSubmit') }),
72
+ h('span', {}, 'On Submit to Renderer'),
73
+ ]),
74
+ h('label', {}, [
75
+ h('input', { type: 'checkbox', checked: breakpoints.effectsStart, onInput: setBreakpointToggle('effectsStart') }),
76
+ h('span', {}, 'On First Effect'),
77
+ ]),
78
+ h('label', {}, [
79
+ h('input', { type: 'checkbox', checked: breakpoints.effectsEnd, onInput: setBreakpointToggle('effectsEnd') }),
80
+ h('span', {}, 'On Last Effect'),
81
+ ]),
82
+ ]),
83
+ commitBreakpoints.length > 0 && [
84
+ h('h4', {}, 'Commits Breakpoints'),
85
+ h('ul', { className: classes.commitList }, commitBreakpoints.map(commitId => {
86
+ const commit = cache.getCommit(commitId);
87
+ if (!commit)
88
+ return null;
89
+ return h('li', {}, [
90
+ h(IconButton, { icon: 'breakpoint', title: 'Clear Breakpoint', onClick() {}, className: classes.commitRowBreakpointToggle }),
91
+ h(CommitPreview, { commit, onClick: () => {
92
+ controller.select({ type: 'commit', id: commitId })
93
+ } })
94
+ ])
95
+ }))
96
+ ],
97
+ effectBreakpoints.length > 0 && [
98
+ h('h4', {}, 'Effect Breakpoints'),
99
+ h('ul', { className: classes.effectList }, effectBreakpoints.map(effectId => {
100
+ return h('li', {}, [
101
+ h(BreakpointToggle, { toggled: true, onToggle(toggled) {
102
+ onBreakpointsChange(toggleEffectBreakpoint(breakpoints, effectId))
103
+ }, }),
104
+ h(EffectButton, { onClick() {}, effectId }),
105
+ ])
106
+ }))
107
+ ],
108
+ ])
109
+ ]);
110
+ }
@@ -0,0 +1,14 @@
1
+ import { Component, h } from "@lukekaalim/act";
2
+ import { IconButton } from "./Button";
3
+ import classes from './index.module.css';
4
+
5
+ export type BreakpointToggleProps = {
6
+ toggled: boolean,
7
+ onToggle(toggled: boolean): void,
8
+ }
9
+
10
+ export const BreakpointToggle: Component<BreakpointToggleProps> = ({ toggled, onToggle }) => {
11
+ return h(IconButton, { icon: toggled ? 'breakpoint' : 'breakpoint_unset', className: classes.breakpointToggle, onClick() {
12
+ onToggle(!toggled)
13
+ }, title: `Toggle Breakpoint` })
14
+ };
@@ -0,0 +1,53 @@
1
+ import { Component, h, OpaqueID } from "@lukekaalim/act"
2
+ import { icons } from "../assets/icons"
3
+ import classes from './index.module.css';
4
+ import { CommitID, EffectID } from "@lukekaalim/act-recon";
5
+
6
+ export type IconButtonProps = {
7
+ icon: keyof typeof icons,
8
+
9
+ onClick(): void,
10
+ title?: string,
11
+ className?: string,
12
+ }
13
+
14
+ export const IconButton: Component<IconButtonProps> = ({ icon, onClick, title, className, children }) => {
15
+ return h('button', { onClick, classList: [classes.iconButton, className || ''] }, [
16
+ h('img', { title: title || '', src: icons[icon] }),
17
+ children
18
+ ])
19
+ }
20
+
21
+
22
+ export type HookButtonProps = {
23
+ hookIndex: number,
24
+
25
+ onClick(): void,
26
+ }
27
+ export const HookButton: Component<HookButtonProps> = ({ onClick, hookIndex }) => {
28
+ return h(IconButton, { icon: 'hook', onClick }, `hook#${hookIndex}`)
29
+ }
30
+ export type EffectButtonProps = {
31
+ effectId: EffectID,
32
+
33
+ onClick(): void,
34
+ }
35
+ export const EffectButton: Component<EffectButtonProps> = ({ onClick, effectId }) => {
36
+ return h(IconButton, { icon: 'effect', onClick }, `effect#${effectId}`)
37
+ }
38
+ export type ThreadButtonProps = {
39
+ threadId: OpaqueID<"ThreadID">,
40
+
41
+ onClick(): void,
42
+ }
43
+ export const ThreadButton: Component<ThreadButtonProps> = ({ onClick, threadId }) => {
44
+ return h(IconButton, { icon: 'thread', onClick }, `thread#${threadId}`)
45
+ }
46
+ export type CommitButtonProps = {
47
+ commitId: CommitID,
48
+
49
+ onClick(): void,
50
+ }
51
+ export const CommitButton: Component<CommitButtonProps> = ({ onClick, commitId }) => {
52
+ return h(IconButton, { icon: 'commit', onClick }, `commit#${commitId}`)
53
+ }
@@ -0,0 +1,17 @@
1
+ import { Component, h, Node } from "@lukekaalim/act"
2
+
3
+ export type CheckboxProps = {
4
+ label: Node,
5
+ checked: boolean,
6
+ onCheckedChange(nextChecked: boolean): void,
7
+ }
8
+
9
+ export const Checkbox: Component<CheckboxProps> = ({ label, checked, onCheckedChange }) => {
10
+ return h('label', {}, [
11
+ h('input', { type: 'checkbox', checked, onInput(e: InputEvent) {
12
+ const input = (e.target) as HTMLInputElement;
13
+ onCheckedChange(input.checked);
14
+ } }),
15
+ h('span', {}, label),
16
+ ]);
17
+ }
@@ -0,0 +1,161 @@
1
+ import { Component, h, useEffect, useState } from "@lukekaalim/act"
2
+
3
+ import { icons } from "../assets/icons"
4
+ import { EffectButton, HookButton, IconButton } from "./Button"
5
+ import classes from './index.module.css';
6
+ import { Breakpoints, CommitDetailsReport, CommitReport, DebugClient, toggleCommitBreakpoint, toggleEffectBreakpoint } from "@lukekaalim/act-debug";
7
+ import { useSelection } from "../lib/selection";
8
+ import { CommitPreview } from "../TreeViewer";
9
+ import { Filters, InsightController, InsightState, toggleCollapsedCommit } from "../lib/controller";
10
+ import { CommitAttributeTag } from "../AttributeTag";
11
+ import { getTextForValue } from "../utils";
12
+ import { getCommitBorder, getCommitColor } from "./CommitTree";
13
+ import { CommitID } from "@lukekaalim/act-recon";
14
+ import { BreakpointToggle } from "./BreakpointToggle";
15
+
16
+ export type CommitInspectorProps = {
17
+ commit: CommitReport,
18
+
19
+ client: DebugClient,
20
+ breakpoints: Breakpoints,
21
+
22
+ state: InsightState,
23
+ controller: InsightController,
24
+ }
25
+
26
+ export const CommitInspector: Component<CommitInspectorProps> = ({ commit, breakpoints, client, state, controller }) => {
27
+ const hasBreakpoint = breakpoints.commits.has(commit.id);
28
+
29
+ const [details, setDetails] = useState<CommitDetailsReport | null>(null);
30
+ useEffect(() => {
31
+ setDetails(state.client.getDetails(commit.id));
32
+ }, [commit])
33
+
34
+ const onToggleBreakpoint = () => {
35
+ client.setBreakpoints(toggleCommitBreakpoint(breakpoints, commit.id));
36
+ }
37
+
38
+ const isCollapsed = state.filters.collapsed.has(commit.id);
39
+ const onToggleCollapse = () => {
40
+ controller.changeFilters(toggleCollapsedCommit(state.filters, commit.id))
41
+ }
42
+
43
+ const ancestors: CommitReport[] = [];
44
+ let parentId = commit.parent;
45
+ while (parentId) {
46
+ const parentCommit = state.client.cache.getCommit(parentId);
47
+ if (!parentCommit)
48
+ break;
49
+ ancestors.push(parentCommit);
50
+ parentId = parentCommit.parent;
51
+ }
52
+ ancestors.reverse();
53
+
54
+ const component = details && details.component;
55
+
56
+ const onCommitClick = (commitId: CommitID) => () => {
57
+ controller.select({ type: 'commit', id: commitId })
58
+ }
59
+
60
+ const renderAncestor = (ancestor: CommitReport, isLast: boolean) => {
61
+ const color = getCommitColor(ancestor, state.client.cache, state.thread);
62
+ const border = getCommitBorder(ancestor, state.client.cache, state.thread);
63
+
64
+ return [
65
+ h(CommitPreview, { commit: ancestor, attributes: [], color, border, onClick: onCommitClick(ancestor.id) }),
66
+ !isLast && h('img', { src: icons.ancestor_column }),
67
+ ]
68
+ }
69
+ const color = getCommitColor(commit, state.client.cache, state.thread);
70
+ const border = getCommitBorder(commit, state.client.cache, state.thread);
71
+
72
+ return h('div', { className: classes.commitInspector }, [
73
+ h("details", {}, [
74
+ h('summary', {}, h('strong', {}, 'Lineage')),
75
+ h('div', { className: classes.lineageColumn }, ancestors.map((a, i) => renderAncestor(a, i === ancestors.length - 1))),
76
+ ]),
77
+ // preview
78
+ h('div', { className: classes.commitInspectorPreviewRow },
79
+ h(CommitPreview, { commit, attributes: [], color, border })
80
+ ),
81
+ h('div', {}, [
82
+ h(CommitAttributeTag, { name: 'Id', value: commit.id.toString() }),
83
+ h(CommitAttributeTag, { name: 'Version', value: commit.version.toString() }),
84
+ !!(details && details.props.key && details.props.key.type === 'primitive') &&
85
+ h(CommitAttributeTag, { name: 'Key', value: details.props.key.value as string }),
86
+ ]),
87
+
88
+ // quick controls
89
+ h('div', { className: classes.commitControlBar }, [
90
+ h(IconButton, { icon: hasBreakpoint ? 'breakpoint' : 'breakpoint_unset', onClick: onToggleBreakpoint }),
91
+ h(IconButton, { icon: 'selection', onClick() {} }),
92
+ h(IconButton, { icon: isCollapsed ? 'expand' : 'collapse', onClick: onToggleCollapse }),
93
+ h(IconButton, { icon: 'reload', onClick() { client.requestRender(commit.id) } }),
94
+ ]),
95
+ h("details", {}, [
96
+ h('summary', {}, h('strong', {}, 'Children')),
97
+ h('ol', { className: classes.commitList }, commit.children.map(child => {
98
+ const childCommit = state.client.cache.getCommit(child);
99
+ if (!childCommit)
100
+ return null;
101
+
102
+ const color = getCommitColor(childCommit, state.client.cache, state.thread);
103
+ const border = getCommitBorder(childCommit, state.client.cache, state.thread);
104
+ return h('li', {}, h(CommitPreview, { color, border, commit: childCommit, attributes: [], onClick: onCommitClick(child) }))
105
+ })),
106
+ ]),
107
+
108
+
109
+ // info
110
+
111
+ // state details
112
+ details && [
113
+ h('div', {}, [
114
+ h('button', {}, 'By Order'),
115
+ h('button', { disabled: true }, 'By Type'),
116
+ ]),
117
+
118
+ h('h4', {}, 'Props'),
119
+ h('table', {},
120
+ Object.entries(details.props).map(([name, value]) => {
121
+ return h('tr', {}, [h('td', {}, name), h('td', {}, getTextForValue(value))])
122
+ })),
123
+ component && [
124
+ h('h4', {}, 'State'),
125
+ h('table', {},
126
+ component.stateValues.map((state) => {
127
+ return h('tr', {}, [
128
+ h('td', {}, h(HookButton, { onClick() {} , hookIndex: state.hookIndex })),
129
+ h('td', {}, getTextForValue(state.value))
130
+ ])
131
+ })),
132
+ h('h4', {}, 'Effects'),
133
+ h('table', {},
134
+ component.effects.map((effectHook) => {
135
+ const queuedForUpdate = state.thread && state.thread.delta.effects.some(e => e.id === effectHook.effect);
136
+ const cleanupTask = state.thread && state.thread.effects.tasks.findIndex(t => t.id === effectHook.effect && t.type === 'cleanup')
137
+ const constructorTask = state.thread && state.thread.effects.tasks.findIndex(t => t.id === effectHook.effect && t.type === 'constructor')
138
+
139
+ return h('tr', { style: { background: queuedForUpdate ? '#a7ceff' : 'none' } }, [
140
+ h('td', {}, h(HookButton, { onClick() {} , hookIndex: effectHook.hookIndex })),
141
+ h('td', {}, h('div', { style: { display: 'flex' } }, [
142
+ h(BreakpointToggle, { onToggle() {
143
+ client.setBreakpoints(toggleEffectBreakpoint(breakpoints, effectHook.effect))
144
+ }, toggled: breakpoints.effects.has(effectHook.effect) }),
145
+ h(EffectButton, { onClick() {}, effectId: effectHook.effect }),
146
+ ])),
147
+ ])
148
+ })),
149
+ h('h4', {}, 'Contexts'),
150
+ h('table', {},
151
+ component.subscriptions.map((subscription) => {
152
+ return h('tr', {}, [
153
+ h('td', {}, h(HookButton, { onClick() {} , hookIndex: subscription.hookIndex })),
154
+ h('td', {}, subscription.context),
155
+ h('td', {}, subscription.provider),
156
+ ])
157
+ })),
158
+ ]
159
+ ]
160
+ ])
161
+ }