"use client"; import type { DatasetDisplayInfo, EpisodeLengthStats, CameraInfo, } from "@/app/[org]/[dataset]/[episode]/fetch-data"; interface StatsPanelProps { datasetInfo: DatasetDisplayInfo; episodeLengthStats: EpisodeLengthStats | null; loading: boolean; } function formatTotalTime(totalFrames: number, fps: number): string { const totalSec = totalFrames / fps; const hours = Math.floor(totalSec / 3600); const minutes = Math.floor((totalSec % 3600) / 60); if (hours > 0) return `${hours}h ${minutes}m`; return `${minutes}m`; } /** SVG bar chart for the episode-length histogram */ function EpisodeLengthHistogram({ data, }: { data: { binLabel: string; count: number }[]; }) { if (data.length === 0) return null; const maxCount = Math.max(...data.map((d) => d.count)); if (maxCount === 0) return null; const totalWidth = 560; const gap = Math.max(1, Math.min(3, Math.floor(60 / data.length))); const barWidth = Math.max( 4, Math.floor((totalWidth - gap * data.length) / data.length), ); const chartHeight = 150; const labelHeight = 30; const topPad = 16; const svgWidth = data.length * (barWidth + gap); const labelStep = Math.max(1, Math.ceil(data.length / 10)); return (
{data.map((bin, i) => { const barH = Math.max(1, (bin.count / maxCount) * chartHeight); const x = i * (barWidth + gap); const y = topPad + chartHeight - barH; return ( {`${bin.binLabel}: ${bin.count} episode${bin.count !== 1 ? "s" : ""}`} {bin.count > 0 && barWidth >= 8 && ( {bin.count} )} ); })} {data.map((bin, idx) => { const isFirst = idx === 0; const isLast = idx === data.length - 1; if (!isFirst && !isLast && idx % labelStep !== 0) return null; const label = bin.binLabel.split("–")[0]; return ( {label}s ); })}
); } function Card({ label, value }: { label: string; value: string | number }) { return (

{label}

{value}

); } function StatsPanel({ datasetInfo, episodeLengthStats, loading, }: StatsPanelProps) { const els = episodeLengthStats; return (

Dataset Statistics:{" "} {datasetInfo.repoId}

{/* Overview cards */}
{/* Camera resolutions */} {datasetInfo.cameras.length > 0 && (

Camera Resolutions

{datasetInfo.cameras.map((cam: CameraInfo) => (

{cam.name}

{cam.width}×{cam.height}

))}
)} {/* Loading spinner for async stats */} {loading && (
Computing episode statistics…
)} {/* Episode length section */} {els && ( <>

Episode Lengths

{els.episodeLengthHistogram.length > 0 && (

Episode Length Distribution {els.episodeLengthHistogram.length} bin {els.episodeLengthHistogram.length !== 1 ? "s" : ""}

)} )}
); } export default StatsPanel;