()
| 59 | } |
| 60 | |
| 61 | export function SecuritySection() { |
| 62 | const { toast } = useToast() |
| 63 | const queryClient = useQueryClient() |
| 64 | |
| 65 | const { |
| 66 | data: sessionsData, |
| 67 | isLoading: loadingSessions, |
| 68 | error: sessionsError, |
| 69 | refetch: refetchSessions, |
| 70 | isFetching: fetchingSessions, |
| 71 | } = useQuery({ |
| 72 | queryKey: ['sessions'], |
| 73 | queryFn: fetchSessions, |
| 74 | }) |
| 75 | |
| 76 | const allSessions = sessionsData?.activeSessions ?? [] |
| 77 | |
| 78 | const webSessions = useMemo( |
| 79 | () => allSessions.filter((session) => session.sessionType === 'web'), |
| 80 | [allSessions], |
| 81 | ) |
| 82 | |
| 83 | const cliSessions = useMemo( |
| 84 | () => allSessions.filter((session) => session.sessionType === 'cli'), |
| 85 | [allSessions], |
| 86 | ) |
| 87 | |
| 88 | const [activeTab, setActiveTab] = useState<'web' | 'cli'>('web') |
| 89 | const [isLogoutConfirmOpen, setIsLogoutConfirmOpen] = useState(false) |
| 90 | const [isBulkLoggingOut, setIsBulkLoggingOut] = useState(false) |
| 91 | |
| 92 | const TAB_LABELS = { web: 'Web Sessions', cli: 'CLI Sessions' } as const |
| 93 | const PRIMARY_VERB = { web: 'Log out of other', cli: 'Revoke all' } as const |
| 94 | const CONFIRM_VERB = { web: 'Log Out', cli: 'Revoke' } as const |
| 95 | |
| 96 | const revokeSessionMutation = useMutation({ |
| 97 | mutationFn: async (id: string) => { |
| 98 | const res = await fetch('/api/sessions', { |
| 99 | method: 'DELETE', |
| 100 | headers: { 'Content-Type': 'application/json' }, |
| 101 | body: JSON.stringify({ sessionIds: [id] }), |
| 102 | }) |
| 103 | if (!res.ok) { |
| 104 | const errorText = await res.text() |
| 105 | throw new Error(errorText) |
| 106 | } |
| 107 | return res.json() |
| 108 | }, |
| 109 | onSuccess: async () => { |
| 110 | await queryClient.invalidateQueries({ queryKey: ['sessions'] }) |
| 111 | toast({ title: 'Session revoked' }) |
| 112 | }, |
| 113 | onError: (e: any) => { |
| 114 | toast({ |
| 115 | title: 'Revoke failed', |
| 116 | description: e.message ?? String(e), |
| 117 | variant: 'destructive', |
| 118 | }) |
nothing calls this directly
no test coverage detected