mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-02-01 22:48:03 +00:00
fix(ui): handle large content in AskUserDialog with MaxSizedBox
Constrain content height using MaxSizedBox to prevent flicker when displaying large plan files. Content is truncated based on available terminal height with a "lines hidden" indicator.
This commit is contained in:
@@ -962,5 +962,70 @@ describe('AskUserDialog', () => {
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('truncates long content when availableTerminalHeight is small', async () => {
|
||||
const longContent = Array.from(
|
||||
{ length: 30 },
|
||||
(_, i) => `Line ${i + 1}`,
|
||||
).join('\n');
|
||||
const questionWithLongContent: Question[] = [
|
||||
{
|
||||
question: 'Approve this plan?',
|
||||
header: 'Plan',
|
||||
options: [{ label: 'Yes', description: '' }],
|
||||
content: longContent,
|
||||
},
|
||||
];
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
<AskUserDialog
|
||||
questions={questionWithLongContent}
|
||||
onSubmit={vi.fn()}
|
||||
onCancel={vi.fn()}
|
||||
/>,
|
||||
{
|
||||
width: 120,
|
||||
uiState: {
|
||||
availableTerminalHeight: 15,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not truncate content when availableTerminalHeight is undefined', () => {
|
||||
const content = Array.from(
|
||||
{ length: 10 },
|
||||
(_, i) => `Line ${i + 1}`,
|
||||
).join('\n');
|
||||
const questionWithContent: Question[] = [
|
||||
{
|
||||
question: 'Approve this plan?',
|
||||
header: 'Plan',
|
||||
options: [{ label: 'Yes', description: '' }],
|
||||
content,
|
||||
},
|
||||
];
|
||||
|
||||
const { lastFrame } = renderWithProviders(
|
||||
<AskUserDialog
|
||||
questions={questionWithContent}
|
||||
onSubmit={vi.fn()}
|
||||
onCancel={vi.fn()}
|
||||
/>,
|
||||
{
|
||||
width: 120,
|
||||
uiState: {
|
||||
availableTerminalHeight: undefined,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(lastFrame()).not.toContain('lines hidden');
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,6 +31,17 @@ import { useTabbedNavigation } from '../hooks/useTabbedNavigation.js';
|
||||
import { DialogFooter } from './shared/DialogFooter.js';
|
||||
import { MaxSizedBox } from './shared/MaxSizedBox.js';
|
||||
|
||||
// Width reduction for content inside the dialog border/padding
|
||||
const CONTENT_WIDTH_REDUCTION = 4;
|
||||
|
||||
// Height consumed by dialog chrome surrounding the content area:
|
||||
// - Border top/bottom: 2
|
||||
// - Question text + marginBottom: 2
|
||||
// - Footer (keyboard hints): 2
|
||||
// - Options/input minimum: 4
|
||||
// - Buffer for tab header when present: 2
|
||||
const DIALOG_CHROME_HEIGHT = 12;
|
||||
|
||||
interface AskUserDialogState {
|
||||
answers: { [key: string]: string };
|
||||
isEditingCustomOption: boolean;
|
||||
@@ -283,11 +294,16 @@ const TextQuestionView: React.FC<TextQuestionViewProps> = ({
|
||||
{progressHeader}
|
||||
{question.content && (
|
||||
<Box marginBottom={1} flexDirection="column">
|
||||
<MaxSizedBox maxHeight={uiState?.availableTerminalHeight}>
|
||||
<MaxSizedBox
|
||||
maxHeight={
|
||||
uiState?.availableTerminalHeight &&
|
||||
uiState.availableTerminalHeight - DIALOG_CHROME_HEIGHT
|
||||
}
|
||||
>
|
||||
<MarkdownDisplay
|
||||
text={question.content}
|
||||
isPending={false}
|
||||
terminalWidth={availableWidth - 4} // Adjust for parent border/padding
|
||||
terminalWidth={availableWidth - CONTENT_WIDTH_REDUCTION}
|
||||
/>
|
||||
</MaxSizedBox>
|
||||
</Box>
|
||||
@@ -722,11 +738,16 @@ const ChoiceQuestionView: React.FC<ChoiceQuestionViewProps> = ({
|
||||
{progressHeader}
|
||||
{question.content && (
|
||||
<Box marginBottom={1} flexDirection="column">
|
||||
<MaxSizedBox maxHeight={uiState?.availableTerminalHeight}>
|
||||
<MaxSizedBox
|
||||
maxHeight={
|
||||
uiState?.availableTerminalHeight &&
|
||||
uiState.availableTerminalHeight - DIALOG_CHROME_HEIGHT
|
||||
}
|
||||
>
|
||||
<MarkdownDisplay
|
||||
text={question.content}
|
||||
isPending={false}
|
||||
terminalWidth={availableWidth - 4} // Adjust for parent border/padding
|
||||
terminalWidth={availableWidth - CONTENT_WIDTH_REDUCTION}
|
||||
/>
|
||||
</MaxSizedBox>
|
||||
</Box>
|
||||
|
||||
@@ -11,6 +11,28 @@ exports[`AskUserDialog > Question content field > does not render content when c
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Question content field > does not truncate content when availableTerminalHeight is undefined 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Line 1 │
|
||||
│ Line 2 │
|
||||
│ Line 3 │
|
||||
│ Line 4 │
|
||||
│ Line 5 │
|
||||
│ Line 6 │
|
||||
│ Line 7 │
|
||||
│ Line 8 │
|
||||
│ Line 9 │
|
||||
│ Line 10 │
|
||||
│ │
|
||||
│ Approve this plan? │
|
||||
│ │
|
||||
│ ● 1. Yes │
|
||||
│ 2. Enter a custom value │
|
||||
│ │
|
||||
│ Enter to select · ↑/↓ to navigate · Esc to cancel │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Question content field > renders content in a choice question 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Plan Details │
|
||||
@@ -44,6 +66,21 @@ exports[`AskUserDialog > Question content field > renders content in a text ques
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Question content field > truncates long content when availableTerminalHeight is small 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ ... first 28 lines hidden ... │
|
||||
│ Line 29 │
|
||||
│ Line 30 │
|
||||
│ │
|
||||
│ Approve this plan? │
|
||||
│ │
|
||||
│ ● 1. Yes │
|
||||
│ 2. Enter a custom value │
|
||||
│ │
|
||||
│ Enter to select · ↑/↓ to navigate · Esc to cancel │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`AskUserDialog > Question content field > uses customOptionPlaceholder for the Other option 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Approve this? │
|
||||
|
||||
Reference in New Issue
Block a user