Skip to content

feat: Trash clear function#14455

Open
man-of-fox wants to merge 24 commits intotoeverything:canaryfrom
man-of-fox:canary-trash-clear-function
Open

feat: Trash clear function#14455
man-of-fox wants to merge 24 commits intotoeverything:canaryfrom
man-of-fox:canary-trash-clear-function

Conversation

@man-of-fox
Copy link
Copy Markdown

@man-of-fox man-of-fox commented Feb 16, 2026

Added a new “Empty Trash” feature in two places:

  • In the left sidebar menu, the Trash item now shows a hover ... menu with an “Empty Trash” action.
  • On the Trash page header (top-right), there is now a dedicated Empty Trash button.

Both actions open a confirmation dialog and then permanently delete all items in Trash.

Summary by CodeRabbit

  • New Features
    • Added a permanent-delete option to the Trash button via a dropdown, with permission checks, confirmation flow, and a success toast.
    • Added an "Empty Trash" action on the Trash page to bulk-permanently delete trashed items; action is enabled/disabled based on permissions and contents.
  • Style
    • Rounded-corner styling for the empty-trash button.
  • Documentation
    • Added localization keys for "Empty trash" (EN/DE).

Screenshot to visualize the changes:
Changes on left menu bar trash icon (the 3 dots only shown on mouse over, like in folder view):
Bildschirmfoto 2026-02-18 um 12 00 30
On click at "Empty trash" the following dialog is shown:
Bildschirmfoto 2026-02-18 um 12 00 53

Changes in Trash page (see icon on the right side):
Bildschirmfoto 2026-02-18 um 12 03 20
On click at the icon the same dialog as above is shown:
Bildschirmfoto 2026-02-18 um 12 04 14

quickinfo on mouse over the icon in trash page:
Bildschirmfoto 2026-02-18 um 12 11 55

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an "Empty trash" action: a postfix menu on TrashButton and an inline button on TrashPage that confirm and permanently delete trashed documents, using trashDocs$, permission checks, permanentlyDeletePage, a success toast, i18n keys, and a small button style.

Changes

Cohort / File(s) Summary
Trash UI & logic
packages/frontend/core/src/components/root-app-sidebar/trash-button.tsx, packages/frontend/core/src/desktop/pages/workspace/trash-page.tsx
Adds a postfix Menu (MoreHorizontalIcon) and an inline DeletePermanentlyIcon action to trigger "Empty trash". Subscribes to trashDocs$, introduces menuOpen state, performs permission checks, shows confirmation modal, calls permanentlyDeletePage per trashed doc, and displays a success toast.
Styles
packages/frontend/core/src/desktop/pages/workspace/trash-page.css.ts
Exports new emptyTrashButton style with borderRadius: '8px'.
Internationalization
packages/frontend/i18n/src/resources/en.json, packages/frontend/i18n/src/resources/de.json
Adds translation key com.affine.workspaceSubPath.trash.empty with values "Empty trash" (en) and "Papierkorb leeren" (de).

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as "Trash Button / Trash Page"
    participant Docs as "DocsService (trashDocs$)"
    participant Confirm as "Confirmation Modal"
    participant Deleter as "permanentlyDeletePage"
    participant Toast as "Toast Notification"

    User->>UI: open menu or click empty action
    UI->>Docs: read current trashed docs
    UI->>Confirm: open confirmation dialog
    Confirm->>User: display confirmation
    User->>Confirm: confirm deletion
    Confirm-->>UI: confirmed
    UI->>Deleter: call permanentlyDeletePage for each doc
    Deleter->>Deleter: perform permanent deletions
    UI->>Toast: show success message
    Toast-->>User: display notification
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped to the menu with a twitchy grin,

I nudged the button, said "let tidy begin",
A confirm, a sweep, the scraps all gone,
The burrow gleams at the rise of the dawn,
Hooray — empty trash, a carrot-for-one!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into canary
Title check ✅ Passed The title 'feat: Trash clear function' directly summarizes the main change—adding an empty/clear trash feature to the application.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can disable sequence diagrams in the walkthrough.

Disable the reviews.sequence_diagrams setting to disable sequence diagrams in the walkthrough.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/frontend/core/src/desktop/pages/workspace/trash-page.tsx (1)

28-55: ⚠️ Potential issue | 🟠 Major

Empty trash button is not gated by admin/owner permissions.

The DocsExplorer below (lines 210-214) conditionally hides delete/restore actions for non-admin/non-owner users, but the "Empty Trash" button in TrashHeader is always visible. A non-privileged user could permanently delete all trashed docs.

Consider applying the same permission guard:

🛡️ Proposed fix

In TrashPage, pass the permission check to TrashHeader:

 <TrashHeader
   onEmptyTrash={onEmptyTrash}
-  disableEmptyTrash={trashDocs.length === 0}
+  disableEmptyTrash={trashDocs.length === 0 || (!isAdmin && !isOwner)}
 />
🤖 Fix all issues with AI agents
In `@packages/frontend/core/src/components/root-app-sidebar/trash-button.tsx`:
- Around line 36-55: Add a permission guard and make the confirm title
consistent: inside handleEmptyTrash, before opening the modal check
guardService.can('Doc_Trash', { workspaceId: workspace.id }) (or the same guard
call used in the drop-to-trash handler) and early-return or show a
permission-error if false; update the openConfirmModal title to use
t['com.affine.trashOperation.deletePermanently']() so it matches trash-page.tsx;
keep the existing onConfirm body (workspace.docCollection.removeDoc for each doc
and toast) but only invoke the modal when the guard passes.
- Around line 48-51: The trash-button uses
workspace.docCollection.removeDoc(doc.id) whereas trash-page uses the helper
permanentlyDeletePage from useBlockSuiteMetaHelper; change the onConfirm handler
to call permanentlyDeletePage for each doc in trashDocs (e.g., map or forEach
over trashDocs invoking permanentlyDeletePage(doc.id)) instead of
workspace.docCollection.removeDoc, and remove the now-unneeded WorkspaceService
import if nothing else uses it so both components use the same deletion API.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/frontend/core/src/components/root-app-sidebar/trash-button.tsx`:
- Around line 63-68: The onConfirm handler calls permanentlyDeletePage for each
item in trashDocs with no error handling; make onConfirm async and wrap the
deletion logic in a try/catch (or use Promise.allSettled and check results) so
any thrown errors are caught, show a user-friendly error toast (consistent with
the drag-to-trash handler’s UserFriendlyError pattern) on failure, and only call
toast(t['com.affine.toastMessage.permanentlyDeleted']()) when all deletions
succeed; reference the onConfirm handler, trashDocs, permanentlyDeletePage, and
toast when updating the code.
- Around line 40-47: The permission check currently uses
guardService.can('Doc_Trash', doc.id) for items in trashDocs before calling
permanentlyDeletePage(); update the check to use guardService.can('Doc_Delete',
doc.id) instead so permanent deletions require the correct permission, leaving
the rest of the flow (Promise.all over trashDocs, the toast call
t['com.affine.no-permission'](), and the early return) unchanged.

man-of-fox and others added 2 commits February 16, 2026 03:32
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
packages/frontend/core/src/desktop/pages/workspace/trash-page.tsx (3)

153-155: Consider using a distinct confirmation message for "Empty Trash".

onEmptyTrash reuses onConfirmPermanentlyDelete, which shows a generic "delete permanently?" dialog. For a bulk "empty entire trash" action, users would benefit from a more explicit message (e.g., mentioning the count of items or that all trashed items will be removed). This reduces the risk of accidental data loss.


199-202: Two different data sources drive "empty" state vs. button disabled state.

disableEmptyTrash is based on trashDocs.length (from DocsService), while isEmpty (line 94-96) is derived from groups (from CollectionRulesService). These could momentarily disagree — e.g., the button could be enabled while the list appears empty, or vice versa. Consider unifying on one source, or at minimum be aware of the transient inconsistency.


112-120: Add error handling to handleMultiDelete to prevent partial failures on bulk delete.

permanentlyDeletePage calls workspace.docCollection.removeDoc(), which throws BlockSuiteError if a document cannot be found. In handleMultiDelete, the forEach loop has no error handling, so if any deletion throws, the loop breaks and remaining items skip silently—yet the success toast still fires. This is inconsistent with trash-button.tsx (lines 64–73), which wraps the same operation in try-catch.

Proposed improvement
   const handleMultiDelete = useCallback(
     (ids: string[]) => {
-      ids.forEach(pageId => {
-        permanentlyDeletePage(pageId);
-      });
-      toast(t['com.affine.toastMessage.permanentlyDeleted']());
+      const failed: string[] = [];
+      ids.forEach(pageId => {
+        try {
+          permanentlyDeletePage(pageId);
+        } catch {
+          failed.push(pageId);
+        }
+      });
+      if (failed.length > 0) {
+        toast(`Failed to delete ${failed.length} item(s)`);
+      } else {
+        toast(t['com.affine.toastMessage.permanentlyDeleted']());
+      }
     },
     [permanentlyDeletePage, t]
   );

@man-of-fox
Copy link
Copy Markdown
Author

man-of-fox commented Feb 18, 2026

Screenshot to visualize the changes:
Changes on left menu bar trash icon (the 3 dots only shown on mouse over, like in folder view):
Bildschirmfoto 2026-02-18 um 12 00 30
On click at "Empty trash" the following dialog is shown:
Bildschirmfoto 2026-02-18 um 12 00 53

Changes in Trash page (see icon on the right side):
Bildschirmfoto 2026-02-18 um 12 03 20
On click at the icon the same dialog as above is shown:
Bildschirmfoto 2026-02-18 um 12 04 14

@man-of-fox
Copy link
Copy Markdown
Author

quickinfo on mouse over the icon in trash page:
Bildschirmfoto 2026-02-18 um 12 11 55

@man-of-fox man-of-fox changed the title feat: Trash clear function feat: Trash clear function - with screenshots in comments Feb 19, 2026
Copy link
Copy Markdown
Author

@man-of-fox man-of-fox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

everything commented by coderabbitai[bot] is integrated and tested

@man-of-fox man-of-fox changed the title feat: Trash clear function - with screenshots in comments feat: Trash clear function Feb 19, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Feb 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.93%. Comparing base (d8cc0ac) to head (f1d7f6d).
⚠️ Report is 6 commits behind head on canary.

Additional details and impacted files
@@            Coverage Diff             @@
##           canary   #14455      +/-   ##
==========================================
- Coverage   57.43%   56.93%   -0.50%     
==========================================
  Files        2859     2859              
  Lines      154468   154468              
  Branches    23330    23199     -131     
==========================================
- Hits        88713    87954     -759     
- Misses      62771    63603     +832     
+ Partials     2984     2911      -73     
Flag Coverage Δ
server-test 74.96% <ø> (-0.98%) ⬇️
unittest 33.93% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@man-of-fox man-of-fox marked this pull request as draft February 23, 2026 22:46
@man-of-fox man-of-fox marked this pull request as ready for review February 23, 2026 23:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app:core mod:i18n Related to i18n

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant