From a7b380cd7aaf5386d87097d3ddbe7e33f714dcad Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 26 Jul 2026 17:11:03 -0500 Subject: [PATCH] Add pagination to /me/sessions endpoint & sessions account page table --- client/pages/account.vue | 31 ++++++++++++++++++++++++++++-- server/controllers/MeController.js | 17 ++++++++++++---- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/client/pages/account.vue b/client/pages/account.vue index 8323772a5..398a21c88 100644 --- a/client/pages/account.vue +++ b/client/pages/account.vue @@ -98,6 +98,11 @@ +
+ +

{{ $getString('LabelPaginationPageXOfY', [authSessionsPage + 1, authSessionsNumPages]) }}

+ +
@@ -122,6 +127,10 @@ export default { changingPassword: false, loggingOut: false, authSessions: [], + authSessionsPage: 0, + authSessionsNumPages: 0, + authSessionsItemsPerPage: 10, + loadingAuthSessions: false, selectedLanguage: '', newEReaderDevice: { name: '', @@ -285,15 +294,33 @@ export default { ereaderDevicesUpdated(ereaderDevices) { this.ereaderDevices = ereaderDevices }, - loadAuthSessions() { + loadAuthSessions(page = 0) { + if (this.loadingAuthSessions) return + if (page < 0) return + if (this.authSessionsNumPages > 0 && page > this.authSessionsNumPages - 1) return + + this.loadingAuthSessions = true this.$axios - .$get('/api/me/sessions') + .$get(`/api/me/sessions?page=${page}&itemsPerPage=${this.authSessionsItemsPerPage}`) .then((data) => { this.authSessions = data.sessions || [] + this.authSessionsPage = data.page ?? page + this.authSessionsNumPages = data.numPages ?? 0 }) .catch((error) => { console.error('Failed to load sessions', error) }) + .finally(() => { + this.loadingAuthSessions = false + }) + }, + prevAuthSessionsPage() { + if (this.authSessionsPage <= 0) return + this.loadAuthSessions(this.authSessionsPage - 1) + }, + nextAuthSessionsPage() { + if (this.authSessionsPage >= this.authSessionsNumPages - 1) return + this.loadAuthSessions(this.authSessionsPage + 1) }, getSessionDeviceLabel(session) { const deviceInfo = session.deviceInfo diff --git a/server/controllers/MeController.js b/server/controllers/MeController.js index b8f378bfa..cdf3034a1 100644 --- a/server/controllers/MeController.js +++ b/server/controllers/MeController.js @@ -35,21 +35,30 @@ class MeController { * @param {Response} res */ async getSessions(req, res) { + const page = Math.max(0, toNumber(req.query.page, 0)) + const itemsPerPage = Math.max(1, toNumber(req.query.itemsPerPage, 10)) + if (req.user.isGuest) { - return res.json({ sessions: [] }) + return res.json({ sessions: [], total: 0, numPages: 0, page, itemsPerPage }) } const refreshToken = req.cookies.refresh_token || req.headers['x-refresh-token'] - const sessions = await Database.sessionModel.findAll({ + const { rows, count } = await Database.sessionModel.findAndCountAll({ where: { userId: req.user.id, expiresAt: { [Op.gt]: new Date() } }, - order: [['updatedAt', 'DESC']] + order: [['updatedAt', 'DESC']], + limit: itemsPerPage, + offset: itemsPerPage * page }) res.json({ - sessions: sessions.map((session) => ({ + total: count, + numPages: Math.ceil(count / itemsPerPage), + page, + itemsPerPage, + sessions: rows.map((session) => ({ id: session.id, ipAddress: session.ipAddress, userAgent: session.userAgent,