diff --git a/packages/cli/src/ui/AppContainer.tsx b/packages/cli/src/ui/AppContainer.tsx
index c4b39696c..3c6f829c9 100644
--- a/packages/cli/src/ui/AppContainer.tsx
+++ b/packages/cli/src/ui/AppContainer.tsx
@@ -1208,8 +1208,7 @@ export const AppContainer = (props: AppContainerProps) => {
isSubagentCreateDialogOpen ||
isAgentsManagerDialogOpen ||
isApprovalModeDialogOpen ||
- isResumeDialogOpen ||
- isFeedbackDialogOpen;
+ isResumeDialogOpen;
const pendingHistoryItems = useMemo(
() => [...pendingSlashCommandHistoryItems, ...pendingGeminiHistoryItems],
diff --git a/packages/cli/src/ui/FeedbackDialog.tsx b/packages/cli/src/ui/FeedbackDialog.tsx
index 187cde7d6..3984664d6 100644
--- a/packages/cli/src/ui/FeedbackDialog.tsx
+++ b/packages/cli/src/ui/FeedbackDialog.tsx
@@ -5,31 +5,39 @@ import { useUIActions } from './contexts/UIActionsContext.js';
import { useUIState } from './contexts/UIStateContext.js';
import { useKeypress } from './hooks/useKeypress.js';
+const FEEDBACK_OPTIONS = {
+ GOOD: 1,
+ BAD: 2,
+ NOT_SURE: 3,
+} as const;
+
+const FEEDBACK_OPTION_KEYS = {
+ [FEEDBACK_OPTIONS.GOOD]: '1',
+ [FEEDBACK_OPTIONS.BAD]: '2',
+ [FEEDBACK_OPTIONS.NOT_SURE]: '3',
+} as const;
+
+export const FEEDBACK_DIALOG_KEYS = ['1', '2', '3'] as const;
+
export const FeedbackDialog: React.FC = () => {
const uiState = useUIState();
const uiActions = useUIActions();
useKeypress(
(key) => {
- if (key.name === 'escape') {
- uiActions.closeFeedbackDialog();
- } else if (key.name === '1') {
- uiActions.submitFeedback(1);
- } else if (key.name === '2') {
- uiActions.submitFeedback(2);
- } else if (key.name === '3') {
- uiActions.submitFeedback(3);
- } else if (key.name === '0') {
- uiActions.closeFeedbackDialog();
+ if (key.name === FEEDBACK_OPTION_KEYS[FEEDBACK_OPTIONS.GOOD]) {
+ uiActions.submitFeedback(FEEDBACK_OPTIONS.GOOD);
+ } else if (key.name === FEEDBACK_OPTION_KEYS[FEEDBACK_OPTIONS.BAD]) {
+ uiActions.submitFeedback(FEEDBACK_OPTIONS.BAD);
+ } else if (key.name === FEEDBACK_OPTION_KEYS[FEEDBACK_OPTIONS.NOT_SURE]) {
+ uiActions.submitFeedback(FEEDBACK_OPTIONS.NOT_SURE);
}
+
+ uiActions.closeFeedbackDialog();
},
{ isActive: uiState.isFeedbackDialogOpen },
);
- if (!uiState.isFeedbackDialogOpen) {
- return null;
- }
-
return (
@@ -37,13 +45,17 @@ export const FeedbackDialog: React.FC = () => {
{t('How is Qwen doing this session? (optional)')}
- 1:
+
+ {FEEDBACK_OPTION_KEYS[FEEDBACK_OPTIONS.GOOD]}:{' '}
+
{t('Good')}
- 2:
+ {FEEDBACK_OPTION_KEYS[FEEDBACK_OPTIONS.BAD]}:
{t('Bad')}
- 3:
+
+ {FEEDBACK_OPTION_KEYS[FEEDBACK_OPTIONS.NOT_SURE]}:{' '}
+
{t('Not Sure Yet')}
diff --git a/packages/cli/src/ui/components/Composer.tsx b/packages/cli/src/ui/components/Composer.tsx
index 1b51227a1..9052e4f4d 100644
--- a/packages/cli/src/ui/components/Composer.tsx
+++ b/packages/cli/src/ui/components/Composer.tsx
@@ -26,6 +26,7 @@ import { useSettings } from '../contexts/SettingsContext.js';
import { ApprovalMode } from '@qwen-code/qwen-code-core';
import { StreamingState } from '../types.js';
import { ConfigInitDisplay } from '../components/ConfigInitDisplay.js';
+import { FeedbackDialog } from '../FeedbackDialog.js';
import { t } from '../../i18n/index.js';
export const Composer = () => {
@@ -134,6 +135,8 @@ export const Composer = () => {
)}
+ {uiState.isFeedbackDialogOpen && }
+
{uiState.isInputActive && (
;
- }
-
return null;
};
diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx
index cf8b9685c..c34578294 100644
--- a/packages/cli/src/ui/components/InputPrompt.test.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.test.tsx
@@ -33,6 +33,9 @@ vi.mock('../hooks/useCommandCompletion.js');
vi.mock('../hooks/useInputHistory.js');
vi.mock('../hooks/useReverseSearchCompletion.js');
vi.mock('../utils/clipboardUtils.js');
+vi.mock('../contexts/UIStateContext.js', () => ({
+ useUIState: vi.fn(() => ({ isFeedbackDialogOpen: false })),
+}));
const mockSlashCommands: SlashCommand[] = [
{
diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index 7d1742505..1f7ed099a 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -36,6 +36,8 @@ import {
import * as path from 'node:path';
import { SCREEN_READER_USER_PREFIX } from '../textConstants.js';
import { useShellFocusState } from '../contexts/ShellFocusContext.js';
+import { useUIState } from '../contexts/UIStateContext.js';
+import { FEEDBACK_DIALOG_KEYS } from '../FeedbackDialog.js';
export interface InputPromptProps {
buffer: TextBuffer;
onSubmit: (value: string) => void;
@@ -100,6 +102,7 @@ export const InputPrompt: React.FC = ({
isEmbeddedShellFocused,
}) => {
const isShellFocused = useShellFocusState();
+ const uiState = useUIState();
const [justNavigatedHistory, setJustNavigatedHistory] = useState(false);
const [escPressCount, setEscPressCount] = useState(0);
const [showEscapePrompt, setShowEscapePrompt] = useState(false);
@@ -326,6 +329,14 @@ export const InputPrompt: React.FC = ({
return;
}
+ // Intercept feedback dialog option keys (1, 2, 3) when dialog is open
+ if (
+ uiState.isFeedbackDialogOpen &&
+ (FEEDBACK_DIALOG_KEYS as readonly string[]).includes(key.name)
+ ) {
+ return;
+ }
+
// Reset ESC count and hide prompt on any non-ESC key
if (key.name !== 'escape') {
if (escPressCount > 0 || showEscapePrompt) {
@@ -670,6 +681,7 @@ export const InputPrompt: React.FC = ({
recentPasteTime,
commandSearchActive,
commandSearchCompletion,
+ uiState,
],
);