"use client"; import { DashboardLayout } from "@/components/dashboard/DashboardLayout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { MoreVertical, Play, Square, Trash2, Container } from "lucide-react"; import { useEffect, useState } from "react"; import { getDocker, removeContainer } from "@/core/docker"; import { getNodes } from "@/core/node"; import { ContainerInfo } from "dockerode"; import { formatBytes } from "@/lib/format"; import { getContainerStats, startContainer, stopContainer, } from "@/core/docker"; import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, } from "@/components/ui/alert-dialog"; type ContainerSummary = { id: string; name: string; image: string; node: string; status: "running" | "stopped"; uptime: string; cpu: number; memory: number; }; async function summarizeContainer( container: ContainerInfo, nodeName: string ): Promise { // 1. Shorten the long container ID const shortId = container.Id; // 2. Clean the name const name = container.Names[0]?.replace(/^\//, "") ?? "unknown"; // 3. Normalize status const status = container.State === "running" ? "running" : "stopped"; // 4. Compute uptime from Status string (if available) const uptime = container.Status?.replace(/^Up\s*/, "") ?? "unknown"; const stats = await getContainerStats(container.Id); return { id: shortId, name, image: container.Image, node: nodeName, status, uptime, cpu: stats?.cpu || 0, memory: stats?.memory || 0, }; } function RemoveDialog({ container }: { container: ContainerSummary }) { return ( Are you absolutely sure? This action cannot be undone. This will permanently remove the container. Cancel removeContainer(container.id)} > Delete ); } export default function ContainersPage() { const [containers, setContainers] = useState([]); useEffect(() => { const fetchNodes = async () => { const nodes = await getNodes(); const dockerNodes = await getDocker(nodes); setContainers( await Promise.all( nodes.flatMap((node, i) => dockerNodes[i].containers.map((c) => summarizeContainer(c, node.name) ) ) ) ); }; fetchNodes(); }, []); return ( {/* Stats */}
{containers.length} containers {containers.filter((c) => c.status === "running").length} running
{/* ================= DESKTOP TABLE ================= */}
{[ "Container", "Image", "Node", "Status", "Uptime", "CPU", "Memory", "Actions", ].map((h) => ( ))} {containers.map((container) => ( ))}
{h}
{container.name}
{container.id.slice(0, 12)}
{container.image} {container.node} {container.status} {container.uptime} {container.cpu.toFixed(1)}% {container.memory.toFixed(1)}%
{container.status === "running" ? ( ) : ( )}
{/* ================= MOBILE CARDS ================= */}
{containers.map((container) => (
{/* Header */}
{container.name}
{container.status}
{container.id}
{container.image}
Node
{container.node}
Uptime
{container.uptime}
CPU
{container.cpu.toFixed(1)}%
Memory
{container.memory.toFixed(1)}%
{container.status === "running" ? ( ) : ( )}
))}
); }