visual improvements

This commit is contained in:
miloschwartz
2026-04-29 13:44:35 -07:00
parent d3870f4920
commit e173f59d89
3 changed files with 27 additions and 143 deletions

View File

@@ -453,6 +453,13 @@ export default function ClientResourcesTable({
return ( return (
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center gap-2 min-w-0">
<div className="">
<CopyToClipboard
text={url}
isLink={isSafeUrlForLink(url)}
displayText={url}
/>
</div>
{did ? ( {did ? (
<PrivateResourceCertAccessIndicator <PrivateResourceCertAccessIndicator
orgId={resourceRow.orgId} orgId={resourceRow.orgId}
@@ -460,13 +467,6 @@ export default function ClientResourcesTable({
fullDomain={fullDomain} fullDomain={fullDomain}
/> />
) : null} ) : null}
<div className="min-w-0 flex-1">
<CopyToClipboard
text={url}
isLink={isSafeUrlForLink(url)}
displayText={url}
/>
</div>
</div> </div>
); );
} }

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { Button } from "@app/components/ui/button"; import CertificateStatus from "@app/components/CertificateStatus";
import { import {
Popover, Popover,
PopoverAnchor, PopoverAnchor,
@@ -8,12 +8,7 @@ import {
} from "@app/components/ui/popover"; } from "@app/components/ui/popover";
import { useCertificate } from "@app/hooks/useCertificate"; import { useCertificate } from "@app/hooks/useCertificate";
import { cn } from "@app/lib/cn"; import { cn } from "@app/lib/cn";
import { import { CheckCircle2, Clock, XCircle } from "lucide-react";
CheckCircle2,
Clock,
RotateCw,
XCircle
} from "lucide-react";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
@@ -53,16 +48,6 @@ function getStatusIcon(status: string) {
} }
} }
function shouldShowRefreshButton(status: string, updatedAt: number) {
return (
status === "failed" ||
status === "expired" ||
(status === "requested" &&
updatedAt &&
new Date(updatedAt * 1000).getTime() < Date.now() - 5 * 60 * 1000)
);
}
export function PrivateResourceCertAccessIndicator({ export function PrivateResourceCertAccessIndicator({
orgId, orgId,
domainId, domainId,
@@ -72,13 +57,12 @@ export function PrivateResourceCertAccessIndicator({
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const { cert, certLoading, certError, refreshing, refreshCert } = const { cert, certLoading, certError } = useCertificate({
useCertificate({ orgId,
orgId, domainId,
domainId, fullDomain,
fullDomain, autoFetch: true
autoFetch: true });
});
const clearCloseTimer = useCallback(() => { const clearCloseTimer = useCallback(() => {
if (closeTimerRef.current != null) { if (closeTimerRef.current != null) {
@@ -101,10 +85,6 @@ export function PrivateResourceCertAccessIndicator({
return () => clearCloseTimer(); return () => clearCloseTimer();
}, [clearCloseTimer]); }, [clearCloseTimer]);
const handleRefresh = async () => {
await refreshCert();
};
if (certLoading) { if (certLoading) {
return ( return (
<div <div
@@ -115,9 +95,6 @@ export function PrivateResourceCertAccessIndicator({
); );
} }
const isPending = cert?.status === "pending";
const disableWildcard = cert?.domainType === "wildcard";
let TriggerIcon = Clock; let TriggerIcon = Clock;
let triggerIconClass = "text-muted-foreground"; let triggerIconClass = "text-muted-foreground";
if (certError) { if (certError) {
@@ -155,7 +132,7 @@ export function PrivateResourceCertAccessIndicator({
</button> </button>
</PopoverAnchor> </PopoverAnchor>
<PopoverContent <PopoverContent
className="w-72 space-y-3 p-4" className="w-72 p-4"
align="start" align="start"
side="bottom" side="bottom"
sideOffset={6} sideOffset={6}
@@ -163,106 +140,13 @@ export function PrivateResourceCertAccessIndicator({
onMouseLeave={scheduleClose} onMouseLeave={scheduleClose}
onOpenAutoFocus={(e) => e.preventDefault()} onOpenAutoFocus={(e) => e.preventDefault()}
> >
<div className="space-y-2"> <CertificateStatus
<div className="text-sm font-medium text-muted-foreground"> orgId={orgId}
{t("certificateStatus")} domainId={domainId}
</div> fullDomain={fullDomain}
{certError ? ( autoFetch
<span className="inline-flex items-center gap-1.5 text-sm"> showLabel
<XCircle className="h-4 w-4 shrink-0 text-red-500" /> />
{certError}
</span>
) : !cert ? (
<span className="inline-flex items-center gap-1.5 text-sm">
<Clock className="h-4 w-4 shrink-0 text-muted-foreground" />
{t("none", { defaultValue: "None" })}
</span>
) : (
<>
{isPending && !disableWildcard ? (
<Button
variant="ghost"
className="h-auto p-0 text-sm font-normal"
onClick={handleRefresh}
disabled={refreshing}
title={t("restartCertificate", {
defaultValue: "Restart Certificate"
})}
>
<span className="inline-flex items-center gap-2">
{(() => {
const StatusIcon = getStatusIcon(
cert.status
);
return (
<StatusIcon
className={`h-4 w-4 shrink-0 ${getStatusColor(cert.status)}`}
/>
);
})()}
{cert.status.charAt(0).toUpperCase() +
cert.status.slice(1)}
<RotateCw
className={`h-3 w-3 ${refreshing ? "animate-spin" : ""}`}
/>
</span>
</Button>
) : (
<span className="text-sm">
<span className="inline-flex items-center gap-2">
{(() => {
const StatusIcon = getStatusIcon(
cert.status
);
return (
<StatusIcon
className={`h-4 w-4 shrink-0 ${getStatusColor(cert.status)}`}
/>
);
})()}
{cert.status.charAt(0).toUpperCase() +
cert.status.slice(1)}
{shouldShowRefreshButton(
cert.status,
cert.updatedAt
) && !disableWildcard ? (
<Button
size="icon"
variant="ghost"
className="p-0 w-3 h-auto align-middle"
onClick={handleRefresh}
disabled={refreshing}
title={t("restartCertificate", {
defaultValue:
"Restart Certificate"
})}
>
<RotateCw
className={`w-3 h-3 ${refreshing ? "animate-spin" : ""}`}
/>
</Button>
) : null}
</span>
</span>
)}
{cert.errorMessage &&
(cert.status === "failed" ||
cert.status === "expired") ? (
<p className="text-xs text-muted-foreground break-all">
{cert.errorMessage}
</p>
) : null}
{cert.expiresAt && cert.status === "valid" ? (
<p className="text-xs text-muted-foreground">
{t("expiresAt")}:{" "}
{new Date(
cert.expiresAt
).toLocaleDateString()}
</p>
) : null}
</>
)}
</div>
</PopoverContent> </PopoverContent>
</Popover> </Popover>
); );

View File

@@ -52,7 +52,7 @@ function aggregateStatusDotClass(status: AggregateSitesStatus): string {
return "bg-neutral-500"; return "bg-neutral-500";
case "unknown": case "unknown":
default: default:
return "bg-transparent"; return "border border-muted-foreground/50 bg-transparent";
} }
} }
@@ -107,10 +107,10 @@ export function ResourceSitesStatusCell({
className={cn( className={cn(
"h-2 w-2 shrink-0 rounded-full", "h-2 w-2 shrink-0 rounded-full",
!hasKnownStatus !hasKnownStatus
? "bg-transparent" ? "border border-muted-foreground/50 bg-transparent"
: isOnline : isOnline
? "bg-green-500" ? "bg-green-500"
: "bg-neutral-500" : "bg-neutral-500"
)} )}
/> />
<span className="truncate"> <span className="truncate">