Removes more Wild Cloud cruft.

This commit is contained in:
2026-07-11 23:21:23 +00:00
parent ac66ba653d
commit 5d8fe6a754
21 changed files with 196 additions and 1391 deletions

View File

@@ -154,7 +154,7 @@ function MobileControls({
{hasCert ? (
<>
<CheckCircle className="h-3.5 w-3.5 text-green-500" />
<span>TLS: {cert!.coveredBy ? `*.${cert!.domain}` : cert!.domain}</span>
<span>TLS: {(cert!.cert.wildcard || cert!.coveredBy) ? `*.${cert!.domain}` : cert!.domain}</span>
{cert!.cert.daysLeft != null && <span className="text-muted-foreground">({cert!.cert.daysLeft}d)</span>}
</>
) : (

View File

@@ -7,7 +7,7 @@ import {
import '@xyflow/react/dist/style.css';
import {
Globe, Wifi, Lock, Shield, ShieldAlert, Router,
AlertCircle, Loader2, Plus, RotateCw, Pencil,
AlertCircle, Loader2, Plus, RotateCw,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
@@ -57,6 +57,68 @@ export interface DomainTopologyProps {
const handleStyle = { opacity: 0, width: 4, height: 4 };
function BackendNode({ data, leftHandle, rightHandle, bottomHandle }: {
data: Record<string, unknown>;
leftHandle: React.ReactNode;
rightHandle: React.ReactNode;
bottomHandle: React.ReactNode;
}) {
const onChangeBackend = data.onChangeBackend as ((addr: string) => void) | undefined;
const hasRoutes = data.hasRoutes as boolean;
const editable = !!onChangeBackend && !hasRoutes;
const [editing, setEditing] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const handleSave = () => {
const val = inputRef.current?.value.trim();
if (val && onChangeBackend) onChangeBackend(val);
setEditing(false);
};
return (
<>
{leftHandle}
<TopologyNode
label={editing ? '' : (data.label as string)}
sublabel={editing ? undefined : (data.sublabel as string | undefined)}
status="ok"
className="font-mono"
interactive={editable && !editing}
onClick={editable && !editing ? () => setEditing(true) : undefined}
tooltip={editable && !editing ? 'Click to edit backend address' : undefined}
>
{editing && (
<div className="nopan nodrag" style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()}>
<Input
ref={inputRef}
defaultValue={data.label as string}
className="h-5 text-[10px] font-mono px-1.5"
autoFocus
onKeyDown={e => {
if (e.key === 'Enter') handleSave();
if (e.key === 'Escape') setEditing(false);
}}
/>
<div className="flex gap-1 mt-1">
<Button variant="ghost" size="sm" className="h-4 text-[9px] px-1 flex-1 !cursor-pointer"
style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()} onClick={handleSave}>
Save
</Button>
<Button variant="ghost" size="sm" className="h-4 text-[9px] px-1 flex-1 !cursor-pointer"
style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()} onClick={() => setEditing(false)}>
Cancel
</Button>
</div>
</div>
)}
</TopologyNode>
{rightHandle}
{bottomHandle}
</>
);
}
function FlowNode({ data }: NodeProps) {
const v = data.variant as string;
@@ -172,6 +234,7 @@ function FlowNode({ data }: NodeProps) {
if (v === 'tls') {
const status = data.status as NodeStatus;
const certDomain = data.certDomain as string | undefined;
const isWildcard = data.isWildcardCert as boolean;
const daysLeft = data.daysLeft as number;
const hasCert = data.hasCert as boolean;
const provisionDomain = data.provisionDomain as string;
@@ -192,7 +255,7 @@ function FlowNode({ data }: NodeProps) {
tooltip={
hasCert ? (
<div className="space-y-1">
<div>Certificate: {certDomain}</div>
<div>Certificate: {certDomain} ({isWildcard ? 'wildcard' : 'single domain'})</div>
<div>Expires: {expiry ?? 'unknown'} ({daysLeft}d)</div>
{issuer && <div>Issuer: {issuer}</div>}
</div>
@@ -230,63 +293,7 @@ function FlowNode({ data }: NodeProps) {
}
if (v === 'backend') {
const onChangeBackend = data.onChangeBackend as ((addr: string) => void) | undefined;
const hasRoutes = data.hasRoutes as boolean;
const editable = !!onChangeBackend && !hasRoutes;
const [editing, setEditing] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const handleSave = () => {
const val = inputRef.current?.value.trim();
if (val && onChangeBackend) onChangeBackend(val);
setEditing(false);
};
return (
<>
{leftHandle}
<TopologyNode
label={data.label as string}
sublabel={data.sublabel as string | undefined}
status="ok"
className="font-mono"
interactive={editable && !editing}
onClick={editable ? () => setEditing(true) : undefined}
tooltip={editable ? 'Click to edit backend address' : undefined}
>
{editable && !editing && (
<Pencil className="absolute top-1.5 right-1.5 h-2.5 w-2.5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" />
)}
{editing && (
<div className="mt-1.5 nopan nodrag" style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()}>
<Input
ref={inputRef}
defaultValue={data.label as string}
className="h-5 text-[10px] font-mono px-1.5"
autoFocus
onKeyDown={e => {
if (e.key === 'Enter') handleSave();
if (e.key === 'Escape') setEditing(false);
}}
/>
<div className="flex gap-1 mt-1">
<Button variant="ghost" size="sm" className="h-4 text-[9px] px-1 flex-1 !cursor-pointer"
style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()} onClick={handleSave}>
Save
</Button>
<Button variant="ghost" size="sm" className="h-4 text-[9px] px-1 flex-1 !cursor-pointer"
style={{ pointerEvents: 'all' }} onPointerDown={e => e.stopPropagation()} onClick={() => setEditing(false)}>
Cancel
</Button>
</div>
</div>
)}
</TopologyNode>
{rightHandle}
{bottomHandle}
</>
);
return <BackendNode data={data} leftHandle={leftHandle} rightHandle={rightHandle} bottomHandle={bottomHandle} />;
}
if (v === 'lan') {
@@ -474,7 +481,8 @@ export function DomainTopology(props: DomainTopologyProps) {
// TLS
const hasCert = !!cert?.cert.exists;
const tlsStatus: NodeStatus = hasCert ? 'ok' : 'error';
const certDomain = hasCert ? (cert!.coveredBy ? `*.${cert!.domain}` : cert!.domain) : undefined;
const isWildcardCert = !!(cert?.cert.wildcard || cert?.coveredBy);
const certDomain = hasCert ? (isWildcardCert ? `*.${cert!.domain}` : cert!.domain) : undefined;
const daysLeft = cert?.cert.daysLeft ?? 0;
const provisionDomain = domain.subdomains ? `*.${domain.domain}` : domain.domain;
@@ -556,7 +564,7 @@ export function DomainTopology(props: DomainTopologyProps) {
id: 'tls', type: 'topology',
position: { x: tlsX, y: pipelineY },
data: {
variant: 'tls', status: tlsStatus, certDomain, daysLeft, hasCert, provisionDomain,
variant: 'tls', status: tlsStatus, certDomain, isWildcardCert, daysLeft, hasCert, provisionDomain,
expiry: cert?.cert.expiry ? new Date(cert.cert.expiry).toLocaleDateString() : undefined,
issuer: cert?.cert.issuerCN,
isProvisioningCert, isRenewingCert, onProvisionCert, onRenewCert,

View File

@@ -57,18 +57,20 @@ export const TopologyNode = forwardRef<HTMLDivElement, TopologyNodeProps>(
className,
)}
>
<div className="flex items-center gap-2">
{icon && <span className="shrink-0 text-muted-foreground">{icon}</span>}
<div className="min-w-0 flex-1">
<div className="flex items-center gap-1.5">
<span className={cn('h-1.5 w-1.5 rounded-full shrink-0', statusDotColors[status])} />
<span className="font-medium truncate">{label}</span>
{label && (
<div className="flex items-center gap-2">
{icon && <span className="shrink-0 text-muted-foreground">{icon}</span>}
<div className="min-w-0 flex-1">
<div className="flex items-center gap-1.5">
<span className={cn('h-1.5 w-1.5 rounded-full shrink-0', statusDotColors[status])} />
<span className="font-medium truncate">{label}</span>
</div>
{sublabel && (
<div className="text-[10px] text-muted-foreground mt-0.5 truncate">{sublabel}</div>
)}
</div>
{sublabel && (
<div className="text-[10px] text-muted-foreground mt-0.5 truncate">{sublabel}</div>
)}
</div>
</div>
)}
{children}
</div>
);