diff --git a/dashboard/src/components/MailboxDialog.vue b/dashboard/src/components/MailboxDialog.vue index a09479701..c718fe976 100644 --- a/dashboard/src/components/MailboxDialog.vue +++ b/dashboard/src/components/MailboxDialog.vue @@ -88,7 +88,7 @@ async function onSubmit() { } } - emit('success'); + emit('success', { domain: domain.value, name: name.value, fullName: name.value + '@' + domain.value }); dialog.value.close(); busy.value = false; } diff --git a/dashboard/src/views/EmailMailboxesView.vue b/dashboard/src/views/EmailMailboxesView.vue index 89a08f3c6..0b45c850e 100644 --- a/dashboard/src/views/EmailMailboxesView.vue +++ b/dashboard/src/views/EmailMailboxesView.vue @@ -108,7 +108,7 @@ const filteredMailboxes = computed(() => { }); const filteredMailboxesUsage = computed(() => { - return filteredMailboxes.value.reduce((acc, m) => acc + (m.usage && m.usage.diskSize), 0); + return filteredMailboxes.value.reduce((acc, m) => acc + (cachedMailboxUsage.value[m.fullName] && cachedMailboxUsage.value[m.fullName].diskSize), 0); }); const mailboxDialog = useTemplateRef('mailboxDialog'); @@ -144,59 +144,68 @@ async function onSubmitRemove() { return console.error(error); } - await refresh(); + const idx = mailboxes.value.findIndex(mbox => mbox.fullName === removeMailbox.value.fullName); + if (idx !== -1) mailboxes.value.splice(idx, 1); + removeDialog.value.close(); removeBusy.value = false; } +const cachedMailboxUsage = ref({}); + +async function refreshDomainUsage(domain) { + const [error, usage] = await mailModel.usage(domain); + // retry if mail addon cannot be reached during restarts + if (error && error.status === 424) return setTimeout(refresh, 2000); + else if (error) return console.error(error); + + mailboxes.value.forEach((m) => { + if (usage[m.fullName]) cachedMailboxUsage.value[m.fullName] = usage[m.fullName]; + }); + + mailboxesUsage.value = mailboxes.value.reduce((acc, m) => acc + (cachedMailboxUsage.value[m.fullName] && cachedMailboxUsage.value[m.fullName].diskSize), 0); +} + async function refreshUsage() { - async function refreshForDomain(domain) { - const [error, usage] = await mailModel.usage(domain); - // retry if mail addon cannot be reached during restarts - if (error && error.status === 424) return setTimeout(refresh, 2000); - else if (error) return console.error(error); - - mailboxes.value.forEach((m) => { - m.usage = usage[m.fullName] ?? { diskSize: 0}; // can be missing from response if no email has been received by dovecot - }); - } - try { - await eachLimit(domains.value.map(d => d.domain), 10, refreshForDomain); + await eachLimit(domains.value.map(d => d.domain), 10, refreshDomainUsage); } catch (error) { return console.error(error); } +} - mailboxesUsage.value = mailboxes.value.reduce((acc, m) => acc + (m.usage && m.usage.diskSize), 0); +async function refreshDomain(domain) { + const [error, result] = await mailboxesModel.list(domain); + if (error) throw error; + + result.forEach((m) => { + m.fullName = m.name + '@' + m.domain; + + m.owner = users.value.find(u => u.id === m.ownerId) || null; + if (!m.owner) m.owner = groups.value.find(g => g.id === m.ownerId) || null; + + m.ownerDisplayName = m.owner ? (m.owner.username || m.owner.name) : ''; + cachedMailboxUsage.value[m.fullName] = cachedMailboxUsage.value[m.fullName] || { diskSize: 0 }; + + // update in-place or add + const idx = mailboxes.value.findIndex(mbox => mbox.fullName === m.fullName); + if (idx !== -1) mailboxes.value[idx] = m; + else mailboxes.value.push(m); + }); } async function refresh() { - let tmp = []; - async function refreshForDomain(domain) { - const [error, result] = await mailboxesModel.list(domain); - if (error) throw error; - - result.forEach((m) => { - m.fullName = m.name + '@' + m.domain; - - m.owner = users.value.find(u => u.id === m.ownerId) || null; - if (!m.owner) m.owner = groups.value.find(g => g.id === m.ownerId) || null; - - m.ownerDisplayName = m.owner ? (m.owner.username || m.owner.name) : ''; - m.usage = -1; - }); - - tmp = tmp.concat(result); - } - try { - await eachLimit(domains.value.map(d => d.domain), 10, refreshForDomain); + await eachLimit(domains.value.map(d => d.domain), 10, refreshDomain); } catch (error) { return console.error(error); } +} - mailboxes.value = tmp; +async function onMailboxDialogSuccess(mailbox) { + await refreshDomain(mailbox.domain); + await refreshDomainUsage(mailbox.domain); } onMounted(async () => { @@ -250,7 +259,7 @@ onMounted(async () => { - +