Skip to content

feat(ui): add optional renderPageHeader override to Domain & Data Product list pages#29720

Open
siddhant1 wants to merge 1 commit into
open-metadata:mainfrom
siddhant1:feat/list-page-render-header
Open

feat(ui): add optional renderPageHeader override to Domain & Data Product list pages#29720
siddhant1 wants to merge 1 commit into
open-metadata:mainfrom
siddhant1:feat/list-page-render-header

Conversation

@siddhant1

@siddhant1 siddhant1 commented Jul 3, 2026

Copy link
Copy Markdown
Member

What

Adds an optional renderPageHeader render prop to DomainListPage and DataProductListPage.

  • When provided, the returned node replaces the default page header and the breadcrumb — the caller owns the header area.
  • When omitted (the default), the pages render their existing breadcrumb + header exactly as before.

Prop types live in colocated DomainListPage.interface.ts / DataProductListPage.interface.ts, following the existing *.interface.ts convention.

Why

A generic, backward-compatible extension point that lets a downstream app inject a custom list-page header (e.g. a branded header) while reusing the page's list body, drawer, and permission wiring. There is no behavior change for existing callers — the new prop is optional and defaults to today's rendering.

Changes

  • DomainListPage / DataProductListPage: accept optional renderPageHeader({ onAddClick, createPermission, count }); render it in place of the default header + breadcrumb when present.
  • New *.interface.ts files for the two props types.

Testing

  • Default path unchanged (prop omitted → existing header + breadcrumb).
  • renderPageHeader provided → returned node renders, breadcrumb suppressed.

Greptile Summary

This PR adds an optional renderPageHeader render prop to both DomainListPage and DataProductListPage. When the prop is omitted the pages behave exactly as before; when it is provided, the default breadcrumb and page header are replaced by the caller's node while the list body, drawer, and permission wiring remain unchanged.

  • New DomainListPage.interface.ts / DataProductListPage.interface.ts files export the props types, following the existing *.interface.ts convention.
  • Both component files guard the HeaderBreadcrumb with !renderPageHeader and use a ternary to select between the custom node and the existing pageHeader — the two render paths are logically symmetric and backward-compatible.
  • pageTitle is kept as a required field in both interfaces because withPageLayout needs it to satisfy its P extends { pageTitle: string } constraint and populate PageLayoutV1; existing router call-sites already pass it.

Confidence Score: 4/5

Safe to merge — the change is purely additive, existing render paths are untouched, and the router call-sites already satisfy the required pageTitle prop.

The logic is correct and backward-compatible. The only observations are stylistic: the render-prop callback shape is copy-pasted verbatim into both interface files with no shared type, and the pageTitle field's purpose (satisfying withPageLayout) is invisible from the interface alone. Neither affects runtime behavior.

Both *.interface.ts files warrant a quick look for the duplicated inline callback type and the undocumented pageTitle field.

Important Files Changed

Filename Overview
openmetadata-ui/src/main/resources/ui/src/components/DataProduct/DataProductListPage.interface.ts New interface file defining DataProductListPageProps with required pageTitle (consumed by withPageLayout) and optional renderPageHeader render prop; inline callback type is duplicated with DomainListPage.interface.ts
openmetadata-ui/src/main/resources/ui/src/components/DataProduct/DataProductListPage.tsx Accepts optional renderPageHeader prop; correctly suppresses breadcrumb and replaces default pageHeader when the prop is provided; no behavior change for existing callers
openmetadata-ui/src/main/resources/ui/src/components/DomainListing/DomainListPage.interface.ts New interface file defining DomainListPageProps with required pageTitle and optional renderPageHeader; inline callback type shape is identical to DataProductListPage.interface.ts with no shared type
openmetadata-ui/src/main/resources/ui/src/components/DomainListing/DomainListPage.tsx Accepts optional renderPageHeader prop; correctly suppresses breadcrumb and replaces default pageHeader when provided; existing router usage (pageTitle only) is unaffected

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Caller["Router / Caller"]
    Caller -->|"pageTitle + renderPageHeader?"| WrappedPage["withPageLayout(DomainListPage / DataProductListPage)"]
    WrappedPage -->|"pageTitle"| PageLayoutV1["PageLayoutV1 (document title)"]
    WrappedPage -->|"all props"| InnerPage["Inner Page Component"]

    InnerPage --> CheckHeader{renderPageHeader\nprovided?}

    CheckHeader -->|"Yes"| NoBC["Breadcrumb suppressed"]
    CheckHeader -->|"Yes"| CustomHeader["renderPageHeader({ onAddClick, createPermission, count })"]

    CheckHeader -->|"No"| ShowBC["HeaderBreadcrumb rendered"]
    CheckHeader -->|"No"| DefaultHeader["Default usePageHeader node rendered"]

    NoBC & CustomHeader --> Body["Card body: filters, list/card/tree, pagination"]
    ShowBC & DefaultHeader --> Body
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
    Caller["Router / Caller"]
    Caller -->|"pageTitle + renderPageHeader?"| WrappedPage["withPageLayout(DomainListPage / DataProductListPage)"]
    WrappedPage -->|"pageTitle"| PageLayoutV1["PageLayoutV1 (document title)"]
    WrappedPage -->|"all props"| InnerPage["Inner Page Component"]

    InnerPage --> CheckHeader{renderPageHeader\nprovided?}

    CheckHeader -->|"Yes"| NoBC["Breadcrumb suppressed"]
    CheckHeader -->|"Yes"| CustomHeader["renderPageHeader({ onAddClick, createPermission, count })"]

    CheckHeader -->|"No"| ShowBC["HeaderBreadcrumb rendered"]
    CheckHeader -->|"No"| DefaultHeader["Default usePageHeader node rendered"]

    NoBC & CustomHeader --> Body["Card body: filters, list/card/tree, pagination"]
    ShowBC & DefaultHeader --> Body
Loading

Reviews (1): Last reviewed commit: "feat(ui): add optional renderPageHeader ..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

…duct list pages

Add an optional renderPageHeader render prop to DomainListPage and
DataProductListPage. When provided it replaces the default page header
and the breadcrumb; when omitted the pages render their existing header
unchanged. Props live in colocated *.interface.ts files.

Generic, backward-compatible extension point with no behavior change for
existing callers.
@siddhant1 siddhant1 requested a review from a team as a code owner July 3, 2026 06:40
Copilot AI review requested due to automatic review settings July 3, 2026 06:40
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

This PR cannot be merged until the following are addressed on its linked issue:

  • No GitHub issue is linked. Link an issue in the Development section of the PR (or add Fixes #12345 to the description). For a same-org cross-repo issue, add Fixes open-metadata/<repo>#123 to the description.

The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically.

Maintainers can bypass this check by adding the skip-pr-checks label.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@siddhant1 siddhant1 added UI UI specific issues safe to test Add this label to run secure Github workflows on PRs labels Jul 3, 2026
@gitar-bot

gitar-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Adds an optional renderPageHeader prop to Domain and Data Product list pages, allowing for custom header injection while maintaining existing default functionality. 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

Copilot AI left a comment

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.

Pull request overview

Adds an optional renderPageHeader render prop to the Domain and Data Product listing pages so callers can fully override the header area (including breadcrumb) while preserving the existing default UI when the prop is omitted.

Changes:

  • DomainListPage / DataProductListPage accept optional renderPageHeader and render it in place of the default breadcrumb + header when provided.
  • Introduces colocated *.interface.ts prop type files for both list pages.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
openmetadata-ui/src/main/resources/ui/src/components/DomainListing/DomainListPage.tsx Adds renderPageHeader override path and suppresses breadcrumb when used.
openmetadata-ui/src/main/resources/ui/src/components/DomainListing/DomainListPage.interface.ts Defines DomainListPageProps including optional renderPageHeader.
openmetadata-ui/src/main/resources/ui/src/components/DataProduct/DataProductListPage.tsx Adds renderPageHeader override path and suppresses breadcrumb when used.
openmetadata-ui/src/main/resources/ui/src/components/DataProduct/DataProductListPage.interface.ts Defines DataProductListPageProps including optional renderPageHeader.

Comment on lines +16 to +23
export interface DataProductListPageProps {
pageTitle: string;
renderPageHeader?: (props: {
onAddClick: () => void;
createPermission: boolean;
count: number;
}) => ReactNode;
}

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 inline callback shape for renderPageHeader is identical in both DataProductListPageProps and DomainListPageProps. Extracting it to a shared named type avoids silent drift if one signature changes without the other.

Suggested change
export interface DataProductListPageProps {
pageTitle: string;
renderPageHeader?: (props: {
onAddClick: () => void;
createPermission: boolean;
count: number;
}) => ReactNode;
}
export interface PageHeaderRenderProps {
onAddClick: () => void;
createPermission: boolean;
count: number;
}
export interface DataProductListPageProps {
pageTitle: string;
renderPageHeader?: (props: PageHeaderRenderProps) => ReactNode;
}

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!

Comment on lines +16 to +23
export interface DataProductListPageProps {
pageTitle: string;
renderPageHeader?: (props: {
onAddClick: () => void;
createPermission: boolean;
count: number;
}) => ReactNode;
}

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 pageTitle required but unused in component body

pageTitle is declared as required here but the component only destructures renderPageHeader. The prop is intentionally consumed by withPageLayout (which spreads all props into PageLayoutV1), but this is non-obvious to future readers. A short JSDoc comment — e.g. /** Consumed by withPageLayout for the document title. */ — above the field would prevent well-meaning refactors that accidentally drop it.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 63%
63.21% (71119/112496) 46.13% (41246/89401) 47.5% (12684/26701)

@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🔴 Playwright Results — 2 failure(s), 23 flaky

✅ 4478 passed · ❌ 2 failed · 🟡 23 flaky · ⏭️ 38 skipped

Shard Passed Failed Flaky Skipped
🔴 Shard 1 439 1 3 16
🟡 Shard 2 803 0 7 8
🟡 Shard 3 808 0 1 7
🟡 Shard 4 809 0 2 5
🔴 Shard 5 852 1 4 0
🟡 Shard 6 767 0 6 2

Genuine Failures (failed on all attempts)

Flow/Tour.spec.ts › Tour should work from help section (shard 1)
Error: �[2mexpect(�[22m�[31mreceived�[39m�[2m).�[22mtoBe�[2m(�[22m�[32mexpected�[39m�[2m) // Object.is equality�[22m

Expected: �[32m"1�[7m5�[27m"�[39m
Received: �[31m"1�[7m4�[27m"�[39m

Call Log:
- Timeout 10000ms exceeded while waiting on the predicate
Pages/ExploreBrowse.spec.ts › service type drill-down disables unrelated roots and query-panel Clear resets it (shard 5)
�[31mTest timeout of 180000ms exceeded.�[39m
🟡 23 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 › User without permission (shard 1, 1 retry)
  • Flow/SearchRBAC.spec.ts › a dashboard-scoped user sees dashboards but never tables (shard 1, 2 retries)
  • Features/BulkEditEntity.spec.ts › Glossary (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Database service (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Database Schema (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Table (shard 2, 1 retry)
  • Features/DataQuality/TestCaseImportExportE2eFlow.spec.ts › Admin: Complete export-import-validate flow (shard 2, 1 retry)
  • Features/DomainFilterQueryFilter.spec.ts › Domain assets tab should NOT show assets from other domains (shard 2, 1 retry)
  • Features/Glossary/GlossaryHierarchy.spec.ts › should cancel move operation (shard 2, 1 retry)
  • Features/SearchExport.spec.ts › Export queues a background job and downloads from the jobs tray (shard 3, 1 retry)
  • Features/Workflows/WorkflowOssRestrictions.spec.ts › delete-node-button absent in node config sidebar (structural edit blocked) (shard 4, 1 retry)
  • Pages/CustomProperties.spec.ts › Set dateTime-cp custom property on column and verify in UI (shard 4, 1 retry)
  • Pages/Entity.spec.ts › Tier Add, Update and Remove (shard 5, 1 retry)
  • Pages/Entity.spec.ts › Tag Add, Update and Remove (shard 5, 1 retry)
  • Pages/ExplorePageRightPanel_KnowledgeCenter.spec.ts › Should remove user owner for knowledgeCenter (shard 5, 1 retry)
  • Pages/ExplorePageRightPanel.spec.ts › Should verify deleted tag not visible in tag selection for dashboardDataModel (shard 5, 1 retry)
  • Pages/ExplorePageRightPanel.spec.ts › Should allow Data Steward to edit tags for searchIndex (shard 6, 1 retry)
  • Pages/GlossaryImportExport.spec.ts › Check for Circular Reference in Glossary Import (shard 6, 1 retry)
  • Pages/GlossaryImportExport.spec.ts › Glossary CSV import preserves typed relations (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)
  • Pages/Lineage/LineageRightPanel.spec.ts › Verify custom properties tab is NOT visible for apiService 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

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.

2 participants