import { useEffect, useMemo, useState } from 'react' import { StatusBadge } from '@/components/ui/status-badge' import { EmptyState } from '@/components/ui/empty-state' import { Skeleton } from '@/components/ui/skeleton' import { Server, Cpu, MemoryStick, HardDrive } from 'lucide-react' import { useNodes } from '@/hooks/useProxmox' import { NodeDetail } from '@/components/nodes/NodeDetail' import { formatBytes, formatUptime } from '@/lib/format' import { cn } from '@/lib/utils' interface NodesPageProps { connectionId: string initialNodeName?: string onNavigate?: (view: string) => void } function nodePercent(used: number, total: number): number { return total > 0 ? Math.round((used / total) * 100) : 0 } function MiniStat({ label, icon: Icon, value, }: { label: string icon: React.ComponentType<{ className?: string }> value: string }) { return (
{label} {value}
) } export function NodesPage({ connectionId, initialNodeName }: NodesPageProps) { const { data: nodes, isLoading, error } = useNodes(connectionId) const [selectedNodeName, setSelectedNodeName] = useState(null) // Auto-select the node requested via the sidebar (node-detail view) when it // is present; otherwise default-select the first node. Keep the selection // valid as the node list refreshes by falling back to the first node when // the selection disappears. useEffect(() => { if (nodes && nodes.length > 0) { setSelectedNodeName((current) => { if (initialNodeName && nodes.some((n) => n.node === initialNodeName)) { return initialNodeName } return nodes.some((n) => n.node === current) ? current : nodes[0].node }) } }, [nodes, initialNodeName]) const selectedNode = useMemo(() => { if (!nodes || nodes.length === 0) return undefined return nodes.find((n) => n.node === selectedNodeName) ?? nodes[0] }, [nodes, selectedNodeName]) if (isLoading) { return (
{Array.from({ length: 3 }, (_, i) => ( ))}
) } if (error) { return (

Failed to load nodes

) } if (!nodes || nodes.length === 0) { return (
) } return (
{/* Node list */}

Nodes

{nodes.length} node{nodes.length !== 1 ? 's' : ''} in the cluster

{nodes.map((node) => ( ))}
{/* Selected node detail */}
{selectedNode && ( )}
) }