diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 48ea0bdd5..98d09e713 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -81,6 +81,7 @@ declare module 'vue' { MailListItemActions: typeof import('./src/components/MailListItemActions.vue')['default'] MailLogo: typeof import('./src/components/Icons/MailLogo.vue')['default'] MailThread: typeof import('./src/components/MailThread.vue')['default'] + MailThreadSkeleton: typeof import('./src/components/MailThreadSkeleton.vue')['default'] NoMails: typeof import('./src/components/Icons/NoMails.vue')['default'] PDFIcon: typeof import('./src/components/Icons/PDFIcon.vue')['default'] ProfileSettings: typeof import('./src/components/Settings/ProfileSettings.vue')['default'] diff --git a/frontend/src/App.vue b/frontend/src/App.vue index ea2a944b3..c192275cc 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -7,10 +7,11 @@ diff --git a/frontend/src/components/AppSidebar.vue b/frontend/src/components/AppSidebar.vue index df2e61035..43e98c818 100644 --- a/frontend/src/components/AppSidebar.vue +++ b/frontend/src/components/AppSidebar.vue @@ -49,7 +49,10 @@ - + {{ item.suffix }} @@ -75,7 +78,7 @@ import { Check, Keyboard, User } from 'lucide-vue-next' import { Avatar, Button, Dropdown, Sidebar, SidebarItem, createResource } from 'frappe-ui' import { FOLDER_ICON_COLOR_MAP } from '@/constants' -import { getIcon, toTitleCase } from '@/utils' +import { getIcon, getMailboxName, toTitleCase } from '@/utils' import { useScreenSize, useSettings, useSidebar } from '@/utils/composables' import { sessionStore } from '@/stores/session' import { userStore } from '@/stores/user' @@ -277,45 +280,67 @@ const mailboxItems = computed( () => mailboxes.data ?.filter((mailbox: MailboxData) => mailbox.subscribed) - ?.map((mailbox: MailboxData) => ({ - label: mailbox._name, - icon: h(Icon, { - name: getIcon(mailbox), - class: FOLDER_ICON_COLOR_MAP[mailbox.color], - }), - to: { - name: 'Mailbox', - params: { accountId: store.accountId, mailbox: mailbox.id }, - }, - suffix: mailbox.unread_threads ? String(mailbox.unread_threads) : '', - activeFor: [mailbox.id], - menuOptions: [ - { - label: __('Configure'), - icon: Settings, - onClick: () => { - selectedMailbox.value = mailbox - showFolderModal.value = true - }, - }, - { - label: __('Delete'), - theme: 'red', - icon: Trash2, - onClick: () => { - selectedMailbox.value = mailbox - showDeleteMailbox.value = true - }, - }, - ], - })) || [], + ?.map((mailbox: MailboxData) => { + // The Screening folder opens the dedicated Screener page, not the thread list. + const isScreener = mailbox.id === store.mailboxIds.screening + return { + mailboxId: mailbox.id, + label: getMailboxName(mailbox), + icon: h(Icon, { + name: getIcon(mailbox), + class: FOLDER_ICON_COLOR_MAP[mailbox.color], + }), + to: isScreener + ? { name: 'Screener', params: { accountId: store.accountId } } + : { + name: 'Mailbox', + params: { accountId: store.accountId, mailbox: mailbox.id }, + }, + suffix: mailbox.unread_threads ? String(mailbox.unread_threads) : '', + activeFor: isScreener ? ['Screener'] : [mailbox.id], + menuOptions: isScreener + ? undefined + : [ + { + label: __('Configure'), + icon: Settings, + onClick: () => { + selectedMailbox.value = mailbox + showFolderModal.value = true + }, + }, + { + label: __('Delete'), + theme: 'red', + icon: Trash2, + onClick: () => { + selectedMailbox.value = mailbox + showDeleteMailbox.value = true + }, + }, + ], + } + }) || [], +) + +const screeningEnabled = computed( + () => + !!store.userResource?.data?.accounts?.find((a) => a.id === store.accountId) + ?.enable_screening, ) const sidebarItems = computed(() => { if (route.meta.isDashboard) return dashboardItems + // Screening is a roleless folder; it gets its own nameless group pinned to the top of the + // sidebar, separate from the default and custom mailboxes. + const isScreening = (item: { mailboxId?: string }) => + !!store.mailboxIds.screening && item.mailboxId === store.mailboxIds.screening + + const screenerItem = mailboxItems.value.find((item) => isScreening(item)) + const defaultMailboxes = mailboxItems.value.filter( - (item) => mailboxes.data?.find((m) => m.id === item.activeFor[0])?.role, + (item) => mailboxes.data?.find((m) => m.id === item.mailboxId)?.role, ) const starredItem = { label: __('Starred'), @@ -326,7 +351,8 @@ const sidebarItems = computed(() => { const defaultItems = [...defaultMailboxes, starredItem] const customMailboxes = mailboxItems.value.filter( - (item) => !mailboxes.data?.find((m) => m.id === item.activeFor[0])?.role, + (item) => + !mailboxes.data?.find((m) => m.id === item.mailboxId)?.role && !isScreening(item), ) const addMailboxItem = { label: __('New Folder'), @@ -353,11 +379,15 @@ const sidebarItems = computed(() => { }, ] - return [ + const groups = [ { label: __('Default'), items: defaultItems }, { label: __('Custom'), items: customItems }, { label: __('People'), items: contactsItems }, ] + // Screener is its own nameless group, pinned first — only when screening is enabled. + if (screenerItem && screeningEnabled.value) + groups.unshift({ label: '', items: [screenerItem] }) + return groups }) // Shortcuts diff --git a/frontend/src/components/EmailContent.vue b/frontend/src/components/EmailContent.vue index 40aac5ad7..081d1e4fb 100644 --- a/frontend/src/components/EmailContent.vue +++ b/frontend/src/components/EmailContent.vue @@ -1,4 +1,18 @@