add cert status to redirects

This commit is contained in:
miloschwartz
2026-10-20 16:19:51 -04:00
parent 1e675f824b
commit 4688e56d9f
4 changed files with 86 additions and 7 deletions
@@ -5,6 +5,7 @@ import type { SelectedResource } from "@app/components/resource-selector";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
import { GetDomainResponse } from "@server/routers/domain/getDomain";
import type { ListRedirectsResponse } from "@server/routers/redirect";
import { GetResourceResponse } from "@server/routers/resource/getResource";
@@ -127,6 +128,50 @@ export default async function RedirectIndexPage(props: RedirectIndexPageProps) {
baseDomain: redirect.baseDomain
}));
// Prefetched in one batched call so the table doesn't fire a separate
// certificate request per visible row once it mounts on the client.
const certDomains = Array.from(
new Set(
redirectRows
.map((redirect) => {
if (redirect.resourceId) {
if (
redirect.resourceSsl &&
redirect.resourceFullDomain
) {
return redirect.resourceFullDomain;
}
return null;
}
if (!redirect.ssl || !redirect.baseDomain) {
return null;
}
return [redirect.subdomain, redirect.baseDomain]
.filter(Boolean)
.join(".");
})
.filter((domain): domain is string => Boolean(domain))
)
);
let initialCertificates: GetBatchedCertificateResponse | undefined;
if (certDomains.length > 0) {
try {
const certSearchParams = new URLSearchParams(
certDomains.map((domain) => ["domains", domain])
);
const certRes = await internal.get<
AxiosResponse<GetBatchedCertificateResponse>
>(
`/org/${orgId}/batched-certificates?${certSearchParams.toString()}`,
header
);
initialCertificates = certRes.data.data;
} catch {
// leave undefined so each row falls back to fetching its own
}
}
return (
<>
<SettingsSectionTitle
@@ -144,6 +189,7 @@ export default async function RedirectIndexPage(props: RedirectIndexPageProps) {
}}
initialFilterResource={initialFilterResource}
initialFilterDomain={initialFilterDomain}
initialCertificates={initialCertificates}
/>
</>
);
@@ -6,7 +6,6 @@ import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import { getCachedOrg } from "@app/lib/api/getCachedOrg";
import OrgProvider from "@app/providers/OrgProvider";
import { build } from "@server/build";
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
import type { ListAllSiteResourcesByOrgResponse } from "@server/routers/siteResource";
import type { AxiosResponse } from "axios";
@@ -120,7 +119,7 @@ export default async function ClientResourcesPage(
);
let initialCertificates: GetBatchedCertificateResponse | undefined;
if (build !== "oss" && certDomains.length > 0) {
if (certDomains.length > 0) {
try {
const certSearchParams = new URLSearchParams(
certDomains.map((domain) => ["domains", domain])
@@ -5,7 +5,6 @@ import PublicResourcesBanner from "@app/components/PublicResourcesBanner";
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import OrgProvider from "@app/providers/OrgProvider";
import { build } from "@server/build";
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
import type { GetOrgResponse } from "@server/routers/org";
import type { ListResourcesResponse } from "@server/routers/resource";
@@ -132,7 +131,7 @@ export default async function ProxyResourcesPage(
);
let initialCertificates: GetBatchedCertificateResponse | undefined;
if (build !== "oss" && certDomains.length > 0) {
if (certDomains.length > 0) {
try {
const certSearchParams = new URLSearchParams(
certDomains.map((domain) => ["domains", domain])
+38 -3
View File
@@ -2,6 +2,7 @@
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
import CopyToClipboard from "@app/components/CopyToClipboard";
import { ResourceAccessCertIndicator } from "@app/components/ResourceAccessCertIndicator";
import {
ResourceSelector,
type SelectedResource
@@ -40,6 +41,7 @@ import { cn } from "@app/lib/cn";
import { dataTableFilterPopoverContentClassName } from "@app/lib/dataTableFilterPopover";
import { orgQueries } from "@app/lib/queries";
import { getNextSortOrder, getSortDirection } from "@app/lib/sortColumn";
import type { GetBatchedCertificateResponse } from "@server/routers/certificates/types";
import { useQuery } from "@tanstack/react-query";
import type { PaginationState } from "@tanstack/react-table";
import {
@@ -113,6 +115,8 @@ type RedirectsTableProps = {
rowCount: number;
initialFilterResource?: SelectedResource | null;
initialFilterDomain?: RedirectFilterDomain | null;
/** Certificates prefetched on the server, keyed by full domain. */
initialCertificates?: GetBatchedCertificateResponse;
};
export default function RedirectsTable({
@@ -121,7 +125,8 @@ export default function RedirectsTable({
pagination,
rowCount,
initialFilterResource = null,
initialFilterDomain = null
initialFilterDomain = null,
initialCertificates
}: RedirectsTableProps) {
const router = useRouter();
const t = useTranslations();
@@ -460,7 +465,36 @@ export default function RedirectsTable({
return <span>-</span>;
}
return <CopyToClipboard text={source} isLink={false} />;
const certDomainId = redirect.resourceId
? redirect.resourceDomainId
: redirect.domainId;
const certHostname = redirect.resourceId
? redirect.resourceFullDomain
: domainHost;
const showHttpsCertIndicator =
sourceSsl &&
certHostname != null &&
certHostname !== "" &&
certDomainId != null &&
certDomainId !== "";
return (
<div className="flex items-center gap-2 min-w-0">
{showHttpsCertIndicator ? (
<ResourceAccessCertIndicator
orgId={orgId}
domainId={certDomainId}
fullDomain={certHostname}
initialCertValue={
initialCertificates?.[certHostname]
}
/>
) : null}
<div className="">
<CopyToClipboard text={source} isLink={false} />
</div>
</div>
);
}
},
{
@@ -647,7 +681,8 @@ export default function RedirectsTable({
domainFilterOpen,
resourceFilterOpen,
selectedDomain,
selectedResource
selectedResource,
initialCertificates
]
);