feat: attachment preview
Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
@@ -2,7 +2,18 @@
|
||||
import { computed } from 'vue'
|
||||
import RecipientDetails from '@/components/common/RecipientDetails.vue'
|
||||
import { formatFileSize } from '@/utile/format'
|
||||
import { mediaViewerCanDisplay, mediaViewerComponent } from '@/services/mediaViewer'
|
||||
import { useMailUiStore } from '@/stores/mailUiStore'
|
||||
import type { EntityObject } from '@MailManager/models';
|
||||
import type { MessagePartInterface } from '@MailManager/types/message';
|
||||
|
||||
interface AttachmentItem {
|
||||
id: string
|
||||
title: string
|
||||
mime: string
|
||||
size?: number | null
|
||||
meta: { index: number; attachment: MessagePartInterface }
|
||||
}
|
||||
|
||||
interface Props {
|
||||
entity: EntityObject | null
|
||||
@@ -11,9 +22,13 @@ interface Props {
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
downloadAttachment: [index: number]
|
||||
download: [index: number]
|
||||
preview: [index: number]
|
||||
}>()
|
||||
|
||||
const mailUiStore = useMailUiStore()
|
||||
const previewPopover = computed(() => mediaViewerComponent('popover'))
|
||||
|
||||
const message = computed(() => {
|
||||
return props.entity?.properties ?? null
|
||||
})
|
||||
@@ -22,6 +37,33 @@ const randomKey = computed(() => {
|
||||
return Math.random().toString(36).substring(2, 15)
|
||||
})
|
||||
|
||||
const attachmentItems = computed<AttachmentItem[]>(() =>
|
||||
(message.value?.attachments ?? []).map((attachment, index) => ({
|
||||
id: attachment.partId || attachment.blobId || attachment.cid || `att-${index}`,
|
||||
title: attachment.name || 'Attachment',
|
||||
mime: attachment.type || '',
|
||||
size: attachment.size ?? null,
|
||||
meta: { index, attachment },
|
||||
})),
|
||||
)
|
||||
|
||||
const isPreviewable = (attachment: MessagePartInterface): boolean => {
|
||||
return mediaViewerCanDisplay(attachment.type)
|
||||
}
|
||||
|
||||
const handleAttachmentClick = (attachment: MessagePartInterface, index: number): void => {
|
||||
if (isPreviewable(attachment)) {
|
||||
emit('preview', index)
|
||||
} else {
|
||||
emit('download', index)
|
||||
}
|
||||
}
|
||||
|
||||
const handleViewerRetrieve = (item: AttachmentItem): Promise<Blob> => {
|
||||
if (!props.entity) return Promise.reject(new Error('No message selected'))
|
||||
return mailUiStore.attachmentBlob(props.entity, item.meta.attachment)
|
||||
}
|
||||
|
||||
// Format date for display
|
||||
const formatDate = (date: Date | string | null | undefined): string => {
|
||||
if (!date) return ''
|
||||
@@ -37,10 +79,6 @@ const formatDate = (date: Date | string | null | undefined): string => {
|
||||
hour12: true
|
||||
})
|
||||
}
|
||||
|
||||
const download = async (index: number): Promise<void> => {
|
||||
emit('downloadAttachment', index)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -101,21 +139,31 @@ const download = async (index: number): Promise<void> => {
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<div
|
||||
v-for="(attachment, index) in message?.attachments"
|
||||
:key="randomKey"
|
||||
:key="attachment.partId || attachment.blobId || attachment.cid || index"
|
||||
class="attachment-item"
|
||||
>
|
||||
<v-chip
|
||||
prepend-icon="mdi-paperclip"
|
||||
:prepend-icon="isPreviewable(attachment) ? 'mdi-eye-outline' : 'mdi-paperclip'"
|
||||
size="small"
|
||||
variant="outlined"
|
||||
class="attachment-chip"
|
||||
@click="download(index)"
|
||||
:title="isPreviewable(attachment) ? 'Preview' : 'Download'"
|
||||
@click="handleAttachmentClick(attachment, index)"
|
||||
>
|
||||
<span class="attachment-name">{{ attachment.name || 'Untitled' }}</span>
|
||||
<span v-if="attachment.size != null" class="text-caption text-medium-emphasis ml-1">
|
||||
({{ formatFileSize(attachment.size) }})
|
||||
</span>
|
||||
</v-chip>
|
||||
|
||||
<!-- Hover preview (provided by the media_viewer module) -->
|
||||
<component
|
||||
:is="previewPopover"
|
||||
v-if="previewPopover && isPreviewable(attachment)"
|
||||
:item="attachmentItems[index]"
|
||||
:source="handleViewerRetrieve"
|
||||
@expand="emit('preview', index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user