import { cva } from "class-variance-authority"; import { format } from "date-fns"; import { Activity, Link as LinkIcon } from "lucide-react"; import * as React from "react"; import { Checkbox } from "@/components/ui/checkbox"; import type { ProcessedAlert } from "@/lib/types/alerts"; import { cn } from "@/lib/utils"; function formatDuration(ms: number): string { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (days > 0) return `${days}d ${hours % 24}h`; if (hours > 0) return `${hours}h ${minutes % 60}m`; if (minutes > 0) return `${minutes}m`; return `${seconds}s`; } function formatTimeRange(start: number, end: number): string { return `${format(start, "HH:mm:ss")} - ${format(end, "HH:mm:ss")}`; } const alertItemVariants = cva( "group relative flex w-full items-center gap-3 border-b border-border p-3 transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", { variants: { status: { firing: "bg-destructive/5 hover:bg-destructive/10 border-l-2 border-l-destructive", resolved: "border-l-2 border-l-transparent", pending: "border-l-2 border-l-yellow-500/50", }, invalid: { true: "opacity-60 grayscale bg-muted/30", false: "", }, }, defaultVariants: { status: "resolved", invalid: false, }, }, ); interface AlertListItemProps { alert: ProcessedAlert; isSelected?: boolean; onToggleInvalid: (id: number, isInvalid: boolean) => void; onSelect: (alert: ProcessedAlert) => void; style?: React.CSSProperties; } export const AlertListItem = React.memo( ({ alert, isSelected, onToggleInvalid, onSelect, style, }: AlertListItemProps) => { const status = alert.isFiring ? "firing" : "resolved"; return (
onSelect(alert)} role="button" tabIndex={0} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { onSelect(alert); } }} >
e.stopPropagation()} > onToggleInvalid(alert.id, checked === true) } aria-label="Mark as invalid" />
{alert.alertName || `Unknown Alert #${alert.alertId}`} {alert.durationMs > 0 && ( {formatDuration(alert.durationMs)} )}
{alert.newState} | {formatTimeRange(alert.time, alert.timeEnd)}
{alert.attachedIncidentId && (
{alert.attachedIncidentId}
)} {alert.isInvalid && ( )}
{Object.entries(alert.values) .map( ([k, v]) => `${k}=${Number.isFinite(v) ? v.toFixed(1) : String(v)}`, ) .join(", ")}
{alert.isFiring && !alert.isInvalid && (
)}
); }, ); AlertListItem.displayName = "AlertListItem";