diff --git a/ui/src/components/monitoring/auth-monitor/components/expandable-account-list.tsx b/ui/src/components/monitoring/auth-monitor/components/expandable-account-list.tsx
new file mode 100644
index 00000000..8f8627bf
--- /dev/null
+++ b/ui/src/components/monitoring/auth-monitor/components/expandable-account-list.tsx
@@ -0,0 +1,83 @@
+/**
+ * Expandable Account List - Account rows with toggle and solo controls
+ * Used in ProviderCard when expanded to show individual account controls
+ */
+
+import { Radio } from 'lucide-react';
+import { Button } from '@/components/ui/button';
+import { Switch } from '@/components/ui/switch';
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
+import { cn } from '@/lib/utils';
+import { cleanEmail } from '../utils';
+import type { AccountRow } from '../types';
+
+interface ExpandableAccountListProps {
+ accounts: AccountRow[];
+ privacyMode: boolean;
+ onPauseToggle: (accountId: string, paused: boolean) => void;
+ onSoloMode: (accountId: string) => void;
+ isPausingAccount?: boolean;
+ isSoloingAccount?: boolean;
+}
+
+export function ExpandableAccountList({
+ accounts,
+ privacyMode,
+ onPauseToggle,
+ onSoloMode,
+ isPausingAccount,
+ isSoloingAccount,
+}: ExpandableAccountListProps) {
+ return (
+
+ {accounts.map((acc) => (
+
+
+
+
+ {privacyMode ? '••••••' : cleanEmail(acc.email)}
+
+
+
+
+
+
+
+
+
+ Solo mode - activate this, pause others
+
+
+
+ {
+ onPauseToggle(acc.id, !checked);
+ }}
+ disabled={isPausingAccount}
+ className="scale-75"
+ onClick={(e) => e.stopPropagation()}
+ />
+
+
+ ))}
+
+ );
+}
diff --git a/ui/src/components/monitoring/auth-monitor/components/provider-card.tsx b/ui/src/components/monitoring/auth-monitor/components/provider-card.tsx
index 56faedbc..56818c73 100644
--- a/ui/src/components/monitoring/auth-monitor/components/provider-card.tsx
+++ b/ui/src/components/monitoring/auth-monitor/components/provider-card.tsx
@@ -1,9 +1,11 @@
/**
- * ProviderCard - Provider status card with account color dots and stats
+ * ProviderCard - Provider status card with expandable account controls
+ * Click to expand and show individual account toggle/solo buttons
*/
import type React from 'react';
-import { ChevronRight, AlertTriangle } from 'lucide-react';
+import { useState } from 'react';
+import { ChevronRight, ChevronDown, AlertTriangle } from 'lucide-react';
import { cn, STATUS_COLORS } from '@/lib/utils';
import { PROVIDER_COLORS } from '@/lib/provider-config';
import { ProviderIcon } from '@/components/shared/provider-icon';
@@ -11,6 +13,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
import type { ProviderStats } from '../types';
import { getSuccessRate, cleanEmail } from '../utils';
import { InlineStatsBadge } from './inline-stats-badge';
+import { ExpandableAccountList } from './expandable-account-list';
interface ProviderCardProps {
stats: ProviderStats;
@@ -19,6 +22,10 @@ interface ProviderCardProps {
onSelect: () => void;
onMouseEnter: () => void;
onMouseLeave: () => void;
+ onPauseToggle?: (accountId: string, paused: boolean) => void;
+ onSoloMode?: (accountId: string) => void;
+ isPausingAccount?: boolean;
+ isSoloingAccount?: boolean;
}
export function ProviderCard({
@@ -28,15 +35,32 @@ export function ProviderCard({
onSelect,
onMouseEnter,
onMouseLeave,
+ onPauseToggle,
+ onSoloMode,
+ isPausingAccount,
+ isSoloingAccount,
}: ProviderCardProps) {
+ const [isExpanded, setIsExpanded] = useState(false);
const successRate = getSuccessRate(stats.successCount, stats.failureCount);
const providerColor = PROVIDER_COLORS[stats.provider.toLowerCase()] || '#6b7280';
+ // Only expandable if account control callbacks are provided
+ const isExpandable = !!(onPauseToggle && onSoloMode);
+
+ const handleClick = () => {
+ if (isExpandable) {
+ setIsExpanded(!isExpanded);
+ } else {
+ onSelect();
+ }
+ };
+
return (
);
}
diff --git a/ui/src/components/monitoring/auth-monitor/hooks.ts b/ui/src/components/monitoring/auth-monitor/hooks.ts
index dd19b8bc..4af76b84 100644
--- a/ui/src/components/monitoring/auth-monitor/hooks.ts
+++ b/ui/src/components/monitoring/auth-monitor/hooks.ts
@@ -100,6 +100,7 @@ export function useAuthMonitorData(): AuthMonitorData {
lastUsedAt: realStats?.lastUsedAt ?? account.lastUsedAt,
color: ACCOUNT_COLORS[colorIndex % ACCOUNT_COLORS.length],
projectId: account.projectId,
+ paused: account.paused,
};
accountsList.push(row);
providerData.accounts.push(row);
diff --git a/ui/src/components/monitoring/auth-monitor/index.tsx b/ui/src/components/monitoring/auth-monitor/index.tsx
index d43e1d48..6cd55d83 100644
--- a/ui/src/components/monitoring/auth-monitor/index.tsx
+++ b/ui/src/components/monitoring/auth-monitor/index.tsx
@@ -9,6 +9,7 @@ import { STATUS_COLORS } from '@/lib/utils';
import { Skeleton } from '@/components/ui/skeleton';
import { AccountFlowViz } from '@/components/account-flow-viz';
import { usePrivacy } from '@/contexts/privacy-context';
+import { usePauseAccount, useResumeAccount, useSoloAccount } from '@/hooks/use-cliproxy';
import { Activity, CheckCircle2, XCircle, Radio } from 'lucide-react';
import { useAuthMonitorData } from './hooks';
@@ -33,11 +34,30 @@ export function AuthMonitor() {
const [selectedProvider, setSelectedProvider] = useState(null);
const [hoveredProvider, setHoveredProvider] = useState(null);
+ // Account control mutations
+ const pauseMutation = usePauseAccount();
+ const resumeMutation = useResumeAccount();
+ const soloMutation = useSoloAccount();
+
// Get selected provider data for detail view
const selectedProviderData = selectedProvider
? providerStats.find((ps) => ps.provider === selectedProvider)
: null;
+ const handlePauseToggle = (provider: string, accountId: string, paused: boolean) => {
+ if (pauseMutation.isPending || resumeMutation.isPending) return;
+ if (paused) {
+ pauseMutation.mutate({ provider, accountId });
+ } else {
+ resumeMutation.mutate({ provider, accountId });
+ }
+ };
+
+ const handleSoloMode = (provider: string, accountId: string) => {
+ if (soloMutation.isPending) return;
+ soloMutation.mutate({ provider, accountId });
+ };
+
if (isLoading) {
return (
@@ -137,6 +157,12 @@ export function AuthMonitor() {
onSelect={() => setSelectedProvider(ps.provider)}
onMouseEnter={() => setHoveredProvider(ps.provider)}
onMouseLeave={() => setHoveredProvider(null)}
+ onPauseToggle={(accountId, paused) =>
+ handlePauseToggle(ps.provider, accountId, paused)
+ }
+ onSoloMode={(accountId) => handleSoloMode(ps.provider, accountId)}
+ isPausingAccount={pauseMutation.isPending || resumeMutation.isPending}
+ isSoloingAccount={soloMutation.isPending}
/>
))}
diff --git a/ui/src/components/monitoring/auth-monitor/types.ts b/ui/src/components/monitoring/auth-monitor/types.ts
index 408b1e71..1490c134 100644
--- a/ui/src/components/monitoring/auth-monitor/types.ts
+++ b/ui/src/components/monitoring/auth-monitor/types.ts
@@ -14,6 +14,8 @@ export interface AccountRow {
color: string;
/** GCP Project ID (Antigravity only) - read-only */
projectId?: string;
+ /** Whether account is paused (skipped in quota rotation) */
+ paused?: boolean;
}
export interface ProviderStats {