From db946461d7952bfdbde5c85a84db4024dd2c7c98 Mon Sep 17 00:00:00 2001 From: Elijah Date: Sat, 23 May 2026 14:11:23 -0700 Subject: [PATCH] fix: resolve upload delay and refine trash functionality --- backend/handlers/files.go | 13 ++++++ frontend/src/components/FileExplorer.tsx | 52 +++++++++++++++--------- frontend/src/lib/api.ts | 5 ++- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/backend/handlers/files.go b/backend/handlers/files.go index 67b4f1c..276bda1 100644 --- a/backend/handlers/files.go +++ b/backend/handlers/files.go @@ -534,6 +534,19 @@ func (h *FSHandler) Delete(c *fiber.Ctx) error { return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "file not found"}) } + // Check if permanent + isPermanent := c.Query("permanent") == "true" + if isPermanent { + if err := os.RemoveAll(resolvedPath); err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to permanently delete"}) + } + + cleanPath := filepath.ToSlash(relativePath) + h.DB.Exec(`DELETE FROM files WHERE path = ? OR path LIKE ?`, cleanPath, cleanPath+"/%") + h.DB.AddAuditLog("permanently_deleted", cleanPath, c.IP()) + return c.JSON(fiber.Map{"message": "permanently deleted"}) + } + // Soft-delete: move to .trash directory trashPath := filepath.Join(h.Config.TrashDir, relativePath) if err := os.MkdirAll(filepath.Dir(trashPath), 0755); err != nil { diff --git a/frontend/src/components/FileExplorer.tsx b/frontend/src/components/FileExplorer.tsx index 369b24a..9ebd9de 100644 --- a/frontend/src/components/FileExplorer.tsx +++ b/frontend/src/components/FileExplorer.tsx @@ -631,20 +631,22 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { async function executeDeleteSelected() { const count = selectedFiles.size; + const isPermanent = activeSection === 'trash'; for (const path of selectedFiles) { - await api.deleteFile(path); + await api.deleteFile(path, isPermanent); } setSelectedFiles(new Set()); loadFiles(undefined, true); setDeleteConfirm(null); - showToast(`Deleted ${count} item${count > 1 ? 's' : ''}`); + showToast(isPermanent ? `Permanently deleted ${count} item${count > 1 ? 's' : ''}` : `Deleted ${count} item${count > 1 ? 's' : ''}`); } async function executeDeleteSingle(file: FileItem) { - await api.deleteFile(file.path); + const isPermanent = activeSection === 'trash'; + await api.deleteFile(file.path, isPermanent); loadFiles(undefined, true); setDeleteConfirm(null); - showToast(`Deleted ${file.name}`); + showToast(isPermanent ? `Permanently deleted ${file.name}` : `Deleted ${file.name}`); } async function handlePin(file: FileItem) { @@ -880,16 +882,16 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { } await Promise.all(workers); + loadFiles(undefined, true); setTimeout(() => { setUploads(prev => prev.filter(u => u.id !== batchId)); - loadFiles(undefined, true); }, 3000); } async function handleDrop(e: React.DragEvent) { e.preventDefault(); setDragOver(false); - if (draggedFile) return; + if (draggedFile || activeSection === 'trash') return; if (e.dataTransfer.items) { const filesToUpload: { file: File; path: string }[] = []; @@ -968,7 +970,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { async function handleFileUpload(e: React.ChangeEvent) { const uploadFiles = e.target.files; - if (!uploadFiles) return; + if (!uploadFiles || activeSection === 'trash') return; const filesArray = Array.from(uploadFiles).map(f => ({ file: f, path: '' })); const fileNames = filesArray.map(f => f.file.name); @@ -1777,18 +1779,20 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) { > - + {activeSection !== 'trash' && ( + + )}