diff --git a/tools/trace_replay/render_retrace_summary.mjs b/tools/trace_replay/render_retrace_summary.mjs
index 2869ee8e..3829fea8 100644
--- a/tools/trace_replay/render_retrace_summary.mjs
+++ b/tools/trace_replay/render_retrace_summary.mjs
@@ -433,9 +433,92 @@ async function renderHtml(rows, groupLabels, outputDir, title, groupLabel, htmlN
font-size: 12px;
}
main { width: 1170px; margin: 0 auto; padding: 14px 10px 96px; }
+ .document-title {
+ margin: 0 0 6px;
+ font-size: 28px;
+ line-height: 1.2;
+ }
+ .overview-note {
+ margin: 0 0 16px;
+ color: var(--muted);
+ }
.group { margin-bottom: 28px; }
+ .group-title {
+ display: flex;
+ align-items: start;
+ justify-content: space-between;
+ gap: 16px;
+ }
h1 { margin: 0; font-size: 24px; line-height: 1.2; }
p { margin: 4px 0 12px; color: var(--muted); }
+ .stats {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin: 8px 0 12px;
+ }
+ .stat {
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ padding: 5px 8px;
+ color: var(--text);
+ background: #151922;
+ font-weight: 700;
+ }
+ .stat strong {
+ margin-left: 5px;
+ font-size: 14px;
+ }
+ .stat.rate {
+ border-color: #6f87ff;
+ background: #1d2544;
+ }
+ .stat.pass {
+ border-color: var(--green);
+ background: #15341e;
+ }
+ .stat.fail {
+ border-color: var(--red);
+ background: #3a171a;
+ }
+ .stat.no-result {
+ border-color: var(--orange);
+ background: #3b2a10;
+ }
+ .status-bar {
+ display: flex;
+ width: min(560px, 100%);
+ height: 14px;
+ margin: -4px 0 12px;
+ overflow: hidden;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ background: #151922;
+ }
+ .status-bar .segment {
+ min-width: 0;
+ height: 100%;
+ }
+ .status-bar .pass { background: var(--green); }
+ .status-bar .no-result { background: var(--orange); }
+ .status-bar .fail { background: var(--red); }
+ .status-bar .empty {
+ width: 100%;
+ background: #252b38;
+ }
+ .toggle-cases {
+ flex: 0 0 auto;
+ margin-top: 2px;
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ padding: 6px 10px;
+ color: var(--text);
+ background: #151922;
+ font: inherit;
+ cursor: pointer;
+ }
+ .toggle-cases:hover { background: #1b2130; }
+ .group.collapsed .case-list { display: none; }
.grid {
display: grid;
grid-template-columns: 280px 430px 430px;
@@ -573,6 +656,8 @@ async function renderHtml(rows, groupLabels, outputDir, title, groupLabel, htmlN
+${htmlEscape(title)}
+Each backend cell shows actual / golden / diff. Failed cases are red; absent results are orange; incomplete image sets get an orange notch.
`);
for (const group of groups) {
@@ -583,15 +668,35 @@ async function renderHtml(rows, groupLabels, outputDir, title, groupLabel, htmlN
const noResult = groupCells.filter((row) => effectiveStatus(row) === "NO_RESULT").length;
const passRateDenominator = passed + failed;
const passRate = passRateDenominator === 0 ? "0.0%" : `${(passed * 100 / passRateDenominator).toFixed(1)}%`;
+ const statusTotal = passed + noResult + failed;
+ const passPercent = statusTotal === 0 ? "0" : (passed * 100 / statusTotal).toFixed(3);
+ const noResultPercent = statusTotal === 0 ? "0" : (noResult * 100 / statusTotal).toFixed(3);
+ const failPercent = statusTotal === 0 ? "0" : (failed * 100 / statusTotal).toFixed(3);
await write(`
-
- ${htmlEscape(title)} - ${htmlEscape(displayGroup)}
- Each backend cell shows actual / golden / diff. Failed cases are red; absent results are orange; incomplete image sets get an orange notch.
PASS ${passed}, FAIL ${failed}, NO RESULT ${noResult}, PASS RATE ${passRate}.
-
`);
}
@@ -635,6 +741,15 @@ async function renderHtml(rows, groupLabels, outputDir, title, groupLabel, htmlN
});
});
+ document.querySelectorAll(".toggle-cases").forEach((button) => {
+ button.addEventListener("click", () => {
+ const group = button.closest(".group");
+ const expanded = group.classList.toggle("collapsed") === false;
+ button.setAttribute("aria-expanded", String(expanded));
+ button.textContent = expanded ? "Collapse cases" : "Expand cases";
+ });
+ });
+
lightbox.addEventListener("click", closeLightbox);
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && !lightbox.hidden) closeLightbox();