"use client" import { useMemo } from "react" import { useQuery } from "@tanstack/react-query" import { Card, CardContent, CardHeader } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Collapsible } from "@/components/ui/collapsible" import { Globe, Server, Activity, ArrowUpRight, ArrowDownRight, Minus, ExternalLink, } from "lucide-react" import { listMonitors, groupMonitorsByDomain, getMonitorStatusColor, formatUptime, type Monitor, type GroupedMonitors, } from "@/lib/monitors" import { Link } from "@/components/router" import { cn } from "@/lib/utils" interface GroupedMonitorsTableProps { view?: "grid" | "list" } function DomainGroupHeader({ domain, group, monitorCount, }: { domain: string group: GroupedMonitors monitorCount: number }) { // Calculate aggregate status for the domain const allMonitors = [...group.monitors, ...Array.from(group.subdomains.values()).flat()] const upCount = allMonitors.filter((m) => m.status === "up").length const downCount = allMonitors.filter((m) => m.status === "down").length const pausedCount = allMonitors.filter((m) => m.status === "paused").length const statusColor = downCount > 0 ? "bg-red-500" : upCount > 0 ? "bg-green-500" : pausedCount > 0 ? "bg-yellow-500" : "bg-gray-400" return (
{domain} {monitorCount} monitor{monitorCount !== 1 ? "s" : ""}
{upCount > 0 && ( {upCount} )} {downCount > 0 && ( {downCount} )} {pausedCount > 0 && ( {pausedCount} )}
) } function MonitorCard({ monitor }: { monitor: Monitor }) { const uptime24h = monitor.uptime_stats?.["24h"] ?? 100 const statusColor = getMonitorStatusColor(monitor.status) return (
{monitor.name} {monitor.active === false && ( Paused )}
24h: {formatUptime(uptime24h)}
) } function SubdomainSection({ subdomain, monitors, }: { subdomain: string monitors: Monitor[] }) { const downCount = monitors.filter((m) => m.status === "down").length const header = (
{subdomain} {monitors.length} {downCount > 0 && ( {downCount} down )}
) return ( } defaultOpen={true} className="ml-4 border-l-2 border-muted rounded-none border-t-0 border-r-0 border-b-0" >
{monitors.map((monitor) => ( ))}
) } function DomainGroup({ domain, group }: { domain: string; group: GroupedMonitors }) { const monitorCount = group.monitors.length + Array.from(group.subdomains.values()).flat().length const content = ( {/* Root domain monitors */} {group.monitors.length > 0 && (
Root Domain
{group.monitors.map((monitor) => ( ))}
)} {/* Subdomain sections */} {Array.from(group.subdomains.entries()).map(([subdomain, monitors]) => ( ))}
) return ( } defaultOpen={true} description={} > {content} ) } export function GroupedMonitorsTable() { const { data: monitors, isLoading } = useQuery({ queryKey: ["monitors"], queryFn: listMonitors, }) const groupedMonitors = useMemo(() => { if (!monitors) return new Map() return groupMonitorsByDomain(monitors) }, [monitors]) const ungroupedMonitors = useMemo(() => { if (!monitors) return [] return monitors.filter((m) => !m.url && !m.hostname) }, [monitors]) if (isLoading) { return (
{[1, 2, 3].map((i) => (
))}
) } const domainGroups = Array.from(groupedMonitors.entries()).sort((a, b) => a[0].localeCompare(b[0])) return (
{/* Domain groups */} {domainGroups.map(([domain, group]) => ( ))} {/* Ungrouped monitors (no URL/hostname) */} {ungroupedMonitors.length > 0 && ( } defaultOpen={true} >
{ungroupedMonitors.map((monitor) => ( ))}
)} {/* Empty state */} {domainGroups.length === 0 && ungroupedMonitors.length === 0 && (

No monitors yet

Create your first monitor to get started

)}
) }