fix: upload failure, share dialog, shared view styling, dark mode fixes

- Fix 'folder_id is required' upload error by adding create_home_folder
  through the full hexagonal architecture (trait, service, repository, auth)
- Fix double upload issue with _isUploading concurrency guard
- Fix Share context menu doing nothing (ID collision between sharedView
  and main share dialog resolved with sv- prefix)
- Fix Compartidos tab duplicate headers and broken layout
- Add missing .shared-dialog CSS with dark mode support
- Fix dark mode white backgrounds on empty-state, shared-filters,
  trash-actions, action-btn, and header
- Fix i18n key mismatches in sharedView
- Bump version to 0.4.1

Closes #120
This commit is contained in:
Dionisio
2026-02-16 16:18:39 +01:00
parent b7bd656a43
commit f70890e884
14 changed files with 524 additions and 271 deletions
+88 -76
View File
@@ -23,6 +23,7 @@ const fileOps = {
// Upload progress — notification bell integration
// ========================================================================
_currentBatchId: null,
_isUploading: false, // Guard against concurrent upload calls
/** Start a new upload batch in the notification bell */
_initUploadToast(totalFiles) {
@@ -103,86 +104,97 @@ const fileOps = {
const totalFiles = files.length;
if (totalFiles === 0) return;
// Legacy progress bar (inside dropzone) — keep working for drag-drop
const progressBar = document.querySelector('.progress-fill');
const uploadProgressDiv = document.querySelector('.upload-progress');
if (uploadProgressDiv) { uploadProgressDiv.style.display = 'block'; }
if (progressBar) { progressBar.style.width = '0%'; }
// Show upload notification
this._initUploadToast(totalFiles);
const batchId = this._currentBatchId;
let uploadedCount = 0;
let successCount = 0;
for (let i = 0; i < totalFiles; i++) {
const file = files[i];
const formData = new FormData();
const targetFolderId = window.app.currentPath || window.app.userHomeFolderId;
if (targetFolderId) formData.append('folder_id', targetFolderId);
formData.append('file', file);
console.log(`Uploading file to folder: ${targetFolderId || 'root'}`, {
file: file.name, size: file.size
});
const result = await this._uploadFileXHR(formData, batchId, file.name);
uploadedCount++;
// Legacy dropzone bar
if (progressBar) {
progressBar.style.width = ((uploadedCount / totalFiles) * 100) + '%';
}
// Notify bell of per-file completion
if (window.notifications && batchId) {
window.notifications.fileCompleted(batchId, result.ok);
}
if (result.ok) {
successCount++;
console.log(`Successfully uploaded ${file.name}`, result.data);
} else {
console.error(`Upload error for ${file.name}`);
if (result.isQuotaError) {
const msg = result.errorMsg || window.i18n?.t('storage_quota_exceeded') || 'Storage quota exceeded';
if (window.notifications) {
window.notifications.addNotification({
icon: 'fa-exclamation-triangle',
iconClass: 'error',
title: file.name,
text: msg
});
}
break;
}
}
}
// All done
this._finishUploadToast(successCount, totalFiles);
// Wait for backend to persist, then reload
await new Promise(resolve => setTimeout(resolve, 800));
// Refresh storage usage display
if (typeof window.refreshUserData === 'function') {
try { await window.refreshUserData(); } catch (_) {}
// Guard: prevent concurrent upload calls (e.g. double drop events)
if (this._isUploading) {
console.warn('Upload already in progress, ignoring duplicate call');
return;
}
this._isUploading = true;
try {
await window.loadFiles({ forceRefresh: true });
} catch (reloadError) {
console.error('Error reloading files:', reloadError);
}
// Legacy progress bar (inside dropzone) — keep working for drag-drop
const progressBar = document.querySelector('.progress-fill');
const uploadProgressDiv = document.querySelector('.upload-progress');
if (uploadProgressDiv) { uploadProgressDiv.style.display = 'block'; }
if (progressBar) { progressBar.style.width = '0%'; }
setTimeout(() => {
const dropzone = document.getElementById('dropzone');
if (dropzone) dropzone.style.display = 'none';
if (uploadProgressDiv) uploadProgressDiv.style.display = 'none';
}, 500);
// Show upload notification
this._initUploadToast(totalFiles);
const batchId = this._currentBatchId;
let uploadedCount = 0;
let successCount = 0;
for (let i = 0; i < totalFiles; i++) {
const file = files[i];
const formData = new FormData();
const targetFolderId = window.app.currentPath || window.app.userHomeFolderId;
if (targetFolderId) formData.append('folder_id', targetFolderId);
formData.append('file', file);
console.log(`Uploading file to folder: ${targetFolderId || 'root'}`, {
file: file.name, size: file.size
});
const result = await this._uploadFileXHR(formData, batchId, file.name);
uploadedCount++;
// Legacy dropzone bar
if (progressBar) {
progressBar.style.width = ((uploadedCount / totalFiles) * 100) + '%';
}
// Notify bell of per-file completion
if (window.notifications && batchId) {
window.notifications.fileCompleted(batchId, result.ok);
}
if (result.ok) {
successCount++;
console.log(`Successfully uploaded ${file.name}`, result.data);
} else {
console.error(`Upload error for ${file.name}`);
if (result.isQuotaError) {
const msg = result.errorMsg || window.i18n?.t('storage_quota_exceeded') || 'Storage quota exceeded';
if (window.notifications) {
window.notifications.addNotification({
icon: 'fa-exclamation-triangle',
iconClass: 'error',
title: file.name,
text: msg
});
}
break;
}
}
}
// All done
this._finishUploadToast(successCount, totalFiles);
// Wait for backend to persist, then reload
await new Promise(resolve => setTimeout(resolve, 800));
// Refresh storage usage display
if (typeof window.refreshUserData === 'function') {
try { await window.refreshUserData(); } catch (_) {}
}
try {
await window.loadFiles({ forceRefresh: true });
} catch (reloadError) {
console.error('Error reloading files:', reloadError);
}
setTimeout(() => {
const dropzone = document.getElementById('dropzone');
if (dropzone) dropzone.style.display = 'none';
if (uploadProgressDiv) uploadProgressDiv.style.display = 'none';
}, 500);
} finally {
this._isUploading = false;
}
},
/**