V1: Add owner-scoped folder pagination (list_folders_by_owner_paginated)
- New method in FolderRepository trait, PG implementation, service & handler
- Prevents IDOR by filtering folder listings to authenticated user
V2: Enforce ownership checks on folder mutations
- rename_folder, move_folder, delete_folder now require caller_id
- Service verifies folder.owner_id == caller_id (returns 404 on mismatch)
- Propagated to folder_handler, batch_handler, batch_operations, webdav_handler
- delete_folder_with_trash upgraded from OptionalAuthUser to AuthUser
- download_folder_zip now checks ownership before streaming
V3: Fix XSS in frontend via DOM APIs
- sharedView.js: innerHTML → createElement + textContent
- contextMenus.js: innerHTML → DOM construction for share dialog
Cleanup: removed unused OptionalAuthUser import, updated all stubs/mocks
- Add checkboxes to list view items (grid view already had them)
- Add 'select all' checkbox in list view header
- Add batch action bar with Delete, Move, and Download buttons
- Batch delete: moves all selected items to trash in one operation
- Batch move: reuses existing move dialog in batch mode
- Batch download: downloads each selected item
- Keyboard shortcuts: Ctrl+A (select all), Escape (deselect), Delete key
- Shift+click for range selection in both grid and list views
- Selection state synced between grid and list views
- New multiSelect.js module manages selection state and batch operations
- Add missing .confirm-dialog.active { display: flex; opacity: 1 } CSS rule.
The confirm dialog was created with display:none and the .active class
was added, but no CSS rule changed it to visible — so the user never
saw the confirmation prompt and delete appeared to do nothing.
- Capture file/folder target before closeContextMenu in delete handlers
to prevent null reference race condition (same as rename/share fix).
- Fix showShareDialog: add try-catch, null checks, prevent textContent
from destroying header icon (use span child instead)
- Capture file/folder target before closeContextMenu to prevent race
- createSharedLink now calls real backend POST /api/shares instead of
localStorage-only mock (still caches locally for offline compat)
- Fix share_handler.rs: use OptionalAuthUser instead of AuthUser to
prevent 401 when auth is disabled (same pattern as delete/trash)
- Add null-safety to closeShareDialog
- Reset new-share-section on dialog open
- Fix rename: context menu was nullifying target reference before rename dialog could use it
- Fix delete files/folders: auth extractors were mandatory, causing 401 when auth not configured
- Fix view-file: async fetch race condition with context menu cleanup
- Fix orphaned ID mappings on file deletion
- Fix Authorization: Bearer null headers sent without token
- Add OptionalUserId and OptionalAuthUser infallible extractors
- Fix file viewer not sending JWT auth tokens when loading files
- inlineViewer.js: already used XHR with auth (images/PDFs worked)
- fileViewer.js: was setting img.src/iframe.src directly without auth headers,
now uses fetch with Bearer token and blob URLs
- ui.js/contextMenus.js/fileRenderer.js/recent.js/favorites.js: replaced all
window.location.href = /api/files/... (unauthenticated navigation) with
authenticated viewer or fileOps.downloadFile()
- Add text file viewing support (text/*, application/json, etc.)
- New createTextViewer() in inlineViewer.js with authenticated fetch
- New loadTextViewer() in fileViewer.js with authenticated fetch
- New isViewableFile() helper in ui.js used across all entry points
- CSS styles for .inline-viewer-text-content and .file-viewer-text-content
- Translate remaining Spanish strings to English in viewer files
Fixes: text files showing 'Token not provided', images failing to load,
and text files not being previewable at all.