diff --git a/ui/src/components/AgentCard.tsx b/ui/src/components/AgentCard.tsx
index 6cbc09b..68c4c39 100644
--- a/ui/src/components/AgentCard.tsx
+++ b/ui/src/components/AgentCard.tsx
@@ -1,4 +1,9 @@
+import { UptimeMessage } from "@/services/types";
+import { formatRelativeTime, isAgentOnline } from "@/services/utils";
+import { DottedProgressBar } from "./Progressbar";
+
export type AgentOverviewCardProps = {
+ count: number;
title: string;
icon: {
ref: React.ReactNode;
@@ -19,7 +24,9 @@ export function AgentOverviewCard({
);
}
+
+export type AgentCardProps = {
+ data: UptimeMessage;
+ onClick?: () => void;
+};
+
+export function AgentCard({ props }: { props: AgentCardProps }) {
+ const status = isAgentOnline(props.data)
+ ? {
+ name: "online",
+ color: "bg-green-500",
+ textColor: "text-green-400",
+ borderColor: "border-green-500/20",
+ bgColor: "bg-green-500/10",
+ }
+ : {
+ name: "offline",
+ color: "bg-red-500",
+ textColor: "text-red-400",
+ borderColor: "border-red-500/20",
+ bgColor: "bg-red-500/10",
+ };
+
+ return (
+
props.onClick?.()}
+ className="bg-[#111111] border border-[#262626] rounded-lg p-6 hover:bg-[#151515] transition-all cursor-pointer group"
+ >
+
+
+
+ {status.name.toUpperCase()}
+
+
+ {props.data.agent}
+
+
+
+
+
+
+
+
+ {formatRelativeTime(props.data.last_seen)}
+
+ {props.data.uptime.toFixed(2)}%
+
+
+
+
+
+ );
+}
diff --git a/ui/src/components/Progressbar.tsx b/ui/src/components/Progressbar.tsx
new file mode 100644
index 0000000..5c797ce
--- /dev/null
+++ b/ui/src/components/Progressbar.tsx
@@ -0,0 +1,24 @@
+export function DottedProgressBar({
+ color,
+ percentage,
+ totalDots = 10,
+}: {
+ color: string;
+ percentage: number;
+ totalDots?: number;
+}) {
+ const filledDots = Math.round((percentage / 100) * totalDots);
+
+ return (
+
+ {Array.from({ length: totalDots }).map((_, index) => (
+
+ ))}
+
+ );
+}
diff --git a/ui/src/pages/home.tsx b/ui/src/pages/home.tsx
index 92495f2..4c09a48 100644
--- a/ui/src/pages/home.tsx
+++ b/ui/src/pages/home.tsx
@@ -1,8 +1,27 @@
-import { AgentOverviewCard } from "@/components/AgentCard";
+"use client";
+
+import { AgentCard, AgentOverviewCard } from "@/components/AgentCard";
import { Header } from "@/components/Header";
+import { UptimeMessage } from "@/services/types";
+import { isAgentOnline } from "@/services/utils";
import { Box } from "lucide-react";
+import { useEffect, useState } from "react";
export function HomePage() {
+ const [agents, setAgents] = useState
([]);
+
+ useEffect(() => {
+ fetch("http://localhost:3000/agents")
+ .then((res) => res.json())
+ .then((data) => {
+ setAgents(data);
+ });
+ }, []);
+
+ const totalAgents = agents.length;
+ const onlineAgents = agents.filter((agent) => isAgentOnline(agent)).length;
+ const offlineAgents = totalAgents - onlineAgents;
+
return (
+ Overview
+
,
@@ -26,6 +48,7 @@ export function HomePage() {
/>
Agents
-
+
+ {agents.map((agent, index) => (
+
+ ))}
+
diff --git a/ui/src/services/types.ts b/ui/src/services/types.ts
index 8dd95e9..21f4f04 100644
--- a/ui/src/services/types.ts
+++ b/ui/src/services/types.ts
@@ -54,5 +54,5 @@ export interface StatusMessage {
export interface UptimeMessage {
agent: string;
uptime: number;
- last_seen: Date;
+ last_seen: string;
}
diff --git a/ui/src/services/utils.ts b/ui/src/services/utils.ts
new file mode 100644
index 0000000..c990716
--- /dev/null
+++ b/ui/src/services/utils.ts
@@ -0,0 +1,28 @@
+import { UptimeMessage } from "@/services/types";
+
+export function isAgentOnline(data: UptimeMessage): boolean {
+ const timeDiff = new Date().getTime() - new Date(data.last_seen).getTime();
+
+ return timeDiff < 10000;
+}
+
+export const formatRelativeTime = (timestamp: string): string => {
+ const now = new Date();
+ const past = new Date(timestamp);
+ const diffInSeconds = Math.floor((now.getTime() - past.getTime()) / 1000);
+
+ if (diffInSeconds < 5) {
+ return "now";
+ } else if (diffInSeconds < 60) {
+ return `${diffInSeconds}s ago`;
+ } else if (diffInSeconds < 3600) {
+ const minutes = Math.floor(diffInSeconds / 60);
+ return `${minutes}m ago`;
+ } else if (diffInSeconds < 86400) {
+ const hours = Math.floor(diffInSeconds / 3600);
+ return `${hours}h ago`;
+ } else {
+ const days = Math.floor(diffInSeconds / 86400);
+ return `${days}d ago`;
+ }
+};