import type { PageComponentImpact } from "@openstatus/db/src/schema/page_components/constants"; import { Add } from "@openstatus/icons"; import { Button } from "@openstatus/ui/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@openstatus/ui/components/ui/dropdown-menu"; import { SelectTrigger } from "@openstatus/ui/components/ui/select"; import { cn } from "@openstatus/ui/lib/utils"; import { Fragment } from "react"; import { StatusDot } from "@/components/common/status-dot"; import { type OrderedComponent, toComponentSections, } from "@/data/page-components.client"; import { impactDisplay } from "@/data/status-report-updates.client"; export function ComponentList({ children, className, ...props }: React.ComponentProps<"ul">) { return ( ); } export function ComponentListItem({ children, className, ...props }: React.ComponentProps<"li">) { return (
  • {children}
  • ); } /** `group` renders muted after the name for components in a group. */ export function ComponentListName({ children, group, className, ...props }: React.ComponentProps<"span"> & { group?: string | null }) { return ( {children} {group ? ( {group} ) : null} ); } /** Dot + label for an impact; nullish reads as untriaged. */ export function ComponentImpact({ impact, className, ...props }: React.ComponentProps<"span"> & { impact: PageComponentImpact | null | undefined; }) { const display = impactDisplay(impact); return ( {display.label} ); } /** Right-aligned controls on a row, like `DetailActions`. */ export function ComponentListActions({ children, className, ...props }: React.ComponentProps<"div">) { return (
    {children}
    ); } export function ComponentListEmpty({ children = "No components affected.", className, ...props }: React.ComponentProps<"p">) { return (

    {children}

    ); } // Borderless until hovered, like PropertySelectTrigger. export function ComponentListSelectTrigger({ className, ...props }: React.ComponentProps) { return ( ); } /** * Adds one of `components` not yet on the list, in page order: a group's * members sit under its label, runs of ungrouped components in between, * separated. Renders nothing once everything is added, unless a * `placeholder` explains the empty state. */ export function ComponentListAdd({ components, groups = [], onAdd, disabled = false, placeholder, className, }: { components: OrderedComponent[]; groups?: { id: number; name: string }[]; onAdd: (id: number) => void; disabled?: boolean; /** Shown as a disabled button when there is nothing to add. */ placeholder?: string; className?: string; }) { const sections = toComponentSections(components, groups); // -ml-2.5 puts the label on the names' edge const buttonClassName = cn( "text-muted-foreground -ml-2.5 h-7 self-start font-normal", className, ); if (components.length === 0) { if (!placeholder) return null; return ( ); } const item = (c: OrderedComponent) => ( onAdd(c.id)} > {c.name} ); return ( {/* long pages: cap at 20rem, still bounded by the viewport on short screens */} {sections.map((section, i) => { const key = section.group?.id ?? `ungrouped-${i}`; return ( {i > 0 ? : null} {section.group ? ( {section.group.name} {section.items.map(item)} ) : ( section.items.map(item) )} ); })} ); }