mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-12 16:06:38 +00:00
Various fixes for rc
This commit is contained in:
@@ -10,7 +10,16 @@ import {
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useDomainContext } from "@app/hooks/useDomainContext";
|
||||
import { SettingsContainer, SettingsSection, SettingsSectionBody, SettingsSectionDescription, SettingsSectionFooter, SettingsSectionForm, SettingsSectionHeader, SettingsSectionTitle } from "./Settings";
|
||||
import {
|
||||
SettingsContainer,
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionFooter,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionHeader,
|
||||
SettingsSectionTitle
|
||||
} from "./Settings";
|
||||
import { Button } from "./ui/button";
|
||||
import {
|
||||
Form,
|
||||
@@ -21,7 +30,13 @@ import {
|
||||
FormMessage,
|
||||
FormDescription
|
||||
} from "@app/components/ui/form";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from "./ui/select";
|
||||
import { Input } from "./ui/input";
|
||||
import { useForm } from "react-hook-form";
|
||||
import z from "zod";
|
||||
@@ -51,7 +66,6 @@ function toPunycode(domain: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isValidDomainFormat(domain: string): boolean {
|
||||
const unicodeRegex = /^(?!:\/\/)([^\s.]+\.)*[^\s.]+$/;
|
||||
|
||||
@@ -59,9 +73,9 @@ function isValidDomainFormat(domain: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parts = domain.split('.');
|
||||
const parts = domain.split(".");
|
||||
for (const part of parts) {
|
||||
if (part.length === 0 || part.startsWith('-') || part.endsWith('-')) {
|
||||
if (part.length === 0 || part.startsWith("-") || part.endsWith("-")) {
|
||||
return false;
|
||||
}
|
||||
if (part.length > 63) {
|
||||
@@ -94,8 +108,10 @@ const certResolverOptions = [
|
||||
{ id: "custom", title: "Custom Resolver" }
|
||||
];
|
||||
|
||||
|
||||
export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps) {
|
||||
export default function DomainInfoCard({
|
||||
orgId,
|
||||
domainId
|
||||
}: DomainInfoCardProps) {
|
||||
const { domain, updateDomain } = useDomainContext();
|
||||
const t = useTranslations();
|
||||
const { env } = useEnvContext();
|
||||
@@ -111,21 +127,24 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
baseDomain: "",
|
||||
type: build == "oss" || !env.flags.usePangolinDns ? "wildcard" : "ns",
|
||||
certResolver: domain.certResolver ?? "",
|
||||
type:
|
||||
build == "oss" || !env.flags.usePangolinDns ? "wildcard" : "ns",
|
||||
certResolver: domain.certResolver,
|
||||
preferWildcardCert: false
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (domain.domainId) {
|
||||
const certResolverValue = domain.certResolver && domain.certResolver.trim() !== ""
|
||||
? domain.certResolver
|
||||
: null;
|
||||
const certResolverValue =
|
||||
domain.certResolver && domain.certResolver.trim() !== ""
|
||||
? domain.certResolver
|
||||
: null;
|
||||
|
||||
form.reset({
|
||||
baseDomain: domain.baseDomain || "",
|
||||
type: (domain.type as "ns" | "cname" | "wildcard") || "wildcard",
|
||||
type:
|
||||
(domain.type as "ns" | "cname" | "wildcard") || "wildcard",
|
||||
certResolver: certResolverValue,
|
||||
preferWildcardCert: domain.preferWildcardCert || false
|
||||
});
|
||||
@@ -170,7 +189,9 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
if (!orgId || !domainId) {
|
||||
toast({
|
||||
title: t("error"),
|
||||
description: t("orgOrDomainIdMissing", { fallback: "Organization or Domain ID is missing" }),
|
||||
description: t("orgOrDomainIdMissing", {
|
||||
fallback: "Organization or Domain ID is missing"
|
||||
}),
|
||||
variant: "destructive"
|
||||
});
|
||||
return;
|
||||
@@ -179,7 +200,11 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
setSaveLoading(true);
|
||||
|
||||
try {
|
||||
const response = await api.patch(
|
||||
if (!values.certResolver) {
|
||||
values.certResolver = null;
|
||||
}
|
||||
|
||||
await api.patch(
|
||||
`/org/${orgId}/domain/${domainId}`,
|
||||
{
|
||||
certResolver: values.certResolver,
|
||||
@@ -195,7 +220,9 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
|
||||
toast({
|
||||
title: t("success"),
|
||||
description: t("domainSettingsUpdated", { fallback: "Domain settings updated successfully" }),
|
||||
description: t("domainSettingsUpdated", {
|
||||
fallback: "Domain settings updated successfully"
|
||||
}),
|
||||
variant: "default"
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -222,30 +249,36 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
<InfoSections cols={3}>
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("type")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionTitle>{t("type")}</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
<span>
|
||||
{getTypeDisplay(domain.type ? domain.type : "")}
|
||||
{getTypeDisplay(
|
||||
domain.type ? domain.type : ""
|
||||
)}
|
||||
</span>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
<InfoSection>
|
||||
<InfoSectionTitle>
|
||||
{t("status")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionTitle>{t("status")}</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{domain.verified ? (
|
||||
<Badge variant="green">{t("verified")}</Badge>
|
||||
domain.type === "wildcard" ? (
|
||||
<Badge variant="outlinePrimary">
|
||||
{t("manual", {
|
||||
fallback: "Manual"
|
||||
})}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="green">
|
||||
{t("verified")}
|
||||
</Badge>
|
||||
)
|
||||
) : (
|
||||
<Badge variant="yellow">
|
||||
{t("pending", { fallback: "Pending" })}
|
||||
@@ -257,20 +290,13 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
{loadingRecords ? (
|
||||
<div className="space-y-4">
|
||||
{t("loadingDNSRecords", { fallback: "Loading DNS Records..." })}
|
||||
</div>
|
||||
) : (
|
||||
<DNSRecordsTable
|
||||
domainId={domain.domainId}
|
||||
records={dnsRecords}
|
||||
isRefreshing={isRefreshing}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<DNSRecordsTable
|
||||
domainId={domain.domainId}
|
||||
records={dnsRecords}
|
||||
isRefreshing={isRefreshing}
|
||||
type={domain.type}
|
||||
/>
|
||||
|
||||
{/* Domain Settings - Only show for wildcard domains */}
|
||||
{domain.type === "wildcard" && (
|
||||
<SettingsContainer>
|
||||
<SettingsSection>
|
||||
@@ -294,33 +320,73 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
name="certResolver"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("certResolver")}</FormLabel>
|
||||
<FormLabel>
|
||||
{t("certResolver")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Select
|
||||
value={
|
||||
field.value === null ? "default" :
|
||||
(field.value === "" || (field.value && field.value !== "default")) ? "custom" :
|
||||
"default"
|
||||
field.value ===
|
||||
null
|
||||
? "default"
|
||||
: field.value ===
|
||||
"" ||
|
||||
(field.value &&
|
||||
field.value !==
|
||||
"default")
|
||||
? "custom"
|
||||
: "default"
|
||||
}
|
||||
onValueChange={(val) => {
|
||||
if (val === "default") {
|
||||
field.onChange(null);
|
||||
} else if (val === "custom") {
|
||||
field.onChange("");
|
||||
onValueChange={(
|
||||
val
|
||||
) => {
|
||||
if (
|
||||
val ===
|
||||
"default"
|
||||
) {
|
||||
field.onChange(
|
||||
null
|
||||
);
|
||||
} else if (
|
||||
val ===
|
||||
"custom"
|
||||
) {
|
||||
field.onChange(
|
||||
""
|
||||
);
|
||||
} else {
|
||||
field.onChange(val);
|
||||
field.onChange(
|
||||
val
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("selectCertResolver")} />
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"selectCertResolver"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{certResolverOptions.map((opt) => (
|
||||
<SelectItem key={opt.id} value={opt.id}>
|
||||
{opt.title}
|
||||
</SelectItem>
|
||||
))}
|
||||
{certResolverOptions.map(
|
||||
(
|
||||
opt
|
||||
) => (
|
||||
<SelectItem
|
||||
key={
|
||||
opt.id
|
||||
}
|
||||
value={
|
||||
opt.id
|
||||
}
|
||||
>
|
||||
{
|
||||
opt.title
|
||||
}
|
||||
</SelectItem>
|
||||
)
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
@@ -328,8 +394,10 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{form.watch("certResolver") !== null &&
|
||||
form.watch("certResolver") !== "default" && (
|
||||
{form.watch("certResolver") !==
|
||||
null &&
|
||||
form.watch("certResolver") !==
|
||||
"default" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="certResolver"
|
||||
@@ -337,9 +405,22 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder={t("enterCustomResolver")}
|
||||
value={field.value || ""}
|
||||
onChange={(e) => field.onChange(e.target.value)}
|
||||
placeholder={t(
|
||||
"enterCustomResolver"
|
||||
)}
|
||||
value={
|
||||
field.value ||
|
||||
""
|
||||
}
|
||||
onChange={(
|
||||
e
|
||||
) =>
|
||||
field.onChange(
|
||||
e
|
||||
.target
|
||||
.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -348,25 +429,39 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
/>
|
||||
)}
|
||||
|
||||
{form.watch("certResolver") !== null &&
|
||||
form.watch("certResolver") !== "default" && (
|
||||
{form.watch("certResolver") !==
|
||||
null &&
|
||||
form.watch("certResolver") !==
|
||||
"default" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="preferWildcardCert"
|
||||
render={({ field: switchField }) => (
|
||||
render={({
|
||||
field: switchField
|
||||
}) => (
|
||||
<FormItem className="items-center space-y-2 mt-4">
|
||||
<FormControl>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch
|
||||
checked={switchField.value}
|
||||
onCheckedChange={switchField.onChange}
|
||||
checked={
|
||||
switchField.value
|
||||
}
|
||||
onCheckedChange={
|
||||
switchField.onChange
|
||||
}
|
||||
/>
|
||||
<FormLabel>{t("preferWildcardCert")}</FormLabel>
|
||||
<FormLabel>
|
||||
{t(
|
||||
"preferWildcardCert"
|
||||
)}
|
||||
</FormLabel>
|
||||
</div>
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
{t("preferWildcardCertDescription")}
|
||||
{t(
|
||||
"preferWildcardCertDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -394,4 +489,4 @@ export default function DomainInfoCard({ orgId, domainId }: DomainInfoCardProps)
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user