import { Dialog as BaseDialog } from '@base-ui/react/dialog'; import { useQuery } from '@tanstack/react-query'; import { MonitorIcon } from 'lucide-react'; import { useState } from 'react'; import { Badge } from '#/components/atoms/badge.jsx'; import { Button } from '#/components/atoms/button.jsx'; import { Panel } from '#/components/atoms/panel.jsx'; import { RowIcon } from '#/components/atoms/row-icon.jsx'; import { Dialog } from '#/components/molecules/dialog.jsx'; import { ErrorNotice } from '#/components/molecules/error-notice.jsx'; import { ListRow } from '#/components/molecules/list-row.jsx'; import { Section } from '#/components/molecules/section.jsx'; import { ShowMore } from '#/components/molecules/show-more.jsx'; import { TextLink } from '#/components/molecules/text-link.jsx'; import { get, post } from '#/lib/api.js'; import { timeAgo } from '#/lib/format.js'; import { queryKeys, useApiMutation } from '#/lib/query.js'; import { formatUserAgent } from '#/lib/userAgent.js'; const SESSIONS_SHOWN = 5; export function SessionsCard() { const { data, error } = useQuery({ queryKey: queryKeys.sessions, queryFn: () => get('/sessions'), }); const [showAll, setShowAll] = useState(false); const action = useApiMutation([ queryKeys.sessions, queryKeys.apps, queryKeys.overview, ]); const revoke = (jti) => action.run(async () => { await post('/sessions/revoke', { jti }); }); const revokeAll = () => action.run(async () => { await post('/sessions/revoke-all'); }); if (data && !data.supported) return null; const sessions = data?.sessions ?? []; const shown = showAll ? sessions : sessions.slice(0, SESSIONS_SHOWN); return (
1 && ( Sign out all} >

This ends all {sessions.length} current logins. You'll stay signed in on this page.

It won't fully lock an app out on its own: one that still has your account password can just sign in again, and access it already holds can linger up to about two hours until its token can no longer refresh.

To remove an app's access for good, change your account password first, then sign out.

Cancel } /> Sign out all } />
) } >
{shown.map((session) => { const device = formatUserAgent(session.userAgent); return ( } title={ <> {session.label} {session.appPassword && limited} } description={ <> {device && {device}} Signed in {timeAgo(session.createdAt)} {session.refreshedAt ? ` ยท renewed ${timeAgo(session.refreshedAt)}` : ''} } actions={ } /> ); })} {sessions.length === 0 && (

No password logins are open.

)}
setShowAll((v) => !v)} noun="logins" />
); }