Implement enhanced loading progress display in DownloadManager and ImportManager. Introduce detailed progress updates and UI elements for current item and overall progress during downloads. Update LoadingManager to support dynamic progress visualization.

This commit is contained in:
Will Miao
2025-03-15 16:25:56 +08:00
parent 9a1fe19cc8
commit 9f2289329c
4 changed files with 224 additions and 20 deletions

View File

@@ -56,6 +56,53 @@
transition: width 200ms ease-out; transition: width 200ms ease-out;
} }
/* Enhanced progress display */
.progress-details-container {
margin-top: var(--space-3);
width: 100%;
text-align: left;
}
.overall-progress-label {
font-size: 0.9rem;
margin-bottom: var(--space-1);
color: var(--text-color);
}
.current-item-progress {
margin-top: var(--space-2);
}
.current-item-label {
font-size: 0.9rem;
margin-bottom: var(--space-1);
color: var(--text-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.current-item-bar-container {
height: 8px;
background-color: var(--lora-border);
border-radius: 4px;
overflow: hidden;
margin-bottom: var(--space-1);
}
.current-item-bar {
height: 100%;
background-color: var(--lora-accent);
transition: width 200ms ease-out;
width: 0%;
}
.current-item-percent {
font-size: 0.8rem;
color: var(--text-color-secondary, var(--text-color));
opacity: 0.7;
}
@keyframes spin { @keyframes spin {
0% { transform: rotate(0deg); } 0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); } 100% { transform: rotate(360deg); }
@@ -63,7 +110,8 @@
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.lora-card, .lora-card,
.progress-bar { .progress-bar,
.current-item-bar {
transition: none; transition: none;
} }
} }

View File

@@ -270,19 +270,37 @@ export class DownloadManager {
throw new Error('No download URL available'); throw new Error('No download URL available');
} }
// Show loading with progress bar for download // Show enhanced loading with progress details
this.loadingManager.show('Downloading LoRA...', 0); const updateProgress = this.loadingManager.showDownloadProgress(1);
updateProgress(0, 0, this.currentVersion.name);
// Setup WebSocket for progress updates // Setup WebSocket for progress updates
const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
const ws = new WebSocket(`${wsProtocol}${window.location.host}/ws/fetch-progress`); const ws = new WebSocket(`${wsProtocol}${window.location.host}/ws/fetch-progress`);
ws.onmessage = (event) => { ws.onmessage = (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.status === 'progress') { if (data.status === 'progress') {
this.loadingManager.setProgress(data.progress); // Update progress display with current progress
this.loadingManager.setStatus(`Downloading: ${data.progress}%`); updateProgress(data.progress, 0, this.currentVersion.name);
// Add more detailed status messages based on progress
if (data.progress < 3) {
this.loadingManager.setStatus(`Preparing download...`);
} else if (data.progress === 3) {
this.loadingManager.setStatus(`Downloaded preview image`);
} else if (data.progress > 3 && data.progress < 100) {
this.loadingManager.setStatus(`Downloading LoRA file`);
} else {
this.loadingManager.setStatus(`Finalizing download...`);
}
} }
}; };
ws.onerror = (error) => {
console.error('WebSocket error:', error);
// Continue with download even if WebSocket fails
};
// Start download // Start download
const response = await fetch('/api/download-lora', { const response = await fetch('/api/download-lora', {

View File

@@ -507,27 +507,56 @@ export class ImportManager {
const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
const ws = new WebSocket(`${wsProtocol}${window.location.host}/ws/fetch-progress`); const ws = new WebSocket(`${wsProtocol}${window.location.host}/ws/fetch-progress`);
// Download missing LoRAs sequentially // Show enhanced loading with progress details for multiple items
this.loadingManager.show('Downloading LoRAs...', 0); const updateProgress = this.loadingManager.showDownloadProgress(this.missingLoras.length);
let completedDownloads = 0; let completedDownloads = 0;
let currentLoraProgress = 0;
// Set up progress tracking for current download
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.status === 'progress') {
// Update current LoRA progress
currentLoraProgress = data.progress;
// Get current LoRA name
const currentLora = this.missingLoras[completedDownloads];
const loraName = currentLora ? currentLora.name : '';
// Update progress display
updateProgress(currentLoraProgress, completedDownloads, loraName);
// Add more detailed status messages based on progress
if (currentLoraProgress < 3) {
this.loadingManager.setStatus(
`Preparing download for LoRA ${completedDownloads+1}/${this.missingLoras.length}`
);
} else if (currentLoraProgress === 3) {
this.loadingManager.setStatus(
`Downloaded preview for LoRA ${completedDownloads+1}/${this.missingLoras.length}`
);
} else if (currentLoraProgress > 3 && currentLoraProgress < 100) {
this.loadingManager.setStatus(
`Downloading LoRA ${completedDownloads+1}/${this.missingLoras.length}`
);
} else {
this.loadingManager.setStatus(
`Finalizing LoRA ${completedDownloads+1}/${this.missingLoras.length}`
);
}
}
};
for (let i = 0; i < this.missingLoras.length; i++) { for (let i = 0; i < this.missingLoras.length; i++) {
const lora = this.missingLoras[i]; const lora = this.missingLoras[i];
// Update overall progress // Reset current LoRA progress for new download
this.loadingManager.setStatus(`Downloading LoRA ${i+1}/${this.missingLoras.length}: ${lora.name}`); currentLoraProgress = 0;
// Set up progress tracking for current download // Initial status update for new LoRA
ws.onmessage = (event) => { this.loadingManager.setStatus(`Starting download for LoRA ${i+1}/${this.missingLoras.length}`);
const data = JSON.parse(event.data); updateProgress(0, completedDownloads, lora.name);
if (data.status === 'progress') {
// Calculate overall progress: completed files + current file progress
const overallProgress = Math.floor(
(completedDownloads + data.progress/100) / this.missingLoras.length * 100
);
this.loadingManager.setProgress(overallProgress);
}
};
try { try {
// Download the LoRA // Download the LoRA
@@ -547,6 +576,15 @@ export class ImportManager {
// Continue with next download // Continue with next download
} else { } else {
completedDownloads++; completedDownloads++;
// Update progress to show completion of current LoRA
updateProgress(100, completedDownloads, '');
if (completedDownloads < this.missingLoras.length) {
this.loadingManager.setStatus(
`Completed ${completedDownloads}/${this.missingLoras.length} LoRAs. Starting next download...`
);
}
} }
} catch (downloadError) { } catch (downloadError) {
console.error(`Error downloading LoRA ${lora.name}:`, downloadError); console.error(`Error downloading LoRA ${lora.name}:`, downloadError);

View File

@@ -4,17 +4,22 @@ export class LoadingManager {
this.overlay = document.getElementById('loading-overlay'); this.overlay = document.getElementById('loading-overlay');
this.progressBar = this.overlay.querySelector('.progress-bar'); this.progressBar = this.overlay.querySelector('.progress-bar');
this.statusText = this.overlay.querySelector('.loading-status'); this.statusText = this.overlay.querySelector('.loading-status');
this.detailsContainer = null; // Will be created when needed
} }
show(message = 'Loading...', progress = 0) { show(message = 'Loading...', progress = 0) {
this.overlay.style.display = 'flex'; this.overlay.style.display = 'flex';
this.setProgress(progress); this.setProgress(progress);
this.setStatus(message); this.setStatus(message);
// Remove any existing details container
this.removeDetailsContainer();
} }
hide() { hide() {
this.overlay.style.display = 'none'; this.overlay.style.display = 'none';
this.reset(); this.reset();
this.removeDetailsContainer();
} }
setProgress(percent) { setProgress(percent) {
@@ -29,6 +34,101 @@ export class LoadingManager {
reset() { reset() {
this.setProgress(0); this.setProgress(0);
this.setStatus(''); this.setStatus('');
this.removeDetailsContainer();
}
// Create a details container for enhanced progress display
createDetailsContainer() {
// Remove existing container if any
this.removeDetailsContainer();
// Create new container
this.detailsContainer = document.createElement('div');
this.detailsContainer.className = 'progress-details-container';
// Insert after the main progress bar
const loadingContent = this.overlay.querySelector('.loading-content');
if (loadingContent) {
loadingContent.appendChild(this.detailsContainer);
}
return this.detailsContainer;
}
// Remove details container
removeDetailsContainer() {
if (this.detailsContainer) {
this.detailsContainer.remove();
this.detailsContainer = null;
}
}
// Show enhanced progress for downloads
showDownloadProgress(totalItems = 1) {
this.show('Preparing download...', 0);
// Create details container
const detailsContainer = this.createDetailsContainer();
// Create current item progress
const currentItemContainer = document.createElement('div');
currentItemContainer.className = 'current-item-progress';
const currentItemLabel = document.createElement('div');
currentItemLabel.className = 'current-item-label';
currentItemLabel.textContent = 'Current file:';
const currentItemBar = document.createElement('div');
currentItemBar.className = 'current-item-bar-container';
const currentItemProgress = document.createElement('div');
currentItemProgress.className = 'current-item-bar';
currentItemProgress.style.width = '0%';
const currentItemPercent = document.createElement('span');
currentItemPercent.className = 'current-item-percent';
currentItemPercent.textContent = '0%';
currentItemBar.appendChild(currentItemProgress);
currentItemContainer.appendChild(currentItemLabel);
currentItemContainer.appendChild(currentItemBar);
currentItemContainer.appendChild(currentItemPercent);
// Create overall progress elements if multiple items
let overallLabel = null;
if (totalItems > 1) {
overallLabel = document.createElement('div');
overallLabel.className = 'overall-progress-label';
overallLabel.textContent = `Overall progress (0/${totalItems} complete):`;
detailsContainer.appendChild(overallLabel);
}
// Add current item progress to container
detailsContainer.appendChild(currentItemContainer);
// Return update function
return (currentProgress, currentIndex = 0, currentName = '') => {
// Update current item progress
currentItemProgress.style.width = `${currentProgress}%`;
currentItemPercent.textContent = `${Math.floor(currentProgress)}%`;
// Update current item label if name provided
if (currentName) {
currentItemLabel.textContent = `Downloading: ${currentName}`;
}
// Update overall label if multiple items
if (totalItems > 1 && overallLabel) {
overallLabel.textContent = `Overall progress (${currentIndex}/${totalItems} complete):`;
// Calculate and update overall progress
const overallProgress = Math.floor((currentIndex + currentProgress/100) / totalItems * 100);
this.setProgress(overallProgress);
} else {
// Single item, just update main progress
this.setProgress(currentProgress);
}
};
} }
async showWithProgress(callback, options = {}) { async showWithProgress(callback, options = {}) {