From 351f2d4e268cfe9c00be0ae0612f9a4d8285f5fc Mon Sep 17 00:00:00 2001 From: Aaron Guise Date: Mon, 27 Jul 2026 16:37:04 +1200 Subject: [PATCH] feat: add "Forward as attachment" to the message list context menu Adds the same "Forward as attachment" action from the message viewer's overflow menu to the right-click context menu on a message row in the list, right after "Forward". Reuses the handleForwardAsAttachment handler and buildForwardAsAttachmentPayload helper introduced earlier in this PR - no new logic, just threading the prop down EmailList -> EmailContextMenu the same way onForward already is. blobId is already present on list-row emails (EMAIL_LIST_PROPERTIES includes it specifically for the existing drag-out-to-filesystem .eml export feature), so this works without any additional fetch. The menu item is disabled if it's ever missing, matching how other actions degrade when their handler prop isn't supplied. Reuses the email_viewer.forward_as_attachment translation key already added (via a second scoped useTranslations("email_viewer") call, matching this file's existing cross-namespace pattern for email_viewer.color_tag) rather than adding a duplicate key under context_menu - avoids touching all 24 locale files again. --- app/(main)/[locale]/page.tsx | 4 ++++ components/email/email-context-menu.tsx | 10 ++++++++++ components/email/email-list.tsx | 3 +++ 3 files changed, 17 insertions(+) diff --git a/app/(main)/[locale]/page.tsx b/app/(main)/[locale]/page.tsx index e8a28691..9a08f6c7 100644 --- a/app/(main)/[locale]/page.tsx +++ b/app/(main)/[locale]/page.tsx @@ -3261,6 +3261,10 @@ export default function Home() { selectEmail(email); handleForward(); }} + onForwardAsAttachment={(email) => { + selectEmail(email); + handleForwardAsAttachment(); + }} onMarkAsRead={async (email, read) => { if (client) { await markAsRead(client, email.id, read); diff --git a/components/email/email-context-menu.tsx b/components/email/email-context-menu.tsx index 7cdfb1f7..d74ed5cb 100644 --- a/components/email/email-context-menu.tsx +++ b/components/email/email-context-menu.tsx @@ -34,6 +34,7 @@ import { EditIcon, CalendarClock, XCircle, + Paperclip, } from "lucide-react"; import { cn, buildMailboxTree, MailboxNode } from "@/lib/utils"; import { localizeMailboxName } from "@/lib/mailbox-label"; @@ -59,6 +60,7 @@ interface EmailContextMenuProps { onReply?: () => void; onReplyAll?: () => void; onForward?: () => void; + onForwardAsAttachment?: () => void; onMarkAsRead?: (read: boolean) => void; onToggleStar?: () => void; onTogglePinned?: () => void; @@ -127,6 +129,7 @@ export function EmailContextMenu({ onReply, onReplyAll, onForward, + onForwardAsAttachment, onMarkAsRead, onToggleStar, onTogglePinned, @@ -150,6 +153,7 @@ export function EmailContextMenu({ const t = useTranslations("context_menu"); const tSidebar = useTranslations("sidebar"); const _tColor = useTranslations("email_viewer.color_tag"); + const tEmailViewer = useTranslations("email_viewer"); const emailKeywords = useSettingsStore((state) => state.emailKeywords); const isUnread = !email.keywords?.$seen; const isStarred = email.keywords?.$flagged; @@ -277,6 +281,12 @@ export function EmailContextMenu({ onClick={() => handleAction(onForward!)} disabled={!onForward} /> + handleAction(onForwardAsAttachment!)} + disabled={!onForwardAsAttachment || !email.blobId} + /> )} diff --git a/components/email/email-list.tsx b/components/email/email-list.tsx index 8f1db908..6dfe4c33 100644 --- a/components/email/email-list.tsx +++ b/components/email/email-list.tsx @@ -33,6 +33,7 @@ interface EmailListProps { onReply?: (email: Email) => void; onReplyAll?: (email: Email) => void; onForward?: (email: Email) => void; + onForwardAsAttachment?: (email: Email) => void; onMarkAsRead?: (email: Email, read: boolean) => void; onToggleStar?: (email: Email) => void; onTogglePinned?: (email: Email) => void; @@ -63,6 +64,7 @@ export function EmailList({ onReply, onReplyAll, onForward, + onForwardAsAttachment, onMarkAsRead, onToggleStar, onTogglePinned, @@ -583,6 +585,7 @@ export function EmailList({ onReply={() => onReply?.(contextMenu.data!)} onReplyAll={() => onReplyAll?.(contextMenu.data!)} onForward={() => onForward?.(contextMenu.data!)} + onForwardAsAttachment={() => onForwardAsAttachment?.(contextMenu.data!)} onMarkAsRead={(read) => onMarkAsRead?.(contextMenu.data!, read)} onToggleStar={() => onToggleStar?.(contextMenu.data!)} onTogglePinned={onTogglePinned ? () => onTogglePinned(contextMenu.data!) : undefined}