email server updates

This commit is contained in:
2025-06-12 18:05:42 +02:00
parent be935e2ba6
commit f111f76a3b
4 changed files with 954 additions and 5 deletions

View File

@@ -5,15 +5,13 @@
Email History
<v-spacer />
<v-btn
:icon="mobile ? undefined : 'mdi-refresh'"
:size="mobile ? 'default' : 'small'"
icon="mdi-refresh"
:size="mobile ? 'small' : 'small'"
variant="text"
@click="loadEmails"
:loading="loading"
:class="mobile ? 'rounded-circle' : ''"
>
<v-icon v-if="!loading">mdi-refresh</v-icon>
<v-tooltip v-if="mobile" activator="parent" location="bottom">
<v-tooltip activator="parent" location="bottom">
Refresh emails
</v-tooltip>
</v-btn>
@@ -95,6 +93,34 @@
Show less
</div>
</div>
<!-- Attachments Section -->
<div v-if="email.attachments && email.attachments.length > 0" class="mt-3">
<v-divider class="mb-2" />
<div class="text-caption text-grey mb-2">
<v-icon size="small" class="mr-1">mdi-paperclip</v-icon>
{{ email.attachments.length }} Attachment{{ email.attachments.length > 1 ? 's' : '' }}
</div>
<div class="d-flex flex-wrap gap-2">
<v-chip
v-for="(attachment, index) in email.attachments"
:key="index"
size="small"
variant="outlined"
:prepend-icon="getAttachmentIcon(attachment.contentType)"
@click="downloadAttachment(attachment)"
:disabled="!!attachment.error"
>
<span class="text-truncate" style="max-width: 150px">
{{ attachment.filename }}
</span>
<span class="text-caption ml-1">({{ formatFileSize(attachment.size) }})</span>
<v-tooltip v-if="attachment.error" activator="parent">
{{ attachment.error }}
</v-tooltip>
</v-chip>
</div>
</div>
</v-card-text>
<v-card-actions>
<v-spacer />
@@ -136,6 +162,16 @@ interface EmailMessage {
timestamp: string;
direction: 'sent' | 'received';
threadId?: string;
attachments?: Array<{
id?: string;
filename: string;
originalName?: string;
contentType: string;
size: number;
path?: string;
bucket?: string;
error?: string;
}>;
}
interface EmailThread {
@@ -269,6 +305,57 @@ const reloadEmails = () => {
loadEmails();
};
// Get icon for attachment based on content type
const getAttachmentIcon = (contentType: string) => {
if (!contentType) return 'mdi-file';
if (contentType.startsWith('image/')) return 'mdi-file-image';
if (contentType.startsWith('video/')) return 'mdi-file-video';
if (contentType.startsWith('audio/')) return 'mdi-file-music';
if (contentType.includes('pdf')) return 'mdi-file-pdf-box';
if (contentType.includes('word') || contentType.includes('document')) return 'mdi-file-word';
if (contentType.includes('sheet') || contentType.includes('excel')) return 'mdi-file-excel';
if (contentType.includes('powerpoint') || contentType.includes('presentation')) return 'mdi-file-powerpoint';
if (contentType.includes('zip') || contentType.includes('compressed')) return 'mdi-folder-zip';
return 'mdi-file';
};
// Format file size for display
const formatFileSize = (bytes: number) => {
if (!bytes || bytes === 0) return '0 B';
const units = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return `${(bytes / Math.pow(1024, i)).toFixed(1)} ${units[i]}`;
};
// Download attachment
const downloadAttachment = async (attachment: any) => {
if (!attachment.path || !attachment.bucket) {
toast.error('Attachment information is missing');
return;
}
try {
// Use the proxy download endpoint
const downloadUrl = `/api/files/proxy-download?bucket=${attachment.bucket}&fileName=${encodeURIComponent(attachment.path)}`;
// Create a temporary link and trigger download
const link = document.createElement('a');
link.href = downloadUrl;
link.download = attachment.originalName || attachment.filename;
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (error) {
console.error('Failed to download attachment:', error);
toast.error('Failed to download attachment');
}
};
// Load emails on mount
onMounted(() => {
loadEmails();