-
-
Notifications
You must be signed in to change notification settings - Fork 706
Delete Draft #1246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: staging
Are you sure you want to change the base?
Delete Draft #1246
Conversation
""" WalkthroughThis change introduces optimistic deletion for draft emails in a mail application. It adds a context menu for drafts with a delete option, updates hooks and state management to support optimistic deletion, extends backend interfaces and APIs to handle draft deletions, and updates localization for the new action. Both single and bulk draft deletions are supported. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DraftContextMenu
participant useOptimisticActions
participant BackendAPI
participant MailManager
User->>DraftContextMenu: Right-click draft, select "Delete"
DraftContextMenu->>useOptimisticActions: optimisticDeleteDrafts([draftId])
useOptimisticActions->>useOptimisticThreadState: Set shouldHide, isRemoving = true
useOptimisticActions->>BackendAPI: Call bulkDeleteDraft([draftId])
BackendAPI->>MailManager: deleteDraft(draftId)
MailManager-->>BackendAPI: Deletion result
BackendAPI-->>useOptimisticActions: Success/Failure response
useOptimisticActions->>useOptimisticThreadState: Finalize optimistic state
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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
🔭 Outside diff range comments (2)
apps/mail/hooks/use-optimistic-actions.ts (2)
367-402
:⚠️ Potential issueFix the syntax error in
optimisticToggleImportant
function.The function is missing proper closure and the dependency array is misplaced. This is not a
useCallback
hook but a regular function.function optimisticToggleImportant(threadIds: string[], isImportant: boolean) { if (!threadIds.length) return; const optimisticId = addOptimisticAction({ type: 'IMPORTANT', threadIds, important: isImportant, }); createPendingAction({ type: 'IMPORTANT', threadIds, params: { important: isImportant }, optimisticId, execute: async () => { await toggleImportant({ ids: threadIds }); if (mail.bulkSelected.length > 0) { setMail({ ...mail, bulkSelected: [] }); } }, undo: () => { removeOptimisticAction(optimisticId); }, toastMessage: isImportant ? 'Marked as important' : 'Unmarked as important', }); - }, - [ - addOptimisticAction, - createPendingAction, - mail, - removeOptimisticAction, - setMail, - toggleImportant, - ], - ); + }🧰 Tools
🪛 Biome (1.9.4)
[error] 393-402: Expected a statement but instead found ',
[
addOptimisticAction,
createPendingAction,
mail,
removeOptimisticAction,
setMail,
toggleImportant,
],
)'.Expected a statement here.
(parse)
467-487
:⚠️ Potential issueFix the
undoLastAction
implementation.The function has several issues that need to be addressed:
- It checks
lastActionIdRef.current
which is an unused ref- Missing closing bracket and dependency array for
useCallback
const undoLastAction = useCallback(() => { - if (!lastActionIdRef.current) return; + if (!optimisticActionsManager.lastActionId) return; const lastAction = optimisticActionsManager.pendingActions.get( optimisticActionsManager.lastActionId, ); if (!lastAction) return; lastAction.undo(); optimisticActionsManager.pendingActions.delete(optimisticActionsManager.lastActionId); optimisticActionsManager.pendingActionsByType .get(lastAction.type) ?.delete(optimisticActionsManager.lastActionId); if (lastAction.toastId) { toast.dismiss(lastAction.toastId); } optimisticActionsManager.lastActionId = null; - } + }, []);
🧹 Nitpick comments (6)
apps/mail/components/mail/mail-list.tsx (1)
534-582
: Consider simplifying the complex conditional rendering structure.The Draft component refactor correctly integrates optimistic deletion state, but the nested conditional logic is quite complex and impacts readability.
Consider this cleaner structure:
return ( - draft ? ( - <AnimatePresence mode="sync"> - {!optimisticState.shouldHide && (<DraftContextMenu draftId={message.id}> + draft && !optimisticState.shouldHide ? ( + <DraftContextMenu draftId={message.id}> <div className="select-none py-1" onClick={handleMailClick}> {/* draft content */} </div> - </DraftContextMenu> )} - </AnimatePresence> - ): null + </DraftContextMenu> + ) : nullAlso, consider whether
AnimatePresence
is necessary here since you're only conditionally rendering based onshouldHide
rather than animating transitions.apps/server/src/trpc/routes/mail.ts (1)
321-339
: Well-implemented bulk deletion with proper error handling.The mutation correctly uses
Promise.allSettled
for concurrent operations and provides appropriate error handling. The implementation follows established patterns in the codebase.Consider enhancing error details to include which specific draft IDs failed:
const results = await Promise.allSettled(ids.map((id) => driver.deleteDraft(id))); - const errors = results.filter((result) => result.status === 'rejected'); + const failures = results + .map((result, index) => ({ result, draftId: ids[index] })) + .filter(({ result }) => result.status === 'rejected'); if (errors.length > 0) { - return { success: false, error: 'Failed to delete some drafts', details: errors }; + return { + success: false, + error: 'Failed to delete some drafts', + failedIds: failures.map(f => f.draftId), + details: failures.map(f => f.result) + }; }apps/mail/components/context/draft-context.tsx (1)
1-11
: Clean up unused imports.Several context menu components are imported but not used in this file.
Remove the unused imports:
import { ContextMenu, ContextMenuContent, ContextMenuItem, - ContextMenuSeparator, - ContextMenuShortcut, - ContextMenuSub, - ContextMenuSubContent, - ContextMenuSubTrigger, ContextMenuTrigger, } from '../ui/context-menu';apps/mail/hooks/use-optimistic-actions.ts (3)
423-423
: Remove debug console.log statement.Debug logging should be removed before merging to production.
- console.log("DELETING DRAFT FROM OPTIMISTIC", draftIds )
95-95
: Remove all debug console.log statements.Multiple debug logging statements should be removed throughout the file.
- console.log('here Generated pending action ID:', pendingActionId);
- console.log('here Creating new Set for action type:', type);
- console.log( - 'here', - 'Added pending action to type:', - type, - 'Current size:', - optimisticActionsManager.pendingActionsByType.get(type)?.size, - );- console.log('here', { - pendingActionsByTypeRef: optimisticActionsManager.pendingActionsByType.get(type)?.size, - pendingActionsRef: optimisticActionsManager.pendingActions.size, - typeActions: typeActions?.size, - });Also applies to: 98-98, 102-108, 129-133
452-465
: Consider optimizing the dependency array.The
optimisticDeleteDrafts
callback has many dependencies which could cause frequent re-creations. Consider whether all these dependencies are necessary, particularlyYou might want to use
+ const mailRef = useRef(mail); + mailRef.current = mail; const optimisticDeleteDrafts = useCallback( (draftIds: string[]) => { // ... existing code ... - if (mail.bulkSelected.length > 0) { - setMail({ ...mail, bulkSelected: [] }); + if (mailRef.current.bulkSelected.length > 0) { + setMail({ ...mailRef.current, bulkSelected: [] }); }And remove
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
apps/mail/components/context/draft-context.tsx
(1 hunks)apps/mail/components/mail/mail-list.tsx
(2 hunks)apps/mail/components/mail/optimistic-thread-state.tsx
(1 hunks)apps/mail/hooks/use-optimistic-actions.ts
(5 hunks)apps/mail/locales/en.json
(1 hunks)apps/mail/store/optimistic-updates.ts
(1 hunks)apps/server/src/lib/driver/google.ts
(1 hunks)apps/server/src/lib/driver/types.ts
(1 hunks)apps/server/src/trpc/routes/mail.ts
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
apps/mail/components/mail/mail-list.tsx (3)
apps/mail/components/mail/optimistic-thread-state.tsx (1)
useOptimisticThreadState
(7-80)apps/mail/components/context/draft-context.tsx (1)
DraftContextMenu
(24-58)apps/mail/lib/utils.ts (1)
cn
(51-51)
apps/server/src/trpc/routes/mail.ts (1)
apps/server/src/trpc/trpc.ts (1)
activeDriverProcedure
(44-78)
apps/mail/hooks/use-optimistic-actions.ts (1)
apps/mail/lib/optimistic-actions-manager.ts (1)
PendingAction
(1-10)
🪛 Biome (1.9.4)
apps/mail/hooks/use-optimistic-actions.ts
[error] 16-16: Shouldn't redeclare 'PendingAction'. Consider to delete it or rename it.
'PendingAction' is defined here:
(lint/suspicious/noRedeclare)
[error] 393-402: Expected a statement but instead found ',
[
addOptimisticAction,
createPendingAction,
mail,
removeOptimisticAction,
setMail,
toggleImportant,
],
)'.
Expected a statement here.
(parse)
🔇 Additional comments (6)
apps/server/src/lib/driver/types.ts (1)
52-52
: Clean interface extension for draft deletion.The method signature is well-designed and appropriately positioned among other draft-related methods in the interface.
apps/mail/locales/en.json (1)
462-462
: Appropriate localization for draft deletion.The label is clear and properly placed in the shortcuts actions section.
apps/mail/store/optimistic-updates.ts (1)
9-10
: Well-structured optimistic action type for deletion.The new DELETE action follows the established pattern and correctly uses threadIds array for consistency with the UI layer.
apps/server/src/lib/driver/google.ts (1)
589-602
: Solid implementation following established patterns.The deleteDraft method correctly implements the interface using the established error handling pattern and appropriate Gmail API calls. The implementation is consistent with other methods in the class.
apps/mail/components/mail/optimistic-thread-state.tsx (1)
66-69
: LGTM! Clean implementation following existing patterns.The DELETE case correctly sets both
isRemoving
andshouldHide
flags, which is consistent with the MOVE action pattern and appropriate for deletion operations.apps/mail/components/context/draft-context.tsx (1)
24-58
: Well-designed context menu component with proper state management.The component correctly handles both single and bulk draft deletion scenarios, and appropriately clears bulk selection state after deletion. The logic is clean and follows React best practices.
const pendingActionsRef = useRef<Map<string, PendingAction>>(new Map()); | ||
const pendingActionsByTypeRef = useRef<Map<string, Set<string>>>(new Map()); | ||
const lastActionIdRef = useRef<string | null>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused ref declarations.
These refs are declared but never used in the code. The implementation continues to use optimisticActionsManager
from the imported module instead.
- const pendingActionsRef = useRef<Map<string, PendingAction>>(new Map());
- const pendingActionsByTypeRef = useRef<Map<string, Set<string>>>(new Map());
- const lastActionIdRef = useRef<string | null>(null);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const pendingActionsRef = useRef<Map<string, PendingAction>>(new Map()); | |
const pendingActionsByTypeRef = useRef<Map<string, Set<string>>>(new Map()); | |
const lastActionIdRef = useRef<string | null>(null); |
🤖 Prompt for AI Agents
In apps/mail/hooks/use-optimistic-actions.ts around lines 48 to 50, the refs
pendingActionsRef, pendingActionsByTypeRef, and lastActionIdRef are declared but
never used. Remove these unused ref declarations to clean up the code since the
implementation relies on optimisticActionsManager from the imported module
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey great pr. I left 1 comment.
Thank you @ahmetskilinc, fixed the requested changes. Please let me know if any update needed |
Merge activity
|
Aded delete draft functionality
This PR fix/complete https://feedback.0.email/p/unable-to-delete-draft-emails-in-zero-client
Screen.Recording.2025-06-08.at.4.41.04.AM.mov
Summary by CodeRabbit
New Features
Bug Fixes
Localization