'use client'; import { useState, useEffect } from 'react'; import Link from 'next/link'; import AudioPlayer from './AudioPlayer'; import { getDatasetEntries } from '@/app/actions/get-dataset-entries'; import { getFilterOptions } from '@/app/actions/get-filter-options'; import { downloadFilteredEntriesAsZip } from '@/lib/download-utils'; interface DatasetEntriesListProps { datasetId: number; } interface DatasetEntry { id: number; datasetId: number; externalId: string; speakerId: string; modelName: string; utteranceId: string | null; utteranceText: string | null; fileName: string; dialect: string; iteration: number; durationMs: number | null; rmsValue: number | null; longestPause: number | null; utmosScore: number | null; werScore: number | null; createdAt: Date; updatedAt: Date; } interface FilterOptions { speakerIds: string[]; modelNames: string[]; dialects: string[]; iterations: number[]; utteranceIds: string[]; } export default function DatasetEntriesList({ datasetId, }: DatasetEntriesListProps) { const [entries, setEntries] = useState([]); const [loading, setLoading] = useState(false); const [downloading, setDownloading] = useState(false); const [hasMore, setHasMore] = useState(true); const [page, setPage] = useState(1); const [total, setTotal] = useState(0); // Filter states const [filters, setFilters] = useState({ speakerId: '', modelName: '', dialect: '', iteration: '', utteranceId: '', }); // Filter options const [filterOptions, setFilterOptions] = useState({ speakerIds: [], modelNames: [], dialects: [], iterations: [], utteranceIds: [], }); // Sort state const [sortBy, setSortBy] = useState('externalId'); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); // Load filter options on mount useEffect(() => { async function loadFilterOptions() { try { const options = await getFilterOptions(datasetId); setFilterOptions(options); } catch (error) { console.error('Error loading filter options:', error); } } loadFilterOptions(); }, [datasetId]); useEffect(() => { setPage(1); loadEntries(1); }, [filters, sortBy, sortOrder]); async function loadEntries(pageNum: number = page) { setLoading(true); try { const filterParams = { speakerId: filters.speakerId || undefined, modelName: filters.modelName || undefined, dialect: filters.dialect || undefined, iteration: filters.iteration ? parseInt(filters.iteration, 10) : undefined, utteranceId: filters.utteranceId || undefined, }; const sortParams = { sortBy: sortBy as keyof DatasetEntry, sortOrder: sortOrder, }; const result = await getDatasetEntries(datasetId, pageNum, filterParams, sortParams); if (pageNum === 1) { setEntries(result.entries); } else { setEntries((prev) => [...prev, ...result.entries]); } setHasMore(result.hasMore); setTotal(result.total); setPage(pageNum); } catch (error) { console.error('Error loading entries:', error); } finally { setLoading(false); } } async function handleLoadMore() { setLoading(true); try { const filterParams = { speakerId: filters.speakerId || undefined, modelName: filters.modelName || undefined, dialect: filters.dialect || undefined, iteration: filters.iteration ? parseInt(filters.iteration, 10) : undefined, utteranceId: filters.utteranceId || undefined, }; const sortParams = { sortBy: sortBy as keyof DatasetEntry, sortOrder: sortOrder, }; const result = await getDatasetEntries(datasetId, page + 1, filterParams, sortParams); setEntries((prev) => [...prev, ...result.entries]); setHasMore(result.hasMore); setTotal(result.total); setPage(page + 1); } catch (error) { console.error('Error loading more entries:', error); } finally { setLoading(false); } } function handleFilterChange(field: string, value: string) { setFilters((prev) => ({ ...prev, [field]: value, })); } function handleClearFilters() { setFilters({ speakerId: '', modelName: '', dialect: '', iteration: '', utteranceId: '', }); } function handleSort(column: keyof DatasetEntry) { if (sortBy === column) { // Toggle sort order if clicking the same column setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); } else { // Set new column to sort by, default to ascending setSortBy(column); setSortOrder('asc'); } } async function handleDownloadFiltered() { setDownloading(true); try { const filterParams = { speakerId: filters.speakerId || undefined, modelName: filters.modelName || undefined, dialect: filters.dialect || undefined, iteration: filters.iteration ? parseInt(filters.iteration, 10) : undefined, utteranceId: filters.utteranceId || undefined, }; await downloadFilteredEntriesAsZip(datasetId, filterParams); } catch (error) { console.error('Error downloading entries:', error); alert('Failed to download entries. Please try again.'); } finally { setDownloading(false); } } if (entries.length === 0 && !loading) { return (

Dataset Entries

{/* Filter Section */}

Filters

No entries found for this dataset.

); } return (

Dataset Entries

{/* Filter Section */}

Filters

{/* Results info */}
Found {total} {total === 1 ? 'entry' : 'entries'}
{/* Table */}
{entries.map((entry) => ( ))}
Play handleSort('externalId')}> External ID {sortBy === 'externalId' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('speakerId')}> Speaker ID {sortBy === 'speakerId' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('modelName')}> Model Name {sortBy === 'modelName' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('utteranceId')}> Utterance ID {sortBy === 'utteranceId' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('dialect')}> Dialect {sortBy === 'dialect' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('iteration')}> Iteration {sortBy === 'iteration' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('durationMs')}> Duration (ms) {sortBy === 'durationMs' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('rmsValue')}> RMS Value {sortBy === 'rmsValue' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('longestPause')}> Longest Pause (s) {sortBy === 'longestPause' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('utmosScore')}> UTMOS Score {sortBy === 'utmosScore' && (sortOrder === 'asc' ? '↑' : '↓')} handleSort('werScore')}> WER Score {sortBy === 'werScore' && (sortOrder === 'asc' ? '↑' : '↓')}
{entry.externalId} {entry.speakerId} {entry.modelName} {entry.utteranceId || '-'} {entry.dialect} {entry.iteration} {entry.durationMs?.toLocaleString() || '-'} {entry.rmsValue?.toFixed(3) || '-'} {entry.longestPause?.toFixed(3) || '-'} {entry.utmosScore?.toFixed(3) || '-'} {entry.werScore?.toFixed(3) || '-'}
{hasMore && (
Showing {entries.length} of {total} entries
)} {!hasMore && entries.length > 0 && (
All {total} entries loaded
)}
); }