feat(frontend): confirm before deleting folders, with multi-select for bulk cleanup - #1426
feat(frontend): confirm before deleting folders, with multi-select for bulk cleanup#1426prawnsgupta wants to merge 3 commits into
Conversation
Deleting a folder from Folder Management happened the moment the trash icon was clicked, so a misclick permanently removed the folder along with its tags, faces and indexing data. Deletion now goes through the shared ConfirmDialog. The confirmation names the folder, states that it cannot be undone, and makes clear that the photos themselves stay on disk, since deletion only clears the library entry and its cascaded rows rather than touching the filesystem. Folders can also be selected with checkboxes and removed together through a single "Delete selected (N)" confirmation, so clearing out a directory tree does not mean dismissing one dialog per folder. Select all is scoped to the folders currently on screen so "View More" cannot silently widen the selection. The delete mutation now takes a list of ids and sends them in one request, which the /folders/delete-folders endpoint already supported. The success dialog that used to appear after a deletion is gone: the user has just confirmed the action and the folders disappear from the list, so a second modal only added a click. Errors are still reported. The icon-only delete button also gains an aria-label, so it has an accessible name and the confirmation can be reached by keyboard and screen reader. Adds tests covering both flows: that clicking delete confirms rather than deleting, that cancelling deletes nothing, that the right folder is removed, and that a bulk confirmation deletes every selected folder in a single call.
WalkthroughFolder deletion now requires confirmation, supports selecting multiple folders, and sends selected folder IDs through a batch deletion hook. Tests cover single-folder and bulk deletion, cancellation, reopening, selection counts, and select-all behavior. ChangesFolder deletion flow
Estimated code review effort: 4 (Complex) | ~45 minutes Suggested labels: Sequence Diagram(s)sequenceDiagram
participant FolderManagementCard
participant ConfirmDialog
participant useFolderOperations
FolderManagementCard->>ConfirmDialog: Open deletion confirmation
ConfirmDialog->>FolderManagementCard: Confirm selected folder IDs
FolderManagementCard->>useFolderOperations: deleteFolders(folderIds)
useFolderOperations->>FolderManagementCard: Expose deleteFoldersPending state
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@prawnsgupta Could you upload the demo video to the PR instead of the issue's comment section? It'll make the review process much easier. |
|
Please resolve the merge conflicts before review. Your PR will only be reviewed by a maintainer after all conflicts have been resolved. 📺 Watch this video to understand why conflicts occur and how to resolve them: |
Reconcile the folder delete-confirmation UI with the indexing-status work that landed on main: rows now use isIndexingPending() and show the new "interrupted" badge, while keeping the multi-select and single batch confirm dialog from this branch.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
frontend/src/components/__tests__/FolderManagementCard.test.tsx (2)
1-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTest file sits under
components/__tests__but exercises a page component.Consider
frontend/src/pages/SettingsPage/components/__tests__/FolderManagementCard.test.tsxso the test lives next to its subject.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/__tests__/FolderManagementCard.test.tsx` around lines 1 - 3, Move the FolderManagementCard test from the generic components test directory into the SettingsPage/components/__tests__ directory alongside the FolderManagementCard subject, preserving its existing imports and test behavior.
17-21: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the visible-scoping guarantee of "Select all".
With only 3 mock folders and a default
visibleFoldersCountof 6, every folder is always visible, so the branch that keeps hidden folders out of the selection is never exercised — precisely the behavior the PR calls out. A fixture of 7+ folders plus a "View More" case would lock it in.Also applies to: 217-232
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/__tests__/FolderManagementCard.test.tsx` around lines 17 - 21, Add test coverage in FolderManagementCard tests for the Select all behavior when more than the default visibleFoldersCount of 6 folders exist. Expand the mockFolders fixture to at least 7 folders and add a View More scenario verifying Select all selects only currently visible folders while hidden folders remain unselected.frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx (1)
96-101: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDeduplicate the deletion copy.
Both branches repeat the same trailing warning verbatim; only the subject differs.
♻️ Optional refactor
const deletionDescription = () => { - if (foldersToDelete.length === 1) { - return `"${foldersToDelete[0].folder_path}" will be removed from your library along with its tags and indexing data. This cannot be undone, though the photos themselves stay on your disk.`; - } - return `${foldersToDelete.length} folders will be removed from your library along with their tags and indexing data. This cannot be undone, though the photos themselves stay on your disk.`; + const subject = + foldersToDelete.length === 1 + ? `"${foldersToDelete[0].folder_path}" will be removed from your library along with its tags and indexing data.` + : `${foldersToDelete.length} folders will be removed from your library along with their tags and indexing data.`; + return `${subject} This cannot be undone, though the photos themselves stay on your disk.`; };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx` around lines 96 - 101, Update deletionDescription to build the differing folder subject separately, then append one shared warning message for both the single-folder and multiple-folder cases. Preserve the existing wording and singular/plural subjects.frontend/src/hooks/useFolderOperations.tsx (1)
133-133: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRename
deleteFolderMutationto match its batch semantics.The mutation, handler, and exposed state are all plural now; the singular variable name is the only leftover.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/hooks/useFolderOperations.tsx` at line 133, Rename deleteFolderMutation to its plural batch-semantics name throughout the mutation declaration, handlers, and exposed state in the surrounding folder operations hook, preserving all existing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx`:
- Around line 111-120: Update the “Select all” control in FolderManagementCard
so its label explicitly indicates it applies only to visible folders when
folders exceed visibleFoldersCount, while retaining “Select all” wording. Set
the checkbox’s indeterminate state when some, but not all, visible folders are
selected, and keep checked tied to allVisibleSelected. Use the existing
selection state and toggleSelectAllVisible behavior.
---
Nitpick comments:
In `@frontend/src/components/__tests__/FolderManagementCard.test.tsx`:
- Around line 1-3: Move the FolderManagementCard test from the generic
components test directory into the SettingsPage/components/__tests__ directory
alongside the FolderManagementCard subject, preserving its existing imports and
test behavior.
- Around line 17-21: Add test coverage in FolderManagementCard tests for the
Select all behavior when more than the default visibleFoldersCount of 6 folders
exist. Expand the mockFolders fixture to at least 7 folders and add a View More
scenario verifying Select all selects only currently visible folders while
hidden folders remain unselected.
In `@frontend/src/hooks/useFolderOperations.tsx`:
- Line 133: Rename deleteFolderMutation to its plural batch-semantics name
throughout the mutation declaration, handlers, and exposed state in the
surrounding folder operations hook, preserving all existing behavior.
In `@frontend/src/pages/SettingsPage/components/FolderManagementCard.tsx`:
- Around line 96-101: Update deletionDescription to build the differing folder
subject separately, then append one shared warning message for both the
single-folder and multiple-folder cases. Preserve the existing wording and
singular/plural subjects.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 2096e026-1fb1-442c-8a73-291c1613d0c7
📒 Files selected for processing (3)
frontend/src/components/__tests__/FolderManagementCard.test.tsxfrontend/src/hooks/useFolderOperations.tsxfrontend/src/pages/SettingsPage/components/FolderManagementCard.tsx
It only spans folders currently on screen, so relabel it "Select all shown" and show an indeterminate state when some but not all visible folders are selected, instead of an empty checkbox.
Fixes #939
The problem
Deleting a folder in Settings → Folder Management happens the instant the trash icon is clicked. There is no warning and no way back — the folder row, its images, and their tags and face data are removed together (
imagesandimage_classesboth cascade offfolders), so a single misclick costs the whole indexing pass for that folder.Following up on the review of #955
@rahulharpal1603 — this takes the direction you laid out when you reviewed #955, rather than the plain per-folder dialog that PR used. Your two objections were:
/folders/delete-foldersendpoint already accepted a list of ids, so this needed no backend change; the mutation now passes the whole selection in a single request.useMutationFeedbackdefaultsshowSuccess: trueand dispatchesshowInfoDialog, so deleting currently pops a "Folder Deleted" modal. With an explicit confirmation in front and the rows disappearing from the list, that success modal is now switched off for deletion. Errors are still surfaced. This is a one-line change if you would rather keep it.What it does
ConfirmDialogwithdestructivestyling.Demo
screen-recording-2026-07-27-162914_k8weeNKP.mp4
Notes for review
checkboxprimitive incomponents/uiand@radix-ui/react-checkboxis not installed, so the selection boxes are native<input type="checkbox">styled with the existing tokens. Happy to add the Radix primitive instead if you would prefer the consistency.aria-label, which is also what the tests select it by.deleteFolder(id)becamedeleteFolders(ids)inuseFolderOperations.FolderManagementCardwas its only consumer, so nothing else needed touching.Tests
Added
frontend/src/components/__tests__/FolderManagementCard.test.tsx— 15 tests over both flows: that clicking delete confirms instead of deleting, that cancelling deletes nothing, that the folder actually clicked is the one removed, that the confirmation can be reopened, and for bulk, that the count is right, that the button appears and disappears with the selection, and that confirming removes every selected folder in a single call.Verified they catch the original bug: restoring the immediate-delete
onClickfails 6 of them.Frontend suite green,
tsc --noEmit, ESLint and Prettier all clean. Merged latestmainto clear the conflict — the delete-confirmation rows now sit on top of the new indexing-status states (isIndexingPending, theinterruptedbadge), reconciled inFolderManagementCard.@rohan-pandeyy let me know for any other changes, if not feel free to merge the PR.