feat: implement dashboard pagination
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -117,6 +117,7 @@
|
|||||||
<tbody id="jobTableBody">
|
<tbody id="jobTableBody">
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div id="paginationControls" class="mt-3"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -307,10 +308,21 @@
|
|||||||
setInterval(checkStatus, 5000);
|
setInterval(checkStatus, 5000);
|
||||||
checkStatus();
|
checkStatus();
|
||||||
|
|
||||||
async function loadJobs() {
|
|
||||||
|
// Pagination state
|
||||||
|
let currentPage = 1;
|
||||||
|
let limit = 10;
|
||||||
|
|
||||||
|
async function loadJobs(page = 1) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/jobs');
|
const res = await fetch(`/api/jobs?page=${page}&limit=${limit}`);
|
||||||
const jobs = await res.json();
|
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');
|
const tbody = document.getElementById('jobTableBody');
|
||||||
tbody.innerHTML = '';
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
@@ -319,6 +331,8 @@
|
|||||||
if(job.status === 'completed') badgeClass = 'success';
|
if(job.status === 'completed') badgeClass = 'success';
|
||||||
else if(job.status === 'processing' || job.status === 'calling') badgeClass = 'warning';
|
else if(job.status === 'processing' || job.status === 'calling') badgeClass = 'warning';
|
||||||
else if(job.status === 'failed') badgeClass = 'danger';
|
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>`;
|
let statusHtml = `<span class="badge bg-${badgeClass}">${job.status}</span>`;
|
||||||
|
|
||||||
@@ -357,13 +371,40 @@
|
|||||||
tbody.appendChild(tr);
|
tbody.appendChild(tr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
renderPagination(currentPage, totalPages);
|
||||||
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error("Failed to load jobs", e);
|
console.error("Failed to load jobs", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll every 2 seconds
|
function renderPagination(current, total) {
|
||||||
setInterval(loadJobs, 2000);
|
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();
|
loadJobs();
|
||||||
|
|
||||||
document.getElementById('testVoiceBtn').addEventListener('click', async () => {
|
document.getElementById('testVoiceBtn').addEventListener('click', async () => {
|
||||||
|
|||||||
@@ -42,12 +42,18 @@ if ($method === 'POST' && $uri === '/api/queue') {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// API: Jobs History
|
// API: Jobs History (Paginated)
|
||||||
if ($method === 'GET' && $uri === '/api/jobs') {
|
if ($method === 'GET' && $uri === '/api/jobs') {
|
||||||
// Get last 50 jobs
|
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
|
||||||
$ids = $redis->lrange('job_history', 0, 49);
|
$limit = isset($_GET['limit']) ? max(1, min(100, (int)$_GET['limit'])) : 20;
|
||||||
$jobs = [];
|
|
||||||
|
|
||||||
|
$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) {
|
foreach ($ids as $id) {
|
||||||
$job = $redis->hgetall("job:$id");
|
$job = $redis->hgetall("job:$id");
|
||||||
if ($job) {
|
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;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user