fix file batch deletion

This commit is contained in:
2025-05-28 12:09:56 +02:00
parent 9b98370989
commit 552d1feb2e
6 changed files with 178 additions and 22 deletions

View File

@@ -304,7 +304,7 @@
}
.progress-bar {
background-color: #16767b !important;
color: #fff !important;
background-color: var(--primary-color) !important;
color: white !important;
transition: background-color 0.2s;
}

View File

@@ -227,6 +227,16 @@ export class FileManager {
return;
}
// Filter out folders and get only file IDs
const fileIds = selectedItems
.filter(item => item.type !== 'folder')
.map(item => item.id);
if (fileIds.length === 0) {
console.log('[FileManager] No files to download (only folders selected)');
return;
}
try {
const response = await fetch(`/api/rooms/${this.roomManager.roomId}/files/download`, {
method: 'POST',
@@ -234,7 +244,7 @@ export class FileManager {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({ file_ids: selectedItems.map(item => item.id) })
body: JSON.stringify({ file_ids: fileIds })
});
console.log('[FileManager] Download response status:', response.status);
@@ -256,6 +266,7 @@ export class FileManager {
console.log('[FileManager] Download initiated');
} catch (error) {
console.error('[FileManager] Error downloading files:', error);
document.getElementById('fileError').textContent = 'Failed to download files. Please try again.';
throw error;
}
}
@@ -322,14 +333,63 @@ export class FileManager {
}
}
updateSelection(index, event) {
console.log('[FileManager] Updating selection:', { index, event });
// Prevent selection if clicking on a checkbox or action button
if (event.target.classList.contains('select-item-checkbox') || event.target.closest('.file-action-btn')) {
return;
}
const checkboxes = document.querySelectorAll('.select-item-checkbox');
const checkbox = checkboxes[index];
if (!checkbox) return;
if (event.ctrlKey) {
// CTRL + Click: Toggle individual selection
checkbox.checked = !checkbox.checked;
if (checkbox.checked) {
this.selectedItems.add(index);
} else {
this.selectedItems.delete(index);
}
} else if (event.shiftKey && this.lastSelectedIndex !== -1) {
// SHIFT + Click: Select range
const start = Math.min(this.lastSelectedIndex, index);
const end = Math.max(this.lastSelectedIndex, index);
for (let i = start; i <= end; i++) {
checkboxes[i].checked = true;
this.selectedItems.add(i);
}
} else {
// Normal click: Select single item
const wasChecked = checkbox.checked;
checkboxes.forEach(cb => {
cb.checked = false;
this.selectedItems.delete(parseInt(cb.dataset.index));
});
checkbox.checked = !wasChecked;
if (!wasChecked) {
this.selectedItems.add(index);
}
}
this.lastSelectedIndex = index;
this.roomManager.viewManager.updateMultiSelectUI();
}
getSelectedItems() {
console.log('[FileManager] Getting selected items');
return Array.from(this.selectedItems).map(index => this.currentFiles[index]);
}
updateSelection(index, event) {
console.log('[FileManager] Updating selection:', { index, event });
// Implementation of selection logic
clearSelection() {
console.log('[FileManager] Clearing selection');
this.selectedItems.clear();
this.lastSelectedIndex = -1;
const checkboxes = document.querySelectorAll('.select-item-checkbox');
checkboxes.forEach(cb => cb.checked = false);
this.roomManager.viewManager.updateMultiSelectUI();
}
navigateToParent() {

View File

@@ -65,6 +65,53 @@ export class ModalManager {
this.deleteModal.show();
}
showBatchDeleteModal() {
const selectedCheckboxes = document.querySelectorAll('.select-item-checkbox:checked');
if (selectedCheckboxes.length === 0) return;
const selectedItems = Array.from(selectedCheckboxes).map(cb => {
const idx = parseInt(cb.dataset.index);
console.log('[ModalManager] Processing checkbox with idx:', idx);
console.log('[ModalManager] Current files:', this.roomManager.fileManager.currentFiles);
if (isNaN(idx) || idx < 0 || idx >= this.roomManager.fileManager.currentFiles.length) {
console.error('[ModalManager] Invalid index:', idx);
return null;
}
const file = this.roomManager.fileManager.currentFiles[idx];
if (!file) {
console.error('[ModalManager] No file found at index:', idx);
return null;
}
console.log('[ModalManager] Found file:', file);
return {
name: file.name,
path: file.path || '',
type: file.type
};
}).filter(item => item !== null); // Remove any null items
if (selectedItems.length === 0) {
console.error('[ModalManager] No valid items selected for deletion');
return;
}
// Update modal content
const fileNameEl = document.getElementById('deleteFileName');
const labelEl = document.getElementById('deleteConfirmLabel');
if (fileNameEl) fileNameEl.textContent = `${selectedItems.length} item${selectedItems.length > 1 ? 's' : ''}`;
if (labelEl) labelEl.textContent = 'Move to Trash';
// Store the items to delete in the FileManager
this.roomManager.fileManager.batchDeleteItems = selectedItems;
// Show the modal
this.deleteModal.show();
}
showRenameModal(filename) {
document.getElementById('renameError').textContent = '';
const ext = filename.includes('.') ? filename.substring(filename.lastIndexOf('.')) : '';

View File

@@ -74,7 +74,46 @@ class RoomManager {
initializeEventListeners() {
console.log('[RoomManager] Setting up event listeners');
// Add any global event listeners here
// Add event listener for select all checkbox
const selectAllCheckbox = document.querySelector('.select-all-checkbox');
if (selectAllCheckbox) {
selectAllCheckbox.addEventListener('change', (event) => {
const checkboxes = document.querySelectorAll('.select-item-checkbox');
checkboxes.forEach((cb, index) => {
cb.checked = event.target.checked;
if (event.target.checked) {
this.fileManager.selectedItems.add(index);
} else {
this.fileManager.selectedItems.delete(index);
}
});
this.viewManager.updateMultiSelectUI();
});
}
// Add event listener for download selected button
const downloadSelectedBtn = document.getElementById('downloadSelectedBtn');
if (downloadSelectedBtn && this.canDownload) {
downloadSelectedBtn.addEventListener('click', () => {
this.fileManager.downloadSelected();
});
}
// Add event listener for delete selected button
const deleteSelectedBtn = document.getElementById('deleteSelectedBtn');
if (deleteSelectedBtn && this.canDelete) {
deleteSelectedBtn.addEventListener('click', () => {
this.modalManager.showBatchDeleteModal();
});
}
// Add event listener for clicking outside to clear selection
document.addEventListener('click', (event) => {
if (!event.target.closest('.file-card') && !event.target.closest('.file-row') && !event.target.closest('.file-action-btn')) {
this.fileManager.clearSelection();
}
});
}
}

View File

@@ -74,8 +74,7 @@ export class UploadManager {
async startUpload(files) {
this.uploadProgressContainer.style.display = 'block';
this.uploadProgressBar.style.width = '0%';
this.uploadProgressBar.classList.remove('bg-success');
this.uploadProgressBar.classList.add('bg-info');
this.uploadProgressBar.className = 'progress-bar bg-primary-opacity-15 text-primary';
this.uploadProgressText.textContent = '';
this.pendingUploads = files;
@@ -109,8 +108,7 @@ export class UploadManager {
// All files processed
this.uploadProgressBar.style.width = '100%';
this.uploadProgressBar.textContent = '100%';
this.uploadProgressBar.classList.remove('bg-info');
this.uploadProgressBar.classList.add('bg-success');
this.uploadProgressBar.className = 'progress-bar bg-success-opacity-15 text-success';
this.uploadProgressText.textContent = 'Upload complete!';
// Reset state
@@ -123,8 +121,7 @@ export class UploadManager {
setTimeout(() => {
this.uploadProgressContainer.style.display = 'none';
this.uploadProgressText.textContent = '';
this.uploadProgressBar.style.backgroundColor = '#16767b';
this.uploadProgressBar.style.color = '#fff';
this.uploadProgressBar.className = 'progress-bar bg-primary-opacity-15 text-primary';
}, 3000);
// Refresh file list
@@ -175,8 +172,7 @@ export class UploadManager {
} catch (error) {
console.error('Upload error:', error);
this.uploadProgressText.textContent = `Error uploading ${file.name}`;
this.uploadProgressBar.style.backgroundColor = '#ef4444';
this.uploadProgressBar.style.color = '#fff';
this.uploadProgressBar.className = 'progress-bar bg-danger-opacity-15 text-danger';
currentFileIndex++;
updateProgress();
await processNextFile();
@@ -226,8 +222,7 @@ export class UploadManager {
}
uploadError.style.display = 'block';
this.uploadProgressBar.style.backgroundColor = '#ef4444';
this.uploadProgressBar.style.color = '#fff';
this.uploadProgressBar.className = 'progress-bar bg-danger-opacity-15 text-danger';
}
async handleFileExists(file, formData) {

View File

@@ -127,7 +127,9 @@ export class ViewManager {
<table class="table table-hover">
<thead>
<tr>
<th style="width: 40px;"></th>
<th style="width: 40px;">
<input type="checkbox" class="form-check-input select-all-checkbox" style="margin: 0;">
</th>
<th style="width: 40px;"></th>
<th>Name</th>
<th>Size</th>
@@ -151,7 +153,14 @@ export class ViewManager {
async renderGridView(files) {
console.log('[ViewManager] Rendering grid view');
const fileGrid = document.getElementById('fileGrid');
let html = '';
let html = `
<div class="col-12 mb-3">
<div class="d-flex align-items-center">
<input type="checkbox" class="form-check-input select-all-checkbox me-2" style="margin: 0;">
<span class="text-muted">Select All</span>
</div>
</div>
`;
files.forEach((file, index) => {
console.log('[ViewManager] Rendering grid item:', file);
@@ -170,10 +179,11 @@ export class ViewManager {
const modified = new Date(file.modified).toLocaleString();
return `
<tr data-index="${index}" class="file-row" style="cursor: pointer;">
<tr data-index="${index}" class="file-row" style="cursor: pointer;" onclick="window.roomManager.fileManager.updateSelection(${index}, event)">
<td>
<input type="checkbox" class="form-check-input select-item-checkbox"
data-index="${index}" style="margin: 0;">
data-index="${index}" style="margin: 0;"
onclick="event.stopPropagation(); window.roomManager.fileManager.updateSelection(${index}, event)">
</td>
<td>
<i class="fas ${icon}" style="font-size:1.5rem;color:${isFolder ? 'var(--primary-color)' : 'var(--secondary-color)'}"></i>
@@ -201,8 +211,13 @@ export class ViewManager {
return `
<div class="col-12 col-sm-6 col-md-4 col-lg-3 mb-3">
<div class="card file-card h-100 border-0 shadow-sm position-relative" data-index="${index}">
<div class="card file-card h-100 border-0 shadow-sm position-relative" data-index="${index}" onclick="window.roomManager.fileManager.updateSelection(${index}, event)">
<div class="card-body d-flex flex-column align-items-center justify-content-center text-center p-4">
<div class="mb-2 w-100 d-flex justify-content-start">
<input type="checkbox" class="form-check-input select-item-checkbox"
data-index="${index}" style="margin: 0;"
onclick="event.stopPropagation(); window.roomManager.fileManager.updateSelection(${index}, event)">
</div>
<div class="mb-2">
<i class="fas ${icon}" style="font-size:2.5rem;color:${isFolder ? 'var(--primary-color)' : 'var(--secondary-color)'};"></i>
</div>