From b2265cfde48bd625632ac068880facd8cb3960f9 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Wed, 28 Jan 2026 13:52:37 -0800 Subject: [PATCH] fix(ux): fixed off-by-some wrapping caused by fixed-width characters (#17816) --- .../cli/src/ui/utils/TableRenderer.test.tsx | 30 +++++++++++++++++++ packages/cli/src/ui/utils/TableRenderer.tsx | 21 ++++++++++--- .../__snapshots__/TableRenderer.test.tsx.snap | 12 ++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/ui/utils/TableRenderer.test.tsx b/packages/cli/src/ui/utils/TableRenderer.test.tsx index 9b65408994..dd807154d6 100644 --- a/packages/cli/src/ui/utils/TableRenderer.test.tsx +++ b/packages/cli/src/ui/utils/TableRenderer.test.tsx @@ -31,4 +31,34 @@ describe('TableRenderer', () => { expect(output).toContain('Row 3, Col 3'); expect(output).toMatchSnapshot(); }); + + it('renders a table with long headers and 4 columns correctly', () => { + const headers = [ + 'Very Long Column Header One', + 'Very Long Column Header Two', + 'Very Long Column Header Three', + 'Very Long Column Header Four', + ]; + const rows = [ + ['Data 1.1', 'Data 1.2', 'Data 1.3', 'Data 1.4'], + ['Data 2.1', 'Data 2.2', 'Data 2.3', 'Data 2.4'], + ['Data 3.1', 'Data 3.2', 'Data 3.3', 'Data 3.4'], + ]; + const terminalWidth = 80; + + const { lastFrame } = renderWithProviders( + , + ); + + const output = lastFrame(); + // Since terminalWidth is 80 and headers are long, they might be truncated. + // We just check for some of the content. + expect(output).toContain('Data 1.1'); + expect(output).toContain('Data 3.4'); + expect(output).toMatchSnapshot(); + }); }); diff --git a/packages/cli/src/ui/utils/TableRenderer.tsx b/packages/cli/src/ui/utils/TableRenderer.tsx index 28ea441604..c8ce4b6d16 100644 --- a/packages/cli/src/ui/utils/TableRenderer.tsx +++ b/packages/cli/src/ui/utils/TableRenderer.tsx @@ -34,11 +34,24 @@ export const TableRenderer: React.FC = ({ }); // Ensure table fits within terminal width - const totalWidth = columnWidths.reduce((sum, width) => sum + width + 1, 1); + // We calculate scale based on content width vs available width (terminal - borders) + // First, extract content widths by removing the 2-char padding. + const contentWidths = columnWidths.map((width) => Math.max(0, width - 2)); + const totalContentWidth = contentWidths.reduce( + (sum, width) => sum + width, + 0, + ); + + // Fixed overhead includes padding (2 per column) and separators (1 per column + 1 final). + const fixedOverhead = headers.length * 2 + (headers.length + 1); + + // Subtract 1 from available width to avoid edge-case wrapping on some terminals + const availableWidth = Math.max(0, terminalWidth - fixedOverhead - 1); + const scaleFactor = - totalWidth > terminalWidth ? terminalWidth / totalWidth : 1; - const adjustedWidths = columnWidths.map((width) => - Math.floor(width * scaleFactor), + totalContentWidth > availableWidth ? availableWidth / totalContentWidth : 1; + const adjustedWidths = contentWidths.map( + (width) => Math.floor(width * scaleFactor) + 2, ); // Helper function to render a cell with proper width diff --git a/packages/cli/src/ui/utils/__snapshots__/TableRenderer.test.tsx.snap b/packages/cli/src/ui/utils/__snapshots__/TableRenderer.test.tsx.snap index 2ee7bc724b..4fd317365b 100644 --- a/packages/cli/src/ui/utils/__snapshots__/TableRenderer.test.tsx.snap +++ b/packages/cli/src/ui/utils/__snapshots__/TableRenderer.test.tsx.snap @@ -54,6 +54,18 @@ exports[`TableRenderer > renders a simple table correctly 1`] = ` " `; +exports[`TableRenderer > renders a table with long headers and 4 columns correctly 1`] = ` +" +┌──────────────────┬──────────────────┬───────────────────┬──────────────────┐ +│ Very Long Col... │ Very Long Col... │ Very Long Colu... │ Very Long Col... │ +├──────────────────┼──────────────────┼───────────────────┼──────────────────┤ +│ Data 1.1 │ Data 1.2 │ Data 1.3 │ Data 1.4 │ +│ Data 2.1 │ Data 2.2 │ Data 2.3 │ Data 2.4 │ +│ Data 3.1 │ Data 3.2 │ Data 3.3 │ Data 3.4 │ +└──────────────────┴──────────────────┴───────────────────┴──────────────────┘ +" +`; + exports[`TableRenderer > truncates content when terminal width is small 1`] = ` " ┌────────┬─────────┬─────────┐