mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 20:20:57 +00:00
feat(ui): enhance LoadingIndicator to display token counts and improve formatting
- Added candidatesTokens prop to LoadingIndicator for displaying token counts. - Updated formatting to show elapsed time and token counts inline. - Refactored tests to validate new token display functionality and formatting changes. - Introduced formatTokenCount utility for consistent token count representation. This improves user feedback during loading states by providing clearer information on token usage.
This commit is contained in:
parent
dbfa5b3e8e
commit
03e59256c4
6 changed files with 152 additions and 18 deletions
|
|
@ -72,7 +72,8 @@ describe('<LoadingIndicator />', () => {
|
|||
const output = lastFrame();
|
||||
expect(output).toContain('MockRespondingSpinner');
|
||||
expect(output).toContain('Loading...');
|
||||
expect(output).toContain('(esc to cancel, 5s)');
|
||||
expect(output).toContain('5s');
|
||||
expect(output).toContain('esc to cancel');
|
||||
});
|
||||
|
||||
it('should render spinner (static), phrase but no time/cancel when streamingState is WaitingForConfirmation', () => {
|
||||
|
|
@ -88,7 +89,7 @@ describe('<LoadingIndicator />', () => {
|
|||
expect(output).toContain('⠏'); // Static char for WaitingForConfirmation
|
||||
expect(output).toContain('Confirm action');
|
||||
expect(output).not.toContain('(esc to cancel)');
|
||||
expect(output).not.toContain(', 10s');
|
||||
expect(output).not.toContain('10s');
|
||||
});
|
||||
|
||||
it('should display the currentLoadingPhrase correctly', () => {
|
||||
|
|
@ -112,7 +113,7 @@ describe('<LoadingIndicator />', () => {
|
|||
<LoadingIndicator {...props} />,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
expect(lastFrame()).toContain('(esc to cancel, 1m)');
|
||||
expect(lastFrame()).toContain('(1m · esc to cancel)');
|
||||
});
|
||||
|
||||
it('should display the elapsedTime correctly in human-readable format', () => {
|
||||
|
|
@ -124,7 +125,7 @@ describe('<LoadingIndicator />', () => {
|
|||
<LoadingIndicator {...props} />,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
expect(lastFrame()).toContain('(esc to cancel, 2m 5s)');
|
||||
expect(lastFrame()).toContain('(2m 5s · esc to cancel)');
|
||||
});
|
||||
|
||||
it('should render rightContent when provided', () => {
|
||||
|
|
@ -155,7 +156,7 @@ describe('<LoadingIndicator />', () => {
|
|||
let output = lastFrame();
|
||||
expect(output).toContain('MockRespondingSpinner');
|
||||
expect(output).toContain('Now Responding');
|
||||
expect(output).toContain('(esc to cancel, 2s)');
|
||||
expect(output).toContain('(2s · esc to cancel)');
|
||||
|
||||
// Transition to WaitingForConfirmation
|
||||
rerender(
|
||||
|
|
@ -170,7 +171,7 @@ describe('<LoadingIndicator />', () => {
|
|||
expect(output).toContain('⠏');
|
||||
expect(output).toContain('Please Confirm');
|
||||
expect(output).not.toContain('(esc to cancel)');
|
||||
expect(output).not.toContain(', 15s');
|
||||
expect(output).not.toContain('15s');
|
||||
|
||||
// Transition back to Idle
|
||||
rerender(
|
||||
|
|
@ -262,7 +263,7 @@ describe('<LoadingIndicator />', () => {
|
|||
// Check for single line output
|
||||
expect(output?.includes('\n')).toBe(false);
|
||||
expect(output).toContain('Loading...');
|
||||
expect(output).toContain('(esc to cancel, 5s)');
|
||||
expect(output).toContain('(5s · esc to cancel)');
|
||||
expect(output).toContain('Right');
|
||||
});
|
||||
|
||||
|
|
@ -284,8 +285,8 @@ describe('<LoadingIndicator />', () => {
|
|||
expect(lines).toHaveLength(3);
|
||||
if (lines) {
|
||||
expect(lines[0]).toContain('Loading...');
|
||||
expect(lines[0]).not.toContain('(esc to cancel, 5s)');
|
||||
expect(lines[1]).toContain('(esc to cancel, 5s)');
|
||||
expect(lines[0]).not.toContain('5s');
|
||||
expect(lines[1]).toContain('5s');
|
||||
expect(lines[2]).toContain('Right');
|
||||
}
|
||||
});
|
||||
|
|
@ -308,4 +309,86 @@ describe('<LoadingIndicator />', () => {
|
|||
expect(lastFrame()?.includes('\n')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('token display', () => {
|
||||
it('should display output tokens inline with arrow notation', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<LoadingIndicator
|
||||
{...defaultProps}
|
||||
promptTokens={1500}
|
||||
candidatesTokens={847}
|
||||
/>,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('↓ 847 tokens');
|
||||
expect(output).not.toContain('↑');
|
||||
expect(output).toContain('5s');
|
||||
expect(output).toContain('esc to cancel');
|
||||
});
|
||||
|
||||
it('should not display tokens when output tokens is 0', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<LoadingIndicator
|
||||
{...defaultProps}
|
||||
promptTokens={1500}
|
||||
candidatesTokens={0}
|
||||
/>,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).not.toContain('↓');
|
||||
expect(output).not.toContain('tokens');
|
||||
});
|
||||
|
||||
it('should not display tokens when props are undefined', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<LoadingIndicator {...defaultProps} />,
|
||||
StreamingState.Responding,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).not.toContain('↓');
|
||||
expect(output).not.toContain('tokens');
|
||||
});
|
||||
|
||||
it('should hide tokens in narrow terminal', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<LoadingIndicator
|
||||
{...defaultProps}
|
||||
promptTokens={1000}
|
||||
candidatesTokens={500}
|
||||
/>,
|
||||
StreamingState.Responding,
|
||||
79,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).not.toContain('↓');
|
||||
expect(output).not.toContain('tokens');
|
||||
expect(output).toContain('esc to cancel');
|
||||
});
|
||||
|
||||
it('should show tokens in wide terminal with inline format', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<LoadingIndicator
|
||||
{...defaultProps}
|
||||
promptTokens={1000}
|
||||
candidatesTokens={5400}
|
||||
/>,
|
||||
StreamingState.Responding,
|
||||
80,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('↓ 5.4k tokens');
|
||||
});
|
||||
|
||||
it('should format tokens inline with time and cancel', () => {
|
||||
const { lastFrame } = renderWithContext(
|
||||
<LoadingIndicator {...defaultProps} candidatesTokens={5400} />,
|
||||
StreamingState.Responding,
|
||||
120,
|
||||
);
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('(5s · ↓ 5.4k tokens · esc to cancel)');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue