'use client'; import { useState, useEffect } from 'react'; import PageBuilder from './PageBuilder'; import SettingsEditor from './SettingsEditor'; import AnalyticsView from './AnalyticsView'; import BackupManagerModal from './BackupManagerModal'; import * as Icons from './Icons'; interface Props { onLogout: () => void; } type Tab = 'pages' | 'settings' | 'analytics'; export default function AdminDashboard({ onLogout }: Props) { const [activeTab, setActiveTab] = useState('pages'); const [saving, setSaving] = useState(false); // Diagnostics & Backup state const [showStatus, setShowStatus] = useState(false); const [showBackupModal, setShowBackupModal] = useState(false); const [status, setStatus] = useState(null); const [statusLoading, setStatusLoading] = useState(false); // Distinct from `status === null`: the check itself did not run. Without this // an expired session or a 500 rendered exactly like a real outage — every // indicator flipped to its alarming value at once (#341). const [statusError, setStatusError] = useState(false); async function handleLogout() { await fetch('/api/admin/auth', { method: 'DELETE' }); onLogout(); } async function handleReload() { setSaving(true); try { await fetch('/api/admin/reload', { method: 'POST' }); // Refresh status after reload await fetchStatus(); } finally { setSaving(false); } } const fetchStatus = async () => { setStatusLoading(true); try { const res = await fetch('/api/admin/status'); if (res.ok) { const data = await res.json(); setStatus(data); setStatusError(false); } else { setStatus(null); setStatusError(true); } } catch { setStatus(null); setStatusError(true); } finally { setStatusLoading(false); } }; /** * Render one diagnostic as ok / bad / unknown. "Unknown" covers both the * in-flight check and a check that failed to run — neither is evidence that * the thing being checked is broken. */ const indicator = (healthy: boolean, okLabel: string, badLabel: string) => { if (statusLoading) return { className: 'unknown', label: 'Checking…' }; if (statusError || !status) return { className: 'unknown', label: 'Unknown' }; return healthy ? { className: 'ok', label: okLabel } : { className: 'error', label: badLabel }; }; useEffect(() => { fetchStatus(); }, []); const immichIndicator = indicator( status?.immich?.status === 'connected', 'Connected', 'Disconnected', ); const configIndicator = indicator(status?.config?.status === 'valid', 'Valid', 'Degraded'); return (

Immich Folio

{/* Diagnostics Badge */}
{showStatus && ( <>
setShowStatus(false)} />

System Diagnostics

Immich Connection {immichIndicator.label}
Config Integrity {configIndicator.label}
Config Backups {status?.backups?.count ?? 0} Backups
Latest Backup {status?.backups?.lastBackup ? new Date(status.backups.lastBackup).toLocaleDateString() : 'None'}
In-Memory Cache {status?.cache?.size ?? 0} items
)}
Site
{activeTab === 'pages' && } {activeTab === 'settings' && } {activeTab === 'analytics' && }
setShowBackupModal(false)} onRestoreSuccess={() => { fetchStatus(); }} />
); }