fix: Restore footer configuration settings (#8041) (#8053)

Co-authored-by: Miguel Solorio <miguelsolorio@google.com>
Co-authored-by: Miguel Solorio <miguel.solorio07@gmail.com>
This commit is contained in:
Keith Lyons
2025-09-11 20:16:09 -04:00
committed by GitHub
parent 68035591da
commit 0d460bbf77
4 changed files with 180 additions and 81 deletions

View File

@@ -54,6 +54,9 @@ export const Composer = () => {
promptTokenCount: uiState.sessionStats.lastPromptTokenCount,
nightly: uiState.nightly,
isTrustedFolder: uiState.isTrustedFolder,
hideCWD: settings.merged.ui?.footer?.hideCWD || false,
hideSandboxStatus: settings.merged.ui?.footer?.hideSandboxStatus || false,
hideModelInfo: settings.merged.ui?.footer?.hideModelInfo || false,
};
return (
@@ -107,12 +110,16 @@ export const Composer = () => {
<Box
marginTop={1}
justifyContent="space-between"
justifyContent={
settings.merged.ui?.hideContextSummary
? 'flex-start'
: 'space-between'
}
width="100%"
flexDirection={isNarrow ? 'column' : 'row'}
alignItems={isNarrow ? 'flex-start' : 'center'}
>
<Box>
<Box marginRight={1}>
{process.env['GEMINI_SYSTEM_MD'] && (
<Text color={theme.status.error}>|_| </Text>
)}

View File

@@ -156,4 +156,56 @@ describe('<Footer />', () => {
vi.unstubAllEnvs();
});
});
describe('footer configuration filtering (golden snapshots)', () => {
it('renders complete footer with all sections visible (baseline)', () => {
const { lastFrame } = renderWithWidth(120, {
...defaultProps,
hideCWD: false,
hideSandboxStatus: false,
hideModelInfo: false,
});
expect(lastFrame()).toMatchSnapshot('complete-footer-wide');
});
it('renders footer with all optional sections hidden (minimal footer)', () => {
const { lastFrame } = renderWithWidth(120, {
...defaultProps,
hideCWD: true,
hideSandboxStatus: true,
hideModelInfo: true,
});
expect(lastFrame()).toMatchSnapshot('footer-minimal');
});
it('renders footer with only model info hidden (partial filtering)', () => {
const { lastFrame } = renderWithWidth(120, {
...defaultProps,
hideCWD: false,
hideSandboxStatus: false,
hideModelInfo: true,
});
expect(lastFrame()).toMatchSnapshot('footer-no-model');
});
it('renders footer with CWD and model info hidden to test alignment (only sandbox visible)', () => {
const { lastFrame } = renderWithWidth(120, {
...defaultProps,
hideCWD: true,
hideSandboxStatus: false,
hideModelInfo: true,
});
expect(lastFrame()).toMatchSnapshot('footer-only-sandbox');
});
it('renders complete footer in narrow terminal (baseline narrow)', () => {
const { lastFrame } = renderWithWidth(79, {
...defaultProps,
hideCWD: false,
hideSandboxStatus: false,
hideModelInfo: false,
});
expect(lastFrame()).toMatchSnapshot('complete-footer-narrow');
});
});
});

View File

@@ -33,6 +33,9 @@ export interface FooterProps {
nightly: boolean;
vimMode?: string;
isTrustedFolder?: boolean;
hideCWD?: boolean;
hideSandboxStatus?: boolean;
hideModelInfo?: boolean;
}
export const Footer: React.FC<FooterProps> = ({
@@ -49,6 +52,9 @@ export const Footer: React.FC<FooterProps> = ({
nightly,
vimMode,
isTrustedFolder,
hideCWD = false,
hideSandboxStatus = false,
hideModelInfo = false,
}) => {
const { columns: terminalWidth } = useTerminalSize();
@@ -60,100 +66,114 @@ export const Footer: React.FC<FooterProps> = ({
? path.basename(tildeifyPath(targetDir))
: shortenPath(tildeifyPath(targetDir), pathLength);
const justifyContent = hideCWD && hideModelInfo ? 'center' : 'space-between';
return (
<Box
justifyContent="space-between"
justifyContent={justifyContent}
width="100%"
flexDirection={isNarrow ? 'column' : 'row'}
alignItems={isNarrow ? 'flex-start' : 'center'}
>
<Box>
{debugMode && <DebugProfiler />}
{vimMode && <Text color={theme.text.secondary}>[{vimMode}] </Text>}
{nightly ? (
<Gradient colors={theme.ui.gradient}>
<Text>
{displayPath}
{branchName && <Text> ({branchName}*)</Text>}
{(debugMode || vimMode || !hideCWD) && (
<Box>
{debugMode && <DebugProfiler />}
{vimMode && <Text color={theme.text.secondary}>[{vimMode}] </Text>}
{!hideCWD &&
(nightly ? (
<Gradient colors={theme.ui.gradient}>
<Text>
{displayPath}
{branchName && <Text> ({branchName}*)</Text>}
</Text>
</Gradient>
) : (
<Text color={theme.text.link}>
{displayPath}
{branchName && (
<Text color={theme.text.secondary}> ({branchName}*)</Text>
)}
</Text>
))}
{debugMode && (
<Text color={theme.status.error}>
{' ' + (debugMessage || '--debug')}
</Text>
</Gradient>
) : (
<Text color={theme.text.link}>
{displayPath}
{branchName && (
<Text color={theme.text.secondary}> ({branchName}*)</Text>
)}
</Text>
)}
{debugMode && (
<Text color={theme.status.error}>
{' ' + (debugMessage || '--debug')}
</Text>
)}
</Box>
)}
</Box>
)}
{/* Middle Section: Centered Trust/Sandbox Info */}
<Box
flexGrow={isNarrow ? 0 : 1}
alignItems="center"
justifyContent={isNarrow ? 'flex-start' : 'center'}
display="flex"
paddingX={isNarrow ? 0 : 1}
paddingTop={isNarrow ? 1 : 0}
>
{isTrustedFolder === false ? (
<Text color={theme.status.warning}>untrusted</Text>
) : process.env['SANDBOX'] &&
process.env['SANDBOX'] !== 'sandbox-exec' ? (
<Text color="green">
{process.env['SANDBOX'].replace(/^gemini-(?:cli-)?/, '')}
</Text>
) : process.env['SANDBOX'] === 'sandbox-exec' ? (
<Text color={theme.status.warning}>
macOS Seatbelt{' '}
<Text color={theme.text.secondary}>
({process.env['SEATBELT_PROFILE']})
{!hideSandboxStatus && (
<Box
flexGrow={isNarrow || hideCWD || hideModelInfo ? 0 : 1}
alignItems="center"
justifyContent={isNarrow || hideCWD ? 'flex-start' : 'center'}
display="flex"
paddingX={isNarrow ? 0 : 1}
paddingTop={isNarrow ? 1 : 0}
>
{isTrustedFolder === false ? (
<Text color={theme.status.warning}>untrusted</Text>
) : process.env['SANDBOX'] &&
process.env['SANDBOX'] !== 'sandbox-exec' ? (
<Text color="green">
{process.env['SANDBOX'].replace(/^gemini-(?:cli-)?/, '')}
</Text>
</Text>
) : (
<Text color={theme.status.error}>
no sandbox <Text color={theme.text.secondary}>(see /docs)</Text>
</Text>
)}
</Box>
) : process.env['SANDBOX'] === 'sandbox-exec' ? (
<Text color={theme.status.warning}>
macOS Seatbelt{' '}
<Text color={theme.text.secondary}>
({process.env['SEATBELT_PROFILE']})
</Text>
</Text>
) : (
<Text color={theme.status.error}>
no sandbox <Text color={theme.text.secondary}>(see /docs)</Text>
</Text>
)}
</Box>
)}
{/* Right Section: Gemini Label and Console Summary */}
<Box alignItems="center" paddingTop={isNarrow ? 1 : 0}>
<Box alignItems="center">
<Text color={theme.text.accent}>
{isNarrow ? '' : ' '}
{model}{' '}
<ContextUsageDisplay
promptTokenCount={promptTokenCount}
model={model}
/>
</Text>
{showMemoryUsage && <MemoryUsageDisplay />}
</Box>
<Box alignItems="center" paddingLeft={2}>
{corgiMode && (
<Text>
<Text color={theme.ui.comment}>| </Text>
<Text color={theme.status.error}></Text>
<Text color={theme.text.primary}>(´</Text>
<Text color={theme.status.error}></Text>
<Text color={theme.text.primary}>`)</Text>
<Text color={theme.status.error}>▼ </Text>
</Text>
)}
{!showErrorDetails && errorCount > 0 && (
<Box>
<Text color={theme.ui.comment}>| </Text>
<ConsoleSummaryDisplay errorCount={errorCount} />
{(!hideModelInfo ||
showMemoryUsage ||
corgiMode ||
(!showErrorDetails && errorCount > 0)) && (
<Box alignItems="center" paddingTop={isNarrow ? 1 : 0}>
{!hideModelInfo && (
<Box alignItems="center">
<Text color={theme.text.accent}>
{isNarrow ? '' : ' '}
{model}{' '}
<ContextUsageDisplay
promptTokenCount={promptTokenCount}
model={model}
/>
</Text>
{showMemoryUsage && <MemoryUsageDisplay />}
</Box>
)}
<Box alignItems="center" paddingLeft={2}>
{corgiMode && (
<Text>
{!hideModelInfo && <Text color={theme.ui.comment}>| </Text>}
<Text color={theme.status.error}></Text>
<Text color={theme.text.primary}>(´</Text>
<Text color={theme.status.error}></Text>
<Text color={theme.text.primary}>`)</Text>
<Text color={theme.status.error}>▼ </Text>
</Text>
)}
{!showErrorDetails && errorCount > 0 && (
<Box>
{!hideModelInfo && <Text color={theme.ui.comment}>| </Text>}
<ConsoleSummaryDisplay errorCount={errorCount} />
</Box>
)}
</Box>
</Box>
</Box>
)}
</Box>
);
};

View File

@@ -0,0 +1,20 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer in narrow terminal (baseline narrow) > complete-footer-narrow 1`] = `
"long (main*)
no sandbox (see /docs)
gemini-pro (100% context left)"
`;
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer with all sections visible (baseline) > complete-footer-wide 1`] = `
"...bar/and/some/more/directories/to/make/it/long no sandbox (see gemini-pro (100% context
(main*) /docs) left)"
`;
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with CWD and model info hidden to test alignment (only sandbox visible) > footer-only-sandbox 1`] = `" no sandbox (see /docs)"`;
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with all optional sections hidden (minimal footer) > footer-minimal 1`] = `""`;
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with only model info hidden (partial filtering) > footer-no-model 1`] = `"...bar/and/some/more/directories/to/make/it/long (main*) no sandbox (see /docs)"`;