/* ======================================================================= File: static/js/dashboard.js Purpose: Dashboard interactions: - select book - refresh logs - refresh progress NOTE: $ / $$ / autoScroll komen uit helpers.js ======================================================================= */ /* --------------------------------------------------------- Simple fetch wrapper --------------------------------------------------------- */ async function apiGet(url) { try { const r = await fetch(url); if (!r.ok) return null; return await r.json(); } catch (e) { console.error("API GET failed:", url, e); return null; } } /* --------------------------------------------------------- Dashboard state --------------------------------------------------------- */ let ACTIVE_BOOK = null; let REFRESH_INTERVAL = null; console.log(">>> dashboard.js LOADED"); /* --------------------------------------------------------- DOM Ready → setup --------------------------------------------------------- */ document.addEventListener("DOMContentLoaded", () => { console.log(">>> dashboard.js DOMContentLoaded"); // ===================================================== // GLOBAL FALLBACK POLLING — ALWAYS FETCH LOGS // Runs when no books exist or no selection has been made // ===================================================== console.log(">>> dashboard.js: enabling global fallback polling"); setInterval(() => { // if no active book → fetch global logs if (!ACTIVE_BOOK) { refreshBook(null); // triggers /logs } }, 2000); const items = $$(".book-list-item"); console.log(">>> dashboard.js found book-list items:", items.length); // Geen boeken → geen polling starten // if (!items || items.length === 0) { // console.log(">>> dashboard.js: geen boeken aanwezig, polling uit."); // return; // } // Book selection listener items.forEach((item) => { item.addEventListener("click", () => { console.log(">>> dashboard.js: user clicked book:", item.dataset.bookId); selectBook(item.dataset.bookId); }); }); // Auto-select first book if (!ACTIVE_BOOK && items[0]) { console.log( ">>> dashboard.js: auto-select first book:", items[0].dataset.bookId ); selectBook(items[0].dataset.bookId); } }); /* --------------------------------------------------------- Select a book (updates UI + starts polling) --------------------------------------------------------- */ function selectBook(bookId) { console.log(">>> selectBook(", bookId, ")"); ACTIVE_BOOK = bookId; // Highlight $$(".book-list-item").forEach((el) => { el.classList.toggle("active", el.dataset.bookId === bookId); }); // Reset previous polling if (REFRESH_INTERVAL) { console.log(">>> dashboard.js: clearing previous polling interval"); clearInterval(REFRESH_INTERVAL); } // Start new polling console.log(">>> dashboard.js: starting polling for bookId =", bookId); REFRESH_INTERVAL = setInterval(() => { refreshBook(ACTIVE_BOOK); }, 2000); // Immediate refresh refreshBook(ACTIVE_BOOK); } setInterval(refreshActiveBooks, 2000); async function refreshActiveBooks() { const books = await apiGet("/api/books"); if (!books) return; const container = $("#book-list"); if (!container) return; // Herbouw de lijst container.innerHTML = ""; books.forEach((b) => { const div = document.createElement("div"); div.className = "book-list-item"; div.dataset.bookId = b.book_id; div.innerHTML = `
${b.title}
${b.status}
${b.download_done}/${b.download_total} downloaded, ${b.audio_done}/${b.audio_total} audio
`; // Event listener opnieuw koppelen div.addEventListener("click", () => selectBook(b.book_id)); container.appendChild(div); }); // Als ACTIVE_BOOK nog niet bekend → auto-selecteer eerste boek if (!ACTIVE_BOOK && books.length > 0) { selectBook(books[0].book_id); } } /* --------------------------------------------------------- Fetch logs + progress from API --------------------------------------------------------- */ async function refreshBook(bookId) { console.log(">>> refreshBook(", bookId, ")"); // 1) Als er GEEN bookId is → haal alleen globale logs op if (!bookId) { console.log(">>> refreshBook: no active book → fetch /logs"); const data = await apiGet("/logs"); if (data && data.logs) updateLogs(data.logs); return; // klaar } // 2) Als er WEL een boek is → haal book status + logs op const state = await apiGet(`/api/book/${bookId}/status`); const logs = await apiGet(`/api/book/${bookId}/logs`); console.log(">>> refreshBook state =", state); console.log(">>> refreshBook logs =", logs); if (state) updateProgressBars(state); if (logs) updateLogs(logs); } /* --------------------------------------------------------- Update LOG VIEW panel --------------------------------------------------------- */ function updateLogs(logList) { const output = $("#log-output"); if (!output) { console.warn(">>> updateLogs: no #log-output element found"); return; } output.innerHTML = ""; logList.forEach((line) => logAppend(line)); autoScroll(output); } function abortBook(book_id) { if (!confirm(`Abort tasks for book ${book_id}?`)) return; fetch(`/abort/${book_id}`, { method: "POST" }) .then((r) => r.json()) .then((data) => { console.log("Abort:", data); }) .catch((err) => { console.error("Abort failed:", err); }); }