From d68737e410b41b0264da78a864273716d8728f69 Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Tue, 4 Nov 2025 22:40:23 -0500 Subject: [PATCH] feat: switch machine apis to new runtime api client --- app/components/Error.tsx | 2 +- app/layouts/dashboard.tsx | 2 +- app/routes/acls/acl-action.ts | 2 +- app/routes/acls/acl-loader.ts | 2 +- app/routes/auth/login/action.ts | 2 +- .../machines/components/machine-row.tsx | 5 +- app/routes/machines/components/menu.tsx | 43 +-- app/routes/machines/dialogs/delete.tsx | 6 +- app/routes/machines/dialogs/move.tsx | 14 +- app/routes/machines/dialogs/new.tsx | 12 +- app/routes/machines/dialogs/rename.tsx | 10 +- app/routes/machines/dialogs/routes.tsx | 4 +- app/routes/machines/dialogs/tags.tsx | 18 +- app/routes/machines/machine-actions.ts | 294 ++++++------------ app/routes/machines/machine.tsx | 38 +-- app/routes/machines/overview.tsx | 12 +- app/server/headscale/api-client.ts | 46 ++- app/server/headscale/api/error.ts | 20 -- app/server/headscale/api/factory.ts | 2 +- app/server/headscale/api/index.ts | 6 +- app/server/headscale/api/response-error.ts | 19 ++ nix/package.nix | 2 +- 22 files changed, 250 insertions(+), 311 deletions(-) create mode 100644 app/server/headscale/api/response-error.ts diff --git a/app/components/Error.tsx b/app/components/Error.tsx index aec26c7..90167f1 100644 --- a/app/components/Error.tsx +++ b/app/components/Error.tsx @@ -1,6 +1,6 @@ import { AlertCircle } from 'lucide-react'; import { isRouteErrorResponse, useRouteError } from 'react-router'; -import ResponseError from '~/server/headscale/api/error'; +import ResponseError from '~/server/headscale/api/response-error'; import cn from '~/utils/cn'; import Card from './Card'; import Code from './Code'; diff --git a/app/layouts/dashboard.tsx b/app/layouts/dashboard.tsx index 2bfa884..82bb441 100644 --- a/app/layouts/dashboard.tsx +++ b/app/layouts/dashboard.tsx @@ -2,7 +2,7 @@ import { type LoaderFunctionArgs, 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/error'; +import ResponseError from '~/server/headscale/api/response-error'; import log from '~/utils/log'; export async function loader({ diff --git a/app/routes/acls/acl-action.ts b/app/routes/acls/acl-action.ts index f200548..3cf680b 100644 --- a/app/routes/acls/acl-action.ts +++ b/app/routes/acls/acl-action.ts @@ -1,6 +1,6 @@ import { ActionFunctionArgs, data } from 'react-router'; import { LoadContext } from '~/server'; -import ResponseError from '~/server/headscale/api/error'; +import ResponseError from '~/server/headscale/api/response-error'; import { Capabilities } from '~/server/web/roles'; import { data400, data403 } from '~/utils/res'; diff --git a/app/routes/acls/acl-loader.ts b/app/routes/acls/acl-loader.ts index 53c253e..3bbe91f 100644 --- a/app/routes/acls/acl-loader.ts +++ b/app/routes/acls/acl-loader.ts @@ -1,6 +1,6 @@ import { LoaderFunctionArgs } from 'react-router'; import { LoadContext } from '~/server'; -import ResponseError from '~/server/headscale/api/error'; +import ResponseError from '~/server/headscale/api/response-error'; import { Capabilities } from '~/server/web/roles'; import { data403 } from '~/utils/res'; diff --git a/app/routes/auth/login/action.ts b/app/routes/auth/login/action.ts index f27ed17..c3b21aa 100644 --- a/app/routes/auth/login/action.ts +++ b/app/routes/auth/login/action.ts @@ -1,6 +1,6 @@ import { ActionFunctionArgs, data, redirect } from 'react-router'; import { LoadContext } from '~/server'; -import ResponseError from '~/server/headscale/api/error'; +import ResponseError from '~/server/headscale/api/response-error'; import { Key } from '~/types'; import log from '~/utils/log'; diff --git a/app/routes/machines/components/machine-row.tsx b/app/routes/machines/components/machine-row.tsx index 7a8fcbd..cb44738 100644 --- a/app/routes/machines/components/machine-row.tsx +++ b/app/routes/machines/components/machine-row.tsx @@ -64,7 +64,10 @@ export default function MachineRow({ {node.givenName}

- {node.user.name || node.user.displayName || node.user.email || node.user.id} + {node.user.name || + node.user.displayName || + node.user.email || + node.user.id}

{mapTagsToComponents(node, uiTags)} diff --git a/app/routes/machines/components/menu.tsx b/app/routes/machines/components/menu.tsx index 4c7a9ce..26434fb 100644 --- a/app/routes/machines/components/menu.tsx +++ b/app/routes/machines/components/menu.tsx @@ -11,6 +11,7 @@ import Move from '../dialogs/move'; import Rename from '../dialogs/rename'; import Routes from '../dialogs/routes'; import Tags from '../dialogs/tags'; + interface MenuProps { node: PopulatedNode; users: User[]; @@ -36,8 +37,8 @@ export default function MachineMenu({
{modal === 'remove' && ( { if (!isOpen) setModal(null); }} @@ -45,19 +46,19 @@ export default function MachineMenu({ )} {modal === 'move' && ( { if (!isOpen) setModal(null); }} + users={users} /> )} {modal === 'rename' && ( { if (!isOpen) setModal(null); }} @@ -65,8 +66,8 @@ export default function MachineMenu({ )} {modal === 'routes' && ( { if (!isOpen) setModal(null); }} @@ -74,8 +75,8 @@ export default function MachineMenu({ )} {modal === 'tags' && ( { if (!isOpen) setModal(null); }} @@ -83,8 +84,8 @@ export default function MachineMenu({ )} {node.expired && modal === 'expire' ? undefined : ( { if (!isOpen) setModal(null); }} @@ -95,33 +96,23 @@ export default function MachineMenu({ isFullButton ? ( ) : ( @@ -142,19 +143,19 @@ export default function MachineMenu({ ) : ( )} setModal(key as Modal)} disabledKeys={node.expired ? ['expire'] : []} + onAction={(key) => setModal(key as Modal)} > Edit machine name diff --git a/app/routes/machines/dialogs/delete.tsx b/app/routes/machines/dialogs/delete.tsx index 9087d06..72f1931 100644 --- a/app/routes/machines/dialogs/delete.tsx +++ b/app/routes/machines/dialogs/delete.tsx @@ -14,16 +14,16 @@ export default function Delete({ machine, isOpen, setIsOpen }: DeleteProps) { return ( navigate('/machines')} + variant="destructive" > Remove {machine.givenName} This machine will be permanently removed from your network. To re-add it, you will need to reauthenticate to your tailnet from the device. - - + + ); diff --git a/app/routes/machines/dialogs/move.tsx b/app/routes/machines/dialogs/move.tsx index 3b86bb7..ae9792b 100644 --- a/app/routes/machines/dialogs/move.tsx +++ b/app/routes/machines/dialogs/move.tsx @@ -20,21 +20,23 @@ export default function Move({ machine, users, isOpen, setIsOpen }: MoveProps) { The owner of the machine is the user associated with it. - - - + + + diff --git a/app/routes/machines/dialogs/new.tsx b/app/routes/machines/dialogs/new.tsx index df98129..53e74a9 100644 --- a/app/routes/machines/dialogs/new.tsx +++ b/app/routes/machines/dialogs/new.tsx @@ -30,14 +30,14 @@ export default function NewMachine(data: NewMachineProps) { tailscale up --login-server={data.server} on your device. - + - + Add Device { diff --git a/app/routes/machines/dialogs/rename.tsx b/app/routes/machines/dialogs/rename.tsx index f3f08a1..d161ef7 100644 --- a/app/routes/machines/dialogs/rename.tsx +++ b/app/routes/machines/dialogs/rename.tsx @@ -27,16 +27,15 @@ export default function Rename({ This name is shown in the admin panel, in Tailscale clients, and used when generating MagicDNS names. - - + + { if (value.length === 0) { return 'Cannot be empty'; @@ -66,6 +65,7 @@ export default function Rename({ return 'Cannot contain consecutive hyphens'; } }} + validationBehavior="native" /> {magic ? ( name.length > 0 && name !== machine.givenName ? ( diff --git a/app/routes/machines/dialogs/routes.tsx b/app/routes/machines/dialogs/routes.tsx index 0fbfa29..1c5dafe 100644 --- a/app/routes/machines/dialogs/routes.tsx +++ b/app/routes/machines/dialogs/routes.tsx @@ -30,8 +30,8 @@ export default function Routes({ node, isOpen, setIsOpen }: RoutesProps) { Connect to devices you can't install Tailscale on by advertising IP ranges as subnet routes.{' '} Learn More @@ -70,8 +70,8 @@ export default function Routes({ node, isOpen, setIsOpen }: RoutesProps) { Allow your network to route internet traffic through this machine.{' '} Learn More diff --git a/app/routes/machines/dialogs/tags.tsx b/app/routes/machines/dialogs/tags.tsx index 4a31c56..b00d081 100644 --- a/app/routes/machines/dialogs/tags.tsx +++ b/app/routes/machines/dialogs/tags.tsx @@ -26,16 +26,16 @@ export default function Tags({ machine, isOpen, setIsOpen }: TagsProps) { ACL tags can be used to reference machines in your ACL policies. See the{' '} Tailscale documentation {' '} for more information. - - - + + + {tags.length === 0 ? ( @@ -44,7 +44,7 @@ export default function Tags({ machine, isOpen, setIsOpen }: TagsProps) { ) : ( tags.map((item) => ( - + {item}