import { useQuery } from "@tanstack/react-query"; import { Activity, Server, AlertTriangle, Wifi, WifiOff, Terminal, RefreshCw, Shield, Zap, } from "lucide-react"; import { agentsApi, Agent } from "../api/client"; /** * Formats a date to a relative time string (e.g., "2 minutes ago", "1 hour ago") */ function formatRelativeTime(dateString: string | null): string { if (!dateString) return "Never seen"; const date = new Date(dateString); const now = new Date(); const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); if (diffInSeconds < 60) { return "Just now"; } 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`; } } /** * Loading skeleton for stat cards with shimmer animation */ function StatCardSkeleton({ delay }: { delay: number }) { return (
); } /** * Stat card component with Mission Control styling */ function StatCard({ title, value, icon: Icon, description, accentColor, delay, }: { title: string; value: string | number; icon: React.ComponentType<{ className?: string }>; description?: string; accentColor: "cyan" | "green" | "amber" | "rose"; delay: number; }) { const colorClasses = { cyan: { icon: "text-cyan", glow: "glow-cyan", bg: "bg-[var(--accent-cyan-muted)]", border: "border-l-[var(--accent-cyan)]", value: "text-cyan", }, green: { icon: "text-green", glow: "glow-green", bg: "bg-[var(--accent-green-muted)]", border: "border-l-[var(--accent-green)]", value: "text-green", }, amber: { icon: "text-amber", glow: "glow-amber", bg: "bg-[var(--accent-amber-muted)]", border: "border-l-[var(--accent-amber)]", value: "text-amber", }, rose: { icon: "text-rose", glow: "glow-rose", bg: "bg-[var(--accent-rose-muted)]", border: "border-l-[var(--accent-rose)]", value: "text-rose", }, }; const colors = colorClasses[accentColor]; return (
{/* Subtle gradient overlay on hover */}

{title}

{value}

{description && (

{description}

)}
{/* Icon with glow effect */}
); } /** * Status indicator dot with pulse animation */ function StatusDot({ status }: { status: string }) { const statusClasses = { online: "status-dot online", offline: "status-dot offline", error: "status-dot error", }; return ( ); } /** * Activity list item with hover effects */ function ActivityItem({ agent }: { agent: Agent }) { return (

{agent.hostname}

{agent.os_type}

{formatRelativeTime(agent.last_seen)}
); } /** * Quick action button with glow effect */ function QuickActionButton({ icon: Icon, label, description, onClick, }: { icon: React.ComponentType<{ className?: string }>; label: string; description: string; onClick?: () => void; }) { return ( ); } /** * Loading skeleton for activity list */ function ActivityListSkeleton() { return (
{[0, 1, 2, 3, 4].map((i) => (
))}
); } /** * Main Dashboard component with Mission Control aesthetic */ export function Dashboard() { const { data: agents = [], isLoading } = useQuery({ queryKey: ["agents"], queryFn: () => agentsApi.list().then((res) => res.data), refetchInterval: 30000, }); const onlineAgents = agents.filter((a: Agent) => a.status === "online"); const offlineAgents = agents.filter((a: Agent) => a.status === "offline"); const errorAgents = agents.filter((a: Agent) => a.status === "error"); // Determine system status const hasErrors = errorAgents.length > 0; const allOffline = agents.length > 0 && onlineAgents.length === 0; const systemStatus = hasErrors ? "ATTENTION REQUIRED" : allOffline ? "ALL SYSTEMS OFFLINE" : "SYSTEMS OPERATIONAL"; const statusClass = hasErrors ? "status-error" : allOffline ? "status-warning" : "status-online"; return (
{/* Page Header */}

DASHBOARD

Mission Control Overview

{/* System Status Indicator */}
{systemStatus}
{/* Stat Cards Grid */}
{isLoading ? ( <> ) : ( <> )}
{/* Bottom Grid: Activity + Quick Actions */}
{/* Recent Activity Card */}

Recent Activity

{!isLoading && agents.length > 0 && ( {agents.length} agent{agents.length !== 1 ? "s" : ""} )}
{isLoading ? ( ) : agents.length === 0 ? (

No agents registered

Deploy an agent to start monitoring endpoints.

) : (
{agents.slice(0, 5).map((agent: Agent) => ( ))}
)}
{/* Quick Actions Card */}

Quick Actions

{/* Terminal-style hint */}
$ guru-rmm --help
); }