mirror of
https://github.com/axllent/mailpit.git
synced 2025-06-17 00:07:54 +02:00
Improve pagination & limit URL parameter handling
This commit is contained in:
@ -16,6 +16,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
mailbox,
|
mailbox,
|
||||||
|
pagination,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -102,11 +103,17 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
toTagUrl: function (t) {
|
toTagUrl: function (t) {
|
||||||
const params = new URLSearchParams({
|
if (t.match(/ /)) {
|
||||||
start: String(0),
|
t = `"${t}"`
|
||||||
limit: pagination.limit.toString(),
|
}
|
||||||
})
|
const p = {
|
||||||
return '/search?q=' + this.tagEncodeURI(t) + '&' + params.toString()
|
q: 'tag:' + t
|
||||||
|
}
|
||||||
|
if (pagination.limit != pagination.defaultLimit) {
|
||||||
|
p.limit = pagination.limit.toString()
|
||||||
|
}
|
||||||
|
const params = new URLSearchParams(p)
|
||||||
|
return '/search?' + params.toString()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,6 +160,7 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="message.Tags.length">
|
<div v-if="message.Tags.length">
|
||||||
<RouterLink class="badge me-1" v-for="t in message.Tags" :to="toTagUrl(t)"
|
<RouterLink class="badge me-1" v-for="t in message.Tags" :to="toTagUrl(t)"
|
||||||
|
v-on:click="pagination.start = 0"
|
||||||
:style="mailbox.showTagColors ? { backgroundColor: colorHash(t) } : { backgroundColor: '#6c757d' }"
|
:style="mailbox.showTagColors ? { backgroundColor: colorHash(t) } : { backgroundColor: '#6c757d' }"
|
||||||
:title="'Filter messages tagged with ' + t">
|
:title="'Filter messages tagged with ' + t">
|
||||||
{{ t }}
|
{{ t }}
|
||||||
|
@ -11,25 +11,11 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
mailbox,
|
mailbox,
|
||||||
|
pagination,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// if the current filter is active then reload view
|
|
||||||
reloadFilter: function (tag) {
|
|
||||||
const urlParams = new URLSearchParams(window.location.search)
|
|
||||||
const query = urlParams.get('q')
|
|
||||||
if (!query) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let re = new RegExp(`^tag:"?${tag}"?$`, 'i')
|
|
||||||
if (query.match(re)) {
|
|
||||||
pagination.start = 0
|
|
||||||
this.$emit('loadMessages')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// test whether a tag is currently being searched for (in the URL)
|
// test whether a tag is currently being searched for (in the URL)
|
||||||
inSearch: function (tag) {
|
inSearch: function (tag) {
|
||||||
const urlParams = new URLSearchParams(window.location.search)
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
@ -76,12 +62,18 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
toTagUrl(tag) {
|
toTagUrl(t) {
|
||||||
const params = new URLSearchParams({
|
if (t.match(/ /)) {
|
||||||
start: String(0),
|
t = `"${t}"`
|
||||||
limit: pagination.limit.toString(),
|
}
|
||||||
})
|
const p = {
|
||||||
return '/search?q=' + this.tagEncodeURI(tag) + '&' + params.toString()
|
q: 'tag:' + t
|
||||||
|
}
|
||||||
|
if (pagination.limit != pagination.defaultLimit) {
|
||||||
|
p.limit = pagination.limit.toString()
|
||||||
|
}
|
||||||
|
const params = new URLSearchParams(p)
|
||||||
|
return '/search?' + params.toString()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +97,7 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div class="list-group mt-1 mb-5 pb-3">
|
<div class="list-group mt-1 mb-5 pb-3">
|
||||||
<RouterLink v-for="tag in mailbox.tags" :to="toTagUrl(tag)" @click="hideNav"
|
<RouterLink v-for="tag in mailbox.tags" :to="toTagUrl(tag)" @click="hideNav"
|
||||||
v-on:click="reloadFilter(tag)" v-on:click.ctrl="toggleTag($event, tag)"
|
v-on:click="pagination.start = 0" v-on:click.ctrl="toggleTag($event, tag)"
|
||||||
:style="mailbox.showTagColors ? { borderLeftColor: colorHash(tag), borderLeftWidth: '4px' } : ''"
|
:style="mailbox.showTagColors ? { borderLeftColor: colorHash(tag), borderLeftWidth: '4px' } : ''"
|
||||||
class="list-group-item list-group-item-action small px-2" :class="inSearch(tag) ? 'active' : ''">
|
class="list-group-item list-group-item-action small px-2" :class="inSearch(tag) ? 'active' : ''">
|
||||||
<i class="bi bi-tag-fill" v-if="inSearch(tag)"></i>
|
<i class="bi bi-tag-fill" v-if="inSearch(tag)"></i>
|
||||||
|
@ -15,7 +15,8 @@ export default {
|
|||||||
reconnectRefresh: false,
|
reconnectRefresh: false,
|
||||||
socketURI: false,
|
socketURI: false,
|
||||||
pauseNotifications: false, // prevent spamming
|
pauseNotifications: false, // prevent spamming
|
||||||
version: false
|
version: false,
|
||||||
|
paginationDelayed: false, // for delayed pagination URL changes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -60,13 +61,8 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
// update pagination offset
|
// update pagination offset
|
||||||
pagination.start++
|
pagination.start++
|
||||||
const path = self.$route.path
|
// prevent "Too many calls to Location or History APIs within a short timeframe"
|
||||||
const params = new URLSearchParams({
|
self.delayedPaginationUpdate()
|
||||||
...self.$route.query,
|
|
||||||
start: pagination.start.toString(),
|
|
||||||
limit: pagination.limit.toString(),
|
|
||||||
})
|
|
||||||
self.$router.push(path + '?' + params.toString())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,6 +124,38 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 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: function () {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams(p)
|
||||||
|
this.$router.push(path + '?' + params.toString())
|
||||||
|
|
||||||
|
this.paginationDelayed = false
|
||||||
|
}, 500)
|
||||||
|
},
|
||||||
|
|
||||||
browserNotify: function (title, message) {
|
browserNotify: function (title, message) {
|
||||||
if (!("Notification" in window)) {
|
if (!("Notification" in window)) {
|
||||||
return
|
return
|
||||||
|
@ -66,11 +66,20 @@ export default {
|
|||||||
|
|
||||||
updateQueryParams: function () {
|
updateQueryParams: function () {
|
||||||
const path = this.$route.path
|
const path = this.$route.path
|
||||||
const params = new URLSearchParams({
|
const p = {
|
||||||
...this.$route.query,
|
...this.$route.query
|
||||||
start: pagination.start.toString(),
|
}
|
||||||
limit: pagination.limit.toString(),
|
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
|
||||||
|
}
|
||||||
|
const params = new URLSearchParams(p)
|
||||||
this.$router.push(path + '?' + params.toString())
|
this.$router.push(path + '?' + params.toString())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,17 @@ export default {
|
|||||||
pagination.start = 0
|
pagination.start = 0
|
||||||
this.$emit('loadMessages')
|
this.$emit('loadMessages')
|
||||||
}
|
}
|
||||||
const params = new URLSearchParams({
|
const p = {
|
||||||
q: this.search,
|
q: this.search
|
||||||
start: pagination.start.toString(),
|
}
|
||||||
limit: pagination.limit.toString(),
|
if (pagination.start > 0) {
|
||||||
})
|
p.start = pagination.start.toString()
|
||||||
|
}
|
||||||
|
if (pagination.limit != pagination.defaultLimit) {
|
||||||
|
p.limit = pagination.limit.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams(p)
|
||||||
this.$router.push('/search?' + params.toString())
|
this.$router.push('/search?' + params.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { reactive } from 'vue'
|
|||||||
export const pagination = reactive({
|
export const pagination = reactive({
|
||||||
start: 0, // pagination offset
|
start: 0, // pagination offset
|
||||||
limit: 50, // per page
|
limit: 50, // per page
|
||||||
|
defaultLimit: 50, // used to shorten URL's if current limit == defaultLimit
|
||||||
total: 0, // total results of current view / filter
|
total: 0, // total results of current view / filter
|
||||||
count: 0, // number of messages currently displayed
|
count: 0, // number of messages currently displayed
|
||||||
})
|
})
|
||||||
|
@ -184,17 +184,26 @@ export default {
|
|||||||
mailbox.lastMessage = this.$route.params.id
|
mailbox.lastMessage = this.$route.params.id
|
||||||
|
|
||||||
if (mailbox.searching) {
|
if (mailbox.searching) {
|
||||||
const params = new URLSearchParams({
|
const p = {
|
||||||
q: mailbox.searching,
|
q: mailbox.searching
|
||||||
start: pagination.start.toString(),
|
}
|
||||||
limit: pagination.limit.toString(),
|
if (pagination.start > 0) {
|
||||||
})
|
p.start = pagination.start.toString()
|
||||||
|
}
|
||||||
|
if (pagination.limit != pagination.defaultLimit) {
|
||||||
|
p.limit = pagination.limit.toString()
|
||||||
|
}
|
||||||
|
const params = new URLSearchParams(p)
|
||||||
this.$router.push('/search?' + params.toString())
|
this.$router.push('/search?' + params.toString())
|
||||||
} else {
|
} else {
|
||||||
const params = new URLSearchParams({
|
const p = {}
|
||||||
start: pagination.start.toString(),
|
if (pagination.start > 0) {
|
||||||
limit: pagination.limit.toString(),
|
p.start = pagination.start.toString()
|
||||||
})
|
}
|
||||||
|
if (pagination.limit != pagination.defaultLimit) {
|
||||||
|
p.limit = pagination.limit.toString()
|
||||||
|
}
|
||||||
|
const params = new URLSearchParams(p)
|
||||||
this.$router.push('/?' + params.toString())
|
this.$router.push('/?' + params.toString())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -230,7 +239,8 @@ export default {
|
|||||||
<i class="bi bi-eye-slash"></i> <span class="d-none d-md-inline">Mark unread</span>
|
<i class="bi bi-eye-slash"></i> <span class="d-none d-md-inline">Mark unread</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-light me-1 me-sm-2" title="Release message"
|
<button class="btn btn-outline-light me-1 me-sm-2" title="Release message"
|
||||||
v-if="mailbox.uiConfig.MessageRelay && mailbox.uiConfig.MessageRelay.Enabled" v-on:click="initReleaseModal">
|
v-if="mailbox.uiConfig.MessageRelay && mailbox.uiConfig.MessageRelay.Enabled"
|
||||||
|
v-on:click="initReleaseModal">
|
||||||
<i class="bi bi-send"></i> <span class="d-none d-md-inline">Release</span>
|
<i class="bi bi-send"></i> <span class="d-none d-md-inline">Release</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-light me-1 me-sm-2" title="Delete message" v-on:click="deleteMessage">
|
<button class="btn btn-outline-light me-1 me-sm-2" title="Delete message" v-on:click="deleteMessage">
|
||||||
@ -350,6 +360,7 @@ export default {
|
|||||||
|
|
||||||
<AboutMailpit modals />
|
<AboutMailpit modals />
|
||||||
<AjaxLoader :loading="loading" />
|
<AjaxLoader :loading="loading" />
|
||||||
<Release v-if="mailbox.uiConfig.MessageRelay && message" ref="ReleaseRef" :message="message" @delete="deleteMessage" />
|
<Release v-if="mailbox.uiConfig.MessageRelay && message" ref="ReleaseRef" :message="message"
|
||||||
|
@delete="deleteMessage" />
|
||||||
<Screenshot v-if="message" ref="ScreenshotRef" :message="message" />
|
<Screenshot v-if="message" ref="ScreenshotRef" :message="message" />
|
||||||
</template>
|
</template>
|
||||||
|
Reference in New Issue
Block a user