Skip to content

Commit 6342083

Browse files
committed
Multiple UI/UX improvements
1 parent 2e502c4 commit 6342083

6 files changed

Lines changed: 114 additions & 112 deletions

File tree

docs/content/compliance/_index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ Each test sends a request that violates a specific **MUST** or **MUST NOT** requ
1717
<div class="probe-hint"><strong style="font-size:14px;">Result Cell</strong><br>Click to see the full HTTP request and response</div>
1818
</div>
1919

20+
<div class="probe-filters">
2021
<div id="lang-filter"></div>
2122
<div id="method-filter"></div>
2223
<div id="rfc-level-filter"></div>
24+
</div>
2325
<div id="table-compliance"><p><em>Loading...</em></p></div>
2426

2527
<script src="/Http11Probe/probe/data.js"></script>

docs/content/malformed-input/_index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ A well-implemented server should respond with `400 Bad Request`, `414 URI Too Lo
1717
<div class="probe-hint"><strong style="font-size:14px;">Result Cell</strong><br>Click to see the full HTTP request and response</div>
1818
</div>
1919

20+
<div class="probe-filters">
2021
<div id="lang-filter"></div>
2122
<div id="method-filter"></div>
2223
<div id="rfc-level-filter"></div>
24+
</div>
2325
<div id="table-malformed"><p><em>Loading...</em></p></div>
2426

2527
<script src="/Http11Probe/probe/data.js"></script>

docs/content/normalization/_index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ Some tests are **unscored** (marked with `*`). These cover behaviors like case n
2323
<div class="probe-hint"><strong style="font-size:14px;">Result Cell</strong><br>Click to see the full HTTP request and response</div>
2424
</div>
2525

26+
<div class="probe-filters">
2627
<div id="lang-filter"></div>
2728
<div id="method-filter"></div>
2829
<div id="rfc-level-filter"></div>
30+
</div>
2931
<div id="table-normalization"><p><em>Loading...</em></p></div>
3032

3133
<script src="/Http11Probe/probe/data.js"></script>

docs/content/probe-results/_index.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ HTTP/1.1 compliance comparison across frameworks. Each test sends a specific mal
1616
These results are from CI runs (`ubuntu-latest`). Click a **server name** to view its Dockerfile and source code. Click on the **Compliance**, **Smuggling**, **Malformed Input**, or **Normalization** tabs above for detailed results per category, where you can click any **result cell** to see the full HTTP request and response.
1717
{{< /callout >}}
1818

19-
<div id="lang-filter" style="margin-bottom:6px;"></div>
20-
<div id="cat-filter" style="margin-bottom:6px;"></div>
21-
<div id="rfc-level-filter" style="margin-bottom:16px;"></div>
19+
<div class="probe-filters">
20+
<div id="lang-filter"></div>
21+
<div id="cat-filter"></div>
22+
<div id="rfc-level-filter"></div>
23+
</div>
2224
<div id="probe-summary"><p><em>Loading probe data...</em></p></div>
2325

2426
**Pass** — the server gave the correct response. For most tests this means rejecting a malformed request with `400` or closing the connection. For body handling tests it means successfully reading the request body and returning `2xx`.

docs/content/smuggling/_index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ Some tests are **unscored** (marked with `*`). These send payloads where the RFC
2121
<div class="probe-hint"><strong style="font-size:14px;">Result Cell</strong><br>Click to see the full HTTP request and response</div>
2222
</div>
2323

24+
<div class="probe-filters">
2425
<div id="lang-filter"></div>
2526
<div id="method-filter"></div>
2627
<div id="rfc-level-filter"></div>
28+
</div>
2729
<div id="table-smuggling"><p><em>Loading...</em></p></div>
2830

2931
<script src="/Http11Probe/probe/data.js"></script>

docs/static/probe/render.js

Lines changed: 101 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
11
// Shared probe rendering utilities
2+
(function injectFilterCSS() {
3+
if (document.getElementById('probe-filter-css')) return;
4+
var s = document.createElement('style');
5+
s.id = 'probe-filter-css';
6+
s.textContent = ''
7+
+ '.probe-filters{border:1px solid #d0d7de;border-radius:8px;padding:12px 16px;margin-bottom:16px;background:#f6f8fa}'
8+
+ '.dark .probe-filters{border-color:#30363d;background:#161b22}'
9+
+ '.probe-filters>div:not(:last-child){border-bottom:1px solid #d0d7de;padding-bottom:10px;margin-bottom:10px}'
10+
+ '.dark .probe-filters>div:not(:last-child){border-bottom-color:#30363d}'
11+
+ '.probe-filter-label{display:inline-block;width:80px;font-size:12px;font-weight:700;color:#656d76;white-space:nowrap}'
12+
+ '.dark .probe-filter-label{color:#8b949e}'
13+
+ '.probe-filter-btn{display:inline-block;padding:4px 12px;font-size:12px;font-weight:600;border-radius:4px;cursor:pointer;border:1px solid #d0d7de;margin-right:6px;transition:all .15s;background:#fff;color:#24292f}'
14+
+ '.dark .probe-filter-btn{border-color:#30363d;background:#21262d;color:#c9d1d9}'
15+
+ '.probe-filter-btn.active{background:#0969da;color:#fff;border-color:#0969da}'
16+
+ '.dark .probe-filter-btn.active{background:#1f6feb;border-color:#1f6feb}';
17+
document.head.appendChild(s);
18+
})();
19+
220
window.ProbeRender = (function () {
321
var PASS_BG = '#1a7f37';
422
var WARN_BG = '#9a6700';
@@ -663,7 +681,12 @@ window.ProbeRender = (function () {
663681
});
664682

665683
var unscoredStart = scoredTests.length;
666-
var t = '<div class="probe-scroll"><table class="probe-table" style="border-collapse:collapse;font-size:13px;white-space:nowrap;">';
684+
var isTopLevel = !testIdFilter && !tableLabel;
685+
var t = '';
686+
if (isTopLevel) {
687+
t += '<div class="probe-filter-wrap"><input class="probe-filter-input" type="text" placeholder="Filter by server or test name (comma-separated)\u2026"><span class="probe-filter-count"></span></div>';
688+
}
689+
t += '<div class="probe-scroll"><table class="probe-table" style="border-collapse:collapse;font-size:13px;white-space:nowrap;">';
667690

668691
// Column header row (horizontal labels)
669692
t += '<thead><tr>';
@@ -882,6 +905,60 @@ window.ProbeRender = (function () {
882905
document.addEventListener('keydown', onKey);
883906
});
884907
});
908+
909+
// Wire filter input (top-level only)
910+
if (isTopLevel) {
911+
var filterInput = el.querySelector('.probe-filter-input');
912+
var filterCount = el.querySelector('.probe-filter-count');
913+
if (filterInput) {
914+
function matchesAny(text, keywords) {
915+
for (var k = 0; k < keywords.length; k++) {
916+
if (text.indexOf(keywords[k]) !== -1) return true;
917+
}
918+
return false;
919+
}
920+
filterInput.addEventListener('input', function () {
921+
var raw = filterInput.value.toLowerCase();
922+
var keywords = raw.split(',').map(function (s) { return s.trim(); }).filter(Boolean);
923+
var fRows = el.querySelectorAll('.probe-server-row');
924+
var allCols = el.querySelectorAll('[data-test-label]');
925+
var thCols = el.querySelectorAll('thead [data-test-label]');
926+
if (keywords.length === 0) {
927+
fRows.forEach(function (r) { r.style.display = ''; });
928+
allCols.forEach(function (c) { c.style.display = ''; });
929+
if (filterCount) filterCount.textContent = '';
930+
return;
931+
}
932+
var serverMatches = 0;
933+
fRows.forEach(function (r) {
934+
var name = (r.getAttribute('data-server') || '').toLowerCase();
935+
var lang = (r.getAttribute('data-language') || '').toLowerCase();
936+
if (matchesAny(name, keywords) || matchesAny(lang, keywords)) serverMatches++;
937+
});
938+
var colMatchSet = {};
939+
thCols.forEach(function (th) {
940+
var label = th.getAttribute('data-test-label').toLowerCase();
941+
if (matchesAny(label, keywords)) colMatchSet[th.getAttribute('data-test-label')] = true;
942+
});
943+
var colMatches = Object.keys(colMatchSet).length;
944+
fRows.forEach(function (r) {
945+
var name = (r.getAttribute('data-server') || '').toLowerCase();
946+
var lang = (r.getAttribute('data-language') || '').toLowerCase();
947+
r.style.display = (serverMatches === 0 || matchesAny(name, keywords) || matchesAny(lang, keywords)) ? '' : 'none';
948+
});
949+
allCols.forEach(function (c) {
950+
var label = c.getAttribute('data-test-label');
951+
c.style.display = (colMatches === 0 || colMatchSet[label]) ? '' : 'none';
952+
});
953+
if (filterCount) {
954+
var parts = [];
955+
if (serverMatches > 0) parts.push(serverMatches + ' server' + (serverMatches !== 1 ? 's' : ''));
956+
if (colMatches > 0) parts.push(colMatches + ' test' + (colMatches !== 1 ? 's' : ''));
957+
filterCount.textContent = parts.length > 0 ? parts.join(', ') : 'No matches';
958+
}
959+
});
960+
}
961+
}
885962
}
886963

887964
// ── Collapsible-group wiring helper ────────────────────────────
@@ -1037,42 +1114,21 @@ window.ProbeRender = (function () {
10371114
var langList = Object.keys(langs).sort();
10381115
if (langList.length === 0) return;
10391116

1040-
var isDark = document.documentElement.classList.contains('dark');
1041-
var baseBg = isDark ? '#21262d' : '#f6f8fa';
1042-
var baseFg = isDark ? '#c9d1d9' : '#24292f';
1043-
var baseBorder = isDark ? '#30363d' : '#d0d7de';
1044-
var activeBg = isDark ? '#1f6feb' : '#0969da';
1045-
1046-
var btnStyle = 'display:inline-block;padding:4px 12px;font-size:12px;font-weight:600;'
1047-
+ 'border-radius:20px;cursor:pointer;border:1px solid ' + baseBorder + ';'
1048-
+ 'margin-right:6px;margin-bottom:6px;transition:all 0.15s;';
1049-
1050-
var labelStyle = 'font-size:12px;font-weight:700;color:#656d76;margin-right:10px;white-space:nowrap;';
1051-
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;margin-bottom:4px;">';
1052-
html += '<span style="' + labelStyle + '">Language:</span>';
1053-
html += '<button class="probe-lang-btn" data-lang="" style="' + btnStyle
1054-
+ 'background:' + activeBg + ';color:#fff;border-color:' + activeBg + ';">All</button>';
1117+
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;">';
1118+
html += '<span class="probe-filter-label">Language</span>';
1119+
html += '<button class="probe-filter-btn active" data-lang="">All</button>';
10551120
langList.forEach(function (lang) {
1056-
html += '<button class="probe-lang-btn" data-lang="' + lang + '" style="' + btnStyle
1057-
+ 'background:' + baseBg + ';color:' + baseFg + ';">' + lang + '</button>';
1121+
html += '<button class="probe-filter-btn" data-lang="' + lang + '">' + lang + '</button>';
10581122
});
10591123
html += '</div>';
10601124
el.innerHTML = html;
10611125

1062-
var buttons = el.querySelectorAll('.probe-lang-btn');
1126+
var buttons = el.querySelectorAll('.probe-filter-btn');
10631127
buttons.forEach(function (btn) {
10641128
btn.addEventListener('click', function () {
10651129
var lang = btn.getAttribute('data-lang');
10661130
buttons.forEach(function (b) {
1067-
if (b === btn) {
1068-
b.style.background = activeBg;
1069-
b.style.color = '#fff';
1070-
b.style.borderColor = activeBg;
1071-
} else {
1072-
b.style.background = baseBg;
1073-
b.style.color = baseFg;
1074-
b.style.borderColor = baseBorder;
1075-
}
1131+
b.classList.toggle('active', b === btn);
10761132
});
10771133
if (!lang) {
10781134
onChange({ commit: data.commit, servers: allServers });
@@ -1117,16 +1173,6 @@ window.ProbeRender = (function () {
11171173
var el = document.getElementById(targetId);
11181174
if (!el) return;
11191175

1120-
var isDark = document.documentElement.classList.contains('dark');
1121-
var baseBg = isDark ? '#21262d' : '#f6f8fa';
1122-
var baseFg = isDark ? '#c9d1d9' : '#24292f';
1123-
var baseBorder = isDark ? '#30363d' : '#d0d7de';
1124-
var activeBg = isDark ? '#1f6feb' : '#0969da';
1125-
1126-
var btnStyle = 'display:inline-block;padding:4px 12px;font-size:12px;font-weight:600;'
1127-
+ 'border-radius:20px;cursor:pointer;border:1px solid ' + baseBorder + ';'
1128-
+ 'margin-right:6px;margin-bottom:6px;transition:all 0.15s;';
1129-
11301176
var filters = [
11311177
{ label: 'All', categories: null },
11321178
{ label: 'Compliance', categories: ['Compliance'] },
@@ -1135,32 +1181,20 @@ window.ProbeRender = (function () {
11351181
{ label: 'Normalization', categories: ['Normalization'] }
11361182
];
11371183

1138-
var labelStyle = 'font-size:12px;font-weight:700;color:#656d76;margin-right:10px;white-space:nowrap;';
1139-
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;margin-bottom:4px;">';
1140-
html += '<span style="' + labelStyle + '">Category:</span>';
1184+
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;">';
1185+
html += '<span class="probe-filter-label">Category</span>';
11411186
filters.forEach(function (f, i) {
1142-
var isActive = i === 0;
1143-
html += '<button class="probe-cat-btn" data-idx="' + i + '" style="' + btnStyle
1144-
+ 'background:' + (isActive ? activeBg : baseBg) + ';color:' + (isActive ? '#fff' : baseFg)
1145-
+ ';border-color:' + (isActive ? activeBg : baseBorder) + ';">' + f.label + '</button>';
1187+
html += '<button class="probe-filter-btn' + (i === 0 ? ' active' : '') + '" data-idx="' + i + '">' + f.label + '</button>';
11461188
});
11471189
html += '</div>';
11481190
el.innerHTML = html;
11491191

1150-
var buttons = el.querySelectorAll('.probe-cat-btn');
1192+
var buttons = el.querySelectorAll('.probe-filter-btn');
11511193
buttons.forEach(function (btn) {
11521194
btn.addEventListener('click', function () {
11531195
var idx = parseInt(btn.getAttribute('data-idx'));
11541196
buttons.forEach(function (b) {
1155-
if (b === btn) {
1156-
b.style.background = activeBg;
1157-
b.style.color = '#fff';
1158-
b.style.borderColor = activeBg;
1159-
} else {
1160-
b.style.background = baseBg;
1161-
b.style.color = baseFg;
1162-
b.style.borderColor = baseBorder;
1163-
}
1197+
b.classList.toggle('active', b === btn);
11641198
});
11651199
onChange(filters[idx].categories);
11661200
});
@@ -1208,42 +1242,21 @@ window.ProbeRender = (function () {
12081242
var methods = Object.keys(methodSet).sort();
12091243
if (methods.length === 0) return;
12101244

1211-
var isDark = document.documentElement.classList.contains('dark');
1212-
var baseBg = isDark ? '#21262d' : '#f6f8fa';
1213-
var baseFg = isDark ? '#c9d1d9' : '#24292f';
1214-
var baseBorder = isDark ? '#30363d' : '#d0d7de';
1215-
var activeBg = isDark ? '#1f6feb' : '#0969da';
1216-
1217-
var btnStyle = 'display:inline-block;padding:4px 12px;font-size:12px;font-weight:600;'
1218-
+ 'border-radius:20px;cursor:pointer;border:1px solid ' + baseBorder + ';'
1219-
+ 'margin-right:6px;margin-bottom:6px;transition:all 0.15s;';
1220-
1221-
var labelStyle = 'font-size:12px;font-weight:700;color:#656d76;margin-right:10px;white-space:nowrap;';
1222-
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;margin-bottom:4px;">';
1223-
html += '<span style="' + labelStyle + '">Method:</span>';
1224-
html += '<button class="probe-method-btn" data-method="" style="' + btnStyle
1225-
+ 'background:' + activeBg + ';color:#fff;border-color:' + activeBg + ';">All</button>';
1245+
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;">';
1246+
html += '<span class="probe-filter-label">Method</span>';
1247+
html += '<button class="probe-filter-btn active" data-method="">All</button>';
12261248
methods.forEach(function (m) {
1227-
html += '<button class="probe-method-btn" data-method="' + m + '" style="' + btnStyle
1228-
+ 'background:' + baseBg + ';color:' + baseFg + ';">' + m + '</button>';
1249+
html += '<button class="probe-filter-btn" data-method="' + m + '">' + m + '</button>';
12291250
});
12301251
html += '</div>';
12311252
el.innerHTML = html;
12321253

1233-
var buttons = el.querySelectorAll('.probe-method-btn');
1254+
var buttons = el.querySelectorAll('.probe-filter-btn');
12341255
buttons.forEach(function (btn) {
12351256
btn.addEventListener('click', function () {
12361257
var method = btn.getAttribute('data-method');
12371258
buttons.forEach(function (b) {
1238-
if (b === btn) {
1239-
b.style.background = activeBg;
1240-
b.style.color = '#fff';
1241-
b.style.borderColor = activeBg;
1242-
} else {
1243-
b.style.background = baseBg;
1244-
b.style.color = baseFg;
1245-
b.style.borderColor = baseBorder;
1246-
}
1259+
b.classList.toggle('active', b === btn);
12471260
});
12481261
onChange(method || null);
12491262
});
@@ -1298,42 +1311,21 @@ window.ProbeRender = (function () {
12981311
var visibleLevels = levels.filter(function (l) { return presentLevels[l.key]; });
12991312
if (visibleLevels.length === 0) return;
13001313

1301-
var isDark = document.documentElement.classList.contains('dark');
1302-
var baseBg = isDark ? '#21262d' : '#f6f8fa';
1303-
var baseFg = isDark ? '#c9d1d9' : '#24292f';
1304-
var baseBorder = isDark ? '#30363d' : '#d0d7de';
1305-
var activeBg = isDark ? '#1f6feb' : '#0969da';
1306-
1307-
var btnStyle = 'display:inline-block;padding:4px 12px;font-size:12px;font-weight:600;'
1308-
+ 'border-radius:20px;cursor:pointer;border:1px solid ' + baseBorder + ';'
1309-
+ 'margin-right:6px;margin-bottom:6px;transition:all 0.15s;';
1310-
1311-
var labelStyle = 'font-size:12px;font-weight:700;color:#656d76;margin-right:10px;white-space:nowrap;';
1312-
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;margin-bottom:4px;">';
1313-
html += '<span style="' + labelStyle + '">RFC Level:</span>';
1314-
html += '<button class="probe-rfc-btn" data-level="" style="' + btnStyle
1315-
+ 'background:' + activeBg + ';color:#fff;border-color:' + activeBg + ';">All</button>';
1314+
var html = '<div style="display:flex;align-items:center;flex-wrap:wrap;">';
1315+
html += '<span class="probe-filter-label">RFC Level</span>';
1316+
html += '<button class="probe-filter-btn active" data-level="">All</button>';
13161317
visibleLevels.forEach(function (l) {
1317-
html += '<button class="probe-rfc-btn" data-level="' + l.key + '" style="' + btnStyle
1318-
+ 'background:' + baseBg + ';color:' + baseFg + ';">' + l.label + '</button>';
1318+
html += '<button class="probe-filter-btn" data-level="' + l.key + '">' + l.label + '</button>';
13191319
});
13201320
html += '</div>';
13211321
el.innerHTML = html;
13221322

1323-
var buttons = el.querySelectorAll('.probe-rfc-btn');
1323+
var buttons = el.querySelectorAll('.probe-filter-btn');
13241324
buttons.forEach(function (btn) {
13251325
btn.addEventListener('click', function () {
13261326
var level = btn.getAttribute('data-level');
13271327
buttons.forEach(function (b) {
1328-
if (b === btn) {
1329-
b.style.background = activeBg;
1330-
b.style.color = '#fff';
1331-
b.style.borderColor = activeBg;
1332-
} else {
1333-
b.style.background = baseBg;
1334-
b.style.color = baseFg;
1335-
b.style.borderColor = baseBorder;
1336-
}
1328+
b.classList.toggle('active', b === btn);
13371329
});
13381330
onChange(level || null);
13391331
});

0 commit comments

Comments
 (0)