diff --git a/components/mail-transfer/__tests__/mail-export-dialog.test.tsx b/components/mail-transfer/__tests__/mail-export-dialog.test.tsx index 53656da6f..bce120993 100644 --- a/components/mail-transfer/__tests__/mail-export-dialog.test.tsx +++ b/components/mail-transfer/__tests__/mail-export-dialog.test.tsx @@ -129,4 +129,26 @@ describe('MailExportDialog', () => { expect(screen.getByTestId('mail-transfer-chip').textContent).toContain('chip'); expect(controller.signal.aborted).toBe(false); }); + + it('keeps the running count out of the live region', () => { + render(); + act(() => { + openMailExport({ mailboxId: 'inbox' }); + useMailTransferStore.getState().startJob({ kind: 'export', controller: new AbortController(), progress: { phase: 'running', exported: 1, failed: 0, failures: [], total: 4, fraction: 0.25 } }); + }); + expect(screen.getByTestId('mail-export-status').textContent).toBe('running_title'); + expect(screen.getByTestId('mail-export-count').textContent).toBe('status_exported'); + }); + + it('says the export stays in memory where the private file system can\'t write files', () => { + vi.stubGlobal('navigator', { ...navigator, storage: { getDirectory: async () => ({}) } }); + vi.stubGlobal('FileSystemFileHandle', class {}); + try { + render(); + act(() => openMailExport()); + expect(screen.getByText('save_memory')).toBeTruthy(); + } finally { + vi.unstubAllGlobals(); + } + }); }); diff --git a/components/mail-transfer/mail-export-dialog.tsx b/components/mail-transfer/mail-export-dialog.tsx index af90c91a9..0f7ecf6c3 100644 --- a/components/mail-transfer/mail-export-dialog.tsx +++ b/components/mail-transfer/mail-export-dialog.tsx @@ -9,7 +9,7 @@ import { useAuthStore } from "@/stores/auth-store"; import { isJobActive, useMailTransferStore, type ExportRequest } from "@/stores/mail-transfer-store"; import type { ExportFormat, ExportProgress } from "@/lib/mail-export/engine"; import { safeName } from "@/lib/mail-export/engine"; -import { canPickSaveFile, memorySink, pickSaveFile, privateFileSink, sweepPrivateExports, type ExportSink } from "@/lib/mail-export/sinks"; +import { canPickSaveFile, canWritePrivateFile, memorySink, pickSaveFile, privateFileSink, sweepPrivateExports, type ExportSink } from "@/lib/mail-export/sinks"; import { formatFileSize } from "@/lib/utils"; import { formatClock, TransferBar } from "./transfer-progress"; import { startExport } from "./start-export"; @@ -21,8 +21,7 @@ function today(): string { /** Where the file will go in this browser, said before the export starts. */ function saveMode(): "picker" | "download" | "memory" { if (canPickSaveFile()) return "picker"; - const storage = typeof navigator !== "undefined" ? (navigator.storage as { getDirectory?: unknown } | undefined) : undefined; - return typeof storage?.getDirectory === "function" ? "download" : "memory"; + return canWritePrivateFile() ? "download" : "memory"; } export function MailExportDialog({ request }: { request: ExportRequest }) { @@ -103,7 +102,7 @@ export function MailExportDialog({ request }: { request: ExportRequest }) { {progress.phase === "done" && progress.file?.download && ( )} - + )} > @@ -120,14 +119,14 @@ export function MailExportDialog({ request }: { request: ExportRequest }) { return ( close()} size="full-on-phone" title={folder ? t("title_folder", { name: mailbox?.name ?? "" }) : t("title_account")} description={folder ? t("description_folder") : t("description_account")} testId="mail-export-dialog" footer={( <> - + )} @@ -135,7 +134,7 @@ export function MailExportDialog({ request }: { request: ExportRequest }) {
{t("format_label")} -
+
{formats.map((f) => (