mirror of
https://github.com/axllent/mailpit.git
synced 2026-03-03 00:27:01 +00:00
Feature: Option to display/hide attachment information in message view in web UI including checksums, content type & disposition
Resolves #625
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script>
|
||||
import commonMixins from "../../mixins/CommonMixins";
|
||||
import { mailbox } from "../../stores/mailbox";
|
||||
import ICAL from "ical.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@@ -19,6 +20,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
mailbox,
|
||||
ical: false,
|
||||
};
|
||||
},
|
||||
@@ -74,46 +76,119 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mt-4 border-top pt-4">
|
||||
<a
|
||||
<hr />
|
||||
|
||||
<button
|
||||
class="btn btn-sm btn-outline-secondary mb-3"
|
||||
@click="mailbox.showAttachmentDetails = !mailbox.showAttachmentDetails"
|
||||
>
|
||||
<i class="bi me-1" :class="mailbox.showAttachmentDetails ? 'bi-eye-slash' : 'bi-eye'"></i>
|
||||
{{ mailbox.showAttachmentDetails ? "Hide" : "Show" }} attachment details
|
||||
</button>
|
||||
|
||||
<div class="row mb-3 gx-1">
|
||||
<div
|
||||
v-for="part in attachments"
|
||||
:key="part.PartID"
|
||||
:href="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID)"
|
||||
class="card attachment float-start me-3 mb-3"
|
||||
target="_blank"
|
||||
style="width: 180px"
|
||||
@click="openAttachment(part, $event)"
|
||||
:class="mailbox.showAttachmentDetails ? 'col-12' : 'col-auto'"
|
||||
>
|
||||
<img
|
||||
v-if="isImage(part)"
|
||||
:src="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID + '/thumb')"
|
||||
class="card-img-top"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAB4AQMAAABhKUq+AAAAA1BMVEX///+nxBvIAAAAGUlEQVQYGe3BgQAAAADDoPtTT+EA1QAAgFsLQAAB12s2WgAAAABJRU5ErkJggg=="
|
||||
class="card-img-top"
|
||||
alt=""
|
||||
/>
|
||||
<div v-if="!isImage(part)" class="icon">
|
||||
<i class="bi" :class="attachmentIcon(part)"></i>
|
||||
<div class="row gx-1 mb-3">
|
||||
<div class="col-auto">
|
||||
<a
|
||||
:href="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID)"
|
||||
class="card attachment float-start me-3 mb-3"
|
||||
target="_blank"
|
||||
style="width: 180px"
|
||||
@click="openAttachment(part, $event)"
|
||||
>
|
||||
<img
|
||||
v-if="isImage(part)"
|
||||
:src="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID + '/thumb')"
|
||||
class="card-img-top"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAAB4AQMAAABhKUq+AAAAA1BMVEX///+nxBvIAAAAGUlEQVQYGe3BgQAAAADDoPtTT+EA1QAAgFsLQAAB12s2WgAAAABJRU5ErkJggg=="
|
||||
class="card-img-top"
|
||||
alt=""
|
||||
/>
|
||||
<div v-if="!isImage(part)" class="icon">
|
||||
<i class="bi" :class="attachmentIcon(part)"></i>
|
||||
</div>
|
||||
<div class="card-body border-0">
|
||||
<p class="mb-1">
|
||||
<i class="bi me-1" :class="attachmentIcon(part)"></i>
|
||||
<small>{{ getFileSize(part.Size) }}</small>
|
||||
</p>
|
||||
<p class="card-text mb-0 small">
|
||||
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer small border-0 text-center text-truncate">
|
||||
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="mailbox.showAttachmentDetails" class="col">
|
||||
<h5 class="mb-1">
|
||||
<a
|
||||
:href="resolve('/api/v1/message/' + message.ID + '/part/' + part.PartID)"
|
||||
class="me-2"
|
||||
@click="openAttachment(part, $event)"
|
||||
>
|
||||
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
|
||||
</a>
|
||||
<small class="text-muted fw-light">
|
||||
<small>({{ getFileSize(part.Size) }})</small>
|
||||
</small>
|
||||
</h5>
|
||||
<p class="mb-1 small"><strong>Disposition</strong>: {{ part.ContentDisposition }}</p>
|
||||
<p class="mb-2 small">
|
||||
<strong>Content type</strong>: <code>{{ part.ContentType }}</code>
|
||||
</p>
|
||||
<p class="m-0 small">
|
||||
<strong>MD5</strong>:
|
||||
<button
|
||||
class="btn btn-sm btn-link p-0"
|
||||
title="Click to copy to clipboard"
|
||||
@click="copyToClipboard(part.Checksums.MD5, $event)"
|
||||
>
|
||||
{{ part.Checksums.MD5 }}
|
||||
<i v-if="!copiedText[part.Checksums.MD5]" class="bi bi-clipboard ms-1"></i>
|
||||
<i v-else class="bi bi-check2-square ms-1 text-success"></i>
|
||||
</button>
|
||||
</p>
|
||||
<p class="m-0 small">
|
||||
<strong>SHA1</strong>:
|
||||
<button
|
||||
class="btn btn-link p-0"
|
||||
title="Click to copy to clipboard"
|
||||
@click="copyToClipboard(part.Checksums.SHA1, $event)"
|
||||
>
|
||||
{{ part.Checksums.SHA1 }}
|
||||
<i v-if="!copiedText[part.Checksums.SHA1]" class="bi bi-clipboard ms-1"></i>
|
||||
<i v-else class="bi bi-check2-square ms-1 text-success"></i>
|
||||
</button>
|
||||
</p>
|
||||
<p class="m-0 small">
|
||||
<strong>SHA256</strong>:
|
||||
<button
|
||||
class="btn btn-sm btn-link p-0"
|
||||
title="Click to copy to clipboard"
|
||||
@click="copyToClipboard(part.Checksums.SHA256, $event)"
|
||||
>
|
||||
{{ part.Checksums.SHA256 }}
|
||||
<i v-if="!copiedText[part.Checksums.SHA256]" class="bi bi-clipboard ms-1"></i>
|
||||
<i v-else class="bi bi-check2-square ms-1 text-success"></i>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body border-0">
|
||||
<p class="mb-1">
|
||||
<i class="bi me-1" :class="attachmentIcon(part)"></i>
|
||||
<small>{{ getFileSize(part.Size) }}</small>
|
||||
</p>
|
||||
<p class="card-text mb-0 small">
|
||||
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer small border-0 text-center text-truncate">
|
||||
{{ part.FileName != "" ? part.FileName : "[ unknown ]" + part.ContentType }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ICS Modal -->
|
||||
<div id="ICSView" class="modal fade" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
|
||||
<div class="modal-content">
|
||||
|
||||
@@ -20,6 +20,7 @@ export default {
|
||||
return {
|
||||
loading: 0,
|
||||
tagColorCache: {},
|
||||
copiedText: {}, // used for clipboard copy feedback
|
||||
};
|
||||
},
|
||||
|
||||
@@ -222,12 +223,15 @@ export default {
|
||||
allAttachments(message) {
|
||||
const a = [];
|
||||
for (const i in message.Attachments) {
|
||||
message.Attachments[i].ContentDisposition = "Attachment";
|
||||
a.push(message.Attachments[i]);
|
||||
}
|
||||
for (const i in message.OtherParts) {
|
||||
message.OtherParts[i].ContentDisposition = "Other";
|
||||
a.push(message.OtherParts[i]);
|
||||
}
|
||||
for (const i in message.Inline) {
|
||||
message.Inline[i].ContentDisposition = "Inline";
|
||||
a.push(message.Inline[i]);
|
||||
}
|
||||
|
||||
@@ -288,5 +292,21 @@ export default {
|
||||
|
||||
return this.tagColorCache[s];
|
||||
},
|
||||
|
||||
// Copy to clipboard functionality
|
||||
copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(
|
||||
() => {
|
||||
this.copiedText[text] = true;
|
||||
setTimeout(() => {
|
||||
delete this.copiedText[text];
|
||||
}, 2000);
|
||||
},
|
||||
() => {
|
||||
// failure
|
||||
alert("Failed to copy to clipboard");
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ export const mailbox = reactive({
|
||||
timeZone: localStorage.getItem("timeZone")
|
||||
? localStorage.getItem("timeZone")
|
||||
: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
showAttachmentDetails: localStorage.getItem("showAttachmentDetails"), // show attachment details
|
||||
});
|
||||
|
||||
watch(
|
||||
@@ -106,3 +107,14 @@ watch(
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => mailbox.showAttachmentDetails,
|
||||
(v) => {
|
||||
if (v) {
|
||||
localStorage.setItem("showAttachmentDetails", "1");
|
||||
} else {
|
||||
localStorage.removeItem("showAttachmentDetails");
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user