Files
gemini-cli/packages/cli/src/ui/contexts/UIActionsContext.tsx
T
gemini-cli[bot] e99c836eb6 fix(cli): allow switching approval mode by clicking the indicator
This PR implements click-to-change-mode functionality for the `ApprovalModeIndicator` component, as requested in issue #27035.

Changes:
- Refactored `useApprovalModeIndicator` hook to return an object with `cycleApprovalMode` and `toggleYolo` functions.
- Added `cycleApprovalMode` to `UIActions` context to allow components to trigger mode changes.
- Updated `AppContainer.tsx` to expose `cycleApprovalMode` via `uiActions`.
- Updated `ApprovalModeIndicator.tsx` to use `useMouseClick` and call `cycleApprovalMode` on click.
- Added a "click or " hint to the indicator text when mouse mode is enabled.
- Updated unit tests for `useApprovalModeIndicator` and `ApprovalModeIndicator`.

CC: @google-gemini-maintainers
2026-05-15 04:11:28 +00:00

112 lines
4.3 KiB
TypeScript

/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { createContext, useContext } from 'react';
import { type Key } from '../hooks/useKeypress.js';
import { type IdeIntegrationNudgeResult } from '../IdeIntegrationNudge.js';
import { type FolderTrustChoice } from '../components/FolderTrustDialog.js';
import {
type AuthType,
type EditorType,
type AgentDefinition,
} from '@google/gemini-cli-core';
import { type LoadableSettingScope } from '../../config/settings.js';
import type { AuthState } from '../types.js';
import { type PermissionsDialogProps } from '../components/PermissionsModifyTrustDialog.js';
import type { SessionInfo } from '../../utils/sessionUtils.js';
import { type NewAgentsChoice } from '../components/NewAgentsNotification.js';
import type { OverageMenuIntent, EmptyWalletIntent } from './UIStateContext.js';
export interface UIActions {
handleThemeSelect: (
themeName: string,
scope: LoadableSettingScope,
) => Promise<void>;
closeThemeDialog: () => void;
handleThemeHighlight: (themeName: string | undefined) => void;
handleAuthSelect: (
authType: AuthType | undefined,
scope: LoadableSettingScope,
) => void;
setAuthState: (state: AuthState) => void;
onAuthError: (error: string | null) => void;
handleEditorSelect: (
editorType: EditorType | undefined,
scope: LoadableSettingScope,
) => void;
exitEditorDialog: () => void;
exitPrivacyNotice: () => void;
closeSettingsDialog: () => void;
closeModelDialog: () => void;
openVoiceModelDialog: () => void;
closeVoiceModelDialog: () => void;
openAgentConfigDialog: (
name: string,
displayName: string,
definition: AgentDefinition,
) => void;
closeAgentConfigDialog: () => void;
openPermissionsDialog: (props?: PermissionsDialogProps) => void;
closePermissionsDialog: () => void;
setShellModeActive: (value: boolean) => void;
vimHandleInput: (key: Key) => boolean;
handleIdePromptComplete: (result: IdeIntegrationNudgeResult) => void;
handleFolderTrustSelect: (choice: FolderTrustChoice) => void;
setIsPolicyUpdateDialogOpen: (value: boolean) => void;
setConstrainHeight: (value: boolean) => void;
onEscapePromptChange: (show: boolean) => void;
refreshStatic: () => void;
handleFinalSubmit: (value: string) => Promise<void>;
handleClearScreen: () => void;
handleProQuotaChoice: (
choice: 'retry_later' | 'retry_once' | 'retry_always' | 'upgrade',
) => void;
handleValidationChoice: (choice: 'verify' | 'change_auth' | 'cancel') => void;
handleOverageMenuChoice: (choice: OverageMenuIntent) => void;
handleEmptyWalletChoice: (choice: EmptyWalletIntent) => void;
openSessionBrowser: () => void;
closeSessionBrowser: () => void;
handleResumeSession: (session: SessionInfo) => Promise<void>;
handleDeleteSession: (session: SessionInfo) => Promise<void>;
setQueueErrorMessage: (message: string | null) => void;
addMessage: (message: string) => void;
popAllMessages: () => string | undefined;
handleApiKeySubmit: (apiKey: string) => Promise<void>;
handleApiKeyCancel: () => void;
setBannerVisible: (visible: boolean) => void;
setShortcutsHelpVisible: (visible: boolean) => void;
setCleanUiDetailsVisible: (visible: boolean) => void;
toggleCleanUiDetailsVisible: () => void;
revealCleanUiDetailsTemporarily: (durationMs?: number) => void;
handleWarning: (message: string) => void;
setEmbeddedShellFocused: (value: boolean) => void;
dismissBackgroundTask: (pid: number) => Promise<void>;
setActiveBackgroundTaskPid: (pid: number) => void;
setIsBackgroundTaskListOpen: (isOpen: boolean) => void;
setAuthContext: (context: { requiresRestart?: boolean }) => void;
dismissLoginRestart: () => void;
onHintInput: (char: string) => void;
onHintBackspace: () => void;
onHintClear: () => void;
onHintSubmit: (hint: string) => void;
handleRestart: () => void;
handleNewAgentsSelect: (choice: NewAgentsChoice) => Promise<void>;
getPreferredEditor: () => EditorType | undefined;
clearAccountSuspension: () => void;
setVoiceModeEnabled: (value: boolean) => void;
cycleApprovalMode: () => void;
}
export const UIActionsContext = createContext<UIActions | null>(null);
export const useUIActions = () => {
const context = useContext(UIActionsContext);
if (!context) {
throw new Error('useUIActions must be used within a UIActionsProvider');
}
return context;
};