import { forwardRef } from 'react'; import { cn } from '@/lib/utils'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; export type NodeStatus = 'ok' | 'error' | 'na' | 'inactive'; interface TopologyNodeProps { label: string; sublabel?: string; status?: NodeStatus; icon?: React.ReactNode; onClick?: () => void; interactive?: boolean; disabled?: boolean; tooltip?: React.ReactNode; className?: string; children?: React.ReactNode; } const statusColors: Record = { ok: 'border-green-500/60 bg-green-50/50 dark:bg-green-950/20', error: 'border-red-500/60 bg-red-50/50 dark:bg-red-950/20', na: 'border-muted-foreground/30 bg-muted/30', inactive: 'border-dashed border-muted-foreground/20 bg-muted/10 opacity-50', }; const statusDotColors: Record = { ok: 'bg-green-500', error: 'bg-red-500', na: 'bg-muted-foreground/40', inactive: 'bg-muted-foreground/20', }; export const TopologyNode = forwardRef( function TopologyNode( { label, sublabel, status = 'ok', icon, onClick, interactive, disabled, tooltip, className, children }, ref, ) { const isClickable = (interactive || onClick) && !disabled; const content = (
e.stopPropagation() : undefined} onKeyDown={isClickable ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onClick?.(); } } : undefined} style={{ pointerEvents: 'all', position: 'relative' }} className={cn( 'rounded-lg border px-3 py-2 text-xs transition-all duration-200', 'nopan nodrag', statusColors[status], isClickable && '!cursor-pointer hover:shadow-sm hover:border-primary/40', disabled && '!pointer-events-none', className, )} >
{icon && {icon}}
{label}
{sublabel && (
{sublabel}
)}
{children}
); if (tooltip) { return ( {content} {tooltip} ); } return content; }, );