E-Mail Ordner einklappbar machen

KI-AGENT: Ergänzt auf- und zuklappbare IMAP-Ordner in der E-Mail Übersicht. Elternordner bleiben initial sichtbar, ausgewählte Unterordner öffnen automatisch ihre übergeordneten Ordner.
This commit is contained in:
2026-05-23 20:15:43 +02:00
parent 7239ad92e4
commit f2adc21fea

View File

@@ -69,6 +69,7 @@ const loadingMailboxes = ref(false)
const loadingMessages = ref(false)
const loadingMessage = ref(false)
const syncing = ref(false)
const expandedMailboxPaths = ref<string[]>([])
const selectedAccount = computed(() =>
accounts.value.find((account) => account.id === selectedAccountId.value) || null
@@ -144,10 +145,13 @@ const mailboxTree = computed(() => {
})
const mailboxRows = computed(() => {
const rows: Array<{ mailbox: EmailMailbox; depth: number }> = []
const rows: Array<{ mailbox: EmailMailbox; depth: number; hasChildren: boolean }> = []
const append = (node: EmailMailboxNode, depth: number) => {
rows.push({ mailbox: node.mailbox, depth })
node.children.forEach((child) => append(child, depth + 1))
const expanded = expandedMailboxPaths.value.includes(node.mailbox.path)
rows.push({ mailbox: node.mailbox, depth, hasChildren: node.children.length > 0 })
if (expanded) {
node.children.forEach((child) => append(child, depth + 1))
}
}
mailboxTree.value.forEach((node) => append(node, 0))
@@ -186,6 +190,47 @@ const mailboxLabel = (mailbox: EmailMailbox) => {
return mailbox.name || mailbox.path
}
const isMailboxExpanded = (mailbox: EmailMailbox) => expandedMailboxPaths.value.includes(mailbox.path)
const expandMailboxPath = (path: string) => {
if (!expandedMailboxPaths.value.includes(path)) {
expandedMailboxPaths.value = [...expandedMailboxPaths.value, path]
}
}
const collapseMailboxPath = (path: string) => {
expandedMailboxPaths.value = expandedMailboxPaths.value.filter((item) => item !== path)
}
const toggleMailboxExpanded = (mailbox: EmailMailbox) => {
if (isMailboxExpanded(mailbox)) {
collapseMailboxPath(mailbox.path)
} else {
expandMailboxPath(mailbox.path)
}
}
const expandMailboxAncestors = (path: string) => {
const mailbox = mailboxes.value.find((item) => item.path === path)
if (!mailbox) return
const delimiter = mailboxDelimiter(mailbox)
const parts = path.split(delimiter)
while (parts.length > 1) {
parts.pop()
expandMailboxPath(parts.join(delimiter))
}
}
const resetExpandedMailboxes = () => {
const roots = mailboxTree.value.map((node) => node.mailbox.path)
expandedMailboxPaths.value = Array.from(new Set([
...roots,
...expandedMailboxPaths.value.filter((path) => mailboxes.value.some((mailbox) => mailbox.path === path)),
]))
}
const formatAddress = (address?: EmailAddress | null) => {
if (!address) return "Unbekannt"
return address.name || address.address || "Unbekannt"
@@ -254,8 +299,10 @@ async function loadMailboxes() {
try {
mailboxes.value = await $api(`/api/email/accounts/${selectedAccountId.value}/mailboxes`)
resetExpandedMailboxes()
const inbox = mailboxes.value.find((mailbox) => mailbox.specialUse === "\\Inbox" || mailbox.path.toUpperCase() === "INBOX")
selectedMailboxPath.value = inbox?.path || mailboxes.value[0]?.path || "INBOX"
expandMailboxAncestors(selectedMailboxPath.value)
await loadMessages()
} finally {
loadingMailboxes.value = false
@@ -286,6 +333,7 @@ async function loadMessages() {
async function selectMailbox(mailbox: EmailMailbox) {
selectedMailboxPath.value = mailbox.path
expandMailboxAncestors(mailbox.path)
await loadMessages()
}
@@ -467,9 +515,14 @@ onMounted(loadAccounts)
@click="selectMailbox(row.mailbox)"
>
<UIcon
v-if="row.depth > 0"
name="i-heroicons-chevron-right"
v-if="row.hasChildren"
:name="isMailboxExpanded(row.mailbox) ? 'i-heroicons-chevron-down' : 'i-heroicons-chevron-right'"
class="size-3 shrink-0 text-dimmed"
@click.stop="toggleMailboxExpanded(row.mailbox)"
/>
<span
v-else
class="size-3 shrink-0"
/>
<UIcon :name="mailboxIcon(row.mailbox)" class="size-4 shrink-0" />
<span class="min-w-0 flex-1 truncate">{{ mailboxLabel(row.mailbox) }}</span>