Client half of #370. Lists every device signed in to your account, with a per-row sign-out and a "sign out all other devices" action. The card does one thing the API alone doesn't: it says "Address changed" when created_ip and last_ip differ, rather than printing two addresses and leaving you to compare them. That mismatch — same device string, different origin — is the shape of a stolen token, and it's the reason IP capture was worth a migration. Making the operator spot it by eye would have wasted the data. Placed with Password and API Token rather than at the bottom of the page: those three are the account-security group, and this is the one that tells you the other two need attention. Details worth naming: - The current session gets a "This device" badge and NO sign-out button — offering one would log you out of the page you're standing on. The server already excludes it from logout-others; this makes that visible. - Sign-out-all-others is a two-step confirm and states the count, so the button can't be a surprise. - A 404 on revoke reloads instead of erroring. It means the session is already gone — revoked elsewhere, or expired — so the list was simply stale and showing the truth is the right response. The code is `session_not_found`, not `not_found`: apierror.NotFound(what) prefixes it. - Empty and error states both handled (rule #24); the empty case is practically unreachable since listing requires an authenticated request, and is handled rather than assumed. - User-agent parsing is deliberately coarse. A real UA parser is a dependency and a maintenance burden for a string whose only job is "do you recognise this?" — the addresses carry the actual signal. Tests cover the parts that would be quiet if broken: the current-session badge suppressing its own sign-out button, the address-changed warning appearing and NOT appearing, the two-step confirm not firing on first click, and the load-failure retry. Android parity is a separate decision, not assumed.
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
import { pushToast } from '$lib/stores/toast.svelte';
|
||||
import MobileAppDownload from '$lib/components/MobileAppDownload.svelte';
|
||||
import ServerVersion from '$lib/components/ServerVersion.svelte';
|
||||
import ActiveSessions from '$lib/components/ActiveSessions.svelte';
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -526,6 +527,11 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Sits with Password and API Token rather than near the bottom: these
|
||||
three are the account-security group, and this is the one that tells
|
||||
you the other two need attention. -->
|
||||
<ActiveSessions />
|
||||
|
||||
<section class="space-y-3 rounded border border-border bg-surface p-4">
|
||||
<h2 class="text-lg font-semibold">Library</h2>
|
||||
<ul class="space-y-2 text-sm">
|
||||
|
||||
Reference in New Issue
Block a user