import { useMemo, useState } from "react" import type { ServiceSummary, HealthStatus } from "@/types" import { ServiceCard } from "./ServiceCard" import { kindLabel } from "@/lib/labels" import { cn } from "@/lib/utils" interface ServiceSectionProps { services: ServiceSummary[] statuses: HealthStatus[] } // The services page mixes systemd services and caddy statics — both URL-reachable. const KIND_ORDER = ["service", "static"] // Active chip color per kind — mirrors KindBadge so the filter reads as the badge. const KIND_ACTIVE: Record = { service: "bg-green-700 text-white border-green-600", static: "bg-cyan-700 text-white border-cyan-600", } export function ServiceSection({ services, statuses }: ServiceSectionProps) { const statusMap = useMemo(() => new Map(statuses.map((s) => [s.id, s])), [statuses]) const [search, setSearch] = useState("") const [kind, setKind] = useState(null) const counts = useMemo(() => { const c: Record = {} for (const s of services) { const k = s.kind ?? "service" c[k] = (c[k] ?? 0) + 1 } return c }, [services]) const kindsPresent = KIND_ORDER.filter((k) => counts[k]) // Sort by name so statics and systemd services interleave alphabetically rather // than clumping by kind (the registry lists them per-kind store). const filtered = useMemo(() => { let base = [...services].sort((a, b) => a.id.localeCompare(b.id)) if (kind) base = base.filter((s) => (s.kind ?? "service") === kind) if (search) { const q = search.toLowerCase() base = base.filter( (s) => s.id.toLowerCase().includes(q) || (s.description?.toLowerCase().includes(q) ?? false), ) } return base }, [services, search, kind]) return (
setSearch(e.target.value)} placeholder="Filter services..." className="bg-black/30 border border-[var(--border)] rounded px-3 py-1.5 text-sm focus:outline-none focus:border-[var(--primary)] w-56" /> {kindsPresent.length > 1 && (
setKind(null)} /> {kindsPresent.map((k) => ( setKind(kind === k ? null : k)} /> ))}
)}
{filtered.length === 0 ? (

No services match.

) : (
{filtered.map((svc) => ( ))}
)}
) } function Chip({ label, active, activeClass, onClick, }: { label: string active: boolean activeClass: string onClick: () => void }) { return ( ) }