"use client"; import type { CustomResourceSummary, DeploymentInfo, K8sConfigMapSummary, K8sServiceSummary, K8sStatus, PodInfo, StatefulSetInfo, } from "@minikura/api"; import { AlertCircle, CheckCircle2, XCircle } from "lucide-react"; import { useEffect, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { api } from "@/lib/api-client"; export default function K8sResourcesPage() { const [status, setStatus] = useState(null); const [pods, setPods] = useState([]); const [deployments, setDeployments] = useState([]); const [statefulSets, setStatefulSets] = useState([]); const [services, setServices] = useState([]); const [configMaps, setConfigMaps] = useState([]); const [minecraftServers, setMinecraftServers] = useState([]); const [reverseProxyServers, setReverseProxyServers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetchData = async () => { try { setLoading(true); setError(null); const [ statusRes, podsRes, deploymentsRes, statefulSetsRes, servicesRes, configMapsRes, minecraftServersRes, reverseProxyServersRes, ] = await Promise.allSettled([ api.api.k8s.status.get(), api.api.k8s.pods.get(), api.api.k8s.deployments.get(), api.api.k8s.statefulsets.get(), api.api.k8s.services.get(), api.api.k8s.configmaps.get(), api.api.k8s["minecraft-servers"].get(), api.api.k8s["reverse-proxy-servers"].get(), ]); if (statusRes.status === "fulfilled" && statusRes.value.data) { setStatus(statusRes.value.data as K8sStatus); } if (podsRes.status === "fulfilled" && podsRes.value.data) { setPods(podsRes.value.data as PodInfo[]); } if (deploymentsRes.status === "fulfilled" && deploymentsRes.value.data) { setDeployments(deploymentsRes.value.data as DeploymentInfo[]); } if (statefulSetsRes.status === "fulfilled" && statefulSetsRes.value.data) { setStatefulSets(statefulSetsRes.value.data as StatefulSetInfo[]); } if (servicesRes.status === "fulfilled" && servicesRes.value.data) { setServices(servicesRes.value.data as K8sServiceSummary[]); } if (configMapsRes.status === "fulfilled" && configMapsRes.value.data) { setConfigMaps(configMapsRes.value.data as K8sConfigMapSummary[]); } if (minecraftServersRes.status === "fulfilled" && minecraftServersRes.value.data) { setMinecraftServers(minecraftServersRes.value.data as CustomResourceSummary[]); } if (reverseProxyServersRes.status === "fulfilled" && reverseProxyServersRes.value.data) { setReverseProxyServers(reverseProxyServersRes.value.data as CustomResourceSummary[]); } } catch (err: unknown) { const errorMessage = err instanceof Error ? err.message : "Failed to fetch Kubernetes resources"; setError(errorMessage); } finally { setLoading(false); } }; // biome-ignore lint/correctness/useExhaustiveDependencies: fetchData intentionally omitted to avoid infinite loop useEffect(() => { fetchData(); const interval = setInterval(fetchData, 30000); return () => clearInterval(interval); }, []); const getStatusBadge = (phase: string) => { const variants: Record< string, { icon: React.ComponentType<{ className?: string }>; variant: "default" | "destructive" | "secondary"; } > = { Running: { icon: CheckCircle2, variant: "default" }, Succeeded: { icon: CheckCircle2, variant: "default" }, Failed: { icon: XCircle, variant: "destructive" }, Pending: { icon: AlertCircle, variant: "secondary" }, Unknown: { icon: AlertCircle, variant: "secondary" }, }; const status = variants[phase] || variants.Unknown; const Icon = status.icon; return ( {phase} ); }; if (loading && !status) { return (

Kubernetes Resources

View and monitor your Kubernetes resources

); } if (error) { return (

Kubernetes Resources

View and monitor your Kubernetes resources

Error

{error}

); } if (!status?.initialized) { return (

Kubernetes Resources

View and monitor your Kubernetes resources

Kubernetes Not Connected The Kubernetes client is not initialized. Please ensure the operator is running with proper Kubernetes configuration.

Set{" "} KUBERNETES_SKIP_TLS_VERIFY=true{" "} if using self-signed certificates.

); } return (

Kubernetes Resources

View and monitor your Kubernetes resources

Connected to Kubernetes
Pods ({pods.length}) Deployments ({deployments.length}) StatefulSets ({statefulSets.length}) Services ({services.length}) ConfigMaps ({configMaps.length}) Minecraft Servers ({minecraftServers.length}) Reverse Proxies ({reverseProxyServers.length}) Pods Running pods in the minikura namespace {pods.length === 0 ? (

No pods found

) : (
Name Status Ready Restarts Node Age {pods.map((pod) => ( {pod.name} {getStatusBadge(pod.status)} {pod.ready} {pod.restarts} {pod.nodeName || "-"} {pod.age} ))}
)}
Deployments Deployments in the minikura namespace {deployments.length === 0 ? (

No deployments found

) : (
Name Ready Up-to-date Available Age {deployments.map((deployment) => ( {deployment.name} {deployment.ready} {deployment.upToDate ?? deployment.updated} {deployment.available ?? 0} {deployment.age} ))}
)}
StatefulSets StatefulSets in the minikura namespace {statefulSets.length === 0 ? (

No statefulsets found

) : (
Name Ready Desired Current Age {statefulSets.map((statefulSet) => ( {statefulSet.name} {statefulSet.ready} {statefulSet.desired} {statefulSet.current} {statefulSet.age} ))}
)}
Services Services in the minikura namespace {services.length === 0 ? (

No services found

) : (
Name Type Cluster IP External IP Ports Age {services.map((service) => ( {service.name} {service.type} {service.clusterIP} {service.externalIP} {service.ports} {service.age} ))}
)}
ConfigMaps ConfigMaps in the minikura namespace {configMaps.length === 0 ? (

No configmaps found

) : (
Name Data Keys Age {configMaps.map((cm) => ( {cm.name} {cm.data} {cm.age} ))}
)}
Minecraft Servers Custom Minecraft server resources {minecraftServers.length === 0 ? (

No Minecraft servers found

) : (
Name Status Age {minecraftServers.map((server) => ( {server.name} {server.status?.phase ? ( getStatusBadge(server.status.phase) ) : ( Unknown )} {server.age} ))}
)}
Reverse Proxy Servers Custom reverse proxy server resources {reverseProxyServers.length === 0 ? (

No reverse proxy servers found

) : (
Name Status Age {reverseProxyServers.map((server) => ( {server.name} {server.status?.phase ? ( getStatusBadge(server.status.phase) ) : ( Unknown )} {server.age} ))}
)}
); }