fix(ui): stop Request Logs page from overflowing horizontally and size its columns - #31426
Conversation
…rflowing Tremor's Table forwards className to a wrapper div rather than the inner table element, so the table-fixed class never reached the table and it stayed table-layout: auto. Across 16 whitespace-nowrap columns that expanded the table far past the viewport Give each spend-logs column an explicit pixel size and drive the table width from getCenterTotalSize(), matching the Virtual Keys table. The shared DataTable applies this only when columns declare sizes, so the other consumers keep their existing fluid layout
… into litellm_/cranky-hamilton-21b5d0
Greptile SummaryFixes horizontal overflow in the Request Logs table by giving each of the 16 spend-log columns an explicit pixel
Confidence Score: 4/5Safe to merge; this is a UI-only layout change with no backend impact and good test coverage of both layout paths. The fix is well-scoped and backward-compatible. The
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/components/view_logs/columns.tsx | Adds explicit pixel size to all 16 spend-log columns, enabling the new fixed-width layout path in DataTable. |
| ui/litellm-dashboard/src/components/view_logs/table.tsx | Introduces hasExplicitColumnSizes gate to drive pixel-width layout (table width, per-column th/td widths) when columns declare sizes; backward-compatible path preserved for unsized consumers. Minor concern: some() means one column with a size triggers the entire sized layout for all columns, silently assigning 150 px to unsized peers. |
| ui/litellm-dashboard/src/components/view_logs/table.test.tsx | New test file covering both layout paths; verifies pixel widths propagate to table, headers, and cells when sized, and that unsized columns keep the fluid layout. Coverage is solid for the happy paths. |
Reviews (1): Last reviewed commit: "Merge branch 'litellm_internal_staging' ..." | Re-trigger Greptile
| enableSorting = false, | ||
| }: DataTableProps<TData, TValue>) { | ||
| const supportsExpansion = !!(renderSubComponent || renderChildRows) && !!getRowCanExpand; | ||
| const hasExplicitColumnSizes = columns.some((column) => column.size !== undefined); |
There was a problem hiding this comment.
some() means the sized layout is activated as soon as even one column carries a size, silently assigning react-table's default 150 px to every peer that doesn't declare one. A future caller that adds a single size to a DataTable column will unknowingly trigger the fixed layout across the whole table. Using every() makes the activation intent explicit and avoids this footgun.
| const hasExplicitColumnSizes = columns.some((column) => column.size !== undefined); | |
| const hasExplicitColumnSizes = columns.every((column) => column.size !== undefined); |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
… of overflowing The Request Logs page pushed the whole page past the viewport horizontally. The cause was the app shell flex layout: <main className="flex-1"> is a flex item, and flex items default to min-width: auto, so they refuse to shrink below their content's intrinsic width. The logs table is intrinsically ~2300px across its 16 nowrap columns, so main grew to that width and dragged the page with it; the table's own overflow-x-auto wrapper never got the chance to scroll Add min-w-0 to main so it can shrink to the available width, at which point the existing overflow-x-auto wrapper engages and the table scrolls inside its card. This applies to every dashboard page, not just logs Also drop the dead max-w-screen class on the logs container (not a real Tailwind utility, so it was a no-op), and revert the earlier column-sizing attempt which targeted table-layout rather than the actual containment problem
…ense ones Now that the page-overflow bug is fixed by letting the main pane shrink, bring back per-column sizing purely to control widths. Columns declare explicit pixel sizes and the table derives its min-width from getCenterTotalSize(), so it stretches to fill a wide card but scrolls once the columns no longer fit. The shared DataTable applies this only when columns declare sizes, leaving the other consumers on their existing fluid layout Trim the columns that were eating horizontal space without earning it: Request ID and Key Hash drop ~30% (Key Hash now narrower than Key Alias, which is the more useful of the two), and Duration and TTFT shrink to fit their short numeric values
The explicit 90px/80px sizes were too narrow for the Duration (s) and TTFT (s) headers once the sort arrows were factored in, cramping the header labels. Dropping the size lets these two columns fall back to the default width like before
Drop the explicit size on Request ID so it falls back to the default width like the other reverted columns. Narrow Session ID from 160px to 120px since its truncated value needs less room
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
This is a UI layout change, so the proof is visual. Against a running proxy with the dashboard (screenshots to follow):
python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml --detailed_debug --reloadType
🐛 Bug Fix
Changes
The Request Logs page pushed the whole page past the viewport horizontally. The cause was the app shell flex layout, not the table itself.
<main className="flex-1">is a flex item, and flex items default tomin-width: auto, which means they refuse to shrink below their content's intrinsic width. The logs table is intrinsically about 2300px across its sixteenwhitespace-nowrapcolumns, somaingrew to that width and dragged the page with it. The table's ownoverflow-x-autowrapper never got the chance to scroll because its ancestor simply expanded insteadAdding
min-w-0tomainlets it shrink to the available width, at which point the existingoverflow-x-autowrapper engages and the table scrolls inside its card. This is the canonical fix for a flex child that won't shrink, and it applies to every dashboard page rather than just logs. Also dropping themax-w-screenclass on the logs container; it is not a real Tailwind utility (the scale ismax-w-screen-smand friends), so it was a silent no-op that read like an intended viewport capOn top of the overflow fix, the spend-logs columns now declare explicit pixel widths so the table is legible rather than letting auto-layout distribute space arbitrarily. The shared
DataTablederives the table'smin-widthfrom react-table'sgetCenterTotalSize(), so it stretches to fill a wide card but scrolls once the columns no longer fit, and it applies per-column widths to each header and body cell. This sizing only kicks in when columns actually declare asize; the otherDataTableconsumers (pass-through settings, MCP toolsets, Usage Top Keys / Top Models) declare none and keep their existing fluid layout untouched. With the widths in place, Request ID and Key Hash are trimmed by about 30% (Key Hash now narrower than the more useful Key Alias) and Duration and TTFT shrink to fit their short numeric valuesview_logs/table.test.tsxpins the sizing contract: when columns declare sizes the table takes amin-widthequal to their total and every header / body cell takes its column width, and when they do not the cells stay unsized and the table keeps its fluid layout. The min-width assertion was mutation-checked by switching it back to a hardwidthand confirming the test fails