feat: show update service status in UI

This commit is contained in:
2026-01-15 11:06:54 +01:00
parent 55e452b6a2
commit f513d46d08
22 changed files with 351 additions and 2 deletions

View File

@ -26,6 +26,7 @@ from backend.models import (
UpdateActionResponse,
UpdateCheckResponse,
UpdateLogEntry,
UpdateServiceStatus,
UpdateStatus,
UserStatus,
)
@ -314,6 +315,12 @@ def update_logs(settings: Settings = Depends(get_settings), limit: int = 200) ->
) from exc
@app.get("/update/service-status", response_model=UpdateServiceStatus, dependencies=[Depends(get_current_admin)])
def update_service_status(settings: Settings = Depends(get_settings)) -> UpdateServiceStatus:
data = update.get_service_status(settings)
return UpdateServiceStatus(**data)
@app.get("/", response_class=HTMLResponse)
@app.get("/login", response_class=HTMLResponse)
@app.get("/dashboard", response_class=HTMLResponse)

View File

@ -73,3 +73,11 @@ class UpdateLogEntry(BaseModel):
version: Optional[str] = None
error: Optional[str] = None
device_id: Optional[str] = None
class UpdateServiceStatus(BaseModel):
url: str
reachable: bool
status_code: Optional[int] = None
error: Optional[str] = None
checked_url: str

View File

@ -414,7 +414,10 @@
statusDiv.innerHTML = '<div class="spinner" style="margin: 0 auto;"></div><p class="text-center text-muted mt-1">Lade Update-Status...</p>';
try {
const data = await api('/update/status');
const [data, serviceStatus] = await Promise.all([
api('/update/status'),
api('/update/service-status')
]);
document.querySelector('#metricVersion .value').textContent = data.current_version;
document.getElementById('headerVersion').textContent = `v${data.current_version}`;
@ -436,12 +439,24 @@
enrollSection.classList.remove('hidden');
}
const serviceBadge = serviceStatus.reachable
? '<span class="badge success"><i data-lucide="server"></i> Online</span>'
: '<span class="badge error"><i data-lucide="server-off"></i> Offline</span>';
const serviceHint = serviceStatus.status_code
? `HTTP ${serviceStatus.status_code}`
: (serviceStatus.error || 'keine Antwort');
statusDiv.innerHTML = `
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem;">
<div>
<div class="text-muted" style="font-size: 0.75rem; text-transform: uppercase; margin-bottom: 0.25rem;">Version</div>
<div style="color: var(--color-accent); font-weight: 600;">${data.current_version}</div>
</div>
<div>
<div class="text-muted" style="font-size: 0.75rem; text-transform: uppercase; margin-bottom: 0.25rem;">Update-Service</div>
<div>${serviceBadge}</div>
<div class="text-muted" style="font-size: 0.75rem;">${serviceStatus.url} (${serviceHint})</div>
</div>
<div>
<div class="text-muted" style="font-size: 0.75rem; text-transform: uppercase; margin-bottom: 0.25rem;">Registrierung</div>
<div>${enrolledBadge}</div>

View File

@ -220,3 +220,35 @@ def get_logs(settings: Settings, limit: int = 200) -> List[Dict[str, Any]]:
except json.JSONDecodeError:
continue
return entries
def get_service_status(settings: Settings) -> Dict[str, Any]:
base_url = settings.update_service_url.rstrip("/")
if not base_url:
return {
"url": "",
"reachable": False,
"status_code": None,
"error": "update service url not configured",
"checked_url": "",
}
check_url = base_url
try:
with httpx.Client(timeout=3.0) as client:
response = client.get(check_url)
return {
"url": base_url,
"reachable": True,
"status_code": response.status_code,
"error": None,
"checked_url": check_url,
}
except Exception as exc:
return {
"url": base_url,
"reachable": False,
"status_code": None,
"error": str(exc),
"checked_url": check_url,
}