add(core): show less entries in download

This commit is contained in:
Steppenstreuner
2026-08-28 14:30:00 +02:00
parent c4e181b05b
commit 90a50e365f
2 changed files with 62 additions and 25 deletions
+57 -25
View File
@@ -265,7 +265,13 @@ $("#scan-btn").addEventListener("click", async () => {
api("/api/requests?status=missing"),
]);
scanItems = scan.items;
// selection state lives here, not in the DOM, so it survives paging
scanItems.forEach((item) => {
item.request_id = item.suggested_request_id;
item.checked = !!item.suggested_request_id;
});
missingReqs = reqs;
importPage = 0;
$("#scan-info").textContent = `${scan.items.length} Kandidat(en) in ${scan.download_dir}`;
renderImportTable();
} catch (err) {
@@ -274,22 +280,36 @@ $("#scan-btn").addEventListener("click", async () => {
}
});
let importPage = 0;
const IMPORT_PAGE_SIZE = 25;
function renderImportTable() {
const table = $("#import-table");
const tbody = table.querySelector("tbody");
if (!scanItems.length) { table.hidden = true; $("#import-btn").hidden = true; return; }
tbody.innerHTML = scanItems
.map((item, i) => {
if (!scanItems.length) {
table.hidden = true;
$("#import-btn").hidden = true;
$("#import-pager").hidden = true;
return;
}
const pages = Math.ceil(scanItems.length / IMPORT_PAGE_SIZE);
importPage = Math.min(importPage, pages - 1);
const start = importPage * IMPORT_PAGE_SIZE;
const pageItems = scanItems.slice(start, start + IMPORT_PAGE_SIZE);
tbody.innerHTML = pageItems
.map((item, k) => {
const i = start + k;
const opts = missingReqs
.filter((r) => r.media_type === item.media_type)
.map(
(r) =>
`<option value="${r.id}" ${r.id === item.suggested_request_id ? "selected" : ""}>
`<option value="${r.id}" ${r.id === item.request_id ? "selected" : ""}>
${esc(r.title)}${esc(r.authors)} (${esc(r.library_name)})</option>`
)
.join("");
return `<tr>
<td><input type="checkbox" data-check="${i}" ${item.suggested_request_id ? "checked" : ""}></td>
<td><input type="checkbox" data-check="${i}" ${item.checked ? "checked" : ""}></td>
<td class="mono">${esc(item.name)}${item.is_dir ? " 📁" : ""}</td>
<td>${esc(item.media_type)}</td>
<td class="row">
@@ -302,11 +322,34 @@ function renderImportTable() {
.join("");
table.hidden = false;
$("#import-btn").hidden = false;
tbody.querySelectorAll("[data-quick]").forEach((b) =>
b.addEventListener("click", () => openQuickDialog(parseInt(b.dataset.quick)))
);
tbody.querySelectorAll("[data-check]").forEach((c) =>
c.addEventListener("change", () => (scanItems[c.dataset.check].checked = c.checked))
);
tbody.querySelectorAll("[data-select]").forEach((s) =>
s.addEventListener("change", () => {
const item = scanItems[s.dataset.select];
item.request_id = s.value ? parseInt(s.value) : null;
item.checked = !!item.request_id;
const check = tbody.querySelector(`[data-check="${s.dataset.select}"]`);
if (check) check.checked = item.checked;
})
);
const selected = scanItems.filter((it) => it.checked && it.request_id).length;
$("#import-pager").hidden = false;
$("#import-page-info").textContent =
`Seite ${importPage + 1}/${pages} · ${scanItems.length} Einträge · ${selected} ausgewählt`;
$("#import-prev").disabled = importPage === 0;
$("#import-next").disabled = importPage >= pages - 1;
}
$("#import-prev").addEventListener("click", () => { importPage--; renderImportTable(); });
$("#import-next").addEventListener("click", () => { importPage++; renderImportTable(); });
// ---- quick request from a scanned file ----
let quickItemIndex = null;
@@ -381,32 +424,21 @@ async function pickQuickResult(r) {
}),
});
missingReqs.push(req);
// add the new request to every dropdown of the same media type, then link this row
const item = scanItems[i];
scanItems.forEach((it, j) => {
if (it.media_type !== item.media_type) return;
const sel = document.querySelector(`[data-select="${j}"]`);
const opt = document.createElement("option");
opt.value = req.id;
opt.textContent = `${req.title}${req.authors} (${req.library_name})`;
sel.appendChild(opt);
});
document.querySelector(`[data-select="${i}"]`).value = req.id;
document.querySelector(`[data-check="${i}"]`).checked = true;
scanItems[i].request_id = req.id;
scanItems[i].checked = true;
renderImportTable();
$("#quick-dialog").close();
toast(`${req.title}" angefragt und verbunden`);
} catch (err) { toast(err.message, true); }
}
$("#import-btn").addEventListener("click", async () => {
const items = [];
scanItems.forEach((item, i) => {
const checked = document.querySelector(`[data-check="${i}"]`).checked;
const reqId = document.querySelector(`[data-select="${i}"]`).value;
if (checked && reqId) {
items.push({ path: item.path, is_dir: item.is_dir, files: item.files, request_id: parseInt(reqId) });
}
});
const items = scanItems
.filter((item) => item.checked && item.request_id)
.map((item) => ({
path: item.path, is_dir: item.is_dir, files: item.files,
request_id: item.request_id,
}));
if (!items.length) { toast("Nichts ausgewählt", true); return; }
try {
const res = await api("/api/import", { method: "POST", body: JSON.stringify({ items }) });
+5
View File
@@ -109,6 +109,11 @@
</thead>
<tbody></tbody>
</table>
<div class="bar" id="import-pager" hidden>
<button id="import-prev" class="secondary">← Zurück</button>
<span id="import-page-info" class="muted"></span>
<button id="import-next" class="secondary">Weiter →</button>
</div>
<div class="bar">
<button id="import-btn" hidden>Ausgewählte importieren</button>
</div>