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;
}
/* 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 {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
@@ -63,7 +110,8 @@
@media (prefers-reduced-motion: reduce) {
.lora-card,
.progress-bar {
.progress-bar,
.current-item-bar {
transition: none;
}
}

View File

@@ -270,19 +270,37 @@ export class DownloadManager {
throw new Error('No download URL available');
}
// Show loading with progress bar for download
this.loadingManager.show('Downloading LoRA...', 0);
// Show enhanced loading with progress details
const updateProgress = this.loadingManager.showDownloadProgress(1);
updateProgress(0, 0, this.currentVersion.name);
// Setup WebSocket for progress updates
const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
const ws = new WebSocket(`${wsProtocol}${window.location.host}/ws/fetch-progress`);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.status === 'progress') {
this.loadingManager.setProgress(data.progress);
this.loadingManager.setStatus(`Downloading: ${data.progress}%`);
// Update progress display with current 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
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 ws = new WebSocket(`${wsProtocol}${window.location.host}/ws/fetch-progress`);
// Download missing LoRAs sequentially
this.loadingManager.show('Downloading LoRAs...', 0);
// Show enhanced loading with progress details for multiple items
const updateProgress = this.loadingManager.showDownloadProgress(this.missingLoras.length);
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++) {
const lora = this.missingLoras[i];
// Update overall progress
this.loadingManager.setStatus(`Downloading LoRA ${i+1}/${this.missingLoras.length}: ${lora.name}`);
// Reset current LoRA progress for new download
currentLoraProgress = 0;
// Set up progress tracking for current download
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
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);
}
};
// Initial status update for new LoRA
this.loadingManager.setStatus(`Starting download for LoRA ${i+1}/${this.missingLoras.length}`);
updateProgress(0, completedDownloads, lora.name);
try {
// Download the LoRA
@@ -547,6 +576,15 @@ export class ImportManager {
// Continue with next download
} else {
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) {
console.error(`Error downloading LoRA ${lora.name}:`, downloadError);

View File

@@ -4,17 +4,22 @@ export class LoadingManager {
this.overlay = document.getElementById('loading-overlay');
this.progressBar = this.overlay.querySelector('.progress-bar');
this.statusText = this.overlay.querySelector('.loading-status');
this.detailsContainer = null; // Will be created when needed
}
show(message = 'Loading...', progress = 0) {
this.overlay.style.display = 'flex';
this.setProgress(progress);
this.setStatus(message);
// Remove any existing details container
this.removeDetailsContainer();
}
hide() {
this.overlay.style.display = 'none';
this.reset();
this.removeDetailsContainer();
}
setProgress(percent) {
@@ -29,6 +34,101 @@ export class LoadingManager {
reset() {
this.setProgress(0);
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 = {}) {