Add /me/sessions endpoint and show sessions table on account page

This commit is contained in:
advplyr 2026-07-25 17:18:38 -05:00
parent 4c71a076e7
commit 35a2c5e87c
5 changed files with 130 additions and 1 deletions

View file

@ -1,6 +1,6 @@
<template>
<div id="page-wrapper" class="page p-6 overflow-y-auto relative" :class="streamLibraryItem ? 'streaming' : ''">
<div class="w-full max-w-xl mx-auto">
<div class="w-full max-w-2xl mx-auto">
<h1 class="text-2xl">{{ $strings.HeaderAccount }}</h1>
<div class="my-4">
@ -69,6 +69,38 @@
</app-settings-content>
</div>
<div v-if="!isGuest">
<div class="w-full h-px bg-white/10 my-4" />
<app-settings-content :header-text="$strings.HeaderSessions">
<table v-if="authSessions.length" class="tracksTable mt-4 table-fixed w-full">
<tr>
<th class="text-left">{{ $strings.LabelDeviceInfo }}</th>
<th class="text-left hidden sm:table-cell w-36">{{ $strings.LabelIpAddress }}</th>
<th class="text-left w-32 sm:w-40">{{ $strings.LabelLastUpdate }}</th>
</tr>
<tr v-for="session in authSessions" :key="session.id">
<td class="max-w-0">
<div class="flex items-center gap-0.5 min-w-0">
<span class="text-sm text-gray-100 truncate min-w-0" :title="session.userAgent">{{ getSessionDeviceLabel(session) }}</span>
<ui-tooltip v-if="session.current" direction="top" :text="$strings.LabelCurrent" class="inline-flex shrink-0">
<span class="material-symbols text-success text-sm leading-none">check</span>
</ui-tooltip>
</div>
</td>
<td class="hidden sm:table-cell w-36">
<p class="text-sm text-gray-100 truncate" :title="session.ipAddress">{{ session.ipAddress || '-' }}</p>
</td>
<td class="w-32 sm:w-40">
<ui-tooltip v-if="session.updatedAt" direction="top" :text="$formatDatetime(session.updatedAt, dateFormat, timeFormat)">
<p class="text-xs sm:text-sm text-gray-100">{{ $dateDistanceFromNow(session.updatedAt) }}</p>
</ui-tooltip>
</td>
</tr>
</table>
</app-settings-content>
</div>
<div class="py-4 mt-8 flex flex-wrap gap-2">
<ui-btn v-if="!isGuest" color="bg-primary flex items-center text-lg" :disabled="loggingOut" @click="logout(true)"> <span class="material-symbols mr-4 icon-text">devices</span>{{ $strings.ButtonLogoutAllDevices }} </ui-btn>
<ui-btn color="bg-primary flex items-center text-lg" :disabled="loggingOut" @click="logout"><span class="material-symbols mr-4 icon-text">logout</span>{{ $strings.ButtonLogout }}</ui-btn>
@ -89,6 +121,7 @@ export default {
confirmPassword: null,
changingPassword: false,
loggingOut: false,
authSessions: [],
selectedLanguage: '',
newEReaderDevice: {
name: '',
@ -131,6 +164,12 @@ export default {
},
revisedEreaderDevices() {
return this.ereaderDevices.filter((device) => device.users?.length === 1)
},
dateFormat() {
return this.$store.getters['getServerSetting']('dateFormat')
},
timeFormat() {
return this.$store.getters['getServerSetting']('timeFormat')
}
},
methods: {
@ -245,11 +284,34 @@ export default {
},
ereaderDevicesUpdated(ereaderDevices) {
this.ereaderDevices = ereaderDevices
},
loadAuthSessions() {
this.$axios
.$get('/api/me/sessions')
.then((data) => {
this.authSessions = data.sessions || []
})
.catch((error) => {
console.error('Failed to load sessions', error)
})
},
getSessionDeviceLabel(session) {
const deviceInfo = session.deviceInfo
if (!deviceInfo) return session.userAgent || '-'
const parts = []
if (deviceInfo.model) parts.push(deviceInfo.model)
if (deviceInfo.osName) parts.push(`${deviceInfo.osName}${deviceInfo.osVersion ? ` ${deviceInfo.osVersion}` : ''}`)
if (deviceInfo.browserName) parts.push(deviceInfo.browserName)
return parts.join(' / ') || session.userAgent || '-'
}
},
mounted() {
this.selectedLanguage = this.$languageCodes.current
this.ereaderDevices = this.$store.state.libraries.ereaderDevices || []
if (!this.isGuest) {
this.loadAuthSessions()
}
}
}
</script>