Open and collapse email status checks

This commit is contained in:
Johannes Zellner
2025-09-24 13:13:05 +02:00
parent 0afc671763
commit 0a7d903dd6

View File

@@ -1,7 +1,7 @@
<script setup>
import { ref, onMounted } from 'vue';
import { Button, ProgressBar } from '@cloudron/pankow';
import { Button } from '@cloudron/pankow';
import Section from './Section.vue';
import MailModel from '../models/MailModel.js';
@@ -9,16 +9,43 @@ const props = defineProps([ 'domain' ]);
const mailModel = MailModel.create();
const dnsRecordLabels = {
'mx': 'MX',
'dkim': 'DKIM',
'spf': 'SPF',
'dmarc': 'DMARC',
'ptr4': 'PTR4',
'ptr6': 'PTR6',
};
const dnsRecordLabels = ref({
'mx': {
label: 'MX',
isOpen: false,
},
'dkim': {
label: 'DKIM',
isOpen: false,
},
'spf': {
label: 'SPF',
isOpen: false,
},
'dmarc': {
label: 'DMARC',
isOpen: false,
},
'ptr4': {
label: 'PTR4',
isOpen: false,
},
'ptr6': {
label: 'PTR6',
isOpen: false,
},
});
const rblTypes = [ 'rbl4', 'rbl6' ];
const rblTypes = ref({
'rbl4': {
label: 'rbl4',
isOpen: false,
},
'rbl6': {
label: 'rbl6',
isOpen: false,
},
});
const busy = ref(false);
const mailConfig = ref({});
@@ -30,6 +57,8 @@ async function refresh() {
let [error, result] = await mailModel.status(props.domain);
if (error) return console.error(error);
if (result.relay) result.relay.isOpen = false;
domainStatus.value = result;
[error, result] = await mailModel.config(props.domain);
@@ -56,44 +85,44 @@ onMounted(async () => {
<br/>
<div v-if="domainStatus.mx">
<div v-for="(label, type) in dnsRecordLabels" :key="type">
<div v-for="(item, key) in dnsRecordLabels" :key="key" class="record-item" @click="item.isOpen = !item.isOpen">
<div>
<i v-if="!busy" class="fa-solid" :class="{
'fa-check-circle text-success': domainStatus[type].status === 'passed',
'fa-exclamation-triangle text-danger': domainStatus[type].status === 'failed',
'fa-circle-minus text-warning': domainStatus[type].status === 'skipped',
'fa-check-circle text-success': domainStatus[key].status === 'passed',
'fa-exclamation-triangle text-danger': domainStatus[key].status === 'failed',
'fa-circle-minus text-warning': domainStatus[key].status === 'skipped',
}"></i>
<i v-else class="fa-solid fa-circle-notch fa-spin"></i>
&nbsp;
<b>{{ label }} record</b>
<b>{{ item.label }} record</b>
</div>
<div class="record-details">
<div v-if="type === 'mx' && domain.provider === 'namecheap'">{{ $t('email.dnsStatus.namecheapInfo') }} <sup><a href="https://docs.cloudron.io/domains/#namecheap-dns" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></div>
<div v-if="type === 'ptr4' || type === 'ptr6'">{{ $t('email.dnsStatus.ptrInfo') }} <sup><a href="https://docs.cloudron.io/email/#ptr-record" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></div>
<div v-if="domainStatus[type].status === 'skipped'">{{ domainStatus[type].message }}</div>
<div class="record-details" v-if="item.isOpen" @click.stop>
<div v-if="key === 'mx' && domain.provider === 'namecheap'">{{ $t('email.dnsStatus.namecheapInfo') }} <sup><a href="https://docs.cloudron.io/domains/#namecheap-dns" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></div>
<div v-if="key === 'ptr4' || key === 'ptr6'">{{ $t('email.dnsStatus.ptrInfo') }} <sup><a href="https://docs.cloudron.io/email/#ptr-record" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></div>
<div v-if="domainStatus[key].status === 'skipped'">{{ domainStatus[key].message }}</div>
<div v-else>
<table class="domain-status">
<tbody>
<tr>
<td>{{ $t('email.dnsStatus.hostname') }}:</td>
<td>{{ domainStatus[type].name }}</td>
<td>{{ domainStatus[key].name }}</td>
</tr>
<tr>
<td>{{ $t('email.dnsStatus.domain') }}:</td>
<td>{{ domainStatus[type].domain }}</td>
<td>{{ domainStatus[key].domain }}</td>
</tr>
<tr>
<td>{{ $t('email.dnsStatus.type') }}:</td>
<td>{{ domainStatus[type].type }}</td>
<td>{{ domainStatus[key].type }}</td>
</tr>
<tr>
<td>{{ $t('email.dnsStatus.expected') }}:</td>
<td>{{ domainStatus[type].expected }}</td>
<td>{{ domainStatus[key].expected }}</td>
</tr>
<tr>
<td>{{ $t('email.dnsStatus.current') }}:</td>
<td>{{ domainStatus[type].value ? domainStatus[type].value : ('['+$t('email.dnsStatus.recordNotSet')+']') }} {{ domainStatus[type].message }}</td>
<td>{{ domainStatus[key].value ? domainStatus[key].value : ('['+$t('email.dnsStatus.recordNotSet')+']') }} {{ domainStatus[key].message }}</td>
</tr>
</tbody>
</table>
@@ -101,9 +130,8 @@ onMounted(async () => {
</div>
</div>
</div>
<br/>
<div v-if="domainStatus.relay">
<div v-if="domainStatus.relay" class="record-item" @click="domainStatus.relay.isOpen = !domainStatus.relay.isOpen">
<div>
<i v-if="!busy" class="fa" :class="{
'fa-check-circle text-success': domainStatus.relay.status === 'passed',
@@ -114,30 +142,31 @@ onMounted(async () => {
&nbsp;
<b>{{ $t('email.smtpStatus.outboundSmtp') }}</b>
</div>
<div class="record-details">
<div class="record-details" v-if="domainStatus.relay.isOpen">
{{ domainStatus.relay.message }}
</div>
</div>
<div v-for="type in rblTypes" :key="type">
<div v-if="domainStatus[type]">
<div v-for="(item, key) in rblTypes" :key="key" class="record-item" @click="item.isOpen = !item.isOpen">
<div v-if="domainStatus[key]">
<div>
<i v-if="!busy" class="fa" :class="{
'fa-check-circle text-success': domainStatus[type].status === 'passed',
'fa-exclamation-triangle text-danger': domainStatus[type].status === 'failed',
'fa-circle-minus text-success': domainStatus[type].status === 'skipped',
'fa-check-circle text-success': domainStatus[key].status === 'passed',
'fa-exclamation-triangle text-danger': domainStatus[key].status === 'failed',
'fa-circle-minus text-success': domainStatus[key].status === 'skipped',
}"></i>
<i v-else class="fa-solid fa-circle-notch fa-spin"></i>
&nbsp;
<b>{{ type === 'rbl4' ? 'IPv4' : 'IPv6' }} {{ $t('email.smtpStatus.rblCheck') }}</b>
<b>{{ key === 'rbl4' ? 'IPv4' : 'IPv6' }} {{ $t('email.smtpStatus.rblCheck') }}</b>
</div>
<div class="record-details">
<div v-if="domainStatus[type].status !== 'failed'">{{ domainStatus[type].message }}</div>
<div class="record-details" v-if="item.isOpen">
<div v-if="domainStatus[key].status !== 'failed'">IP: {{ domainStatus[key].ip }}</div>
<div v-else>
<div v-if="domainStatus[type].servers.length" v-html="$t('email.smtpStatus.blacklisted', { ip: domainStatus[type].ip })"></div>
<div v-else v-html="$t('email.smtpStatus.notBlacklisted', { ip: domainStatus[type].ip })"></div>
{{ domainStatus[key] }}
<div v-if="domainStatus[key].servers.length" v-html="$t('email.smtpStatus.blacklisted', { ip: domainStatus[key].ip })"></div>
<div v-else v-html="$t('email.smtpStatus.notBlacklisted', { ip: domainStatus[key].ip })"></div>
<div v-for="server in domainStatus[type].servers" :key="server.name">
<div v-for="server in domainStatus[key].servers" :key="server.name">
<a :href="server.removal" target="_blank">{{ server.name }}</a>
</div>
</div>
@@ -149,6 +178,18 @@ onMounted(async () => {
<style scoped>
.record-item {
border-radius: var(--pankow-border-radius);
padding: 10px;
gap: 10px;
color: var(--pankow-text-color);
cursor: pointer;
}
.record-item:hover {
background-color: var(--pankow-color-background-hover);
}
.record-details {
padding: 10px 30px;
overflow: hidden;