mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-13 08:26:40 +00:00
Show/allow unicode domain name
This commit is contained in:
@@ -43,6 +43,7 @@ import {
|
||||
validateByDomainType,
|
||||
isValidSubdomainStructure
|
||||
} from "@/lib/subdomain-utils";
|
||||
import { toUnicode } from "punycode";
|
||||
|
||||
type OrganizationDomain = {
|
||||
domainId: string;
|
||||
@@ -126,6 +127,7 @@ export default function DomainPicker2({
|
||||
)
|
||||
.map((domain) => ({
|
||||
...domain,
|
||||
baseDomain: toUnicode(domain.baseDomain),
|
||||
type: domain.type as "ns" | "cname" | "wildcard"
|
||||
}));
|
||||
setOrganizationDomains(domains);
|
||||
@@ -406,6 +408,12 @@ export default function DomainPicker2({
|
||||
const hasMoreProvided =
|
||||
sortedAvailableOptions.length > providedDomainsShown;
|
||||
|
||||
|
||||
const isValidDomainCharacter = (char: string) => {
|
||||
// Allow Unicode letters, numbers, hyphens, and periods
|
||||
return /[\p{L}\p{N}.-]/u.test(char);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
@@ -424,8 +432,8 @@ export default function DomainPicker2({
|
||||
showProvidedDomainSearch
|
||||
? ""
|
||||
: showSubdomainInput
|
||||
? ""
|
||||
: t("domainPickerNotAvailableForCname")
|
||||
? ""
|
||||
: t("domainPickerNotAvailableForCname")
|
||||
}
|
||||
disabled={
|
||||
!showSubdomainInput && !showProvidedDomainSearch
|
||||
@@ -436,10 +444,16 @@ export default function DomainPicker2({
|
||||
"border-red-500 focus:border-red-500"
|
||||
)}
|
||||
onChange={(e) => {
|
||||
const rawInput = e.target.value;
|
||||
const validInput = rawInput
|
||||
.split("")
|
||||
.filter((char) => isValidDomainCharacter(char))
|
||||
.join("");
|
||||
|
||||
if (showProvidedDomainSearch) {
|
||||
handleProvidedDomainInputChange(e.target.value);
|
||||
handleProvidedDomainInputChange(validInput);
|
||||
} else {
|
||||
handleSubdomainChange(e.target.value);
|
||||
handleSubdomainChange(validInput);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -448,7 +462,6 @@ export default function DomainPicker2({
|
||||
This subdomain contains invalid characters or structure. It will be sanitized automatically when you save.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{showSubdomainInput && !subdomainInput && (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("domainPickerEnterSubdomainOrLeaveBlank")}
|
||||
@@ -474,7 +487,7 @@ export default function DomainPicker2({
|
||||
{selectedBaseDomain ? (
|
||||
<div className="flex items-center space-x-2 min-w-0 flex-1">
|
||||
{selectedBaseDomain.type ===
|
||||
"organization" ? null : (
|
||||
"organization" ? null : (
|
||||
<Zap className="h-4 w-4 flex-shrink-0" />
|
||||
)}
|
||||
<span className="truncate">
|
||||
@@ -568,67 +581,67 @@ export default function DomainPicker2({
|
||||
</CommandGroup>
|
||||
{(build === "saas" ||
|
||||
build === "enterprise") && (
|
||||
<CommandSeparator className="my-2" />
|
||||
)}
|
||||
<CommandSeparator className="my-2" />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{(build === "saas" ||
|
||||
build === "enterprise") && (
|
||||
<CommandGroup
|
||||
heading={
|
||||
build === "enterprise"
|
||||
? t(
|
||||
"domainPickerProvidedDomains"
|
||||
)
|
||||
: t("domainPickerFreeDomains")
|
||||
}
|
||||
className="py-2"
|
||||
>
|
||||
<CommandList>
|
||||
<CommandItem
|
||||
key="provided-search"
|
||||
onSelect={() =>
|
||||
handleBaseDomainSelect({
|
||||
id: "provided-search",
|
||||
domain:
|
||||
build ===
|
||||
"enterprise"
|
||||
<CommandGroup
|
||||
heading={
|
||||
build === "enterprise"
|
||||
? t(
|
||||
"domainPickerProvidedDomains"
|
||||
)
|
||||
: t("domainPickerFreeDomains")
|
||||
}
|
||||
className="py-2"
|
||||
>
|
||||
<CommandList>
|
||||
<CommandItem
|
||||
key="provided-search"
|
||||
onSelect={() =>
|
||||
handleBaseDomainSelect({
|
||||
id: "provided-search",
|
||||
domain:
|
||||
build ===
|
||||
"enterprise"
|
||||
? "Provided Domain"
|
||||
: "Free Provided Domain",
|
||||
type: "provided-search"
|
||||
})
|
||||
}
|
||||
className="mx-2 rounded-md"
|
||||
>
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-primary/10 mr-3">
|
||||
<Zap className="h-4 w-4 text-primary" />
|
||||
</div>
|
||||
<div className="flex flex-col flex-1 min-w-0">
|
||||
<span className="font-medium truncate">
|
||||
{build === "enterprise"
|
||||
? "Provided Domain"
|
||||
: "Free Provided Domain",
|
||||
type: "provided-search"
|
||||
})
|
||||
}
|
||||
className="mx-2 rounded-md"
|
||||
>
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-primary/10 mr-3">
|
||||
<Zap className="h-4 w-4 text-primary" />
|
||||
</div>
|
||||
<div className="flex flex-col flex-1 min-w-0">
|
||||
<span className="font-medium truncate">
|
||||
{build === "enterprise"
|
||||
? "Provided Domain"
|
||||
: "Free Provided Domain"}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{t(
|
||||
"domainPickerSearchForAvailableDomains"
|
||||
: "Free Provided Domain"}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{t(
|
||||
"domainPickerSearchForAvailableDomains"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<Check
|
||||
className={cn(
|
||||
"h-4 w-4 text-primary",
|
||||
selectedBaseDomain?.id ===
|
||||
"provided-search"
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<Check
|
||||
className={cn(
|
||||
"h-4 w-4 text-primary",
|
||||
selectedBaseDomain?.id ===
|
||||
"provided-search"
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
</CommandList>
|
||||
</CommandGroup>
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
</CommandList>
|
||||
</CommandGroup>
|
||||
)}
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
@@ -684,7 +697,7 @@ export default function DomainPicker2({
|
||||
htmlFor={option.domainNamespaceId}
|
||||
data-state={
|
||||
selectedProvidedDomain?.domainNamespaceId ===
|
||||
option.domainNamespaceId
|
||||
option.domainNamespaceId
|
||||
? "checked"
|
||||
: "unchecked"
|
||||
}
|
||||
@@ -764,4 +777,4 @@ function debounce<T extends (...args: any[]) => any>(
|
||||
func(...args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user