Problem: - Many format modules imported from '../core/reader-context' - reader-context.ts was a local interface file, not a true context module - Confusion between canonical reader-shell.ts and local reader-context.ts - PDF page-cache.ts was 100% dead code (unused, unregistered, no exports) - Several unused variables and imports across reader modules Root Cause: - reader-context.ts created as temporary file during refactoring - Modules imported from it instead of canonical reader-shell.ts - page-cache.ts copied from comic version but never integrated - Incomplete refactoring left behind unused code Solution: - Update all imports to use reader-shell (canonical source) - Remove unused page-cache.ts (dead code) - Clean up unused variables and imports - Consolidate type definitions Changes: Import Path Updates: - comic/*: '../core/reader-context' → '../../reader-shell' - manga/*: '../core/reader-context' → '../../reader-shell' - pdf/*: '../core/reader-context' → '../../reader-shell' - reflowable/ebook/*: '../core/reader-context' → '../../reader-shell' - All now import UniversalReader from single source Dead Code Removal: - pdf/page-cache.ts: Deleted entirely - No init() function exported - Not registered in reader-shell.ts - All functions unused (createPDFPageCache, getCachedPage, etc.) - Only 2 lines of executable code (console.log, DOM cleanup) - 148 lines of dead code Clean Up: - navigator-panel.ts: Remove unused containerRect variable - api-explorer-docs.ts, api.ts, queue.ts: Fix unused imports - unlinked_books.ts: Remove unused variables - panel-dock-system.ts: Remove unused context variables Impact: - ✅ All modules use canonical type definitions - ✅ No more duplicate/conflicting interfaces - ✅ Dead code removed (148 lines) - ✅ Cleaner imports, easier maintenance - ✅ TypeScript compiler warnings resolved Files changed: 26 Lines changed: +450, -520 (net -70 lines)
205 lines
5.7 KiB
TypeScript
205 lines
5.7 KiB
TypeScript
import { Alpine } from "./alpine";
|
|
import { showToast } from "./toast";
|
|
|
|
async function refreshQueue(): Promise<void> {
|
|
const token = localStorage.getItem("token");
|
|
if (!token) return;
|
|
|
|
try {
|
|
const response = await fetch("/api/queue/all", {
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
renderQueueItems(data.items || []);
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to refresh queue:", error);
|
|
}
|
|
}
|
|
|
|
async function processPendingItems(): Promise<void> {
|
|
const token = localStorage.getItem("token");
|
|
if (!token) return;
|
|
|
|
try {
|
|
const response = await fetch("/api/queue/process", {
|
|
method: "POST",
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
|
|
if (response.ok) {
|
|
showToast("Processing queue items", "success");
|
|
refreshQueue();
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to process queue:", error);
|
|
showToast("Failed to process queue", "error");
|
|
}
|
|
}
|
|
|
|
async function clearFailedItems(): Promise<void> {
|
|
const token = localStorage.getItem("token");
|
|
if (!token) return;
|
|
|
|
if (!confirm("Are you sure you want to clear all failed items?")) return;
|
|
|
|
try {
|
|
const response = await fetch("/api/queue/failed", {
|
|
method: "DELETE",
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
|
|
if (response.ok) {
|
|
showToast("Failed items cleared", "success");
|
|
refreshQueue();
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to clear failed items:", error);
|
|
showToast("Failed to clear items", "error");
|
|
}
|
|
}
|
|
|
|
async function clearAllItems(): Promise<void> {
|
|
const token = localStorage.getItem("token");
|
|
if (!token) return;
|
|
|
|
if (!confirm("Are you sure you want to clear all queue items?")) return;
|
|
|
|
try {
|
|
const response = await fetch("/api/queue/all", {
|
|
method: "DELETE",
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
|
|
if (response.ok) {
|
|
showToast("Queue cleared", "success");
|
|
refreshQueue();
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to clear queue:", error);
|
|
showToast("Failed to clear queue", "error");
|
|
}
|
|
}
|
|
|
|
async function retryQueueItem(itemId: string): Promise<void> {
|
|
const token = localStorage.getItem("token");
|
|
if (!token) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/queue/items/${itemId}/retry`, {
|
|
method: "POST",
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
|
|
if (response.ok) {
|
|
showToast("Item queued for retry", "success");
|
|
refreshQueue();
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to retry item:", error);
|
|
showToast("Failed to retry item", "error");
|
|
}
|
|
}
|
|
|
|
async function deleteQueueItem(itemId: string): Promise<void> {
|
|
const token = localStorage.getItem("token");
|
|
if (!token) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/queue/items/${itemId}`, {
|
|
method: "DELETE",
|
|
headers: { Authorization: `Bearer ${token}` },
|
|
});
|
|
|
|
if (response.ok) {
|
|
showToast("Item deleted", "success");
|
|
refreshQueue();
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to delete item:", error);
|
|
showToast("Failed to delete item", "error");
|
|
}
|
|
}
|
|
|
|
function renderQueueItems(items: QueueItemResponse[]): void {
|
|
const container = document.getElementById("queue-items");
|
|
if (!container) return;
|
|
|
|
if (items.length === 0) {
|
|
container.innerHTML =
|
|
'<p class="text-center p-4" style="color: var(--text-secondary)">Queue is empty</p>';
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = items
|
|
.map(
|
|
(item) => `
|
|
<div class="p-3 rounded-lg border mb-2" style="background-color: var(--bg-secondary); border-color: var(--border)">
|
|
<div class="flex justify-between items-center">
|
|
<div>
|
|
<p class="font-medium" style="color: var(--text-primary)">${item.media_title || "Unknown"}</p>
|
|
<p class="text-sm" style="color: var(--text-secondary)">${item.status} - ${item.sync_type}</p>
|
|
<p class="text-xs" style="color: var(--text-secondary)">Attempts: ${item.attempts}/${item.max_attempts}</p>
|
|
</div>
|
|
<div class="flex space-x-2">
|
|
${item.status === "failed" ? `<button onclick="window.retryQueueItem('${item.id}')" class="btn-secondary px-2 py-1 rounded text-sm">Retry</button>` : ""}
|
|
<button onclick="window.deleteQueueItem('${item.id}')" class="btn-secondary px-2 py-1 rounded text-sm">Delete</button>
|
|
</div>
|
|
</div>
|
|
${item.error_message ? `<p class="text-xs mt-2" style="color: var(--accent)">${item.error_message}</p>` : ""}
|
|
</div>
|
|
`,
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
function showQueueItemModal(): void {
|
|
const modal = document.getElementById("queue-item-modal");
|
|
const detailsContainer = document.getElementById("queue-item-details");
|
|
|
|
if (modal && detailsContainer) {
|
|
// TODO: Fetch and display item details
|
|
detailsContainer.innerHTML = "<p>Loading item details...</p>";
|
|
modal.classList.remove("hidden");
|
|
}
|
|
}
|
|
|
|
function hideQueueItemModal(): void {
|
|
const modal = document.getElementById("queue-item-modal");
|
|
if (modal) {
|
|
modal.classList.add("hidden");
|
|
}
|
|
}
|
|
|
|
function filterQueue(status: string): void {
|
|
const filterValue = status || "all";
|
|
// TODO: Implement filtering logic
|
|
console.log("Filter queue by:", filterValue);
|
|
}
|
|
|
|
export {
|
|
clearAllItems,
|
|
clearFailedItems,
|
|
deleteQueueItem,
|
|
processPendingItems,
|
|
refreshQueue,
|
|
retryQueueItem,
|
|
showQueueItemModal,
|
|
hideQueueItemModal,
|
|
filterQueue,
|
|
};
|
|
|
|
Alpine.data("queue", () => ({
|
|
clearAllItems,
|
|
clearFailedItems,
|
|
deleteQueueItem,
|
|
processPendingItems,
|
|
refreshQueue,
|
|
retryQueueItem,
|
|
showQueueItemModal,
|
|
hideQueueItemModal,
|
|
filterQueue,
|
|
}));
|