fix(ui): escaping theme dialog no longer resets theme to default (#11323)

Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
Pyush Sinha
2025-10-20 10:50:09 -07:00
committed by GitHub
parent d0ab6e9982
commit 397e52dac7
6 changed files with 51 additions and 14 deletions

View File

@@ -335,6 +335,7 @@ export const AppContainer = (props: AppContainerProps) => {
const {
isThemeDialogOpen,
openThemeDialog,
closeThemeDialog,
handleThemeSelect,
handleThemeHighlight,
} = useThemeCommand(
@@ -1266,6 +1267,7 @@ Logging in with Google... Please restart Gemini CLI to continue.
const uiActions: UIActions = useMemo(
() => ({
handleThemeSelect,
closeThemeDialog,
handleThemeHighlight,
handleAuthSelect,
setAuthState,
@@ -1291,6 +1293,7 @@ Logging in with Google... Please restart Gemini CLI to continue.
}),
[
handleThemeSelect,
closeThemeDialog,
handleThemeHighlight,
handleAuthSelect,
setAuthState,

View File

@@ -115,6 +115,7 @@ export const DialogManager = ({
)}
<ThemeDialog
onSelect={uiActions.handleThemeSelect}
onCancel={uiActions.closeThemeDialog}
onHighlight={uiActions.handleThemeHighlight}
settings={settings}
availableTerminalHeight={

View File

@@ -12,6 +12,7 @@ import { KeypressProvider } from '../contexts/KeypressContext.js';
import { SettingsContext } from '../contexts/SettingsContext.js';
import { DEFAULT_THEME, themeManager } from '../themes/theme-manager.js';
import { act } from 'react';
import { waitFor } from '@testing-library/react';
const createMockSettings = (
userSettings = {},
@@ -58,6 +59,7 @@ const createMockSettings = (
describe('ThemeDialog Snapshots', () => {
const baseProps = {
onSelect: vi.fn(),
onCancel: vi.fn(),
onHighlight: vi.fn(),
availableTerminalHeight: 40,
terminalWidth: 120,
@@ -105,4 +107,28 @@ describe('ThemeDialog Snapshots', () => {
expect(lastFrame()).toMatchSnapshot();
});
it('should call onCancel when ESC is pressed', async () => {
const mockOnCancel = vi.fn();
const settings = createMockSettings();
const { stdin } = render(
<SettingsContext.Provider value={settings}>
<KeypressProvider kittyProtocolEnabled={false}>
<ThemeDialog
{...baseProps}
onCancel={mockOnCancel}
settings={settings}
/>
</KeypressProvider>
</SettingsContext.Provider>,
);
act(() => {
stdin.write('\x1b');
});
await waitFor(() => {
expect(mockOnCancel).toHaveBeenCalled();
});
});
});

View File

@@ -20,7 +20,10 @@ import { ScopeSelector } from './shared/ScopeSelector.js';
interface ThemeDialogProps {
/** Callback function when a theme is selected */
onSelect: (themeName: string | undefined, scope: SettingScope) => void;
onSelect: (themeName: string, scope: SettingScope) => void;
/** Callback function when the dialog is cancelled */
onCancel: () => void;
/** Callback function when a theme is highlighted */
onHighlight: (themeName: string | undefined) => void;
@@ -32,6 +35,7 @@ interface ThemeDialogProps {
export function ThemeDialog({
onSelect,
onCancel,
onHighlight,
settings,
availableTerminalHeight,
@@ -42,9 +46,9 @@ export function ThemeDialog({
);
// Track the currently highlighted theme name
const [highlightedThemeName, setHighlightedThemeName] = useState<
string | undefined
>(settings.merged.ui?.theme || DEFAULT_THEME.name);
const [highlightedThemeName, setHighlightedThemeName] = useState<string>(
settings.merged.ui?.theme || DEFAULT_THEME.name,
);
// Generate theme items filtered by selected scope
const customThemes =
@@ -112,7 +116,7 @@ export function ThemeDialog({
setMode((prev) => (prev === 'theme' ? 'scope' : 'theme'));
}
if (key.name === 'escape') {
onSelect(undefined, selectedScope);
onCancel();
}
},
{ isActive: true },

View File

@@ -13,10 +13,8 @@ import { type SettingScope } from '../../config/settings.js';
import type { AuthState } from '../types.js';
export interface UIActions {
handleThemeSelect: (
themeName: string | undefined,
scope: SettingScope,
) => void;
handleThemeSelect: (themeName: string, scope: SettingScope) => void;
closeThemeDialog: () => void;
handleThemeHighlight: (themeName: string | undefined) => void;
handleAuthSelect: (
authType: AuthType | undefined,

View File

@@ -13,10 +13,8 @@ import process from 'node:process';
interface UseThemeCommandReturn {
isThemeDialogOpen: boolean;
openThemeDialog: () => void;
handleThemeSelect: (
themeName: string | undefined,
scope: SettingScope,
) => void; // Added scope
closeThemeDialog: () => void;
handleThemeSelect: (themeName: string, scope: SettingScope) => void;
handleThemeHighlight: (themeName: string | undefined) => void;
}
@@ -63,8 +61,14 @@ export const useThemeCommand = (
[applyTheme],
);
const closeThemeDialog = useCallback(() => {
// Re-apply the saved theme to revert any preview changes from highlighting
applyTheme(loadedSettings.merged.ui?.theme);
setIsThemeDialogOpen(false);
}, [applyTheme, loadedSettings]);
const handleThemeSelect = useCallback(
(themeName: string | undefined, scope: SettingScope) => {
(themeName: string, scope: SettingScope) => {
try {
// Merge user and workspace custom themes (workspace takes precedence)
const mergedCustomThemes = {
@@ -95,6 +99,7 @@ export const useThemeCommand = (
return {
isThemeDialogOpen,
openThemeDialog,
closeThemeDialog,
handleThemeSelect,
handleThemeHighlight,
};