From bd91ab73cc8ae12012fed633537a18db8fef1dc0 Mon Sep 17 00:00:00 2001 From: Waleed Date: Tue, 11 Aug 2026 13:06:44 -0700 Subject: [PATCH] fix(files): restore horizontal scroll in CSV and XLSX preview tables (#6550) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(files): restore horizontal scroll in CSV and XLSX preview tables #6125 moved the preview tables onto the markdown table chrome and gave both surfaces `width: 100%`. That is right for prose and wrong for data: a CSV with dozens of columns divides the frame between them, and since the same change added `overflow-wrap: anywhere`, every column was free to break down to a single character — so headers rendered as vertical columns of letters and the table never exceeded its frame, leaving `overflow-x-auto` with nothing to scroll. Split sizing out of the shared rule. Prose tables keep `width: 100%`; preview tables size to their content and scroll, with column bounds so no column collapses to a sliver and one long value wraps instead of pushing the rest off-screen. Chrome (borders, padding, typography, header fill) stays shared. * fix(files): scroll preview tables from one container, not two nested ones DataTable owned `overflow-x-auto` while its caller owns the vertical scroll, so now that preview tables are actually wider than the frame the horizontal scrollbar rendered at the foot of the table rather than at the bottom of the viewport — up to 1,000 rows below it for the two callers whose container is a plain block (xlsx-preview, preview-panel). csv-table-preview escaped it only because its flex column compressed the wrapper to the frame height. Drop the inner overflow so the caller's bounded container scrolls both axes. All three callers now place the scrollbar at the viewport bottom. * fix(files): correct a stale reference to the removed inner overflow The sizing comment still credited `.document-table`'s own `overflow-x-auto` for the horizontal scroll, which the previous commit removed in favour of the caller's container. --- .../components/file-viewer/data-table.tsx | 6 +++- .../components/file-viewer/document-table.css | 31 +++++++++++++++++-- .../file-viewer/document-table.test.ts | 22 +++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/data-table.tsx b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/data-table.tsx index 2ba7a2e313..a8471c89d3 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/data-table.tsx +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/data-table.tsx @@ -25,6 +25,10 @@ type EditingCell = { row: number; col: number } | null * Tabular renderer for CSV and XLSX previews. Chrome (borders, padding, typography, header fill) * comes entirely from `document-table.css`, the definition shared with markdown tables in the rich * markdown editor — the only classes here are the optional edit affordances. + * + * Scrolling belongs to the caller's bounded container, which already scrolls vertically. A preview + * table is wider than its frame, so an `overflow-x` of its own would put the horizontal scrollbar + * at the foot of all {@link CSV_PREVIEW_MAX_ROWS} rows instead of at the bottom of the viewport. */ const DataTableBase = forwardRef(function DataTable( { headers, rows, editConfig }, @@ -100,7 +104,7 @@ const DataTableBase = forwardRef(function DataT editingCell?.row === row && editingCell?.col === col return ( -
+
diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.css b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.css index d883230503..43e6809375 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.css +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.css @@ -2,8 +2,10 @@ * Canonical table chrome for the file viewer. Both surfaces that render a table for a file — the * rich markdown editor (`.rich-markdown-prose table`) and the tabular previews CSV/XLSX render * through `DataTable` (`.document-table`) — share this one definition so a table looks the same - * whichever file it came from. Editor-only concerns (prose block margin, fixed layout for column - * resizing, cell paragraph reset) stay in rich-markdown-editor.css. + * whichever file it came from. Chrome is shared; *sizing* is not — prose fits the document width + * while a preview sizes to its data and scrolls (see the two rules below). Editor-only concerns + * (prose block margin, fixed layout for column resizing, cell paragraph reset) stay in + * rich-markdown-editor.css. */ /* `overflow-wrap` matches what `.rich-markdown-prose` sets on its own root: cells hold arbitrary @@ -15,11 +17,34 @@ .rich-markdown-prose table, .document-table table { - width: 100%; border-collapse: collapse; overflow: hidden; } +.rich-markdown-prose table { + width: 100%; +} + +/* A preview table is data, not prose. A CSV can carry dozens of columns, so sizing the table to the + frame (`width: 100%`) divides that frame between them and — with `overflow-wrap: anywhere` able to + break every column down to one character — renders each header a vertical column of letters. + `max-content` sizes columns to their values and lets the table exceed the frame, which the + caller's own scroll container then scrolls; `min-width: 100%` keeps a narrow table filling the + frame rather than hugging the left edge. */ +.document-table table { + width: max-content; + min-width: 100%; +} + +/* Bounds for a content-sized column: no column collapses to a sliver, and one long value (a URL, a + pasted paragraph) wraps at `max-width` instead of pushing every other column off-screen. 80px is + the tables grid's own `COL_WIDTH_MIN`; 320px is the capped content width used across the app. */ +.document-table th, +.document-table td { + min-width: 80px; + max-width: 320px; +} + .rich-markdown-prose th, .rich-markdown-prose td, .document-table th, diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.test.ts b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.test.ts index 0fb8336c70..fda1bbb36d 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.test.ts +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/document-table.test.ts @@ -115,6 +115,28 @@ describe('document-table chrome is shared with markdown tables', () => { expect(getComputedStyle(preview.root).getPropertyValue('overflow-wrap')).toBe(wrap) }) + it('the preview table sizes to its content while the prose table fits the frame', () => { + const prose = mountTable('rich-markdown-prose') + const preview = mountTable('document-table') + + const proseTable = prose.root.querySelector('table') + const previewTable = preview.root.querySelector('table') + if (!proseTable || !previewTable) throw new Error('tables not found') + + expect(getComputedStyle(proseTable).getPropertyValue('width')).toBe('100%') + expect(getComputedStyle(previewTable).getPropertyValue('width')).toBe('max-content') + expect(getComputedStyle(previewTable).getPropertyValue('min-width')).toBe('100%') + }) + + it('a preview column is bounded so no value collapses or monopolises the row', () => { + const { th, td } = mountTable('document-table') + + for (const cell of [th, td]) { + expect(getComputedStyle(cell).getPropertyValue('min-width')).toBe('80px') + expect(getComputedStyle(cell).getPropertyValue('max-width')).toBe('320px') + } + }) + it('the resolved values are the markdown editor values, not jsdom defaults', () => { const { th, td } = mountTable('document-table')