1
0
mirror of https://github.com/axllent/mailpit.git synced 2025-08-15 20:13:16 +02:00

Merge branch 'release/v1.20.1'

This commit is contained in:
Ralph Slooten
2024-08-10 12:07:13 +12:00
6 changed files with 92 additions and 58 deletions

View File

@@ -2,6 +2,17 @@
Notable changes to Mailpit will be documented in this file.
## [v1.20.1]
### Chore
- Shift inbox pagination to inbox component
- Live load up to 100 new messages in sidebar ([#336](https://github.com/axllent/mailpit/issues/336))
- Show icon attachment in new side navigation message listing ([#345](https://github.com/axllent/mailpit/issues/345))
### Fix
- Correctly decode X-Tags message headers (RFC 2047) ([#344](https://github.com/axllent/mailpit/issues/344))
## [v1.20.0]
### Feature

View File

@@ -50,7 +50,7 @@ func Store(body *[]byte) (string, error) {
ReplyTo: addressToSlice(env, "Reply-To"),
}
messageID := strings.Trim(env.Root.Header.Get("Message-ID"), "<>")
messageID := strings.Trim(env.GetHeader("Message-ID"), "<>")
created := time.Now()
// use message date instead of created date
@@ -116,7 +116,7 @@ func Store(body *[]byte) (string, error) {
tags := findTagsInRawMessage(body)
if !config.TagsDisableXTags {
xTagsHdr := env.Root.Header.Get("X-Tags")
xTagsHdr := env.GetHeader("X-Tags")
if xTagsHdr != "" {
// extract tags from X-Tags header
tags = append(tags, tools.SetTagCasing(strings.Split(strings.TrimSpace(xTagsHdr), ","))...)

View File

@@ -21,7 +21,6 @@ export default {
socketBreaks: 0, // to track sockets that continually connect & disconnect, reset every 15s
pauseNotifications: false, // prevent spamming
version: false,
paginationDelayed: false, // for delayed pagination URL changes
}
},
@@ -56,20 +55,7 @@ export default {
// new messages
if (response.Type == "new" && response.Data) {
if (!mailbox.searching) {
if (pagination.start < 1) {
// push results directly into first page
mailbox.messages.unshift(response.Data)
if (mailbox.messages.length > pagination.limit) {
mailbox.messages.pop()
}
} else {
// update pagination offset
pagination.start++
// prevent "Too many calls to Location or History APIs within a short time frame"
this.delayedPaginationUpdate()
}
}
this.eventBus.emit("new", response.Data)
for (let i in response.Data.Tags) {
if (mailbox.tags.findIndex(e => { return e.toLowerCase() === response.Data.Tags[i].toLowerCase() }) < 0) {
@@ -106,10 +92,10 @@ export default {
}
} else if (response.Type == "delete" && response.Data) {
// broadcast for components
this.eventBus.emit("delete", response.Data);
this.eventBus.emit("delete", response.Data)
} else if (response.Type == "update" && response.Data) {
// broadcast for components
this.eventBus.emit("update", response.Data);
this.eventBus.emit("update", response.Data)
} else if (response.Type == "truncate") {
// broadcast for components
this.eventBus.emit("truncate")
@@ -171,39 +157,6 @@ export default {
}, 15000)
},
// This will only update the pagination offset at a maximum of 2x per second
// when viewing the inbox on > page 1, while receiving an influx of new messages.
delayedPaginationUpdate() {
if (this.paginationDelayed) {
return
}
this.paginationDelayed = true
window.setTimeout(() => {
const path = this.$route.path
const p = {
...this.$route.query
}
if (pagination.start > 0) {
p.start = pagination.start.toString()
} else {
delete p.start
}
if (pagination.limit != pagination.defaultLimit) {
p.limit = pagination.limit.toString()
} else {
delete p.limit
}
mailbox.autoPaginating = false // prevent reload of messages when URL changes
const params = new URLSearchParams(p)
this.$router.replace(path + '?' + params.toString())
this.paginationDelayed = false
}, 500)
},
browserNotify(title, message) {
if (!("Notification" in window)) {
return

View File

@@ -275,11 +275,6 @@ export default {
return 'bi-file-arrow-down-fill'
},
// wrapper to update one or more messages with
updateMessages(messages, updates) {
},
// Returns a hex color based on a string.
// Values are stored in an array for faster lookup / processing.
colorHash(s) {

View File

@@ -31,6 +31,7 @@ export default {
return {
mailbox,
delayedRefresh: false,
paginationDelayed: false, // for delayed pagination URL changes
}
},
@@ -46,6 +47,7 @@ export default {
this.loadMailbox()
// subscribe to events
this.eventBus.on("new", this.handleWSNew)
this.eventBus.on("update", this.handleWSUpdate)
this.eventBus.on("delete", this.handleWSDelete)
this.eventBus.on("truncate", this.handleWSTruncate)
@@ -53,6 +55,7 @@ export default {
unmounted() {
// unsubscribe from events
this.eventBus.off("new", this.handleWSNew)
this.eventBus.off("update", this.handleWSUpdate)
this.eventBus.off("delete", this.handleWSDelete)
this.eventBus.off("truncate", this.handleWSTruncate)
@@ -73,6 +76,55 @@ export default {
this.loadMessages()
},
// This will only update the pagination offset at a maximum of 2x per second
// when viewing the inbox on > page 1, while receiving an influx of new messages.
delayedPaginationUpdate() {
if (this.paginationDelayed) {
return
}
this.paginationDelayed = true
window.setTimeout(() => {
const path = this.$route.path
const p = {
...this.$route.query
}
if (pagination.start > 0) {
p.start = pagination.start.toString()
} else {
delete p.start
}
if (pagination.limit != pagination.defaultLimit) {
p.limit = pagination.limit.toString()
} else {
delete p.limit
}
mailbox.autoPaginating = false // prevent reload of messages when URL changes
const params = new URLSearchParams(p)
this.$router.replace(path + '?' + params.toString())
this.paginationDelayed = false
}, 500)
},
// handler for websocket new messages
handleWSNew(data) {
if (pagination.start < 1) {
// push results directly into first page
mailbox.messages.unshift(data)
if (mailbox.messages.length > pagination.limit) {
mailbox.messages.pop()
}
} else {
// update pagination offset
pagination.start++
// prevent "Too many calls to Location or History APIs within a short time frame"
this.delayedPaginationUpdate()
}
},
// handler for websocket message updates
handleWSUpdate(data) {
for (let x = 0; x < this.mailbox.messages.length; x++) {

View File

@@ -33,6 +33,7 @@ export default {
apiSideNavParams: URLSearchParams,
apiIsMore: true,
messagesList: [],
liveLoaded: 0, // the number new messages prepended tp messageList
scrollLoading: false,
canLoadMore: true,
}
@@ -62,6 +63,7 @@ export default {
this.refreshUI()
// subscribe to events
this.eventBus.on("new", this.handleWSNew)
this.eventBus.on("update", this.handleWSUpdate)
this.eventBus.on("delete", this.handleWSDelete)
this.eventBus.on("truncate", this.handleWSTruncate)
@@ -69,6 +71,7 @@ export default {
unmounted() {
// unsubscribe from events
this.eventBus.off("new", this.handleWSNew)
this.eventBus.off("update", this.handleWSUpdate)
this.eventBus.off("delete", this.handleWSDelete)
this.eventBus.off("truncate", this.handleWSTruncate)
@@ -212,6 +215,18 @@ export default {
}, 30000)
},
// handler for websocket new messages
handleWSNew(data) {
// do not add when searching or >= 100 new messages have been received
if (this.mailbox.searching || this.liveLoaded >= 100) {
return
}
this.liveLoaded++
this.messagesList.unshift(data)
this.scrollSidebarToCurrent()
},
// handler for websocket message updates
handleWSUpdate(data) {
for (let x = 0; x < this.messagesList.length; x++) {
@@ -419,6 +434,10 @@ export default {
}
},
reloadWindow() {
location.reload()
},
initReleaseModal() {
this.modal('ReleaseModal').show()
window.setTimeout(() => {
@@ -537,7 +556,7 @@ export default {
<span class="ms-1">
Return to
<template v-if="mailbox.searching">search</template>
<template v-else>mailbox</template>
<template v-else>inbox</template>
</span>
<span class="badge rounded-pill ms-1 float-end text-bg-secondary" title="Unread messages"
v-if="mailbox.unread && !errorMessage">
@@ -548,6 +567,9 @@ export default {
<div class="flex-grow-1 overflow-y-auto px-1 me-n1" id="MessageList" ref="MessageList"
@scroll="scrollHandler">
<button v-if="liveLoaded >= 100" class="w-100 alert alert-warning small" @click="reloadWindow()">
Reload to see newer messages
</button>
<template v-if="messagesList && messagesList.length">
<div class="list-group">
<RouterLink v-for="message in messagesList" :to="'/view/' + message.ID" :key="message.ID"
@@ -566,6 +588,7 @@ export default {
</div>
</div>
<div class="col-auto small">
<i class="bi bi-paperclip h6" v-if="message.Attachments"></i>
{{ getRelativeCreated(message) }}
</div>
<div v-if="message.Tags.length" class="col-12">