mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
feat(cli): add loading state to new agents notification (#19190)
This commit is contained in:
@@ -7,6 +7,8 @@
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import { renderWithProviders as render } from '../../test-utils/render.js';
|
import { renderWithProviders as render } from '../../test-utils/render.js';
|
||||||
import { NewAgentsNotification } from './NewAgentsNotification.js';
|
import { NewAgentsNotification } from './NewAgentsNotification.js';
|
||||||
|
import { waitFor } from '../../test-utils/async.js';
|
||||||
|
import { act } from 'react';
|
||||||
|
|
||||||
describe('NewAgentsNotification', () => {
|
describe('NewAgentsNotification', () => {
|
||||||
const mockAgents = [
|
const mockAgents = [
|
||||||
@@ -54,4 +56,28 @@ describe('NewAgentsNotification', () => {
|
|||||||
expect(frame).toMatchSnapshot();
|
expect(frame).toMatchSnapshot();
|
||||||
unmount();
|
unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows processing state when an option is selected', async () => {
|
||||||
|
const asyncOnSelect = vi.fn(
|
||||||
|
() =>
|
||||||
|
new Promise<void>(() => {
|
||||||
|
// Never resolve
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const { lastFrame, stdin, unmount } = render(
|
||||||
|
<NewAgentsNotification agents={mockAgents} onSelect={asyncOnSelect} />,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Press Enter to select the first option
|
||||||
|
await act(async () => {
|
||||||
|
stdin.write('\r');
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(lastFrame()).toContain('Processing...');
|
||||||
|
});
|
||||||
|
|
||||||
|
unmount();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
import { Box, Text } from 'ink';
|
import { Box, Text } from 'ink';
|
||||||
import { type AgentDefinition } from '@google/gemini-cli-core';
|
import { type AgentDefinition } from '@google/gemini-cli-core';
|
||||||
import { theme } from '../semantic-colors.js';
|
import { theme } from '../semantic-colors.js';
|
||||||
@@ -11,6 +12,7 @@ import {
|
|||||||
RadioButtonSelect,
|
RadioButtonSelect,
|
||||||
type RadioSelectItem,
|
type RadioSelectItem,
|
||||||
} from './shared/RadioButtonSelect.js';
|
} from './shared/RadioButtonSelect.js';
|
||||||
|
import { CliSpinner } from './CliSpinner.js';
|
||||||
|
|
||||||
export enum NewAgentsChoice {
|
export enum NewAgentsChoice {
|
||||||
ACKNOWLEDGE = 'acknowledge',
|
ACKNOWLEDGE = 'acknowledge',
|
||||||
@@ -19,13 +21,15 @@ export enum NewAgentsChoice {
|
|||||||
|
|
||||||
interface NewAgentsNotificationProps {
|
interface NewAgentsNotificationProps {
|
||||||
agents: AgentDefinition[];
|
agents: AgentDefinition[];
|
||||||
onSelect: (choice: NewAgentsChoice) => void;
|
onSelect: (choice: NewAgentsChoice) => void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NewAgentsNotification = ({
|
export const NewAgentsNotification = ({
|
||||||
agents,
|
agents,
|
||||||
onSelect,
|
onSelect,
|
||||||
}: NewAgentsNotificationProps) => {
|
}: NewAgentsNotificationProps) => {
|
||||||
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
|
|
||||||
const options: Array<RadioSelectItem<NewAgentsChoice>> = [
|
const options: Array<RadioSelectItem<NewAgentsChoice>> = [
|
||||||
{
|
{
|
||||||
label: 'Acknowledge and Enable',
|
label: 'Acknowledge and Enable',
|
||||||
@@ -39,6 +43,15 @@ export const NewAgentsNotification = ({
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleSelect = async (choice: NewAgentsChoice) => {
|
||||||
|
setIsProcessing(true);
|
||||||
|
try {
|
||||||
|
await onSelect(choice);
|
||||||
|
} finally {
|
||||||
|
setIsProcessing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Limit display to 5 agents to avoid overflow, show count for rest
|
// Limit display to 5 agents to avoid overflow, show count for rest
|
||||||
const MAX_DISPLAYED_AGENTS = 5;
|
const MAX_DISPLAYED_AGENTS = 5;
|
||||||
const displayAgents = agents.slice(0, MAX_DISPLAYED_AGENTS);
|
const displayAgents = agents.slice(0, MAX_DISPLAYED_AGENTS);
|
||||||
@@ -85,11 +98,18 @@ export const NewAgentsNotification = ({
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{isProcessing ? (
|
||||||
|
<Box>
|
||||||
|
<CliSpinner />
|
||||||
|
<Text color={theme.text.primary}> Processing...</Text>
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
<RadioButtonSelect
|
<RadioButtonSelect
|
||||||
items={options}
|
items={options}
|
||||||
onSelect={onSelect}
|
onSelect={handleSelect}
|
||||||
isFocused={true}
|
isFocused={true}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user