Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
26 changes: 20 additions & 6 deletions packages/cli/src/ui/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ 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 justifyContent =
hideCWD && hideModelInfo && hideContextPercentage
? 'center'
: 'space-between';
const displayVimMode = vimEnabled ? vimMode : undefined;

const showDebugProfiler = debugMode || isDevelopment;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The logic for justifyContent is an improvement, but it's still not fully robust. It doesn't account for all elements that can be visible on the left and right sides of the footer, which can lead to incorrect centering. For example, if hideCWD, hideModelInfo, and hideContextPercentage are all true, but quotaStats is visible on the right, justifyContent will incorrectly be set to 'center'.

To make this more reliable, I suggest refactoring to define all visibility flags first, then use them to determine the layout. This makes the logic clearer and bug-free.

  const displayVimMode = vimEnabled ? vimMode : undefined;
  const showDebugProfiler = debugMode || isDevelopment;

  const showLeftSection = showDebugProfiler || !!displayVimMode || !hideCWD;
  const showRightSection =
    !hideModelInfo ||
    !hideContextPercentage ||
    !!quotaStats ||
    showMemoryUsage ||
    corgiMode ||
    showErrorSummary;

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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the logic to use the suggested showLeftSection and showRightSection flags. This ensures the layout correctly handles secondary elements like showMemoryUsage and quotaStats even when the primary model info is hidden.

I verified this locally with the following configuration:

"ui": {
    "showMemoryUsage": true,
    "footer": {
      "hideCWD": true,
      "hideModelInfo": true,
      "hideContextPercentage": true
    }
  }

Even when hiding all primary footer elements, the Memory Usage now correctly stays right-aligned while the Sandbox Status remains centered.

image

Expand Down Expand Up @@ -140,15 +143,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 +171,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