Skip to content

feat(contextCenter): support sortBy/sortOrder on page hierarchy search - #31625

Open
sonika-shah wants to merge 7 commits into
open-metadata:mainfrom
sonika-shah:sonika/cc-hierarchy-sort
Open

feat(contextCenter): support sortBy/sortOrder on page hierarchy search#31625
sonika-shah wants to merge 7 commits into
open-metadata:mainfrom
sonika-shah:sonika/cc-hierarchy-sort

Conversation

@sonika-shah

@sonika-shah sonika-shah commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

What

Adds sortBy / sortOrder query params to GET /v1/contextCenter/pages/search/hierarchy so the Context Center left-tree can control ordering — e.g. a newly created article or quick link surfaces at the top instead of the bottom.

Fixes open-metadata/openmetadata-collate#4781 (item 1 — article hierarchy sorting).

How

Threads a SearchSortFilter from the resource through KnowledgePageRepository → the SearchClient interface → the ES/OS client implementations:

  • KnowledgePageResourcelistHierarchyWithSearch gains sortBy (name / updatedAt) and sortOrder (asc / desc). Reuses the existing resolveSortField / resolveSortOrder validators, so invalid values return 400. Default is updatedAt desc (newest first).
  • ElasticSearchClient / OpenSearchClient — a shared buildPageHierarchySortOptions applies the requested primary sort, then always appends fullyQualifiedName (keyword, unique per page) as a stable tiebreaker so from/size pagination cannot miss or duplicate hits when the primary sort field is non-unique. Uses Entity.FIELD_FULLY_QUALIFIED_NAME + a SORT_ORDER_DESC constant rather than raw literals.
  • SearchClient / KnowledgePageRepository — signature threading only.

The Collate ElasticSearchClientExt / OpenSearchClientExt override these same methods; the matching Collate change is in openmetadata-collate (linked below).

Tests

KnowledgePageHierarchyIT gains three cases: invalid sortBy → 400, invalid sortOrder → 400, and a name asc/desc ordering assertion (Awaitility-gated on the search index).

Verified end-to-end on a real Collate stack against both Elasticsearch 9.3.0 and OpenSearch 3.4.0: sortBy=name asc/desc and the updatedAt desc default all order correctly.

Targets main; to be cherry-picked to 2.0 separately.

Greptile Summary

The PR adds configurable, deterministic sorting to Context Center page-hierarchy searches and refreshes the article tree after successful edits.

  • Threads validated sortBy and sortOrder parameters through the resource, repository, and search-client layers.
  • Applies equivalent primary sorting and a stable fully-qualified-name tiebreaker in Elasticsearch and OpenSearch.
  • Adds integration coverage for validation and name ordering.
  • Refreshes the UI hierarchy after successful article updates.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
openmetadata-service/src/main/java/org/openmetadata/service/resources/knowledge/KnowledgePageResource.java Adds validated hierarchy sort parameters with an updatedAt desc default.
openmetadata-service/src/main/java/org/openmetadata/service/search/SearchClient.java Extends both hierarchy-search contracts to carry the resolved sort filter.
openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchClient.java Applies the requested primary sort and a stable fully-qualified-name tiebreaker.
openmetadata-service/src/main/java/org/openmetadata/service/search/opensearch/OpenSearchClient.java Mirrors Elasticsearch hierarchy sorting for OpenSearch.
openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/KnowledgePageHierarchyIT.java Covers invalid sort parameters and ascending/descending name ordering.
openmetadata-ui/src/main/resources/ui/src/components/KnowledgeCenter/KnowledgePageDetailComponent/KnowledgePageDetailComponent.tsx Notifies the parent after successful article mutations so hierarchy state can refresh.
openmetadata-ui/src/main/resources/ui/src/pages/ContextCenterPage/ContextCenterArticlesPage/ContextCenterArticlesPage.tsx Force-refreshes the article hierarchy after successful saves and consolidates its translation key.

Sequence Diagram

sequenceDiagram
  participant UI as Context Center UI
  participant Resource as KnowledgePageResource
  participant Repository as KnowledgePageRepository
  participant Search as SearchClient
  participant Index as Elasticsearch/OpenSearch
  UI->>Resource: "GET /search/hierarchy?sortBy&sortOrder"
  Resource->>Resource: Validate and resolve sort filter
  Resource->>Repository: Request hierarchy with SearchSortFilter
  Repository->>Search: listPageHierarchy(...)
  Search->>Index: Query with primary sort + FQN tiebreaker
  Index-->>UI: Deterministically ordered hierarchy
  UI->>Resource: Save article
  Resource-->>UI: Updated article
  UI->>Index: Force hierarchy refresh
Loading

Reviews (5): Last reviewed commit: "chore(contextCenter): extract duplicated..." | Re-trigger Greptile

Context used (3)

Adds sortBy/sortOrder query params to GET /v1/contextCenter/pages/search/hierarchy
so newly created articles/quick links can surface at the top of the left-tree
hierarchy. Threads a SearchSortFilter from the resource through
KnowledgePageRepository, the SearchClient interface, and the ES/OS clients.

- Default sort is updatedAt desc (newest first); sortBy accepts name/createdAt/
  updatedAt, sortOrder accepts asc/desc, invalid values return 400 (reuses the
  existing resolveSortField/resolveSortOrder validators).
- fullyQualifiedName (keyword, unique per page) is always appended as a stable
  tiebreaker so from/size pagination cannot miss or duplicate hits when the
  primary sort field is non-unique.
limit=1000000 on the search hierarchy path becomes the ES/OpenSearch query
size, which exceeds the default index.max_result_window (10000) and makes the
shard fail with search_phase_execution_exception (500). The three test pages
fit comfortably in a small window, so query with limit=1000.
Addresses PR review:
- Drop 'createdAt' from the hierarchy sortBy allowableValues/description.
  resolveSortField maps createdAt -> the updatedAt field (the index has no
  createdAt), so advertising it was misleading. Advertise name + updatedAt only;
  the updatedAt-desc default already surfaces newly-created pages at the top.
- Replace the raw "fullyQualifiedName"/"desc" literals in the ES/OS hierarchy
  sort helper with Entity.FIELD_FULLY_QUALIFIED_NAME and a SORT_ORDER_DESC
  constant.
@sonika-shah
sonika-shah requested a review from a team as a code owner August 17, 2026 09:56
Copilot AI lite review requested due to automatic review settings August 17, 2026 09:56

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

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

  • Linked issue open-metadata/openmetadata-collate#4781 does not exist or is not accessible.

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 added backend safe to test Add this label to run secure Github workflows on PRs labels Aug 17, 2026
yan-3005
yan-3005 previously approved these changes Aug 17, 2026
The left-tree hierarchy is fetched once and only refreshed on create / quick-link
edit, so editing an article's content in place did not reorder the tree — the
edited page stayed put even though the backend now returns updatedAt-desc order
(the card list, which refetches, did move it to the top). Refresh the tree
whenever the currently-open article's updatedAt bumps, so an edit moves it to the
top of its branch without a manual reload. Guarded to the same article's
updatedAt increasing, so navigating between pages only records a baseline.
@sonarqubecloud

Copy link
Copy Markdown

The previous updatedAt watcher on the parent page.data never fired: the content
and displayName autosaves in KnowledgePageDetailComponent update only local
state (description/displayName/version) and never push a fresh updatedAt up via
onPageChange, so the parent never saw a change and the left-tree stayed frozen.

Trigger the tree refresh where the save actually completes instead: add an
onArticleSaved callback, wired from ContextCenterArticlesPage to
knowledgePagesHierarchyRef.fetchKnowledgePageHierarchy(true), and invoke it on
successful content and displayName saves. The edited article now re-sorts to the
top of its branch (updatedAt desc) without a manual reload.

Verified live on OpenSearch: editing a mid-tree article moves it to the top and
issues a fresh /search/hierarchy fetch.
Copilot AI review requested due to automatic review settings August 17, 2026 14:05

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added safe to test Add this label to run secure Github workflows on PRs and removed safe to test Add this label to run secure Github workflows on PRs labels Aug 17, 2026
updatePage (tags/owners/reviewers/domains) and updatePageTag also patch the page
and advance updatedAt, so they must trigger the tree re-sort too — otherwise
editing those fields wouldn't move the article to the top. Call onArticleSaved()
after the successful patch in both, matching the content/displayName paths.
Copilot AI review requested due to automatic review settings August 17, 2026 17:38

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added safe to test Add this label to run secure Github workflows on PRs and removed safe to test Add this label to run secure Github workflows on PRs labels Aug 17, 2026
Knocks down the sonarjs/no-duplicate-string warning near the changed code:
'label.article-plural' was repeated 4x; extracted to ARTICLE_PLURAL_LABEL.
Copilot AI review requested due to automatic review settings August 17, 2026 17:56

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@gitar-bot

gitar-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 resolved / 1 findings

Adds validated sortBy and sortOrder query parameters to the Context Center page hierarchy search, supporting deterministic sorting and reliable tree refreshes. No issues found.

✅ 1 resolved
Quality: onArticleSaved not fired on tag/owner/domain saves

📄 openmetadata-ui/src/main/resources/ui/src/components/KnowledgeCenter/KnowledgePageDetailComponent/KnowledgePageDetailComponent.tsx:455 📄 openmetadata-ui/src/main/resources/ui/src/components/KnowledgeCenter/KnowledgePageDetailComponent/KnowledgePageDetailComponent.tsx:620 📄 openmetadata-ui/src/main/resources/ui/src/components/KnowledgeCenter/KnowledgePageDetailComponent/KnowledgePageDetailComponent.tsx:515-529 📄 openmetadata-ui/src/main/resources/ui/src/components/KnowledgeCenter/KnowledgePageDetailComponent/KnowledgePageDetailComponent.tsx:543-557
onArticleSaved?.() is invoked only from the content (updatedPageContent) and display-name (handleDisplayNameUpdate) save paths, but updatePage (tags/owners/reviewers/domains) and updatePageTag also patch the page and advance updatedAt. After editing those fields the left-tree won't re-sort the edited article to the top, which is inconsistent with the stated goal. Consider calling onArticleSaved?.() after the successful patch in updatePage/updatePageTag as well.

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 👍 / 👎 | Powered by Gitar — free for open source

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants