@opensip-cli/dashboard 0.1.6 → 0.1.8

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 (199) hide show
  1. package/README.md +2 -2
  2. package/dist/__tests__/catalog-provenance.test.js +6 -24
  3. package/dist/__tests__/catalog-provenance.test.js.map +1 -1
  4. package/dist/__tests__/coupling-attribution.test.js +10 -14
  5. package/dist/__tests__/coupling-attribution.test.js.map +1 -1
  6. package/dist/__tests__/dashboard-bundle-weight.test.d.ts +9 -2
  7. package/dist/__tests__/dashboard-bundle-weight.test.d.ts.map +1 -1
  8. package/dist/__tests__/dashboard-bundle-weight.test.js +19 -12
  9. package/dist/__tests__/dashboard-bundle-weight.test.js.map +1 -1
  10. package/dist/__tests__/dashboard-cell-containment.test.js +5 -2
  11. package/dist/__tests__/dashboard-cell-containment.test.js.map +1 -1
  12. package/dist/__tests__/dashboard-editor-link.test.d.ts +9 -0
  13. package/dist/__tests__/dashboard-editor-link.test.d.ts.map +1 -1
  14. package/dist/__tests__/dashboard-editor-link.test.js +72 -21
  15. package/dist/__tests__/dashboard-editor-link.test.js.map +1 -1
  16. package/dist/__tests__/dashboard-filters.test.js +6 -14
  17. package/dist/__tests__/dashboard-filters.test.js.map +1 -1
  18. package/dist/__tests__/dashboard-function-card-singleton.test.js +15 -27
  19. package/dist/__tests__/dashboard-function-card-singleton.test.js.map +1 -1
  20. package/dist/__tests__/dashboard-function-card.test.d.ts +4 -4
  21. package/dist/__tests__/dashboard-function-card.test.js +23 -44
  22. package/dist/__tests__/dashboard-function-card.test.js.map +1 -1
  23. package/dist/__tests__/dashboard-function-row.test.js +6 -16
  24. package/dist/__tests__/dashboard-function-row.test.js.map +1 -1
  25. package/dist/__tests__/dashboard-generator-graph-catalog.test.js +3 -1
  26. package/dist/__tests__/dashboard-generator-graph-catalog.test.js.map +1 -1
  27. package/dist/__tests__/dashboard-graph-offline.integration.test.js +3 -1
  28. package/dist/__tests__/dashboard-graph-offline.integration.test.js.map +1 -1
  29. package/dist/__tests__/dashboard-help-drawer.test.js +11 -17
  30. package/dist/__tests__/dashboard-help-drawer.test.js.map +1 -1
  31. package/dist/__tests__/dashboard-indexes.test.d.ts +6 -4
  32. package/dist/__tests__/dashboard-indexes.test.d.ts.map +1 -1
  33. package/dist/__tests__/dashboard-indexes.test.js +10 -7
  34. package/dist/__tests__/dashboard-indexes.test.js.map +1 -1
  35. package/dist/__tests__/dashboard-path-utils.test.d.ts +7 -0
  36. package/dist/__tests__/dashboard-path-utils.test.d.ts.map +1 -1
  37. package/dist/__tests__/dashboard-path-utils.test.js +11 -3
  38. package/dist/__tests__/dashboard-path-utils.test.js.map +1 -1
  39. package/dist/__tests__/dashboard-search.test.d.ts +5 -0
  40. package/dist/__tests__/dashboard-search.test.d.ts.map +1 -1
  41. package/dist/__tests__/dashboard-search.test.js +9 -3
  42. package/dist/__tests__/dashboard-search.test.js.map +1 -1
  43. package/dist/__tests__/dashboard-sessions.test.js +13 -11
  44. package/dist/__tests__/dashboard-sessions.test.js.map +1 -1
  45. package/dist/__tests__/dashboard-trace.test.d.ts +11 -0
  46. package/dist/__tests__/dashboard-trace.test.d.ts.map +1 -1
  47. package/dist/__tests__/dashboard-trace.test.js +55 -32
  48. package/dist/__tests__/dashboard-trace.test.js.map +1 -1
  49. package/dist/__tests__/dashboard-view-conformance.test.js +9 -15
  50. package/dist/__tests__/dashboard-view-conformance.test.js.map +1 -1
  51. package/dist/__tests__/dashboard-view-coupling.test.js +14 -35
  52. package/dist/__tests__/dashboard-view-coupling.test.js.map +1 -1
  53. package/dist/__tests__/dashboard-view-distribution.test.js +14 -37
  54. package/dist/__tests__/dashboard-view-distribution.test.js.map +1 -1
  55. package/dist/__tests__/dashboard-view-graph.test.js +29 -62
  56. package/dist/__tests__/dashboard-view-graph.test.js.map +1 -1
  57. package/dist/__tests__/dashboard-view-template.test.d.ts +13 -14
  58. package/dist/__tests__/dashboard-view-template.test.d.ts.map +1 -1
  59. package/dist/__tests__/dashboard-view-template.test.js +165 -112
  60. package/dist/__tests__/dashboard-view-template.test.js.map +1 -1
  61. package/dist/__tests__/graph-tab.test.js +4 -2
  62. package/dist/__tests__/graph-tab.test.js.map +1 -1
  63. package/dist/client-bundle.generated.d.ts +2 -0
  64. package/dist/client-bundle.generated.d.ts.map +1 -0
  65. package/dist/client-bundle.generated.js +3 -0
  66. package/dist/client-bundle.generated.js.map +1 -0
  67. package/dist/code-paths/__tests__/views-registry.test.d.ts +13 -8
  68. package/dist/code-paths/__tests__/views-registry.test.d.ts.map +1 -1
  69. package/dist/code-paths/__tests__/views-registry.test.js +27 -25
  70. package/dist/code-paths/__tests__/views-registry.test.js.map +1 -1
  71. package/dist/code-paths.d.ts +21 -62
  72. package/dist/code-paths.d.ts.map +1 -1
  73. package/dist/code-paths.js +24 -349
  74. package/dist/code-paths.js.map +1 -1
  75. package/dist/generator.d.ts +2 -0
  76. package/dist/generator.d.ts.map +1 -1
  77. package/dist/generator.js +28 -17
  78. package/dist/generator.js.map +1 -1
  79. package/package.json +5 -4
  80. package/dist/checks.d.ts +0 -7
  81. package/dist/checks.d.ts.map +0 -1
  82. package/dist/checks.js +0 -283
  83. package/dist/checks.js.map +0 -1
  84. package/dist/code-paths/catalog-provenance.d.ts +0 -22
  85. package/dist/code-paths/catalog-provenance.d.ts.map +0 -1
  86. package/dist/code-paths/catalog-provenance.js +0 -108
  87. package/dist/code-paths/catalog-provenance.js.map +0 -1
  88. package/dist/code-paths/catalog-recipes-tables.d.ts +0 -11
  89. package/dist/code-paths/catalog-recipes-tables.d.ts.map +0 -1
  90. package/dist/code-paths/catalog-recipes-tables.js +0 -86
  91. package/dist/code-paths/catalog-recipes-tables.js.map +0 -1
  92. package/dist/code-paths/editor-link.d.ts +0 -10
  93. package/dist/code-paths/editor-link.d.ts.map +0 -1
  94. package/dist/code-paths/editor-link.js +0 -20
  95. package/dist/code-paths/editor-link.js.map +0 -1
  96. package/dist/code-paths/filters.d.ts +0 -19
  97. package/dist/code-paths/filters.d.ts.map +0 -1
  98. package/dist/code-paths/filters.js +0 -47
  99. package/dist/code-paths/filters.js.map +0 -1
  100. package/dist/code-paths/function-card.d.ts +0 -15
  101. package/dist/code-paths/function-card.d.ts.map +0 -1
  102. package/dist/code-paths/function-card.js +0 -169
  103. package/dist/code-paths/function-card.js.map +0 -1
  104. package/dist/code-paths/function-row.d.ts +0 -17
  105. package/dist/code-paths/function-row.d.ts.map +0 -1
  106. package/dist/code-paths/function-row.js +0 -77
  107. package/dist/code-paths/function-row.js.map +0 -1
  108. package/dist/code-paths/graph-controls.d.ts +0 -27
  109. package/dist/code-paths/graph-controls.d.ts.map +0 -1
  110. package/dist/code-paths/graph-controls.js +0 -257
  111. package/dist/code-paths/graph-controls.js.map +0 -1
  112. package/dist/code-paths/graph-stylesheet.d.ts +0 -22
  113. package/dist/code-paths/graph-stylesheet.d.ts.map +0 -1
  114. package/dist/code-paths/graph-stylesheet.js +0 -121
  115. package/dist/code-paths/graph-stylesheet.js.map +0 -1
  116. package/dist/code-paths/help-drawer.d.ts +0 -18
  117. package/dist/code-paths/help-drawer.d.ts.map +0 -1
  118. package/dist/code-paths/help-drawer.js +0 -54
  119. package/dist/code-paths/help-drawer.js.map +0 -1
  120. package/dist/code-paths/indexes.d.ts +0 -28
  121. package/dist/code-paths/indexes.d.ts.map +0 -1
  122. package/dist/code-paths/indexes.js +0 -97
  123. package/dist/code-paths/indexes.js.map +0 -1
  124. package/dist/code-paths/path-utils.d.ts +0 -15
  125. package/dist/code-paths/path-utils.d.ts.map +0 -1
  126. package/dist/code-paths/path-utils.js +0 -47
  127. package/dist/code-paths/path-utils.js.map +0 -1
  128. package/dist/code-paths/search.d.ts +0 -14
  129. package/dist/code-paths/search.d.ts.map +0 -1
  130. package/dist/code-paths/search.js +0 -54
  131. package/dist/code-paths/search.js.map +0 -1
  132. package/dist/code-paths/trace.d.ts +0 -11
  133. package/dist/code-paths/trace.d.ts.map +0 -1
  134. package/dist/code-paths/trace.js +0 -60
  135. package/dist/code-paths/trace.js.map +0 -1
  136. package/dist/code-paths/view-coupling.d.ts +0 -22
  137. package/dist/code-paths/view-coupling.d.ts.map +0 -1
  138. package/dist/code-paths/view-coupling.js +0 -218
  139. package/dist/code-paths/view-coupling.js.map +0 -1
  140. package/dist/code-paths/view-distribution.d.ts +0 -20
  141. package/dist/code-paths/view-distribution.d.ts.map +0 -1
  142. package/dist/code-paths/view-distribution.js +0 -82
  143. package/dist/code-paths/view-distribution.js.map +0 -1
  144. package/dist/code-paths/view-graph.d.ts +0 -35
  145. package/dist/code-paths/view-graph.d.ts.map +0 -1
  146. package/dist/code-paths/view-graph.js +0 -379
  147. package/dist/code-paths/view-graph.js.map +0 -1
  148. package/dist/code-paths/view-template.d.ts +0 -154
  149. package/dist/code-paths/view-template.d.ts.map +0 -1
  150. package/dist/code-paths/view-template.js +0 -218
  151. package/dist/code-paths/view-template.js.map +0 -1
  152. package/dist/code-paths/views-registry.d.ts +0 -13
  153. package/dist/code-paths/views-registry.d.ts.map +0 -1
  154. package/dist/code-paths/views-registry.js +0 -53
  155. package/dist/code-paths/views-registry.js.map +0 -1
  156. package/dist/overview.d.ts +0 -13
  157. package/dist/overview.d.ts.map +0 -1
  158. package/dist/overview.js +0 -91
  159. package/dist/overview.js.map +0 -1
  160. package/dist/recipes.d.ts +0 -6
  161. package/dist/recipes.d.ts.map +0 -1
  162. package/dist/recipes.js +0 -68
  163. package/dist/recipes.js.map +0 -1
  164. package/dist/sessions.d.ts +0 -6
  165. package/dist/sessions.d.ts.map +0 -1
  166. package/dist/sessions.js +0 -288
  167. package/dist/sessions.js.map +0 -1
  168. package/dist/shared/el.d.ts +0 -13
  169. package/dist/shared/el.d.ts.map +0 -1
  170. package/dist/shared/el.js +0 -27
  171. package/dist/shared/el.js.map +0 -1
  172. package/dist/shared/pagination.d.ts +0 -15
  173. package/dist/shared/pagination.d.ts.map +0 -1
  174. package/dist/shared/pagination.js +0 -113
  175. package/dist/shared/pagination.js.map +0 -1
  176. package/dist/shared/sortable.d.ts +0 -14
  177. package/dist/shared/sortable.d.ts.map +0 -1
  178. package/dist/shared/sortable.js +0 -101
  179. package/dist/shared/sortable.js.map +0 -1
  180. package/dist/shared/tab-activators.d.ts +0 -16
  181. package/dist/shared/tab-activators.d.ts.map +0 -1
  182. package/dist/shared/tab-activators.js +0 -33
  183. package/dist/shared/tab-activators.js.map +0 -1
  184. package/dist/shared/tab-bar.d.ts +0 -8
  185. package/dist/shared/tab-bar.d.ts.map +0 -1
  186. package/dist/shared/tab-bar.js +0 -20
  187. package/dist/shared/tab-bar.js.map +0 -1
  188. package/dist/shared.d.ts +0 -26
  189. package/dist/shared.d.ts.map +0 -1
  190. package/dist/shared.js +0 -39
  191. package/dist/shared.js.map +0 -1
  192. package/dist/subtab-bar.d.ts +0 -23
  193. package/dist/subtab-bar.d.ts.map +0 -1
  194. package/dist/subtab-bar.js +0 -77
  195. package/dist/subtab-bar.js.map +0 -1
  196. package/dist/tool-tabs.d.ts +0 -12
  197. package/dist/tool-tabs.d.ts.map +0 -1
  198. package/dist/tool-tabs.js +0 -80
  199. package/dist/tool-tabs.js.map +0 -1
@@ -1,379 +0,0 @@
1
- /**
2
- * View 8 — "Visualization" (node-link topology, Cytoscape.js + dagre).
3
- *
4
- * The non-tabular Code Graph view. A self-contained **Level** control switches
5
- * what the graph shows:
6
- *
7
- * - PACKAGE level (default) — one node per package, one edge per directed
8
- * package→package coupling. Function granularity across the whole repo
9
- * produced thousands of nodes, unusable in a node-link layout; the package
10
- * rollup is the same data the Coupling matrix shows, drawn as a graph.
11
- * Source: the pre-projected `graph-view-model` JSON blob embedded by
12
- * `generator.ts` (projector in `graph-view-model.ts`, run at
13
- * report-generation time) — NOT the raw catalog. Absent blob → empty state.
14
- * - FUNCTION level — the functions of ONE selected package and the calls
15
- * among them, projected client-side from the embedded catalog indexes by
16
- * `gvBuildFunctionElements`. Scoping to a single package keeps the node
17
- * count bounded. The "Edges" toggle chooses intra-package only (default) or
18
- * "+ cross-package" (also draw calls leaving the package, to faded external
19
- * nodes). Honors the Scope (test inclusion) and Kind (multi-select) filters.
20
- *
21
- * The view owns its controls (Level / Scope / Package / Kind / Edges) in
22
- * `gvRenderControls`; the shared Explore filter chips govern the Functions
23
- * table, NOT this view. Package + Kind only apply at function level, so they
24
- * are disabled at package level. Renderer is the vendored `cytoscape` global +
25
- * the `cytoscapeDagre` layout extension, both inlined by
26
- * `dashboardCytoscapeVendorJs()` ahead of this emitter in `code-paths.ts`.
27
- *
28
- * Features: pan/zoom, layout selector (dagre/cose/breadthfirst), name search,
29
- * node-click impact highlight (direct caller/callee neighbors), and
30
- * cross-package cycle highlighting (package level). Visual encoding
31
- * (totalCoupling→size, weight→edge thickness, sccId→accent, external→faded) is
32
- * applied in `gvStylesheet` / `gvBuildElements` / `gvBuildFunctionElements`.
33
- */
34
- import { dashboardGraphControlsJs } from './graph-controls.js';
35
- import { dashboardViewGraphStylesheetJs } from './graph-stylesheet.js';
36
- // @graph-ignore-next-line graph:large-function -- emits one cohesive browser-JS bundle as a String.raw template; bodyLines counts the embedded JS-as-string, not splittable logic (ADR-0014)
37
- export function dashboardViewGraphJs() {
38
- return String.raw `
39
- // Register the dagre layout extension once (the vendored globals are
40
- // declared earlier in the bundle). Guarded so a double-load is harmless.
41
- (function registerGraphLayouts() {
42
- try {
43
- if (typeof cytoscape === 'function' && typeof cytoscapeDagre !== 'undefined' && !cytoscape.__gvDagreRegistered) {
44
- cytoscape.use(cytoscapeDagre);
45
- cytoscape.__gvDagreRegistered = true;
46
- }
47
- } catch (e) { /* extension already registered or unavailable */ }
48
- })();
49
-
50
- // Available layouts. dagre is the default for mostly-DAG package graphs; cose
51
- // (built-in force-directed) reads better when cycles dominate;
52
- // breadthfirst is a cheap hierarchical fallback. No fcose — it needs a
53
- // fourth vendored extension and the bundle budget is tight.
54
- var GV_LAYOUTS = [
55
- { id: 'dagre', label: 'Dagre (layered)' },
56
- { id: 'cose', label: 'Cose (force)' },
57
- { id: 'breadthfirst', label: 'Breadthfirst' },
58
- ];
59
- var gvCurrentLayout = 'dagre';
60
- var gvCy = null;
61
-
62
- // ---- Visualization control state (self-contained; NOT the shared Explore
63
- // filter bar). These live in module vars so they survive the in-place
64
- // re-render each control change triggers (gvRenderGraph). ----
65
- // gvLevel 'package' (default) → package→package rollup blob.
66
- // 'function' → the selected package's functions.
67
- // gvIncludeTests Scope dropdown: false = production only (default).
68
- // gvSelectedPackage single package chosen at function level (null = none).
69
- // gvKinds multi-selected function kinds ([] = all).
70
- // gvCrossPackage function-level "Edges" toggle: false = intra-package
71
- // (default), true = also draw edges leaving the package
72
- // to faded external function nodes.
73
- var gvLevel = 'package';
74
- var gvIncludeTests = false;
75
- var gvSelectedPackage = null;
76
- var gvKinds = [];
77
- var gvCrossPackage = false;
78
- // The active Escape handler, tracked so each re-render replaces (not stacks)
79
- // its document-level keydown listener.
80
- var gvEscHandler = null;
81
-
82
- function gvLoadViewModel() {
83
- var blob = document.getElementById('graph-view-model');
84
- if (!blob || !blob.textContent) return null;
85
- try { return JSON.parse(blob.textContent); } catch (e) { return null; }
86
- }
87
-
88
- // The init loop renders EVERY Code Graph panel, not just the active one — the
89
- // row-table views re-render in O(rows), but a full Cytoscape mount + dagre
90
- // layout is far from free. Defer that work until this panel is actually
91
- // visible: the panel orchestrator toggles an 'active' class on the live
92
- // '.code-paths-view' panel. A container that is a panel but not active is
93
- // hidden → skip the mount (it runs on activation). A container that is NOT a
94
- // panel (e.g. a unit-test harness div) is treated as visible so direct
95
- // render() calls mount.
96
- function gvPanelHidden(container) {
97
- return !!(container && container.classList &&
98
- container.classList.contains('code-paths-view') &&
99
- !container.classList.contains('active'));
100
- }
101
-
102
- // Map a sccId to a stable hue so cross-package cyclic clusters are grouped.
103
- function gvSccColor(sccId) {
104
- if (!sccId) return null;
105
- var h = 0;
106
- for (var i = 0; i < sccId.length; i++) { h = (h * 31 + sccId.charCodeAt(i)) % 360; }
107
- return 'hsl(' + h + ', 70%, 55%)';
108
- }
109
-
110
- function gvBuildElements(vm) {
111
- var elements = [];
112
- for (var i = 0; i < vm.nodes.length; i++) {
113
- var n = vm.nodes[i];
114
- elements.push({
115
- group: 'nodes',
116
- data: {
117
- id: n.id,
118
- label: n.label,
119
- totalCoupling: n.totalCoupling || 0,
120
- sccId: n.sccId || null,
121
- sccColor: gvSccColor(n.sccId),
122
- },
123
- });
124
- }
125
- for (var j = 0; j < vm.edges.length; j++) {
126
- var e = vm.edges[j];
127
- elements.push({
128
- group: 'edges',
129
- data: {
130
- id: 'e' + j,
131
- source: e.source,
132
- target: e.target,
133
- weight: e.weight || 1,
134
- isCycleEdge: !!e.isCycleEdge,
135
- },
136
- });
137
- }
138
- return elements;
139
- }
140
-
141
- ${dashboardViewGraphStylesheetJs()}
142
-
143
- function gvLayoutOptions(layoutId) {
144
- if (layoutId === 'dagre') {
145
- return { name: 'dagre', rankDir: 'LR', nodeSep: 24, rankSep: 64, fit: true, padding: 24 };
146
- }
147
- if (layoutId === 'breadthfirst') {
148
- return { name: 'breadthfirst', directed: true, spacingFactor: 1.2, fit: true, padding: 24 };
149
- }
150
- return { name: 'cose', animate: false, fit: true, padding: 24, nodeRepulsion: 6000 };
151
- }
152
-
153
- function gvRunLayout(layoutId) {
154
- if (!gvCy) return;
155
- gvCurrentLayout = layoutId;
156
- var layout = gvCy.layout(gvLayoutOptions(layoutId));
157
- layout.run();
158
- }
159
-
160
- // The Layout selector and the "Highlight cycles" toggle now live in the single
161
- // control toolbar built by gvRenderControls (graph-controls.ts) — Layout as a
162
- // dropdown matching the other controls. gvRunLayout / gvSccHighlight /
163
- // gvApplySccHighlight (below) are the shared handlers those controls call.
164
-
165
- // Emphasize cross-package cyclic clusters on the live graph. A node is "in a
166
- // cycle" when it carries an sccId; an edge when isCycleEdge is set. Toggling
167
- // off clears the emphasis.
168
- var gvSccHighlight = false;
169
-
170
- function gvApplySccHighlight() {
171
- if (!gvCy) return;
172
- gvCy.batch(function() {
173
- gvCy.elements().removeClass('gv-scc-member gv-scc-edge gv-scc-dimmed');
174
- if (!gvSccHighlight) return;
175
- gvCy.nodes().forEach(function(n) {
176
- if (n.data('sccId')) n.addClass('gv-scc-member');
177
- else n.addClass('gv-scc-dimmed');
178
- });
179
- gvCy.edges().forEach(function(ed) {
180
- if (ed.data('isCycleEdge')) ed.addClass('gv-scc-edge');
181
- else ed.addClass('gv-scc-dimmed');
182
- });
183
- });
184
- }
185
-
186
- function gvClearImpact() {
187
- if (!gvCy) return;
188
- gvCy.elements().removeClass('gv-selected gv-upstream gv-downstream gv-dimmed');
189
- }
190
-
191
- // Impact highlight at package granularity: light the clicked package, its
192
- // direct caller packages (incomers) and direct callee packages (outgoers).
193
- // Built straight off the live Cytoscape adjacency rather than a function-level
194
- // index, since the nodes ARE packages here.
195
- function gvApplyImpact(seedId) {
196
- if (!gvCy) return;
197
- var seed = gvCy.getElementById(seedId);
198
- if (!seed || seed.length === 0) return;
199
- var upstream = {}; // packages that call the seed
200
- var downstream = {}; // packages the seed calls
201
- seed.incomers('node').forEach(function(n) { if (n.id() !== seedId) upstream[n.id()] = true; });
202
- seed.outgoers('node').forEach(function(n) { if (n.id() !== seedId) downstream[n.id()] = true; });
203
- gvCy.batch(function() {
204
- gvCy.elements().removeClass('gv-selected gv-upstream gv-downstream');
205
- gvCy.elements().addClass('gv-dimmed');
206
- gvCy.nodes().forEach(function(n) {
207
- var id = n.id();
208
- if (id === seedId) { n.removeClass('gv-dimmed').addClass('gv-selected'); }
209
- else if (upstream[id]) { n.removeClass('gv-dimmed').addClass('gv-upstream'); }
210
- else if (downstream[id]) { n.removeClass('gv-dimmed').addClass('gv-downstream'); }
211
- });
212
- // Un-dim edges incident to the seed so the lit neighborhood reads as
213
- // connected coupling, not isolated nodes.
214
- gvCy.edges().forEach(function(ed) {
215
- var s = ed.source().id();
216
- var t = ed.target().id();
217
- if (s === seedId || t === seedId) ed.removeClass('gv-dimmed');
218
- });
219
- });
220
- }
221
-
222
- // Search box (DOM, above the canvas). Filters by PACKAGE NAME. Reuses the same
223
- // fuzzy index the table views use (fuzzyMatch over the node labels = package
224
- // names). A hit centers + fits the matched node and flags it; non-matches
225
- // fade. Clearing restores opacity.
226
- function gvRenderSearchBox(host) {
227
- var input = el('input', {
228
- type: 'search',
229
- class: 'search-input code-paths-graph-search',
230
- id: 'code-paths-graph-search-input',
231
- // Labels are package names at package level, function names at function
232
- // level; the search matches whatever the live node labels are.
233
- placeholder: gvLevel === 'function' ? 'Find a function by name…' : 'Find a package by name…',
234
- });
235
- input.addEventListener('input', function(e) {
236
- gvApplySearch((e.target && e.target.value) || '');
237
- });
238
- host.appendChild(input);
239
- }
240
-
241
- function gvApplySearch(query) {
242
- if (!gvCy) return;
243
- var q = (query || '').trim();
244
- gvCy.nodes().removeClass('gv-search-hit gv-search-fade');
245
- if (q.length === 0) return;
246
- // The view-model label is the package name; match against it directly
247
- // (the fuzzy scorer lives in search.js, emitted earlier in the bundle).
248
- var labels = gvCy.nodes().map(function(n) { return n.data('label') || ''; });
249
- var matches = (typeof fuzzyMatch === 'function') ? fuzzyMatch(q, labels) : [];
250
- var hitLabels = {};
251
- for (var i = 0; i < matches.length; i++) hitLabels[matches[i].name] = true;
252
- var hitCollection = gvCy.collection();
253
- gvCy.nodes().forEach(function(n) {
254
- if (hitLabels[n.data('label')]) { n.addClass('gv-search-hit'); hitCollection = hitCollection.union(n); }
255
- else { n.addClass('gv-search-fade'); }
256
- });
257
- if (hitCollection.length > 0) {
258
- try { gvCy.center(hitCollection); gvCy.fit(hitCollection, 120); } catch (e) { /* ignore */ }
259
- }
260
- }
261
-
262
- ${dashboardGraphControlsJs()}
263
-
264
- // The actual render driver — called by the view's render() AND by every
265
- // control-change handler (so a control change re-renders in place). Mirrors
266
- // the old render() but branches on gvLevel for the element source. Package
267
- // level keeps the historical empty-state ORDER (view-model check before the
268
- // cytoscape check) so the structural view tests stay valid.
269
- function gvRenderGraph(container, catalog, indexes) {
270
- while (container.firstChild) container.removeChild(container.firstChild);
271
- // Defer the expensive mount while this panel is hidden (see gvPanelHidden).
272
- // activateView() re-renders the panel once it becomes visible.
273
- if (gvPanelHidden(container)) return;
274
-
275
- // Section heading + ⓘ help button, consistent with the Coupling and
276
- // Functions views (makeSectionHeading wires the button to openHelpDrawer for
277
- // this view's id, which surfaces the 'graph' view's help sections).
278
- container.appendChild(makeSectionHeading('Visualization', 'graph'));
279
- // The control grid includes the search box and the Highlight-cycles toggle
280
- // (row 1, cols 3-4), so there's nothing else to render here.
281
- gvRenderControls(container, catalog, indexes);
282
-
283
- var elements;
284
- if (gvLevel === 'function') {
285
- if (typeof cytoscape !== 'function') {
286
- container.appendChild(el('div', { class: 'empty', text: 'Graph renderer unavailable.' }));
287
- return;
288
- }
289
- if (!gvSelectedPackage) {
290
- container.appendChild(el('div', { class: 'empty', text: 'Select a package to view its functions.' }));
291
- return;
292
- }
293
- elements = gvBuildFunctionElements(indexes, gvSelectedPackage, gvIncludeTests, gvKinds, gvCrossPackage);
294
- if (!elements || elements.length === 0) {
295
- container.appendChild(el('div', { class: 'empty', text: 'No functions in this package.' }));
296
- return;
297
- }
298
- } else {
299
- var vm = gvLoadViewModel();
300
- if (!vm || !vm.nodes || vm.nodes.length === 0) {
301
- container.appendChild(el('div', { class: 'empty', text: 'No graph to display.' }));
302
- return;
303
- }
304
- if (typeof cytoscape !== 'function') {
305
- container.appendChild(el('div', { class: 'empty', text: 'Graph renderer unavailable.' }));
306
- return;
307
- }
308
- elements = gvBuildElements(vm);
309
- if (elements.length === 0) {
310
- container.appendChild(el('div', { class: 'empty', text: 'No packages to display.' }));
311
- return;
312
- }
313
- }
314
-
315
- var canvas = el('div', { class: 'code-paths-graph-canvas', id: 'code-paths-graph-canvas' });
316
- container.appendChild(canvas);
317
-
318
- // Mounting can throw in environments without a real 2D canvas (e.g. headless
319
- // test runners). Fail soft — the rest of the page stays usable.
320
- try {
321
- gvCy = cytoscape({
322
- container: canvas,
323
- elements: elements,
324
- style: gvStylesheet(),
325
- layout: gvLayoutOptions(gvCurrentLayout),
326
- wheelSensitivity: 0.2,
327
- minZoom: 0.05,
328
- maxZoom: 4,
329
- });
330
- } catch (e) {
331
- gvCy = null;
332
- canvas.appendChild(el('div', { class: 'empty', text: 'Graph renderer could not initialize in this environment.' }));
333
- return;
334
- }
335
-
336
- // Click a node → highlight its direct caller/callee neighbors. Background
337
- // click or Esc clears. Replace (don't stack) the document keydown listener.
338
- gvCy.on('tap', 'node', function(evt) { gvApplyImpact(evt.target.id()); });
339
- gvCy.on('tap', function(evt) { if (evt.target === gvCy) gvClearImpact(); });
340
- if (gvEscHandler) { try { document.removeEventListener('keydown', gvEscHandler); } catch (e) { /* ignore */ } }
341
- gvEscHandler = function(e) { if (e.key === 'Escape') gvClearImpact(); };
342
- document.addEventListener('keydown', gvEscHandler);
343
-
344
- // Re-apply the cycle emphasis if the toggle was left on across a re-render.
345
- gvApplySccHighlight();
346
- }
347
-
348
- views.push({
349
- id: 'graph',
350
- label: 'Visualization',
351
- help: {
352
- title: 'Visualization',
353
- sections: [
354
- { heading: 'What this is', body: 'A node-link visualization of the call graph, rendered with Cytoscape.js. At Package level each node is a package and each edge is the directed coupling from one package into another; node size reflects total coupling (calls in + calls out) and edge thickness reflects the number of call edges. At Function level it shows the functions of one selected package and the calls among them.' },
355
- { heading: 'Levels', body: 'Use the Level control to switch between Package (the whole-repo package rollup, the same data as the Coupling matrix) and Function (one package at a time). Function level enables the Package picker (which package to show) and the Kind multi-select, plus an Edges toggle: "Intra-package" shows only calls inside the package; "+ cross-package" also draws calls leaving the package to faded external nodes. The Scope control (production only vs include tests) applies at both levels.' },
356
- { heading: 'Why you care', body: 'The table views project the graph into rankings and lists, and the Coupling matrix shows the same package data as a grid. This view shows that topology directly — hub packages, tightly-coupled clusters, and circular package dependencies at package level; the internal call structure of a single package at function level.' },
357
- { heading: 'How to read it', body: 'Bigger nodes are more coupled; thicker edges carry more calls. Use the layout selector to switch between layered (dagre), force (cose), and hierarchical (breadthfirst). The matrix on the Coupling tab is the package-level data in tabular form.' },
358
- { heading: 'What to do', body: 'Pan and zoom to explore. Type in the search box to center and highlight a node by name; non-matches fade. Click a node to trace its direct callers (upstream) and callees (downstream).' },
359
- { heading: 'Cross-package cycles', body: 'Strongly-connected components are groups of packages that can all reach each other through call edges (found via Tarjan’s algorithm). Click "Highlight cycles" in the toolbar to emphasize cycle members and cycle edges while dimming the acyclic remainder. A cycle between packages is usually a layering smell. Break it by extracting the shared protocol into a third package both sides depend on, or by inverting one call into a callback/event.' },
360
- ],
361
- },
362
- render(container, catalog, indexes, filterState) {
363
- // The shared Explore filterState is intentionally NOT consulted here — this
364
- // view owns its own controls (gvRenderControls). All rendering lives in
365
- // gvRenderGraph so control-change handlers can re-render in place.
366
- gvRenderGraph(container, catalog, indexes);
367
- },
368
- onActivate() {
369
- // The canvas needs a measured size before fit() — defer one frame so
370
- // the container has finished switching from display:none to block.
371
- if (!gvCy) return;
372
- setTimeout(function() {
373
- try { gvCy.resize(); gvCy.fit(undefined, 24); } catch (e) { /* ignore */ }
374
- }, 0);
375
- },
376
- });
377
- `;
378
- }
379
- //# sourceMappingURL=view-graph.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"view-graph.js","sourceRoot":"","sources":["../../src/code-paths/view-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AAEvE,6LAA6L;AAC7L,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuGjB,8BAA8B,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyHhC,wBAAwB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmH3B,CAAC;AACF,CAAC"}
@@ -1,154 +0,0 @@
1
- /**
2
- * `defineRankedView` — JS-string emitter for ranked-list views.
3
- *
4
- * Hot, Big, Wide, and Untested all share the same skeleton:
5
- *
6
- * 1. Bail out with an empty-state message if the catalog is missing.
7
- * 2. Walk `indexes.byBodyHash.values()`, applying the active filter
8
- * chips (`passesFilter`) and an optional view-specific predicate.
9
- * 3. Compute a per-occurrence numeric metric.
10
- * 4. Sort descending by that metric.
11
- * 5. Render via `renderFunctionRows` with the supplied column
12
- * definitions, or show an empty-state if everything was filtered
13
- * out.
14
- *
15
- * This helper accepts a declarative config and emits the JS source for
16
- * one view. Each `view-*.ts` that fits the shape collapses to ~15 lines
17
- * of config; bespoke views (coupling, sccs, search) keep their own
18
- * emitters.
19
- *
20
- * The `metric` and `predicate` (and column `value`) fields are JS
21
- * source strings that close over the in-page locals `occ`, `o`,
22
- * `indexes`, `filterState`, etc. The helper splices them directly into
23
- * the emitted view; that is how the existing per-view emitters work
24
- * too. The skeleton is the only place that knows the rank-and-render
25
- * shape — adding a new ranked view means writing a config, not a new
26
- * `view-*.ts` file from scratch.
27
- */
28
- interface RankedViewColumn {
29
- /** Header label (e.g. "Function", "Callers"). */
30
- label: string;
31
- /**
32
- * JS source for the cell value, spliced VERBATIM into the emitted
33
- * view body — there is no TS type-checking on this expression.
34
- *
35
- * Conventionally a single-arg arrow function `o => …`, where `o`
36
- * is the augmented occurrence: the original `occ` (graph function
37
- * descriptor) plus a `__metric` field carrying the ranking value
38
- * plus any extras the view's `rowExtras` returned (e.g. `__thumb`
39
- * in Wide). The expression closes over the in-page locals
40
- * `displayName` and `packageOfPath` (declared by `dashboardPathUtilsJs`)
41
- * and any helper the view's `preamble` declared.
42
- *
43
- * A typo here (`o => o.callerz`) compiles, lints, and ships — it
44
- * will fail at runtime as an undefined property read, not a build
45
- * error. Keep these expressions minimal and prefer pulling logic
46
- * into `preamble`-declared helpers when complexity grows.
47
- *
48
- * Example: `o => displayName(o.simpleName)`.
49
- */
50
- value: string;
51
- }
52
- interface RankedViewHelpSection {
53
- heading: string;
54
- body: string;
55
- }
56
- interface RankedViewHelp {
57
- title: string;
58
- sections: RankedViewHelpSection[];
59
- }
60
- export interface RankedViewConfig {
61
- /** Stable id (e.g. `'hot'`). Must match the existing tab id. */
62
- id: string;
63
- /** Tab label. */
64
- label: string;
65
- /** Help-drawer copy. */
66
- help: RankedViewHelp;
67
- /**
68
- * JS source for the metric expression, spliced VERBATIM into the
69
- * emitted view body — there is no TS type-checking on this
70
- * expression.
71
- *
72
- * Closes over `occ` (the graph function occurrence) and `indexes`
73
- * (the in-page indexes built by `buildIndexes`). The expression is
74
- * normally a non-negative number — `ranked.sort` uses `b.metric -
75
- * a.metric` so larger values rank higher.
76
- *
77
- * Sentinel: returning `false` skips the row entirely (used by Hot
78
- * and Wide to drop functions with zero callers / zero parameters
79
- * rather than rank them at zero). Returning any other falsy value
80
- * (`0`, `null`, `undefined`, `NaN`) does NOT skip — only literal
81
- * `false`. New views that want a "drop if predicate doesn't match"
82
- * filter should put it in `predicate` instead; the sentinel exists
83
- * because Hot and Wide want different drop conditions per call,
84
- * not a fixed predicate.
85
- *
86
- * Example: `(indexes.callers.get(occ.bodyHash) || []).length`.
87
- */
88
- metric: string;
89
- /**
90
- * Optional JS source for a predicate expression, spliced VERBATIM
91
- * into the emitted view body — there is no TS type-checking on
92
- * this expression.
93
- *
94
- * Closes over `occ` and `filterState`. Truthy = keep; falsy = skip.
95
- * Defaults to `passesFilter(occ, filterState)`. When a predicate
96
- * is supplied it REPLACES the default `passesFilter` call entirely
97
- * — include it in the predicate (e.g. `passesFilter(occ,
98
- * filterState) && occ.calls.length === 0`) when you still want
99
- * chip filtering.
100
- */
101
- predicate?: string;
102
- /**
103
- * Optional JS source emitting extra fields to splice into the row
104
- * via `Object.assign`, spliced VERBATIM into the emitted view body.
105
- * Closes over `occ` and `metric`. Defaults to `{}`. Used by Wide
106
- * to splice in a `__thumb` parameter list.
107
- */
108
- rowExtras?: string;
109
- /**
110
- * Optional JS source for additional helper declarations to emit
111
- * inside the `render` body, before the metric loop. Spliced
112
- * VERBATIM. Used by Wide for the `paramThumb` helper. Helpers
113
- * declared here are visible to `metric`, `predicate`, `rowExtras`,
114
- * and the column `value` expressions.
115
- */
116
- preamble?: string;
117
- /** Columns rendered by `renderFunctionRows`. */
118
- columns: RankedViewColumn[];
119
- /** Section heading text (e.g. "Big functions"). */
120
- headingText: string;
121
- /** Empty-state message when the filter strips everything. */
122
- emptyMessage: string;
123
- /**
124
- * When true, render a search input above the table that filters the
125
- * ranked rows by function simple-name (case-insensitive substring).
126
- * Typing re-filters the table in place; the search box auto-focuses
127
- * when the view activates. Used by the Functions view to absorb the
128
- * former standalone Search subtab.
129
- */
130
- searchByName?: boolean;
131
- /**
132
- * When true, render a Kind single-select and a Package single-select
133
- * dropdown alongside the search box (in one controls row above the table)
134
- * that further narrow the ranked rows. Both default to "all"; selecting a
135
- * value re-filters the table in place. Combines with `searchByName` (Kind,
136
- * Package, then the search box, in that order). Used by the Functions view.
137
- */
138
- filterByKindPackage?: boolean;
139
- /**
140
- * When set, render a checkbox toggle AFTER the search box that narrows the
141
- * table to rows matching `predicate` when checked (off by default).
142
- *
143
- * `predicate` is JS source spliced VERBATIM into the row filter — a boolean
144
- * expression closing over `occ` (and any `preamble`-declared helper). Used by
145
- * the Functions view for a "Test-only" toggle (`distTestOnly(occ)`).
146
- */
147
- filterToggle?: {
148
- label: string;
149
- predicate: string;
150
- };
151
- }
152
- export declare function defineRankedView(config: RankedViewConfig): string;
153
- export {};
154
- //# sourceMappingURL=view-template.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"view-template.d.ts","sourceRoot":"","sources":["../../src/code-paths/view-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,UAAU,gBAAgB;IACxB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AA8BD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAmKjE"}