'use client'; import Link from 'next/link'; import { useMemo, useState } from 'react'; import { useMutation } from '@tanstack/react-query'; import { Eye, Plus, Trash2 } from 'lucide-react'; import { toast } from 'sonner'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { Button } from '@/components/ui/button'; import { EmptyStateWithBorder } from '@/components/layout/empty'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; import { ZoneDomainService, type ProxyRouteItem, type TlsCertificateItem, type ZoneDomainItem, } from '@/lib/services/openflare'; import { useTranslations } from 'next-intl'; import { getUpstreamLabels } from '../../../proxy-routes/components/helpers'; import { ZoneDomainDialog } from './zone-domain-dialog'; export function ZoneDomainsTable({ zoneId, zoneRoot, domains, certificates, routes, routesLoading = false, onChanged, }: { zoneId: number; zoneRoot: string; domains: ZoneDomainItem[]; certificates: TlsCertificateItem[]; routes: ProxyRouteItem[]; routesLoading?: boolean; onChanged(): Promise | void; }) { const t = useTranslations('websites'); const tc = useTranslations('common'); const tp = useTranslations('proxyRoutes'); const [createOpen, setCreateOpen] = useState(false); const [deleting, setDeleting] = useState(null); const remove = useMutation({ mutationFn: (id: number) => ZoneDomainService.deleteById(zoneId, id), onSuccess: async () => { toast.success(t('domainDeleted')); setDeleting(null); await onChanged(); }, onError: (error) => toast.error(error instanceof Error ? error.message : t('deleteFailed')), }); const certificateMap = useMemo( () => new Map(certificates.map((certificate) => [certificate.id, certificate])), [certificates], ); const routeMap = useMemo( () => new Map(routes.map((route) => [route.id, route])), [routes], ); return ( <>
{domains.length === 0 ? ( ) : (
FQDN {t('certificate')} {t('upstream')} {t('actions')} {domains.map((domain) => { const route = domain.proxy_route_id != null ? routeMap.get(domain.proxy_route_id) : undefined; const upstreams = route ? getUpstreamLabels(route, tp) : []; const certLabel = domain.cert_id ? (certificateMap.get(domain.cert_id)?.name ?? t('certNumber', { id: domain.cert_id })) : t('unbound'); return ( {domain.domain} {certLabel} {!domain.proxy_route_id ? ( {t('unlinkedRoute')} ) : routesLoading && !route ? ( {t('loadingEllipsis')} ) : upstreams.length === 0 ? ( {t('upstreamUnset')} ) : (
{upstreams.map((upstream) => ( {upstream} ))}
)}
event.stopPropagation()} >
{domain.proxy_route_id ? ( {t('viewRoute')} ) : null} {t('deleteDomain')}
); })}
)} { if (!open) { setDeleting(null); } }} > {t('deleteDomainTitle')} {t('deleteDomainDesc', { domain: deleting?.domain ?? '' })} {tc('cancel')} { event.preventDefault(); if (deleting) { remove.mutate(deleting.id); } }} > {remove.isPending ? t('deleting') : t('confirmDelete')} ); }