import { ChevronDownIcon, CopyIcon } from '@primer/octicons-react'; import { useMemo } from 'react'; import { Link } from 'react-router'; import Chip from '~/components/Chip'; import Menu from '~/components/Menu'; import StatusCircle from '~/components/StatusCircle'; import type { User } from '~/types'; import cn from '~/utils/cn'; import * as hinfo from '~/utils/host-info'; import { ExitNodeTag } from '~/components/tags/ExitNode'; import { ExpiryTag } from '~/components/tags/Expiry'; import { HeadplaneAgentTag } from '~/components/tags/HeadplaneAgent'; import { SubnetTag } from '~/components/tags/Subnet'; import { PopulatedNode } from '~/utils/node-info'; import toast from '~/utils/toast'; import MenuOptions from './menu'; interface Props { node: PopulatedNode; users: User[]; isAgent?: boolean; magic?: string; isDisabled?: boolean; } export default function MachineRow({ node, users, isAgent, magic, isDisabled, }: Props) { const uiTags = useMemo(() => { const tags = uiTagsForNode(node, isAgent); return tags; }, [node, isAgent]); const ipOptions = useMemo(() => { if (magic) { return [...node.ipAddresses, `${node.givenName}.${magic}`]; } return node.ipAddresses; }, [magic, node.ipAddresses]); return (

{node.givenName}

{node.user.name}

{mapTagsToComponents(node, uiTags)} {node.validTags.map((tag) => ( ))}
{node.ipAddresses[0]} { await navigator.clipboard.writeText(key.toString()); toast('Copied IP address to clipboard'); }} > {ipOptions.map((ip) => (
{ip}
))}
{/* We pass undefined when agents are not enabled */} {isAgent !== undefined ? ( {node.hostInfo !== undefined ? ( <>

{hinfo.getTSVersion(node.hostInfo)}

{hinfo.getOSInfo(node.hostInfo)}

) : (

Unknown

)} ) : undefined}

{node.online && !node.expired ? 'Connected' : new Date(node.lastSeen).toLocaleString()}

); } export function uiTagsForNode(node: PopulatedNode, isAgent?: boolean) { const uiTags: string[] = []; if (node.expired) { uiTags.push('expired'); } if (node.expiry === null) { uiTags.push('no-expiry'); } if (node.customRouting.exitRoutes.length > 0) { if (node.customRouting.exitApproved) { uiTags.push('exit-approved'); } else { uiTags.push('exit-waiting'); } } if (node.customRouting.subnetWaitingRoutes.length > 0) { uiTags.push('subnet-waiting'); } else if (node.customRouting.subnetApprovedRoutes.length > 0) { uiTags.push('subnet-approved'); } if (isAgent === true) { uiTags.push('headplane-agent'); } return uiTags; } export function mapTagsToComponents(node: PopulatedNode, uiTags: string[]) { return uiTags.map((tag) => { switch (tag) { case 'exit-approved': case 'exit-waiting': return ; case 'subnet-approved': case 'subnet-waiting': return ; case 'expired': case 'no-expiry': return ( ); case 'headplane-agent': return ; default: return; } }); }