feat: add customizable Data Marketplace landing page - #26255
Conversation
Add a new Data Marketplace page at /data-marketplace with: - Greeting banner, search bar with recent searches (per-user via Zustand) - New Data Products and New Domains widgets with add/view-all actions - ReactGridLayout-based customizable widget grid - Per-persona layout persistence via DocStore (same pattern as MyData home page) - New DataMarketplace PageType in backend schema - Marketplace section in left sidebar - Edit mode via /customize-page/:personaFqn/DataMarketplace Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
Changed marketplaceDataProducts and marketplaceDomains default heights from 3 to 1 to match the page's MARKETPLACE_ROW_HEIGHT of 200px. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
Replace the landing page customization pattern (CustomizeMyData) with the entity detail page pattern (CustomizeTabWidget) for the Data Marketplace page. This gives proper drag handles, add/remove controls, and tab-based widget management. - Create DataMarketplaceClassBase with default tabs, layouts, widgets - Create CustomizableDataMarketplacePage using CustomizeTabWidget - Register DataMarketplace in CustomizePageUtils (all 6 switch statements) - Add marketplace widgets to GenericWidgetUtils WIDGET_COMPONENTS - Update DataMarketplacePage to use tab-based layout (8-col grid) - Clean up old landing page pattern code from CustomizeMyDataPageClassBase - Move widget keys from LandingPageWidgetKeys to DetailPageWidgetKeys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
…Name Commit 119e9fe accidentally reverted the fix from PR #26793 by changing entity.name back to getEntityName(entity) for Metric breadcrumbs. In search results, getEntityName() returns the displayName which contains Elasticsearch highlight HTML fragments (<span class="text-highlighter">), causing breadcrumbs to render raw HTML as text. Using entity.name directly returns the plain, non-highlighted name. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| <SelectPopover | ||
| isNonModal | ||
| className="!tw:max-h-[400px]" | ||
| isOpen={isOpen && searchValue?.trim().length > 0} | ||
| offset={4} | ||
| placement="bottom" | ||
| size="md" | ||
| style={{ width: containerRef?.current?.offsetWidth }} |
There was a problem hiding this comment.
SelectPopover uses className="!tw:max-h-[400px]", which doesn’t match the repo’s Tailwind prefixing pattern (e.g., tw:!size-4). As written, this class likely won’t be generated/applied, so the popover may not get the intended max-height styling. Use the prefixed important syntax (e.g., tw:!max-h-[400px]) or move the constraint into the .marketplace-search-results styling only.
| export const getDomainPath = (fqn?: string) => { | ||
| let path = ROUTES.DOMAIN; | ||
| const basePath = useMarketplaceStore.getState().domainBasePath; | ||
|
|
||
| if (fqn) { | ||
| path = ROUTES.DOMAIN_DETAILS; | ||
| path = path.replace(PLACEHOLDER_ROUTE_FQN, getEncodedFqn(fqn)); | ||
| return `${basePath}/${getEncodedFqn(fqn)}`; | ||
| } | ||
|
|
||
| return path; | ||
| return basePath; | ||
| }; | ||
|
|
||
| export const getDomainDetailsPath = ( | ||
| fqn: string, | ||
| tab?: string, | ||
| subTab = 'all' | ||
| ) => { |
There was a problem hiding this comment.
💡 Performance: getCertificationClassification called on every getTags invocation
Every call to getTags(fqn) now calls getCertificationClassification(), which reads from SettingsCache. When listing entities (e.g., paginated list of 100 tables with tags), this results in 100+ cache lookups per request. While SettingsCache is in-memory, the repeated deserialization of AssetCertificationSettings and string allocation could add up in hot paths. Consider caching the classification name in a field (invalidated on settings change) or computing it once per request.
Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion
| const handleLanguageChange = useCallback(({ key }: MenuInfo) => { | ||
| i18next.changeLanguage(key); | ||
| setPreference({ language: key as SupportedLocales }); | ||
| navigate(0); | ||
| }, []); |
There was a problem hiding this comment.
💡 Bug: useEffect missing deps: currentPage, handlePagingChange
The pagination sync useEffect at line 137 uses handlePagingChange, currentPage, and handlePageChange in its body, but the dependency array is [allTasksInternal.length, pageSize]. While handlePagingChange (which is setPaging) is stable, currentPage is read directly and handlePageChange is recreated when currentPage changes. This means the currentPage > maxPage correction (line 140) won't re-run when currentPage changes externally (e.g. via URL params). The eslint exhaustive-deps rule would flag this.
Suggested fix:
useEffect(() => {
handlePagingChange({ total: allTasksInternal.length });
const maxPage = Math.max(1, Math.ceil(allTasksInternal.length / pageSize));
if (currentPage > maxPage) {
handlePageChange(maxPage, { cursorType: null, cursorValue: undefined });
}
}, [allTasksInternal.length, pageSize, currentPage, handlePagingChange, handlePageChange]);
Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion
Code Review
|
| Compact |
|
Was this helpful? React with 👍 / 👎 | Gitar
| <Link | ||
| className="flex-shrink-0 tw:bg-transparent" | ||
| id="openmetadata_logo" | ||
| to="/"> | ||
| {collapsed ? ( |
There was a problem hiding this comment.
This file uses Tailwind classes, but flex-shrink-0 is missing the required tw: prefix (Tailwind is imported with prefix(tw)), so the class won’t apply. Update it to tw:flex-shrink-0 (or equivalent) to ensure the logo link doesn’t shrink in the collapsed state.
|
|



Describe your changes:
I worked on adding a new Data Marketplace page at
/data-marketplace— a discovery hub for data products and domains, because the platform needed a centralized entry point for browsing and discovering data products and domains with persona-based customization support.Core features:
DataMarketplaceadded to thePageTypebackend schema enumNew files:
pages/DataMarketplacePage/— Main page component + stylescomponents/DataMarketplace/— MarketplaceGreetingBanner, MarketplaceSearchBar, MarketplaceDataProductsWidget, MarketplaceDomainsWidget, MarketplaceItemCard, AnnouncementsWidgetV2hooks/useMarketplaceRecentSearches.ts— Recent search persistence hookhooks/useMarketplaceStore.ts— Zustand store for marketplace navigation context (usesROUTESconstants)Modified files:
page.json— newDataMarketplacePageTypepage.ts,uiCustomization.tsCustomizeMyDataPageClassBase— marketplace widget registrations + default layoutCustomizeMyData— dynamic pageType + default layout (no longer hardcoded to LandingPage)CustomizablePageHeader— "Add Widgets" button visible for marketplace pagesCustomizablePage— DataMarketplace routing casePersonaUtils— DataMarketplace category in persona settingsCode quality improvements (reviewer feedback):
AnnouncementsWidgetV2: UseTypographysize/weightprops instead of custom Tailwind font-size/weight classesMarketplaceItemCard: UseisClickableprop onCardcomponent; Space key now also activates the card for accessibilitymarketplace-widget-shared.less: Replaced hardcoded hex colors (#fff,#eaecf0) with Less variables (@white,@border-color)useMarketplaceStore: Now imports and usesROUTESconstants instead of hardcoded path strings to avoid driftuseMarketplaceRecentSearches: Fixed in-place mutation of Zustand state ([...entries].sort()instead ofentries.sort())useCallbackdependency arrays fixed inMarketplaceDomainsWidget,MarketplaceDataProductsWidget, andMarketplaceSearchBar👋) moved into i18n translation strings across all locale filesScreen.Recording.2026-03-17.at.10.56.12.AM.mov
Type of change:
Checklist:
Fixes <issue-number>: <short explanation>💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.