feat(ux) Expandable (ctrl-O) and scrollable approvals in alternate buffer mode. (#17640)

This commit is contained in:
Jacob Richman
2026-01-27 16:06:24 -08:00
committed by GitHub
parent ff6547857e
commit d165b6d4e7
34 changed files with 1177 additions and 496 deletions

View File

@@ -12,6 +12,10 @@ import { ToolConfirmationMessage } from './messages/ToolConfirmationMessage.js';
import { ToolStatusIndicator, ToolInfo } from './messages/ToolShared.js';
import { useUIState } from '../contexts/UIStateContext.js';
import type { ConfirmingToolState } from '../hooks/useConfirmingTool.js';
import { OverflowProvider } from '../contexts/OverflowContext.js';
import { ShowMoreLines } from './ShowMoreLines.js';
import { StickyHeader } from './StickyHeader.js';
import { useAlternateBuffer } from '../hooks/useAlternateBuffer.js';
interface ToolConfirmationQueueProps {
confirmingTool: ConfirmingToolState;
@@ -21,7 +25,8 @@ export const ToolConfirmationQueue: React.FC<ToolConfirmationQueueProps> = ({
confirmingTool,
}) => {
const config = useConfig();
const { terminalWidth, terminalHeight } = useUIState();
const isAlternateBuffer = useAlternateBuffer();
const { mainAreaWidth, terminalHeight, constrainHeight } = useUIState();
const { tool, index, total } = confirmingTool;
// Safety check: ToolConfirmationMessage requires confirmationDetails
@@ -38,52 +43,85 @@ export const ToolConfirmationQueue: React.FC<ToolConfirmationQueueProps> = ({
// - 2 lines for the rounded border
// - 2 lines for the Header (text + margin)
// - 2 lines for Tool Identity (text + margin)
const availableContentHeight = Math.max(maxHeight - 6, 4);
const availableContentHeight =
constrainHeight && !isAlternateBuffer
? Math.max(maxHeight - 6, 4)
: undefined;
const borderColor = theme.status.warning;
return (
<Box
flexDirection="column"
borderStyle="round"
borderColor={theme.status.warning}
paddingX={1}
// Matches existing layout spacing
width={terminalWidth}
flexShrink={0}
>
{/* Header */}
<Box marginBottom={1} justifyContent="space-between">
<Text color={theme.status.warning} bold>
Action Required
</Text>
<Text color={theme.text.secondary}>
{index} of {total}
</Text>
</Box>
<OverflowProvider>
<Box flexDirection="column" width={mainAreaWidth} flexShrink={0}>
<StickyHeader
width={mainAreaWidth}
isFirst={true}
borderColor={borderColor}
borderDimColor={false}
>
<Box flexDirection="column" width={mainAreaWidth - 4}>
{/* Header */}
<Box marginBottom={1} justifyContent="space-between">
<Text color={theme.status.warning} bold>
Action Required
</Text>
<Text color={theme.text.secondary}>
{index} of {total}
</Text>
</Box>
{/* Tool Identity (Context) */}
<Box marginBottom={1}>
<ToolStatusIndicator status={tool.status} name={tool.name} />
<ToolInfo
name={tool.name}
status={tool.status}
description={tool.description}
emphasis="high"
{/* Tool Identity (Context) */}
<Box>
<ToolStatusIndicator status={tool.status} name={tool.name} />
<ToolInfo
name={tool.name}
status={tool.status}
description={tool.description}
emphasis="high"
/>
</Box>
</Box>
</StickyHeader>
<Box
width={mainAreaWidth}
borderStyle="round"
borderColor={borderColor}
borderTop={false}
borderBottom={false}
borderLeft={true}
borderRight={true}
paddingX={1}
flexDirection="column"
>
{/* Interactive Area */}
{/*
Note: We force isFocused={true} because if this component is rendered,
it effectively acts as a modal over the shell/composer.
*/}
<ToolConfirmationMessage
callId={tool.callId}
confirmationDetails={tool.confirmationDetails}
config={config}
terminalWidth={mainAreaWidth - 4} // Adjust for parent border/padding
availableTerminalHeight={availableContentHeight}
isFocused={true}
/>
</Box>
<Box
height={0}
width={mainAreaWidth}
borderLeft={true}
borderRight={true}
borderTop={false}
borderBottom={true}
borderColor={borderColor}
borderStyle="round"
/>
</Box>
{/* Interactive Area */}
{/*
Note: We force isFocused={true} because if this component is rendered,
it effectively acts as a modal over the shell/composer.
*/}
<ToolConfirmationMessage
callId={tool.callId}
confirmationDetails={tool.confirmationDetails}
config={config}
terminalWidth={terminalWidth - 4} // Adjust for parent border/padding
availableTerminalHeight={availableContentHeight}
isFocused={true}
/>
</Box>
<Box paddingX={2} marginBottom={1}>
<ShowMoreLines constrainHeight={constrainHeight} />
</Box>
</OverflowProvider>
);
};