diff --git a/Overlord-Server/public/assets/purgatory-ui.js b/Overlord-Server/public/assets/purgatory-ui.js index fe13e43..489002c 100644 --- a/Overlord-Server/public/assets/purgatory-ui.js +++ b/Overlord-Server/public/assets/purgatory-ui.js @@ -40,12 +40,25 @@ const denyReasonInput = document.getElementById("deny-reason-input"); const denyReasonModalConfirm = document.getElementById("deny-reason-modal-confirm"); const denyReasonModalCancel = document.getElementById("deny-reason-modal-cancel"); const denyReasonModalBackdrop = document.getElementById("deny-reason-modal-backdrop"); +const paginationEl = document.getElementById("enrollment-pagination"); +const pageSummaryEl = document.getElementById("enrollment-page-summary"); +const pageSizeEl = document.getElementById("enrollment-page-size"); +const prevPageBtn = document.getElementById("enrollment-prev-page"); +const nextPageBtn = document.getElementById("enrollment-next-page"); +const pageLabelEl = document.getElementById("enrollment-page-label"); let currentFilter = "pending"; let searchQuery = ""; let clients = []; const expandedCells = new Set(); // tracks "clientId:field" keys let lastEnrollmentDigest = ""; +let currentPage = 1; +let rowsPerPage = 100; +try { + rowsPerPage = Number(localStorage.getItem("purgatory_rows_per_page") || 100); +} catch {} +if (![50, 100, 200].includes(rowsPerPage)) rowsPerPage = 100; +if (pageSizeEl) pageSizeEl.value = String(rowsPerPage); const SUSPICIOUS_FLAG_LABELS = { hwid_flood: "HWID Flood (40+ same hardware ID)", @@ -105,6 +118,7 @@ async function loadClients() { const hasRows = body.querySelector("tr[data-id]"); loadingRow.classList.toggle("hidden", !!hasRows); emptyEl.classList.add("hidden"); + if (!hasRows) paginationEl?.classList.add("hidden"); const fetchFilter = currentFilter; try { @@ -117,20 +131,8 @@ async function loadClients() { // Sort by newest first (highest lastSeen = most recent) clients.sort((a, b) => (b.lastSeen || 0) - (a.lastSeen || 0)); - // Apply suspicious tab filter - let base = clients; - if (currentFilter === "suspicious") { - base = clients.filter((c) => (c.suspiciousFlags || []).length > 0); - } - - // Apply search filter + const filtered = getFilteredClients(); const q = searchQuery.toLowerCase().trim(); - const filtered = q - ? base.filter((c) => { - const fields = [c.host, c.user, c.ip, c.id, c.os, c.country, c.keyFingerprint, c.cpu, c.gpu, c.ram]; - return fields.some((f) => f && String(f).toLowerCase().includes(q)); - }) - : base; loadingRow.classList.add("hidden"); @@ -143,11 +145,20 @@ async function loadClients() { lastEnrollmentDigest = `empty:${currentFilter}:${q}`; body.querySelectorAll("tr:not(#enrollment-loading)").forEach((r) => r.remove()); emptyEl.classList.remove("hidden"); + paginationEl?.classList.add("hidden"); + paginationEl?.classList.remove("flex"); updateBulkButtons(); return; } - const nextDigest = tableDigest(filtered, [ + const totalPages = Math.max(1, Math.ceil(filtered.length / rowsPerPage)); + if (currentPage > totalPages) currentPage = totalPages; + if (currentPage < 1) currentPage = 1; + const startIndex = (currentPage - 1) * rowsPerPage; + const visible = filtered.slice(startIndex, startIndex + rowsPerPage); + updatePagination(filtered.length, startIndex, visible.length, totalPages); + + const nextDigest = tableDigest(visible, [ "id", "host", "user", @@ -162,7 +173,7 @@ async function loadClients() { "enrollmentStatus", "denyReason", "suspiciousFlags", - ]); + ], { total: filtered.length, page: currentPage, rowsPerPage, filter: currentFilter, q }); if (nextDigest === lastEnrollmentDigest) { updateBulkButtons(); return; @@ -172,7 +183,8 @@ async function loadClients() { const selectedBeforeRender = new Set(getSelectedIds()); body.querySelectorAll("tr:not(#enrollment-loading)").forEach((r) => r.remove()); - for (const c of filtered) { + const fragment = document.createDocumentFragment(); + for (const c of visible) { const tr = document.createElement("tr"); tr.className = "group hover:bg-slate-800/45 transition-colors"; tr.dataset.id = c.id; @@ -208,17 +220,45 @@ async function loadClients() {
No clients in this category.
+