feat: implement dashboard pagination

This commit is contained in:
Joan
2026-01-26 18:14:05 +01:00
parent b062b15797
commit 2a9e9888d4
3 changed files with 1409 additions and 10 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -117,6 +117,7 @@
<tbody id="jobTableBody">
</tbody>
</table>
<div id="paginationControls" class="mt-3"></div>
</div>
</div>
@@ -307,10 +308,21 @@
setInterval(checkStatus, 5000);
checkStatus();
async function loadJobs() {
// Pagination state
let currentPage = 1;
let limit = 10;
async function loadJobs(page = 1) {
try {
const res = await fetch('/api/jobs');
const jobs = await res.json();
const res = await fetch(`/api/jobs?page=${page}&limit=${limit}`);
const data = await res.json();
// Handle both legacy (array) and new (object) format gracefully
const jobs = Array.isArray(data) ? data : (data.jobs || []);
const totalPages = data.total_pages || 1;
currentPage = data.page || 1;
const tbody = document.getElementById('jobTableBody');
tbody.innerHTML = '';
@@ -319,6 +331,8 @@
if(job.status === 'completed') badgeClass = 'success';
else if(job.status === 'processing' || job.status === 'calling') badgeClass = 'warning';
else if(job.status === 'failed') badgeClass = 'danger';
else if(job.status === 'rejected') badgeClass = 'dark';
else if(job.status === 'no_answer') badgeClass = 'warning text-dark';
let statusHtml = `<span class="badge bg-${badgeClass}">${job.status}</span>`;
@@ -357,13 +371,40 @@
tbody.appendChild(tr);
});
renderPagination(currentPage, totalPages);
} catch(e) {
console.error("Failed to load jobs", e);
}
}
// Poll every 2 seconds
setInterval(loadJobs, 2000);
function renderPagination(current, total) {
const container = document.getElementById('paginationControls');
if (!container) return; // Should be added to HTML
container.innerHTML = `
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
<li class="page-item ${current <= 1 ? 'disabled' : ''}">
<button class="page-link" onclick="changePage(${current - 1})">Previous</button>
</li>
<li class="page-item disabled">
<span class="page-link">Page ${current} of ${Math.max(1, total)}</span>
</li>
<li class="page-item ${current >= total ? 'disabled' : ''}">
<button class="page-link" onclick="changePage(${current + 1})">Next</button>
</li>
</ul>
</nav>
`;
}
function changePage(newPage) {
loadJobs(newPage);
}
// Poll every 5 seconds (slower poll for pagination)
setInterval(() => loadJobs(currentPage), 5000);
loadJobs();
document.getElementById('testVoiceBtn').addEventListener('click', async () => {

View File

@@ -42,12 +42,18 @@ if ($method === 'POST' && $uri === '/api/queue') {
exit;
}
// API: Jobs History
// API: Jobs History (Paginated)
if ($method === 'GET' && $uri === '/api/jobs') {
// Get last 50 jobs
$ids = $redis->lrange('job_history', 0, 49);
$jobs = [];
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = isset($_GET['limit']) ? max(1, min(100, (int)$_GET['limit'])) : 20;
$start = ($page - 1) * $limit;
$end = $start + $limit - 1;
$total = $redis->llen('job_history');
$ids = $redis->lrange('job_history', $start, $end);
$jobs = [];
foreach ($ids as $id) {
$job = $redis->hgetall("job:$id");
if ($job) {
@@ -55,7 +61,13 @@ if ($method === 'GET' && $uri === '/api/jobs') {
}
}
echo json_encode($jobs);
echo json_encode([
'jobs' => $jobs,
'total' => $total,
'page' => $page,
'limit' => $limit,
'total_pages' => ceil($total / $limit)
]);
exit;
}