fix(inline-viewer): add download progress bar for files >2GB
Add download progress tracking to createBlobUrlViewer to fix incorrect progress display for large files. Changes: - Add xhr.onprogress handler to track download bytes - Use 64-bit float division to avoid 32-bit integer overflow - Show progress bar UI for files >10MB with percentage - Add CSS styles with dark theme support The progress calculation now correctly handles files larger than 2GB by using JavaScript's native double-precision floats instead of operations that might truncate to 32-bit integers. Fixes #82
This commit is contained in:
@@ -171,6 +171,56 @@
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* Download progress container */
|
||||
.inline-viewer-progress {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Progress bar track */
|
||||
.inline-viewer-progress-bar {
|
||||
width: 200px;
|
||||
height: 8px;
|
||||
background: #e2e8f0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Progress bar fill */
|
||||
.inline-viewer-progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #3b82f6, #60a5fa);
|
||||
border-radius: 4px;
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
|
||||
/* Progress percentage text */
|
||||
.inline-viewer-progress-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #475569;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
/* Dark theme support */
|
||||
[data-theme="dark"] .inline-viewer-progress {
|
||||
background: rgba(30, 41, 59, 0.95);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .inline-viewer-progress-bar {
|
||||
background: #334155;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .inline-viewer-progress-text {
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
/* Error and unsupported message */
|
||||
.inline-viewer-message {
|
||||
padding: 32px;
|
||||
|
||||
@@ -251,13 +251,42 @@ class InlineViewer {
|
||||
async createBlobUrlViewer(file, type, container, loader) {
|
||||
try {
|
||||
console.log('Creating blob URL viewer for:', file.name, 'type:', type);
|
||||
|
||||
|
||||
// Update loader to show progress bar for large files
|
||||
let progressBar = null;
|
||||
let progressText = null;
|
||||
if (loader && file.size > 10 * 1024 * 1024) { // Show progress for files > 10MB
|
||||
loader.innerHTML = `
|
||||
<div class="inline-viewer-progress">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<div class="inline-viewer-progress-bar">
|
||||
<div class="inline-viewer-progress-fill" style="width: 0%"></div>
|
||||
</div>
|
||||
<div class="inline-viewer-progress-text">0%</div>
|
||||
</div>
|
||||
`;
|
||||
progressBar = loader.querySelector('.inline-viewer-progress-fill');
|
||||
progressText = loader.querySelector('.inline-viewer-progress-text');
|
||||
}
|
||||
|
||||
// Use XMLHttpRequest instead of fetch to get better control over the response
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', `/api/files/${file.id}?inline=true`, true);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.withCredentials = true;
|
||||
|
||||
|
||||
// Track download progress - use double precision for large file support (>2GB)
|
||||
xhr.onprogress = (e) => {
|
||||
if (e.lengthComputable && progressBar && progressText) {
|
||||
// Use direct division to avoid 32-bit overflow issues
|
||||
// e.loaded and e.total are JavaScript numbers (64-bit float)
|
||||
const progress = e.loaded / e.total;
|
||||
const pct = Math.round(progress * 100);
|
||||
progressBar.style.width = pct + '%';
|
||||
progressText.textContent = pct + '%';
|
||||
}
|
||||
};
|
||||
|
||||
// Create a promise to handle the XHR
|
||||
const response = await new Promise((resolve, reject) => {
|
||||
xhr.onload = function() {
|
||||
@@ -267,11 +296,11 @@ class InlineViewer {
|
||||
reject(new Error(`Error fetching file: ${this.status} ${this.statusText}`));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
xhr.onerror = function() {
|
||||
reject(new Error('Network error'));
|
||||
};
|
||||
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user