feat(viewer): replace severity dropdown with per-column header filters

Removes the standalone toolbar severity <select> and instead builds a
second <thead> row in JS with a text input (debounced 300 ms) per
column and a <select> for icon-only columns (severity_icon, status).
All active column filters apply together (AND logic). Adds data-col
attributes to <th> elements so JS can identify columns by name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-05-21 14:26:30 +03:00
parent 2a15bc87f1
commit 8105c7ec08
4 changed files with 136 additions and 99 deletions

View File

@@ -48,7 +48,7 @@ func TestRenderHTMLIncludesKnownSectionsAndFields(t *testing.T) {
}
}
for _, needle := range []string{
`<th class="status-column" aria-label="status"></th>`,
`<th data-col="status" class="status-column" aria-label="status"></th>`,
`<td class="status-column">`,
`<span class="status-badge status-ok" role="img" aria-label="OK" title="OK"></span>`,
} {
@@ -278,7 +278,7 @@ func TestRenderHTMLGroupsPCIeDevicesByClass(t *testing.T) {
if strings.Contains(text, "<th>device_class</th>") {
t.Fatalf("expected device_class column to be hidden from PCIe tables")
}
if !strings.Contains(text, `<th class="status-column" aria-label="status"></th>`) {
if !strings.Contains(text, `<th data-col="status" class="status-column" aria-label="status"></th>`) {
t.Fatalf("expected grouped PCIe tables to render compact status header cells")
}
if !strings.Contains(text, `<span class="status-badge status-warning" role="img" aria-label="Warning" title="Warning"></span>`) {
@@ -320,15 +320,12 @@ func TestRenderHTMLAddsSeverityFilterForEventLogs(t *testing.T) {
text := string(html)
for _, needle := range []string{
"Event Logs",
"All severities",
`<option value="critical">Critical</option>`,
`<option value="info">Info</option>`,
`data-severity="critical"`,
`data-severity="info"`,
`<th class="status-column" aria-label="severity"></th>`,
`<th data-col="severity_icon" class="status-column" aria-label="severity"></th>`,
`<span class="status-badge severity-info" role="img" aria-label="Info" title="Info"></span>`,
`<span class="status-badge severity-critical" role="img" aria-label="Critical" title="Critical"></span>`,
`<th>severity</th>`,
`<th data-col="severity">severity</th>`,
"/static/view.js",
} {
if !strings.Contains(text, needle) {
@@ -400,9 +397,9 @@ func TestRenderHTMLDisplaysHardwareContract210Fields(t *testing.T) {
"Storage",
"Event Logs",
"Platform Config",
"<th>logical_block_size_bytes</th>",
"<th>physical_block_size_bytes</th>",
"<th>metadata_bytes_per_block</th>",
`<th data-col="logical_block_size_bytes">logical_block_size_bytes</th>`,
`<th data-col="physical_block_size_bytes">physical_block_size_bytes</th>`,
`<th data-col="metadata_bytes_per_block">metadata_bytes_per_block</th>`,
"512",
"4096",
"8",