From e00c6efcda8612b9508e90b131c1c577d1404a13 Mon Sep 17 00:00:00 2001 From: mblanke Date: Fri, 13 Feb 2026 13:15:36 -0500 Subject: [PATCH] fix: add labels to container API, null-safe ContainerGroup, error boundary - containers/route.ts: include c.Labels in response (was missing, caused null crash) - ContainerGroup.tsx: null-safe getTraefikUrl with optional chaining - error.tsx: add Next.js error boundary for graceful client-side error handling --- src/app/api/containers/route.ts | 3 ++- src/app/error.tsx | 30 ++++++++++++++++++++++++++++++ src/components/ContainerGroup.tsx | 5 +++-- 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 src/app/error.tsx diff --git a/src/app/api/containers/route.ts b/src/app/api/containers/route.ts index 355e90c..eed7e0f 100644 --- a/src/app/api/containers/route.ts +++ b/src/app/api/containers/route.ts @@ -47,6 +47,7 @@ export async function GET() { state: c.State, status: c.Status, ports: c.Ports || [], + labels: c.Labels || {}, cpu, memory, stats: statsText, @@ -59,4 +60,4 @@ export async function GET() { console.error("Containers API error:", error); return NextResponse.json({ error: "Failed to fetch containers" }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/src/app/error.tsx b/src/app/error.tsx new file mode 100644 index 0000000..6030d3b --- /dev/null +++ b/src/app/error.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { useEffect } from "react"; + +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + useEffect(() => { + console.error("Dashboard error:", error); + }, [error]); + + return ( +
+
+

Something went wrong

+

{error.message}

+ +
+
+ ); +} diff --git a/src/components/ContainerGroup.tsx b/src/components/ContainerGroup.tsx index 4f6d788..890523a 100644 --- a/src/components/ContainerGroup.tsx +++ b/src/components/ContainerGroup.tsx @@ -28,7 +28,8 @@ export default function ContainerGroup({ } }; - const getTraefikUrl = (labels: Record) => { + const getTraefikUrl = (labels?: Record | null) => { + if (!labels || typeof labels !== "object") return null; for (const key of Object.keys(labels)) { if (key.includes("traefik.http.routers") && key.endsWith(".rule")) { const match = labels[key].match(/Host\(`([^`]+)`\)/); @@ -96,7 +97,7 @@ export default function ContainerGroup({ {container.status} - {container.ports.length > 0 && ( + {container.ports && container.ports.length > 0 && (
Ports