mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-21 02:24:09 -07:00
feat(core): agnostic background task UI with CompletionBehavior (#22740)
Co-authored-by: mkorwel <matt.korwel@gmail.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import { DefaultAppLayout } from './DefaultAppLayout.js';
|
||||
import { StreamingState } from '../types.js';
|
||||
import { Text } from 'ink';
|
||||
import type { UIState } from '../contexts/UIStateContext.js';
|
||||
import type { BackgroundShell } from '../hooks/shellCommandProcessor.js';
|
||||
import type { BackgroundTask } from '../hooks/useExecutionLifecycle.js';
|
||||
|
||||
// Mock dependencies
|
||||
const mockUIState = {
|
||||
@@ -18,13 +18,13 @@ const mockUIState = {
|
||||
terminalHeight: 24,
|
||||
terminalWidth: 80,
|
||||
mainAreaWidth: 80,
|
||||
backgroundShells: new Map<number, BackgroundShell>(),
|
||||
activeBackgroundShellPid: null as number | null,
|
||||
backgroundShellHeight: 10,
|
||||
backgroundTasks: new Map<number, BackgroundTask>(),
|
||||
activeBackgroundTaskPid: null as number | null,
|
||||
backgroundTaskHeight: 10,
|
||||
embeddedShellFocused: false,
|
||||
dialogsVisible: false,
|
||||
streamingState: StreamingState.Idle,
|
||||
isBackgroundShellListOpen: false,
|
||||
isBackgroundTaskListOpen: false,
|
||||
mainControlsRef: vi.fn(),
|
||||
customDialog: null,
|
||||
historyManager: { addItem: vi.fn() },
|
||||
@@ -34,7 +34,7 @@ const mockUIState = {
|
||||
constrainHeight: false,
|
||||
availableTerminalHeight: 20,
|
||||
activePtyId: null,
|
||||
isBackgroundShellVisible: true,
|
||||
isBackgroundTaskVisible: true,
|
||||
} as unknown as UIState;
|
||||
|
||||
vi.mock('../contexts/UIStateContext.js', () => ({
|
||||
@@ -79,11 +79,11 @@ vi.mock('../components/ExitWarning.js', () => ({
|
||||
vi.mock('../components/CopyModeWarning.js', () => ({
|
||||
CopyModeWarning: () => <Text>CopyModeWarning</Text>,
|
||||
}));
|
||||
vi.mock('../components/BackgroundShellDisplay.js', () => ({
|
||||
BackgroundShellDisplay: () => <Text>BackgroundShellDisplay</Text>,
|
||||
vi.mock('../components/BackgroundTaskDisplay.js', () => ({
|
||||
BackgroundTaskDisplay: () => <Text>BackgroundTaskDisplay</Text>,
|
||||
}));
|
||||
|
||||
const createMockShell = (pid: number): BackgroundShell => ({
|
||||
const createMockShell = (pid: number): BackgroundTask => ({
|
||||
pid,
|
||||
command: 'test command',
|
||||
output: 'test output',
|
||||
@@ -96,25 +96,25 @@ describe('<DefaultAppLayout />', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Reset mock state defaults
|
||||
mockUIState.backgroundShells = new Map();
|
||||
mockUIState.activeBackgroundShellPid = null;
|
||||
mockUIState.backgroundTasks = new Map();
|
||||
mockUIState.activeBackgroundTaskPid = null;
|
||||
mockUIState.streamingState = StreamingState.Idle;
|
||||
});
|
||||
|
||||
it('renders BackgroundShellDisplay when shells exist and active', async () => {
|
||||
mockUIState.backgroundShells.set(123, createMockShell(123));
|
||||
mockUIState.activeBackgroundShellPid = 123;
|
||||
mockUIState.backgroundShellHeight = 5;
|
||||
it('renders BackgroundTaskDisplay when shells exist and active', async () => {
|
||||
mockUIState.backgroundTasks.set(123, createMockShell(123));
|
||||
mockUIState.activeBackgroundTaskPid = 123;
|
||||
mockUIState.backgroundTaskHeight = 5;
|
||||
|
||||
const { lastFrame, unmount } = await render(<DefaultAppLayout />);
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('hides BackgroundShellDisplay when StreamingState is WaitingForConfirmation', async () => {
|
||||
mockUIState.backgroundShells.set(123, createMockShell(123));
|
||||
mockUIState.activeBackgroundShellPid = 123;
|
||||
mockUIState.backgroundShellHeight = 5;
|
||||
it('hides BackgroundTaskDisplay when StreamingState is WaitingForConfirmation', async () => {
|
||||
mockUIState.backgroundTasks.set(123, createMockShell(123));
|
||||
mockUIState.activeBackgroundTaskPid = 123;
|
||||
mockUIState.backgroundTaskHeight = 5;
|
||||
mockUIState.streamingState = StreamingState.WaitingForConfirmation;
|
||||
|
||||
const { lastFrame, unmount } = await render(<DefaultAppLayout />);
|
||||
@@ -122,10 +122,10 @@ describe('<DefaultAppLayout />', () => {
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('shows BackgroundShellDisplay when StreamingState is NOT WaitingForConfirmation', async () => {
|
||||
mockUIState.backgroundShells.set(123, createMockShell(123));
|
||||
mockUIState.activeBackgroundShellPid = 123;
|
||||
mockUIState.backgroundShellHeight = 5;
|
||||
it('shows BackgroundTaskDisplay when StreamingState is NOT WaitingForConfirmation', async () => {
|
||||
mockUIState.backgroundTasks.set(123, createMockShell(123));
|
||||
mockUIState.activeBackgroundTaskPid = 123;
|
||||
mockUIState.backgroundTaskHeight = 5;
|
||||
mockUIState.streamingState = StreamingState.Responding;
|
||||
|
||||
const { lastFrame, unmount } = await render(<DefaultAppLayout />);
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useUIState } from '../contexts/UIStateContext.js';
|
||||
import { useFlickerDetector } from '../hooks/useFlickerDetector.js';
|
||||
import { useAlternateBuffer } from '../hooks/useAlternateBuffer.js';
|
||||
import { CopyModeWarning } from '../components/CopyModeWarning.js';
|
||||
import { BackgroundShellDisplay } from '../components/BackgroundShellDisplay.js';
|
||||
import { BackgroundTaskDisplay } from '../components/BackgroundTaskDisplay.js';
|
||||
import { StreamingState } from '../types.js';
|
||||
|
||||
export const DefaultAppLayout: React.FC = () => {
|
||||
@@ -39,21 +39,21 @@ export const DefaultAppLayout: React.FC = () => {
|
||||
>
|
||||
<MainContent />
|
||||
|
||||
{uiState.isBackgroundShellVisible &&
|
||||
uiState.backgroundShells.size > 0 &&
|
||||
uiState.activeBackgroundShellPid &&
|
||||
uiState.backgroundShellHeight > 0 &&
|
||||
{uiState.isBackgroundTaskVisible &&
|
||||
uiState.backgroundTasks.size > 0 &&
|
||||
uiState.activeBackgroundTaskPid &&
|
||||
uiState.backgroundTaskHeight > 0 &&
|
||||
uiState.streamingState !== StreamingState.WaitingForConfirmation && (
|
||||
<Box height={uiState.backgroundShellHeight} flexShrink={0}>
|
||||
<BackgroundShellDisplay
|
||||
shells={uiState.backgroundShells}
|
||||
activePid={uiState.activeBackgroundShellPid}
|
||||
<Box height={uiState.backgroundTaskHeight} flexShrink={0}>
|
||||
<BackgroundTaskDisplay
|
||||
shells={uiState.backgroundTasks}
|
||||
activePid={uiState.activeBackgroundTaskPid}
|
||||
width={uiState.terminalWidth}
|
||||
height={uiState.backgroundShellHeight}
|
||||
height={uiState.backgroundTaskHeight}
|
||||
isFocused={
|
||||
uiState.embeddedShellFocused && !uiState.dialogsVisible
|
||||
}
|
||||
isListOpenProp={uiState.isBackgroundShellListOpen}
|
||||
isListOpenProp={uiState.isBackgroundTaskListOpen}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`<DefaultAppLayout /> > hides BackgroundShellDisplay when StreamingState is WaitingForConfirmation 1`] = `
|
||||
exports[`<DefaultAppLayout /> > hides BackgroundTaskDisplay when StreamingState is WaitingForConfirmation 1`] = `
|
||||
"MainContent
|
||||
Notifications
|
||||
CopyModeWarning
|
||||
@@ -9,9 +9,9 @@ ExitWarning
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<DefaultAppLayout /> > renders BackgroundShellDisplay when shells exist and active 1`] = `
|
||||
exports[`<DefaultAppLayout /> > renders BackgroundTaskDisplay when shells exist and active 1`] = `
|
||||
"MainContent
|
||||
BackgroundShellDisplay
|
||||
BackgroundTaskDisplay
|
||||
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ ExitWarning
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<DefaultAppLayout /> > shows BackgroundShellDisplay when StreamingState is NOT WaitingForConfirmation 1`] = `
|
||||
exports[`<DefaultAppLayout /> > shows BackgroundTaskDisplay when StreamingState is NOT WaitingForConfirmation 1`] = `
|
||||
"MainContent
|
||||
BackgroundShellDisplay
|
||||
BackgroundTaskDisplay
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user