import React from "react"; import { useSidebar } from "@/components/ui/sidebar"; import {Status, StatusIndicator} from "@/components/ui/shadcn-io/status"; import {Separator} from "@/components/ui/separator.tsx"; import {Button} from "@/components/ui/button.tsx"; import { Progress } from "@/components/ui/progress" import {Cpu, HardDrive, MemoryStick} from "lucide-react"; import {Tunnel} from "@/ui/apps/Tunnel/Tunnel.tsx"; import { getServerStatusById, getServerMetricsById, ServerMetrics } from "@/ui/main-axios.ts"; import { useTabs } from "@/ui/Navigation/Tabs/TabContext.tsx"; interface ServerProps { hostConfig?: any; title?: string; isVisible?: boolean; isTopbarOpen?: boolean; embedded?: boolean; // when rendered inside a pane in TerminalView } export function Server({ hostConfig, title, isVisible = true, isTopbarOpen = true, embedded = false }: ServerProps): React.ReactElement { const { state: sidebarState } = useSidebar(); const { addTab } = useTabs() as any; const [serverStatus, setServerStatus] = React.useState<'online' | 'offline'>('offline'); const [metrics, setMetrics] = React.useState(null); const [currentHostConfig, setCurrentHostConfig] = React.useState(hostConfig); // Listen for host configuration changes React.useEffect(() => { setCurrentHostConfig(hostConfig); }, [hostConfig]); // Always fetch latest host config when component mounts or hostConfig changes React.useEffect(() => { const fetchLatestHostConfig = async () => { if (hostConfig?.id) { try { // Import the getSSHHosts function to fetch updated host data const { getSSHHosts } = await import('@/ui/main-axios.ts'); const hosts = await getSSHHosts(); const updatedHost = hosts.find(h => h.id === hostConfig.id); if (updatedHost) { setCurrentHostConfig(updatedHost); } } catch (error) { console.error('Failed to fetch latest host config:', error); } } }; // Fetch immediately when component mounts or hostConfig changes fetchLatestHostConfig(); // Also listen for SSH hosts changed event to refresh host config const handleHostsChanged = async () => { if (hostConfig?.id) { try { // Import the getSSHHosts function to fetch updated host data const { getSSHHosts } = await import('@/ui/main-axios.ts'); const hosts = await getSSHHosts(); const updatedHost = hosts.find(h => h.id === hostConfig.id); if (updatedHost) { setCurrentHostConfig(updatedHost); } } catch (error) { console.error('Failed to refresh host config:', error); } } }; window.addEventListener('ssh-hosts:changed', handleHostsChanged); return () => window.removeEventListener('ssh-hosts:changed', handleHostsChanged); }, [hostConfig?.id]); React.useEffect(() => { let cancelled = false; let intervalId: number | undefined; const fetchStatus = async () => { try { const res = await getServerStatusById(currentHostConfig?.id); if (!cancelled) { setServerStatus(res?.status === 'online' ? 'online' : 'offline'); } } catch { if (!cancelled) setServerStatus('offline'); } }; const fetchMetrics = async () => { if (!currentHostConfig?.id) return; try { const data = await getServerMetricsById(currentHostConfig.id); if (!cancelled) setMetrics(data); } catch { if (!cancelled) setMetrics(null); } }; if (currentHostConfig?.id) { fetchStatus(); fetchMetrics(); intervalId = window.setInterval(() => { fetchStatus(); fetchMetrics(); }, 10_000); } return () => { cancelled = true; if (intervalId) window.clearInterval(intervalId); }; }, [currentHostConfig?.id]); const topMarginPx = isTopbarOpen ? 74 : 16; const leftMarginPx = sidebarState === 'collapsed' ? 16 : 8; const bottomMarginPx = 8; const wrapperStyle: React.CSSProperties = embedded ? { opacity: isVisible ? 1 : 0, height: '100%', width: '100%' } : { opacity: isVisible ? 1 : 0, marginLeft: leftMarginPx, marginRight: 17, marginTop: topMarginPx, marginBottom: bottomMarginPx, height: `calc(100vh - ${topMarginPx + bottomMarginPx}px)`, }; const containerClass = embedded ? "h-full w-full text-white overflow-hidden bg-transparent" : "bg-[#18181b] text-white rounded-lg border-2 border-[#303032] overflow-hidden"; return (
{/* Top Header */}

{currentHostConfig?.folder} / {title}

{currentHostConfig?.enableFileManager && ( )}
{/* Stats */}
{/* CPU */}

{(() => { const pct = metrics?.cpu?.percent; const cores = metrics?.cpu?.cores; const la = metrics?.cpu?.load; const pctText = (typeof pct === 'number') ? `${pct}%` : 'N/A'; const coresText = (typeof cores === 'number') ? `${cores} CPU(s)` : 'N/A CPU(s)'; const laText = (la && la.length === 3) ? `Avg: ${la[0].toFixed(2)}, ${la[1].toFixed(2)}, ${la[2].toFixed(2)}` : 'Avg: N/A'; return `CPU Usage - ${pctText} of ${coresText} (${laText})`; })()}

{/* Memory */}

{(() => { const pct = metrics?.memory?.percent; const used = metrics?.memory?.usedGiB; const total = metrics?.memory?.totalGiB; const pctText = (typeof pct === 'number') ? `${pct}%` : 'N/A'; const usedText = (typeof used === 'number') ? `${used} GiB` : 'N/A'; const totalText = (typeof total === 'number') ? `${total} GiB` : 'N/A'; return `Memory Usage - ${pctText} (${usedText} of ${totalText})`; })()}

{/* HDD */}

{(() => { const pct = metrics?.disk?.percent; const used = metrics?.disk?.usedHuman; const total = metrics?.disk?.totalHuman; const pctText = (typeof pct === 'number') ? `${pct}%` : 'N/A'; const usedText = used ?? 'N/A'; const totalText = total ?? 'N/A'; return `HD Space - ${pctText} (${usedText} of ${totalText})`; })()}

{/* SSH Tunnels */} {(currentHostConfig?.tunnelConnections && currentHostConfig.tunnelConnections.length > 0) && (
)}

Have ideas for what should come next for server management? Share them on{" "} GitHub !

); }