feat(tui): clarify monitoring continuity and quitting

This commit is contained in:
xavierk
2026-09-10 19:43:32 +05:30
parent 7bbe5cede7
commit d01df6468f
6 changed files with 462 additions and 18 deletions
+72 -16
View File
@@ -23,7 +23,7 @@ from typing import Any, Dict, List, Optional
from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical
from textual.containers import Container, Horizontal, VerticalScroll
from textual.screen import ModalScreen
from textual.widgets import Static
@@ -43,6 +43,9 @@ from .status import (
format_disclosures,
freshness_age_human,
grade_freshness,
deliberate_pause_lines,
is_deliberately_paused,
monitoring_continuity,
open_store_readonly,
query_service_state,
read_config,
@@ -229,6 +232,7 @@ def _query_service_facts(conn: sqlite3.Connection, clock_now: datetime) -> Dict[
"freshness": freshness,
"freshness_age_s": None,
"period": period_info,
"deliberately_paused": is_deliberately_paused(conn, svc),
**svc,
}
@@ -292,14 +296,32 @@ class FenrisTuiApp(App):
CSS = """
#main-grid {
layout: grid;
grid-size: 2 3;
grid-size: 2 4;
grid-columns: 3fr 2fr;
grid-rows: 8 1fr 7;
height: 1fr;
grid-rows: 8 10 7 3;
height: auto;
}
#main-grid.paused {
grid-size: 2 5;
grid-rows: 8 5 10 7 3;
}
#dashboard-scroll { height: 1fr; }
#headline-band { column-span: 2; }
#service-strip { column-span: 2; }
.pane { border: round #555555; padding: 0 1; }
#paused-banner {
column-span: 2;
display: none;
background: $error 20%;
color: $text;
height: 100%;
}
#service-strip { column-span: 2; height: 100%; }
#quit-rail {
column-span: 2;
border: heavy $accent;
content-align: center middle;
height: 100%;
}
.pane { border: round #555555; padding: 0 1; height: 100%; }
#confirm-text { padding: 1 2; }
#disc-text { padding: 1 2; }
"""
@@ -330,11 +352,14 @@ class FenrisTuiApp(App):
self._clock_now = datetime.now(timezone.utc)
def compose(self) -> ComposeResult:
with Vertical(id="main-grid"):
yield Static("", id="headline-band", classes="pane")
yield Static("", id="usage-history", classes="pane")
yield Static("", id="drive-health", classes="pane")
yield Static("", id="service-strip", classes="pane")
with VerticalScroll(id="dashboard-scroll"):
with Container(id="main-grid"):
yield Static("", id="headline-band", classes="pane")
yield Static("", id="paused-banner")
yield Static("", id="usage-history", classes="pane")
yield Static("", id="drive-health", classes="pane")
yield Static("", id="service-strip", classes="pane")
yield Static("q QUIT TUI", id="quit-rail")
def on_mount(self) -> None:
"""Set border titles and render initial state."""
@@ -391,6 +416,7 @@ class FenrisTuiApp(App):
def _render_empty_or_fault(self) -> None:
"""Render empty store greeting or store fault."""
self._hide_paused_banner()
if not self.store_path.exists():
# Empty store — greeting with enable hint (IN-3)
self._render_headline(
@@ -402,7 +428,9 @@ class FenrisTuiApp(App):
self.query_one("#service-strip").update(
"boot: disabled · timer: inactive · last collect: unknown · freshness: empty · "
"[dim]by Bongbetic[/dim]\n"
"p pause · r resume · c collect · d disclosures · q quit"
"[bold]CONTINUITY[/bold] %s\n"
"p pause · r resume · c collect · d disclosures"
% monitoring_continuity({"boot_enabled": False})
)
else:
# Store fault (FL-4)
@@ -414,7 +442,7 @@ class FenrisTuiApp(App):
self.query_one("#drive-health").update("")
self.query_one("#service-strip").update(
"[dim]by Bongbetic[/dim]\n"
"p pause · r resume · c collect · d disclosures · q quit"
"p pause · r resume · c collect · d disclosures"
)
def _render_all_regions(self, conn: sqlite3.Connection) -> None:
@@ -473,17 +501,45 @@ class FenrisTuiApp(App):
self.query_one("#service-strip").update(
"boot: %s · timer: %s · last collect: %s · freshness: %s · "
"[dim]by Bongbetic[/dim]\n"
"[bold]CONTINUITY[/bold] %s\n"
"%s\n"
"p pause · r resume · c collect · d disclosures · q quit"
% (boot, activity, collect, freshness, svc.get("period", ""))
"p pause · r resume · c collect · d disclosures"
% (
boot, activity, collect, freshness,
monitoring_continuity(svc), svc.get("period", ""),
)
)
self._render_paused_banner(svc)
except Exception:
self._hide_paused_banner()
self.query_one("#service-strip").update(
"boot: unknown · timer: unknown · last collect: unknown · freshness: unknown · "
"[dim]by Bongbetic[/dim]\n"
"p pause · r resume · c collect · d disclosures · q quit"
"p pause · r resume · c collect · d disclosures"
)
def _render_paused_banner(self, service: Dict[str, Any]) -> None:
"""Show the high-contrast Deliberate disable block only when sanctioned."""
banner = self.query_one("#paused-banner")
if service.get("deliberately_paused"):
banner.update(
"[bold black on red]%s[/bold black on red]\n%s"
% tuple(deliberate_pause_lines())
)
banner.styles.display = "block"
main_grid = self.query_one("#main-grid")
main_grid.add_class("paused")
main_grid.refresh(layout=True)
else:
self._hide_paused_banner()
def _hide_paused_banner(self) -> None:
"""Ensure an unavailable store cannot retain a stale paused presentation."""
self.query_one("#paused-banner").styles.display = "none"
main_grid = self.query_one("#main-grid")
main_grid.remove_class("paused")
main_grid.refresh(layout=True)
def _format_headline(self, proj: ProjectionResult) -> str:
"""Format the lifespan headline (spec §6.11)."""
if proj.headline_remaining_seconds is None: