mirror of
https://github.com/tale/headplane.git
synced 2026-08-30 08:49:30 +00:00
feat: switch to new dialog across all code
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Form, useSubmit } from 'react-router';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useSubmit } from 'react-router';
|
||||
|
||||
import Code from '~/components/Code';
|
||||
import Dialog from '~/components/Dialog';
|
||||
@@ -23,80 +23,61 @@ export default function AddDNS({ records }: Props) {
|
||||
return lookup.value === ip;
|
||||
}, [records, name, ip]);
|
||||
|
||||
// TODO: Ditch useSubmit here (non JSON form)
|
||||
return (
|
||||
<Dialog>
|
||||
<Dialog.Button>Add DNS record</Dialog.Button>
|
||||
<Dialog.Panel>
|
||||
{(close) => (
|
||||
<>
|
||||
<Dialog.Title>Add DNS record</Dialog.Title>
|
||||
<Dialog.Text>
|
||||
Enter the domain and IP address for the new DNS record.
|
||||
</Dialog.Text>
|
||||
<Form
|
||||
method="POST"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (!name || !ip) return;
|
||||
<Dialog.Panel
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (!name || !ip) return;
|
||||
|
||||
setName('');
|
||||
setIp('');
|
||||
|
||||
submit(
|
||||
{
|
||||
'dns.extra_records': [
|
||||
...records,
|
||||
{
|
||||
name,
|
||||
type: 'A',
|
||||
value: ip,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
method: 'PATCH',
|
||||
encType: 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
label="Domain"
|
||||
placeholder="test.example.com"
|
||||
name="domain"
|
||||
state={[name, setName]}
|
||||
className={cn('mt-2', isDuplicate && 'outline outline-red-500')}
|
||||
/>
|
||||
<TextField
|
||||
label="IP Address"
|
||||
placeholder="101.101.101.101"
|
||||
name="ip"
|
||||
state={[ip, setIp]}
|
||||
className={cn(isDuplicate && 'outline outline-red-500')}
|
||||
/>
|
||||
{isDuplicate ? (
|
||||
<p className="text-sm opacity-50">
|
||||
A record with the domain name <Code>{name}</Code> and IP
|
||||
address <Code>{ip}</Code> already exists.
|
||||
</p>
|
||||
) : undefined}
|
||||
<Dialog.Gutter>
|
||||
<Dialog.Action variant="cancel" onPress={close}>
|
||||
Cancel
|
||||
</Dialog.Action>
|
||||
<Dialog.Action
|
||||
variant="confirm"
|
||||
onPress={close}
|
||||
isDisabled={isDuplicate}
|
||||
>
|
||||
Add
|
||||
</Dialog.Action>
|
||||
</Dialog.Gutter>
|
||||
</Form>
|
||||
</>
|
||||
)}
|
||||
setName('');
|
||||
setIp('');
|
||||
submit(
|
||||
{
|
||||
'dns.extra_records': [
|
||||
...records,
|
||||
{
|
||||
name,
|
||||
type: 'A',
|
||||
value: ip,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
method: 'PATCH',
|
||||
encType: 'application/json',
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Dialog.Title>Add DNS record</Dialog.Title>
|
||||
<Dialog.Text>
|
||||
Enter the domain and IP address for the new DNS record.
|
||||
</Dialog.Text>
|
||||
<TextField
|
||||
isRequired
|
||||
label="Domain"
|
||||
placeholder="test.example.com"
|
||||
name="domain"
|
||||
state={[name, setName]}
|
||||
className={cn('mt-2', isDuplicate && 'outline outline-red-500')}
|
||||
/>
|
||||
<TextField
|
||||
isRequired
|
||||
label="IP Address"
|
||||
placeholder="101.101.101.101"
|
||||
name="ip"
|
||||
state={[ip, setIp]}
|
||||
className={cn(isDuplicate && 'outline outline-red-500')}
|
||||
/>
|
||||
{isDuplicate ? (
|
||||
<p className="text-sm opacity-50">
|
||||
A record with the domain name <Code>{name}</Code> and IP address{' '}
|
||||
<Code>{ip}</Code> already exists.
|
||||
</p>
|
||||
) : undefined}
|
||||
</Dialog.Panel>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RepoForkedIcon } from '@primer/octicons-react';
|
||||
import { Form, useSubmit } from 'react-router';
|
||||
import { useState } from 'react';
|
||||
import { useSubmit } from 'react-router';
|
||||
|
||||
import Dialog from '~/components/Dialog';
|
||||
import Switch from '~/components/Switch';
|
||||
@@ -21,135 +21,116 @@ export default function AddNameserver({ nameservers }: Props) {
|
||||
return (
|
||||
<Dialog>
|
||||
<Dialog.Button>Add nameserver</Dialog.Button>
|
||||
<Dialog.Panel>
|
||||
{(close) => (
|
||||
<>
|
||||
<Dialog.Title>Add nameserver</Dialog.Title>
|
||||
<Dialog.Text className="font-semibold">Nameserver</Dialog.Text>
|
||||
<Dialog.Panel
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (!ns) return;
|
||||
if (split) {
|
||||
const splitNs: Record<string, string[]> = {};
|
||||
for (const [key, value] of Object.entries(nameservers)) {
|
||||
if (key === 'global') continue;
|
||||
splitNs[key] = value;
|
||||
}
|
||||
|
||||
if (Object.keys(splitNs).includes(domain)) {
|
||||
splitNs[domain].push(ns);
|
||||
} else {
|
||||
splitNs[domain] = [ns];
|
||||
}
|
||||
|
||||
submit(
|
||||
{
|
||||
'dns.nameservers.split': splitNs,
|
||||
},
|
||||
{
|
||||
method: 'PATCH',
|
||||
encType: 'application/json',
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const globalNs = nameservers.global;
|
||||
globalNs.push(ns);
|
||||
|
||||
submit(
|
||||
{
|
||||
'dns.nameservers.global': globalNs,
|
||||
},
|
||||
{
|
||||
method: 'PATCH',
|
||||
encType: 'application/json',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
setNs('');
|
||||
setDomain('');
|
||||
setSplit(false);
|
||||
}}
|
||||
>
|
||||
<Dialog.Title>Add nameserver</Dialog.Title>
|
||||
<Dialog.Text className="font-semibold">Nameserver</Dialog.Text>
|
||||
<Dialog.Text className="text-sm">
|
||||
Use this IPv4 or IPv6 address to resolve names.
|
||||
</Dialog.Text>
|
||||
<TextField
|
||||
label="DNS Server"
|
||||
placeholder="1.2.3.4"
|
||||
name="ns"
|
||||
state={[ns, setNs]}
|
||||
className="mt-2 mb-8"
|
||||
/>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="block">
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<Dialog.Text className="font-semibold">
|
||||
Restrict to domain
|
||||
</Dialog.Text>
|
||||
<Tooltip>
|
||||
<Tooltip.Button
|
||||
className={cn(
|
||||
'text-xs rounded-md px-1.5 py-0.5',
|
||||
'bg-ui-200 dark:bg-ui-800',
|
||||
'text-ui-600 dark:text-ui-300',
|
||||
)}
|
||||
>
|
||||
<RepoForkedIcon className="w-4 h-4 mr-0.5" />
|
||||
Split DNS
|
||||
</Tooltip.Button>
|
||||
<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">
|
||||
Use this IPv4 or IPv6 address to resolve names.
|
||||
This nameserver will only be used for some domains.
|
||||
</Dialog.Text>
|
||||
</div>
|
||||
<Switch
|
||||
label="Split DNS"
|
||||
defaultSelected={split}
|
||||
onChange={() => {
|
||||
setSplit(!split);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{split ? (
|
||||
<>
|
||||
<Dialog.Text className="font-semibold mt-8">Domain</Dialog.Text>
|
||||
<TextField
|
||||
label="Domain"
|
||||
placeholder="example.com"
|
||||
name="domain"
|
||||
state={[domain, setDomain]}
|
||||
className="my-2"
|
||||
/>
|
||||
<Dialog.Text className="text-sm">
|
||||
Only single-label or fully-qualified queries matching this suffix
|
||||
should use the nameserver.
|
||||
</Dialog.Text>
|
||||
<Form
|
||||
method="POST"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (!ns) return;
|
||||
|
||||
if (split) {
|
||||
const splitNs: Record<string, string[]> = {};
|
||||
for (const [key, value] of Object.entries(nameservers)) {
|
||||
if (key === 'global') continue;
|
||||
splitNs[key] = value;
|
||||
}
|
||||
|
||||
if (Object.keys(splitNs).includes(domain)) {
|
||||
splitNs[domain].push(ns);
|
||||
} else {
|
||||
splitNs[domain] = [ns];
|
||||
}
|
||||
|
||||
submit(
|
||||
{
|
||||
'dns.nameservers.split': splitNs,
|
||||
},
|
||||
{
|
||||
method: 'PATCH',
|
||||
encType: 'application/json',
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const globalNs = nameservers.global;
|
||||
globalNs.push(ns);
|
||||
|
||||
submit(
|
||||
{
|
||||
'dns.nameservers.global': globalNs,
|
||||
},
|
||||
{
|
||||
method: 'PATCH',
|
||||
encType: 'application/json',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
setNs('');
|
||||
setDomain('');
|
||||
setSplit(false);
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
label="DNS Server"
|
||||
placeholder="1.2.3.4"
|
||||
name="ns"
|
||||
state={[ns, setNs]}
|
||||
className="mt-2 mb-8"
|
||||
/>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="block">
|
||||
<div className="inline-flex items-center gap-2">
|
||||
<Dialog.Text className="font-semibold">
|
||||
Restrict to domain
|
||||
</Dialog.Text>
|
||||
<Tooltip>
|
||||
<Tooltip.Button
|
||||
className={cn(
|
||||
'text-xs rounded-md px-1.5 py-0.5',
|
||||
'bg-ui-200 dark:bg-ui-800',
|
||||
'text-ui-600 dark:text-ui-300',
|
||||
)}
|
||||
>
|
||||
<RepoForkedIcon className="w-4 h-4 mr-0.5" />
|
||||
Split DNS
|
||||
</Tooltip.Button>
|
||||
<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"
|
||||
defaultSelected={split}
|
||||
onChange={() => {
|
||||
setSplit(!split);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{split ? (
|
||||
<>
|
||||
<Dialog.Text className="font-semibold mt-8">
|
||||
Domain
|
||||
</Dialog.Text>
|
||||
<TextField
|
||||
label="Domain"
|
||||
placeholder="example.com"
|
||||
name="domain"
|
||||
state={[domain, setDomain]}
|
||||
className="my-2"
|
||||
/>
|
||||
<Dialog.Text className="text-sm">
|
||||
Only single-label or fully-qualified queries matching this
|
||||
suffix should use the nameserver.
|
||||
</Dialog.Text>
|
||||
</>
|
||||
) : undefined}
|
||||
<Dialog.Gutter>
|
||||
<Dialog.Action variant="cancel" onPress={close}>
|
||||
Cancel
|
||||
</Dialog.Action>
|
||||
<Dialog.Action variant="confirm" onPress={close}>
|
||||
Add
|
||||
</Dialog.Action>
|
||||
</Dialog.Gutter>
|
||||
</Form>
|
||||
</>
|
||||
)}
|
||||
) : undefined}
|
||||
</Dialog.Panel>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user