Skip to content

fix(listview): shared min/max column-width model for CRUD list views - #45824

Open
sadpandajoe wants to merge 12 commits into
masterfrom
fix-crud-list-view-column-sizing
Open

sadpandajoe wants to merge 12 commits into
masterfrom
fix-crud-list-view-column-sizing

Conversation

@sadpandajoe

@sadpandajoe sadpandajoe commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

SUMMARY

The CRUD list tables (Datasets, Dashboards, Charts, Databases, Saved queries, Tags, ...) rendered with an auto table layout where only the Name column was pinned to a width (#37299). Any column without a size hint absorbed all spare container width, so Name looked squashed next to a huge, mostly-empty Actions column (Datasets, Dashboards) and an over-wide Type column (Charts); the same bug existed on other lists (Databases and Tags Actions were 1000px+ wide at 1920px).

The table stack cannot express a min/max column range natively (react-table's width/minWidth/maxWidth are only read by its layout plugins, which ListView does not use; antd/rc-table has minWidth in auto layout only and no maxWidth). This adds a small shared layer in TableCollection that every ListView-based page inherits:

  • TableCollection/columnWidths.ts: one COLUMN_LAYOUT_PRESETS table plus a pure resolveColumnWidths(specs, containerWidth). Columns start at their minimum; spare width is shared by weight between the flexible columns, each capped at its maximum (if every flexible column is capped the remainder is still shared, so the table always fills its container); fixed columns never change.
  • Typed widths sized from measured content, including German: fixed icon 48, statusIcon 48, statusIcons 144, status 144, flag 176, count 104, timer 136, people 120, iconList 120, dateRelative 176, dateTwoLine 136, timestamp 240, actions 120 and actionsWide 168 (5-6 icons). Flexible: title 320-640 (the one primary column per list), text 140-280, identifier 180-360, longtext 200-560, tags 200-320.
  • When the sum of the minimums exceeds the container the table scrolls inside its container at the minimums, and the leading block (bulk-select checkbox, favorite star, title) is frozen (fixed: 'left'), but only if that block is at most 50% of the container and at least 240px remain scrollable. Focus is kept visible: scroll padding is applied only during the table's own scrollIntoView on focus, for body cells and sortable header cells, so a focused cell is never hidden under the frozen block.
  • ListViewColumn.layout takes a preset name or an explicit { fixed } / { min, max?, weight? }; legacy size still works as a deprecated fixed width. TableCollection measures its container and passes explicit pixel widths with tableLayout="fixed". This is opt-in via managedColumnWidths; only ListView enables it, so TableView, AlteredSliceTag and other tables are unchanged.
  • All ListView pages and the extensions list use the presets (layout-only changes to column configs; a guard test fails on legacy size hints, unknown presets, custom page layouts, or a page without exactly one title column).
  • Renderer fixes found while auditing every column type: the "Tables" cell keeps its "(+N)" visible while the first name ellipsizes (Query history, Saved queries); the Tags-list title pill and the Charts "Matrixified" tag get a max width with ellipsis; Saved queries tag chips are limited to 3 like Dashboards/Charts; the Task title no longer double-ellipsizes.

The numbers are a starting point that live in one table; they came from a benchmark of the options (public design systems and grid libraries, public name-length and viewport data, and a standalone antd harness that reproduces these widths), not from customer data.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

These screenshots were captured at earlier iterations of this change (the first sizing model and the shared title cell). Updated captures for the final typed widths and the frozen leading block are being added.

Datasets list at 1920px (same data, viewport and state; before = unmodified base):

Before

before

After

after

Measured on a live build (headless Chrome, normal / extreme-content / +40% text, 2560 to 768px): at 1920px Datasets Actions went from 916px to 120px and Name from 360px to ~590px; Dashboards Actions 447px -> 120px; Charts Type 555px -> bounded. Fixed columns have identical widths at every viewport, no action icon is clipped, and no page-level horizontal scroll appeared. Datasets, Dashboards and Charts do not scroll at 1440px or wider. Before/after pairs for Datasets, Dashboards and Charts at 1920/1440/1024, extreme-content pairs, hover states and the raw numbers are in the same Gist.

Known trade-offs: pages with few columns still give most of a very wide viewport to the title (fixed columns never grow and the table fills its container); Query history (11 columns) and Saved queries with Tags scroll inside the table at 1440px, where the old layout squeezed columns until values were cut off.

Shared title cell

Name cells that put the link in a flex row (Datasets, Dashboards, Charts, Themes) each carried a hand-copied FlexRowContainer. Only the Dashboard and Chart copies had the rule that lets the link shrink and truncate, so Datasets (and Themes, whose tags were pushed out of the cell at 1440px and below) hard-clipped long names with no ellipsis. A new ListViewTitleCell owns that behaviour once (badges before the title and tooltips/tags after it keep their size; the title truncates on one line with the full name in the tooltip), and the four per-page wrappers are deleted (-26 CSS declarations, +12 shared). The shared table styles are unchanged, and the other lists already truncate through the table cell.

Before (Datasets, 120-character name, 1440px)

before

After

after

TESTING INSTRUCTIONS

  1. Open Datasets, Dashboards, Charts and a few other CRUD lists (Databases, Saved queries, Tags) at 2560/1920/1440/1280px wide.
  2. Confirm Name/title is wide but capped, Actions is a narrow fixed column, status/people/count columns keep the same width at every viewport, and nothing collapses; narrow the window (e.g. Charts with Tags on at 1280px) and confirm the table scrolls inside its container rather than the page and that the checkbox/star/title block stays frozen; with keyboard Tab/Shift+Tab through the headers and cells confirm the focused cell is never hidden under the frozen block; below roughly 1024px (frozen block > 50% of the width) nothing freezes.
  3. Try long titles, long connection/schema names, many owners/tags and hover a row to confirm Actions icons are never clipped.
  4. Automated: npm test -- TableCollection ListView DatasetList DashboardList ChartList (resolver unit tests, managed-mode TableCollection tests, a guard test, freeze-guard and focus tests, renderer regression tests, and per-page tests asserting every visible column resolves within its preset bounds). jsdom cannot measure real layout, so the visual behaviour (widths, freezing, focus) was verified in headless Chrome on a live build and in a standalone harness; screenshots to follow.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

The Datasets, Dashboards and Charts list tables pin the Name column to a
fixed size but left other columns unsized. With auto table layout, spare
container width goes to unsized columns, so Dataset and Dashboard Actions
(and Dashboard Last modified, Chart Type) stretched to hundreds of pixels
while Name stayed squashed.

Give every visible column an explicit size so spare width is distributed
proportionally across all of them, keep Name as the widest column, bound the
Chart Type column, and use a consistent Actions size across the three pages.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Oct 28, 2026

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 7abfe9f
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6ae23e496d85eb412f3c3446
😎 Deploy Preview https://deploy-preview-45824--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov

codecov Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.43750% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.69%. Comparing base (ece8991) to head (efc277f).
⚠️ Report is 75 commits behind head on master.

Files with missing lines Patch % Lines
...t-ui-core/src/components/TableCollection/index.tsx 96.55% 2 Missing ⚠️
...t-ui-core/src/components/TableCollection/utils.tsx 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #45824      +/-   ##
==========================================
+ Coverage   84.61%   84.69%   +0.08%     
==========================================
  Files        3069     3071       +2     
  Lines      205513   205636     +123     
  Branches    48300    48345      +45     
==========================================
+ Hits       173893   174171     +278     
+ Misses      28320    28165     -155     
  Partials     3300     3300              
Flag Coverage Δ
javascript 80.97% <98.43%> (+0.19%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

mistercrunch and others added 2 commits October 28, 2026 19:57
List view tables sized columns from per-page `size` hints under an auto
table layout, so whichever columns were left unsized absorbed all spare
width (huge Actions/Type columns, squashed Name) and every page had to be
tuned by hand.

Give every ListView column a `layout`: a preset from a single
COLUMN_LAYOUT_PRESETS table (fixed widths for icons, status badges,
counts, avatar groups and actions; min/max/weight ranges for titles,
text, long text, tags and dates) or an explicit fixed / min-max object.
TableCollection resolves the widths from the measured container width
(water-filling spare width by weight, capping each flexible column at its
max until all are capped) and renders them with a fixed table layout,
scrolling horizontally only when the minimums don't fit. The legacy
`size` token keeps working as a fixed width and is deprecated.

Only ListView opts in (`managedColumnWidths`); other TableCollection /
TableView callers keep the browser's auto layout. Every list page is
migrated to presets, and a guard test keeps legacy `size` tokens out of
list pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Status badges render as antd tags with an inline margin, so the dataset
"Physical"/"Virtual" type and dashboard "Published"/"Draft" badges need
128px including cell padding; at 112px they overflowed and showed an
ellipsis next to the badge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mistercrunch mistercrunch changed the title fix(listview): size every column in dataset, dashboard and chart lists fix(listview): shared min/max column-width model for CRUD list views Oct 28, 2026
The Name cell of the Datasets and Themes lists hard-clipped long titles
without an ellipsis and could push the adornments beside them (badges,
description tooltip, status tags) out of the cell. Each list view carried
its own copy of a flex-row wrapper, and only the Dashboard and Chart
copies remembered to make the title link shrinkable; inside a flex row the
table cell's own text-overflow does not apply.

Add ListViewTitleCell, which owns the flex row, the single-line ellipsis
on the title and the non-shrinking adornments once, and use it in the
Dataset, Dashboard, Chart and Theme lists in place of the per-page
wrappers. Title columns that render bare text or inline links already
ellipsize through the shared table cell styles and are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kasiazjc and others added 2 commits October 30, 2026 17:18
… block when a list scrolls

Rework the shared list view preset table from measured content, English
and German included:

- typed fixed presets: icon/statusIcon 48, statusIcons 64, status 144,
  flag 176 (boolean columns; longer headers ellipsize with the full text
  in the header title), count 104, timer 136, people 120, iconList 120,
  dateRelative 176, dateTwoLine 136, timestamp 240, actions 120,
  actionsWide 168
- title is the one primary flexible column: min 320, max 640, weight 3
- flexible text 140-280, identifier 180-360 (database, schema, table
  and dataset names), longtext 200-560, tags 200-320
- statusWide and date are replaced by flag, iconList, dateRelative,
  dateTwoLine and timestamp

When the minimums do not fit, the table scrolls inside its container and
the leading block (selection checkbox, favorite star or state icon, and
the title) is frozen, but only while that block takes at most half of
the container and leaves at least 240px to scroll. The rule lives in
pure functions (getLeadingBlockLength, getFrozenColumnCount) with
exported tuning constants. Frozen tables set scroll-padding on the
scroll container and scroll a focused cell into view, so keyboard focus
never lands under the frozen columns.

Every list view page is migrated to the new presets; column ids,
accessors, renderers, hidden flags and sorting are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Query history and Saved queries "Tables": the first table name
  ellipsizes while the "(+N)" count stays visible.
- Tags list name pill and the Charts "Matrixified" pill get a max width
  and an ellipsis, so a pill is never cut mid-pill; the chart type name
  shrinks first.
- Saved queries tags show at most three chips, like Dashboards and
  Charts.
- Task names are no longer cut at 30 characters in JS on top of the
  cell's CSS ellipsis; the tooltip still carries the full name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sadpandajoe
sadpandajoe marked this pull request as ready for review October 30, 2026 19:24
… tables

The header ellipsis and the frozen-block scroll padding only make sense for
list views with managed column widths. Scope them to managed tables so
TableView and other auto-layout tables keep sizing columns to their
headers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
},
Header: t('Actions'),
id: 'actions',
layout: 'actions',

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.

Suggestion: On OAuth2 databases, a user with edit, export, token-management, and delete permissions sees five actions; the 120px preset clips the last control.

Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Css layout issue

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/pages/DatabaseList/index.tsx
**Line:** 1046:1046
**Comment:**
	*Css Layout Issue: On OAuth2 databases, a user with edit, export, token-management, and delete permissions sees five actions; the 120px preset clips the last control.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

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.

✅ CodeAnt verified this suggestion was addressed in subsequent commits and marked this thread resolved as of 34d8f0f.

The actions column now uses the actionsWide layout preset instead of the 120px preset.

If that's not right, unresolve this thread and CodeAnt will leave it open.

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.

✅ CodeAnt verified this suggestion was addressed in subsequent commits and marked this thread resolved as of 410786f.

The actions column now uses the actionsWide layout preset instead of the narrower preset.

If that's not right, unresolve this thread and CodeAnt will leave it open.

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.

✅ CodeAnt verified this suggestion was addressed in subsequent commits and marked this thread resolved as of 3d51961.

The actions column now uses the actionsWide layout instead of the 120px preset.

If that's not right, unresolve this thread and CodeAnt will leave it open.

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.

✅ CodeAnt verified this suggestion was addressed in subsequent commits and marked this thread resolved as of efc277f.

The Actions column now uses the actionsWide layout instead of the narrower preset.

If that's not right, unresolve this thread and CodeAnt will leave it open.

pagination={paginationConfig}
scroll={{ x: 'max-content' }}
tableLayout="auto"
scroll={{ x: columnLayout ? columnLayout.totalWidth : 'max-content' }}

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.

Suggestion: TableView does not enable managed widths, but this still sets scroll.x to 'max-content', forcing generic tables into horizontal scrolling and changing their auto-width behavior.

Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Api mismatch

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/packages/superset-ui-core/src/components/TableCollection/index.tsx
**Line:** 451:451
**Comment:**
	*Api Mismatch: `TableView` does not enable managed widths, but this still sets `scroll.x` to `'max-content'`, forcing generic tables into horizontal scrolling and changing their auto-width behavior.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not adopting this one. An unmanaged TableView deliberately keeps its pre-existing behavior (scroll.x: max-content with auto table layout); only list views that opt into managed column widths get the new fixed layout and frozen block. A TableView test pins that behavior, so generic tables are unchanged by this PR.

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.

✅ Customized review instruction saved!

Instruction:

Preserve the existing scroll.x: 'max-content' and auto table layout for unmanaged TableView instances; apply fixed layout and frozen blocks only to list views that opt into managed column widths.

Applied to:

  • superset-frontend/packages/superset-ui-core/src/components/TableCollection/index.tsx

💡 To manage or update this instruction, visit: CodeAnt AI Settings

sadpandajoe and others added 2 commits October 30, 2026 21:45
A database with OAuth2 enabled shows Edit, Export, Sync permissions,
Manage OAuth2 tokens and Delete. Five icons end flush with the 120px
actions cell, so the column uses the 168px actionsWide preset like the
other five- and six-icon lists. A TableView test pins that generic tables
keep the auto layout and content-width scroll.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unding

- Annotation start and end dates render as short dates, so they use the
  relative-date width instead of the full timestamp width.
- Focusing a cell inside the frozen leading block no longer scrolls the
  table back to the start.
- The rounding remainder goes to the heaviest flexible column that still
  has room below its max.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
accessor: 'payload',
Header: t('Details'),
size: 'sm',
layout: 'statusIcons',

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.

Suggestion: Rows with several task details, such as payload, dependency, and deduplication indicators, can exceed this fixed-width column and get clipped.

Assessment: 🟠 Major · 🔁 Occurrence: Sometimes · 🏷️ Logic error

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/pages/TaskList/index.tsx
**Line:** 567:567
**Comment:**
	*Logic Error: Rows with several task details, such as payload, dependency, and deduplication indicators, can exceed this fixed-width column and get clipped.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

* contiguous run of columns from the start and freezing those would hide
* more than the row's name.
*/
export function getLeadingBlockLength(layouts: ColumnLayout[]): number {

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.

Suggestion: This lookup recognizes only the 'title' string. A primary-name column using a supported custom min/max layout is not frozen and can scroll out of view.

Assessment: 🟠 Major · 🔁 Occurrence: Rarely · 🏷️ Api mismatch

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/packages/superset-ui-core/src/components/TableCollection/columnWidths.ts
**Line:** 271:271
**Comment:**
	*Api Mismatch: This lookup recognizes only the `'title'` string. A primary-name column using a supported custom min/max layout is not frozen and can scroll out of view.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not adopting this one. All 22 ListView consumers size their primary name column with the title preset, and none uses a custom {min,max}/{fixed} layout for it, so there is no consumer the current lookup misses. Instead of adding a freeze flag, the rule is now explicit: the getLeadingBlockLength doc comment states that only the title preset marks the frozen primary column, and the ListView.columnLayouts guard test fails if any list page introduces a custom layout object.

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.

✅ Customized review instruction saved!

Instruction:

Treat only the title preset as identifying the frozen primary-name column; do not flag custom {min,max} or {fixed} layouts as supported primary-name layouts.

Applied to:

  • superset-frontend/packages/superset-ui-core/src/components/TableCollection/columnWidths.ts

💡 To manage or update this instruction, visit: CodeAnt AI Settings

kasiazjc and others added 3 commits October 30, 2026 22:25
…back

A permanent scroll padding made the browser scroll to the start whenever a
frozen cell took focus. Apply the frozen width as scroll padding only while
a focused scrolling cell is brought into view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The task details cell can show up to four 16px indicator icons 8px apart,
the last with a reuse count. Measured in Chrome that row takes 118px
(+999), so the 64px statusIcons preset clipped anything past two icons.
Widen the preset to 144px and add a regression test on the measured need.

Also document that only the 'title' preset marks the frozen primary
column, and guard that no list view page sizes a column with a custom
layout object.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lumns

antd makes sortable header cells focusable, and list views have no sticky
header, so headers scroll with the body. Shift+Tab through the headers
with the leading block frozen scrolled each one under the frozen header
cells. The managed focus handler only handled body cells; it also handles
header cells, so a focused header gets the same frozen-width scroll
padding while frozen headers are left alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants