Skip to content

fix(ui): keep Ant overlays interactive inside SlideoutMenu drawers#29151

Open
harshach wants to merge 2 commits into
mainfrom
harshach/add-asset-filter-dropdown-fix
Open

fix(ui): keep Ant overlays interactive inside SlideoutMenu drawers#29151
harshach wants to merge 2 commits into
mainfrom
harshach/add-asset-filter-dropdown-fix

Conversation

@harshach

@harshach harshach commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Describe your changes:

Fixes #29152

Ant Design overlays (Dropdown, Select, TreeSelect, …) portal to document.body by default; inside the react-aria SlideoutMenu drawer that lands them outside the dialog's focus scope, so their popups become non-interactive (options can't be selected or scrolled). This broke the Add Assets filter dropdowns in Domains / Data Products / Input-Output ports and the Column Bulk Operations edit-drawer tag & glossary selects. The fix wraps drawer content in a shared DrawerPopupContainerProvider (an Ant ConfigProvider) whose getPopupContainer resolves to the enclosing [role="dialog"], applied once at the useCompositeDrawer and useDrawer boundaries so every hook-based drawer is fixed without per-call wiring.

Type of change:

  • Bug fix

High-level design:

The defect is a class, not a one-off: any Ant overlay rendered inside a SlideoutMenu drawer portals outside react-aria's focus/scroll containment. Instead of patching each call site, the popup container is defaulted at the two drawer hooks, so current and future hook-based drawers inherit a dialog-scoped getPopupContainer; component-level getPopupContainer props still take precedence, and non-drawer usages (e.g. the Explore page) are untouched. A narrower per-component fix in useAssetSelectionContent/ExploreQuickFilters was prototyped and then reverted in favor of this single mechanism. Residual: components that render <SlideoutMenu> JSX directly (not via the hooks) aren't auto-covered and can wrap their content in the exported provider if they add Ant overlays.

Tests:

Use cases covered

  • In "Add Assets" for a Domain / Data Product / Input or Output port, every quick filter (Entity Type, Owners, Tag, Tier, Service, Service Type) can be opened, scrolled and applied.
  • In the Column Bulk Operations edit drawer, the tag/glossary select popups render inside the drawer and an option can be selected.

Unit tests

  • Not applicable — this is a real-DOM react-aria/portal interaction that jsdom does not reproduce; it is covered by Playwright instead.

Backend integration tests

  • Not applicable (no backend API changes).

Ingestion integration tests

  • Not applicable (no ingestion changes).

Playwright (UI) tests

  • Added/updated:
    • openmetadata-ui/.../ui/playwright/utils/assetSelection.ts (new shared helper; asserts the popup renders inside [role="dialog"], scrolls, and applies each filter)
    • playwright/e2e/Pages/Domains.spec.ts, DataProducts.spec.ts, InputOutputPorts.spec.ts, Tag.spec.ts
    • playwright/e2e/Features/ColumnBulkOperations.spec.ts

Manual testing performed

  1. Served this branch's UI via Vite (yarn start, :3000) proxied to a local backend (:8585).
  2. Ran the new Domain add-assets drawer filter test (all six filters) — passed.
  3. Ran the new Column Bulk Operations edit-drawer tag-select test — passed.

UI screen recording / screenshots:

Behavioral interaction fix (no visual change); covered by the Playwright tests above. Screen recording can be added if required.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title uses the repo's conventional-commit style (fix(ui): …) instead of Fixes <issue>: ….
  • My PR is linked to a GitHub issue via Fixes #29152 above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • For UI changes: I attached a screen recording and/or screenshots above.
  • I have added tests (Playwright) and listed them above.
  • I have added a test that covers the exact scenario we are fixing.

🤖 Generated with Claude Code


Summary by Gitar

  • UI Architecture:
    • Introduced DrawerPopupContainerProvider using Ant ConfigProvider to scope overlays within [role="dialog"].
    • Integrated provider into useDrawer and useCompositeDrawer to ensure drawer-based popups remain interactive.
  • Testing:
    • Added assetSelection.ts utility for verifying dropdown interaction, scrollability, and focus containment.
    • Updated Playwright suites for Domains, DataProducts, InputOutputPorts, Tag, and ColumnBulkOperations.
  • Internationalization:
    • Synchronized sv-se.json with new SSO configuration test strings and keys.

This will update automatically on new commits.

Greptile Summary

This PR fixes a class of non-interactive Ant Design overlay bugs inside SlideoutMenu drawers: because react-aria portals focus/scroll containment to [role="dialog"], but Ant overlays default-portal to document.body, their popups landed outside the focus scope and became unclickable. The fix introduces a DrawerPopupContainerProvider (an Ant ConfigProvider with getPopupContainer resolving to the nearest [role="dialog"]) applied once at both useDrawer and useCompositeDrawer, so every hook-based drawer gets the fix without per-call wiring.

  • DrawerPopupContainerProvider.tsx: new thin wrapper around Ant ConfigProvider; getDrawerPopupContainer walks up the DOM with closest('[role="dialog"]') and falls back to document.body when no dialog ancestor is found (safe for non-drawer contexts).
  • useDrawer / useCompositeDrawer: each wraps its rendered content in DrawerPopupContainerProvider; the two providers do not double-wrap — useCompositeDrawer overrides useDrawer's children entirely via JSX prop spreading so exactly one ConfigProvider sits in the tree.
  • Playwright utilities (assetSelection.ts): shared helpers that assert the popup is found inside [role="dialog"], verify scroll, and apply + clear each filter; used across Domain, DataProduct, InputOutputPort, ColumnBulkOperations, and Tag specs.

Confidence Score: 5/5

Safe to merge — a tightly scoped portal fix applied at the two hook boundaries with no changes to drawer APIs or backend surfaces.

The change is additive: a new ConfigProvider context is inserted inside the drawer boundary and the existing API contract is unchanged. The getDrawerPopupContainer fallback to document.body keeps non-drawer usage unaffected. useCompositeDrawer correctly overrides useDrawer's wrapped children so only one ConfigProvider sits in the rendered tree. Playwright tests directly assert the popup appears inside [role="dialog"] and that options are selectable and scrollable, covering the exact failure mode being fixed.

No files require special attention. The sv-se.json additions use English placeholder values, which appears intentional for new SSO keys pending translation.

Important Files Changed

Filename Overview
openmetadata-ui/src/main/resources/ui/src/components/common/atoms/drawer/DrawerPopupContainerProvider.tsx New provider component that sets getPopupContainer to resolve to the enclosing [role="dialog"] element, keeping Ant overlays within react-aria's focus scope.
openmetadata-ui/src/main/resources/ui/src/components/common/atoms/drawer/useDrawer.tsx Wraps SlideoutMenu children in DrawerPopupContainerProvider so standalone useDrawer callers inherit dialog-scoped popup containers.
openmetadata-ui/src/main/resources/ui/src/components/common/atoms/drawer/useCompositeDrawer.tsx Wraps drawerContent (header+body+footer) in DrawerPopupContainerProvider; the useDrawer-provided wrapper is discarded when compositeDrawer replaces SlideoutMenu children — one ConfigProvider per drawer, correct.
openmetadata-ui/src/main/resources/ui/playwright/utils/assetSelection.ts New shared Playwright utility providing verifyDrawerAssetFilters and helpers for asserting popup renders inside [role="dialog"], applying filters, and verifying scroll — solid regression guards.
openmetadata-ui/src/main/resources/ui/src/locale/languages/sv-se.json Adds SSO test-login and test-validation i18n keys; several values are English placeholders not yet translated to Swedish.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[useDrawer / useCompositeDrawer] --> B[SlideoutMenu\nreact-aria modal]
    B --> C[DrawerPopupContainerProvider\nAnt ConfigProvider]
    C --> D[Drawer content\nheader · body · footer]
    D --> E[Ant overlay triggered\ne.g. Select, Dropdown]
    E --> F{getPopupContainer\ncalled with triggerNode}
    F -->|triggerNode.closest found| G[Portal into dialog ✅\nwithin focus scope]
    F -->|no dialog ancestor| H[Fall back to\ndocument.body]
    G --> I[Overlay interactive\nclick · scroll work]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[useDrawer / useCompositeDrawer] --> B[SlideoutMenu\nreact-aria modal]
    B --> C[DrawerPopupContainerProvider\nAnt ConfigProvider]
    C --> D[Drawer content\nheader · body · footer]
    D --> E[Ant overlay triggered\ne.g. Select, Dropdown]
    E --> F{getPopupContainer\ncalled with triggerNode}
    F -->|triggerNode.closest found| G[Portal into dialog ✅\nwithin focus scope]
    F -->|no dialog ancestor| H[Fall back to\ndocument.body]
    G --> I[Overlay interactive\nclick · scroll work]
Loading

Reviews (2): Last reviewed commit: "chore(ui): sync sv-se locale with en-us ..." | Re-trigger Greptile

Ant Design overlays (Dropdown, Select, TreeSelect, ...) portal to
document.body by default. Inside the react-aria SlideoutMenu drawer this
lands outside the dialog's focus scope, so the popup becomes
non-interactive — options can't be selected or scrolled. This broke the
Add Assets filter dropdowns (Domains, Data Products, Input/Output ports)
and the Column Bulk Operations edit-drawer tag/glossary selects.

Wrap drawer content in a shared DrawerPopupContainerProvider (an Ant
ConfigProvider) whose getPopupContainer resolves to the enclosing
[role="dialog"], applied at the useCompositeDrawer and useDrawer
boundaries so every hook-based drawer is fixed without per-call wiring.

Add Playwright coverage: the Add Assets drawer filters (Domain, Data
Product, Input/Output ports), the Add Assets modal filters (Tag), and the
Column Bulk Operations edit-drawer selects.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@harshach harshach requested a review from a team as a code owner June 17, 2026 23:32
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

✅ PR checks passed

The linked issue has a description and all required Shipping project fields set. Thanks!

@github-actions github-actions Bot added backend safe to test Add this label to run secure Github workflows on PRs labels Jun 17, 2026
Comment on lines +72 to +74
const clearFilter = page.locator(
'.asset-filters-wrapper .text-primary.cursor-pointer'
);

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.

P2 The clear-filter affordance is identified by Tailwind utility classes (.text-primary.cursor-pointer). If these classes are renamed or if other elements on the page happen to share them, the locator would silently pick the wrong element. A data-testid on the clear-filter button would make this test ID stable and its intent explicit.

Suggested change
const clearFilter = page.locator(
'.asset-filters-wrapper .text-primary.cursor-pointer'
);
const clearFilter = page.locator(
'[data-testid="clear-filters"]'
);

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!

@github-actions

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 62%
62.26% (66568/106911) 44.01% (37227/84582) 45.36% (11181/24647)

`yarn i18n` surfaced pre-existing drift in the Swedish locale: SSO/login
keys present in en-us were missing from sv-se.json. Sync them so the
UI Checkstyle i18n-sync job passes. Unrelated to the drawer overlay fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@harshach harshach added the To release Will cherry-pick this PR into the release branch label Jun 18, 2026
@gitar-bot

gitar-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Globalizes Ant Design popup container scoping via DrawerPopupContainerProvider to restore interactivity in SlideoutMenu drawers, alongside a synchronized sv-se locale update. No issues found.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

🔴 Playwright Results — 1 failure(s), 14 flaky

✅ 4285 passed · ❌ 1 failed · 🟡 14 flaky · ⏭️ 102 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 301 0 1 4
🟡 Shard 2 812 0 1 9
✅ Shard 3 813 0 0 8
🟡 Shard 4 854 0 5 12
🟡 Shard 5 732 0 1 47
🔴 Shard 6 773 1 6 22

Genuine Failures (failed on all attempts)

Pages/Tag.spec.ts › Add and Remove Assets (shard 6)
�[31mTest timeout of 180000ms exceeded.�[39m
🟡 14 flaky test(s) (passed on retry)
  • Pages/Roles.spec.ts › Roles page should work properly (shard 1, 1 retry)
  • Features/Glossary/GlossaryHierarchy.spec.ts › should cancel move operation (shard 2, 1 retry)
  • Pages/CustomProperties.spec.ts › Sql Query (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Entity Reference (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Timestamp (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Entity Reference (shard 4, 1 retry)
  • Pages/DataContracts.spec.ts › Create Data Contract and validate for Table (shard 4, 1 retry)
  • Pages/ExplorePageRightPanel_KnowledgeCenter.spec.ts › Should remove user owner for knowledgeCenter (shard 5, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › Column lineage for apiEndpoint -> searchIndex (shard 6, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify Impact Analysis service filter selection (shard 6, 1 retry)
  • Pages/ServiceEntity.spec.ts › Domain Add, Update and Remove (shard 6, 2 retries)
  • Pages/Tag.spec.ts › Verify Tag UI (shard 6, 2 retries)
  • Pages/Tag.spec.ts › Certification Page should not have Asset button (shard 6, 2 retries)
  • Pages/TaskComments.spec.ts › Non-author cannot edit comment - returns 403 (shard 6, 2 retries)

📦 Download artifacts

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

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

Labels

backend safe to test Add this label to run secure Github workflows on PRs To release Will cherry-pick this PR into the release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Assets drawer filter dropdowns are not interactive (can't select or scroll)

1 participant