feat: import .eml files via folder right-click menu
This commit is contained in:
@@ -1504,6 +1504,43 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleImportEmailFromContextMenu = (mailboxId: string) => {
|
||||||
|
if (!client) return;
|
||||||
|
const mailbox = mailboxes.find(mb => mb.id === mailboxId);
|
||||||
|
if (!mailbox) return;
|
||||||
|
const targetMailboxId = mailbox.originalId || mailbox.id;
|
||||||
|
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = '.eml,message/rfc822';
|
||||||
|
input.multiple = true;
|
||||||
|
input.onchange = async (e) => {
|
||||||
|
const files = Array.from((e.target as HTMLInputElement).files ?? []);
|
||||||
|
if (files.length === 0) return;
|
||||||
|
|
||||||
|
let imported = 0;
|
||||||
|
let failed = 0;
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const blob = new Blob([await file.arrayBuffer()], { type: 'message/rfc822' });
|
||||||
|
await client.importRawEmail(blob, { [targetMailboxId]: true }, { '$seen': true });
|
||||||
|
imported++;
|
||||||
|
} catch {
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imported > 0) {
|
||||||
|
toast.success(t('notifications.import_email_success'));
|
||||||
|
if (selectedMailbox) await fetchEmails(client, selectedMailbox);
|
||||||
|
}
|
||||||
|
if (failed > 0) {
|
||||||
|
toast.error(t('notifications.import_email_error'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.click();
|
||||||
|
};
|
||||||
|
|
||||||
const handleRefreshMailboxes = async () => {
|
const handleRefreshMailboxes = async () => {
|
||||||
if (!client) return;
|
if (!client) return;
|
||||||
try {
|
try {
|
||||||
@@ -1894,6 +1931,7 @@ export default function Home() {
|
|||||||
onCreateFolder={handleCreateFolderFromContextMenu}
|
onCreateFolder={handleCreateFolderFromContextMenu}
|
||||||
onRenameFolder={handleRenameFolderFromContextMenu}
|
onRenameFolder={handleRenameFolderFromContextMenu}
|
||||||
onDeleteFolder={handleDeleteFolderFromContextMenu}
|
onDeleteFolder={handleDeleteFolderFromContextMenu}
|
||||||
|
onImportEmail={handleImportEmailFromContextMenu}
|
||||||
onRefreshMailboxes={handleRefreshMailboxes}
|
onRefreshMailboxes={handleRefreshMailboxes}
|
||||||
onCompose={() => {
|
onCompose={() => {
|
||||||
setComposerMode('compose');
|
setComposerMode('compose');
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
Pencil,
|
Pencil,
|
||||||
FolderX,
|
FolderX,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
|
Upload,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
interface Position {
|
interface Position {
|
||||||
@@ -84,6 +85,7 @@ interface MailboxContextMenuProps {
|
|||||||
onCreateFolder?: () => void;
|
onCreateFolder?: () => void;
|
||||||
onRenameFolder?: (mailboxId: string) => void;
|
onRenameFolder?: (mailboxId: string) => void;
|
||||||
onDeleteFolder?: (mailboxId: string) => void;
|
onDeleteFolder?: (mailboxId: string) => void;
|
||||||
|
onImportEmail?: (mailboxId: string) => void;
|
||||||
onRefresh?: () => void;
|
onRefresh?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +104,7 @@ export function MailboxContextMenu({
|
|||||||
onCreateFolder,
|
onCreateFolder,
|
||||||
onRenameFolder,
|
onRenameFolder,
|
||||||
onDeleteFolder,
|
onDeleteFolder,
|
||||||
|
onImportEmail,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
}: MailboxContextMenuProps) {
|
}: MailboxContextMenuProps) {
|
||||||
const t = useTranslations("mailbox_context_menu");
|
const t = useTranslations("mailbox_context_menu");
|
||||||
@@ -149,6 +152,7 @@ export function MailboxContextMenu({
|
|||||||
const canCreateChild = mailbox.myRights?.mayCreateChild !== false;
|
const canCreateChild = mailbox.myRights?.mayCreateChild !== false;
|
||||||
const canSetSeen = mailbox.myRights?.maySetSeen !== false;
|
const canSetSeen = mailbox.myRights?.maySetSeen !== false;
|
||||||
const canRemoveItems = mailbox.myRights?.mayRemoveItems !== false;
|
const canRemoveItems = mailbox.myRights?.mayRemoveItems !== false;
|
||||||
|
const canAddItems = mailbox.myRights?.mayAddItems !== false;
|
||||||
|
|
||||||
const fullPath = getMailboxPath(mailbox, mailboxes);
|
const fullPath = getMailboxPath(mailbox, mailboxes);
|
||||||
|
|
||||||
@@ -190,6 +194,15 @@ export function MailboxContextMenu({
|
|||||||
|
|
||||||
<ContextMenuSeparator />
|
<ContextMenuSeparator />
|
||||||
|
|
||||||
|
<ContextMenuItem
|
||||||
|
icon={Upload}
|
||||||
|
label={t("import_email")}
|
||||||
|
onClick={() => handleAction(() => onImportEmail?.(mailbox.id))}
|
||||||
|
disabled={!onImportEmail || !canAddItems}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
icon={FolderX}
|
icon={FolderX}
|
||||||
label={isTrashOrJunk ? t("empty_folder") : t("empty_folder_generic")}
|
label={isTrashOrJunk ? t("empty_folder") : t("empty_folder_generic")}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ interface SidebarProps {
|
|||||||
onCreateFolder?: () => void;
|
onCreateFolder?: () => void;
|
||||||
onRenameFolder?: (mailboxId: string) => void;
|
onRenameFolder?: (mailboxId: string) => void;
|
||||||
onDeleteFolder?: (mailboxId: string) => void;
|
onDeleteFolder?: (mailboxId: string) => void;
|
||||||
|
onImportEmail?: (mailboxId: string) => void;
|
||||||
onRefreshMailboxes?: () => void;
|
onRefreshMailboxes?: () => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
@@ -636,6 +637,7 @@ export function Sidebar({
|
|||||||
onCreateFolder,
|
onCreateFolder,
|
||||||
onRenameFolder,
|
onRenameFolder,
|
||||||
onDeleteFolder,
|
onDeleteFolder,
|
||||||
|
onImportEmail,
|
||||||
onRefreshMailboxes,
|
onRefreshMailboxes,
|
||||||
className,
|
className,
|
||||||
}: SidebarProps) {
|
}: SidebarProps) {
|
||||||
@@ -1037,6 +1039,7 @@ export function Sidebar({
|
|||||||
onCreateFolder={onCreateFolder}
|
onCreateFolder={onCreateFolder}
|
||||||
onRenameFolder={onRenameFolder}
|
onRenameFolder={onRenameFolder}
|
||||||
onDeleteFolder={onDeleteFolder}
|
onDeleteFolder={onDeleteFolder}
|
||||||
|
onImportEmail={onImportEmail}
|
||||||
onRefresh={onRefreshMailboxes}
|
onRefresh={onRefreshMailboxes}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1684,6 +1684,7 @@
|
|||||||
"new_subfolder": "New subfolder...",
|
"new_subfolder": "New subfolder...",
|
||||||
"new_folder": "New folder...",
|
"new_folder": "New folder...",
|
||||||
"rename": "Rename...",
|
"rename": "Rename...",
|
||||||
|
"import_email": "Import .eml...",
|
||||||
"empty_folder": "Empty folder",
|
"empty_folder": "Empty folder",
|
||||||
"empty_folder_generic": "Empty folder",
|
"empty_folder_generic": "Empty folder",
|
||||||
"delete_folder": "Delete folder",
|
"delete_folder": "Delete folder",
|
||||||
|
|||||||
Reference in New Issue
Block a user