fix(dashboard): findings-view polish — selection-safe poll, unique row ids, active-tab highlight, header/nav realign, collapse pod replicas#132
Merged
Conversation
…w ids, active-tab highlight, header/nav realign, collapse pod replicas Five Findings-view fixes: 1. Selection-safe live poll. dashboard.js now skips the /fragment innerHTML swap while the operator has an active, non-collapsed text selection anchored inside #live (window.getSelection), deferring to the next tick so a poll never rips away the model judgement mid-drag. Scroll-restore is kept; zero-dependency, same-origin. 2. Rows open the wrong row (root cause). finding_id() slugified non-alphanumerics to '-', so distinct entry keys (e.g. secret/app/db and secret-app-db) mapped to the SAME id — duplicate data-finding / id / aria-controls="detail-<id>", so expanded.has(id) and getElementById matched multiple rows and the .row.open + .row-detail reveal targeted the wrong node. Fixed by appending a short, stable FNV-1a hash of the full entry key, so every row + its detail row are unique. 3. Active tab highlight. .tab-active gains a raised surface fill + a stronger (3px) accent rail, keeping the bold weight — meaning not by colour alone, tokens only. 4. Header/nav realign to the table's `+`. Reverses the shared-gutter decision: the brand text and the tab row now left-align with the table's first-column `+` expander glyph via a new --brand-indent token (page gutter + .cell-expand pad + .expander pad), applied to .strip and .tabs. 5. Collapse pod replicas into one workload row. New collapse_pod_replicas step in map_findings derives a workload-group key from a workload/<ns>/Pod/<name> entry by stripping the replica suffix — StatefulSet name-<ordinal>, Deployment name-<rs-hash>-<pod-hash>, DaemonSet/ReplicaSet name-<pod-hash>. Conservative: hash segments must mix a letter and a digit (a dictionary-word tail like debug-shell is left un-merged), and only groups with 2+ pods collapse — so unrelated and standalone pods are never merged. The representative row carries the worst/most-urgent posture (urgency_rank) and a ×N replica count. Tests: findings view_model tests (id collision-free + stable; StatefulSet/Deployment collapse; unrelated + standalone + single-replica never merge; workload_group_key units) and render-level tests (unique detail ids, ×N workload row). dashboard_guards extended for the selection-deferring poll, the raised active tab, and the brand-indent alignment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VtjoJttCvBY4dzCoE4f9vP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five Findings-view fixes (scope: Findings view only —
finding_row.rs,nav.rs,findings.rsmap/collapse/id,dashboard.css,dashboard.js, the preview + tests; behavior/evidence rendering andobserve/graph/reasonuntouched).1. Copy-paste / scroll-jump on the live poll (bug)
dashboard.jsdidlive.innerHTML = htmlevery 5s, destroying any in-progress text selection. The poll now checkswindow.getSelection()and defers the swap while a non-collapsed selection is anchored inside#live, swapping on the next tick once it clears. Scroll-restore preserved; zero-dependency, same-origin.2. Rows open the wrong row (bug) — root cause
finding_id()slugified every non-alphanumeric to-, so distinct entry keys (e.g.secret/app/dbandsecret-app-db, orendpoint/aandendpoint-a) collapsed to the same id — duplicatedata-finding/id/aria-controls="detail-<id>".expanded.has(id)andgetElementById/.row.open + .row-detailthen matched multiple rows, opening the wrong detail. Fixed by appending a short, stable FNV-1a hash of the full entry key (deterministic across renders so the JS open-state keying survives a poll), making every row + detail id unique. Test: two distinct entries that previously collided now get distinct ids.3. Highlight the active tab
.tab-activegains a raised--surface-raisedfill + a stronger 3px accent rail, keeping bold weight + the accent — clearly highlighted, meaning not by colour alone, tokens only (no raw hex).4. Realign header + nav to the table's
+(reverses the gutter decision)New shared
--brand-indenttoken =--page-gutter + --space-2 (.cell-expand pad) + --space-1 (.expander pad), reproducing the x of the first-column+glyph. Applied to.stripand.tabsleft padding so the brand 'p', the active tab's first letter, and the+form one vertical line. Verified in the dev preview.5. Collapse pod replicas into one workload row (feature)
New
collapse_pod_replicasstep inmap_findings(mirrorscollapse_fanout). Derives a workload-group key from aworkload/<ns>/Pod/<name>entry by stripping the replica suffix:name-<ordinal>(trailing-<digits>)name-<rs-hash>-<pod-hash>(two trailing hash segments)name-<pod-hash>(one trailing 5-char hash)Collapse heuristic (conservative): a hash segment must mix at least one letter and one digit, so a dictionary-word tail like
debug-shellis treated as part of the name and left un-merged; and only groups with 2+ pods collapse. So unrelated pods and standalone pods are never merged. The representative row carries the worst/most-urgent posture (urgency_rank) and a×Nreplica count, relabeled to the workload (analytics/murmurify-aggregator). Replicas run the same image, so a merged posture is sound. Tests: 3 StatefulSet replicas → one×3breach row; Deployment replicas collapse; unrelated + standalone + single-replica never merge.Checks (from
engine/)cargo fmt— cleancargo build— okcargo build --example dashboard_preview— okcargo clippy --all-targets— 0 warningscargo test— 355 lib + 9 dashboard_guards + 1 file-size + 1 bin, all green?scenario=breachshows the singleanalytics/murmurify-aggregator ×3row, no duplicatedata-findingids, brand/tab/+aligned, raised active tab.Closes JEF-... (findings-view polish)
🤖 Generated with Claude Code