feat: add compact unified dashboard

This commit is contained in:
2026-07-27 03:26:32 +08:00
parent 545c1abbe6
commit 69f72c09b5
5 changed files with 518 additions and 44 deletions
+114
View File
@@ -668,5 +668,119 @@ class Sub2APILogsTests(unittest.TestCase):
self.assertIn("logs token not configured", err.getvalue())
class DashboardLayoutTests(unittest.IsolatedAsyncioTestCase):
async def test_dashboard_fits_three_tables_at_80_by_24_and_focuses_each(self) -> None:
from textual.app import App
mod = load_module()
mod.fetch_payload = lambda *args, **kwargs: {
"source_name": "test",
"totals": {"total_accounts": 1, "usable_accounts": 1, "today_cost_usd": 1},
"accounts": [
{
"id": 1,
"name": "account-one",
"routing_group": "fast",
"provider": "openai",
"kind": "pay_as_you_go",
"status": "ok",
}
],
}
mod.fetch_optional_payload = lambda *args, **kwargs: ({}, "")
mod.fetch_logs_payload = lambda *args, **kwargs: {
"data": {
"total": 1,
"items": [
{
"id": 1,
"api_key_name": "key-one",
"account_name": "account-one",
"model": "gpt-5.5-codex",
"duration_ms": 1200,
"created_at": "2026-07-24T12:00:00+08:00",
}
],
}
}
mod.fetch_merged_errors = lambda *args, **kwargs: {
"items": [
{
"_node": "cn",
"id": 1,
"status_code": 500,
"account_name": "account-one",
"requested_model": "gpt-5.5-codex",
"phase": "upstream",
"type": "api_error",
"created_at": "2026-07-24T12:01:00+08:00",
}
],
"sources": {"cn": {"ok": True, "total": 1}},
}
captured = {}
original_run = App.run
App.run = lambda self, *args, **kwargs: captured.setdefault("app", self)
try:
rc = mod.run_textual(
"https://example/accounts",
"",
"https://example/usage",
"token",
"https://example/cn",
"https://example/us",
999,
999,
999,
1,
100,
100,
"24h",
)
finally:
App.run = original_run
self.assertEqual(rc, 0)
app = captured["app"]
async with app.run_test(size=(80, 24)) as pilot:
await pilot.pause()
await pilot.pause()
screen = app.screen
self.assertEqual(type(screen).__name__, "DashboardScreen")
self.assertEqual(screen.query_one("#filter").region.height, 1)
self.assertEqual(screen.query_one("#detail").region.height, 2)
for selector in ("#accounts", "#logs", "#errors"):
table = screen.query_one(selector)
self.assertGreaterEqual(table.region.height, 5)
self.assertLessEqual(table.virtual_size.width, table.region.width)
for key, expected_id in (("l", "logs"), ("e", "errors"), ("a", "accounts")):
await pilot.press(key)
await pilot.pause()
self.assertEqual(screen.focused.id, expected_id)
class PageSelectionTests(unittest.TestCase):
def test_dedicated_page_flags_are_mutually_exclusive(self) -> None:
mod = load_module()
old_token = os.environ.pop("SHUSUB2_LOGS_TOKEN", None)
old_file = os.environ.get("SHUSUB2_LOGS_TOKEN_FILE")
os.environ["SHUSUB2_LOGS_TOKEN_FILE"] = "/nonexistent/shusub2/logs-token"
err = io.StringIO()
try:
with contextlib.redirect_stderr(err):
rc = mod.main(["--accounts", "--logs", "--no-version-check"])
finally:
if old_token is not None:
os.environ["SHUSUB2_LOGS_TOKEN"] = old_token
if old_file is None:
os.environ.pop("SHUSUB2_LOGS_TOKEN_FILE", None)
else:
os.environ["SHUSUB2_LOGS_TOKEN_FILE"] = old_file
self.assertEqual(rc, 2)
self.assertIn("choose only one", err.getvalue())
if __name__ == "__main__":
unittest.main()