+ {/* Select All checkbox */}
+ {isSelectable && accounts.length > 0 && (
+
+ )}
Accounts
{accounts.length > 0 && (
@@ -73,10 +164,15 @@ export function AccountsSection({
onPauseToggle={
onPauseToggle ? (paused) => onPauseToggle(account.id, paused) : undefined
}
+ onSoloMode={onSoloMode ? () => onSoloMode(account.id) : undefined}
isRemoving={isRemovingAccount}
isPausingAccount={isPausingAccount}
+ isSoloingAccount={isSoloingAccount}
privacyMode={privacyMode}
showQuota={showQuota}
+ selectable={isSelectable}
+ selected={selectedIds.has(account.id)}
+ onSelectChange={() => toggleSelect(account.id)}
/>
))}
@@ -88,6 +184,18 @@ export function AccountsSection({
)}
+ {/* Bulk Action Bar - shows when accounts selected */}
+ {isSelectable && (
+
diff --git a/ui/src/components/cliproxy/provider-editor/bulk-action-bar.tsx b/ui/src/components/cliproxy/provider-editor/bulk-action-bar.tsx
new file mode 100644
index 00000000..426c8c8f
--- /dev/null
+++ b/ui/src/components/cliproxy/provider-editor/bulk-action-bar.tsx
@@ -0,0 +1,67 @@
+/**
+ * Bulk Action Bar Component
+ * Appears when accounts are selected for bulk pause/resume operations
+ */
+
+import { Button } from '@/components/ui/button';
+import { Pause, Play, Loader2 } from 'lucide-react';
+
+interface BulkActionBarProps {
+ selectedCount: number;
+ onPauseSelected: () => void;
+ onResumeSelected: () => void;
+ onClearSelection: () => void;
+ isPausing: boolean;
+ isResuming: boolean;
+}
+
+export function BulkActionBar({
+ selectedCount,
+ onPauseSelected,
+ onResumeSelected,
+ onClearSelection,
+ isPausing,
+ isResuming,
+}: BulkActionBarProps) {
+ // Show bar when at least 1 account is selected (per validation decision)
+ if (selectedCount < 1) return null;
+
+ const isLoading = isPausing || isResuming;
+
+ return (
+
+
{selectedCount} selected
+
+
+
+
+
+
+ );
+}
diff --git a/ui/src/components/cliproxy/provider-editor/index.tsx b/ui/src/components/cliproxy/provider-editor/index.tsx
index b2d5b089..77672594 100644
--- a/ui/src/components/cliproxy/provider-editor/index.tsx
+++ b/ui/src/components/cliproxy/provider-editor/index.tsx
@@ -39,8 +39,14 @@ export function ProviderEditor({
onSetDefault,
onRemoveAccount,
onPauseToggle,
+ onSoloMode,
+ onBulkPause,
+ onBulkResume,
isRemovingAccount,
isPausingAccount,
+ isSoloingAccount,
+ isBulkPausing,
+ isBulkResuming,
}: ProviderEditorProps) {
const [customPresetOpen, setCustomPresetOpen] = useState(false);
const { privacyMode } = usePrivacy();
@@ -203,8 +209,14 @@ export function ProviderEditor({
onSetDefault={onSetDefault}
onRemoveAccount={onRemoveAccount}
onPauseToggle={onPauseToggle}
+ onSoloMode={onSoloMode}
+ onBulkPause={onBulkPause}
+ onBulkResume={onBulkResume}
isRemovingAccount={isRemovingAccount}
isPausingAccount={isPausingAccount}
+ isSoloingAccount={isSoloingAccount}
+ isBulkPausing={isBulkPausing}
+ isBulkResuming={isBulkResuming}
privacyMode={privacyMode}
isRemoteMode={isRemoteMode}
/>
diff --git a/ui/src/components/cliproxy/provider-editor/model-config-tab.tsx b/ui/src/components/cliproxy/provider-editor/model-config-tab.tsx
index 51e46d55..62eeadd8 100644
--- a/ui/src/components/cliproxy/provider-editor/model-config-tab.tsx
+++ b/ui/src/components/cliproxy/provider-editor/model-config-tab.tsx
@@ -37,9 +37,21 @@ interface ModelConfigTabProps {
onSetDefault: (accountId: string) => void;
onRemoveAccount: (accountId: string) => void;
onPauseToggle?: (accountId: string, paused: boolean) => void;
+ /** Solo mode: activate one account, pause all others */
+ onSoloMode?: (accountId: string) => void;
isRemovingAccount?: boolean;
/** Pause/resume mutation in progress */
isPausingAccount?: boolean;
+ /** Solo mode mutation in progress */
+ isSoloingAccount?: boolean;
+ /** Bulk pause multiple accounts */
+ onBulkPause?: (accountIds: string[]) => void;
+ /** Bulk resume multiple accounts */
+ onBulkResume?: (accountIds: string[]) => void;
+ /** Bulk pause mutation in progress */
+ isBulkPausing?: boolean;
+ /** Bulk resume mutation in progress */
+ isBulkResuming?: boolean;
privacyMode?: boolean;
/** True if connected to remote CLIProxy (quota not available) */
isRemoteMode?: boolean;
@@ -64,8 +76,14 @@ export function ModelConfigTab({
onSetDefault,
onRemoveAccount,
onPauseToggle,
+ onSoloMode,
+ onBulkPause,
+ onBulkResume,
isRemovingAccount,
isPausingAccount,
+ isSoloingAccount,
+ isBulkPausing,
+ isBulkResuming,
privacyMode,
isRemoteMode,
}: ModelConfigTabProps) {
@@ -140,8 +158,14 @@ export function ModelConfigTab({
onSetDefault={onSetDefault}
onRemoveAccount={onRemoveAccount}
onPauseToggle={onPauseToggle}
+ onSoloMode={onSoloMode}
+ onBulkPause={onBulkPause}
+ onBulkResume={onBulkResume}
isRemovingAccount={isRemovingAccount}
isPausingAccount={isPausingAccount}
+ isSoloingAccount={isSoloingAccount}
+ isBulkPausing={isBulkPausing}
+ isBulkResuming={isBulkResuming}
privacyMode={privacyMode}
showQuota={provider === 'agy' && !isRemoteMode}
isKiro={isKiro}
diff --git a/ui/src/components/cliproxy/provider-editor/types.ts b/ui/src/components/cliproxy/provider-editor/types.ts
index 743a1bf3..a9023729 100644
--- a/ui/src/components/cliproxy/provider-editor/types.ts
+++ b/ui/src/components/cliproxy/provider-editor/types.ts
@@ -31,9 +31,21 @@ export interface ProviderEditorProps {
onSetDefault: (accountId: string) => void;
onRemoveAccount: (accountId: string) => void;
onPauseToggle?: (accountId: string, paused: boolean) => void;
+ /** Solo mode: activate one account, pause all others */
+ onSoloMode?: (accountId: string) => void;
+ /** Bulk pause multiple accounts */
+ onBulkPause?: (accountIds: string[]) => void;
+ /** Bulk resume multiple accounts */
+ onBulkResume?: (accountIds: string[]) => void;
isRemovingAccount?: boolean;
/** Pause/resume mutation in progress */
isPausingAccount?: boolean;
+ /** Solo mode mutation in progress */
+ isSoloingAccount?: boolean;
+ /** Bulk pause mutation in progress */
+ isBulkPausing?: boolean;
+ /** Bulk resume mutation in progress */
+ isBulkResuming?: boolean;
}
export interface AccountItemProps {
@@ -41,12 +53,22 @@ export interface AccountItemProps {
onSetDefault: () => void;
onRemove: () => void;
onPauseToggle?: (paused: boolean) => void;
+ /** Solo mode: activate this account, pause all others */
+ onSoloMode?: () => void;
isRemoving?: boolean;
/** Pause/resume mutation in progress */
isPausingAccount?: boolean;
+ /** Solo mode mutation in progress */
+ isSoloingAccount?: boolean;
privacyMode?: boolean;
/** Show quota bar (only for 'agy' provider) */
showQuota?: boolean;
+ /** Enable checkbox for multi-select */
+ selectable?: boolean;
+ /** Whether this account is currently selected */
+ selected?: boolean;
+ /** Called when checkbox is toggled */
+ onSelectChange?: (selected: boolean) => void;
}
export interface ModelMappingValues {