tech-debt-visualizer 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/reports/assets/report.css +160 -54
- package/dist/reports/html.js +70 -61
- package/package.json +1 -1
|
@@ -43,14 +43,14 @@ body.dashboard-page {
|
|
|
43
43
|
padding-bottom: 2rem;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/* ——— Dashboard header (Grafana
|
|
46
|
+
/* ——— Dashboard header (Grafana top bar: title left, score right) ——— */
|
|
47
47
|
.dashboard-header {
|
|
48
48
|
display: flex;
|
|
49
|
-
align-items:
|
|
49
|
+
align-items: center;
|
|
50
50
|
justify-content: space-between;
|
|
51
51
|
flex-wrap: wrap;
|
|
52
|
-
gap:
|
|
53
|
-
padding:
|
|
52
|
+
gap: 0.75rem;
|
|
53
|
+
padding: 0.75rem 1.5rem;
|
|
54
54
|
background: var(--bg-elevated);
|
|
55
55
|
border-bottom: 1px solid var(--border);
|
|
56
56
|
position: sticky;
|
|
@@ -60,95 +60,111 @@ body.dashboard-page {
|
|
|
60
60
|
|
|
61
61
|
.dashboard-header-left {
|
|
62
62
|
display: flex;
|
|
63
|
-
align-items:
|
|
64
|
-
gap:
|
|
65
|
-
min-width: 0;
|
|
66
|
-
flex: 1;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.dashboard-score-badge {
|
|
70
|
-
flex-shrink: 0;
|
|
71
|
-
line-height: 0;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.dashboard-score-badge .score-badge-svg {
|
|
75
|
-
width: 56px;
|
|
76
|
-
height: auto;
|
|
77
|
-
display: block;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.dashboard-score-badge .score-badge-num { font-size: 22px; }
|
|
81
|
-
.dashboard-score-badge .score-badge-of { font-size: 9px; }
|
|
82
|
-
|
|
83
|
-
.dashboard-hero {
|
|
63
|
+
align-items: baseline;
|
|
64
|
+
gap: 0.75rem;
|
|
84
65
|
min-width: 0;
|
|
85
66
|
}
|
|
86
67
|
|
|
87
68
|
.dashboard-title {
|
|
88
|
-
margin: 0
|
|
69
|
+
margin: 0;
|
|
89
70
|
font-size: 1.125rem;
|
|
90
71
|
font-weight: 600;
|
|
91
72
|
letter-spacing: -0.01em;
|
|
92
73
|
color: var(--text);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
margin: 0 0 0.35rem;
|
|
97
|
-
font-size: 14px;
|
|
98
|
-
line-height: 1.45;
|
|
99
|
-
color: var(--text);
|
|
100
|
-
max-width: 42em;
|
|
74
|
+
white-space: nowrap;
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
text-overflow: ellipsis;
|
|
101
77
|
}
|
|
102
78
|
|
|
103
79
|
.dashboard-meta {
|
|
104
80
|
font-size: 12px;
|
|
105
81
|
color: var(--text-muted);
|
|
82
|
+
white-space: nowrap;
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
text-overflow: ellipsis;
|
|
106
85
|
}
|
|
107
86
|
|
|
108
87
|
.dashboard-header-right {
|
|
109
88
|
display: flex;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
gap: 0.25rem;
|
|
89
|
+
align-items: center;
|
|
90
|
+
gap: 1rem;
|
|
113
91
|
flex-shrink: 0;
|
|
114
92
|
}
|
|
115
93
|
|
|
116
|
-
.dashboard-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
94
|
+
.dashboard-score {
|
|
95
|
+
display: inline-flex;
|
|
96
|
+
align-items: baseline;
|
|
97
|
+
gap: 0.2rem;
|
|
98
|
+
padding: 0.35rem 0.65rem;
|
|
99
|
+
border-radius: var(--radius);
|
|
100
|
+
font-weight: 600;
|
|
120
101
|
}
|
|
121
102
|
|
|
103
|
+
.dashboard-score-value { font-size: 1.25rem; line-height: 1; }
|
|
104
|
+
.dashboard-score-of { font-size: 0.85rem; font-weight: 500; color: var(--text-muted); }
|
|
105
|
+
.dashboard-score-label { font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.04em; margin-left: 0.35rem; opacity: 0.95; }
|
|
106
|
+
|
|
107
|
+
.dashboard-score.tier-1 { background: rgba(204, 0, 0, 0.2); color: #f66; }
|
|
108
|
+
.dashboard-score.tier-2 { background: rgba(232, 93, 0, 0.2); color: #f90; }
|
|
109
|
+
.dashboard-score.tier-3 { background: rgba(184, 134, 11, 0.2); color: #db9; }
|
|
110
|
+
.dashboard-score.tier-4 { background: rgba(0, 102, 153, 0.2); color: #6cf; }
|
|
111
|
+
.dashboard-score.tier-5 { background: rgba(10, 107, 10, 0.2); color: #6c6; }
|
|
112
|
+
|
|
122
113
|
.dashboard-date {
|
|
123
|
-
font-size:
|
|
114
|
+
font-size: 12px;
|
|
124
115
|
color: var(--text-muted);
|
|
125
|
-
opacity: 0.9;
|
|
126
116
|
}
|
|
127
117
|
|
|
128
|
-
/* ——— Main content
|
|
118
|
+
/* ——— Main content: 2×2 dashboard grid ——— */
|
|
129
119
|
.dashboard-main {
|
|
130
|
-
max-width:
|
|
120
|
+
max-width: 1400px;
|
|
131
121
|
margin: 0 auto;
|
|
132
|
-
padding:
|
|
122
|
+
padding: 1rem 1.5rem;
|
|
123
|
+
min-height: calc(100vh - 52px);
|
|
133
124
|
}
|
|
134
125
|
|
|
135
|
-
.dashboard-grid {
|
|
126
|
+
.dashboard-grid-2x2 {
|
|
136
127
|
display: grid;
|
|
128
|
+
grid-template-columns: 1fr 1fr;
|
|
129
|
+
grid-template-rows: auto minmax(320px, 1fr);
|
|
137
130
|
gap: 1rem;
|
|
138
|
-
|
|
131
|
+
align-items: start;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.dashboard-cell {
|
|
135
|
+
min-height: 0;
|
|
136
|
+
min-width: 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.dashboard-cell .panel {
|
|
140
|
+
height: 100%;
|
|
141
|
+
display: flex;
|
|
142
|
+
flex-direction: column;
|
|
139
143
|
}
|
|
140
144
|
|
|
141
|
-
.dashboard-
|
|
142
|
-
|
|
145
|
+
.dashboard-cell .panel-body {
|
|
146
|
+
flex: 1;
|
|
147
|
+
min-height: 0;
|
|
148
|
+
overflow: auto;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.dashboard-cell-score .panel-body-score { flex: 1 1 auto; overflow: visible; }
|
|
152
|
+
|
|
153
|
+
.dashboard-cell-heatmap .panel-body-heatmap,
|
|
154
|
+
.dashboard-cell-list .panel-body {
|
|
155
|
+
min-height: 280px;
|
|
143
156
|
}
|
|
144
157
|
|
|
145
158
|
@media (max-width: 900px) {
|
|
146
|
-
.dashboard-grid-
|
|
159
|
+
.dashboard-grid-2x2 {
|
|
160
|
+
grid-template-columns: 1fr;
|
|
161
|
+
grid-template-rows: auto auto auto auto;
|
|
162
|
+
}
|
|
147
163
|
}
|
|
148
164
|
|
|
149
165
|
@media (max-width: 560px) {
|
|
150
|
-
.dashboard-header { padding: 0.
|
|
151
|
-
.dashboard-main { padding: 1rem; }
|
|
166
|
+
.dashboard-header { padding: 0.6rem 1rem; }
|
|
167
|
+
.dashboard-main { padding: 0.75rem 1rem; }
|
|
152
168
|
}
|
|
153
169
|
|
|
154
170
|
/* ——— Panels (Grafana-style) ——— */
|
|
@@ -193,7 +209,97 @@ body.dashboard-page {
|
|
|
193
209
|
text-align: center;
|
|
194
210
|
}
|
|
195
211
|
|
|
196
|
-
/* ———
|
|
212
|
+
/* ——— Score panel (top-left: shield + caption + stats) ——— */
|
|
213
|
+
.panel-score .panel-body-score {
|
|
214
|
+
text-align: center;
|
|
215
|
+
padding: 1.25rem 1rem;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.panel-score .score-badge {
|
|
219
|
+
display: inline-block;
|
|
220
|
+
margin-bottom: 0.75rem;
|
|
221
|
+
line-height: 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.panel-score .score-badge-svg {
|
|
225
|
+
display: block;
|
|
226
|
+
width: 100px;
|
|
227
|
+
height: auto;
|
|
228
|
+
margin: 0 auto;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.panel-score .score-badge-svg .score-badge-num {
|
|
232
|
+
font-size: 36px;
|
|
233
|
+
font-weight: 800;
|
|
234
|
+
letter-spacing: -0.02em;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.panel-score .score-badge-svg .score-badge-of {
|
|
238
|
+
font-size: 11px;
|
|
239
|
+
font-weight: 700;
|
|
240
|
+
letter-spacing: 0.08em;
|
|
241
|
+
text-transform: uppercase;
|
|
242
|
+
opacity: 0.95;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.panel-score .score-label {
|
|
246
|
+
margin: 0 0 0.25rem;
|
|
247
|
+
font-size: 1rem;
|
|
248
|
+
font-weight: 600;
|
|
249
|
+
color: var(--text);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.panel-score .score-desc {
|
|
253
|
+
margin: 0 0 0.5rem;
|
|
254
|
+
font-size: 13px;
|
|
255
|
+
color: var(--text-muted);
|
|
256
|
+
line-height: 1.45;
|
|
257
|
+
max-width: 280px;
|
|
258
|
+
margin-left: auto;
|
|
259
|
+
margin-right: auto;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.panel-score .score-stats {
|
|
263
|
+
margin: 0;
|
|
264
|
+
font-size: 11px;
|
|
265
|
+
color: var(--text-muted);
|
|
266
|
+
text-transform: uppercase;
|
|
267
|
+
letter-spacing: 0.03em;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* ——— Description of problems panel (top-right) ——— */
|
|
271
|
+
.panel-empty {
|
|
272
|
+
margin: 0;
|
|
273
|
+
font-size: 13px;
|
|
274
|
+
color: var(--text-muted);
|
|
275
|
+
font-style: italic;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.priority-inline {
|
|
279
|
+
display: grid;
|
|
280
|
+
grid-template-columns: 1fr 1fr;
|
|
281
|
+
gap: 1rem;
|
|
282
|
+
margin-top: 1rem;
|
|
283
|
+
padding-top: 1rem;
|
|
284
|
+
border-top: 1px solid var(--border-subtle);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.priority-inline h4 {
|
|
288
|
+
margin: 0 0 0.5rem;
|
|
289
|
+
font-size: 11px;
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
text-transform: uppercase;
|
|
292
|
+
letter-spacing: 0.04em;
|
|
293
|
+
color: var(--text-muted);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.priority-inline .priority-list { margin: 0; }
|
|
297
|
+
|
|
298
|
+
@media (max-width: 600px) {
|
|
299
|
+
.priority-inline { grid-template-columns: 1fr; }
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* ——— Heatmap panel (bottom-left) ——— */
|
|
197
303
|
.panel-heatmap .panel-header-heatmap {
|
|
198
304
|
display: flex;
|
|
199
305
|
flex-wrap: wrap;
|
package/dist/reports/html.js
CHANGED
|
@@ -78,21 +78,6 @@ function buildHtml(run, title, darkMode, css, script) {
|
|
|
78
78
|
};
|
|
79
79
|
const tierColor = tierColors[cleanliness.tier] ?? "#666";
|
|
80
80
|
const scoreBadgeSvg = buildScoreBadgeSvg(cleanliness.tier, tierColor);
|
|
81
|
-
const llmPanelHtml = run.llmOverallAssessment || run.llmOverallRaw
|
|
82
|
-
? `
|
|
83
|
-
<div class="panel panel-llm">
|
|
84
|
-
<div class="panel-header">
|
|
85
|
-
<h2 class="panel-title">LLM overall assessment</h2>
|
|
86
|
-
</div>
|
|
87
|
-
<div class="panel-body">
|
|
88
|
-
<div class="llm-output">${run.llmOverallAssessment
|
|
89
|
-
? renderLlmOutputToHtml(run.llmOverallAssessment)
|
|
90
|
-
: '<div class="llm-prose">' +
|
|
91
|
-
escapeHtml(stripTrailingSeverityAndScore(run.llmOverallRaw ?? "")).replace(/\n/g, "<br>") +
|
|
92
|
-
"</div>"}</div>
|
|
93
|
-
</div>
|
|
94
|
-
</div>`
|
|
95
|
-
: "";
|
|
96
81
|
const statsLine = `${run.fileMetrics.length} files · ${run.debtItems.length} items · ${highCriticalCount} high/crit · ${hotspotCount} hotspots`;
|
|
97
82
|
return `<!DOCTYPE html>
|
|
98
83
|
<html lang="en" data-theme="${theme}">
|
|
@@ -112,67 +97,91 @@ function buildHtml(run, title, darkMode, css, script) {
|
|
|
112
97
|
${!hasLlm ? `<div class="no-llm-banner"><p class="no-llm-cta">Analysis run without LLM — for full results, run with LLM</p></div>` : ""}
|
|
113
98
|
<header class="dashboard-header">
|
|
114
99
|
<div class="dashboard-header-left">
|
|
115
|
-
<
|
|
116
|
-
<
|
|
117
|
-
<h1 class="dashboard-title">${escapeHtml(title)}</h1>
|
|
118
|
-
<p class="dashboard-blurb">${escapeHtml(cleanliness.description)}</p>
|
|
119
|
-
<span class="dashboard-meta">${escapeHtml(run.repoPath)}</span>
|
|
120
|
-
</div>
|
|
100
|
+
<h1 class="dashboard-title">${escapeHtml(title)}</h1>
|
|
101
|
+
<span class="dashboard-meta">${escapeHtml(run.repoPath)}</span>
|
|
121
102
|
</div>
|
|
122
103
|
<div class="dashboard-header-right">
|
|
123
|
-
<
|
|
104
|
+
<div class="dashboard-score tier-${cleanliness.tier}" aria-label="Score ${cleanliness.tier} of 5">
|
|
105
|
+
<span class="dashboard-score-value">${cleanliness.tier}</span>
|
|
106
|
+
<span class="dashboard-score-of">/ 5</span>
|
|
107
|
+
<span class="dashboard-score-label">${escapeHtml(cleanliness.label)}</span>
|
|
108
|
+
</div>
|
|
124
109
|
<span class="dashboard-date">${run.completedAt ?? run.startedAt}</span>
|
|
125
110
|
</div>
|
|
126
111
|
</header>
|
|
127
112
|
|
|
128
113
|
<main class="dashboard-main">
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
114
|
+
<div class="dashboard-grid-2x2">
|
|
115
|
+
<div class="dashboard-cell dashboard-cell-score">
|
|
116
|
+
<div class="panel panel-score tier-${cleanliness.tier}">
|
|
117
|
+
<div class="panel-header">
|
|
118
|
+
<h2 class="panel-title">Technical Debt Cleanliness Score</h2>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="panel-body panel-body-score">
|
|
121
|
+
<div class="score-badge" aria-hidden="true">${scoreBadgeSvg}</div>
|
|
122
|
+
<p class="score-label">${escapeHtml(cleanliness.label)}</p>
|
|
123
|
+
<p class="score-desc">${escapeHtml(cleanliness.description)}</p>
|
|
124
|
+
<p class="score-stats">${statsLine}</p>
|
|
125
|
+
</div>
|
|
141
126
|
</div>
|
|
142
127
|
</div>
|
|
143
|
-
<div class="panel-body panel-body-heatmap">
|
|
144
|
-
<div id="treemap"></div>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
128
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
129
|
+
<div class="dashboard-cell dashboard-cell-problems">
|
|
130
|
+
<div class="panel panel-llm">
|
|
131
|
+
<div class="panel-header">
|
|
132
|
+
<h2 class="panel-title">Description of problems</h2>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="panel-body">
|
|
135
|
+
${run.llmOverallAssessment || run.llmOverallRaw
|
|
136
|
+
? `<div class="llm-output">${run.llmOverallAssessment
|
|
137
|
+
? renderLlmOutputToHtml(run.llmOverallAssessment)
|
|
138
|
+
: '<div class="llm-prose">' +
|
|
139
|
+
escapeHtml(stripTrailingSeverityAndScore(run.llmOverallRaw ?? "")).replace(/\n/g, "<br>") +
|
|
140
|
+
"</div>"}</div>`
|
|
141
|
+
: '<p class="panel-empty">Run with LLM for an overall assessment of problems.</p>'}
|
|
142
|
+
<div class="priority-inline">
|
|
143
|
+
<div class="priority-inline-col">
|
|
144
|
+
<h4>High impact, easier</h4>
|
|
145
|
+
<ul id="q1" class="priority-list"></ul>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="priority-inline-col">
|
|
148
|
+
<h4>High impact, harder</h4>
|
|
149
|
+
<ul id="q2" class="priority-list"></ul>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
156
153
|
</div>
|
|
157
154
|
</div>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
155
|
+
|
|
156
|
+
<div class="dashboard-cell dashboard-cell-heatmap">
|
|
157
|
+
<div class="panel panel-heatmap">
|
|
158
|
+
<div class="panel-header panel-header-heatmap">
|
|
159
|
+
<h2 class="panel-title">Files by debt</h2>
|
|
160
|
+
<p class="panel-desc">Size = complexity + churn. Color = severity. Click for details.</p>
|
|
161
|
+
<div class="legend legend-inline">
|
|
162
|
+
<span><span class="swatch swatch-crit"></span> Critical</span>
|
|
163
|
+
<span><span class="swatch swatch-high"></span> High</span>
|
|
164
|
+
<span><span class="swatch swatch-med"></span> Medium</span>
|
|
165
|
+
<span><span class="swatch swatch-low"></span> Low</span>
|
|
166
|
+
<span><span class="swatch swatch-none"></span> None</span>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
<div class="panel-body panel-body-heatmap">
|
|
170
|
+
<div id="treemap"></div>
|
|
171
|
+
</div>
|
|
165
172
|
</div>
|
|
166
173
|
</div>
|
|
167
|
-
</div>
|
|
168
174
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
<div class="dashboard-cell dashboard-cell-list">
|
|
176
|
+
<div class="panel">
|
|
177
|
+
<div class="panel-header">
|
|
178
|
+
<h2 class="panel-title">Ratings & files</h2>
|
|
179
|
+
<p class="panel-desc">Files rated above none by static or LLM. Click for full details.</p>
|
|
180
|
+
</div>
|
|
181
|
+
<div class="panel-body">
|
|
182
|
+
<ul class="debt-list" id="debtList"></ul>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
176
185
|
</div>
|
|
177
186
|
</div>
|
|
178
187
|
</main>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tech-debt-visualizer",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Language-agnostic CLI that analyzes repos and generates interactive technical debt visualizations with AI-powered insights",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|