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"),
|
api("/api/requests?status=missing"),
|
||||||
]);
|
]);
|
||||||
scanItems = scan.items;
|
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;
|
missingReqs = reqs;
|
||||||
|
importPage = 0;
|
||||||
$("#scan-info").textContent = `${scan.items.length} Kandidat(en) in ${scan.download_dir}`;
|
$("#scan-info").textContent = `${scan.items.length} Kandidat(en) in ${scan.download_dir}`;
|
||||||
renderImportTable();
|
renderImportTable();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -274,22 +280,36 @@ $("#scan-btn").addEventListener("click", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let importPage = 0;
|
||||||
|
const IMPORT_PAGE_SIZE = 25;
|
||||||
|
|
||||||
function renderImportTable() {
|
function renderImportTable() {
|
||||||
const table = $("#import-table");
|
const table = $("#import-table");
|
||||||
const tbody = table.querySelector("tbody");
|
const tbody = table.querySelector("tbody");
|
||||||
if (!scanItems.length) { table.hidden = true; $("#import-btn").hidden = true; return; }
|
if (!scanItems.length) {
|
||||||
tbody.innerHTML = scanItems
|
table.hidden = true;
|
||||||
.map((item, i) => {
|
$("#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
|
const opts = missingReqs
|
||||||
.filter((r) => r.media_type === item.media_type)
|
.filter((r) => r.media_type === item.media_type)
|
||||||
.map(
|
.map(
|
||||||
(r) =>
|
(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>`
|
${esc(r.title)} — ${esc(r.authors)} (${esc(r.library_name)})</option>`
|
||||||
)
|
)
|
||||||
.join("");
|
.join("");
|
||||||
return `<tr>
|
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 class="mono">${esc(item.name)}${item.is_dir ? " 📁" : ""}</td>
|
||||||
<td>${esc(item.media_type)}</td>
|
<td>${esc(item.media_type)}</td>
|
||||||
<td class="row">
|
<td class="row">
|
||||||
@@ -302,11 +322,34 @@ function renderImportTable() {
|
|||||||
.join("");
|
.join("");
|
||||||
table.hidden = false;
|
table.hidden = false;
|
||||||
$("#import-btn").hidden = false;
|
$("#import-btn").hidden = false;
|
||||||
|
|
||||||
tbody.querySelectorAll("[data-quick]").forEach((b) =>
|
tbody.querySelectorAll("[data-quick]").forEach((b) =>
|
||||||
b.addEventListener("click", () => openQuickDialog(parseInt(b.dataset.quick)))
|
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 ----
|
// ---- quick request from a scanned file ----
|
||||||
let quickItemIndex = null;
|
let quickItemIndex = null;
|
||||||
|
|
||||||
@@ -381,32 +424,21 @@ async function pickQuickResult(r) {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
missingReqs.push(req);
|
missingReqs.push(req);
|
||||||
// add the new request to every dropdown of the same media type, then link this row
|
scanItems[i].request_id = req.id;
|
||||||
const item = scanItems[i];
|
scanItems[i].checked = true;
|
||||||
scanItems.forEach((it, j) => {
|
renderImportTable();
|
||||||
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;
|
|
||||||
$("#quick-dialog").close();
|
$("#quick-dialog").close();
|
||||||
toast(`„${req.title}" angefragt und verbunden`);
|
toast(`„${req.title}" angefragt und verbunden`);
|
||||||
} catch (err) { toast(err.message, true); }
|
} catch (err) { toast(err.message, true); }
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#import-btn").addEventListener("click", async () => {
|
$("#import-btn").addEventListener("click", async () => {
|
||||||
const items = [];
|
const items = scanItems
|
||||||
scanItems.forEach((item, i) => {
|
.filter((item) => item.checked && item.request_id)
|
||||||
const checked = document.querySelector(`[data-check="${i}"]`).checked;
|
.map((item) => ({
|
||||||
const reqId = document.querySelector(`[data-select="${i}"]`).value;
|
path: item.path, is_dir: item.is_dir, files: item.files,
|
||||||
if (checked && reqId) {
|
request_id: item.request_id,
|
||||||
items.push({ path: item.path, is_dir: item.is_dir, files: item.files, request_id: parseInt(reqId) });
|
}));
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!items.length) { toast("Nichts ausgewählt", true); return; }
|
if (!items.length) { toast("Nichts ausgewählt", true); return; }
|
||||||
try {
|
try {
|
||||||
const res = await api("/api/import", { method: "POST", body: JSON.stringify({ items }) });
|
const res = await api("/api/import", { method: "POST", body: JSON.stringify({ items }) });
|
||||||
|
|||||||
@@ -109,6 +109,11 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
</table>
|
</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">
|
<div class="bar">
|
||||||
<button id="import-btn" hidden>Ausgewählte importieren</button>
|
<button id="import-btn" hidden>Ausgewählte importieren</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user