Source code for exlab_wizard.ui.components.test_connection_panel
"""Test-connection result panel (Frontend Spec §7.4.2).
A persistent inline panel below the Settings dialog's [Test connection]
button. Shape:
* **Result icon + headline** -- *"Connected"* (green check) or
*"Connection failed"* (red X).
* **Detail line** -- one-line context (latency on success; reason on
failure).
* **Show details** disclosure -- collapsed by default; expanded shows the
full underlying response in a monospaced block.
The panel persists until the next test or until any field in the same
section is edited; on edit, ``mark_stale()`` flips a flag that the
caller renders as *"(may be stale; re-test to confirm)"*.
"""
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 TestConnectionResult:
"""One result rendered in the panel."""
success: bool
headline: str
detail: str
raw: str
[docs]
def panel_props(result: TestConnectionResult | None, *, stale: bool = False) -> dict[str, Any]:
"""Compute the rendered props for the panel.
Returns a dict suitable for asserting in tests; the NiceGUI factory
consumes the same dict.
"""
if result is None:
return {
"visible": False,
"headline": "",
"detail": "",
"raw": "",
"success": False,
"stale": False,
"color_var": "--color-muted",
}
headline = result.headline
if stale:
headline = f"{headline} (may be stale; re-test to confirm)"
return {
"visible": True,
"headline": headline,
"detail": result.detail,
"raw": result.raw,
"success": result.success,
"stale": stale,
"color_var": "--color-success" if result.success else "--color-danger",
}
[docs]
def test_connection_panel(
result: TestConnectionResult | None = None,
*,
stale: bool = False,
) -> Any:
"""Build the inline result panel.
Returns a NiceGUI element, or the props dict when called outside of
a NiceGUI app context.
"""
props = panel_props(result, stale=stale)
try:
from nicegui import ui
except Exception:
return props
if not props["visible"]:
return ui.column().style("display: none;")
column = (
ui.column()
.classes("w-full")
.style(
"gap: 0.25rem; "
"padding: 0.75rem 1rem; "
"border-radius: var(--radius); "
"border: 1px solid var(--color-border); "
"background: var(--color-surface);"
)
)
with column:
with ui.row().classes("items-center").style("gap: 0.5rem;"):
ui.icon(
"check_circle" if props["success"] else "error",
).style(f"color: var({props['color_var']});")
ui.label(props["headline"]).style(
"font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500;"
)
ui.label(props["detail"]).style(
"font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-muted);"
)
with ui.expansion("Show details", icon="expand_more").classes("w-full"):
ui.code(props["raw"]).classes("w-full")
return column