mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-12 21:56:36 +00:00
Add alert about domain error
This commit is contained in:
@@ -2681,5 +2681,6 @@
|
|||||||
"approvalsEmptyStateStep2Title": "Enable Device Approvals",
|
"approvalsEmptyStateStep2Title": "Enable Device Approvals",
|
||||||
"approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
|
"approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
|
||||||
"approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
|
"approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
|
||||||
"approvalsEmptyStateButtonText": "Manage Roles"
|
"approvalsEmptyStateButtonText": "Manage Roles",
|
||||||
|
"domainErrorTitle": "We are having trouble verifying your domain"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export const domains = pgTable("domains", {
|
|||||||
tries: integer("tries").notNull().default(0),
|
tries: integer("tries").notNull().default(0),
|
||||||
certResolver: varchar("certResolver"),
|
certResolver: varchar("certResolver"),
|
||||||
customCertResolver: varchar("customCertResolver"),
|
customCertResolver: varchar("customCertResolver"),
|
||||||
preferWildcardCert: boolean("preferWildcardCert")
|
preferWildcardCert: boolean("preferWildcardCert"),
|
||||||
|
errorMessage: text("errorMessage")
|
||||||
});
|
});
|
||||||
|
|
||||||
export const dnsRecords = pgTable("dnsRecords", {
|
export const dnsRecords = pgTable("dnsRecords", {
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ export const domains = sqliteTable("domains", {
|
|||||||
failed: integer("failed", { mode: "boolean" }).notNull().default(false),
|
failed: integer("failed", { mode: "boolean" }).notNull().default(false),
|
||||||
tries: integer("tries").notNull().default(0),
|
tries: integer("tries").notNull().default(0),
|
||||||
certResolver: text("certResolver"),
|
certResolver: text("certResolver"),
|
||||||
preferWildcardCert: integer("preferWildcardCert", { mode: "boolean" })
|
preferWildcardCert: integer("preferWildcardCert", { mode: "boolean" }),
|
||||||
|
errorMessage: text("errorMessage")
|
||||||
});
|
});
|
||||||
|
|
||||||
export const dnsRecords = sqliteTable("dnsRecords", {
|
export const dnsRecords = sqliteTable("dnsRecords", {
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ async function queryDomains(orgId: string, limit: number, offset: number) {
|
|||||||
tries: domains.tries,
|
tries: domains.tries,
|
||||||
configManaged: domains.configManaged,
|
configManaged: domains.configManaged,
|
||||||
certResolver: domains.certResolver,
|
certResolver: domains.certResolver,
|
||||||
preferWildcardCert: domains.preferWildcardCert
|
preferWildcardCert: domains.preferWildcardCert,
|
||||||
|
errorMessage: domains.errorMessage
|
||||||
})
|
})
|
||||||
.from(orgDomains)
|
.from(orgDomains)
|
||||||
.where(eq(orgDomains.orgId, orgId))
|
.where(eq(orgDomains.orgId, orgId))
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export default async function DomainSettingsPage({
|
|||||||
failed={domain.failed}
|
failed={domain.failed}
|
||||||
verified={domain.verified}
|
verified={domain.verified}
|
||||||
type={domain.type}
|
type={domain.type}
|
||||||
|
errorMessage={domain.errorMessage}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DNSRecordsTable records={dnsRecords} type={domain.type} />
|
<DNSRecordsTable records={dnsRecords} type={domain.type} />
|
||||||
|
|||||||
@@ -10,17 +10,20 @@ import {
|
|||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { Badge } from "./ui/badge";
|
import { Badge } from "./ui/badge";
|
||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
|
import { AlertTriangle } from "lucide-react";
|
||||||
|
|
||||||
type DomainInfoCardProps = {
|
type DomainInfoCardProps = {
|
||||||
failed: boolean;
|
failed: boolean;
|
||||||
verified: boolean;
|
verified: boolean;
|
||||||
type: string | null;
|
type: string | null;
|
||||||
|
errorMessage?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DomainInfoCard({
|
export default function DomainInfoCard({
|
||||||
failed,
|
failed,
|
||||||
verified,
|
verified,
|
||||||
type
|
type,
|
||||||
|
errorMessage
|
||||||
}: DomainInfoCardProps) {
|
}: DomainInfoCardProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const env = useEnvContext();
|
const env = useEnvContext();
|
||||||
@@ -39,6 +42,7 @@ export default function DomainInfoCard({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className="space-y-3">
|
||||||
<Alert>
|
<Alert>
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
<InfoSections cols={3}>
|
<InfoSections cols={3}>
|
||||||
@@ -79,5 +83,19 @@ export default function DomainInfoCard({
|
|||||||
</InfoSections>
|
</InfoSections>
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
{errorMessage && (failed || !verified) && (
|
||||||
|
<Alert variant={failed ? "destructive" : "warning"}>
|
||||||
|
<AlertTriangle className="h-4 w-4" />
|
||||||
|
<AlertTitle>
|
||||||
|
{failed
|
||||||
|
? t("domainErrorTitle", { fallback: "Domain Error" })
|
||||||
|
: t("domainPendingErrorTitle", { fallback: "Verification Issue" })}
|
||||||
|
</AlertTitle>
|
||||||
|
<AlertDescription className="font-mono text-xs break-all">
|
||||||
|
{errorMessage}
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from "./ui/dropdown-menu";
|
} from "./ui/dropdown-menu";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger
|
||||||
|
} from "./ui/tooltip";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
export type DomainRow = {
|
export type DomainRow = {
|
||||||
@@ -39,6 +45,7 @@ export type DomainRow = {
|
|||||||
configManaged: boolean;
|
configManaged: boolean;
|
||||||
certResolver: string;
|
certResolver: string;
|
||||||
preferWildcardCert: boolean;
|
preferWildcardCert: boolean;
|
||||||
|
errorMessage?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -175,7 +182,7 @@ export default function DomainsTable({ domains, orgId }: Props) {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const { verified, failed, type } = row.original;
|
const { verified, failed, type, errorMessage } = row.original;
|
||||||
if (verified) {
|
if (verified) {
|
||||||
return type == "wildcard" ? (
|
return type == "wildcard" ? (
|
||||||
<Badge variant="outlinePrimary">{t("manual")}</Badge>
|
<Badge variant="outlinePrimary">{t("manual")}</Badge>
|
||||||
@@ -183,12 +190,44 @@ export default function DomainsTable({ domains, orgId }: Props) {
|
|||||||
<Badge variant="green">{t("verified")}</Badge>
|
<Badge variant="green">{t("verified")}</Badge>
|
||||||
);
|
);
|
||||||
} else if (failed) {
|
} else if (failed) {
|
||||||
|
if (errorMessage) {
|
||||||
|
return (
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Badge variant="red" className="cursor-help">
|
||||||
|
{t("failed", { fallback: "Failed" })}
|
||||||
|
</Badge>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent className="max-w-xs">
|
||||||
|
<p className="break-words">{errorMessage}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Badge variant="red">
|
<Badge variant="red">
|
||||||
{t("failed", { fallback: "Failed" })}
|
{t("failed", { fallback: "Failed" })}
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
if (errorMessage) {
|
||||||
|
return (
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Badge variant="yellow" className="cursor-help">
|
||||||
|
{t("pending")}
|
||||||
|
</Badge>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent className="max-w-xs">
|
||||||
|
<p className="break-words">{errorMessage}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
return <Badge variant="yellow">{t("pending")}</Badge>;
|
return <Badge variant="yellow">{t("pending")}</Badge>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user