refactor(tui): extract Activity readout and show local time
Move activity data assembly out of tui.py into activity_readout, behind readout(conn, selection, now). Dashboard and fenris-monitor enable now show local time with a timezone label, inspected points keep a secondary UTC line, and the legacy UTC-relabelled day and hour branches are gone. Time formatting (including freshness_age_human) lives in timefmt. Hour offsets now render as +05:30 to match day labels.
This commit is contained in:
@@ -20,6 +20,7 @@ NOW = datetime(2026, 9, 19, 12, tzinfo=timezone.utc)
|
||||
@pytest.fixture
|
||||
def dashboard(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "prefs"))
|
||||
monkeypatch.setenv("TZ", "UTC")
|
||||
|
||||
class Clock(datetime):
|
||||
@classmethod
|
||||
@@ -124,6 +125,19 @@ async def test_mouse_inspection_matches_time_axis(dashboard):
|
||||
assert "09:00 → 09:03 UTC" in text
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_live_readout_shows_local_time_with_secondary_utc_line(dashboard, monkeypatch):
|
||||
monkeypatch.setenv("TZ", "Asia/Kolkata")
|
||||
app = dashboard
|
||||
async with app.run_test(size=(100, 36)) as pilot:
|
||||
await pilot.pause()
|
||||
await pilot.press("left")
|
||||
text = str(app.query_one("#live-readout").render())
|
||||
assert "17:24 → 17:27 Asia/Kolkata +05:30" in text
|
||||
assert text.splitlines()[-1] == "11:54 → 11:57 UTC"
|
||||
assert "local time" in str(app.query_one("#live-legend").render())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_theme_control_persists_choice_and_quit_never_pauses(dashboard, monkeypatch):
|
||||
calls = []
|
||||
@@ -144,14 +158,27 @@ async def test_unallocated_volume_survives_day_with_missing_coverage(dashboard,
|
||||
await pilot.click("#view-history")
|
||||
graph = dashboard.query_one("#usage-history")
|
||||
graph.set_data([{
|
||||
"day": "2026-09-18", "total_bytes": 2_000_000_000,
|
||||
"unallocated_bytes": 2_000_000_000, "is_gap": True,
|
||||
"is_partial": True,
|
||||
"day": "2026-09-18", "local_label": "2026-09-18",
|
||||
"timezone_label": "UTC +00:00", "identity": None,
|
||||
"total_bytes": None, "total_written": None, "total_read": None,
|
||||
"shared_bytes_written": 2_000_000_000, "shared_bytes_read": 0,
|
||||
"unallocated_bytes_written": 2_000_000_000,
|
||||
"unallocated_bytes_read": 0, "activity_state": "incomplete",
|
||||
"is_gap": True, "is_partial": True,
|
||||
}])
|
||||
readout = str(dashboard.query_one("#bar-readout").render())
|
||||
assert "W 2.000 GB unallocated" in readout
|
||||
assert "R unavailable" in readout and "gap" in readout
|
||||
assert "unallocated W 2.000 GB" in readout
|
||||
assert "W unavailable · R unavailable" in readout
|
||||
if size[0] >= 80:
|
||||
graph.set_data([{
|
||||
"day": "2026-09-18", "local_label": "2026-09-18",
|
||||
"timezone_label": "UTC +00:00", "identity": None,
|
||||
"total_bytes": 2_000_000_000, "total_written": 2_000_000_000,
|
||||
"total_read": None, "shared_bytes_written": 2_000_000_000,
|
||||
"shared_bytes_read": 0, "unallocated_bytes_written": 0,
|
||||
"unallocated_bytes_read": 0, "activity_state": "incomplete",
|
||||
"is_gap": False, "is_partial": True,
|
||||
}])
|
||||
plot = str(dashboard.query_one("#bar-render").render())
|
||||
assert any(0x2801 <= ord(c) <= 0x28ff for c in plot)
|
||||
graph.measure = "read"
|
||||
@@ -167,7 +194,9 @@ async def test_small_terminal_hour_readout_does_not_invent_zero(dashboard, state
|
||||
await pilot.click("#view-day")
|
||||
graph = dashboard.query_one("#usage-history")
|
||||
graph.set_hour_data([{
|
||||
"hour": "2026-09-18T12:00:00+00:00", "local_label": "12",
|
||||
"hour": "2026-09-18T12:00:00+00:00", "local_label": "12:00",
|
||||
"timezone_label": "UTC +00:00",
|
||||
"utc_label": "2026-09-18 12:00 UTC",
|
||||
"is_gap": state == "gap", "is_future": state == "future",
|
||||
}])
|
||||
graph._hourly_selected = 0
|
||||
|
||||
Reference in New Issue
Block a user