Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 0 additions & 55 deletions packages/web-app-mail/src/components/MailAccountList.vue

This file was deleted.

86 changes: 86 additions & 0 deletions packages/web-app-mail/src/components/MailAccountSwitch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<template>
<oc-button
id="account-list-toggle"
class="w-full"
appearance="filled"
color-role="surface"
justify-content="space-between"
no-hover
>
<app-loading-spinner v-if="isLoading" />
<div v-else class="flex justify-between items-center w-full">
<div class="flex items-center truncate">
<oc-avatar :user-name="currentAccount.name" />
<div class="flex flex-col items-start ml-5 truncate">
<span class="font-bold" v-text="currentAccount.name" />
<span
v-if="currentAccount.identities?.[0]?.email"
v-text="currentAccount.identities[0].email"
/>
</div>
</div>
<oc-icon class="ml-2" name="more-2" />
</div>
</oc-button>
<oc-drop :title="$gettext('Accounts')" class="w-md" toggle="#account-list-toggle" close-on-click>
<oc-list>
<li v-for="account in accounts" :key="account.accountId" class="oc-list">
<oc-button
class="p-2"
:appearance="account.accountId === currentAccount.accountId ? 'filled' : 'raw-inverse'"
:color-role="
account.accountId === currentAccount.accountId ? 'secondaryContainer' : 'surface'
"
@click="onSelectAccount(account)"
>
<div class="flex justify-between items-center w-full">
<div class="flex items-center truncate">
<oc-avatar :user-name="account.name" />
<div class="flex flex-col items-start ml-5 truncate">
<span class="font-bold" v-text="account.name" />
<span v-if="account.identities?.[0]?.email" v-text="account.identities[0].email" />
</div>
</div>
<oc-icon
v-if="account.accountId === currentAccount.accountId"
class="ml-2"
name="check"
/>
</div>
</oc-button>
</li>
</oc-list>
</oc-drop>
</template>

<script setup lang="ts">
import { AppLoadingSpinner } from '@opencloud-eu/web-pkg'
import type { MailAccount } from '../types'
import { useLoadAccounts } from '../composables/useLoadAccounts'
import { useAccountsStore } from '../composables/piniaStores/accounts'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just noticing it here: could you add index.ts files which export all the files of a dir, so that we can merge multiple imports into one line? like we do it in all other apps and packages...

import { storeToRefs } from 'pinia'
import { useMailboxesStore } from '../composables/piniaStores/mailboxes'
import { useLoadMailboxes } from '../composables/useLoadMailboxes'
import { unref } from 'vue'
import { useLoadMails } from '../composables/useLoadMails'
import { useMailsStore } from '../composables/piniaStores/mails'

const accountsStore = useAccountsStore()
const { accounts, currentAccount } = storeToRefs(accountsStore)
const { setCurrentAccount } = accountsStore
const mailboxesStore = useMailboxesStore()
const { mailboxes, currentMailbox } = storeToRefs(mailboxesStore)
const { setCurrentMailbox } = mailboxesStore
const { loadMailboxes } = useLoadMailboxes()
const { loadMails } = useLoadMails()
const { setCurrentMail } = useMailsStore()
const { isLoading } = useLoadAccounts()

const onSelectAccount = async (account: MailAccount) => {
setCurrentAccount(account)
setCurrentMail(null)
await loadMailboxes(unref(currentAccount).accountId)
setCurrentMailbox(unref(mailboxes)[0])
await loadMails(unref(currentAccount).accountId, unref(currentMailbox).id)
Comment on lines +83 to +84
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential runtime error if mailboxes array is empty after loading. Add a check to ensure the array has at least one element before accessing index 0.

Suggested change
setCurrentMailbox(unref(mailboxes)[0])
await loadMails(unref(currentAccount).accountId, unref(currentMailbox).id)
if (unref(mailboxes) && unref(mailboxes).length > 0) {
setCurrentMailbox(unref(mailboxes)[0])
await loadMails(unref(currentAccount).accountId, unref(mailboxes)[0].id)
} else {
setCurrentMailbox(null)
// Optionally handle the empty mailbox case here (e.g., show a message)
}

Copilot uses AI. Check for mistakes.
}
</script>
84 changes: 45 additions & 39 deletions packages/web-app-mail/src/components/MailboxTree.vue
Original file line number Diff line number Diff line change
@@ -1,44 +1,49 @@
<template>
<div class="mailbox-tree h-full px-1">
<h1 v-if="currentAccount" class="text-lg ml-4 truncate" v-text="currentAccount.name" />
<app-loading-spinner v-if="isLoading" />
<template v-else>
<no-content-message v-if="!mailboxes?.length" icon="folder-reduce" icon-fill-type="line">
<template #message>
<span v-text="$gettext('No mailboxes found')" />
</template>
</no-content-message>
<div v-else>
<oc-list class="mailbox-tree mt-1">
<li v-for="mailbox in mailboxes" :key="mailbox.id" class="pb-1 px-2">
<oc-button
class="w-full p-2 hover:bg-role-surface-container-highest focus:bg-role-surface-container-highest"
:class="{ '!bg-role-secondary-container': currentMailbox?.id === mailbox.id }"
no-hover
justify-content="left"
appearance="raw"
size="small"
@click="onSelectMailbox(mailbox)"
>
<div class="flex items-center justify-between w-full">
<div class="flex items-center truncate">
<oc-icon name="folder" class="mr-2" fill-type="line" />
<span class="truncate" v-text="mailbox.name" />
<div class="mailbox-tree h-full px-1 flex flex-col">
<div>
<h1 v-if="currentAccount" class="text-lg ml-4 truncate" v-text="currentAccount.name" />
<app-loading-spinner v-if="isLoading" />
<template v-else>
<no-content-message v-if="!mailboxes?.length" icon="folder-reduce" icon-fill-type="line">
<template #message>
<span v-text="$gettext('No mailboxes found')" />
</template>
</no-content-message>
<div v-else>
<oc-list class="mailbox-tree mt-1">
<li v-for="mailbox in mailboxes" :key="mailbox.id" class="pb-1 px-2">
<oc-button
class="w-full p-2 hover:bg-role-surface-container-highest focus:bg-role-surface-container-highest"
:class="{ '!bg-role-secondary-container': currentMailbox?.id === mailbox.id }"
no-hover
justify-content="left"
appearance="raw"
size="small"
@click="onSelectMailbox(mailbox)"
>
<div class="flex items-center justify-between w-full">
<div class="flex items-center truncate">
<oc-icon name="folder" class="mr-2" fill-type="line" />
<span class="truncate" v-text="mailbox.name" />
</div>
<oc-tag
v-if="mailbox.unreadEmails"
v-oc-tooltip="$gettext('Unread emails')"
class="ml-2"
appearance="filled"
:rounded="true"
><span v-text="mailbox.unreadEmails"
/></oc-tag>
</div>
<oc-tag
v-if="mailbox.unreadEmails"
v-oc-tooltip="$gettext('Unread emails')"
class="ml-2"
appearance="filled"
:rounded="true"
><span v-text="mailbox.unreadEmails"
/></oc-tag>
</div>
</oc-button>
</li>
</oc-list>
</div>
</template>
</oc-button>
</li>
</oc-list>
</div>
</template>
</div>
<div class="w-full self-end mt-auto px-2 py-4">
<MailAccountSwitch />
</div>
</div>
</template>

Expand All @@ -52,6 +57,7 @@ import { useAccountsStore } from '../composables/piniaStores/accounts'
import { useMailsStore } from '../composables/piniaStores/mails'
import { useLoadMails } from '../composables/useLoadMails'
import { unref } from 'vue'
import MailAccountSwitch from './MailAccountSwitch.vue'

const mailboxesStore = useMailboxesStore()
const accountsStore = useAccountsStore()
Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-mail/src/composables/useLoadAccounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const useLoadAccounts = () => {
}).restartable()
}

const loadAccounts = async () => {
const loadAccounts = () => {
return loadAccountsTask!.perform()
}

Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-mail/src/composables/useLoadMail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const useLoadMail = () => {
}).restartable()
}

const loadMail = async (accountId: string, mailId: string) => {
const loadMail = (accountId: string, mailId: string) => {
return loadMailTask!.perform(accountId, mailId)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-mail/src/composables/useLoadMailboxes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const useLoadMailboxes = () => {
}).restartable()
}

const loadMailboxes = async (accountId: string) => {
const loadMailboxes = (accountId: string) => {
return loadMailboxesTask!.perform(accountId)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-mail/src/composables/useLoadMails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const useLoadMails = () => {
}).restartable()
}

const loadMails = async (accountId: string, mailboxId: string) => {
const loadMails = (accountId: string, mailboxId: string) => {
return loadMailsTask!.perform(accountId, mailboxId)
}

Expand Down
5 changes: 0 additions & 5 deletions packages/web-app-mail/src/views/Inbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
'hidden md:flex': currentMailbox
}"
>
<div class="border-r-2 overflow-y-auto bg-role-surface-container w-[100px]">
<MailAccountList />
</div>

<div class="overflow-y-auto md:border-r-2 bg-role-surface-container w-full">
<MailboxTree />
</div>
Expand Down Expand Up @@ -41,7 +37,6 @@ import { ref, unref, onMounted } from 'vue'
import MailList from '../components/MailList.vue'
import MailDetails from '../components/MailDetails.vue'
import MailboxTree from '../components/MailboxTree.vue'
import MailAccountList from '../components/MailAccountList.vue'
import { AppLoadingSpinner, queryItemAsString } from '@opencloud-eu/web-pkg'
import { useRouteQuery } from '@opencloud-eu/web-pkg'
import { useMailsStore } from '../composables/piniaStores/mails'
Expand Down