feat(accounts): remove a specific account from the switcher

The switcher only offered 'sign out of active' and 'sign out of all' — no
way to drop a single non-active account (e.g. one stuck in an error state you
can't switch into to sign out). Add a hover × on non-active, non-default rows
and a removeAccount(id) auth action that tears down the client, drops it from
the registry, and clears its per-slot session/token cookies.

Stacks on the switcher redesign in #517.
This commit is contained in:
Shuki Vaknin
2026-07-21 20:59:52 +02:00
committed by Linus Rath
parent 0f3459c2e5
commit 6dfcb07b9a
22 changed files with 108 additions and 23 deletions
+26
View File
@@ -44,6 +44,7 @@ interface AuthState {
refreshAccessToken: () => Promise<string | null>;
logout: () => void;
logoutAll: () => void;
removeAccount: (accountId: string) => void;
switchAccount: (accountId: string) => Promise<void>;
checkAuth: () => Promise<void>;
clearError: () => void;
@@ -1243,6 +1244,31 @@ export const useAuthStore = create<AuthState>()(
redirectToLogin();
},
// Remove a specific (typically non-active) account: tear down its client,
// drop it from the registry, and clear its per-slot cookies. If asked to
// remove the active account, defer to logout() which handles switching
// away or redirecting.
removeAccount: (accountId: string) => {
if (accountId === get().activeAccountId) { get().logout(); return; }
const accountStore = useAccountStore.getState();
const account = accountStore.getAccountById(accountId);
if (!account) return;
const slot = account.cookieSlot ?? 0;
const wasOAuth = account.authMode === 'oauth';
clearRefreshTimer(accountId);
const client = clients.get(accountId);
if (client) { try { client.disconnect(); } catch { /* noop */ } }
clients.delete(accountId);
evictAccount(accountId);
accountStore.removeAccount(accountId);
apiFetch(`/api/auth/session?slot=${slot}`, { method: 'DELETE', keepalive: true }).catch(() => {});
if (wasOAuth) {
apiFetch(`/api/auth/token?slot=${slot}`, { method: 'DELETE', keepalive: true }).catch(() => {});
}
},
logoutAll: () => {
// Disconnect all clients
for (const c of clients.values()) {