diff --git a/src/app/smoke-tests/SmokeHarness.tsx b/src/app/smoke-tests/SmokeHarness.tsx index e4753d7..6cda0ac 100644 --- a/src/app/smoke-tests/SmokeHarness.tsx +++ b/src/app/smoke-tests/SmokeHarness.tsx @@ -148,6 +148,7 @@ export default function SmokeHarness({ panel }: { panel: SmokePanel }) { archiveMailboxId="mailbox-archive" trashMailboxId="mailbox-trash" threadHrefPrefix="/smoke-tests/thread" + autoSyncIntervalMs={0} /> )} diff --git a/src/components/EmailListPanel.tsx b/src/components/EmailListPanel.tsx index 84266de..0808031 100644 --- a/src/components/EmailListPanel.tsx +++ b/src/components/EmailListPanel.tsx @@ -1044,6 +1044,58 @@ export default function EmailListPanel({ const actionBtnCls = "flex h-10 w-10 items-center justify-center rounded-md hover:bg-blue-100 dark:hover:bg-blue-900/60 text-blue-600 dark:text-blue-400 transition-colors shrink-0"; + const selectionActions = ( + <> + + + {view === "spam" && ( + + )} + + + {view === "inbox" && ( + + )} + {view === "inbox" && archiveMailboxId && ( + + )} + {trashMailboxId && ( + + )} + + ); + // ------------------------------------------------------------------------- // Render // ------------------------------------------------------------------------- @@ -1112,7 +1164,20 @@ export default function EmailListPanel({ {/* Search (inbox only) */} {view === "inbox" && ( -
+
+ {selectionMode ? ( +
+ {selectionActions} +
+ ) : ( + <>
)} + + )}
)} @@ -1259,55 +1326,9 @@ export default function EmailListPanel({ )} {/* Bulk action bar */} - {(view === "inbox" || view === "spam") && selectionMode && ( + {view === "spam" && selectionMode && (
- - - {view === "spam" && ( - - )} - - - {view === "inbox" && ( - - )} - {view === "inbox" && archiveMailboxId && ( - - )} - {trashMailboxId && ( - - )} + {selectionActions}
)} diff --git a/tests/smoke/mail.spec.ts b/tests/smoke/mail.spec.ts index b7a7abb..ad95241 100644 --- a/tests/smoke/mail.spec.ts +++ b/tests/smoke/mail.spec.ts @@ -71,6 +71,37 @@ test("opens a conversation from a desktop click", async ({ page }) => { ).toBeVisible(); }); +test("replaces search with selection actions without shifting conversations", async ({ + page, +}) => { + await page.goto("/smoke-tests"); + + const conversation = page.locator( + 'a[href="/smoke-tests/thread/thread-maya"]', + ); + const beforeTop = await conversation.evaluate( + (element) => element.getBoundingClientRect().top, + ); + + await page + .getByRole("button", { name: "Select conversation from GitHub" }) + .click(); + + await expect(page.getByRole("searchbox", { name: "Search all mail" })).toHaveCount(0); + await expect(page.getByRole("button", { name: "Cancel selection" })).toBeVisible(); + const selectedTop = await conversation.evaluate( + (element) => element.getBoundingClientRect().top, + ); + expect(selectedTop).toBe(beforeTop); + + await page.getByRole("button", { name: "Cancel selection" }).click(); + await expect(page.getByRole("searchbox", { name: "Search all mail" })).toBeVisible(); + const restoredTop = await conversation.evaluate( + (element) => element.getBoundingClientRect().top, + ); + expect(restoredTop).toBe(beforeTop); +}); + test("fetches new mail in the background and pauses while offline", async ({ page, }) => {