From c84e9ca4a8ae256a365c788ac44748d6a25a6867 Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Tue, 4 Nov 2025 23:06:56 -0500 Subject: [PATCH] feat: update more primitives to use the new api --- app/layouts/dashboard.tsx | 17 +++-- app/layouts/shell.tsx | 31 ++++----- app/routes/machines/machine.tsx | 8 +-- app/routes/machines/overview.tsx | 42 ++++++------- app/routes/ssh/console.tsx | 63 ++++++------------- app/routes/util/healthz.ts | 10 +-- app/server/db/pruner.ts | 15 ++--- app/server/headscale/api/endpoints/index.ts | 31 +++++++++ .../headscale/api/endpoints/pre-auth-keys.ts | 8 +-- 9 files changed, 109 insertions(+), 116 deletions(-) diff --git a/app/layouts/dashboard.tsx b/app/layouts/dashboard.tsx index 82bb441..eecd2d2 100644 --- a/app/layouts/dashboard.tsx +++ b/app/layouts/dashboard.tsx @@ -1,24 +1,21 @@ -import { type LoaderFunctionArgs, Outlet, redirect } from 'react-router'; +import { Outlet, redirect } from 'react-router'; import { ErrorPopup } from '~/components/Error'; -import type { LoadContext } from '~/server'; import { pruneEphemeralNodes } from '~/server/db/pruner'; import ResponseError from '~/server/headscale/api/response-error'; import log from '~/utils/log'; +import type { Route } from './+types/dashboard'; -export async function loader({ - request, - context, - ...rest -}: LoaderFunctionArgs) { - const healthy = await context.client.healthcheck(); +export async function loader({ request, context, ...rest }: Route.LoaderArgs) { const session = await context.sessions.auth(request); + const api = context.hsApi.getRuntimeClient(session.api_key); await pruneEphemeralNodes({ context, request, ...rest }); + const healthy = await api.isHealthy(); // We shouldn't session invalidate if Headscale is down - // TODO: Notify in the logs or the UI that OIDC auth key is wrong if enabled + // TODO: Notify in the logs or the UI whether or not the OIDC auth key is wrong if enabled if (healthy) { try { - await context.client.get('v1/apikey', session.api_key); + await api.getApiKeys(); } catch (error) { if (error instanceof ResponseError) { log.debug('api', 'API Key validation failed %o', error); diff --git a/app/layouts/shell.tsx b/app/layouts/shell.tsx index 0b2d247..6a6c67b 100644 --- a/app/layouts/shell.tsx +++ b/app/layouts/shell.tsx @@ -1,26 +1,18 @@ import { eq } from 'drizzle-orm'; import { CircleCheckIcon } from 'lucide-react'; -import { - LoaderFunctionArgs, - Outlet, - redirect, - useLoaderData, -} from 'react-router'; +import { Outlet, redirect } from 'react-router'; import Button from '~/components/Button'; import Card from '~/components/Card'; import Footer from '~/components/Footer'; import Header from '~/components/Header'; -import type { LoadContext } from '~/server'; import { users } from '~/server/db/schema'; import { Capabilities } from '~/server/web/roles'; import toast from '~/utils/toast'; +import { Route } from './+types/shell'; // This loads the bare minimum for the application to function // So we know that if context fails to load then well, oops? -export async function loader({ - request, - context, -}: LoaderFunctionArgs) { +export async function loader({ request, context }: Route.LoaderArgs) { try { const session = await context.sessions.auth(request); if ( @@ -39,6 +31,7 @@ export async function loader({ } } + const api = context.hsApi.getRuntimeClient(session.api_key); const check = await context.sessions.check(request, Capabilities.ui_access); return { config: context.hs.c, @@ -62,7 +55,7 @@ export async function loader({ ), }, onboarding: request.url.endsWith('/onboarding'), - healthy: await context.client.healthcheck(), + healthy: await api.isHealthy(), }; } catch { return redirect('/login', { @@ -73,14 +66,12 @@ export async function loader({ } } -export default function Shell() { - const data = useLoaderData(); - +export default function Shell({ loaderData }: Route.ComponentProps) { return ( <> -
+
{/* Always show the outlet if we are onboarding */} - {(data.onboarding ? true : data.uiAccess) ? ( + {(loaderData.onboarding ? true : loaderData.uiAccess) ? ( ) : ( @@ -96,13 +87,13 @@ export default function Shell() { className="flex text-md font-mono" onPress={async () => { await navigator.clipboard.writeText( - `tailscale up --login-server=${data.url}`, + `tailscale up --login-server=${loaderData.url}`, ); toast('Copied to clipboard'); }} > - tailscale up --login-server={data.url} + tailscale up --login-server={loaderData.url}

Click this button to copy the command. @@ -113,7 +104,7 @@ export default function Shell() {

)} -