mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-19 02:20:42 -07:00
refactor: Update Card component to use a status prop and integrate ToolStatusIndicator.
This commit is contained in:
@@ -8,55 +8,55 @@ import { render } from '../../../test-utils/render.js';
|
||||
import { Card } from './Card.js';
|
||||
import { Text } from 'ink';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
|
||||
describe('Card', () => {
|
||||
it.each([
|
||||
{
|
||||
variant: 'warning',
|
||||
status: ToolCallStatus.Pending,
|
||||
title: 'Gemini CLI update available',
|
||||
suffix: '0.26.0 → 0.27.0',
|
||||
prefix: true,
|
||||
body: 'Installed via Homebrew. Please update with "brew upgrade gemini-cli".',
|
||||
},
|
||||
{
|
||||
variant: 'information',
|
||||
status: ToolCallStatus.Canceled,
|
||||
title: 'Delegate to agent',
|
||||
suffix: "Delegating to agent 'cli_help'",
|
||||
prefix: true,
|
||||
body: '🤖💭 Execution limit reached (ERROR_NO_COMPLETE_TASK_CALL). Attempting one final recovery turn with a grace period.',
|
||||
},
|
||||
{
|
||||
variant: 'error',
|
||||
status: ToolCallStatus.Error,
|
||||
title: 'Error',
|
||||
suffix: '429 You exceeded your current quota',
|
||||
prefix: true,
|
||||
body: 'Go to https://aistudio.google.com/apikey to upgrade your quota tier, or submit a quota increase request in https://ai.google.dev/gemini-api/docs/rate-limits',
|
||||
},
|
||||
{
|
||||
variant: 'confirmation',
|
||||
status: ToolCallStatus.Confirming,
|
||||
title: 'Shell',
|
||||
suffix: 'node -v && which gemini',
|
||||
prefix: true,
|
||||
body: "ls /usr/local/bin | grep 'xattr'",
|
||||
},
|
||||
{
|
||||
variant: 'success',
|
||||
status: ToolCallStatus.Success,
|
||||
title: 'ReadFolder',
|
||||
suffix: '/usr/local/bin',
|
||||
prefix: true,
|
||||
body: 'Listed 39 item(s).',
|
||||
},
|
||||
] as const)(
|
||||
'renders a $variant card with prefix=$prefix',
|
||||
({ variant, title, suffix, prefix, body }) => {
|
||||
'renders a $status card with prefix=$prefix',
|
||||
({ status, title, suffix, prefix, body }) => {
|
||||
const { lastFrame } = render(
|
||||
<Card variant={variant} title={title} suffix={suffix} prefix={prefix}>
|
||||
<Card status={status} title={title} suffix={suffix} prefix={prefix}>
|
||||
<Text>{body}</Text>
|
||||
</Card>,
|
||||
);
|
||||
|
||||
const output = lastFrame();
|
||||
|
||||
expect(output).toMatchSnapshot();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
import type React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { TOOL_STATUS } from '../../constants.js';
|
||||
import { ToolStatusIndicator } from '../messages/ToolShared.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
|
||||
/**
|
||||
* Props for the Card component.
|
||||
@@ -22,55 +23,39 @@ export interface CardProps {
|
||||
/** The content to be displayed inside the card. */
|
||||
children?: React.ReactNode;
|
||||
/** The styling and intent of the card. */
|
||||
variant?: 'information' | 'success' | 'warning' | 'error' | 'confirmation';
|
||||
status?: ToolCallStatus;
|
||||
}
|
||||
|
||||
export const Card: React.FC<CardProps> = ({
|
||||
variant = 'information',
|
||||
status = ToolCallStatus.Pending,
|
||||
title,
|
||||
prefix = true,
|
||||
suffix,
|
||||
children,
|
||||
}) => {
|
||||
const getColors = () => {
|
||||
switch (variant) {
|
||||
case 'error':
|
||||
return { border: theme.status.error, text: theme.status.error };
|
||||
case 'warning':
|
||||
return { border: theme.status.warning, text: theme.status.warning };
|
||||
case 'success':
|
||||
return { border: theme.status.success, text: theme.status.success };
|
||||
case 'confirmation':
|
||||
switch (status) {
|
||||
case ToolCallStatus.Pending:
|
||||
return { border: theme.border.default, text: theme.text.accent };
|
||||
case ToolCallStatus.Confirming:
|
||||
return { border: theme.border.focused, text: theme.text.link };
|
||||
case 'information':
|
||||
return { border: theme.border.default, text: theme.text.primary };
|
||||
case ToolCallStatus.Error:
|
||||
return { border: theme.status.error, text: theme.status.error };
|
||||
case ToolCallStatus.Success:
|
||||
return { border: theme.border.default, text: theme.status.success };
|
||||
case ToolCallStatus.Canceled:
|
||||
return { border: theme.status.warning, text: theme.status.warning };
|
||||
case ToolCallStatus.Executing:
|
||||
return { border: theme.border.default, text: theme.status.success };
|
||||
default:
|
||||
return { border: theme.border.default, text: theme.text.primary };
|
||||
}
|
||||
};
|
||||
|
||||
const getGlyph = () => {
|
||||
switch (variant) {
|
||||
case 'error':
|
||||
return TOOL_STATUS.ERROR;
|
||||
case 'success':
|
||||
return TOOL_STATUS.SUCCESS;
|
||||
case 'warning':
|
||||
return TOOL_STATUS.WARNING;
|
||||
case 'confirmation':
|
||||
return TOOL_STATUS.CONFIRMING;
|
||||
case 'information':
|
||||
return TOOL_STATUS.INFORMATION;
|
||||
default:
|
||||
return TOOL_STATUS.INFORMATION;
|
||||
}
|
||||
};
|
||||
|
||||
const colors = getColors();
|
||||
const glyph = getGlyph();
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Box flexDirection="column">
|
||||
<Box width="100%" flexDirection="row">
|
||||
{/* Top border section */}
|
||||
<Box
|
||||
@@ -88,7 +73,10 @@ export const Card: React.FC<CardProps> = ({
|
||||
gap={1}
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
<Box>{prefix && <Text color={colors.text}>{glyph}</Text>}</Box>
|
||||
{/* TODO: Use shared ToolStatusIndicator component */}
|
||||
<Box marginRight={-2}>
|
||||
{prefix && <ToolStatusIndicator status={status} name={title} />}
|
||||
</Box>
|
||||
<Text bold color={colors.text}>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
@@ -1,38 +1,33 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Card > renders a 'confirmation' card with prefix=true 1`] = `
|
||||
"╭ ? Shell node -v && which gemini ─────────────────────────────────────────────────────────────────╮
|
||||
│ ls /usr/local/bin | grep 'xattr' │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
exports[`Card > renders a 'Canceled' card with prefix=true 1`] = `
|
||||
"[38;2;249;226;175m╭[39m [1m[38;2;249;226;175m-[39m[22m [1m[38;2;249;226;175mDelegate to agent[39m[22m [38;2;249;226;175m[2mDelegating to agent 'cli_help'[22m[39m [38;2;249;226;175m──────────────────────────────────────────────╮[39m
|
||||
[38;2;249;226;175m│[39m 🤖💭 Execution limit reached (ERROR_NO_COMPLETE_TASK_CALL). Attempting one final recovery turn [38;2;249;226;175m│[39m
|
||||
[38;2;249;226;175m│[39m with a grace period. [38;2;249;226;175m│[39m
|
||||
[38;2;249;226;175m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯[39m"
|
||||
`;
|
||||
|
||||
exports[`Card > renders a 'error' card with prefix=true 1`] = `
|
||||
"╭ x Error 429 You exceeded your current quota ─────────────────────────────────────────────────────╮
|
||||
│ Go to https://aistudio.google.com/apikey to upgrade your quota tier, or submit a quota increase │
|
||||
│ request in https://ai.google.dev/gemini-api/docs/rate-limits │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
exports[`Card > renders a 'Confirming' card with prefix=true 1`] = `
|
||||
"[38;2;137;180;250m╭[39m [38;2;137;220;235m?[39m [1m[38;2;137;180;250mShell[39m[22m [38;2;137;180;250m[2mnode -v && which gemini[22m[39m [38;2;137;180;250m─────────────────────────────────────────────────────────────────╮[39m
|
||||
[38;2;137;180;250m│[39m ls /usr/local/bin | grep 'xattr' [38;2;137;180;250m│[39m
|
||||
[38;2;137;180;250m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯[39m"
|
||||
`;
|
||||
|
||||
exports[`Card > renders a 'information' card with prefix=true 1`] = `
|
||||
"╭ ℹ Delegate to agent Delegating to agent 'cli_help' ──────────────────────────────────────────────╮
|
||||
│ 🤖💭 Execution limit reached (ERROR_NO_COMPLETE_TASK_CALL). Attempting one final recovery turn │
|
||||
│ with a grace period. │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
exports[`Card > renders a 'Error' card with prefix=true 1`] = `
|
||||
"[38;2;243;139;168m╭[39m [1m[38;2;243;139;168mx[39m[22m [1m[38;2;243;139;168mError[39m[22m [38;2;243;139;168m[2m429 You exceeded your current quota[22m[39m [38;2;243;139;168m─────────────────────────────────────────────────────╮[39m
|
||||
[38;2;243;139;168m│[39m Go to https://aistudio.google.com/apikey to upgrade your quota tier, or submit a quota increase [38;2;243;139;168m│[39m
|
||||
[38;2;243;139;168m│[39m request in https://ai.google.dev/gemini-api/docs/rate-limits [38;2;243;139;168m│[39m
|
||||
[38;2;243;139;168m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯[39m"
|
||||
`;
|
||||
|
||||
exports[`Card > renders a 'success' card with prefix=true 1`] = `
|
||||
"╭ ✓ ReadFolder /usr/local/bin ─────────────────────────────────────────────────────────────────────╮
|
||||
│ Listed 39 item(s). │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
exports[`Card > renders a 'Pending' card with prefix=true 1`] = `
|
||||
"[38;2;108;112;134m╭[39m [38;2;166;227;161mo[39m [1m[38;2;203;166;247mGemini CLI update available[39m[22m [38;2;203;166;247m[2m0.26.0 → 0.27.0[22m[39m [38;2;108;112;134m───────────────────────────────────────────────────╮[39m
|
||||
[38;2;108;112;134m│[39m Installed via Homebrew. Please update with "brew upgrade gemini-cli". [38;2;108;112;134m│[39m
|
||||
[38;2;108;112;134m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯[39m"
|
||||
`;
|
||||
|
||||
exports[`Card > renders a 'warning' card with prefix=true 1`] = `
|
||||
"╭ ⚠ Gemini CLI update available 0.26.0 → 0.27.0 ───────────────────────────────────────────────────╮
|
||||
│ Installed via Homebrew. Please update with "brew upgrade gemini-cli". │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
"
|
||||
exports[`Card > renders a 'Success' card with prefix=true 1`] = `
|
||||
"[38;2;108;112;134m╭[39m [38;2;166;227;161m✓[39m [1m[38;2;166;227;161mReadFolder[39m[22m [38;2;166;227;161m[2m/usr/local/bin[22m[39m [38;2;108;112;134m─────────────────────────────────────────────────────────────────────╮[39m
|
||||
[38;2;108;112;134m│[39m Listed 39 item(s). [38;2;108;112;134m│[39m
|
||||
[38;2;108;112;134m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯[39m"
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user