'use client'; import { useTranslations } from 'next-intl'; import { useState } from 'react'; import { Badge } from '@/components/ui/badge'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import type { AccessLogItem } from '@/lib/services/openflare'; import { formatDateTime } from '@/lib/utils'; import { formatBytes } from '@/lib/utils/metrics'; import { cacheOutcomeLabel, resolveCacheOutcome } from './access-log-utils'; function DetailField({ label, value, mono, full, }: { label: string; value: React.ReactNode; mono?: boolean; full?: boolean; }) { return (

{label}

{value}
); } function formatRequestTimeMs(value: number | undefined | null) { if (value == null || !Number.isFinite(value) || value < 0) { return '—'; } if (value < 1000) { return `${Math.round(value)} ms`; } return `${(value / 1000).toFixed(2)} s`; } export function AccessLogDetailDialog({ open, item, onOpenChange, }: { open: boolean; item: AccessLogItem | null; onOpenChange: (open: boolean) => void; }) { const t = useTranslations('accessLogs'); // Keep last selected item while the dialog closes to avoid empty-state flash. const [displayItem, setDisplayItem] = useState(item); if (item && item !== displayItem) { setDisplayItem(item); } const activeItem = item ?? displayItem; return ( {t('detail.title')} {t('detail.description')} {activeItem ? (
{activeItem.status_code} } /> {cacheOutcomeLabel( resolveCacheOutcome(activeItem.cache_status), (key) => t(key), )} {activeItem.cache_status || '—'}
} /> ) : null}
); }