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.
201 lines
5.7 KiB
201 lines
5.7 KiB
/* =======================================================================
|
|
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 = `
|
|
<div class="book-title">${b.title}</div>
|
|
<div class="book-status">${b.status}</div>
|
|
<div class="book-progress">
|
|
${b.download_done}/${b.download_total} downloaded,
|
|
${b.audio_done}/${b.audio_total} audio
|
|
</div>
|
|
|
|
<button class="abort-btn" onclick="abortBook('${b.book_id}')">Abort</button>
|
|
`;
|
|
|
|
// 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);
|
|
});
|
|
}
|