Files
cloudron-box/dashboard/src/views/EmailStatusView.vue
T
Girish Ramakrishnan 9428cf0d06 mail: make status a tristate
status can be 'passed', 'failed' or 'skipped'. The motivation for this
change is that when using a relay, we can provide a message indicating
why the check was skipped.
2025-06-28 12:20:25 +02:00

132 lines
4.2 KiB
Vue

<script setup>
import { ref, onMounted } from 'vue';
import { eachLimit } from 'async';
import { Button, Icon } from 'pankow';
import { prettyDecimalSize } from 'pankow/utils';
import Section from '../components/Section.vue';
import StateLED from '../components/StateLED.vue';
import MailDomainStatus from '../components/MailDomainStatus.vue';
import DomainsModel from '../models/DomainsModel.js';
import MailModel from '../models/MailModel.js';
const domainsModel = DomainsModel.create();
const mailModel = MailModel.create();
const refreshBusy = ref(true);
const domains = ref([]);
const expandedDomain = ref('');
async function onRefresh() {
refreshBusy.value = true;
await eachLimit(domains.value, 10, refreshStatus);
refreshBusy.value = false;
}
async function refreshStatus(domain) {
domain.loading = true;
let [error, result] = await mailModel.status(domain.domain);
if (error) {
console.error(error);
} else {
domain.status = Object.keys(result).every((k) => {
return result[k].status === 'passed' || result[k].status === 'skipped';
});
domain.statusCheckDone = true;
}
[error, result] = await mailModel.config(domain.domain);
if (error) {
console.error(error);
} else {
domain.inbound = result.enabled;
domain.outbound = result.relay?.provider !== 'noop';
}
// do this even if no outbound since people forget to remove mailboxes
[error, result] = await mailModel.mailboxCount(domain.domain);
if (error) {
console.error(error);
} else {
domain.mailboxCount = result;
}
domain.loading = false;
[error, result] = await mailModel.usage(domain.domain);
if (error) {
console.error(error);
} else {
domain.usage = 0;
// we used to use quotaValue here but it's quite different wrt diskSize. so choose diskSize consistently
// also, quotaValue can be missing for deleted mailboxes that are on disk but removed from dovecot/ldap itself
Object.keys(result).forEach(function (m) { domain.usage += result[m].diskSize; });
domain.loadingUsage = false;
}
}
function onToggleExpanded(domain) {
expandedDomain.value = expandedDomain.value === domain ? '' : domain;
}
onMounted(async () => {
const [error, result] = await domainsModel.list();
if (error) return console.error(error);
domains.value = result;
onRefresh();
});
</script>
<template>
<div class="content">
<Section title="Mail domain status">
<template #header-buttons>
<Button @click="onRefresh" :disabled="refreshBusy" :loading="refreshBusy">Refresh</Button>
</template>
<div class="domain-list-item" :class="{ active: domain.domain === expandedDomain }" v-for="domain in domains" :key="domain.domain">
<div @click="onToggleExpanded(domain.domain)" style="display: flex; justify-content: space-between; padding: 10px 0;">
<div>
<i class="collapse fa-solid fa-angle-right" :class="{ expanded: domain.domain === expandedDomain }" style="margin-right: 6px;"></i>
<StateLED :busy="!domain.statusCheckDone" :state="domain.status ? 'success' : 'danger'" style="margin-right: 6px"/>
{{ domain.domain }}
</div>
<div v-if="domain.loading">{{ $t('main.loadingPlaceholder') }} ...</div>
<div v-else>
<div v-if="domain.inbound">
<span v-if="domain.loadingUsage">{{ $t('emails.domains.stats', { mailboxCount: domain.mailboxCount }) }} {{ $t('main.loadingPlaceholder') }} ... </span>
<span v-else>{{ $t('emails.domains.stats', { mailboxCount: domain.mailboxCount, usage: prettyDecimalSize(domain.usage) }) }}</span>
</div>
<div v-else>
<span v-if="domain.outbound">{{ $t('emails.domains.outbound') }}</span>
<span v-else>{{ $t('emails.domains.disabled') }}</span>
</div>
</div>
</div>
<MailDomainStatus :domain="domain.domain" v-if="expandedDomain === domain.domain"/>
</div>
</Section>
</div>
</template>
<style scoped>
.domain-list-item {
cursor: pointer;
padding: 0 10px;
margin-bottom: 10px;
border-radius: var(--pankow-border-radius);
}
.domain-list-item.active,
.domain-list-item:hover {
background-color: var(--pankow-color-background-hover);
}
</style>