// PAGINATION REPLACEMENT CODE FOR dashboard.html // Replace lines 1439-1625 with this code // File Quality Analysis with Pagination let selectedFiles = new Set(); let currentAttributeFilter = null; // Track the current attribute filter let currentStatusFilter = 'all'; // Track the current status filter let currentPage = 1; let totalPages = 1; let filesPerPage = 100; let totalFiles = 0; async function loadFileQuality() { const tbody = document.getElementById('qualityTableBody'); // Clear selections when reloading (not when paginating) // selectedFiles stays intact during pagination try { // Calculate offset from current page const offset = (currentPage - 1) * filesPerPage; // Build URL with state filter and attribute filter let url = `/api/files?limit=${filesPerPage}&offset=${offset}`; if (currentStatusFilter !== 'all') { url += `&state=${currentStatusFilter}`; } if (currentAttributeFilter && currentAttributeFilter !== 'all') { url += `&filter=${currentAttributeFilter}`; } const response = await fetch(url); const result = await response.json(); if (result.success) { const files = result.data; let html = ''; if (files.length === 0 && currentPage === 1) { html = 'No files found'; } else { files.forEach(file => { const savings = file.original_size && file.encoded_size ? ((file.original_size - file.encoded_size) / file.original_size * 100).toFixed(1) : '-'; const stateBadgeColors = { 'discovered': '#8b5cf6', 'pending': '#fbbf24', 'processing': '#3b82f6', 'completed': '#10b981', 'failed': '#ef4444', 'skipped': '#94a3b8' }; const statusIcon = file.state === 'completed' ? '✅' : file.state === 'failed' ? '❌' : file.state === 'processing' ? '⏳' : file.state === 'skipped' ? '⏭️' : '⏸️'; const disableCheckbox = file.state === 'processing' ? 'disabled' : ''; // Create tooltip for state badge let stateTooltip = ''; if (file.state === 'discovered') { stateTooltip = 'Discovered - select to encode'; } else if (file.state === 'pending') { stateTooltip = 'Selected - will encode when you click Encode Selected'; } else if (file.state === 'processing') { stateTooltip = 'Currently encoding...'; } else if (file.state === 'completed' && file.encoder_used) { stateTooltip = `Completed with ${file.encoder_used}`; } else if (file.state === 'failed' && file.error_message) { stateTooltip = `Failed: ${file.error_message}`; } else if (file.state === 'skipped' && file.error_message) { stateTooltip = `Skipped: ${file.error_message}`; } const rowClass = file.state === 'processing' ? 'row-processing' : ''; // Escape all user-controlled content const escapedPath = escapeHtml(file.relative_path); const escapedPathAttr = escapeAttr(file.relative_path); const escapedState = escapeHtml(file.state); const escapedTooltip = escapeAttr(stateTooltip); // Check if this file is selected const isChecked = selectedFiles.has(file.id) ? 'checked' : ''; html += ` ${escapedPath} ${escapedState} - ${file.original_size ? formatBytes(file.original_size) : '-'} ${file.encoded_size ? formatBytes(file.encoded_size) : '-'} ${savings !== '-' ? escapeHtml(savings) + '%' : '-'} ${statusIcon} `; }); } tbody.innerHTML = html; // Update pagination controls // Calculate total pages (estimate based on if we got less than limit) if (files.length < filesPerPage) { totalPages = currentPage; } else { // We don't know total, just enable next totalPages = currentPage + 1; } updatePaginationControls(); document.getElementById('selectAll').checked = false; } } catch (error) { console.error('Failed to load file quality:', error); tbody.innerHTML = 'Error loading files'; } } function updatePaginationControls() { const paginationContainer = document.getElementById('paginationControls'); if (!paginationContainer) return; const startFile = (currentPage - 1) * filesPerPage + 1; const endFile = currentPage * filesPerPage; let html = `
Page ${currentPage} | Showing ${startFile}-${endFile}
`; paginationContainer.innerHTML = html; } function goToPage(page) { if (page < 1) return; currentPage = page; loadFileQuality(); } function goToPageInput() { const input = document.getElementById('pageInput'); const page = parseInt(input.value); if (page && page > 0) { goToPage(page); } } function changeStatusFilter(status) { currentStatusFilter = status; currentPage = 1; // Reset to first page selectedFiles.clear(); // Clear selections when changing filter loadFileQuality(); } function toggleFileSelection(fileId) { if (selectedFiles.has(fileId)) { selectedFiles.delete(fileId); } else { selectedFiles.add(fileId); } updateSelectedCount(); }