mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
fix(admin): surface query errors instead of an infinite spinner
P19. `useSystemStatus()` and `useAdminSettings()` already throw on non-OK responses so React Query sets `isError`, but neither caller read it — the system-status panel just kept spinning forever and the settings sections silently rendered defaults as if they were live. Now system-status renders a destructive inline alert when isError, and the admin page top renders a one-line "Failed to load admin settings" banner when the shared settings query fails so the admin notices the toggles below aren't reflecting reality. Both messages have new i18n keys (`admin.systemStatusLoadError`, `admin.adminSettingsLoadError`) in en.json (canonical) + de.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
86a4b52053
commit
26543378b5
4 files changed
+30
-1
No files matched your search
@@ -1259,6 +1259,8 @@
|
||||
"activeTokens": "Aktive API-Tokens",
|
||||
"activeSessions": "Aktive Sessions",
|
||||
"loadingStatus": "Lade Status...",
|
||||
"systemStatusLoadError": "System-Status konnte nicht geladen werden. Bitte die Seite neu laden.",
|
||||
"adminSettingsLoadError": "Admin-Einstellungen konnten nicht geladen werden. Schalter unten zeigen evtl. nicht den Live-Zustand — Seite neu laden.",
|
||||
"workerStatus": "Job-Worker",
|
||||
"workerRunning": "Aktiv",
|
||||
"workerStopped": "Gestoppt",
|
||||
|
||||
@@ -1259,6 +1259,8 @@
|
||||
"activeTokens": "Active API Tokens",
|
||||
"activeSessions": "Active Sessions",
|
||||
"loadingStatus": "Loading status...",
|
||||
"systemStatusLoadError": "Failed to load system status. Try refreshing the page.",
|
||||
"adminSettingsLoadError": "Failed to load admin settings. Toggles below may not reflect the live state — refresh the page.",
|
||||
"workerStatus": "Job Worker",
|
||||
"workerRunning": "Running",
|
||||
"workerStopped": "Stopped",
|
||||
|
||||
@@ -16,10 +16,16 @@ import { SystemStatusSection } from "@/components/admin/system-status-section";
|
||||
import { UmamiSection } from "@/components/admin/umami-section";
|
||||
import { UserManagementSection } from "@/components/admin/user-management-section";
|
||||
import { WebPushVapidSection } from "@/components/admin/web-push-vapid-section";
|
||||
import { useAdminSettings } from "@/components/admin/_shared";
|
||||
|
||||
export default function AdminPage() {
|
||||
const { user } = useAuth();
|
||||
const { t } = useTranslations();
|
||||
// P19: surface admin-settings fetch failures once at the top of the
|
||||
// page. Many child sections share `useAdminSettings()` and render
|
||||
// defaults silently on error — the banner makes the failure visible
|
||||
// so the admin knows the toggles below aren't reflecting real state.
|
||||
const { isError: settingsError } = useAdminSettings();
|
||||
|
||||
if (!user || user.role !== "ADMIN") return null;
|
||||
|
||||
@@ -32,6 +38,15 @@ export default function AdminPage() {
|
||||
<p className="text-muted-foreground text-sm">{t("admin.subtitle")}</p>
|
||||
</div>
|
||||
|
||||
{settingsError && (
|
||||
<div
|
||||
role="alert"
|
||||
className="text-destructive bg-destructive/10 border-destructive/30 rounded-md border px-3 py-2 text-sm"
|
||||
>
|
||||
{t("admin.adminSettingsLoadError")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<StatusCardGrid />
|
||||
|
||||
<div className="space-y-6">
|
||||
|
||||
@@ -22,7 +22,7 @@ import { StatusItem, useSystemStatus } from "./_shared";
|
||||
export function SystemStatusSection({ id }: { id: string }) {
|
||||
const { t } = useTranslations();
|
||||
const fmt = useFormatters();
|
||||
const { data: status } = useSystemStatus();
|
||||
const { data: status, isError } = useSystemStatus();
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -142,6 +142,16 @@ export function SystemStatusSection({ id }: { id: string }) {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : isError ? (
|
||||
// P19: surface load failures inline instead of leaving the
|
||||
// section spinning forever. The hook throws on non-OK
|
||||
// responses, so isError is true on 500s, network errors, etc.
|
||||
<div
|
||||
role="alert"
|
||||
className="text-destructive bg-destructive/10 border-destructive/30 mt-4 rounded-md border px-3 py-2 text-sm"
|
||||
>
|
||||
{t("admin.systemStatusLoadError")}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-4 flex items-center gap-2">
|
||||
<Loader2 className="text-muted-foreground h-4 w-4 animate-spin" />
|
||||
|
||||
Reference in new issue
Block a user