import { useMemo, useState } from 'react'; import type { JobTimings } from '../types/api'; import { useI18n } from '../i18n'; function formatDuration(ms: number): string { if (ms >= 1000) { return `${(ms / 1000).toFixed(1)}s`; } return `${Math.round(ms)}ms`; } interface TimingPanelProps { timings?: JobTimings; submittedAt?: string | null; finishedAt?: string | null; } export function TimingPanel({ timings, submittedAt, finishedAt }: TimingPanelProps) { const { t } = useI18n(); const [isOpen, setIsOpen] = useState(false); const { total, items } = useMemo(() => { const timingLabels: Array<{ key: keyof JobTimings; label: string }> = [ { key: 'analyze', label: t('timing.analyze') }, { key: 'edit', label: t('timing.edit') }, { key: 'retry', label: t('timing.retry') }, { key: 'render', label: t('timing.render') }, { key: 'store', label: t('timing.store') }, ]; const items = timingLabels .map(({ key, label }) => ({ key, label, value: timings?.[key] })) .filter((item) => typeof item.value === 'number'); const submittedMs = submittedAt ? Date.parse(submittedAt) : Number.NaN; const finishedMs = finishedAt ? Date.parse(finishedAt) : Number.NaN; const endToEndTotal = Number.isFinite(submittedMs) && Number.isFinite(finishedMs) ? Math.max(0, finishedMs - submittedMs) : undefined; const total = typeof endToEndTotal === 'number' ? endToEndTotal : typeof timings?.total === 'number' ? timings.total : items.reduce((sum, item) => sum + (item.value || 0), 0); return { total, items }; }, [finishedAt, submittedAt, t, timings]); if (!items.length && !Number.isFinite(total)) { return null; } return (