bug-report-js 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +144 -0
- package/background.js +279 -0
- package/content.js +905 -0
- package/icons/icon128.png +0 -0
- package/icons/icon16.png +0 -0
- package/icons/icon48.png +0 -0
- package/manifest.json +43 -0
- package/package.json +27 -0
- package/popup.css +289 -0
- package/popup.html +92 -0
- package/popup.js +126 -0
- package/report-template.js +623 -0
- package/sanitizer.js +262 -0
- package/website/README.md +282 -0
- package/website/bug-report.js +1089 -0
- package/website/docs.html +241 -0
- package/website/index.html +996 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* report-template.js — Shared HTML Report Template Generator
|
|
3
|
+
*
|
|
4
|
+
* Builds a self-contained, styled HTML developer dashboard for bug reports.
|
|
5
|
+
* Used by both background.js (extension) and bug-report.js (widget).
|
|
6
|
+
*
|
|
7
|
+
* @param {Object} reportData - The sanitized report data object
|
|
8
|
+
* @returns {string} Complete HTML document string
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const ReportTemplate = (() => {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Escape HTML special characters to prevent XSS in the report.
|
|
15
|
+
*/
|
|
16
|
+
function escapeHtml(str) {
|
|
17
|
+
if (!str || typeof str !== 'string') return str || '';
|
|
18
|
+
return str
|
|
19
|
+
.replace(/&/g, '&')
|
|
20
|
+
.replace(/</g, '<')
|
|
21
|
+
.replace(/>/g, '>')
|
|
22
|
+
.replace(/"/g, '"')
|
|
23
|
+
.replace(/'/g, ''');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Format JSON with syntax highlighting spans.
|
|
28
|
+
*/
|
|
29
|
+
function syntaxHighlight(json) {
|
|
30
|
+
if (typeof json !== 'string') {
|
|
31
|
+
json = JSON.stringify(json, null, 2);
|
|
32
|
+
}
|
|
33
|
+
json = escapeHtml(json);
|
|
34
|
+
return json.replace(
|
|
35
|
+
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
|
|
36
|
+
function (match) {
|
|
37
|
+
let cls = 'json-number';
|
|
38
|
+
if (/^"/.test(match)) {
|
|
39
|
+
if (/:$/.test(match)) {
|
|
40
|
+
cls = 'json-key';
|
|
41
|
+
} else {
|
|
42
|
+
cls = 'json-string';
|
|
43
|
+
}
|
|
44
|
+
} else if (/true|false/.test(match)) {
|
|
45
|
+
cls = 'json-boolean';
|
|
46
|
+
} else if (/null/.test(match)) {
|
|
47
|
+
cls = 'json-null';
|
|
48
|
+
}
|
|
49
|
+
return '<span class="' + cls + '">' + match + '</span>';
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Build the complete HTML report.
|
|
56
|
+
*/
|
|
57
|
+
function build(data) {
|
|
58
|
+
const {
|
|
59
|
+
schemaVersion,
|
|
60
|
+
reportTimestamp,
|
|
61
|
+
extensionVersion,
|
|
62
|
+
widgetVersion,
|
|
63
|
+
pageMetadata,
|
|
64
|
+
userDescription,
|
|
65
|
+
screenshotBase64,
|
|
66
|
+
interactions,
|
|
67
|
+
consoleLogs,
|
|
68
|
+
jsErrors,
|
|
69
|
+
networkRequests,
|
|
70
|
+
sanitizationSummary,
|
|
71
|
+
captureLimitations,
|
|
72
|
+
} = data;
|
|
73
|
+
|
|
74
|
+
const toolVersion = extensionVersion || widgetVersion || 'unknown';
|
|
75
|
+
const reportTime = reportTimestamp ? new Date(reportTimestamp).toLocaleString('de-DE', {
|
|
76
|
+
year: 'numeric', month: '2-digit', day: '2-digit',
|
|
77
|
+
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
|
78
|
+
}) : 'N/A';
|
|
79
|
+
|
|
80
|
+
const actual = userDescription?.actual || 'Keine Angabe';
|
|
81
|
+
const expected = userDescription?.expected || 'Keine Angabe';
|
|
82
|
+
|
|
83
|
+
return `<!DOCTYPE html>
|
|
84
|
+
<html lang="de">
|
|
85
|
+
<head>
|
|
86
|
+
<meta charset="UTF-8">
|
|
87
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
88
|
+
<title>Bug Report — ${escapeHtml(reportTime)}</title>
|
|
89
|
+
<style>
|
|
90
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
91
|
+
Bug Report HTML Dashboard — Styles
|
|
92
|
+
═══════════════════════════════════════════════════════════════ */
|
|
93
|
+
|
|
94
|
+
:root {
|
|
95
|
+
--bg-primary: #0f1117;
|
|
96
|
+
--bg-secondary: #1a1d27;
|
|
97
|
+
--bg-card: #222636;
|
|
98
|
+
--bg-card-hover: #2a2f42;
|
|
99
|
+
--border: #2d3348;
|
|
100
|
+
--text-primary: #e8eaf0;
|
|
101
|
+
--text-secondary: #9096a8;
|
|
102
|
+
--text-muted: #636882;
|
|
103
|
+
--accent: #6366f1;
|
|
104
|
+
--accent-hover: #7577f5;
|
|
105
|
+
--accent-glow: rgba(99, 102, 241, 0.15);
|
|
106
|
+
--danger: #ef4444;
|
|
107
|
+
--success: #22c55e;
|
|
108
|
+
--warning: #f59e0b;
|
|
109
|
+
--info: #3b82f6;
|
|
110
|
+
--radius: 12px;
|
|
111
|
+
--radius-sm: 8px;
|
|
112
|
+
--font-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
|
|
113
|
+
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', Roboto, sans-serif;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
117
|
+
|
|
118
|
+
body {
|
|
119
|
+
font-family: var(--font-sans);
|
|
120
|
+
background: var(--bg-primary);
|
|
121
|
+
color: var(--text-primary);
|
|
122
|
+
line-height: 1.6;
|
|
123
|
+
-webkit-font-smoothing: antialiased;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.container {
|
|
127
|
+
max-width: 960px;
|
|
128
|
+
margin: 0 auto;
|
|
129
|
+
padding: 32px 24px 64px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* ── Header ─────────────────────────────────────────────────── */
|
|
133
|
+
|
|
134
|
+
.report-header {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: 12px;
|
|
138
|
+
margin-bottom: 8px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.report-logo { font-size: 32px; }
|
|
142
|
+
|
|
143
|
+
.report-title {
|
|
144
|
+
font-size: 24px;
|
|
145
|
+
font-weight: 800;
|
|
146
|
+
letter-spacing: -0.03em;
|
|
147
|
+
flex: 1;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.report-badge {
|
|
151
|
+
font-size: 11px;
|
|
152
|
+
color: var(--text-muted);
|
|
153
|
+
background: var(--bg-secondary);
|
|
154
|
+
padding: 4px 10px;
|
|
155
|
+
border-radius: 20px;
|
|
156
|
+
border: 1px solid var(--border);
|
|
157
|
+
font-weight: 500;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.report-sub {
|
|
161
|
+
font-size: 13px;
|
|
162
|
+
color: var(--text-muted);
|
|
163
|
+
margin-bottom: 28px;
|
|
164
|
+
padding-bottom: 20px;
|
|
165
|
+
border-bottom: 1px solid var(--border);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ── Sections ───────────────────────────────────────────────── */
|
|
169
|
+
|
|
170
|
+
.section {
|
|
171
|
+
margin-bottom: 24px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.section-header {
|
|
175
|
+
display: flex;
|
|
176
|
+
align-items: center;
|
|
177
|
+
gap: 8px;
|
|
178
|
+
cursor: pointer;
|
|
179
|
+
padding: 14px 16px;
|
|
180
|
+
background: var(--bg-secondary);
|
|
181
|
+
border: 1px solid var(--border);
|
|
182
|
+
border-radius: var(--radius);
|
|
183
|
+
transition: all 0.2s ease;
|
|
184
|
+
user-select: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.section-header:hover {
|
|
188
|
+
background: var(--bg-card);
|
|
189
|
+
border-color: var(--accent);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.section-icon { font-size: 18px; }
|
|
193
|
+
|
|
194
|
+
.section-title {
|
|
195
|
+
font-size: 14px;
|
|
196
|
+
font-weight: 700;
|
|
197
|
+
flex: 1;
|
|
198
|
+
letter-spacing: -0.01em;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.section-count {
|
|
202
|
+
font-size: 11px;
|
|
203
|
+
background: var(--accent-glow);
|
|
204
|
+
color: var(--accent);
|
|
205
|
+
padding: 2px 8px;
|
|
206
|
+
border-radius: 12px;
|
|
207
|
+
font-weight: 600;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.section-chevron {
|
|
211
|
+
font-size: 12px;
|
|
212
|
+
color: var(--text-muted);
|
|
213
|
+
transition: transform 0.2s ease;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.section-body {
|
|
217
|
+
margin-top: 8px;
|
|
218
|
+
padding: 16px;
|
|
219
|
+
background: var(--bg-secondary);
|
|
220
|
+
border: 1px solid var(--border);
|
|
221
|
+
border-radius: var(--radius);
|
|
222
|
+
display: none;
|
|
223
|
+
animation: slideDown 0.2s ease;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.section.open .section-body { display: block; }
|
|
227
|
+
.section.open .section-chevron { transform: rotate(90deg); }
|
|
228
|
+
|
|
229
|
+
@keyframes slideDown {
|
|
230
|
+
from { opacity: 0; transform: translateY(-4px); }
|
|
231
|
+
to { opacity: 1; transform: translateY(0); }
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* ── Metadata Grid ──────────────────────────────────────────── */
|
|
235
|
+
|
|
236
|
+
.meta-grid {
|
|
237
|
+
display: grid;
|
|
238
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
239
|
+
gap: 10px;
|
|
240
|
+
margin-bottom: 24px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.meta-card {
|
|
244
|
+
background: var(--bg-card);
|
|
245
|
+
border: 1px solid var(--border);
|
|
246
|
+
border-radius: var(--radius-sm);
|
|
247
|
+
padding: 12px 14px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.meta-label {
|
|
251
|
+
font-size: 10px;
|
|
252
|
+
text-transform: uppercase;
|
|
253
|
+
letter-spacing: 0.06em;
|
|
254
|
+
color: var(--text-muted);
|
|
255
|
+
margin-bottom: 4px;
|
|
256
|
+
font-weight: 600;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.meta-value {
|
|
260
|
+
font-size: 13px;
|
|
261
|
+
font-weight: 600;
|
|
262
|
+
word-break: break-all;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.meta-value.mono {
|
|
266
|
+
font-family: var(--font-mono);
|
|
267
|
+
font-size: 12px;
|
|
268
|
+
font-weight: 500;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* ── User Description ───────────────────────────────────────── */
|
|
272
|
+
|
|
273
|
+
.user-desc {
|
|
274
|
+
display: grid;
|
|
275
|
+
grid-template-columns: 1fr 1fr;
|
|
276
|
+
gap: 12px;
|
|
277
|
+
margin-bottom: 24px;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
@media (max-width: 600px) {
|
|
281
|
+
.user-desc { grid-template-columns: 1fr; }
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.desc-card {
|
|
285
|
+
background: var(--bg-card);
|
|
286
|
+
border: 1px solid var(--border);
|
|
287
|
+
border-radius: var(--radius);
|
|
288
|
+
padding: 16px;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.desc-card.actual { border-left: 3px solid var(--danger); }
|
|
292
|
+
.desc-card.expected { border-left: 3px solid var(--success); }
|
|
293
|
+
|
|
294
|
+
.desc-label {
|
|
295
|
+
font-size: 11px;
|
|
296
|
+
text-transform: uppercase;
|
|
297
|
+
letter-spacing: 0.06em;
|
|
298
|
+
font-weight: 700;
|
|
299
|
+
margin-bottom: 8px;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.desc-card.actual .desc-label { color: var(--danger); }
|
|
303
|
+
.desc-card.expected .desc-label { color: var(--success); }
|
|
304
|
+
|
|
305
|
+
.desc-text {
|
|
306
|
+
font-size: 14px;
|
|
307
|
+
line-height: 1.6;
|
|
308
|
+
color: var(--text-secondary);
|
|
309
|
+
white-space: pre-wrap;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* ── Screenshot ──────────────────────────────────────────────── */
|
|
313
|
+
|
|
314
|
+
.screenshot-container {
|
|
315
|
+
margin-bottom: 24px;
|
|
316
|
+
border: 1px solid var(--border);
|
|
317
|
+
border-radius: var(--radius);
|
|
318
|
+
overflow: hidden;
|
|
319
|
+
background: var(--bg-secondary);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.screenshot-label {
|
|
323
|
+
font-size: 11px;
|
|
324
|
+
text-transform: uppercase;
|
|
325
|
+
letter-spacing: 0.06em;
|
|
326
|
+
font-weight: 700;
|
|
327
|
+
color: var(--text-muted);
|
|
328
|
+
padding: 12px 16px;
|
|
329
|
+
border-bottom: 1px solid var(--border);
|
|
330
|
+
display: flex;
|
|
331
|
+
align-items: center;
|
|
332
|
+
gap: 6px;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.screenshot-container img {
|
|
336
|
+
width: 100%;
|
|
337
|
+
display: block;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* ── JSON Display ───────────────────────────────────────────── */
|
|
341
|
+
|
|
342
|
+
.json-block {
|
|
343
|
+
background: var(--bg-primary);
|
|
344
|
+
border: 1px solid var(--border);
|
|
345
|
+
border-radius: var(--radius-sm);
|
|
346
|
+
padding: 14px;
|
|
347
|
+
overflow-x: auto;
|
|
348
|
+
font-family: var(--font-mono);
|
|
349
|
+
font-size: 11.5px;
|
|
350
|
+
line-height: 1.7;
|
|
351
|
+
white-space: pre-wrap;
|
|
352
|
+
word-break: break-word;
|
|
353
|
+
max-height: 500px;
|
|
354
|
+
overflow-y: auto;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.json-key { color: #93c5fd; }
|
|
358
|
+
.json-string { color: #86efac; }
|
|
359
|
+
.json-number { color: #fbbf24; }
|
|
360
|
+
.json-boolean { color: #c084fc; }
|
|
361
|
+
.json-null { color: #f87171; }
|
|
362
|
+
|
|
363
|
+
/* ── Limitations / Summary ──────────────────────────────────── */
|
|
364
|
+
|
|
365
|
+
.limitations-list {
|
|
366
|
+
list-style: none;
|
|
367
|
+
padding: 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.limitations-list li {
|
|
371
|
+
font-size: 12.5px;
|
|
372
|
+
color: var(--text-secondary);
|
|
373
|
+
padding: 6px 0;
|
|
374
|
+
border-bottom: 1px solid rgba(45, 51, 72, 0.5);
|
|
375
|
+
display: flex;
|
|
376
|
+
align-items: flex-start;
|
|
377
|
+
gap: 8px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.limitations-list li:last-child { border-bottom: none; }
|
|
381
|
+
|
|
382
|
+
.limitations-list li::before {
|
|
383
|
+
content: '⚠️';
|
|
384
|
+
font-size: 12px;
|
|
385
|
+
flex-shrink: 0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.summary-grid {
|
|
389
|
+
display: grid;
|
|
390
|
+
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
|
391
|
+
gap: 8px;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.summary-item {
|
|
395
|
+
background: var(--bg-primary);
|
|
396
|
+
border: 1px solid var(--border);
|
|
397
|
+
border-radius: var(--radius-sm);
|
|
398
|
+
padding: 10px 12px;
|
|
399
|
+
text-align: center;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.summary-item-label {
|
|
403
|
+
font-size: 10px;
|
|
404
|
+
text-transform: uppercase;
|
|
405
|
+
letter-spacing: 0.04em;
|
|
406
|
+
color: var(--text-muted);
|
|
407
|
+
margin-bottom: 4px;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.summary-item-value {
|
|
411
|
+
font-size: 18px;
|
|
412
|
+
font-weight: 700;
|
|
413
|
+
color: var(--accent);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* ── Footer ──────────────────────────────────────────────────── */
|
|
417
|
+
|
|
418
|
+
.report-footer {
|
|
419
|
+
text-align: center;
|
|
420
|
+
font-size: 11px;
|
|
421
|
+
color: var(--text-muted);
|
|
422
|
+
margin-top: 40px;
|
|
423
|
+
padding-top: 20px;
|
|
424
|
+
border-top: 1px solid var(--border);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* ── Scrollbar ───────────────────────────────────────────────── */
|
|
428
|
+
|
|
429
|
+
::-webkit-scrollbar { width: 6px; height: 6px; }
|
|
430
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
431
|
+
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
|
432
|
+
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
|
|
433
|
+
</style>
|
|
434
|
+
</head>
|
|
435
|
+
<body>
|
|
436
|
+
<div class="container">
|
|
437
|
+
|
|
438
|
+
<!-- Header -->
|
|
439
|
+
<div class="report-header">
|
|
440
|
+
<div class="report-logo">🐛</div>
|
|
441
|
+
<div class="report-title">Bug Report</div>
|
|
442
|
+
<div class="report-badge">Schema v${escapeHtml(schemaVersion || '2.0.0')}</div>
|
|
443
|
+
<div class="report-badge">Tool v${escapeHtml(toolVersion)}</div>
|
|
444
|
+
</div>
|
|
445
|
+
<div class="report-sub">
|
|
446
|
+
Erstellt am ${escapeHtml(reportTime)}
|
|
447
|
+
</div>
|
|
448
|
+
|
|
449
|
+
<!-- User Description: Ist / Soll -->
|
|
450
|
+
<div class="user-desc">
|
|
451
|
+
<div class="desc-card actual">
|
|
452
|
+
<div class="desc-label">Ist-Zustand (Actual)</div>
|
|
453
|
+
<div class="desc-text">${escapeHtml(actual)}</div>
|
|
454
|
+
</div>
|
|
455
|
+
<div class="desc-card expected">
|
|
456
|
+
<div class="desc-label">Soll-Zustand (Expected)</div>
|
|
457
|
+
<div class="desc-text">${escapeHtml(expected)}</div>
|
|
458
|
+
</div>
|
|
459
|
+
</div>
|
|
460
|
+
|
|
461
|
+
<!-- Screenshot -->
|
|
462
|
+
${screenshotBase64 ? `
|
|
463
|
+
<div class="screenshot-container">
|
|
464
|
+
<div class="screenshot-label">📸 Annotated Screenshot (DOM Capture via layout2vector)</div>
|
|
465
|
+
<img src="${screenshotBase64}" alt="Annotated screenshot of the page at time of bug report">
|
|
466
|
+
</div>
|
|
467
|
+
` : `
|
|
468
|
+
<div class="screenshot-container">
|
|
469
|
+
<div class="screenshot-label">📸 Screenshot not available</div>
|
|
470
|
+
</div>
|
|
471
|
+
`}
|
|
472
|
+
|
|
473
|
+
<!-- Page Metadata -->
|
|
474
|
+
<div class="meta-grid">
|
|
475
|
+
<div class="meta-card">
|
|
476
|
+
<div class="meta-label">URL</div>
|
|
477
|
+
<div class="meta-value mono">${escapeHtml(pageMetadata?.url || 'N/A')}</div>
|
|
478
|
+
</div>
|
|
479
|
+
<div class="meta-card">
|
|
480
|
+
<div class="meta-label">Browser</div>
|
|
481
|
+
<div class="meta-value">${escapeHtml((pageMetadata?.browserName || 'Unknown') + ' ' + (pageMetadata?.browserVersion || ''))}</div>
|
|
482
|
+
</div>
|
|
483
|
+
<div class="meta-card">
|
|
484
|
+
<div class="meta-label">Viewport</div>
|
|
485
|
+
<div class="meta-value">${pageMetadata?.viewportSize ? pageMetadata.viewportSize.width + ' × ' + pageMetadata.viewportSize.height : 'N/A'}</div>
|
|
486
|
+
</div>
|
|
487
|
+
<div class="meta-card">
|
|
488
|
+
<div class="meta-label">Screen Resolution</div>
|
|
489
|
+
<div class="meta-value">${pageMetadata?.screenResolution ? pageMetadata.screenResolution.width + ' × ' + pageMetadata.screenResolution.height : 'N/A'}</div>
|
|
490
|
+
</div>
|
|
491
|
+
<div class="meta-card">
|
|
492
|
+
<div class="meta-label">Scroll Position</div>
|
|
493
|
+
<div class="meta-value">${pageMetadata?.scrollPosition ? 'X: ' + pageMetadata.scrollPosition.x + ' Y: ' + pageMetadata.scrollPosition.y : 'N/A'}</div>
|
|
494
|
+
</div>
|
|
495
|
+
<div class="meta-card">
|
|
496
|
+
<div class="meta-label">Zoom Level</div>
|
|
497
|
+
<div class="meta-value">${pageMetadata?.zoomLevel != null ? pageMetadata.zoomLevel : 'N/A'}</div>
|
|
498
|
+
</div>
|
|
499
|
+
<div class="meta-card">
|
|
500
|
+
<div class="meta-label">User Agent</div>
|
|
501
|
+
<div class="meta-value mono" style="font-size:10px;">${escapeHtml(pageMetadata?.userAgent || 'N/A')}</div>
|
|
502
|
+
</div>
|
|
503
|
+
</div>
|
|
504
|
+
|
|
505
|
+
<!-- Interactions -->
|
|
506
|
+
<div class="section open" id="sectionInteractions">
|
|
507
|
+
<div class="section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
508
|
+
<span class="section-icon">👆</span>
|
|
509
|
+
<span class="section-title">User Interactions</span>
|
|
510
|
+
<span class="section-count">${(interactions || []).length}</span>
|
|
511
|
+
<span class="section-chevron">▶</span>
|
|
512
|
+
</div>
|
|
513
|
+
<div class="section-body">
|
|
514
|
+
<div class="json-block">${syntaxHighlight(interactions || [])}</div>
|
|
515
|
+
</div>
|
|
516
|
+
</div>
|
|
517
|
+
|
|
518
|
+
<!-- Console Logs -->
|
|
519
|
+
<div class="section" id="sectionConsole">
|
|
520
|
+
<div class="section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
521
|
+
<span class="section-icon">📋</span>
|
|
522
|
+
<span class="section-title">Console Logs</span>
|
|
523
|
+
<span class="section-count">${(consoleLogs || []).length}</span>
|
|
524
|
+
<span class="section-chevron">▶</span>
|
|
525
|
+
</div>
|
|
526
|
+
<div class="section-body">
|
|
527
|
+
<div class="json-block">${syntaxHighlight(consoleLogs || [])}</div>
|
|
528
|
+
</div>
|
|
529
|
+
</div>
|
|
530
|
+
|
|
531
|
+
<!-- JS Errors -->
|
|
532
|
+
<div class="section" id="sectionErrors">
|
|
533
|
+
<div class="section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
534
|
+
<span class="section-icon">⚠️</span>
|
|
535
|
+
<span class="section-title">JavaScript Errors</span>
|
|
536
|
+
<span class="section-count">${(jsErrors || []).length}</span>
|
|
537
|
+
<span class="section-chevron">▶</span>
|
|
538
|
+
</div>
|
|
539
|
+
<div class="section-body">
|
|
540
|
+
<div class="json-block">${syntaxHighlight(jsErrors || [])}</div>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
|
|
544
|
+
<!-- Network Requests -->
|
|
545
|
+
<div class="section" id="sectionNetwork">
|
|
546
|
+
<div class="section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
547
|
+
<span class="section-icon">🌐</span>
|
|
548
|
+
<span class="section-title">Network Requests</span>
|
|
549
|
+
<span class="section-count">${(networkRequests || []).length}</span>
|
|
550
|
+
<span class="section-chevron">▶</span>
|
|
551
|
+
</div>
|
|
552
|
+
<div class="section-body">
|
|
553
|
+
<div class="json-block">${syntaxHighlight(networkRequests || [])}</div>
|
|
554
|
+
</div>
|
|
555
|
+
</div>
|
|
556
|
+
|
|
557
|
+
<!-- Sanitization Summary -->
|
|
558
|
+
<div class="section" id="sectionSanitization">
|
|
559
|
+
<div class="section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
560
|
+
<span class="section-icon">🔒</span>
|
|
561
|
+
<span class="section-title">Sanitization Summary</span>
|
|
562
|
+
<span class="section-count">${sanitizationSummary?.totalRedactions || 0} redactions</span>
|
|
563
|
+
<span class="section-chevron">▶</span>
|
|
564
|
+
</div>
|
|
565
|
+
<div class="section-body">
|
|
566
|
+
${sanitizationSummary?.redactionsByType && Object.keys(sanitizationSummary.redactionsByType).length > 0 ? `
|
|
567
|
+
<div class="summary-grid">
|
|
568
|
+
${Object.entries(sanitizationSummary.redactionsByType).map(([type, count]) => `
|
|
569
|
+
<div class="summary-item">
|
|
570
|
+
<div class="summary-item-label">${escapeHtml(type)}</div>
|
|
571
|
+
<div class="summary-item-value">${count}</div>
|
|
572
|
+
</div>
|
|
573
|
+
`).join('')}
|
|
574
|
+
</div>
|
|
575
|
+
` : '<p style="color:var(--text-muted);font-size:13px;">No redactions were necessary.</p>'}
|
|
576
|
+
${sanitizationSummary?.validationIssues && sanitizationSummary.validationIssues.length > 0 ? `
|
|
577
|
+
<div style="margin-top:12px;">
|
|
578
|
+
<p style="color:var(--warning);font-size:12px;font-weight:600;margin-bottom:6px;">Validation Issues:</p>
|
|
579
|
+
<ul class="limitations-list">
|
|
580
|
+
${sanitizationSummary.validationIssues.map(issue => `<li>${escapeHtml(issue)}</li>`).join('')}
|
|
581
|
+
</ul>
|
|
582
|
+
</div>
|
|
583
|
+
` : ''}
|
|
584
|
+
</div>
|
|
585
|
+
</div>
|
|
586
|
+
|
|
587
|
+
<!-- Capture Limitations -->
|
|
588
|
+
<div class="section" id="sectionLimitations">
|
|
589
|
+
<div class="section-header" onclick="this.parentElement.classList.toggle('open')">
|
|
590
|
+
<span class="section-icon">ℹ️</span>
|
|
591
|
+
<span class="section-title">Capture Limitations</span>
|
|
592
|
+
<span class="section-chevron">▶</span>
|
|
593
|
+
</div>
|
|
594
|
+
<div class="section-body">
|
|
595
|
+
<ul class="limitations-list">
|
|
596
|
+
${(captureLimitations || []).map(l => `<li>${escapeHtml(l)}</li>`).join('')}
|
|
597
|
+
</ul>
|
|
598
|
+
</div>
|
|
599
|
+
</div>
|
|
600
|
+
|
|
601
|
+
<!-- Embedded JSON (stable, versioned, for automated extraction) -->
|
|
602
|
+
<script type="application/json" id="bug-report-json">
|
|
603
|
+
${escapeHtml(JSON.stringify(data, null, 2))}
|
|
604
|
+
</script>
|
|
605
|
+
|
|
606
|
+
<div class="report-footer">
|
|
607
|
+
Bug Report Dashboard — Schema v${escapeHtml(schemaVersion || '2.0.0')} — Tool v${escapeHtml(toolVersion)}<br>
|
|
608
|
+
Generated ${escapeHtml(reportTime)}
|
|
609
|
+
</div>
|
|
610
|
+
|
|
611
|
+
</div>
|
|
612
|
+
</body>
|
|
613
|
+
</html>`;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return { build, escapeHtml, syntaxHighlight };
|
|
617
|
+
|
|
618
|
+
})();
|
|
619
|
+
|
|
620
|
+
// Make available in different contexts
|
|
621
|
+
if (typeof globalThis !== 'undefined') {
|
|
622
|
+
globalThis.ReportTemplate = ReportTemplate;
|
|
623
|
+
}
|