import { useFetcher } from "react-router"; import Button from "~/components/button"; import Link from "~/components/link"; import Notice from "~/components/notice"; import StatusCircle from "~/components/status-circle"; import Text from "~/components/text"; import Title from "~/components/title"; import { agentsContext, authContext } from "~/server/context"; import { formatTimeDelta } from "~/utils/time"; import type { Route } from "./+types/agent"; export async function loader({ request, context }: Route.LoaderArgs) { const agents = context.get(agentsContext); const auth = context.get(authContext); await auth.require(request); if (agents.state !== "enabled") { return { enabled: false as const, reason: agents.reason }; } const sync = agents.value.lastSync(); return { enabled: true as const, syncedAt: sync.syncedAt?.toISOString() ?? null, nodeCount: sync.nodeCount, error: sync.error, authUrl: sync.authUrl, }; } export async function action({ request, context }: Route.ActionArgs) { const agents = context.get(agentsContext); const auth = context.get(authContext); await auth.require(request); if (agents.state !== "enabled") { return { success: false, error: agents.reason }; } await agents.value.triggerSync(); const sync = agents.value.lastSync(); return { success: !sync.error, error: sync.error, authUrl: sync.authUrl, }; } export default function Page({ loaderData }: Route.ComponentProps) { const fetcher = useFetcher(); const isSyncing = fetcher.state !== "idle"; if (!loaderData.enabled) { return (
Headplane Agent {loaderData.reason}. To learn how to set up the agent, visit the{" "} documentation
); } const isPending = !loaderData.syncedAt && loaderData.authUrl; const hasError = Boolean(loaderData.error); return (
Headplane Agent The Headplane Agent syncs node information like OS version and connectivity details from your Tailnet.
{hasError ? "Error" : isPending ? "Waiting for approval" : "Healthy"}
Last synced: {loaderData.syncedAt ? ( {formatTimeDelta(new Date(loaderData.syncedAt))} ) : ( "Never" )} Nodes synced: {loaderData.nodeCount}
{isPending ? ( The agent is waiting for its Tailnet registration to be approved. Headplane will attempt to auto-approve it, but if that fails, you can complete approval by visiting{" "} this link . ) : undefined} {loaderData.error ? ( {loaderData.error} ) : undefined}
); }