diff --git a/app/routes/_data.machines.$id.tsx b/app/routes/_data.machines.$id.tsx index 3145fc1..773844b 100644 --- a/app/routes/_data.machines.$id.tsx +++ b/app/routes/_data.machines.$id.tsx @@ -1,4 +1,4 @@ -import { type LoaderFunctionArgs } from '@remix-run/node' +import { ActionFunctionArgs, type LoaderFunctionArgs } from '@remix-run/node' import { Link, useLoaderData } from '@remix-run/react' import Attribute from '~/components/Attribute' @@ -12,6 +12,7 @@ import { pull } from '~/utils/headscale' import { getSession } from '~/utils/sessions' import { useLiveData } from '~/utils/useLiveData' +import { menuAction } from './_data.machines._index/action' import MenuOptions from './_data.machines._index/menu' export async function loader({ request, params }: LoaderFunctionArgs) { @@ -44,6 +45,10 @@ export async function loader({ request, params }: LoaderFunctionArgs) { } } +export async function action({ request }: ActionFunctionArgs) { + return menuAction(request) +} + export default function Page() { const { machine, magic, routes } = useLoaderData() useLiveData({ interval: 1000 }) diff --git a/app/routes/_data.machines._index/action.tsx b/app/routes/_data.machines._index/action.tsx new file mode 100644 index 0000000..b4dfdf1 --- /dev/null +++ b/app/routes/_data.machines._index/action.tsx @@ -0,0 +1,70 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { ActionFunctionArgs, json } from '@remix-run/node' + +import { del, post } from '~/utils/headscale' +import { getSession } from '~/utils/sessions' + +export async function menuAction(request: ActionFunctionArgs['request']) { + const session = await getSession(request.headers.get('Cookie')) + if (!session.has('hsApiKey')) { + return json({ message: 'Unauthorized' }, { + status: 401, + }) + } + + const data = await request.formData() + if (!data.has('_method') || !data.has('id')) { + return json({ message: 'No method or ID provided' }, { + status: 400, + }) + } + + const id = String(data.get('id')) + const method = String(data.get('_method')) + + switch (method) { + case 'delete': { + await del(`v1/node/${id}`, session.get('hsApiKey')!) + return json({ message: 'Machine removed' }) + } + + case 'expire': { + await post(`v1/node/${id}/expire`, session.get('hsApiKey')!) + return json({ message: 'Machine expired' }) + } + + case 'rename': { + if (!data.has('name')) { + return json({ message: 'No name provided' }, { + status: 400, + }) + } + + const name = String(data.get('name')) + + await post(`v1/node/${id}/rename/${name}`, session.get('hsApiKey')!) + return json({ message: 'Machine renamed' }) + } + + case 'routes': { + if (!data.has('route') || !data.has('enabled')) { + return json({ message: 'No route or enabled provided' }, { + status: 400, + }) + } + + const route = String(data.get('route')) + const enabled = data.get('enabled') === 'true' + const postfix = enabled ? 'enable' : 'disable' + + await post(`v1/routes/${route}/${postfix}`, session.get('hsApiKey')!) + return json({ message: 'Route updated' }) + } + + default: { + return json({ message: 'Invalid method' }, { + status: 400, + }) + } + } +} diff --git a/app/routes/_data.machines._index/route.tsx b/app/routes/_data.machines._index/route.tsx index 77adbb1..7fd4e95 100644 --- a/app/routes/_data.machines._index/route.tsx +++ b/app/routes/_data.machines._index/route.tsx @@ -13,6 +13,7 @@ import { del, post, pull } from '~/utils/headscale' import { getSession } from '~/utils/sessions' import { useLiveData } from '~/utils/useLiveData' +import { menuAction } from './action' import MachineRow from './machine' export async function loader({ request }: LoaderFunctionArgs) { @@ -40,68 +41,7 @@ export async function loader({ request }: LoaderFunctionArgs) { } export async function action({ request }: ActionFunctionArgs) { - const session = await getSession(request.headers.get('Cookie')) - if (!session.has('hsApiKey')) { - return json({ message: 'Unauthorized' }, { - status: 401, - }) - } - - const data = await request.formData() - if (!data.has('_method') || !data.has('id')) { - return json({ message: 'No method or ID provided' }, { - status: 400, - }) - } - - const id = String(data.get('id')) - const method = String(data.get('_method')) - - switch (method) { - case 'delete': { - await del(`v1/node/${id}`, session.get('hsApiKey')!) - return json({ message: 'Machine removed' }) - } - - case 'expire': { - await post(`v1/node/${id}/expire`, session.get('hsApiKey')!) - return json({ message: 'Machine expired' }) - } - - case 'rename': { - if (!data.has('name')) { - return json({ message: 'No name provided' }, { - status: 400, - }) - } - - const name = String(data.get('name')) - - await post(`v1/node/${id}/rename/${name}`, session.get('hsApiKey')!) - return json({ message: 'Machine renamed' }) - } - - case 'routes': { - if (!data.has('route') || !data.has('enabled')) { - return json({ message: 'No route or enabled provided' }, { - status: 400, - }) - } - - const route = String(data.get('route')) - const enabled = data.get('enabled') === 'true' - const postfix = enabled ? 'enable' : 'disable' - - await post(`v1/routes/${route}/${postfix}`, session.get('hsApiKey')!) - return json({ message: 'Route updated' }) - } - - default: { - return json({ message: 'Invalid method' }, { - status: 400, - }) - } - } + return menuAction(request) } export default function Page() {