import { useFetcher } from '@remix-run/react' import { Dispatch, SetStateAction, useMemo } from 'react' import Dialog from '~/components/Dialog' import Switch from '~/components/Switch' import Link from '~/components/Link' import { Machine, Route } from '~/types' import { cn } from '~/utils/cn' interface RoutesProps { readonly machine: Machine readonly routes: Route[] readonly state: [boolean, Dispatch>] } // TODO: Support deleting routes export default function Routes({ machine, routes, state }: RoutesProps) { const fetcher = useFetcher() // This is much easier with Object.groupBy but it's too new for us const { exit, subnet } = routes.reduce((acc, route) => { if (route.prefix === '::/0' || route.prefix === '0.0.0.0/0') { acc.exit.push(route) return acc } acc.subnet.push(route) return acc }, { exit: [], subnet: [] }) const exitEnabled = useMemo(() => { if (exit.length !== 2) return false return exit[0].enabled && exit[1].enabled }, [exit]) return ( {close => ( <> Edit route settings of {' '} {machine.givenName} Subnet routes Connect to devices you can't install Tailscale on by advertising IP ranges as subnet routes. {' '} Learn More
{subnet.length === 0 ? (

No routes are advertised on this machine.

) : undefined} {subnet.map(route => (

{route.prefix}

{ const form = new FormData() form.set('id', machine.id) form.set('_method', 'routes') form.set('route', route.id) form.set('enabled', String(checked)) fetcher.submit(form, { method: 'POST', }) }} />
))}
Exit nodes Allow your network to route internet traffic through this machine. {' '} Learn More
{exit.length === 0 ? (

This machine is not an exit node.

) : (

Use as exit node

{ const form = new FormData() form.set('id', machine.id) form.set('_method', 'exit-node') form.set('routes', exit.map(route => route.id).join(',')) form.set('enabled', String(checked)) fetcher.submit(form, { method: 'POST', }) }} />
)}
Close
)}
) }