Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions packages/cli/src/ui/components/Footer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,61 @@ describe('<Footer />', () => {
unmount();
});

it('shows the context percentage even when hideModelInfo is true', async () => {
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
<Footer />,
{
width: 120,
uiState: { sessionStats: mockSessionStats },
settings: createMockSettings({
ui: {
footer: {
hideModelInfo: true,
hideContextPercentage: false,
},
},
}),
},
);
await waitUntilReady();

expect(lastFrame()).not.toContain(defaultProps.model);
expect(lastFrame()).toMatch(/\d+% context left/);
unmount();
});

it('shows quota stats even when hideModelInfo is true', async () => {
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
<Footer />,
{
width: 120,
uiState: {
sessionStats: mockSessionStats,
quota: {
userTier: undefined,
stats: { remaining: 15, limit: 100, resetTime: undefined },
proQuotaRequest: null,
validationRequest: null,
overageMenuRequest: null,
emptyWalletRequest: null,
},
},
settings: createMockSettings({
ui: {
footer: {
hideModelInfo: true,
},
},
}),
},
);
await waitUntilReady();

expect(lastFrame()).not.toContain(defaultProps.model);
expect(lastFrame()).toContain('15%');
unmount();
});

it('renders footer with all optional sections hidden (minimal footer)', async () => {
const { lastFrame, waitUntilReady, unmount } = renderWithProviders(
<Footer />,
Expand Down
36 changes: 29 additions & 7 deletions packages/cli/src/ui/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,22 @@ export const Footer: React.FC = () => {
const pathLength = Math.max(20, Math.floor(terminalWidth * 0.25));
const displayPath = shortenPath(tildeifyPath(targetDir), pathLength);

const justifyContent = hideCWD && hideModelInfo ? 'center' : 'space-between';
const displayVimMode = vimEnabled ? vimMode : undefined;

const showDebugProfiler = debugMode || isDevelopment;

// Determine if anything is visible on the left or right to set layout
const showLeftSection = showDebugProfiler || !!displayVimMode || !hideCWD;
const showRightSection =
!hideModelInfo ||
!hideContextPercentage ||
!!quotaStats ||
showMemoryUsage ||
corgiMode ||
showErrorSummary;

const justifyContent =
!showLeftSection && !showRightSection ? 'center' : 'space-between';

return (
<Box
justifyContent={justifyContent}
Expand Down Expand Up @@ -140,15 +151,25 @@ export const Footer: React.FC = () => {
)}

{/* Right Section: Gemini Label and Console Summary */}
{!hideModelInfo && (
{(!hideModelInfo ||
!hideContextPercentage ||
!!quotaStats ||
showMemoryUsage ||
corgiMode ||
showErrorSummary) && (
<Box alignItems="center" justifyContent="flex-end">
<Box alignItems="center">
<Text color={theme.text.primary}>
<Text color={theme.text.secondary}>/model </Text>
{getDisplayString(model)}
{!hideModelInfo && (
<>
<Text color={theme.text.secondary}>/model </Text>
{getDisplayString(model)}
</>
)}
{!hideContextPercentage && (
<>
{' '}
{/* Adds a space between Model Info and Context if BOTH are shown */}
{!hideModelInfo && ' '}
<ContextUsageDisplay
promptTokenCount={promptTokenCount}
model={model}
Expand All @@ -158,7 +179,8 @@ export const Footer: React.FC = () => {
)}
{quotaStats && (
<>
{' '}
{/* Adds a space if either of the previous items are shown */}
{(!hideModelInfo || !hideContextPercentage) && ' '}
<QuotaDisplay
remaining={quotaStats.remaining}
limit={quotaStats.limit}
Expand Down