Add custom dns domain (#458)

* Update domain validator

* Add custom dns domain
This commit is contained in:
Eduard Gert
2025-04-28 11:58:16 +02:00
committed by GitHub
parent 6c0ab88488
commit ebbe865ce0
2 changed files with 118 additions and 27 deletions

View File

@@ -14,5 +14,6 @@ export interface Account {
jwt_allow_groups: string[]; jwt_allow_groups: string[];
regular_users_view_blocked: boolean; regular_users_view_blocked: boolean;
routing_peer_dns_resolution_enabled: boolean; routing_peer_dns_resolution_enabled: boolean;
dns_domain: string;
}; };
} }

View File

@@ -1,10 +1,18 @@
import Breadcrumbs from "@components/Breadcrumbs"; import Breadcrumbs from "@components/Breadcrumbs";
import Button from "@components/Button";
import FancyToggleSwitch from "@components/FancyToggleSwitch"; import FancyToggleSwitch from "@components/FancyToggleSwitch";
import HelpText from "@components/HelpText";
import InlineLink from "@components/InlineLink";
import { Input } from "@components/Input";
import { Label } from "@components/Label";
import { notify } from "@components/Notification"; import { notify } from "@components/Notification";
import { useHasChanges } from "@hooks/useHasChanges";
import * as Tabs from "@radix-ui/react-tabs"; import * as Tabs from "@radix-ui/react-tabs";
import { useApiCall } from "@utils/api"; import { useApiCall } from "@utils/api";
import { GlobeIcon, NetworkIcon } from "lucide-react"; import { validator } from "@utils/helpers";
import React, { useState } from "react"; import { isNetBirdHosted } from "@utils/netbird";
import { ExternalLinkIcon, GlobeIcon, NetworkIcon } from "lucide-react";
import React, { useMemo, useState } from "react";
import { useSWRConfig } from "swr"; import { useSWRConfig } from "swr";
import SettingsIcon from "@/assets/icons/SettingsIcon"; import SettingsIcon from "@/assets/icons/SettingsIcon";
import { Account } from "@/interfaces/Account"; import { Account } from "@/interfaces/Account";
@@ -13,18 +21,23 @@ type Props = {
account: Account; account: Account;
}; };
export default function NetworkSettingsTab({ account }: Props) { export default function NetworkSettingsTab({ account }: Readonly<Props>) {
const { mutate } = useSWRConfig(); const { mutate } = useSWRConfig();
const saveRequest = useApiCall<Account>("/accounts/" + account.id); const saveRequest = useApiCall<Account>("/accounts/" + account.id, true);
const [routingPeerDNSSetting, setRoutingPeerDNSSetting] = useState( const [routingPeerDNSSetting, setRoutingPeerDNSSetting] = useState(
account.settings.routing_peer_dns_resolution_enabled, account.settings.routing_peer_dns_resolution_enabled,
); );
const [customDNSDomain, setCustomDNSDomain] = useState(
account.settings.dns_domain || "",
);
const toggleSetting = async (toggle: boolean) => { const toggleNetworkDNSSetting = async (toggle: boolean) => {
notify({ notify({
title: "Save Network Settings", title: "DNS Wildcard Routing",
description: "Network settings successfully saved.", description: `DNS Wildcard Routing successfully ${
toggle ? "enabled" : "disabled"
}.`,
promise: saveRequest promise: saveRequest
.put({ .put({
id: account.id, id: account.id,
@@ -37,10 +50,43 @@ export default function NetworkSettingsTab({ account }: Props) {
setRoutingPeerDNSSetting(toggle); setRoutingPeerDNSSetting(toggle);
mutate("/accounts"); mutate("/accounts");
}), }),
loadingMessage: "Saving the network settings...", loadingMessage: "Updating DNS wildcard setting...",
}); });
}; };
const { hasChanges, updateRef } = useHasChanges([customDNSDomain]);
const saveChanges = async () => {
notify({
title: "Custom DNS Domain",
description: `Custom DNS Domain successfully updated.`,
promise: saveRequest
.put({
id: account.id,
settings: {
...account.settings,
dns_domain: customDNSDomain || "",
},
})
.then(() => {
mutate("/accounts");
updateRef([customDNSDomain]);
}),
loadingMessage: "Updating Custom DNS domain...",
});
};
const domainError = useMemo(() => {
if (customDNSDomain == "") return "";
const valid = validator.isValidDomain(customDNSDomain, {
allowWildcard: false,
allowOnlyTld: false,
});
if (!valid) {
return "Please enter a valid domain, e.g. example.com or intra.example.com";
}
}, [customDNSDomain]);
return ( return (
<Tabs.Content value={"networks"}> <Tabs.Content value={"networks"}>
<div className={"p-default py-6 max-w-2xl"}> <div className={"p-default py-6 max-w-2xl"}>
@@ -51,21 +97,57 @@ export default function NetworkSettingsTab({ account }: Props) {
icon={<SettingsIcon size={13} />} icon={<SettingsIcon size={13} />}
/> />
<Breadcrumbs.Item <Breadcrumbs.Item
href={"/settings#network"} href={"/settings?tab=networks"}
label={"Network"} label={"Networks"}
icon={<NetworkIcon size={14} />} icon={<NetworkIcon size={14} />}
active active
/> />
</Breadcrumbs> </Breadcrumbs>
<div className={"flex items-start justify-between"}> <div className={"flex items-start justify-between"}>
<div>
<h1>Networks</h1> <h1>Networks</h1>
</div> </div>
<Button
variant={"primary"}
disabled={!hasChanges}
onClick={saveChanges}
>
Save Changes
</Button>
</div>
<div className={"flex flex-col gap-6 w-full mt-8"}> <div className={"flex flex-col gap-6 w-full mt-8"}>
<div> <div>
<div
className={
"flex flex-col gap-1 sm:flex-row w-full sm:gap-4 items-center"
}
>
<div className={"min-w-[330px]"}>
<Label>DNS Domain</Label>
<HelpText>
Specify a custom DNS domain for your network. This will be
used for all your peers.
</HelpText>
</div>
<div className={"w-full"}>
<Input
placeholder={
isNetBirdHosted() ? "netbird.cloud" : "netbird.selfhosted"
}
errorTooltip={true}
errorTooltipPosition={"top"}
error={domainError}
value={customDNSDomain}
onChange={(e) => setCustomDNSDomain(e.target.value)}
/>
</div>
</div>
</div>
<FancyToggleSwitch <FancyToggleSwitch
value={routingPeerDNSSetting} value={routingPeerDNSSetting}
onChange={toggleSetting} onChange={toggleNetworkDNSSetting}
label={ label={
<> <>
<GlobeIcon size={15} /> <GlobeIcon size={15} />
@@ -74,15 +156,23 @@ export default function NetworkSettingsTab({ account }: Props) {
} }
helpText={ helpText={
<> <>
Allow routing using DNS wildcards. This requires NetBird Allow routing using DNS wildcards. This requires NetBird client
client v0.35 or higher. Changes will only take effect after v0.35 or higher. Changes will only take effect after restarting
restarting the clients. the clients.{" "}
<InlineLink
href={
"https://docs.netbird.io/how-to/accessing-entire-domains-within-networks#enabling-dns-wildcard-routing"
}
target={"_blank"}
>
Learn more
<ExternalLinkIcon size={12} />
</InlineLink>
</> </>
} }
/> />
</div> </div>
</div> </div>
</div>
</Tabs.Content> </Tabs.Content>
); );
} }