diff --git a/FEATURES.md b/FEATURES.md index 6a78de96..1043c7c1 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -6,6 +6,7 @@ - Gmail-style threading with inline expansion and an optional conversation toggle - Unified Mailbox – combined Inbox, Sent, Drafts, Junk, Archive, and Trash, scoped by default to the active account and its shared/group folders, with an optional admin-gated cross-account mode that spans every connected account - Aggregated All mail / Unread / Starred entries in the Unified Mailbox – scoped by the same account boundary (or all accounts in cross-account mode) and narrowed by a per-account folder selection; each list labels the source folder of every message +- Search inside the Unified Mailbox – text search across every unified view (the per-role mailboxes and the folder-selected All mail / Unread / Starred lists); advanced filters are additionally available in the per-role unified mailboxes - Three selectable mail layouts: split (three-pane), focused list, and reading pane at bottom - Draft auto-save with identity preservation, persisted HTML body, and proper `In-Reply-To` / `References` headers on replies - Attachment upload, download, drag-out to local file system, and inline preview – images, inline PDF on desktop and mobile, composer attachments (click to open), and `.eml` (`message/rfc822`) attachments rendered like an email; image thumbnails and forgotten-attachment warning diff --git a/app/(main)/[locale]/page.tsx b/app/(main)/[locale]/page.tsx index 64947e0d..26352683 100644 --- a/app/(main)/[locale]/page.tsx +++ b/app/(main)/[locale]/page.tsx @@ -1838,7 +1838,18 @@ export default function Home() { } const populated = await buildPopulatedUnifiedAccounts(); - await fetchUnifiedEmailsAction(populated, role); + // Keep an active search across the switch and re-run it in this view + // (mirrors normal mailboxes), preserving advanced filters; otherwise browse. + if (client && (!isFilterEmpty(searchFilters) || searchQuery)) { + useEmailStore.setState({ isUnifiedView: true, unifiedRole: role, crossView: null }); + if (!isFilterEmpty(searchFilters)) { + await advancedSearch(client); + } else { + await searchEmails(client, searchQuery); + } + } else { + await fetchUnifiedEmailsAction(populated, role); + } refreshUnifiedCounts(populated); return; } @@ -1860,7 +1871,18 @@ export default function Home() { } const populated = await buildPopulatedUnifiedAccounts(); - await fetchCrossViewAction(populated, view); + // Keep an active search across the switch and re-run it in this view + // (mirrors normal mailboxes), preserving advanced filters; otherwise browse. + if (client && (!isFilterEmpty(searchFilters) || searchQuery)) { + useEmailStore.setState({ isUnifiedView: true, crossView: view, unifiedRole: null }); + if (!isFilterEmpty(searchFilters)) { + await advancedSearch(client); + } else { + await searchEmails(client, searchQuery); + } + } else { + await fetchCrossViewAction(populated, view); + } refreshCrossCounts(populated); return; } @@ -2206,13 +2228,16 @@ export default function Home() { setSearchQuery(""); clearSearchFilters(); if (!client) return; - // In unified view the active "mailbox" is a virtual role, so refresh via - // the unified fan-out instead of fetchEmails. + // In unified view the active "mailbox" is a virtual role or cross view, so + // refresh via the unified fan-out instead of fetchEmails. if (isUnifiedView) { + const populated = await buildPopulatedUnifiedAccounts(); const role = useEmailStore.getState().unifiedRole; + const cross = useEmailStore.getState().crossView; if (role) { - const populated = await buildPopulatedUnifiedAccounts(); await fetchUnifiedEmailsAction(populated, role); + } else if (cross) { + await fetchCrossViewAction(populated, cross); } return; } @@ -2848,8 +2873,8 @@ export default function Home() { className={cn("ps-9 h-9", searchQuery && "pe-8")} data-search-input data-tour="search-input" - disabled={isUnifiedView || isScheduledView} - title={isUnifiedView ? t("unified_mailbox.search_unavailable") : isScheduledView ? t('email_viewer.scheduled_actions_only') : undefined} + disabled={isScheduledView} + title={isScheduledView ? t('email_viewer.scheduled_actions_only') : undefined} /> {searchQuery && (