Show total items to scan in progress overlay

- Add total_items parameter to broadcast_scan_started and broadcast_scan_progress
- Pass total from SeriesApp to WebSocket broadcasts in AnimeService
- Update JS overlay to show progress bar and current/total count
- Add CSS for progress bar styling
- Add unit tests for new total_items parameter
- All 1024 tests passing
This commit is contained in:
2025-12-24 20:54:27 +01:00
parent a24f07a36e
commit 72ac201153
10 changed files with 212 additions and 16 deletions

View File

@@ -1978,6 +1978,47 @@ body {
}
}
/* Progress bar for scan */
.scan-progress-bar-container {
width: 100%;
height: 8px;
background-color: var(--color-bg-tertiary);
border-radius: 4px;
overflow: hidden;
margin-bottom: var(--spacing-sm);
}
.scan-progress-bar {
height: 100%;
background: linear-gradient(90deg, var(--color-accent), var(--color-accent-hover, var(--color-accent)));
border-radius: 4px;
transition: width 0.3s ease;
}
.scan-progress-container.completed .scan-progress-bar {
background: linear-gradient(90deg, var(--color-success), var(--color-success));
}
.scan-progress-text {
font-size: var(--font-size-body);
color: var(--color-text-secondary);
margin-bottom: var(--spacing-md);
}
.scan-progress-text #scan-current-count {
font-weight: 600;
color: var(--color-accent);
}
.scan-progress-text #scan-total-count {
font-weight: 600;
color: var(--color-text-primary);
}
.scan-progress-container.completed .scan-progress-text #scan-current-count {
color: var(--color-success);
}
.scan-progress-stats {
display: flex;
justify-content: space-around;

View File

@@ -1085,10 +1085,16 @@ class AniWorldApp {
// Remove existing overlay if present
this.removeScanProgressOverlay();
// Store total items for progress calculation
this.scanTotalItems = data?.total_items || 0;
// Create overlay element
const overlay = document.createElement('div');
overlay.id = 'scan-progress-overlay';
overlay.className = 'scan-progress-overlay';
const totalDisplay = this.scanTotalItems > 0 ? this.scanTotalItems : '...';
overlay.innerHTML = `
<div class="scan-progress-container">
<div class="scan-progress-header">
@@ -1098,10 +1104,16 @@ class AniWorldApp {
<span class="scan-title-text">Scanning Library</span>
</h3>
</div>
<div class="scan-progress-bar-container">
<div class="scan-progress-bar" id="scan-progress-bar" style="width: 0%"></div>
</div>
<div class="scan-progress-text" id="scan-progress-text">
<span id="scan-current-count">0</span> / <span id="scan-total-count">${totalDisplay}</span> directories
</div>
<div class="scan-progress-stats">
<div class="scan-stat">
<span class="scan-stat-value" id="scan-directories-count">0</span>
<span class="scan-stat-label">Directories</span>
<span class="scan-stat-label">Scanned</span>
</div>
<div class="scan-stat">
<span class="scan-stat-value" id="scan-files-count">0</span>
@@ -1109,7 +1121,7 @@ class AniWorldApp {
</div>
</div>
<div class="scan-current-directory" id="scan-current-directory">
<span class="scan-current-directory-label">Scanning:</span>
<span class="scan-current-directory-label">Current:</span>
<span id="scan-current-path">${this.escapeHtml(data?.directory || 'Initializing...')}</span>
</div>
<div class="scan-elapsed-time hidden" id="scan-elapsed-time">
@@ -1135,6 +1147,28 @@ class AniWorldApp {
const overlay = document.getElementById('scan-progress-overlay');
if (!overlay) return;
// Update total items if provided (in case it wasn't available at start)
if (data.total_items && data.total_items > 0) {
this.scanTotalItems = data.total_items;
const totalCount = document.getElementById('scan-total-count');
if (totalCount) {
totalCount.textContent = this.scanTotalItems;
}
}
// Update progress bar
const progressBar = document.getElementById('scan-progress-bar');
if (progressBar && this.scanTotalItems > 0 && data.directories_scanned !== undefined) {
const percentage = Math.min(100, (data.directories_scanned / this.scanTotalItems) * 100);
progressBar.style.width = `${percentage}%`;
}
// Update current/total count display
const currentCount = document.getElementById('scan-current-count');
if (currentCount && data.directories_scanned !== undefined) {
currentCount.textContent = data.directories_scanned;
}
// Update directories count
const dirCount = document.getElementById('scan-directories-count');
if (dirCount && data.directories_scanned !== undefined) {
@@ -1179,6 +1213,12 @@ class AniWorldApp {
titleText.textContent = 'Scan Complete';
}
// Complete the progress bar
const progressBar = document.getElementById('scan-progress-bar');
if (progressBar) {
progressBar.style.width = '100%';
}
// Update final stats
if (data) {
const dirCount = document.getElementById('scan-directories-count');
@@ -1191,6 +1231,16 @@ class AniWorldApp {
filesCount.textContent = data.total_files;
}
// Update progress text to show final count
const currentCount = document.getElementById('scan-current-count');
const totalCount = document.getElementById('scan-total-count');
if (currentCount && data.total_directories !== undefined) {
currentCount.textContent = data.total_directories;
}
if (totalCount && data.total_directories !== undefined) {
totalCount.textContent = data.total_directories;
}
// Show elapsed time
const elapsedTimeEl = document.getElementById('scan-elapsed-time');
const elapsedValueEl = document.getElementById('scan-elapsed-value');