diff --git a/src/pages/AdminMonitor.tsx b/src/pages/AdminMonitor.tsx index e0b26fb..60f8e9c 100644 --- a/src/pages/AdminMonitor.tsx +++ b/src/pages/AdminMonitor.tsx @@ -2,6 +2,16 @@ 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 DeployEntry { repo: string host: string @@ -13,9 +23,21 @@ interface DeployEntry { } export function AdminMonitor({ user }: { user: User }) { - const [tab, setTab] = useState<'kuma' | 'deploys'>('kuma') + const [tab, setTab] = useState<'updates' | 'kuma' | 'deploys'>('updates') + const [statuses, setStatuses] = useState([]) const [deploys, setDeploys] = 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 fetchDeploys() { setLoading(true) @@ -27,36 +49,127 @@ export function AdminMonitor({ user }: { user: User }) { } } + 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() }, [tab]) + const updatesAvailable = statuses.filter(s => s.updateAvailable).length + return (
- {(['kuma', 'deploys'] as const).map(t => ( + {(['updates', 'kuma', '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 === 'kuma' && ( -