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 type { Machine, Route, User } from '~/types'; import cn from '~/utils/cn'; import { loadContext } from '~/utils/config/headplane'; import { loadConfig } from '~/utils/config/headscale'; import { pull } from '~/utils/headscale'; import { getSession } from '~/utils/sessions.server'; import { initAgentSocket, queryAgent } from '~/utils/ws-agent'; import Tooltip from '~/components/Tooltip'; import { menuAction } from './action'; import MachineRow from './components/machine'; import NewMachine from './dialogs/new'; export async function loader({ request, context: lC }: LoaderFunctionArgs) { const session = await getSession(request.headers.get('Cookie')); const [machines, routes, users] = await Promise.all([ pull<{ nodes: Machine[] }>('v1/node', session.get('hsApiKey')!), pull<{ routes: Route[] }>('v1/routes', session.get('hsApiKey')!), pull<{ users: User[] }>('v1/user', session.get('hsApiKey')!), ]); initAgentSocket(lC); const stats = await queryAgent(machines.nodes.map((node) => node.nodeKey)); const context = await loadContext(); let magic: string | undefined; if (context.config.read) { const config = await loadConfig(); if (config.dns.magic_dns) { magic = config.dns.base_domain; } } return { nodes: machines.nodes, routes: routes.routes, users: users.users, magic, stats, server: context.headscaleUrl, publicServer: context.headscalePublicUrl, }; } 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

{/****/} {data.nodes.map((machine) => ( route.node.id === machine.id, )} users={data.users} magic={data.magic} 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 ; }