You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
5.0 KiB
179 lines
5.0 KiB
/* =======================================================================
|
|
File: static/js/dashboard.js
|
|
Purpose:
|
|
- Sidebar selectie
|
|
- Start / Abort acties
|
|
- UI status updates
|
|
NOTE:
|
|
- GEEN polling
|
|
- state_updater.js is leidend
|
|
======================================================================= */
|
|
|
|
console.log("[DASHBOARD] loaded");
|
|
|
|
/* ---------------------------------------------------------
|
|
Helpers
|
|
--------------------------------------------------------- */
|
|
async function apiGet(url) {
|
|
console.log("[DASHBOARD][API] GET", url);
|
|
try {
|
|
const r = await fetch(url, { cache: "no-store" });
|
|
if (!r.ok) {
|
|
console.warn("[DASHBOARD][API] GET failed", url, r.status);
|
|
return null;
|
|
}
|
|
return await r.json();
|
|
} catch (e) {
|
|
console.error("[DASHBOARD][API] GET error", url, e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function safeUpdateLogs(data) {
|
|
if (typeof window.updateLogs === "function") {
|
|
console.log("[DASHBOARD] updateLogs()");
|
|
window.updateLogs(data);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------
|
|
State
|
|
--------------------------------------------------------- */
|
|
let ACTIVE_BOOK_IDX = null;
|
|
|
|
/* ---------------------------------------------------------
|
|
DOM READY
|
|
--------------------------------------------------------- */
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
console.log("[DASHBOARD] DOMContentLoaded");
|
|
|
|
bindSidebar();
|
|
bindBookCardButtons();
|
|
|
|
const first = document.querySelector(".book-list-item");
|
|
if (first) {
|
|
console.log("[DASHBOARD] auto-select", first.dataset.bookIdx);
|
|
selectBook(first.dataset.bookIdx);
|
|
}
|
|
});
|
|
|
|
/* ---------------------------------------------------------
|
|
Sidebar
|
|
--------------------------------------------------------- */
|
|
function bindSidebar() {
|
|
console.log("[DASHBOARD] bindSidebar()");
|
|
document.querySelectorAll(".book-list-item").forEach((item) => {
|
|
item.onclick = () => selectBook(item.dataset.bookIdx);
|
|
});
|
|
}
|
|
|
|
function selectBook(bookIdx) {
|
|
if (!bookIdx || bookIdx === ACTIVE_BOOK_IDX) return;
|
|
|
|
ACTIVE_BOOK_IDX = bookIdx;
|
|
console.log("[DASHBOARD] selectBook", bookIdx);
|
|
|
|
document.querySelectorAll(".book-list-item").forEach((el) => {
|
|
el.classList.toggle("active", el.dataset.bookIdx === bookIdx);
|
|
});
|
|
|
|
refreshBook(bookIdx);
|
|
}
|
|
|
|
/* ---------------------------------------------------------
|
|
Book refresh (NO POLLING)
|
|
--------------------------------------------------------- */
|
|
async function refreshBook(bookIdx) {
|
|
console.log("[DASHBOARD] refreshBook", bookIdx);
|
|
|
|
const logs = await apiGet(`/api/book/${bookIdx}/logs`);
|
|
if (logs) safeUpdateLogs(logs);
|
|
|
|
refreshBookCards();
|
|
}
|
|
|
|
/* ---------------------------------------------------------
|
|
Bookcard buttons
|
|
--------------------------------------------------------- */
|
|
function bindBookCardButtons() {
|
|
console.log("[DASHBOARD] bindBookCardButtons()");
|
|
|
|
document.querySelectorAll(".icon-start").forEach((btn) => {
|
|
if (btn.dataset.bound) return;
|
|
btn.dataset.bound = "1";
|
|
|
|
btn.onclick = (e) => {
|
|
e.preventDefault();
|
|
const card = btn.closest(".book-card");
|
|
if (!card) return;
|
|
startBook(card.dataset.bookIdx);
|
|
};
|
|
});
|
|
|
|
document.querySelectorAll(".icon-abort").forEach((btn) => {
|
|
if (btn.dataset.bound) return;
|
|
btn.dataset.bound = "1";
|
|
|
|
btn.onclick = (e) => {
|
|
e.preventDefault();
|
|
const card = btn.closest(".book-card");
|
|
if (!card) return;
|
|
abortBook(card.dataset.bookIdx);
|
|
};
|
|
});
|
|
}
|
|
|
|
/* ---------------------------------------------------------
|
|
START
|
|
--------------------------------------------------------- */
|
|
function startBook(bookIdx) {
|
|
console.log("[DASHBOARD] START", bookIdx);
|
|
|
|
fetch("/start", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
body: `book_idx=${bookIdx}`,
|
|
}).then(() => refreshBook(bookIdx));
|
|
}
|
|
|
|
/* ---------------------------------------------------------
|
|
ABORT
|
|
--------------------------------------------------------- */
|
|
function abortBook(bookIdx) {
|
|
if (!confirm(`Abort book ${bookIdx}?`)) return;
|
|
|
|
console.log("[DASHBOARD] ABORT", bookIdx);
|
|
|
|
fetch(`/abort/${bookIdx}`, { method: "POST" }).then(() =>
|
|
refreshBook(bookIdx)
|
|
);
|
|
}
|
|
|
|
/* ---------------------------------------------------------
|
|
Bookcard UI refresh (non-progress)
|
|
--------------------------------------------------------- */
|
|
async function refreshBookCards() {
|
|
console.log("[DASHBOARD] refreshBookCards()");
|
|
const books = await apiGet("/api/books");
|
|
if (!books) return;
|
|
|
|
document.querySelectorAll(".book-card").forEach((card) => {
|
|
const idx = card.dataset.bookIdx;
|
|
const info = books.find((b) => b.book_idx === idx);
|
|
if (!info) return;
|
|
|
|
console.log("[DASHBOARD] card status", idx, info.status);
|
|
card.className = `book-card ${info.status}`;
|
|
|
|
const abortBtn = card.querySelector(".icon-abort");
|
|
if (abortBtn) {
|
|
abortBtn.disabled = ![
|
|
"processing",
|
|
"downloading",
|
|
"parsing",
|
|
"audio",
|
|
].includes(info.status);
|
|
}
|
|
});
|
|
}
|