import { InfoIcon } from '@primer/octicons-react'; import type { ActionFunctionArgs, LoaderFunctionArgs } from 'react-router'; import { useLoaderData } from 'react-router'; import Code from '~/components/Code'; import { ErrorPopup } from '~/components/Error'; import Link from '~/components/Link'; import Tooltip from '~/components/Tooltip'; import type { LoadContext } from '~/server'; import type { Machine, Route, User } from '~/types'; import cn from '~/utils/cn'; import { menuAction } from './action'; import MachineRow from './components/machine'; import NewMachine from './dialogs/new'; export async function loader({ request, context, }: LoaderFunctionArgs) { const session = await context.sessions.auth(request); const [machines, routes, users] = await Promise.all([ context.client.get<{ nodes: Machine[] }>( 'v1/node', session.get('api_key')!, ), context.client.get<{ routes: Route[] }>( 'v1/routes', session.get('api_key')!, ), context.client.get<{ users: User[] }>('v1/user', session.get('api_key')!), ]); let magic: string | undefined; if (context.hs.readable()) { if (context.hs.c?.dns.magic_dns) { magic = context.hs.c.dns.base_domain; } } return { nodes: machines.nodes, routes: routes.routes, users: users.users, magic, server: context.config.headscale.url, publicServer: context.config.headscale.public_url, agents: context.agents?.tailnetIDs(), stats: context.agents?.lookup(machines.nodes.map((node) => node.nodeKey)), }; } export async function action(request: ActionFunctionArgs) { return menuAction(request); } export default function Page() { const data = useLoaderData(); return ( <>

Machines

Manage the devices connected to your Tailnet.{' '} Learn more

{/* We only want to show the version column if there are agents */} {data.agents !== undefined ? ( ) : undefined} {data.nodes.map((machine) => ( route.node.id === machine.id, )} users={data.users} magic={data.magic} // If we pass undefined, the column will not be rendered // This is useful for when there are no agents configured isAgent={data.agents?.includes(machine.id)} stats={data.stats?.[machine.nodeKey]} /> ))}
Name

Addresses

{data.magic ? ( Since MagicDNS is enabled, you can access devices based on their name and also at{' '} [name]. {data.magic} ) : undefined}
VersionLast Seen
); } export function ErrorBoundary() { return ; }