diff --git a/ui/src/hooks/use-cliproxy.ts b/ui/src/hooks/use-cliproxy.ts index 493fe6ea..be6dc613 100644 --- a/ui/src/hooks/use-cliproxy.ts +++ b/ui/src/hooks/use-cliproxy.ts @@ -127,6 +127,7 @@ export function usePauseAccount() { onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['cliproxy-accounts'] }); queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-stats'] }); toast.success('Account paused'); }, onError: (error: Error) => { @@ -144,6 +145,7 @@ export function useResumeAccount() { onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['cliproxy-accounts'] }); queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-stats'] }); toast.success('Account resumed'); }, onError: (error: Error) => { @@ -152,6 +154,77 @@ export function useResumeAccount() { }); } +export function useSoloAccount() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ provider, accountId }: { provider: string; accountId: string }) => + api.cliproxy.accounts.solo(provider, accountId), + onSuccess: (data) => { + queryClient.invalidateQueries({ queryKey: ['cliproxy-accounts'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-stats'] }); + const pausedCount = data.paused.length; + toast.success( + `Solo mode: paused ${pausedCount} other account${pausedCount !== 1 ? 's' : ''}` + ); + }, + onError: (error: Error) => { + toast.error(error.message); + }, + }); +} + +export function useBulkPauseAccounts() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ provider, accountIds }: { provider: string; accountIds: string[] }) => + api.cliproxy.accounts.bulkPause(provider, accountIds), + onSuccess: (data) => { + queryClient.invalidateQueries({ queryKey: ['cliproxy-accounts'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-stats'] }); + toast.success( + `Paused ${data.succeeded.length} account${data.succeeded.length !== 1 ? 's' : ''}` + ); + if (data.failed.length > 0) { + toast.warning( + `${data.failed.length} account${data.failed.length !== 1 ? 's' : ''} failed to pause` + ); + } + }, + onError: (error: Error) => { + toast.error(error.message); + }, + }); +} + +export function useBulkResumeAccounts() { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ provider, accountIds }: { provider: string; accountIds: string[] }) => + api.cliproxy.accounts.bulkResume(provider, accountIds), + onSuccess: (data) => { + queryClient.invalidateQueries({ queryKey: ['cliproxy-accounts'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); + queryClient.invalidateQueries({ queryKey: ['cliproxy-stats'] }); + toast.success( + `Resumed ${data.succeeded.length} account${data.succeeded.length !== 1 ? 's' : ''}` + ); + if (data.failed.length > 0) { + toast.warning( + `${data.failed.length} account${data.failed.length !== 1 ? 's' : ''} failed to resume` + ); + } + }, + onError: (error: Error) => { + toast.error(error.message); + }, + }); +} + // OAuth flow hook export function useStartAuth() { const queryClient = useQueryClient(); diff --git a/ui/src/lib/api-client.ts b/ui/src/lib/api-client.ts index 445b9133..6f052997 100644 --- a/ui/src/lib/api-client.ts +++ b/ui/src/lib/api-client.ts @@ -415,6 +415,30 @@ export const api = { `/cliproxy/auth/accounts/${provider}/${accountId}/resume`, { method: 'POST' } ), + /** Solo mode: activate one account, pause all others */ + solo: (provider: string, accountId: string) => + request<{ activated: string; paused: string[] }>('/accounts/solo', { + method: 'POST', + body: JSON.stringify({ provider, accountId }), + }), + /** Bulk pause multiple accounts */ + bulkPause: (provider: string, accountIds: string[]) => + request<{ succeeded: string[]; failed: Array<{ id: string; reason: string }> }>( + '/accounts/bulk-pause', + { + method: 'POST', + body: JSON.stringify({ provider, accountIds }), + } + ), + /** Bulk resume multiple accounts */ + bulkResume: (provider: string, accountIds: string[]) => + request<{ succeeded: string[]; failed: Array<{ id: string; reason: string }> }>( + '/accounts/bulk-resume', + { + method: 'POST', + body: JSON.stringify({ provider, accountIds }), + } + ), }, // OAuth flow auth: {