import { useEffect, useState } from 'react' import { Sidebar } from '../components/Sidebar' import type { User } from '../types' interface AppStatus { repo: string host: string currentCommit: string latestCommit: string updateAvailable: boolean deployed: boolean checkedAt: string } interface HealthStatus { name: string up: boolean ms: number | null } interface DeployEntry { repo: string host: string started: string finished?: string status: 'running' | 'success' | 'failed' output?: string error?: string } export function AdminMonitor({ user }: { user: User }) { const [tab, setTab] = useState<'updates' | 'uptime' | 'deploys'>('updates') const [statuses, setStatuses] = useState([]) const [deploys, setDeploys] = useState([]) const [health, setHealth] = useState([]) const [loading, setLoading] = useState(false) const [deploying, setDeploying] = useState>(new Set()) async function fetchStatus() { setLoading(true) try { const res = await fetch('/deploy/status', { credentials: 'include' }) if (res.ok) setStatuses(await res.json()) } finally { setLoading(false) } } async function fetchHealth() { setLoading(true) try { const res = await fetch('/deploy/health-status', { credentials: 'include' }) if (res.ok) setHealth(await res.json()) } finally { setLoading(false) } } async function fetchDeploys() { setLoading(true) try { const res = await fetch('/deploy/deploys', { credentials: 'include' }) if (res.ok) setDeploys(await res.json()) } finally { setLoading(false) } } async function triggerDeploy(repo: string) { setDeploying(prev => new Set(prev).add(repo)) try { await fetch(`/deploy/deploy/${repo}`, { method: 'POST', credentials: 'include' }) setTimeout(() => { fetchStatus() setDeploying(prev => { const s = new Set(prev); s.delete(repo); return s }) }, 3000) } catch { setDeploying(prev => { const s = new Set(prev); s.delete(repo); return s }) } } useEffect(() => { if (tab === 'updates') fetchStatus() if (tab === 'deploys') fetchDeploys() if (tab === 'uptime') { fetchHealth() const id = setInterval(fetchHealth, 30_000) return () => clearInterval(id) } }, [tab]) const updatesAvailable = statuses.filter(s => s.updateAvailable).length return (
{(['updates', 'uptime', 'deploys'] as const).map(t => ( ))}
{tab === 'updates' && (

App Updates

{statuses.length === 0 && !loading && (

No apps in deploy map yet.

)}
{statuses.map(s => (
{s.repo} {!s.deployed && ( not deployed )}
{s.deployed ? `deployed: ${s.currentCommit}` : s.currentCommit} {s.latestCommit !== 'unknown' && ( latest: {s.latestCommit} )}
{s.updateAvailable ? ( ) : s.deployed ? ( âś“ Up to date ) : null}
))}
)} {tab === 'uptime' && (

Service Health

{health.length === 0 && !loading && (

Checking services…

)}
{health.map(h => (
{h.name}
{h.up ? `${h.ms}ms` : 'unreachable'}
))}
)} {tab === 'deploys' && (

Deploy History

{deploys.length === 0 && !loading && (

No deploys recorded yet.

)} {deploys.map((d, i) => (
{d.repo} {d.status}
{d.host} · {new Date(d.started).toLocaleString()} {d.finished && ` → ${new Date(d.finished).toLocaleString()}`}
{(d.output || d.error) && (
{d.output || d.error}
)}
))}
)}
) }