mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
feat(cli): Show permission mode badge in footer for DEFAULT mode (#6498)
Always display the current permission/approval mode in the footer,
including when in the default (Ask permissions) mode. Previously,
non-default modes showed indicators but the default mode showed nothing,
creating ambiguity for users switching between modes.
- Add grey ⏸ badge with 'Ask permissions' text for DEFAULT mode
- Update both main Footer and AgentFooter to render DEFAULT indicator
- Use theme.text.secondary for subtle, unobtrusive styling
- Badge is i18n-aware using existing t('Ask permissions') key
- Other mode indicators remain unchanged
Closes #6496
This commit is contained in:
parent
29cefd7fb1
commit
79bc668b71
6 changed files with 70 additions and 6 deletions
49
packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
Normal file
49
packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { render } from 'ink-testing-library';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { AutoAcceptIndicator } from './AutoAcceptIndicator.js';
|
||||
import { ApprovalMode } from '@qwen-code/qwen-code-core';
|
||||
|
||||
describe('<AutoAcceptIndicator />', () => {
|
||||
it('renders DEFAULT mode with pause badge and Ask permissions text', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.DEFAULT} />,
|
||||
);
|
||||
const frame = lastFrame()!;
|
||||
expect(frame).toContain('⏸');
|
||||
expect(frame).toContain('Ask permissions');
|
||||
});
|
||||
|
||||
it('renders PLAN mode indicator', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.PLAN} />,
|
||||
);
|
||||
expect(lastFrame()).toContain('plan mode');
|
||||
});
|
||||
|
||||
it('renders AUTO_EDIT mode indicator', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.AUTO_EDIT} />,
|
||||
);
|
||||
expect(lastFrame()).toContain('auto-accept edits');
|
||||
});
|
||||
|
||||
it('renders AUTO mode indicator', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.AUTO} />,
|
||||
);
|
||||
expect(lastFrame()).toContain('auto mode (classifier-evaluated)');
|
||||
});
|
||||
|
||||
it('renders YOLO mode indicator', () => {
|
||||
const { lastFrame } = render(
|
||||
<AutoAcceptIndicator approvalMode={ApprovalMode.YOLO} />,
|
||||
);
|
||||
expect(lastFrame()).toContain('YOLO mode');
|
||||
});
|
||||
});
|
||||
|
|
@ -45,6 +45,9 @@ export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
|
|||
subText = cycleText;
|
||||
break;
|
||||
case ApprovalMode.DEFAULT:
|
||||
textContent = `⏸ ${t('Ask permissions')}`;
|
||||
subText = cycleText;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { render } from 'ink-testing-library';
|
|||
import { act } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { Footer } from './Footer.js';
|
||||
import { ApprovalMode } from '@qwen-code/qwen-code-core';
|
||||
import * as useTerminalSize from '../hooks/useTerminalSize.js';
|
||||
import * as useStatusLineModule from '../hooks/useStatusLine.js';
|
||||
import { type UIState, UIStateContext } from '../contexts/UIStateContext.js';
|
||||
|
|
@ -233,6 +234,19 @@ describe('<Footer />', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('shows the default approval mode badge when in DEFAULT mode', () => {
|
||||
const { lastFrame } = renderWithWidth(
|
||||
120,
|
||||
createMockUIState({
|
||||
showAutoAcceptIndicator: ApprovalMode.DEFAULT,
|
||||
}),
|
||||
);
|
||||
const frame = lastFrame()!;
|
||||
expect(frame).toContain('⏸');
|
||||
expect(frame).toContain('Ask permissions');
|
||||
expect(frame).not.toContain('? for shortcuts');
|
||||
});
|
||||
|
||||
it('does not display the working directory or branch name', () => {
|
||||
const { lastFrame } = renderWithWidth(120, createMockUIState());
|
||||
expect(lastFrame()).not.toMatch(/\(.*\*\)/);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import { useUIState } from '../contexts/UIStateContext.js';
|
|||
import { useConfig } from '../contexts/ConfigContext.js';
|
||||
import { useSettings } from '../contexts/SettingsContext.js';
|
||||
import { useVimModeState } from '../contexts/VimModeContext.js';
|
||||
import { ApprovalMode } from '@qwen-code/qwen-code-core';
|
||||
import { GeminiSpinner } from './GeminiRespondingSpinner.js';
|
||||
import { GoalPill, useFooterGoalState } from './GoalPill.js';
|
||||
import { CronPill, useFooterCronTaskCount } from './CronPill.js';
|
||||
|
|
@ -107,8 +106,7 @@ export const Footer: React.FC = () => {
|
|||
message: uiState.startupIdeConnectionStatus.message,
|
||||
})}
|
||||
</Text>
|
||||
) : showAutoAcceptIndicator !== undefined &&
|
||||
showAutoAcceptIndicator !== ApprovalMode.DEFAULT ? (
|
||||
) : showAutoAcceptIndicator !== undefined ? (
|
||||
<AutoAcceptIndicator approvalMode={showAutoAcceptIndicator} />
|
||||
) : suppressHint ? null : (
|
||||
<Text color={theme.text.secondary}>{t('? for shortcuts')}</Text>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import type React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { ApprovalMode } from '@qwen-code/qwen-code-core';
|
||||
import type { ApprovalMode } from '@qwen-code/qwen-code-core';
|
||||
import { AutoAcceptIndicator } from '../AutoAcceptIndicator.js';
|
||||
import { ContextUsageDisplay } from '../ContextUsageDisplay.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
|
|
@ -30,8 +30,7 @@ export const AgentFooter: React.FC<AgentFooterProps> = ({
|
|||
contextWindowSize,
|
||||
terminalWidth,
|
||||
}) => {
|
||||
const showApproval =
|
||||
approvalMode !== undefined && approvalMode !== ApprovalMode.DEFAULT;
|
||||
const showApproval = approvalMode !== undefined;
|
||||
const showContext = promptTokenCount > 0 && contextWindowSize !== undefined;
|
||||
|
||||
if (!showApproval && !showContext) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export function getApprovalModeIndicatorColor(
|
|||
case ApprovalMode.YOLO:
|
||||
return theme.status.error;
|
||||
case ApprovalMode.DEFAULT:
|
||||
return theme.text.secondary;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue