Files
provider_imap/src/components/ImapAuthPanel.vue
T
Sebastian 7485e4c897 feat: lots more improvements
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
2026-04-25 15:43:56 -04:00

158 lines
3.8 KiB
Vue

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { IdentityBasic } from '@KTXM/MailManager/models/identity'
import { ServiceObject } from '@KTXM/MailManager/models/service'
import type { ServiceIdentity, ServiceIdentityBasic } from '@KTXM/MailManager/types/service'
import type { ProviderAuthPanelProps, ProviderAuthPanelEmits } from '@KTXM/MailManager/types/integration'
const props = defineProps<ProviderAuthPanelProps>()
const emit = defineEmits<ProviderAuthPanelEmits>()
const identity = ref('')
const secret = ref('')
const rules = {
required: (value: unknown) => !!value || 'This field is required'
}
const currentIdentity = computed((): ServiceIdentityBasic | null => {
if (!identity.value || !secret.value) {
return null
}
return {
type: 'BA',
identity: identity.value,
secret: secret.value,
}
})
watch(
() => props.service,
service => {
syncFromService(service)
},
{ immediate: true }
)
watch(
() => props.emailAddress,
value => {
if (value && !identity.value) {
identity.value = value
}
},
{ immediate: true }
)
watch(
currentIdentity,
value => {
const existingIdentity = props.service?.identity?.toJson() ?? null
if (sameIdentity(existingIdentity, value)) {
return
}
const nextService = props.service ?? new ServiceObject()
if (value === null) {
nextService.identity = null
emit('update:service', nextService)
return
}
if (nextService.identity instanceof IdentityBasic) {
nextService.identity.identity = value.identity
nextService.identity.secret = value.secret
} else {
nextService.identity = new IdentityBasic(value.identity, value.secret)
}
emit('update:service', nextService)
},
{ immediate: true, deep: true }
)
function syncFromService(service?: ServiceObject) {
const serviceIdentity = service?.identity?.toJson() ?? null
if (serviceIdentity?.type === 'BA') {
identity.value = serviceIdentity.identity || props.prefilledIdentity || props.emailAddress || ''
secret.value = serviceIdentity.secret || props.prefilledSecret || ''
return
}
identity.value = props.prefilledIdentity || props.emailAddress || ''
secret.value = props.prefilledSecret || ''
}
function sameIdentity(a: ServiceIdentity | null, b: ServiceIdentity | null): boolean {
if (a === null || b === null) {
return a === b
}
return a.type === 'BA'
&& b.type === 'BA'
&& a.identity === b.identity
&& a.secret === b.secret
}
</script>
<template>
<div class="imap-auth-panel">
<h3 class="text-h6 mb-4">Authentication</h3>
<p class="text-body-2 mb-6">Provide the username and password your IMAP server expects.</p>
<v-alert type="info" variant="tonal">
Most IMAP servers use your full email address as the username. Use an app password if your mail host requires one.
</v-alert>
<v-text-field
v-model="identity"
label="Username / Email"
hint="Account login used by the IMAP server"
persistent-hint
variant="outlined"
prepend-inner-icon="mdi-account"
class="mb-4"
autocomplete="username"
autocorrect="off"
autocapitalize="none"
:rules="[rules.required]"
/>
<v-text-field
v-model="secret"
type="password"
label="Password"
hint="Password or app-specific password"
persistent-hint
variant="outlined"
prepend-inner-icon="mdi-lock"
class="mb-4"
autocomplete="current-password"
:rules="[rules.required]"
/>
</div>
</template>
<style scoped>
.imap-auth-panel {
max-width: 800px;
}
.text-h6 {
font-size: 1.25rem;
font-weight: 500;
line-height: 2rem;
letter-spacing: 0.0125em;
}
.text-body-2 {
font-size: 0.875rem;
font-weight: 400;
line-height: 1.25rem;
letter-spacing: 0.0178571429em;
color: rgba(var(--v-theme-on-surface), 0.7);
}
</style>