chore: bunch of improvements
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { ProviderDiscoveryStatus } from '@MailManager/types'
|
||||
|
||||
const props = defineProps<{
|
||||
address: string
|
||||
status: Record<string, ProviderDiscoveryStatus>
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'select': [providerId: string]
|
||||
'advanced': [providerId: string]
|
||||
'manual': []
|
||||
'back': []
|
||||
}>()
|
||||
|
||||
const sortedStatus = computed(() => {
|
||||
const statusArray = Object.values(props.status)
|
||||
const order: Record<string, number> = { success: 0, discovering: 1, pending: 2, failed: 3 }
|
||||
return statusArray.sort((a, b) => order[a.status] - order[b.status])
|
||||
})
|
||||
|
||||
const progressPercent = computed(() => {
|
||||
const total = Object.keys(props.status).length
|
||||
if (total === 0) return 0
|
||||
|
||||
const completed = Object.values(props.status).filter(
|
||||
s => s.status === 'success' || s.status === 'failed'
|
||||
).length
|
||||
|
||||
return (completed / total) * 100
|
||||
})
|
||||
|
||||
const isDiscovering = computed(() => {
|
||||
return Object.values(props.status).some(
|
||||
s => s.status === 'discovering' || s.status === 'pending'
|
||||
)
|
||||
})
|
||||
|
||||
const successCount = computed(() => {
|
||||
return Object.values(props.status).filter(s => s.status === 'success').length
|
||||
})
|
||||
|
||||
function getStatusColor(status: string): string {
|
||||
const colors: Record<string, string> = {
|
||||
success: 'success',
|
||||
failed: 'error',
|
||||
discovering: 'primary',
|
||||
pending: 'grey'
|
||||
}
|
||||
return colors[status] || 'grey'
|
||||
}
|
||||
|
||||
function getProviderLabel(providerId: string): string {
|
||||
const labels: Record<string, string> = {
|
||||
jmap: 'JMAP',
|
||||
smtp: 'SMTP/IMAP',
|
||||
imap: 'IMAP',
|
||||
exchange: 'Microsoft Exchange'
|
||||
}
|
||||
return labels[providerId] || providerId.toUpperCase()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="discovery-status-step">
|
||||
<h3 class="text-h6 mb-2">Discovering Mail Servers</h3>
|
||||
<p class="text-body-2 text-medium-emphasis mb-6">
|
||||
Testing {{ address }} across multiple providers...
|
||||
</p>
|
||||
|
||||
<!-- Overall Progress -->
|
||||
<v-progress-linear
|
||||
:model-value="progressPercent"
|
||||
color="primary"
|
||||
height="8"
|
||||
rounded
|
||||
class="mb-6"
|
||||
/>
|
||||
|
||||
<!-- Provider Status List -->
|
||||
<v-list class="provider-status-list">
|
||||
<v-list-item
|
||||
v-for="status in sortedStatus"
|
||||
:key="status.provider"
|
||||
class="provider-status-item mb-2"
|
||||
:class="`status-${status.status}`"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-avatar :color="getStatusColor(status.status)" size="40">
|
||||
<v-icon v-if="status.status === 'success'" color="white">
|
||||
mdi-check
|
||||
</v-icon>
|
||||
<v-icon v-else-if="status.status === 'failed'" color="white">
|
||||
mdi-close
|
||||
</v-icon>
|
||||
<v-progress-circular
|
||||
v-else-if="status.status === 'discovering'"
|
||||
indeterminate
|
||||
size="24"
|
||||
width="3"
|
||||
color="white"
|
||||
/>
|
||||
<v-icon v-else color="white">
|
||||
mdi-clock-outline
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
</template>
|
||||
|
||||
<v-list-item-title class="d-flex align-center gap-2">
|
||||
<span class="font-weight-medium">{{ getProviderLabel(status.provider) }}</span>
|
||||
<v-chip
|
||||
v-if="status.status === 'success'"
|
||||
size="x-small"
|
||||
color="success"
|
||||
variant="flat"
|
||||
>
|
||||
Found
|
||||
</v-chip>
|
||||
<v-chip
|
||||
v-else-if="status.status === 'failed'"
|
||||
size="x-small"
|
||||
color="error"
|
||||
variant="flat"
|
||||
>
|
||||
{{ status.error || 'Failed' }}
|
||||
</v-chip>
|
||||
<v-chip
|
||||
v-else-if="status.status === 'discovering'"
|
||||
size="x-small"
|
||||
color="primary"
|
||||
variant="flat"
|
||||
>
|
||||
Testing...
|
||||
</v-chip>
|
||||
</v-list-item-title>
|
||||
|
||||
<v-list-item-subtitle v-if="status.status === 'success' && status.metadata">
|
||||
<div class="text-caption">
|
||||
<v-icon size="14" class="mr-1">mdi-server</v-icon>
|
||||
{{ status.metadata.host }}{{ status.metadata.port ? ':' + status.metadata.port : '' }}
|
||||
<span v-if="status.metadata.protocol" class="ml-2">
|
||||
<v-icon size="14" class="mr-1">mdi-shield-lock</v-icon>
|
||||
{{ status.metadata.protocol.toUpperCase() }}
|
||||
</span>
|
||||
</div>
|
||||
</v-list-item-subtitle>
|
||||
|
||||
<template #append>
|
||||
<div v-if="status.status === 'success'" class="d-flex gap-2">
|
||||
<v-btn
|
||||
size="small"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
prepend-icon="mdi-check"
|
||||
@click="$emit('select', status.provider)"
|
||||
>
|
||||
Select
|
||||
</v-btn>
|
||||
<v-tooltip text="Advanced configuration">
|
||||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
size="small"
|
||||
variant="outlined"
|
||||
icon="mdi-tune"
|
||||
@click="$emit('advanced', status.provider)"
|
||||
/>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<!-- No Results Message -->
|
||||
<v-alert
|
||||
v-if="!isDiscovering && successCount === 0"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
class="mt-6"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon>mdi-alert</v-icon>
|
||||
</template>
|
||||
<div>
|
||||
<div class="font-weight-medium mb-1">No configurations found</div>
|
||||
<div class="text-caption">
|
||||
We couldn't automatically discover server settings for {{ address }}.
|
||||
You can try manual configuration instead.
|
||||
</div>
|
||||
</div>
|
||||
</v-alert>
|
||||
|
||||
<div
|
||||
v-if="!isDiscovering && successCount === 0"
|
||||
class="mt-6"
|
||||
>
|
||||
<v-btn
|
||||
size="large"
|
||||
variant="text"
|
||||
block
|
||||
class="manual-action-btn"
|
||||
prepend-icon="mdi-tune"
|
||||
@click="$emit('manual')"
|
||||
>
|
||||
Manual Configuration
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.provider-status-item {
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.provider-status-item.status-success {
|
||||
background-color: rgba(var(--v-theme-success), 0.05);
|
||||
}
|
||||
|
||||
.provider-status-item.status-discovering {
|
||||
background-color: rgba(var(--v-theme-primary), 0.05);
|
||||
}
|
||||
|
||||
.gap-2 {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.gap-3 {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.manual-action-btn {
|
||||
background-color: rgba(var(--v-theme-on-surface), 0.06);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user