add(core): show less entries in download
This commit is contained in:
+57
-25
@@ -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 }) });
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user