perf(ui): defer my-data shell widgets#29177
Conversation
|
Code Review ✅ Approved 9 resolved / 9 findingsOptimizes dashboard loading by deferring landing page widgets behind IntersectionObserver and refactoring the shell into lightweight utilities. Resolved all identified loading edge cases and state management issues. ✅ 9 resolved✅ Edge Case: Stale data set into state after cache epoch change
✅ Bug: Widget stuck in loading when currentUser is undefined
✅ Bug: ownedAssets.map can throw when hits is undefined
✅ Edge Case: NLP-active mount can leave Suggestions stuck on Loader
✅ Bug: WidgetCard test mocks named export instead of default singleton
...and 4 more resolved from earlier reviews OptionsDisplay: compact → Showing less information. Comment with these commands to change:
Was this helpful? React with 👍 / 👎 | Gitar |



Summary
Testing
Ref: https://github.com/open-metadata/openmetadata-collate/issues/4230
Greptile Summary
This PR defers all landing-page widget rendering behind
DeferredWidget(IntersectionObserver) and breaksCustomizeMyDataPageClassBaseinto focused utility files (CustomizeMyDataPageWidgetUtils,CustomizeMyDataPageImageUtils,DataAssetServiceUtils,LandingPageWidgetIconUtils) to shrink the/my-datashell bundle. It also lazy-loadsSuggestions/SearchOptionsin the search bar and fixes severaluseEffectdependency arrays.DeferredWidget, deferring data-fetch effects until the IO callback fires;AdvanceSearchProvideris removed from the page wrapper sinceCuratedAssetsWidgetnests its own.getEntityLinkFromType,getDataAssetExploreTab,getFormattedDataAssetServiceType, andgetEntityIconreplace corresponding class-method calls, eliminating runtime class lookups on the hot render path.Confidence Score: 5/5
Safe to merge; all functional paths for standard entity types and widget rendering are covered, and the widget/image/service splits correctly preserve the class extension points introduced in the previous fix commit.
The core deferred-rendering path is well-reasoned and the IO/fallback logic handles test, SSR, and Lighthouse environments explicitly. The two observations flagged are confined to uncommon extension-point scenarios.
DataAssetServiceUtils.tsx — the security-category to TABLES tab mapping warrants a second look; FollowingWidget.tsx (and CuratedAssetsWidget, CustomiseLandingPageHeader) — getEntityLinkFromType bypasses the entityUtilClassBase override point.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Browser participant MyDataPage participant DeferredWidget participant IO as IntersectionObserver participant Widget as Widget (lazy chunk) Browser->>MyDataPage: navigate to /my-data MyDataPage->>MyDataPage: useState(getDefaultLandingPageLayout) Note over MyDataPage: Shell + skeleton render MyDataPage->>MyDataPage: fetchDocument() MyDataPage-->>Browser: Paint skeleton immediately par fetch persona layout MyDataPage->>MyDataPage: getDocumentByFQN(persona) MyDataPage->>MyDataPage: setLayout + setIsLoading(false) and IO setup MyDataPage->>DeferredWidget: "mount all DeferredWidgets (shouldRender=false)" DeferredWidget->>IO: observe each widget wrapper end MyDataPage-->>Browser: Replace skeleton with empty grid placeholders IO-->>DeferredWidget: "inView=true (above-fold first)" DeferredWidget->>DeferredWidget: setHasBeenVisible(true) DeferredWidget->>Widget: import() lazy chunk Widget-->>Browser: Render widget + fire data fetch IO-->>DeferredWidget: "inView=true (on scroll)" DeferredWidget->>Widget: mount + fetch%%{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 Browser participant MyDataPage participant DeferredWidget participant IO as IntersectionObserver participant Widget as Widget (lazy chunk) Browser->>MyDataPage: navigate to /my-data MyDataPage->>MyDataPage: useState(getDefaultLandingPageLayout) Note over MyDataPage: Shell + skeleton render MyDataPage->>MyDataPage: fetchDocument() MyDataPage-->>Browser: Paint skeleton immediately par fetch persona layout MyDataPage->>MyDataPage: getDocumentByFQN(persona) MyDataPage->>MyDataPage: setLayout + setIsLoading(false) and IO setup MyDataPage->>DeferredWidget: "mount all DeferredWidgets (shouldRender=false)" DeferredWidget->>IO: observe each widget wrapper end MyDataPage-->>Browser: Replace skeleton with empty grid placeholders IO-->>DeferredWidget: "inView=true (above-fold first)" DeferredWidget->>DeferredWidget: setHasBeenVisible(true) DeferredWidget->>Widget: import() lazy chunk Widget-->>Browser: Render widget + fire data fetch IO-->>DeferredWidget: "inView=true (on scroll)" DeferredWidget->>Widget: mount + fetchReviews (17): Last reviewed commit: "fix(ui): guard NLP suggestions fetch" | Re-trigger Greptile