import React, { useState, useEffect, useCallback } from 'react'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/index'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/index'; import { Button } from '@/components/ui/index'; import { Input } from '@/components/ui/index'; import { RefreshCw, Power, RotateCcw } from 'lucide-react'; import { listProxmoxClusters, getNodeStatus, listAptUpdates, listAptRepositories, getSyslog, listClusterTasks, } from '@/lib/proxmoxClient'; import type { NodeStatus, AptPackage, AptRepository, SyslogEntry, ClusterTask, } from '@/lib/proxmoxClient'; import type { ClusterInfo } from '@/lib/domain'; export function ProxmoxAdminPage() { const [clusters, setClusters] = useState([]); const [clusterId, setClusterId] = useState(''); const [nodeId, setNodeId] = useState('localhost'); const [nodeInputValue, setNodeInputValue] = useState('localhost'); const [nodeStatus, setNodeStatus] = useState(null); const [aptUpdates, setAptUpdates] = useState([]); const [aptRepos, setAptRepos] = useState([]); const [syslog, setSyslog] = useState([]); const [tasks, setTasks] = useState([]); const [activeTab, setActiveTab] = useState('status'); const [tabError, setTabError] = useState(null); useEffect(() => { listProxmoxClusters() .then((cls) => { setClusters(cls); if (cls.length > 0) setClusterId(cls[0].id); }) .catch((err: unknown) => console.error('Failed to load clusters:', err)); }, []); const loadTabData = useCallback( async (tab: string, cId: string, nId: string) => { if (!cId) return; setTabError(null); try { switch (tab) { case 'status': setNodeStatus(await getNodeStatus(cId, nId)); break; case 'updates': setAptUpdates(await listAptUpdates(cId, nId)); break; case 'repositories': setAptRepos(await listAptRepositories(cId, nId)); break; case 'syslog': setSyslog(await getSyslog(cId, nId)); break; case 'tasks': setTasks(await listClusterTasks(cId)); break; } } catch (e) { setTabError(String(e)); } }, [] ); useEffect(() => { void loadTabData(activeTab, clusterId, nodeId); }, [activeTab, clusterId, nodeId, loadTabData]); const applyNodeId = () => { setNodeId(nodeInputValue.trim() || 'localhost'); }; const formatBytes = (bytes: number) => bytes >= 1073741824 ? `${(bytes / 1073741824).toFixed(1)} GB` : `${Math.round(bytes / 1048576)} MB`; const formatUptime = (seconds: number) => { const d = Math.floor(seconds / 86400); const h = Math.floor((seconds % 86400) / 3600); const m = Math.floor((seconds % 3600) / 60); return d > 0 ? `${d}d ${h}h ${m}m` : `${h}h ${m}m`; }; return (

Administration

Node management, updates, and system monitoring

{/* Cluster / Node selector bar */}
Cluster:
Node: setNodeInputValue(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') applyNodeId(); }} placeholder="localhost" />
{tabError &&
{tabError}
} Node Status Updates Repositories System Log Tasks {/* ── Node Status ─────────────────────────────────────────────────── */} Node Status
{nodeStatus ? (
CPU:{' '} {(nodeStatus.cpu * 100).toFixed(1)}%
Memory:{' '} {formatBytes(nodeStatus.memory.used)} / {formatBytes(nodeStatus.memory.total)}
Swap:{' '} {formatBytes(nodeStatus.swap.used)} / {formatBytes(nodeStatus.swap.total)}
Disk:{' '} {formatBytes(nodeStatus.disk.used)} / {formatBytes(nodeStatus.disk.total)}
Uptime:{' '} {formatUptime(nodeStatus.uptime)}
Version:{' '} {nodeStatus.version}
{nodeStatus.loadAvg.length > 0 && (
Load Avg:{' '} {nodeStatus.loadAvg.map((v) => v.toFixed(2)).join(' / ')}
)}
) : (
Loading node status...
)}
{/* ── APT Updates ─────────────────────────────────────────────────── */} Available Updates ({aptUpdates.length}) {aptUpdates.length === 0 ? (
No updates available
) : (
{aptUpdates.map((pkg, i) => (
{pkg.package} {pkg.version} {pkg.newVersion ? ` → ${pkg.newVersion}` : ''} {pkg.description && ( {pkg.description} )}
))}
)}
{/* ── APT Repositories ────────────────────────────────────────────── */} APT Repositories {aptRepos.length === 0 ? (
No repositories found
) : (
{aptRepos.map((repo, i) => (
{repo.types.join(' ')} {repo.uris.join(' ')} {repo.suites.join(' ')}{' '} {repo.components.join(' ')}
{repo.enabled ? 'Enabled' : 'Disabled'} {repo.comment && ( {repo.comment} )}
))}
)}
{/* ── Syslog ──────────────────────────────────────────────────────── */} System Log
{syslog.length === 0 ? (
No log entries
) : ( syslog.map((entry) => (
{entry.t} {entry.msg}
)) )}
{/* ── Tasks ───────────────────────────────────────────────────────── */} Recent Tasks {tasks.length === 0 ? (
No tasks found
) : (
{tasks.map((t) => (
{t.upid} {t.type} {t.node} {t.exitstatus ?? 'running'}
))}
)}
); }