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({

{props.title}

-

0

+

+ {props.count} +

); } + +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`; + } +};