"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
)}
)
}