-
- {/* Services */}
-
-
- Services
-
- {data?.services.length ?? 0}
-
-
-
- {data?.services.length ? (
-
- {data.services.map((s) => (
-
-
- {s.name}
-
- ))}
-
- ) : (
-
- No services detected
-
- )}
-
-
-
- {/* Overview */}
-
-
- Overview
-
-
-
-
-
- {data?.services.length ?? "-"}
-
-
- Total
-
-
-
-
- {running}
-
-
- Healthy
-
-
-
-
- {data?.traces.length ?? 0}
-
-
- Traces
-
-
-
-
-
-
-
- {/* Health */}
-
-
- Health
-
-
-
-
-
-
- {/* Links */}
-
-
- Links
-
-
+
+
+ {/* Services */}
+
+
+ Services
+
+ {data?.services.length ?? 0}
+
+
+
+ {data?.services.length ? (
-
-
+ ) : (
+
+ No services detected
+
+ )}
+
+
- {/* System Resources */}
- {hasNode && (
-
-
- System Resources
-
+
+ Overview
+
+
+
+
+
+
+
+
+
+
+
+ {/* Health */}
+
+
+ Health
+
+
+
+
+
+
+ {/* Links */}
+
+
+ Links
+
+
+
+
+
- {/* Request Rate */}
- {hasTraffik && (
-
-
- Request Rate
-
- {data?.rps?.length
- ? `${data.rps[data.rps.length - 1].toFixed(1)}/s`
- : "-"}
-
-
-
-
-
-
- )}
-
- {/* Latency */}
- {hasTraffik && (
-
-
- Latency
-
- {data?.latency?.length
- ? `${data.latency[data.latency.length - 1].toFixed(0)}ms`
- : "-"}
-
-
-
-
-
-
- )}
-
- {/* Error Rate */}
- {hasTraffik && (
-
-
- Error Rate
-
- {data?.errors?.length
- ? `${data.errors[data.errors.length - 1].toFixed(1)}/s`
- : "-"}
-
-
-
-
-
-
- )}
-
- {/* Trace Volume */}
+ {/* System Resources */}
+ {hasNode && (
- Trace Volume
-
- {data?.traces.length ?? 0} traces
-
-
-
-
-
-
-
- {/* Recent Traces */}
-
-
- Recent Traces
-
- {data?.traces.length ?? 0}
+ System Resources
+
+ {node?.load1?.toFixed(2)} {node?.load5?.toFixed(2)}{" "}
+ {node?.load15?.toFixed(2)}
- {data?.traces.length ? (
-
- ) : (
-
- No traces — data appears once services send OTel telemetry
-
- )}
+
+
+
+
+
-
+ )}
+
+ {/* Request Rate */}
+ {hasTraffik && (
+
+
+ Request Rate
+
+ {data?.rps?.length
+ ? `${data.rps[data.rps.length - 1].toFixed(1)}/s`
+ : "-"}
+
+
+
+
+
+
+ )}
+
+ {/* Latency */}
+ {hasTraffik && (
+
+
+ Latency
+
+ {data?.latency?.length
+ ? `${data.latency[data.latency.length - 1].toFixed(0)}ms`
+ : "-"}
+
+
+
+
+
+
+ )}
+
+ {/* Error Rate */}
+ {hasTraffik && (
+
+
+ Error Rate
+
+ {data?.errors?.length
+ ? `${data.errors[data.errors.length - 1].toFixed(1)}/s`
+ : "-"}
+
+
+
+
+
+
+ )}
+
+ {/* Trace Volume */}
+
+
+ Trace Volume
+
+ {data?.traces.length ?? 0} traces
+
+
+
+
+
+
+
+ {/* Recent Traces */}
+
+
+ Recent Traces
+
+ {data?.traces.length ?? 0}
+
+
+
+ {data?.traces.length ? (
+
+ ) : (
+
+ No traces — data appears once services send OTel telemetry
+
+ )}
+
+
);
}
+
+function StatBox({
+ value,
+ label,
+ color,
+}: {
+ value: number | string | undefined;
+ label: string;
+ color: string;
+}) {
+ return (
+
+
+ {value ?? "-"}
+
+
+ {label}
+
+
+ );
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index f2f1483..bfec96c 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
+import { DashboardHeader } from "@/components/dashboard/header";
import "./globals.css";
const geistSans = Geist({
@@ -13,9 +14,9 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
- title: "Asep Haryana Saputra — Hub",
+ title: "Asep Haryana Saputra",
description:
- "Personal portfolio and infrastructure monitoring dashboard by Asep Haryana Saputra.",
+ "Backend & infrastructure engineer — portfolio, projects, and live monitoring dashboard by Asep Haryana Saputra.",
};
export default function RootLayout({
@@ -28,7 +29,10 @@ export default function RootLayout({
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
- {children}
+
+
+ {children}
+