"use client"; import type { ConnectionInfo, NormalServer, PodInfo, ReverseProxyServer } from "@minikura/api"; import { AlertCircle, Check, CheckCircle2, Copy, FileText, Globe, Pencil, Plus, Server, Trash2, } from "lucide-react"; import { useRouter } from "next/navigation"; import { useCallback, useEffect, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { api } from "@/lib/api-client"; import { getReverseProxyApi } from "@/lib/api-helpers"; function ServerStatusCell({ serverId, type }: { serverId: string; type: "normal" | "proxy" }) { const [pods, setPods] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { const fetchPods = async () => { try { const endpoint = type === "normal" ? api.api.k8s.servers({ serverId }).pods.get : api.api.k8s["reverse-proxy"]({ serverId }).pods.get; const res = await endpoint(); if (res.data) { setPods(res.data as PodInfo[]); } } catch (_error) { } finally { setLoading(false); } }; fetchPods(); }, [serverId, type]); if (loading) { return (
Loading...
); } if (pods.length === 0) { return (
No pods
); } const allRunning = pods.every((pod) => pod.status === "Running"); const readyCount = pods.filter((pod) => pod.ready === "1/1").length; return (
{allRunning ? ( ) : ( )} {readyCount}/{pods.length} Ready
); } function ConnectionInfoCell({ serverId, type }: { serverId: string; type: "normal" | "proxy" }) { const [connectionInfo, setConnectionInfo] = useState(null); const [loading, setLoading] = useState(true); const [copied, setCopied] = useState(false); useEffect(() => { const fetchConnectionInfo = async () => { try { const reverseProxyApi = getReverseProxyApi(); const endpoint = type === "normal" ? api.api.servers({ id: serverId })["connection-info"] : reverseProxyApi({ id: serverId })["connection-info"]; const res = await endpoint.get(); if (res.data) { setConnectionInfo(res.data as ConnectionInfo); } } catch (_error) { } finally { setLoading(false); } }; fetchConnectionInfo(); }, [serverId, type]); const handleCopy = async () => { if (connectionInfo?.connectionString) { await navigator.clipboard.writeText(connectionInfo.connectionString); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; if (loading) { return Loading...; } if (!connectionInfo) { return N/A; } return (
{connectionInfo.type} {connectionInfo.connectionString && (
{connectionInfo.connectionString}

{copied ? "Copied!" : "Copy to clipboard"}

)} {connectionInfo.note && (

{connectionInfo.note}

)}
); } export default function ServersPage() { const router = useRouter(); const [normalServers, setNormalServers] = useState([]); const [reverseProxies, setReverseProxies] = useState([]); const [loading, setLoading] = useState(true); const [deleteTarget, setDeleteTarget] = useState<{ id: string; type: "normal" | "proxy"; } | null>(null); const fetchServers = useCallback(async () => { try { const reverseProxyApi = getReverseProxyApi(); const [normalRes, proxyRes] = await Promise.all([ api.api.servers.get(), reverseProxyApi.get(), ]); if (normalRes.data) { setNormalServers(normalRes.data as unknown as NormalServer[]); } if (proxyRes.data) { setReverseProxies(proxyRes.data as unknown as ReverseProxyServer[]); } } catch (_error) { } finally { setLoading(false); } }, []); useEffect(() => { fetchServers(); }, [fetchServers]); const handleDelete = async () => { if (!deleteTarget) return; try { const reverseProxyApi = getReverseProxyApi(); if (deleteTarget.type === "normal") { await api.api.servers({ id: deleteTarget.id }).delete(); } else { await reverseProxyApi({ id: deleteTarget.id }).delete(); } await fetchServers(); setDeleteTarget(null); } catch (_error) {} }; if (loading) { return (

Server Management

Manage your Minecraft servers

Loading...

); } return (

Server Management

Manage your Minecraft servers and reverse proxies

Minecraft Servers
Manage your normal Minecraft server instances
{normalServers.length === 0 ? (

No servers created yet

) : (
ID Status Storage Software Version Memory (MB) Network Description Actions {normalServers.map((server) => ( {server.id} {server.type} {server.jar_type || "VANILLA"} {server.minecraft_version || "LATEST"} {server.memory || 1024} {server.description || "-"}
))}
)}
Reverse Proxy Servers
Manage your Velocity and BungeeCord proxy servers
{reverseProxies.length === 0 ? (

No reverse proxies created yet

) : (
ID Status Type External Listen Port Memory (MB) Network Description Actions {reverseProxies.map((proxy) => ( {proxy.id} {proxy.type} {proxy.external_address}:{proxy.external_port} {proxy.listen_port} {proxy.memory} {proxy.description || "-"}
))}
)}
setDeleteTarget(null)}> Delete Server Are you sure you want to delete this{" "} {deleteTarget?.type === "normal" ? "server" : "reverse proxy"}? This action cannot be undone.
); }