Skip to content

feat(ui): add TableV2 component as Untitled UI / React Aria migration wrapper#26716

Open
harsh-vador wants to merge 2 commits intomainfrom
tablev2-untitled-migration
Open

feat(ui): add TableV2 component as Untitled UI / React Aria migration wrapper#26716
harsh-vador wants to merge 2 commits intomainfrom
tablev2-untitled-migration

Conversation

@harsh-vador
Copy link
Contributor

Describe your changes:

Fixes 3271

Summary

Introduces TableV2 as a standalone migration wrapper that renders tables via @openmetadata/ui-core-components (React Aria + Untitled UI) instead of Ant Design — with zero consumer changes in this PR.

  • Adds TableV2.tsx, TableV2.interface.ts, and TableV2Utils.ts as new files alongside the existing Table.tsx
  • Preserves the exact TableComponentProps<T> interface so consumers can swap imports with no API changes
  • Extends Table.interface.ts with cellClassName, dragAndDropHooks, and data-testid props needed by the new renderer
  • Adds @untitledui/icons dependency and updates table.less with TableV2-specific drop-target styles

No existing component is migrated to use TableV2 in this PR — consumer migrations will follow in separate PRs.

What's supported

Feature Status
Column rendering (AntD → React Aria Table compound components) Done
Column customization dropdown (drag-to-reorder, show/hide, user preferences) Done
Search bar integration Done
Client-side & server-side pagination (NextPrevious) Done
Loading overlay Done
Row selection (single + multiple) Done
Client-side column sorting Done
Column filtering (filterDropdown / onFilter) Done
Empty state (locale.emptyText) Done
Tree/expandable rows (record.children, expand icons) Done
Resizable columns (React Aria ColumnResizer) Done
Sticky columns (col.fixed left/right) Done
Sticky header (scroll.y) Done
Ellipsis truncation Done
onRow (onClick, onDoubleClick, drag handlers) Done
onCell forwarding Done
data-row-key attribute for Playwright compatibility Done

Known limitations (v1)

  • expandable.expandedRowRender not supported (only tree-based children expansion)
  • components (AntD custom cell/header renderer overrides) accepted but ignored
  • showHeader={false} not implemented
  • rowSelection.getCheckboxProps ignored
  • onChange only fires for sort actions (not for pagination/filter side effects)

Files changed

File Change
TableV2.tsx New — core migration wrapper component
TableV2.interface.ts New — FlatRow<T>, AriaSelection, AriaSortDescriptor types
TableV2Utils.ts New — flattenTreeRows, resolveCellValue, resolveColumnTitle, getColumnStickyStyle
Table.interface.ts Extended with cellClassName, dragAndDropHooks, data-testid
table.less Added TableV2 drop-target styles
package.json / yarn.lock Added @untitledui/icons dependency
Screen.Recording.2026-03-10.at.5.26.33.PM.mov
Screen.Recording.2026-03-04.at.1.07.58.PM.mov

Type of change:

  • Bug fix
  • Improvement
  • New feature
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed.

@harsh-vador harsh-vador self-assigned this Mar 24, 2026
@harsh-vador harsh-vador requested a review from a team as a code owner March 24, 2026 07:28
@harsh-vador harsh-vador added UI UI specific issues safe to test Add this label to run secure Github workflows on PRs labels Mar 24, 2026
Comment on lines +126 to +138
export function getColumnStickyStyle(
fixed: ColumnType<unknown>['fixed'],
zIndex: number
): React.CSSProperties {
if (fixed === 'left') {
return { background: 'white', left: 0, position: 'sticky', zIndex };
}
if (fixed === 'right') {
return { background: 'white', position: 'sticky', right: 0, zIndex };
}

return {};
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Bug: getColumnStickyStyle assumes at most one fixed column per side

The getColumnStickyStyle utility always uses left: 0 for fixed='left' and right: 0 for fixed='right' (lines 130-134). The JSDoc comment acknowledges this limitation, but if a consumer passes multiple columns with fixed='left', they will all stack at left: 0 and overlap each other. Since this is a migration wrapper aiming for AntD API compatibility, and AntD correctly computes cumulative offsets for multiple fixed columns, this silent visual breakage could be surprising.

Suggested fix:

Consider computing cumulative offsets based on the widths of preceding fixed columns. For example, pass the column index and column definitions to compute the left/right offset dynamically:

export function getColumnStickyStyle(
  columns: ColumnType<unknown>[],
  colIndex: number,
  zIndex: number
): React.CSSProperties {
  const col = columns[colIndex];
  if (col.fixed === 'left') {
    const offset = columns.slice(0, colIndex)
      .filter(c => c.fixed === 'left')
      .reduce((sum, c) => sum + (Number(c.width) || 0), 0);
    return { background: 'white', left: offset, position: 'sticky', zIndex };
  }
  // similar for 'right' in reverse
}

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

@github-actions
Copy link
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 64%
64.85% (58080/89547) 44.5% (30712/69003) 47.64% (9196/19302)

@github-actions
Copy link
Contributor

github-actions bot commented Mar 24, 2026

🟡 Playwright Results — all passed (22 flaky)

✅ 3108 passed · ❌ 0 failed · 🟡 22 flaky · ⏭️ 207 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 449 0 6 2
🟡 Shard 2 543 0 3 33
🟡 Shard 3 543 0 3 27
🟡 Shard 4 533 0 5 45
🟡 Shard 5 510 0 1 67
🟡 Shard 6 530 0 4 33
🟡 22 flaky test(s) (passed on retry)
  • Features/DataAssetRulesDisabled.spec.ts › Verify the Pipeline entity item action after rules disabled (shard 1, 1 retry)
  • Features/CustomizeDetailPage.spec.ts › Search Index - customization should work (shard 1, 1 retry)
  • Flow/Metric.spec.ts › Verify Related Metrics Update (shard 1, 1 retry)
  • Flow/Tour.spec.ts › Tour should work from help section (shard 1, 1 retry)
  • Flow/Tour.spec.ts › Tour should work from URL directly (shard 1, 2 retries)
  • Pages/UserCreationWithPersona.spec.ts › Create user with persona and verify on profile (shard 1, 1 retry)
  • Features/DataQuality/TestCaseIncidentPermissions.spec.ts › User with TEST_CASE.EDIT_ALL can see edit icon on incidents (shard 2, 1 retry)
  • Features/DataQuality/TestCaseResultPermissions.spec.ts › User with only VIEW cannot PATCH results (shard 2, 1 retry)
  • Features/ImpactAnalysis.spec.ts › Verify Upstream connections (shard 2, 1 retry)
  • Features/Permissions/GlossaryPermissions.spec.ts › Team-based permissions work correctly (shard 3, 1 retry)
  • Flow/ObservabilityAlerts.spec.ts › Alert operations for a user with and without permissions (shard 3, 1 retry)
  • Pages/Customproperties-part2.spec.ts › entityReferenceList shows item count, scrollable list, no expand toggle (shard 3, 1 retry)
  • Pages/DomainAdvanced.spec.ts › Domain expert can edit domain description and tags (shard 4, 1 retry)
  • Pages/DomainDataProductsRightPanel.spec.ts › Should edit tags for data product from domain context (shard 4, 1 retry)
  • Pages/Domains.spec.ts › Data Product announcement create, edit & delete (shard 4, 1 retry)
  • Pages/Entity.spec.ts › Glossary Term Add, Update and Remove for child entities (shard 4, 1 retry)
  • Pages/Entity.spec.ts › Set & Update table-cp, hyperlink-cp, string, integer, markdown, number, duration, email, enum, sqlQuery, timestamp, entityReference, entityReferenceList, timeInterval, time-cp, date-cp, dateTime-cp Custom Property (shard 4, 1 retry)
  • Pages/EntityDataSteward.spec.ts › Tag Add, Update and Remove (shard 5, 1 retry)
  • Pages/ServiceEntity.spec.ts › Announcement create, edit & delete (shard 6, 1 retry)
  • Pages/ServiceEntity.spec.ts › Set & Update table-cp, hyperlink-cp, string, integer, markdown, number, duration, email, enum, sqlQuery, timestamp, entityReference, entityReferenceList, timeInterval, time-cp, date-cp, dateTime-cp Custom Property (shard 6, 1 retry)
  • Pages/Users.spec.ts › Permissions for table details page for Data Consumer (shard 6, 1 retry)
  • VersionPages/EntityVersionPages.spec.ts › Directory (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

@gitar-bot
Copy link

gitar-bot bot commented Mar 24, 2026

Code Review ⚠️ Changes requested 0 resolved / 2 findings

Adds TableV2 component as a migration wrapper for Untitled UI and React Aria, but the sticky column positioning logic assumes only one fixed column per side (always using left: 0 or right: 0), which breaks layouts with multiple pinned columns. Additionally, the 976-line component should be refactored into smaller, more maintainable pieces.

⚠️ Bug: getColumnStickyStyle assumes at most one fixed column per side

📄 openmetadata-ui/src/main/resources/ui/src/components/common/Table/TableV2Utils.ts:126-138

The getColumnStickyStyle utility always uses left: 0 for fixed='left' and right: 0 for fixed='right' (lines 130-134). The JSDoc comment acknowledges this limitation, but if a consumer passes multiple columns with fixed='left', they will all stack at left: 0 and overlap each other. Since this is a migration wrapper aiming for AntD API compatibility, and AntD correctly computes cumulative offsets for multiple fixed columns, this silent visual breakage could be surprising.

Suggested fix
Consider computing cumulative offsets based on the widths of preceding fixed columns. For example, pass the column index and column definitions to compute the left/right offset dynamically:

export function getColumnStickyStyle(
  columns: ColumnType<unknown>[],
  colIndex: number,
  zIndex: number
): React.CSSProperties {
  const col = columns[colIndex];
  if (col.fixed === 'left') {
    const offset = columns.slice(0, colIndex)
      .filter(c => c.fixed === 'left')
      .reduce((sum, c) => sum + (Number(c.width) || 0), 0);
    return { background: 'white', left: offset, position: 'sticky', zIndex };
  }
  // similar for 'right' in reverse
}
💡 Quality: 976-line component would benefit from extraction

📄 openmetadata-ui/src/main/resources/ui/src/components/common/Table/TableV2.tsx

TableV2.tsx is a single ~976-line component with inline rendering logic for headers, filter dropdowns, expand icons, column resizers, cells, pagination, search bar, and column customization. This makes it difficult to review, test, and maintain. Consider extracting logical sections into sub-components (e.g., TableV2Header, TableV2Row, TableV2FilterDropdown, TableV2ColumnCustomizer) in follow-up PRs to improve readability and enable targeted unit testing.

🤖 Prompt for agents
Code Review: Adds TableV2 component as a migration wrapper for Untitled UI and React Aria, but the sticky column positioning logic assumes only one fixed column per side (always using left: 0 or right: 0), which breaks layouts with multiple pinned columns. Additionally, the 976-line component should be refactored into smaller, more maintainable pieces.

1. ⚠️ Bug: getColumnStickyStyle assumes at most one fixed column per side
   Files: openmetadata-ui/src/main/resources/ui/src/components/common/Table/TableV2Utils.ts:126-138

   The `getColumnStickyStyle` utility always uses `left: 0` for `fixed='left'` and `right: 0` for `fixed='right'` (lines 130-134). The JSDoc comment acknowledges this limitation, but if a consumer passes multiple columns with `fixed='left'`, they will all stack at `left: 0` and overlap each other. Since this is a migration wrapper aiming for AntD API compatibility, and AntD correctly computes cumulative offsets for multiple fixed columns, this silent visual breakage could be surprising.

   Suggested fix:
   Consider computing cumulative offsets based on the widths of preceding fixed columns. For example, pass the column index and column definitions to compute the left/right offset dynamically:
   
   export function getColumnStickyStyle(
     columns: ColumnType<unknown>[],
     colIndex: number,
     zIndex: number
   ): React.CSSProperties {
     const col = columns[colIndex];
     if (col.fixed === 'left') {
       const offset = columns.slice(0, colIndex)
         .filter(c => c.fixed === 'left')
         .reduce((sum, c) => sum + (Number(c.width) || 0), 0);
       return { background: 'white', left: offset, position: 'sticky', zIndex };
     }
     // similar for 'right' in reverse
   }

2. 💡 Quality: 976-line component would benefit from extraction
   Files: openmetadata-ui/src/main/resources/ui/src/components/common/Table/TableV2.tsx

   TableV2.tsx is a single ~976-line component with inline rendering logic for headers, filter dropdowns, expand icons, column resizers, cells, pagination, search bar, and column customization. This makes it difficult to review, test, and maintain. Consider extracting logical sections into sub-components (e.g., `TableV2Header`, `TableV2Row`, `TableV2FilterDropdown`, `TableV2ColumnCustomizer`) in follow-up PRs to improve readability and enable targeted unit testing.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud
Copy link

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

Labels

safe to test Add this label to run secure Github workflows on PRs UI UI specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant