@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
package/dist/sessions.js DELETED
@@ -1,288 +0,0 @@
1
- /**
2
- * Session table + session detail rendering — used by fitness/sim tabs.
3
- * Returns JS code as a string.
4
- */
5
- export function dashboardSessionsJs() {
6
- return String.raw `
7
- // =======================================================
8
- // SESSION TABLE (used by fitness/sim tabs)
9
- // =======================================================
10
-
11
- // Per-rule metric column map for the expanded findings table. For these
12
- // graph rules the finding message just repeats the file + the metric, so
13
- // we DROP the Message column and render a dedicated metric column read
14
- // from finding.metadata (persisted on the signal metadata payload).
15
- const RULE_METRIC_COLUMNS = {
16
- 'graph:large-function': { label: 'Lines', key: 'bodyLines' },
17
- 'graph:high-blast-untested': { label: 'Score', key: 'blast' },
18
- 'graph:wide-function': { label: 'Parameters', key: 'paramCount' },
19
- 'graph:cycle': { label: 'Call Cycle', key: 'sccSize' },
20
- };
21
-
22
- /** Derive 3-state session status: 'fail' | 'warn' | 'pass'
23
- * Counts live in the tool-owned opaque payload (summary). */
24
- function sessionStatus(s) {
25
- const sm = (s.payload && s.payload.summary) || {};
26
- if (sm.failed > 0) return 'fail';
27
- if (sm.warnings > 0) return 'warn';
28
- return 'pass';
29
- }
30
-
31
- function statusBadge(status) {
32
- const labels = { fail: 'FAIL', warn: 'WARN', pass: 'PASS' };
33
- const classes = { fail: 'badge-fail', warn: 'badge-warn', pass: 'badge-pass' };
34
- return el('span', {class:'badge ' + classes[status], text: labels[status]});
35
- }
36
-
37
- function renderSessionTable(panel, toolSessions, accentColor) {
38
- if (!toolSessions.length) {
39
- panel.appendChild(el('div', {class:'empty', text:'No sessions yet.'}));
40
- return;
41
- }
42
-
43
- const tool = toolSessions[0].tool;
44
-
45
- const table = el('table', {class:'data-table sortable'});
46
- const thead = el('thead');
47
- const headerRow = el('tr');
48
- ['Timestamp', 'Recipe', 'Pass Rate', 'Status', 'Passed', 'Failed', 'Findings', 'Duration'].forEach(h => {
49
- headerRow.appendChild(el('th', {text: h}));
50
- });
51
- thead.appendChild(headerRow);
52
- table.appendChild(thead);
53
-
54
- const tbody = el('tbody');
55
- toolSessions.forEach((s, idx) => {
56
- const sc = s.score >= 90 ? 'color:var(--success)' : s.score >= 70 ? 'color:var(--warning)' : 'color:var(--error)';
57
- const sm = (s.payload && s.payload.summary) || { total: 0, passed: 0, failed: 0, errors: 0, warnings: 0 };
58
- const row = el('tr', {class:'clickable', id: 'session-row-' + tool + '-' + idx, 'data-session-id': s.id, onclick: () => {
59
- tbody.querySelectorAll('tr.selected').forEach(r => r.classList.remove('selected'));
60
- row.classList.add('selected');
61
- renderDetail(s, idx);
62
- }});
63
- row.appendChild(el('td', {class:'cell-nowrap', text: new Date(s.startedAt).toLocaleString()}));
64
- row.appendChild(el('td', {text: s.recipe || 'default', style:'color:var(--text-muted)'}));
65
- const scoreCell = el('td', {style: 'font-weight:600;' + sc});
66
- scoreCell.textContent = s.score + '%';
67
- row.appendChild(scoreCell);
68
- const badgeCell = el('td');
69
- badgeCell.appendChild(statusBadge(sessionStatus(s)));
70
- row.appendChild(badgeCell);
71
- row.appendChild(el('td', {text: ''+sm.passed, style:'color:var(--success)'}));
72
- row.appendChild(el('td', {text: ''+sm.failed, style: sm.failed > 0 ? 'color:var(--error)' : 'color:var(--text-dim)'}));
73
- row.appendChild(el('td', {text: ''+(sm.errors + (sm.warnings || 0))}));
74
- row.appendChild(el('td', {text: (s.durationMs/1000).toFixed(1)+'s', style:'color:var(--text-dim)'}));
75
- tbody.appendChild(row);
76
- });
77
- table.appendChild(tbody);
78
-
79
- const sessionPag = el('div', {class:'pagination'});
80
- const sec = el('div', {class:'section'}, [el('h3', {text:'Sessions (' + toolSessions.length + ')'}), el('div', {class:'card'}, [table, sessionPag])]);
81
- panel.appendChild(sec);
82
- paginateTable(tbody, sessionPag, 10);
83
-
84
- // Detail container — kept as a direct reference, no global ID lookup needed
85
- const detailContainer = el('div', {id: 'detail-' + tool + '-' + Math.random().toString(36).slice(2,8), class:'section', style:'display:none'});
86
- panel.appendChild(detailContainer);
87
-
88
- function renderDetail(session, idx) {
89
- detailContainer.style.display = 'block';
90
- while (detailContainer.firstChild) detailContainer.removeChild(detailContainer.firstChild);
91
-
92
- // Sessions written before the tool-owned payload split (or by a tool
93
- // that records no per-item detail) have no payload at all. Distinguish
94
- // that from "payload present but empty" so the panel says so explicitly
95
- // rather than rendering a silent empty table.
96
- if (!session.payload) {
97
- detailContainer.appendChild(el('h3', {text: 'Session Detail — ' + new Date(session.startedAt).toLocaleString(), style:'margin-bottom:4px'}));
98
- detailContainer.appendChild(el('div', {class:'empty', text:'No detail recorded for this session.'}));
99
- return;
100
- }
101
-
102
- // Per-item detail lives in the tool-owned opaque payload. Fitness calls
103
- // these "checks"; graph groups signals by rule (relabeled below).
104
- const checks = (session.payload && session.payload.checks) || [];
105
-
106
- // A payload that records no per-item rows (e.g. a clean graph run — graph
107
- // only persists rules that emitted a finding) would otherwise render a
108
- // header-only table that reads as "nothing shows up". Render an explicit
109
- // empty state instead so a clean run is unambiguous.
110
- if (checks.length === 0) {
111
- detailContainer.appendChild(el('h3', {text: 'Session Detail — ' + new Date(session.startedAt).toLocaleString(), style:'margin-bottom:4px'}));
112
- const sm = (session.payload && session.payload.summary) || {};
113
- const clean = !((sm.errors || 0) > 0 || (sm.warnings || 0) > 0);
114
- const subline = el('div', {style:'color:var(--text-dim);font-size:12px;margin-bottom:12px'});
115
- subline.textContent = session.cwd + (session.recipe ? ' — recipe: ' + session.recipe : '');
116
- detailContainer.appendChild(subline);
117
- detailContainer.appendChild(el('div', {class:'empty', text: clean
118
- ? 'No findings — this run was clean. Every rule passed with zero violations.'
119
- : 'No per-rule detail was recorded for this run.'}));
120
- return;
121
- }
122
-
123
- // Compute session-level totals from check findings
124
- let totalErrors = 0;
125
- let totalWarnings = 0;
126
- checks.forEach(c => {
127
- if (c.findings) {
128
- c.findings.forEach(f => {
129
- if (f.severity === 'error') totalErrors++;
130
- else if (f.severity === 'warning') totalWarnings++;
131
- });
132
- }
133
- });
134
-
135
- const headerRow = el('div', {style:'display:flex;align-items:center;justify-content:space-between;margin-bottom:16px'});
136
- const headerLeft = el('div');
137
- headerLeft.appendChild(el('h3', {text: 'Session Detail \u2014 ' + new Date(session.startedAt).toLocaleString(), style:'margin-bottom:4px'}));
138
- const sub = el('div', {style:'color:var(--text-dim);font-size:12px'});
139
- const countParts = [];
140
- if (totalErrors > 0) countParts.push(totalErrors + ' error' + (totalErrors !== 1 ? 's' : ''));
141
- if (totalWarnings > 0) countParts.push(totalWarnings + ' warning' + (totalWarnings !== 1 ? 's' : ''));
142
- const countsStr = countParts.length > 0 ? ' \u2014 ' + countParts.join(', ') : '';
143
- sub.textContent = session.cwd + (session.recipe ? ' \u2014 recipe: ' + session.recipe : '') + countsStr;
144
- headerLeft.appendChild(sub);
145
- headerRow.appendChild(headerLeft);
146
-
147
- detailContainer.appendChild(headerRow);
148
- const filterUid = 'df-' + tool + '-' + idx + '-' + Math.random().toString(36).slice(2,6);
149
-
150
- // Check detail table
151
- const table = el('table', {class:'data-table sortable'});
152
- const thead = el('thead');
153
- const thRow = el('tr');
154
- // Graph groups findings by rule, not by check — relabel that one
155
- // column so the header reads in the tool's own vocabulary. The
156
- // structural payload shape is identical; only the label differs.
157
- const itemColumn = tool === 'graph' ? 'Rule' : 'Check';
158
- // Graph rules are dataset queries, not timed units — their per-rule
159
- // duration is always 0ms, so drop the Duration column for graph
160
- // sessions. Fitness/sim checks ARE timed; keep it for them.
161
- const showDuration = tool !== 'graph';
162
- const itemHeaders = ['', itemColumn, 'Status', 'Errors', 'Warnings', 'Findings'];
163
- if (showDuration) itemHeaders.push('Duration');
164
- itemHeaders.forEach(h => {
165
- thRow.appendChild(el('th', {text: h}));
166
- });
167
- thead.appendChild(thRow);
168
- table.appendChild(thead);
169
-
170
- const tbody = el('tbody');
171
- // Sort rules/checks by severity weight: most errors first, then by
172
- // warning count as a tiebreak (error-then-warning, stable).
173
- const sortedChecks = [...checks].sort((a, b) => {
174
- const aErrors = a.findings ? a.findings.filter(f => f.severity === 'error').length : 0;
175
- const bErrors = b.findings ? b.findings.filter(f => f.severity === 'error').length : 0;
176
- if (bErrors !== aErrors) return bErrors - aErrors;
177
- const aWarn = a.findings ? a.findings.filter(f => f.severity === 'warning').length : 0;
178
- const bWarn = b.findings ? b.findings.filter(f => f.severity === 'warning').length : 0;
179
- return bWarn - aWarn;
180
- });
181
- sortedChecks.forEach((check, i) => {
182
- const checkErrors = check.findings ? check.findings.filter(f => f.severity === 'error').length : 0;
183
- const checkWarnings = check.findings ? check.findings.filter(f => f.severity === 'warning').length : 0;
184
- const findingsTotal = checkErrors + checkWarnings;
185
- const hasFindings = findingsTotal > 0;
186
- const expanderId = filterUid + '-exp-' + i;
187
- const checkStatusVal = check.passed ? 'pass' : 'fail';
188
-
189
- const arrowCell = el('td', {style:'width:24px;text-align:center;color:var(--text-dim);font-size:12px'});
190
- if (hasFindings) arrowCell.textContent = '\u25B6';
191
-
192
- const row = el('tr', {class: hasFindings ? 'clickable' : '', 'data-check-status': checkStatusVal, onclick: hasFindings ? () => {
193
- const exp = document.getElementById(expanderId);
194
- if (exp) {
195
- const isOpen = exp.classList.toggle('open');
196
- exp.style.display = isOpen ? 'table-row' : 'none';
197
- arrowCell.textContent = isOpen ? '\u25BC' : '\u25B6';
198
- }
199
- row.classList.toggle('expanded');
200
- } : undefined});
201
- row.appendChild(arrowCell);
202
- row.appendChild(el('td', {text: check.checkSlug, style:'font-weight:500'}));
203
-
204
- const statusCell = el('td');
205
- statusCell.appendChild(el('span', {class:'badge ' + (check.passed ? 'badge-pass' : 'badge-fail'), text: check.passed ? 'PASS' : 'FAIL'}));
206
- row.appendChild(statusCell);
207
- row.appendChild(el('td', {text: ''+checkErrors, style: checkErrors > 0 ? 'color:var(--error)' : 'color:var(--text-dim)'}));
208
- row.appendChild(el('td', {text: ''+checkWarnings, style: checkWarnings > 0 ? 'color:var(--warning)' : 'color:var(--text-dim)'}));
209
- row.appendChild(el('td', {text: ''+findingsTotal, style: findingsTotal > 0 ? 'color:var(--text)' : 'color:var(--text-dim)'}));
210
- if (showDuration) row.appendChild(el('td', {text: check.durationMs > 0 ? check.durationMs + 'ms' : '0ms', style:'color:var(--text-dim)'}));
211
- tbody.appendChild(row);
212
-
213
- if (hasFindings) {
214
- const expRow = el('tr', {id: expanderId, class:'expander-row', 'data-check-status': checkStatusVal});
215
- const expCell = el('td', {colspan: '' + itemHeaders.length, style:'padding:0'});
216
- const expContent = el('div', {class:'expander-content'});
217
-
218
- const fTable = el('table', {class:'data-table', style:'margin:0;border:none'});
219
- const fHead = el('thead');
220
- const fHeaderRow = el('tr');
221
- // Per-rule column shape. Most rules render the default
222
- // [Severity, Message, File, Suggestion]. The graph metric rules
223
- // below repeat the file + metric in their message, so they DROP
224
- // Message and ADD a metric column read from finding.metadata.
225
- const metricColumn = RULE_METRIC_COLUMNS[check.checkSlug];
226
- const fHeaders = metricColumn
227
- ? ['Severity', 'File', metricColumn.label, 'Suggestion']
228
- : ['Severity', 'Message', 'File', 'Suggestion'];
229
- fHeaders.forEach(h => {
230
- fHeaderRow.appendChild(el('th', {text: h, style:'font-size:11px;padding:6px 12px'}));
231
- });
232
- fHead.appendChild(fHeaderRow);
233
- fTable.appendChild(fHead);
234
-
235
- const fBody = el('tbody');
236
- // Sort findings within the rule: errors first, then warnings (stable).
237
- const sevWeight = { error: 0, warning: 1 };
238
- const sortedFindings = [...check.findings].sort((a, b) =>
239
- (sevWeight[a.severity] ?? 2) - (sevWeight[b.severity] ?? 2));
240
- sortedFindings.forEach(f => {
241
- const fRow = el('tr');
242
- const sevCell = el('td', {style:'padding:6px 12px'});
243
- sevCell.appendChild(el('span', {class:'finding-sev ' + f.severity, text: f.severity}));
244
- fRow.appendChild(sevCell);
245
- const fileText = f.filePath ? f.filePath + (f.line ? ':' + f.line : '') : '\u2014';
246
- if (metricColumn) {
247
- fRow.appendChild(el('td', {text: fileText, style:'padding:6px 12px;color:var(--text-dim);font-size:12px'}));
248
- const mv = f.metadata ? f.metadata[metricColumn.key] : undefined;
249
- fRow.appendChild(el('td', {text: (mv === undefined || mv === null) ? '\u2014' : '' + mv, style:'padding:6px 12px;font-size:13px'}));
250
- } else {
251
- fRow.appendChild(el('td', {text: f.message, style:'padding:6px 12px;font-size:13px'}));
252
- fRow.appendChild(el('td', {text: fileText, style:'padding:6px 12px;color:var(--text-dim);font-size:12px'}));
253
- }
254
- fRow.appendChild(el('td', {text: f.suggestion || '\u2014', style:'padding:6px 12px;color:var(--accent);font-size:12px'}));
255
- fBody.appendChild(fRow);
256
- });
257
- fTable.appendChild(fBody);
258
- // Wrap the wide findings table in a horizontal-scroll container so
259
- // long file paths / messages scroll inside the card instead of
260
- // overrunning the section (mirrors the .coupling-scroll fix).
261
- const fScroll = el('div', {style:'overflow-x:auto;max-width:100%'}, [fTable]);
262
- expContent.appendChild(fScroll);
263
- expCell.appendChild(expContent);
264
- expRow.appendChild(expCell);
265
- tbody.appendChild(expRow);
266
- }
267
- });
268
- table.appendChild(tbody);
269
- const detailPag = el('div', {class:'pagination'});
270
- detailContainer.appendChild(el('div', {class:'card'}, [table, detailPag]));
271
-
272
- // Enable sorting on the detail table
273
- makeSortable(table);
274
-
275
- // Paginate
276
- paginateGroupedRows(tbody, detailPag, 10);
277
- }
278
-
279
- // Auto-show latest and highlight first row
280
- renderDetail(toolSessions[0], 0);
281
- const firstRow = tbody.querySelector('tr');
282
- if (firstRow) firstRow.classList.add('selected');
283
- }
284
-
285
-
286
- `;
287
- }
288
- //# sourceMappingURL=sessions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,mBAAmB;IACjC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwRlB,CAAC;AACF,CAAC"}
@@ -1,13 +0,0 @@
1
- /**
2
- * `el(tag, attrs, children)` — tiny DOM-builder helper used everywhere
3
- * a string of `document.createElement` + setAttribute calls would
4
- * otherwise live.
5
- *
6
- * Special attribute keys: `text` sets `textContent`, `class` sets
7
- * `className`, anything starting with `on` is treated as an event
8
- * listener (e.g. `onclick`), everything else passes through to
9
- * `setAttribute`. `children` may include strings (auto-wrapped into
10
- * text nodes) or `null`/`undefined` (skipped).
11
- */
12
- export declare function dashboardElJs(): string;
13
- //# sourceMappingURL=el.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"el.d.ts","sourceRoot":"","sources":["../../src/shared/el.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,IAAI,MAAM,CActC"}
package/dist/shared/el.js DELETED
@@ -1,27 +0,0 @@
1
- /**
2
- * `el(tag, attrs, children)` — tiny DOM-builder helper used everywhere
3
- * a string of `document.createElement` + setAttribute calls would
4
- * otherwise live.
5
- *
6
- * Special attribute keys: `text` sets `textContent`, `class` sets
7
- * `className`, anything starting with `on` is treated as an event
8
- * listener (e.g. `onclick`), everything else passes through to
9
- * `setAttribute`. `children` may include strings (auto-wrapped into
10
- * text nodes) or `null`/`undefined` (skipped).
11
- */
12
- export function dashboardElJs() {
13
- return String.raw `
14
- function el(tag, attrs, children) {
15
- const e = document.createElement(tag);
16
- if (attrs) Object.entries(attrs).forEach(([k,v]) => {
17
- if (k === 'text') e.textContent = v;
18
- else if (k === 'class') e.className = v;
19
- else if (k.startsWith('on')) e.addEventListener(k.slice(2), v);
20
- else e.setAttribute(k, v);
21
- });
22
- if (children) children.forEach(c => { if (typeof c === 'string') e.appendChild(document.createTextNode(c)); else if (c) e.appendChild(c); });
23
- return e;
24
- }
25
- `;
26
- }
27
- //# sourceMappingURL=el.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"el.js","sourceRoot":"","sources":["../../src/shared/el.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;CAYlB,CAAC;AACF,CAAC"}
@@ -1,15 +0,0 @@
1
- /**
2
- * Pagination helpers — `paginateTable`, `paginateGroupedRows`, and the
3
- * page-button renderer.
4
- *
5
- * Every data-table in the dashboard paginates at 10 rows/page (or
6
- * 10 groups/page when expander rows are present). The grouped variant
7
- * keeps a data row and its trailing `.expander-row` together so they
8
- * page as one unit.
9
- *
10
- * `renderPageButtons` is shared between both paginators; the checks
11
- * catalog declares its own paginator inline that also calls this
12
- * helper, so it must be in scope before any caller.
13
- */
14
- export declare function dashboardPaginationJs(): string;
15
- //# sourceMappingURL=pagination.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/shared/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAkG9C"}
@@ -1,113 +0,0 @@
1
- /**
2
- * Pagination helpers — `paginateTable`, `paginateGroupedRows`, and the
3
- * page-button renderer.
4
- *
5
- * Every data-table in the dashboard paginates at 10 rows/page (or
6
- * 10 groups/page when expander rows are present). The grouped variant
7
- * keeps a data row and its trailing `.expander-row` together so they
8
- * page as one unit.
9
- *
10
- * `renderPageButtons` is shared between both paginators; the checks
11
- * catalog declares its own paginator inline that also calls this
12
- * helper, so it must be in scope before any caller.
13
- */
14
- export function dashboardPaginationJs() {
15
- return String.raw `
16
- // =======================================================
17
- // PAGINATION HELPERS
18
- // =======================================================
19
-
20
- function renderPageButtons(container, currentPage, totalPages, goToPage) {
21
- container.appendChild(el('button', {class:'pagination-btn' + (currentPage === 0 ? ' disabled' : ''), text:'← Prev', onclick: () => { if (currentPage > 0) goToPage(currentPage - 1); }}));
22
-
23
- const pages = [];
24
- for (let p = 0; p < totalPages; p++) {
25
- if (p < 2 || p >= totalPages - 2 || Math.abs(p - currentPage) <= 1) {
26
- pages.push(p);
27
- } else if (pages.length > 0 && pages[pages.length - 1] !== -1) {
28
- pages.push(-1);
29
- }
30
- }
31
-
32
- pages.forEach(p => {
33
- if (p === -1) {
34
- container.appendChild(el('span', {style:'color:var(--text-dim);padding:4px 4px;font-size:12px', text:'…'}));
35
- } else {
36
- container.appendChild(el('button', {class:'pagination-btn' + (p === currentPage ? ' active' : ''), text: ''+(p+1), onclick: () => goToPage(p)}));
37
- }
38
- });
39
-
40
- container.appendChild(el('button', {class:'pagination-btn' + (currentPage >= totalPages-1 ? ' disabled' : ''), text:'Next →', onclick: () => { if (currentPage < totalPages-1) goToPage(currentPage + 1); }}));
41
- }
42
-
43
- function paginateTable(tbody, paginationContainer, pageSize) {
44
- const rows = Array.from(tbody.children);
45
- let currentPage = 0;
46
- const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
47
-
48
- function renderPage() {
49
- const start = currentPage * pageSize;
50
- const end = start + pageSize;
51
- rows.forEach((row, i) => { row.style.display = (i >= start && i < end) ? '' : 'none'; });
52
-
53
- while (paginationContainer.firstChild) paginationContainer.removeChild(paginationContainer.firstChild);
54
- if (rows.length <= pageSize) return;
55
-
56
- const info = el('div', {class:'pagination-info', text: 'Showing ' + (start+1) + '-' + Math.min(end, rows.length) + ' of ' + rows.length});
57
- paginationContainer.appendChild(info);
58
-
59
- const btns = el('div', {class:'pagination-btns'});
60
- renderPageButtons(btns, currentPage, totalPages, (p) => { currentPage = p; renderPage(); });
61
- paginationContainer.appendChild(btns);
62
- }
63
-
64
- renderPage();
65
- }
66
-
67
- function paginateGroupedRows(tbody, paginationContainer, pageSize) {
68
- const allRows = Array.from(tbody.children);
69
- const groups = [];
70
- for (let i = 0; i < allRows.length; i++) {
71
- const row = allRows[i];
72
- if (row.classList.contains('expander-row')) continue;
73
- const group = [row];
74
- if (i + 1 < allRows.length && allRows[i+1].classList.contains('expander-row')) {
75
- group.push(allRows[i+1]);
76
- }
77
- groups.push(group);
78
- }
79
-
80
- let currentPage = 0;
81
- const totalPages = Math.max(1, Math.ceil(groups.length / pageSize));
82
-
83
- function renderPage() {
84
- const start = currentPage * pageSize;
85
- const end = start + pageSize;
86
- groups.forEach((group, i) => {
87
- const visible = i >= start && i < end;
88
- group.forEach(row => {
89
- if (row.classList.contains('expander-row')) {
90
- row.dataset.paged = visible ? 'yes' : 'no';
91
- if (!visible) row.style.display = 'none';
92
- } else {
93
- row.style.display = visible ? '' : 'none';
94
- }
95
- });
96
- });
97
-
98
- while (paginationContainer.firstChild) paginationContainer.removeChild(paginationContainer.firstChild);
99
- if (groups.length <= pageSize) return;
100
-
101
- const info = el('div', {class:'pagination-info', text: 'Showing ' + (start+1) + '-' + Math.min(end, groups.length) + ' of ' + groups.length + ' checks'});
102
- paginationContainer.appendChild(info);
103
-
104
- const btns = el('div', {class:'pagination-btns'});
105
- renderPageButtons(btns, currentPage, totalPages, (p) => { currentPage = p; renderPage(); });
106
- paginationContainer.appendChild(btns);
107
- }
108
-
109
- renderPage();
110
- }
111
- `;
112
- }
113
- //# sourceMappingURL=pagination.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/shared/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGlB,CAAC;AACF,CAAC"}
@@ -1,14 +0,0 @@
1
- /**
2
- * Sortable-table activation.
3
- *
4
- * `makeSortable(table)` wires click handlers to each `<th>` so columns
5
- * can be sorted asc/desc with a numeric/date/string fallback. Keeps
6
- * any trailing `.expander-row` glued to its parent during sort.
7
- *
8
- * After all rendering, a `setTimeout(0)` pass scans the DOM for
9
- * `.data-table.sortable` elements and activates each — this catches
10
- * tables created during the synchronous render but defers the
11
- * activation until after `renderXxxTab()` calls have returned.
12
- */
13
- export declare function dashboardSortableJs(): string;
14
- //# sourceMappingURL=sortable.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sortable.d.ts","sourceRoot":"","sources":["../../src/shared/sortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAuF5C"}
@@ -1,101 +0,0 @@
1
- /**
2
- * Sortable-table activation.
3
- *
4
- * `makeSortable(table)` wires click handlers to each `<th>` so columns
5
- * can be sorted asc/desc with a numeric/date/string fallback. Keeps
6
- * any trailing `.expander-row` glued to its parent during sort.
7
- *
8
- * After all rendering, a `setTimeout(0)` pass scans the DOM for
9
- * `.data-table.sortable` elements and activates each — this catches
10
- * tables created during the synchronous render but defers the
11
- * activation until after `renderXxxTab()` calls have returned.
12
- */
13
- export function dashboardSortableJs() {
14
- return String.raw `
15
- // =======================================================
16
- // SORTABLE TABLE COLUMNS
17
- // =======================================================
18
-
19
- function makeSortable(table) {
20
- const thead = table.querySelector('thead');
21
- const tbody = table.querySelector('tbody');
22
- if (!thead || !tbody) return;
23
-
24
- const headers = Array.from(thead.querySelectorAll('th'));
25
- let sortCol = -1;
26
- let sortAsc = true;
27
-
28
- headers.forEach((th, colIdx) => {
29
- if (!th.textContent.trim()) return; // skip empty headers (arrow column)
30
- th.style.cursor = 'pointer';
31
- th.style.userSelect = 'none';
32
- th.addEventListener('click', () => {
33
- if (sortCol === colIdx) {
34
- sortAsc = !sortAsc;
35
- } else {
36
- sortCol = colIdx;
37
- sortAsc = true;
38
- }
39
-
40
- // Update sort indicators
41
- headers.forEach(h => { h.dataset.sort = ''; });
42
- th.dataset.sort = sortAsc ? 'asc' : 'desc';
43
-
44
- // Collect data rows with their expander rows
45
- const allRows = Array.from(tbody.children);
46
- const groups = [];
47
- for (let i = 0; i < allRows.length; i++) {
48
- const row = allRows[i];
49
- if (row.classList.contains('expander-row')) continue;
50
- const group = [row];
51
- if (i + 1 < allRows.length && allRows[i+1].classList.contains('expander-row')) {
52
- group.push(allRows[i+1]);
53
- }
54
- groups.push(group);
55
- }
56
-
57
- groups.sort((a, b) => {
58
- const aText = (a[0].children[colIdx]?.textContent || '').trim();
59
- const bText = (b[0].children[colIdx]?.textContent || '').trim();
60
- // Try numeric comparison
61
- const aNum = parseFloat(aText);
62
- const bNum = parseFloat(bText);
63
- if (!isNaN(aNum) && !isNaN(bNum)) {
64
- return sortAsc ? aNum - bNum : bNum - aNum;
65
- }
66
- // Date detection (contains / or -)
67
- const aDate = Date.parse(aText);
68
- const bDate = Date.parse(bText);
69
- if (!isNaN(aDate) && !isNaN(bDate)) {
70
- return sortAsc ? aDate - bDate : bDate - aDate;
71
- }
72
- // String comparison
73
- return sortAsc ? aText.localeCompare(bText) : bText.localeCompare(aText);
74
- });
75
-
76
- // Reorder DOM — append each group (data row + optional expander)
77
- groups.forEach(group => {
78
- group.forEach(row => tbody.appendChild(row));
79
- });
80
-
81
- // Re-paginate if a pagination container exists after the table
82
- const pagContainer = table.parentElement?.querySelector('.pagination');
83
- if (pagContainer) {
84
- const hasExpanders = groups.some(g => g.length > 1);
85
- if (hasExpanders) {
86
- paginateGroupedRows(tbody, pagContainer, 10);
87
- } else {
88
- paginateTable(tbody, pagContainer, 10);
89
- }
90
- }
91
- });
92
- });
93
- }
94
-
95
- // After all rendering: init sorting
96
- setTimeout(() => {
97
- document.querySelectorAll('.data-table.sortable').forEach(t => makeSortable(t));
98
- }, 0);
99
- `;
100
- }
101
- //# sourceMappingURL=sortable.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sortable.js","sourceRoot":"","sources":["../../src/shared/sortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFlB,CAAC;AACF,CAAC"}
@@ -1,16 +0,0 @@
1
- /**
2
- * Tab activator registry — runtime side.
3
- *
4
- * Decouples cross-tab navigation from "tab X is loaded into the page"
5
- * guards. The Overview row-click handler asks the registry to
6
- * activate the tab for a given session; each tab tooling (Code Paths
7
- * today; future tabs like fit-detail, sim-detail, etc.) registers
8
- * its activator at module init.
9
- *
10
- * New tabs that need session-aware deep-linking should call
11
- * `registerTabActivator(<session.tool>, fn)` at the top of their
12
- * JS-string emitter — the same place `dashboardCodePathsJs()` does
13
- * for `'graph'`.
14
- */
15
- export declare function dashboardTabActivatorsJs(): string;
16
- //# sourceMappingURL=tab-activators.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tab-activators.d.ts","sourceRoot":"","sources":["../../src/shared/tab-activators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAiBjD"}
@@ -1,33 +0,0 @@
1
- /**
2
- * Tab activator registry — runtime side.
3
- *
4
- * Decouples cross-tab navigation from "tab X is loaded into the page"
5
- * guards. The Overview row-click handler asks the registry to
6
- * activate the tab for a given session; each tab tooling (Code Paths
7
- * today; future tabs like fit-detail, sim-detail, etc.) registers
8
- * its activator at module init.
9
- *
10
- * New tabs that need session-aware deep-linking should call
11
- * `registerTabActivator(<session.tool>, fn)` at the top of their
12
- * JS-string emitter — the same place `dashboardCodePathsJs()` does
13
- * for `'graph'`.
14
- */
15
- export function dashboardTabActivatorsJs() {
16
- return String.raw `
17
- // =======================================================
18
- // TAB ACTIVATOR REGISTRY
19
- // =======================================================
20
- const tabActivators = {};
21
- function registerTabActivator(key, fn) {
22
- tabActivators[key] = fn;
23
- }
24
- function activateTabForSession(session) {
25
- if (!session) return false;
26
- const fn = tabActivators[session.tool];
27
- if (typeof fn !== 'function') return false;
28
- fn(session.id);
29
- return true;
30
- }
31
- `;
32
- }
33
- //# sourceMappingURL=tab-activators.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tab-activators.js","sourceRoot":"","sources":["../../src/shared/tab-activators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;CAelB,CAAC;AACF,CAAC"}