initial comment
This commit is contained in:
202
pagination-replacement.js
Normal file
202
pagination-replacement.js
Normal file
@@ -0,0 +1,202 @@
|
||||
// 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 = '<tr><td colspan="8" style="text-align: center; padding: 40px; color: #64748b;">No files found</td></tr>';
|
||||
} 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 += `
|
||||
<tr class="${rowClass}" data-file-id="${file.id}" style="border-bottom: 1px solid #334155; transition: all 0.2s ease;">
|
||||
<td style="padding: 12px; text-align: center;">
|
||||
<input type="checkbox" class="file-checkbox" data-file-id="${file.id}"
|
||||
onchange="toggleFileSelection(${file.id})"
|
||||
${disableCheckbox} ${isChecked}
|
||||
style="cursor: ${file.state === 'processing' ? 'not-allowed' : 'pointer'}; transform: scale(1.2);">
|
||||
</td>
|
||||
<td style="padding: 12px; max-width: 400px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${escapedPathAttr}">
|
||||
<span style="font-weight: 500;">${escapedPath}</span>
|
||||
</td>
|
||||
<td style="padding: 12px;">
|
||||
<span style="background: ${stateBadgeColors[file.state] || '#64748b'}; padding: 6px 12px; border-radius: 6px; font-size: 0.85em; cursor: help; font-weight: 600;"
|
||||
title="${escapedTooltip}">
|
||||
${escapedState}
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding: 12px; color: #94a3b8;">-</td>
|
||||
<td style="padding: 12px; font-weight: 500;">${file.original_size ? formatBytes(file.original_size) : '-'}</td>
|
||||
<td style="padding: 12px; font-weight: 500;">${file.encoded_size ? formatBytes(file.encoded_size) : '-'}</td>
|
||||
<td style="padding: 12px; font-weight: 600; color: ${savings !== '-' && parseFloat(savings) > 0 ? '#10b981' : '#64748b'};">
|
||||
${savings !== '-' ? escapeHtml(savings) + '%' : '-'}
|
||||
</td>
|
||||
<td style="padding: 12px; font-size: 1.2em;">${statusIcon}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
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 = '<tr><td colspan="8" style="text-align: center; padding: 40px; color: #ef4444;">Error loading files</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
function updatePaginationControls() {
|
||||
const paginationContainer = document.getElementById('paginationControls');
|
||||
if (!paginationContainer) return;
|
||||
|
||||
const startFile = (currentPage - 1) * filesPerPage + 1;
|
||||
const endFile = currentPage * filesPerPage;
|
||||
|
||||
let html = `
|
||||
<div style="display: flex; align-items: center; justify-content: center; gap: 15px; padding: 20px;">
|
||||
<button class="btn" onclick="goToPage(${currentPage - 1})" ${currentPage === 1 ? 'disabled' : ''}
|
||||
style="background: #3b82f6; color: white; ${currentPage === 1 ? 'opacity: 0.5; cursor: not-allowed;' : ''}">
|
||||
← Previous
|
||||
</button>
|
||||
|
||||
<div style="color: #94a3b8; font-weight: 500;">
|
||||
Page ${currentPage} | Showing ${startFile}-${endFile}
|
||||
</div>
|
||||
|
||||
<button class="btn" onclick="goToPage(${currentPage + 1})"
|
||||
style="background: #3b82f6; color: white;">
|
||||
Next →
|
||||
</button>
|
||||
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<label style="color: #94a3b8;">Go to page:</label>
|
||||
<input type="number" id="pageInput" min="1" value="${currentPage}"
|
||||
style="width: 80px; padding: 8px; border-radius: 6px; background: #1e293b; color: #e2e8f0; border: 1px solid #334155; text-align: center;"
|
||||
onkeypress="if(event.key==='Enter') goToPageInput()">
|
||||
<button class="btn" onclick="goToPageInput()" style="background: #10b981; color: white;">Go</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user