Initial commit: Metro Warden TUI network operations center

This commit is contained in:
2026-03-22 21:33:40 -04:00
commit 98a17d9b7e
45 changed files with 4215 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
"""Metro Warden custom widgets."""
from .header import MetroHeader
__all__ = ["MetroHeader"]
+122
View File
@@ -0,0 +1,122 @@
"""
Metro Warden header widget — industrial metro-map style banner.
Displays the application name, a live clock, and a pulsing status indicator
that reflects overall system health sourced from the state store.
"""
from __future__ import annotations
import asyncio
from datetime import datetime, timezone
from typing import Optional
from textual.app import ComposeResult
from textual.reactive import reactive
from textual.widget import Widget
from textual.widgets import Label, Static
class PulseIndicator(Static):
"""A small pulsing dot that animates to show the system is alive."""
DEFAULT_CSS = """
PulseIndicator {
width: 3;
height: 1;
color: $success;
}
PulseIndicator.pulse-off {
color: $panel;
}
"""
_frames = ["", ""]
_frame_idx: reactive[int] = reactive(0)
def on_mount(self) -> None:
self.set_interval(1.0, self._tick)
def _tick(self) -> None:
self._frame_idx = (self._frame_idx + 1) % len(self._frames)
self.update(self._frames[self._frame_idx])
if self._frame_idx == 0:
self.add_class("pulse-off")
else:
self.remove_class("pulse-off")
def render(self):
return self._frames[self._frame_idx]
class MetroHeader(Widget):
"""
Industrial metro-map style header bar.
Shows:
- Application name and tagline (left)
- Live UTC clock (centre)
- Pulse indicator + status label (right)
"""
DEFAULT_CSS = """
MetroHeader {
height: 3;
background: $surface;
border-bottom: heavy $primary;
layout: horizontal;
align: left middle;
padding: 0 1;
}
MetroHeader .header-brand {
width: 1fr;
color: $primary;
text-style: bold;
}
MetroHeader .header-clock {
width: auto;
color: $text-muted;
text-align: center;
min-width: 24;
}
MetroHeader .header-status {
width: 1fr;
text-align: right;
color: $success;
}
MetroHeader .header-sep {
color: $primary;
width: 1;
}
"""
_clock: reactive[str] = reactive("--:--:-- UTC")
_status: reactive[str] = reactive("NOMINAL")
def compose(self) -> ComposeResult:
yield Static("METRO WARDEN // NOC", classes="header-brand")
yield Static(self._clock, id="header-clock", classes="header-clock")
yield Static("" + self._status, id="header-status", classes="header-status")
def on_mount(self) -> None:
self.set_interval(1.0, self._update_clock)
def _update_clock(self) -> None:
now = datetime.now(timezone.utc)
self._clock = now.strftime("%Y-%m-%d %H:%M:%S UTC")
clock_widget = self.query_one("#header-clock", Static)
clock_widget.update(self._clock)
def set_status(self, status: str, healthy: bool = True) -> None:
"""Update the status label text and colour."""
self._status = status
status_widget = self.query_one("#header-status", Static)
status_widget.update(("" if healthy else "") + status)
if healthy:
status_widget.remove_class("status-warn")
else:
status_widget.add_class("status-warn")