Source code for exlab_wizard.ui.components.validation_summary
"""Validation summary block (Frontend Spec §3.6.4, §11.4.1).
Renders the per-run validation snapshot in the detail pane:
* Header line *"⚠ N hard-tier findings"* in ``--color-warning`` (or
the soft-only / override variants).
* First two findings as one-line excerpts (rule + matched-token).
* Optional *"+ N more in Problems"* link when more findings exist.
* Override summary line when an override is active.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from exlab_wizard.logging import get_logger
_log = get_logger(__name__)
[docs]
@dataclass(frozen=True)
class FindingExcerpt:
"""A single finding row used in the summary."""
rule: str
matched_token: str
[docs]
@dataclass(frozen=True)
class ValidationSummary:
"""Inputs to the summary block."""
hard_count: int
soft_count: int
excerpts: tuple[FindingExcerpt, ...]
override_active: bool = False
override_reason_snippet: str | None = None
override_operator: str | None = None
override_set_at: str | None = None
[docs]
def excerpt_line(finding: FindingExcerpt) -> str:
"""Compose one-line text for a finding excerpt (Frontend §3.6.4)."""
return f"{finding.rule} -- {finding.matched_token}"
[docs]
def overflow_line(summary: ValidationSummary) -> str | None:
"""Return the *"+ N more in Problems"* line, or ``None`` if not needed.
Frontend §3.6.4: at most two excerpts are rendered; remaining
findings collapse into a single overflow line.
"""
visible = min(len(summary.excerpts), 2)
total = summary.hard_count + summary.soft_count
overflow = max(0, total - visible)
if overflow == 0:
return None
return f"+ {overflow} more in Problems"
[docs]
def override_line(summary: ValidationSummary) -> str | None:
"""Return the override summary line if an override is active."""
if not summary.override_active:
return None
snippet = summary.override_reason_snippet or "(no reason)"
operator = summary.override_operator or "unknown"
set_at = summary.override_set_at or "unknown"
return f'Override active -- "{snippet}" (set by {operator} on {set_at})'
[docs]
def validation_summary(summary: ValidationSummary) -> Any:
"""Build the summary block."""
header_text, header_color = header_line(summary)
excerpts: list[str] = [excerpt_line(f) for f in summary.excerpts[:2]]
overflow = overflow_line(summary)
override = override_line(summary)
payload: dict[str, Any] = {
"header_text": header_text,
"header_color": header_color,
"excerpts": excerpts,
"overflow": overflow,
"override_line": override,
}
try:
from nicegui import ui
except Exception:
return payload
column = ui.column().classes("w-full").style("gap: 0.25rem;")
with column:
if header_text:
ui.label(f"⚠ {header_text}").style(
f"color: var({header_color}); "
"font-family: var(--font-body); "
"font-weight: 600; "
"font-size: var(--text-sm);"
)
for excerpt in excerpts:
ui.label(f"⚠ {excerpt}").style(
"font-family: var(--font-mono); "
"font-size: var(--text-xs); "
"color: var(--color-body);"
)
if overflow:
ui.label(overflow).style(
"font-family: var(--font-body); "
"font-size: var(--text-xs); "
"color: var(--color-info); "
"cursor: pointer;"
)
if override:
ui.label(override).style(
"font-family: var(--font-body); "
"font-size: var(--text-xs); "
"color: var(--color-info);"
)
return column