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:
@@ -69,6 +69,7 @@ const loadingMailboxes = ref(false)
|
|||||||
const loadingMessages = ref(false)
|
const loadingMessages = ref(false)
|
||||||
const loadingMessage = ref(false)
|
const loadingMessage = ref(false)
|
||||||
const syncing = ref(false)
|
const syncing = ref(false)
|
||||||
|
const expandedMailboxPaths = ref<string[]>([])
|
||||||
|
|
||||||
const selectedAccount = computed(() =>
|
const selectedAccount = computed(() =>
|
||||||
accounts.value.find((account) => account.id === selectedAccountId.value) || null
|
accounts.value.find((account) => account.id === selectedAccountId.value) || null
|
||||||
@@ -144,10 +145,13 @@ const mailboxTree = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const mailboxRows = 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) => {
|
const append = (node: EmailMailboxNode, depth: number) => {
|
||||||
rows.push({ mailbox: node.mailbox, depth })
|
const expanded = expandedMailboxPaths.value.includes(node.mailbox.path)
|
||||||
node.children.forEach((child) => append(child, depth + 1))
|
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))
|
mailboxTree.value.forEach((node) => append(node, 0))
|
||||||
@@ -186,6 +190,47 @@ const mailboxLabel = (mailbox: EmailMailbox) => {
|
|||||||
return mailbox.name || mailbox.path
|
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) => {
|
const formatAddress = (address?: EmailAddress | null) => {
|
||||||
if (!address) return "Unbekannt"
|
if (!address) return "Unbekannt"
|
||||||
return address.name || address.address || "Unbekannt"
|
return address.name || address.address || "Unbekannt"
|
||||||
@@ -254,8 +299,10 @@ async function loadMailboxes() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
mailboxes.value = await $api(`/api/email/accounts/${selectedAccountId.value}/mailboxes`)
|
mailboxes.value = await $api(`/api/email/accounts/${selectedAccountId.value}/mailboxes`)
|
||||||
|
resetExpandedMailboxes()
|
||||||
const inbox = mailboxes.value.find((mailbox) => mailbox.specialUse === "\\Inbox" || mailbox.path.toUpperCase() === "INBOX")
|
const inbox = mailboxes.value.find((mailbox) => mailbox.specialUse === "\\Inbox" || mailbox.path.toUpperCase() === "INBOX")
|
||||||
selectedMailboxPath.value = inbox?.path || mailboxes.value[0]?.path || "INBOX"
|
selectedMailboxPath.value = inbox?.path || mailboxes.value[0]?.path || "INBOX"
|
||||||
|
expandMailboxAncestors(selectedMailboxPath.value)
|
||||||
await loadMessages()
|
await loadMessages()
|
||||||
} finally {
|
} finally {
|
||||||
loadingMailboxes.value = false
|
loadingMailboxes.value = false
|
||||||
@@ -286,6 +333,7 @@ async function loadMessages() {
|
|||||||
|
|
||||||
async function selectMailbox(mailbox: EmailMailbox) {
|
async function selectMailbox(mailbox: EmailMailbox) {
|
||||||
selectedMailboxPath.value = mailbox.path
|
selectedMailboxPath.value = mailbox.path
|
||||||
|
expandMailboxAncestors(mailbox.path)
|
||||||
await loadMessages()
|
await loadMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,9 +515,14 @@ onMounted(loadAccounts)
|
|||||||
@click="selectMailbox(row.mailbox)"
|
@click="selectMailbox(row.mailbox)"
|
||||||
>
|
>
|
||||||
<UIcon
|
<UIcon
|
||||||
v-if="row.depth > 0"
|
v-if="row.hasChildren"
|
||||||
name="i-heroicons-chevron-right"
|
:name="isMailboxExpanded(row.mailbox) ? 'i-heroicons-chevron-down' : 'i-heroicons-chevron-right'"
|
||||||
class="size-3 shrink-0 text-dimmed"
|
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" />
|
<UIcon :name="mailboxIcon(row.mailbox)" class="size-4 shrink-0" />
|
||||||
<span class="min-w-0 flex-1 truncate">{{ mailboxLabel(row.mailbox) }}</span>
|
<span class="min-w-0 flex-1 truncate">{{ mailboxLabel(row.mailbox) }}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user