headplane/app/routes/dns/dialogs/add-ns.tsx

95 lines
2.8 KiB
TypeScript
Raw Normal View History

2025-08-21 11:33:45 -04:00
import { Split } from 'lucide-react';
import { useMemo, useState } from 'react';
2025-02-01 15:28:04 -05:00
import Chip from '~/components/Chip';
2024-12-31 10:30:14 +05:30
import Dialog from '~/components/Dialog';
2025-01-28 16:02:47 -05:00
import Input from '~/components/Input';
2024-12-31 10:30:14 +05:30
import Switch from '~/components/Switch';
import Tooltip from '~/components/Tooltip';
2025-01-28 17:46:16 -05:00
import cn from '~/utils/cn';
2024-05-21 17:21:14 -04:00
interface Props {
2024-12-31 10:30:14 +05:30
nameservers: Record<string, string[]>;
2024-05-21 17:21:14 -04:00
}
export default function AddNameserver({ nameservers }: Props) {
2024-12-31 10:30:14 +05:30
const [split, setSplit] = useState(false);
const [ns, setNs] = useState('');
const [domain, setDomain] = useState('');
2024-05-21 17:21:14 -04:00
const isInvalid = useMemo(() => {
if (ns === '') return false;
// Test if it's a valid IPv4 or IPv6 address
const ipv4 = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
const ipv6 = /^([0-9a-fA-F:]+:+)+[0-9a-fA-F]+$/;
if (!ipv4.test(ns) && !ipv6.test(ns)) return true;
2024-05-21 17:21:14 -04:00
if (split) {
return nameservers[domain]?.includes(ns);
}
2024-05-21 17:21:14 -04:00
return Object.values(nameservers).some((nsList) => nsList.includes(ns));
}, [nameservers, ns]);
2024-05-21 17:21:14 -04:00
return (
<Dialog>
<Dialog.Button>Add nameserver</Dialog.Button>
<Dialog.Panel>
<Dialog.Title className="mb-4">Add nameserver</Dialog.Title>
2025-08-21 11:33:45 -04:00
<input name="action_id" type="hidden" value="add_ns" />
2025-01-28 16:02:47 -05:00
<Input
2025-08-21 11:33:45 -04:00
description="Use this IPv4 or IPv6 address to resolve names."
isInvalid={isInvalid}
isRequired
2025-01-28 16:02:47 -05:00
label="Nameserver"
name="ns"
2025-01-28 16:02:47 -05:00
onChange={setNs}
2025-08-21 11:33:45 -04:00
placeholder="1.2.3.4"
/>
<div className="flex items-center justify-between mt-8">
<div className="block">
<div className="inline-flex items-center gap-2">
<Dialog.Text className="font-semibold">
Restrict to domain
</Dialog.Text>
<Tooltip>
2025-02-01 15:28:04 -05:00
<Chip
className={cn('inline-flex items-center')}
2025-08-21 11:33:45 -04:00
leftIcon={<Split className="w-3 h-3 mr-0.5" />}
text="Split DNS"
2025-02-01 15:28:04 -05:00
/>
<Tooltip.Body>
Only clients that support split DNS (Tailscale v1.8 or later
for most platforms) will use this nameserver. Older clients
will ignore it.
</Tooltip.Body>
</Tooltip>
</div>
<Dialog.Text className="text-sm">
This nameserver will only be used for some domains.
</Dialog.Text>
</div>
<Switch label="Split DNS" onChange={setSplit} />
</div>
{split ? (
<>
<Dialog.Text className="font-semibold mt-8">Domain</Dialog.Text>
2025-01-28 16:02:47 -05:00
<Input
isRequired={split === true}
label="Domain"
name="split_name"
2025-01-28 16:02:47 -05:00
onChange={setDomain}
2025-08-21 11:33:45 -04:00
placeholder="example.com"
/>
<Dialog.Text className="text-sm">
Only single-label or fully-qualified queries matching this suffix
should use the nameserver.
</Dialog.Text>
2024-05-21 17:21:14 -04:00
</>
) : (
2025-08-21 11:33:45 -04:00
<input name="split_name" type="hidden" value="global" />
)}
2024-05-21 17:21:14 -04:00
</Dialog.Panel>
</Dialog>
2024-12-31 10:30:14 +05:30
);
2024-05-21 17:21:14 -04:00
}