feat: redesign Telegram Mini App in keenetichome style

- Sectioned card layout: СЕРВЕРЫ, ДЕЙСТВИЯ, УВЕДОМЛЕНИЯ, СИСТЕМА
- Expandable server cards with metrics detail + reboot/delete
- Mute/unmute alerts (2h, 8h) with API support
- Green/red pulsing status dots, colored badges
- Toast notifications, loading spinner
- Overview API endpoint for Mini App data
- Mute integration with alerter system

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Андрей Бобырев
2026-05-20 12:32:59 +03:00
parent 4846742c60
commit dbe2faf7dc
3 changed files with 551 additions and 184 deletions

View File

@@ -1,3 +1,5 @@
from datetime import datetime, timedelta
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import RedirectResponse, JSONResponse
@@ -49,3 +51,74 @@ async def update_settings(update: SettingsUpdate, request: Request):
settings[key] = val
save_settings(settings)
return {"status": "ok"}
# Mute alerts
mute_until: datetime | None = None
@router.post("/api/mute")
async def mute_alerts(request: Request):
global mute_until
require_auth(request)
body = await request.json()
hours = body.get("hours", 2)
mute_until = datetime.now() + timedelta(hours=hours)
return {"status": "ok", "muted_until": mute_until.isoformat()}
@router.post("/api/unmute")
async def unmute_alerts(request: Request):
global mute_until
require_auth(request)
mute_until = None
return {"status": "ok"}
@router.get("/api/mute/status")
async def mute_status(request: Request):
require_auth(request)
if mute_until and datetime.now() < mute_until:
return {"muted": True, "until": mute_until.isoformat()}
return {"muted": False}
@router.get("/api/overview")
async def overview(request: Request):
"""Full overview for Telegram Mini App."""
require_auth(request)
from server.config import load_servers
from server.services.monitor import get_all_metrics
servers = load_servers()
metrics = get_all_metrics()
srv_list = []
online_count = 0
for s in servers:
m = metrics.get(s["host"], {})
is_online = m.get("online", False)
if is_online:
online_count += 1
srv_list.append({
"id": s.get("id", ""),
"name": s["name"],
"host": s["host"],
"online": is_online,
"cpu": m.get("cpu_percent", 0),
"ram": m.get("ram_percent", 0),
"disk": m.get("disk_percent", 0),
"uptime": m.get("uptime", ""),
"load": m.get("load_average", ""),
})
is_muted = mute_until and datetime.now() < mute_until
return {
"servers": srv_list,
"total": len(servers),
"online": online_count,
"offline": len(servers) - online_count,
"muted": is_muted,
"muted_until": mute_until.isoformat() if is_muted else None,
}