1
0
mirror of https://github.com/axllent/mailpit.git synced 2025-11-29 22:57:41 +02:00

UI: Changes to use new data API

This commit is contained in:
Ralph Slooten
2022-10-07 19:47:41 +13:00
parent 34da0e5042
commit df758d063a
4 changed files with 84 additions and 63 deletions

View File

@@ -84,11 +84,11 @@ export default {
let params = {};
this.selected = [];
let uri = 'api/messages';
let uri = 'api/v1/messages';
if (self.search) {
self.searching = true;
self.items = [];
uri = 'api/search'
uri = 'api/v1/search'
self.start = 0; // search is displayed on one page
params['query'] = self.search;
} else {
@@ -104,7 +104,12 @@ export default {
self.unread = response.data.unread;
self.count = response.data.count;
self.start = response.data.start;
self.items = response.data.items;
self.items = response.data.messages;
if (self.items == 0 && self.start > 0) {
self.start = 0;
return self.loadMessages();
}
if (!self.scrollInPlace) {
let mp = document.getElementById('message-page');
@@ -153,7 +158,7 @@ export default {
let self = this;
self.selected = [];
let uri = 'api/' + self.currentPath
let uri = 'api/v1/message/' + self.currentPath
self.get(uri, false, function(response) {
for (let i in self.items) {
if (self.items[i].ID == self.currentPath) {
@@ -171,14 +176,14 @@ export default {
if (a.ContentID != '') {
d.HTML = d.HTML.replace(
new RegExp('cid:'+a.ContentID, 'g'),
window.location.origin+'/api/'+d.ID+'/part/'+a.PartID
window.location.origin+'/api/v1/message/'+d.ID+'/part/'+a.PartID
);
}
if (a.FileName.match(/^[a-zA-Z0-9\_\-\.]+$/)) {
// some old email clients use the filename
d.HTML = d.HTML.replace(
new RegExp('src=(\'|")'+a.FileName+'(\'|")', 'g'),
'src="'+window.location.origin+'/api/'+d.ID+'/part/'+a.PartID+'"'
'src="'+window.location.origin+'/api/v1/message/'+d.ID+'/part/'+a.PartID+'"'
);
}
}
@@ -190,14 +195,14 @@ export default {
if (a.ContentID != '') {
d.HTML = d.HTML.replace(
new RegExp('cid:'+a.ContentID, 'g'),
window.location.origin+'/api/'+d.ID+'/part/'+a.PartID
window.location.origin+'/api/v1/message/'+d.ID+'/part/'+a.PartID
);
}
if (a.FileName.match(/^[a-zA-Z0-9\_\-\.]+$/)) {
// some old email clients use the filename
d.HTML = d.HTML.replace(
new RegExp('src=(\'|")'+a.FileName+'(\'|")', 'g'),
'src="'+window.location.origin+'/api/'+d.ID+'/part/'+a.PartID+'"'
'src="'+window.location.origin+'/api/v1/message/'+d.ID+'/part/'+a.PartID+'"'
);
}
}
@@ -221,48 +226,42 @@ export default {
});
},
// universal handler to delete current or selected messages
deleteMessages: function() {
let ids = [];
let self = this;
if (self.message) {
ids.push(self.message.ID);
} else {
ids = JSON.parse(JSON.stringify(self.selected));
}
if (!ids.length) {
return false;
}
let uri = 'api/v1/messages';
self.delete(uri, {'ids': ids}, function(response) {
window.location.hash = "";
self.scrollInPlace = true;
self.loadMessages();
});
},
deleteAll: function() {
let self = this;
let uri = 'api/delete'
self.get(uri, false, function(response) {
let uri = 'api/v1/messages';
self.delete(uri, false, function(response) {
window.location.hash = "";
self.reloadMessages();
});
},
deleteOne: function() {
let self = this;
if (!self.message) {
return false;
}
let uri = 'api/' + self.message.ID + '/delete'
self.get(uri, false, function(response) {
window.location.hash = "";
self.scrollInPlace = true;
self.loadMessages();
});
},
deleteSelected: function() {
let self = this;
if (!self.selected.length) {
return false;
}
let uri = 'api/delete'
self.post(uri, {'ids': self.selected}, function(response) {
window.location.hash = "";
self.scrollInPlace = true;
self.loadMessages();
});
},
markUnread: function() {
let self = this;
if (!self.message) {
return false;
}
let uri = 'api/' + self.message.ID + '/unread'
self.get(uri, false, function(response) {
let uri = 'api/v1/messages';
self.put(uri, {'read': false, 'ids': [self.message.ID]}, function(response) {
window.location.hash = "";
self.scrollInPlace = true;
self.loadMessages();
@@ -271,8 +270,8 @@ export default {
markAllRead: function() {
let self = this;
let uri = 'api/read'
self.get(uri, false, function(response) {
let uri = 'api/v1/messages'
self.put(uri, {'read': true}, function(response) {
window.location.hash = "";
self.scrollInPlace = true;
self.loadMessages();
@@ -284,8 +283,8 @@ export default {
if (!self.selected.length) {
return false;
}
let uri = 'api/read'
self.post(uri, {'ids': self.selected}, function(response) {
let uri = 'api/v1/messages';
self.put(uri, {'read': true, 'ids': self.selected}, function(response) {
window.location.hash = "";
self.scrollInPlace = true;
self.loadMessages();
@@ -297,8 +296,8 @@ export default {
if (!self.selected.length) {
return false;
}
let uri = 'api/unread'
self.post(uri, {'ids': self.selected}, function(response) {
let uri = 'api/v1/messages';
self.put(uri, {'read': false, 'ids': self.selected}, function(response) {
window.location.hash = "";
self.scrollInPlace = true;
self.loadMessages();
@@ -357,7 +356,8 @@ export default {
}
self.total++;
self.unread++;
self.browserNotify("New mail from: " + response.Data.From.Address, response.Data.Subject);
let from = response.Data.From != null ? response.Data.From.Address : '[unknown]';
self.browserNotify("New mail from: " + from, response.Data.Subject);
} else if (response.Type == "prune") {
// messages have been deleted, reload messages to adjust
self.scrollInPlace = true;
@@ -497,19 +497,19 @@ export default {
<a class="btn btn-outline-secondary me-4 px-3" href="#" v-on:click="message=false" title="Return to messages">
<i class="bi bi-arrow-return-left"></i>
</a>
<button class="btn btn-outline-secondary me-2" title="Delete message" v-on:click="deleteOne">
<i class="bi bi-trash-fill"></i> <span class="d-none d-md-inline">Delete</span>
</button>
<button class="btn btn-outline-secondary me-2" title="Mark unread" v-on:click="markUnread">
<i class="bi bi-eye-slash"></i> <span class="d-none d-md-inline">Mark unread</span>
</button>
<button class="btn btn-outline-secondary me-2" title="Delete message" v-on:click="deleteMessages">
<i class="bi bi-trash-fill"></i> <span class="d-none d-md-inline">Delete</span>
</button>
<a class="btn btn-outline-secondary float-end" :class="messageNext ? '':'disabled'" :href="'#'+messageNext" title="View next message">
<i class="bi bi-caret-right-fill"></i>
</a>
<a class="btn btn-outline-secondary ms-2 me-1 float-end" :class="messagePrev ? '': 'disabled'" :href="'#'+messagePrev" title="View previous message">
<i class="bi bi-caret-left-fill"></i>
</a>
<a :href="'api/' + message.ID + '/raw?dl=1'" class="btn btn-outline-secondary me-2 float-end" title="Download message">
<a :href="'api/v1/' + message.ID + '/raw?dl=1'" class="btn btn-outline-secondary me-2 float-end" title="Download message">
<i class="bi bi-file-arrow-down-fill"></i> <span class="d-none d-md-inline">Download</span>
</a>
</div>

View File

@@ -88,16 +88,16 @@ const commonMixins = {
},
/**
* Axios Post request
* Axios POST request
*
* @params string url
* @params array array parameters Object/array
* @params array object/array values
* @params function callback function
*/
post: function (url, values, callback) {
post: function (url, data, callback) {
let self = this;
self.loading++;
axios.post(url, values)
axios.post(url, data)
.then(callback)
.catch(self.handleError)
.then(function () {
@@ -112,13 +112,34 @@ const commonMixins = {
* Axios DELETE request (REST only)
*
* @params string url
* @params array array parameters Object/array
* @params array object/array values
* @params function callback function
*/
delete: function (url, values, callback) {
delete: function (url, data, callback) {
let self = this;
self.loading++;
axios.delete(url, { data: values })
axios.delete(url, { data: data })
.then(callback)
.catch(self.handleError)
.then(function () {
// always executed
if (self.loading > 0) {
self.loading--;
}
});
},
/**
* Axios PUT request (REST only)
*
* @params string url
* @params array object/array values
* @params function callback function
*/
put: function (url, data, callback) {
let self = this;
self.loading++;
axios.put(url, data)
.then(callback)
.catch(self.handleError)
.then(function () {

View File

@@ -14,8 +14,8 @@ export default {
<template>
<div class="mt-4 border-top pt-4">
<a v-for="part in attachments" :href="'api/'+message.ID+'/part/'+part.PartID" class="card attachment float-start me-3 mb-3" target="_blank" style="width: 180px">
<img v-if="isImage(part)" :src="'api/'+message.ID+'/part/'+part.PartID+'/thumb'" class="card-img-top" alt="">
<a v-for="part in attachments" :href="'api/v1/message/'+message.ID+'/part/'+part.PartID" class="card attachment float-start me-3 mb-3" target="_blank" style="width: 180px">
<img v-if="isImage(part)" :src="'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 class="icon" v-if="!isImage(part)">
<i class="bi" :class="attachmentIcon(part)"></i>

View File

@@ -44,7 +44,7 @@ export default {
self.renderUI();
var tabEl = document.getElementById('nav-raw-tab');
tabEl.addEventListener('shown.bs.tab', function (event) {
self.srcURI = 'api/' + self.message.ID + '/raw';
self.srcURI = 'api/v1/message/' + self.message.ID + '/raw';
});
},
@@ -174,7 +174,7 @@ export default {
</button>
<ul class="dropdown-menu">
<li v-for="part in allAttachments(message)">
<a :href="'api/'+message.ID+'/part/'+part.PartID" type="button"
<a :href="'api/v1/message/'+message.ID+'/part/'+part.PartID" type="button"
class="dropdown-item" target="_blank">
<i class="bi" :class="attachmentIcon(part)"></i>
{{ part.FileName != '' ? part.FileName : '[ unknown ]' }}
@@ -193,7 +193,7 @@ export default {
aria-selected="true" v-if="message.HTML">HTML</button>
<button class="nav-link" id="nav-html-source-tab" data-bs-toggle="tab"
data-bs-target="#nav-html-source" type="button" role="tab" aria-controls="nav-html-source"
aria-selected="false" v-if="message.HTMLSource">HTML Source</button>
aria-selected="false" v-if="message.HTML">HTML Source</button>
<button class="nav-link" id="nav-plain-text-tab" data-bs-toggle="tab"
data-bs-target="#nav-plain-text" type="button" role="tab" aria-controls="nav-plain-text"
aria-selected="false" :class="message.HTML == '' ? 'show':''">Text</button>
@@ -211,8 +211,8 @@ export default {
<Attachments v-if="allAttachments(message).length" :message="message" :attachments="allAttachments(message)"></Attachments>
</div>
<div class="tab-pane fade" id="nav-html-source" role="tabpanel"
aria-labelledby="nav-html-source-tab" tabindex="0" v-if="message.HTMLSource">
<pre><code class="language-html">{{ message.HTMLSource }}</code></pre>
aria-labelledby="nav-html-source-tab" tabindex="0" v-if="message.HTML">
<pre><code class="language-html">{{ message.HTML }}</code></pre>
</div>
<div class="tab-pane fade" id="nav-plain-text" role="tabpanel"
aria-labelledby="nav-plain-text-tab" tabindex="0" :class="message.HTML == '' ? 'show':''">