Skip to content

Add loading & progress feedback to the entity export modal#29755

Open
anuj-kumary wants to merge 4 commits into
mainfrom
export-loader
Open

Add loading & progress feedback to the entity export modal#29755
anuj-kumary wants to merge 4 commits into
mainfrom
export-loader

Conversation

@anuj-kumary

@anuj-kumary anuj-kumary commented Jul 6, 2026

Copy link
Copy Markdown
Member

Describe your changes:

Fix: image/PDF loader now paints immediately. flushSync committed the loading state but the browser couldn't paint it before html-to-image's synchronous DOM cloning blocked the main thread, so the disabled/loading button only appeared after the export finished. Added a double-requestAnimationFrame yield so the loading state paints before the blocking work.

Screen.Recording.2026-07-06.at.11.55.08.AM.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

High-level design:

N/A — small change.

Tests:

Use cases covered

Unit tests

Backend integration tests

Ingestion integration tests

Playwright (UI) tests

Manual testing performed

UI screen recording / screenshots:

Not applicable.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • My PR is linked to a GitHub issue via Fixes #<issue-number> above.
  • 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.
  • For UI changes: I attached a screen recording and/or screenshots above.
  • I have added tests (unit / integration / Playwright as applicable) and listed them above.

Greptile Summary

This PR fixes a paint-ordering issue in the entity export modal where the loading state (spinner + disabled button) was not visible to the user before html-to-image's synchronous DOM cloning blocked the main thread. It also simplifies the isLoading prop on the submit button to be consistent across all export types.

  • Double requestAnimationFrame yield is added after flushSync on the non-CSV export path so the browser completes at least one paint cycle before the blocking exportMethodBasedOnType call begins (~2 frames, ≈33 ms at 60 fps — imperceptible to users).
  • isLoading is simplified from selectedExportType !== ExportTypes.CSV && downloading to just downloading, so the button consistently shows a loading spinner during all export types.

Confidence Score: 5/5

Safe to merge — two small, well-targeted changes with no new async pitfalls or regressions.

The double-rAF pattern is the canonical way to guarantee a browser paint between a synchronous state flush and a main-thread-blocking call. Error handling and component teardown are both handled correctly before and after the new await. The isLoading simplification removes an unnecessary condition without altering any functional branch.

No files require special attention.

Important Files Changed

Filename Overview
openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityExportModalProvider/EntityExportModalProvider.component.tsx Two focused changes: adds a double-rAF yield after flushSync to guarantee a browser paint before blocking image export work, and simplifies isLoading to apply uniformly across all export types. Both changes are correct and well-scoped.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant Button
    participant React
    participant Browser
    participant htmlToImage

    User->>Button: Click Export (non-CSV)
    Button->>React: handleExport()
    React->>React: flushSync → setDownloading(true)
    Note over React,Browser: State committed to DOM
    React->>Browser: "requestAnimationFrame #1"
    Browser->>Browser: "requestAnimationFrame #2"
    Browser-->>React: resolve() — browser has painted loading state
    Note over Button: Spinner & disabled state visible ✓
    React->>htmlToImage: exportMethodBasedOnType() [blocks main thread]
    htmlToImage-->>React: export complete
    React->>React: handleCancel() + setDownloading(false)
    React->>Browser: Re-render (modal closed)
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"}}}%%
sequenceDiagram
    participant User
    participant Button
    participant React
    participant Browser
    participant htmlToImage

    User->>Button: Click Export (non-CSV)
    Button->>React: handleExport()
    React->>React: flushSync → setDownloading(true)
    Note over React,Browser: State committed to DOM
    React->>Browser: "requestAnimationFrame #1"
    Browser->>Browser: "requestAnimationFrame #2"
    Browser-->>React: resolve() — browser has painted loading state
    Note over Button: Spinner & disabled state visible ✓
    React->>htmlToImage: exportMethodBasedOnType() [blocks main thread]
    htmlToImage-->>React: export complete
    React->>React: handleCancel() + setDownloading(false)
    React->>Browser: Re-render (modal closed)
Loading

Reviews (4): Last reviewed commit: "Merge branch 'main' into export-loader" | Re-trigger Greptile

@anuj-kumary anuj-kumary self-assigned this Jul 6, 2026
@anuj-kumary anuj-kumary requested a review from a team as a code owner July 6, 2026 06:28
@anuj-kumary anuj-kumary added safe to test Add this label to run secure Github workflows on PRs skip-pr-checks Bypass PR metadata validation check labels Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 63%
63.77% (72760/114091) 46.92% (42342/90240) 48.19% (13023/27021)

@anuj-kumary anuj-kumary enabled auto-merge (squash) July 6, 2026 06:52
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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

✅ 4478 passed · ❌ 1 failed · 🟡 26 flaky · ⏭️ 37 skipped

Shard Passed Failed Flaky Skipped
🔴 Shard 1 439 1 2 16
🟡 Shard 2 815 0 9 3
🟡 Shard 3 793 0 2 12
🟡 Shard 4 808 0 5 5
🟡 Shard 5 855 0 2 0
🟡 Shard 6 768 0 6 1

Genuine Failures (failed on all attempts)

Flow/Tour.spec.ts › Tour should work from help section (shard 1)
TimeoutError: locator.waitFor: Timeout 10000ms exceeded.
Call log:
�[2m  - waiting for locator('[data-tour-elem="badge"]') to be visible�[22m

🟡 26 flaky test(s) (passed on retry)
  • Pages/Lineage/LineageRightPanel.spec.ts › Verify custom properties tab IS visible for supported type: metric (shard 1, 1 retry)
  • Flow/SearchRBAC.spec.ts › a fully denied user sees neither asset type when browsing (shard 1, 1 retry)
  • Features/Announcements/AnnouncementEntity.spec.ts › deletes an existing announcement on a domain (shard 2, 1 retry)
  • Features/BulkEditEntity.spec.ts › Database (shard 2, 1 retry)
  • Features/BulkEditOperationBadges.spec.ts › Database service bulk edit search filters rows and clear restores them (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Database (shard 2, 2 retries)
  • Features/BulkImport.spec.ts › Database Schema (shard 2, 1 retry)
  • Features/ContextCenterArticles.spec.ts › Article listing search filters, clears, and shows empty state (shard 2, 1 retry)
  • Features/ContextCenterArticles.spec.ts › Article list cards, recently viewed widget, and pagination work (shard 2, 1 retry)
  • Features/DataQuality/TableLevelTests.spec.ts › Table Column Name To Exist (shard 2, 1 retry)
  • Features/Glossary/GlossaryAdvancedOperations.spec.ts › should show error when glossary name exceeds limit (shard 2, 1 retry)
  • Features/Table.spec.ts › should persist page size (shard 3, 1 retry)
  • Features/Tasks/TaskNavigation.spec.ts › navigating to /table/TASK-XXXXX should show 404 (invalid URL pattern) (shard 3, 2 retries)
  • Features/Workflows/WorkflowOssRestrictions.spec.ts › graph canvas contains workflow nodes (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Set & Update all CP types on dashboard (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Markdown (shard 4, 1 retry)
  • Pages/DataContracts.spec.ts › Create Data Contract and validate for Directory (shard 4, 1 retry)
  • Pages/DataContractsSemanticRules.spec.ts › Validate Description Rule Is_Set (shard 4, 1 retry)
  • Pages/ExplorePageRightPanel_KnowledgeCenter.spec.ts › Should remove user owner for knowledgeCenter (shard 5, 1 retry)
  • Pages/ExplorePageRightPanel.spec.ts › Should verify deleted user not visible in owner selection for database (shard 5, 1 retry)
  • Pages/ExplorePageRightPanel.spec.ts › Should allow Data Steward to edit tier for searchIndex (shard 6, 1 retry)
  • Pages/GlossaryImportExport.spec.ts › Import partial success - some terms pass, some fail (shard 6, 2 retries)
  • Pages/GlossaryImportExport.spec.ts › Glossary CSV import preserves typed relations (shard 6, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › Column lineage for apiEndpoint -> apiEndpoint (shard 6, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify Impact Analysis service filter selection (shard 6, 1 retry)
  • Pages/Lineage/LineageRightPanel.spec.ts › Verify custom properties tab is NOT visible for pipelineService in platform lineage (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

gitar-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Improves entity export modal responsiveness by implementing a double-rAF yield to force a UI paint before blocking DOM operations and adds spinner feedback to CSV exports. No issues found.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

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 skip-pr-checks Bypass PR metadata validation check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants