Skip to content

Fixes #29916: replace API_RES_MAX_SIZE with cursor-based pagination in GlossaryTermTab - #31949

Closed
anuj-kumary wants to merge 6 commits into
mainfrom
fix/29916-clean
Closed

Fixes #29916: replace API_RES_MAX_SIZE with cursor-based pagination in GlossaryTermTab#31949
anuj-kumary wants to merge 6 commits into
mainfrom
fix/29916-clean

Conversation

@anuj-kumary

@anuj-kumary anuj-kumary commented Aug 24, 2026

Copy link
Copy Markdown
Member

Fixes #29916

Summary

  • Replaced two API_RES_MAX_SIZE (100,000) usages in GlossaryTermTab.component.tsx with do…while cursor-based pagination using PAGE_SIZE_LARGE (50), so the expand-all and task-loading paths no longer issue a single massive request.
  • Removed the now-unused API_RES_MAX_SIZE import.
  • Wrapped fetchExpadedTree in try/catch/finally so a mid-loop network error cannot leave the loading spinner permanently stuck.
  • Added sequence counters (expandTreeSeqRef, fetchTasksSeqRef) — the same pattern fetchAllTerms already uses with fetchRequestSeqRef — to guard against two concurrency races:
    • Glossary-switch race: user navigates A → B while expand-all or task fetch is paginating; stale results are discarded.
    • A → B → A race: user returns to the original glossary before the first request completes; FQN alone would accept the stale result, but the sequence counter correctly rejects it.
    • finally-block spinner leak: a stale expand-all's finally block no longer clears loading state owned by a newer request.
  • Added targeted eslint-disable-next-line openmetadata-imports/no-api-calls-in-iteration — the rule targets N+1-per-item patterns; cursor pagination is O(pages), not O(items).

Changed files

  • openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx

Test plan

  • Open a glossary with more than 50 terms — term table loads correctly
  • Click "Expand All" on a glossary with more than 50 terms — all levels expand correctly
  • Switch glossaries rapidly while expand-all is running — new glossary shows correct data, not stale data from the previous one
  • Approval task badges appear on terms with pending approval tasks
  • yarn ui-checkstyle:changed — 0 errors ✅
  • TypeScript: no errors in the changed file ✅

🤖 Generated with Claude Code

Greptile Summary

The PR replaces oversized glossary-term and task requests with incremental pagination and adds stale-request sequencing. It also changes Expand All to use the normal paginated table and lazy child loading.

  • Paginates approval-task retrieval in 50-item pages.
  • Reworks Expand All around first-level pagination, infinite scrolling, and lazy child requests.
  • Adds request-sequence checks and glossary-switch state resets.

Confidence Score: 3/5

The PR is not yet safe to merge because pending expansion work can still update the term table after the user switches glossaries.

Expand All now launches unguarded child requests whose late responses can overwrite the newly selected glossary, and the previously reported isLoadingMore-gated switch invalidation remains outstanding.

Files Needing Attention: openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx

Important Files Changed

Filename Overview
openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx Pagination and sequencing improve request size handling, but unguarded lazy-child writes and conditional switch invalidation leave cross-glossary stale-state failures.
openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx Updates task request expectations to the new page size but does not cover glossary switches during expand-all child loading.

Sequence Diagram

sequenceDiagram
  participant U as User
  participant T as GlossaryTermTab
  participant API as Glossary API
  U->>T: Expand All on glossary A
  T->>API: Fetch first-level page
  API-->>T: Expandable terms
  loop Each unloaded expandable term
    T->>API: Fetch child terms
  end
  U->>T: Switch to glossary B
  T->>API: Fetch B first-level terms
  API-->>T: B terms
  API-->>T: Late A child terms
  T->>T: Unguarded child-state update
  Note over T: B table can be replaced by A hierarchy
Loading

Reviews (4): Last reviewed commit: "fix(glossary): replace eager expand-all ..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used:

anuj-kumary and others added 3 commits August 24, 2026 16:21
…n GlossaryTermTab

Replace two usages of API_RES_MAX_SIZE (100,000) with do…while cursor
pagination using PAGE_SIZE_LARGE (50), so the expand-all and task-loading
paths no longer issue a single massive request.

Also wrap fetchExpadedTree in try/catch/finally so a mid-loop network error
cannot leave the loading spinner stuck, and suppress the false-positive
no-api-calls-in-iteration lint warnings (pagination is O(pages), not N+1).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…switch

Snapshot activeGlossary.fullyQualifiedName before each paginated loop and
compare against the store's current value after all pages are fetched.
If the user navigated to a different glossary while the request was in flight,
the results are silently dropped instead of overwriting the new glossary's state.

Addresses the race condition flagged by Greptile on PR #31946.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sk results

Replace FQN-only staleness guards with monotonic sequence counters
(expandTreeSeqRef, fetchTasksSeqRef) — the same pattern fetchAllTerms
already uses with fetchRequestSeqRef.

This fixes two races the FQN guard missed:
- A→B→A: user switches back to the original glossary before an old
  in-flight request completes; FQN matches but results are stale.
- finally-block spinner leak: a stale expand-all's finally block ran
  unconditionally and cleared the loading state owned by a newer request,
  making the new glossary appear loaded before its data arrived.

Both setIsTableLoading/setIsExpandingAll in fetchExpadedTree's finally
are now guarded by the same seq check so only the latest invocation
can reset the loading indicators.

Addresses Greptile and gitar-bot review comments on PR #31946.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the UI UI specific issues label Aug 24, 2026
@github-actions

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!

@anuj-kumary anuj-kumary self-assigned this Aug 24, 2026
@anuj-kumary anuj-kumary added skip-pr-checks Bypass PR metadata validation check safe to test Add this label to run secure Github workflows on PRs labels Aug 24, 2026
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

❌ UI Checkstyle Failed

❌ ESLint + Prettier + Organise Imports (src)

One or more source files have linting or formatting issues.

Affected files
  • openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx

🔍 ESLint findings in this PR's files — 0 error(s), 33 warning(s)

Errors block the build. Warnings do not yet — they are rules whose backlog is still
being worked down, listed so this PR does not add to it. See docs/ui-code-quality-gate.md.

0 error(s), 33 warning(s) across 2 changed file(s).

Count Rule
15 react-hooks/exhaustive-deps
3 sonarjs/cyclomatic-complexity
3 sonarjs/no-duplicate-string
2 sonarjs/cognitive-complexity
2 sonarjs/expression-complexity
2 jsx-a11y/click-events-have-key-events
2 jsx-a11y/no-static-element-interactions
1 openmetadata-imports/review-sequential-api-calls
1 parse-error
1 react/no-unstable-nested-components
All findings
Location Rule Message
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:135:75 sonarjs/cyclomatic-complexity {"message":"Function has a complexity of 17 which is greater than 10 authorized.","cost":7,"secondaryLocations":[{"line":135,"column":74,"endLine":135,"endColum
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:173:6 react-hooks/exhaustive-deps React Hook useMemo has an unnecessary dependency: 'findExpandableKeysForArray'. Either exclude it or remove the dependency array. Outer scope values like 'findE
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:223:34 react-hooks/exhaustive-deps React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:227:9 react-hooks/exhaustive-deps The 'fetchChildTerms' function makes the dependencies of useCallback Hook (at line 834) change on every render. To fix this, wrap the definition of 'fetchChildT
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:294:9 react-hooks/exhaustive-deps The 'fetchAllTerms' function makes the dependencies of useEffect Hook (at line 613) change on every render. To fix this, wrap the definition of 'fetchAllTerms'
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:294:9 react-hooks/exhaustive-deps The 'fetchAllTerms' function makes the dependencies of useEffect Hook (at line 660) change on every render. To fix this, wrap the definition of 'fetchAllTerms'
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:294:9 react-hooks/exhaustive-deps The 'fetchAllTerms' function makes the dependencies of useCallback Hook (at line 1169) change on every render. To fix this, wrap the definition of 'fetchAllTerm
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:294:50 sonarjs/cognitive-complexity Refactor this function to reduce its Cognitive Complexity from 29 to the 15 allowed.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:294:50 sonarjs/cyclomatic-complexity {"message":"Function has a complexity of 26 which is greater than 10 authorized.","cost":16,"secondaryLocations":[{"line":294,"column":49,"endLine":294,"endColu
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:374:31 openmetadata-imports/review-sequential-api-calls Review these sequential API requests. If they are independent, start them together with Promise.all/Promise.allSettled; keep sequencing only when data-dependent
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:426:15 parse-error Unused eslint-disable directive (no problems were reported from 'openmetadata-imports/no-api-calls-in-iteration').
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:529:6 react-hooks/exhaustive-deps React Hook useEffect has missing dependencies: 'fetchAllTerms', 'handlePagingChange', and 'setGlossaryChildTerms'. Either include them or remove the dependency
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:541:6 react-hooks/exhaustive-deps React Hook useEffect has a missing dependency: 'setGlossaryChildTerms'. Either include it or remove the dependency array.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:730:7 sonarjs/cognitive-complexity Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:730:7 sonarjs/cyclomatic-complexity {"message":"Function has a complexity of 12 which is greater than 10 authorized.","cost":2,"secondaryLocations":[{"line":730,"column":6,"endLine":730,"endColumn
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:806:5 react-hooks/exhaustive-deps React Hook useCallback has missing dependencies: 'setGlossaryChildTerms', 't', and 'updateGlossaryTermStatus'. Either include them or remove the dependency arra
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1065:31 sonarjs/no-duplicate-string Define a constant instead of duplicating this literal 4 times.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1102:6 react-hooks/exhaustive-deps React Hook useMemo has missing dependencies: 'currentUser', 'onAddGlossaryTerm', 'onEditGlossaryTerm', and 't'. Either include them or remove the dependency arr
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1232:5 react-hooks/exhaustive-deps React Hook useMemo has missing dependencies: 'handleCheckboxChange' and 't'. Either include them or remove the dependency array.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1326:6 react-hooks/exhaustive-deps React Hook useMemo has missing dependencies: 'handleEditGlossary', 'handleSearchChange', 'permissions.EditAll', and 't'. Either include them or remove the depen
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1363:19 react/no-unstable-nested-components Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactj
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1370:31 sonarjs/no-duplicate-string Define a constant instead of duplicating this literal 3 times.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1371:29 sonarjs/no-duplicate-string Define a constant instead of duplicating this literal 3 times.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1395:16 sonarjs/expression-complexity Reduce the number of conditional operators (4) used in the expression (maximum allowed 3).
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1450:11 sonarjs/expression-complexity Reduce the number of conditional operators (4) used in the expression (maximum allowed 3).
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1455:5 react-hooks/exhaustive-deps React Hook useMemo has unnecessary dependencies: 'glossaryChildTerms', 'glossaryTerms', and 'setGlossaryChildTerms'. Either exclude them or remove the dependenc
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1528:6 react-hooks/exhaustive-deps React Hook useMemo has an unnecessary dependency: 'movedGlossaryTerm'. Either exclude it or remove the dependency array.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:1737:6 react-hooks/exhaustive-deps React Hook useEffect has missing dependencies: 'activeGlossary', 'fetchAllTerms', and 'previousGlossaryFQN'. Either include them or remove the dependency array.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx:141:7 jsx-a11y/click-events-have-key-events Visible, non-interactive elements with click handlers must have at least one keyboard listener.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx:141:7 jsx-a11y/no-static-element-interactions Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx:151:9 jsx-a11y/click-events-have-key-events Visible, non-interactive elements with click handlers must have at least one keyboard listener.
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx:151:9 jsx-a11y/no-static-element-interactions Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs
🟡 src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx:261:63 react/no-array-index-key Do not use Array index in keys

Fix locally (fast - only checks files changed in this branch):

make ui-checkstyle-changed

Bump expandTreeSeqRef when switching glossaries so a still-paginating
expand-all for the old glossary cannot pass its seq check and overwrite
the newly selected glossary's child terms.

Closes #29916

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the stale limit: 100000 (API_RES_MAX_SIZE) assertion with
limit: 50 (PAGE_SIZE_LARGE) to match the listTasks cursor-pagination
call introduced in the parent fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 67%
67.06% (80450/119964) 51.46% (49258/95703) 52.45% (14705/28031)

…ll expansion

Remove fetchExpadedTree's all-pages-at-once loop (getGlossaryTerms with a
do-while) and replace it with the same infinite-scroll pattern the normal
term table already uses:

- "Expand All" now calls fetchAllTerms() instead of fetchExpadedTree()
- After each page of first-level terms loads, rows with children are
  auto-expanded and their children lazy-loaded via fetchChildTerms —
  exactly the same code path as a manual row expand
- Infinite scroll continues to work in expand-all mode (removed the
  !toggleExpandBtn guard from both the MutationObserver and scroll
  listener) so pages load and auto-expand as the user scrolls
- Switching glossaries while in expand-all mode now resets the mode and
  clears expanded keys, preventing stale state bleed-through
- Removes fetchExpadedTree, expandTreeSeqRef, and the unused
  getGlossaryTerms / buildTree / TabSpecificField imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment on lines +421 to +429
termsToExpand.forEach((term) => {
if (
(!term.children || term.children.length === 0) &&
(term.childrenCount ?? 0) > 0
) {
// eslint-disable-next-line openmetadata-imports/no-api-calls-in-iteration
fetchChildTerms(term.fullyQualifiedName ?? '');
}
});

@gitar-bot gitar-bot Bot Aug 24, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Concurrent expand-all child fetches clobber each other

The new expand-all path fires fetchChildTerms for every expandable top-level term in a single forEach (lines 421-429), so multiple calls run concurrently. fetchChildTerms captures glossaryChildTerms from its render closure and commits with the non-functional setGlossaryChildTerms(updatedTerms) (line 269-270), while the store setter only accepts a plain array (no functional updater). Each concurrent resolution therefore overwrites the store based on a stale snapshot that lacks the siblings' just-added children, so only the last-resolving parent keeps its children — expand-all visibly fails to expand most branches on any glossary with several expandable top-level terms. The same stale-closure path is unguarded on glossary switch: a lingering child fetch from glossary A can resolve after navigation and re-commit A's term tree over B. Read the freshest store state before computing the update (as the loadMore branch already does via useGlossaryStore.getState()).

Read the latest committed store state before applying the child-term update, replacing the stale closure read of glossaryChildTerms.:

// Recursive function to update nested terms
const updateNestedTerms = (
  terms: ModifiedGlossary[]
): ModifiedGlossary[] => { /* unchanged */ };

// Read the freshest committed terms so concurrent child fetches (e.g.
// expand-all) build on each other instead of clobbering, and a fetch
// that resolves after a glossary switch becomes a no-op.
const currentTerms = useGlossaryStore.getState().glossaryChildTerms;
if (!Array.isArray(currentTerms)) {
  return;
}
const updatedTerms = updateNestedTerms(currentTerms);
setGlossaryChildTerms(updatedTerms);

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 1 resolved / 2 findings

Replaces eager API_RES_MAX_SIZE fetches with cursor-based pagination and sequence guards in GlossaryTermTab. However, concurrent child fetches during expand-all can clobber each other.

⚠️ Bug: Concurrent expand-all child fetches clobber each other

📄 openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:227-241 📄 openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:421-429

The new expand-all path fires fetchChildTerms for every expandable top-level term in a single forEach (lines 421-429), so multiple calls run concurrently. fetchChildTerms captures glossaryChildTerms from its render closure and commits with the non-functional setGlossaryChildTerms(updatedTerms) (line 269-270), while the store setter only accepts a plain array (no functional updater). Each concurrent resolution therefore overwrites the store based on a stale snapshot that lacks the siblings' just-added children, so only the last-resolving parent keeps its children — expand-all visibly fails to expand most branches on any glossary with several expandable top-level terms. The same stale-closure path is unguarded on glossary switch: a lingering child fetch from glossary A can resolve after navigation and re-commit A's term tree over B. Read the freshest store state before computing the update (as the loadMore branch already does via useGlossaryStore.getState()).

Read the latest committed store state before applying the child-term update, replacing the stale closure read of `glossaryChildTerms`.
// Recursive function to update nested terms
const updateNestedTerms = (
  terms: ModifiedGlossary[]
): ModifiedGlossary[] => { /* unchanged */ };

// Read the freshest committed terms so concurrent child fetches (e.g.
// expand-all) build on each other instead of clobbering, and a fetch
// that resolves after a glossary switch becomes a no-op.
const currentTerms = useGlossaryStore.getState().glossaryChildTerms;
if (!Array.isArray(currentTerms)) {
  return;
}
const updatedTerms = updateNestedTerms(currentTerms);
setGlossaryChildTerms(updatedTerms);
✅ 1 resolved
Bug: Expand-all seq guard misses the glossary-switch race

📄 openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:414-428 📄 openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:531-545
The expand-all guard only rejects stale results when expandTreeSeqRef is bumped, which happens exclusively inside fetchExpadedTree. Switching glossaries (the effect at ~line 531) calls fetchAllTerms() — bumping fetchRequestSeqRef, not expandTreeSeqRef — so an expand-all that is still paginating for glossary A passes its seq === expandTreeSeqRef.current check and applies A's tree via setGlossaryChildTerms/setExpandedRowKeys onto glossary B. This directly contradicts the PR's claim that the glossary-switch race is covered (the tasks path is fine because fetchAllTasks re-runs on switch and does bump fetchTasksSeqRef). Fix by invalidating in-flight expand-all work when the glossary changes, e.g. increment expandTreeSeqRef in the switch effect, or capture the active glossary id at invocation and re-check it before applying results.

🤖 Prompt for agents
Code Review: Replaces eager API_RES_MAX_SIZE fetches with cursor-based pagination and sequence guards in GlossaryTermTab. However, concurrent child fetches during expand-all can clobber each other.

1. ⚠️ Bug: Concurrent expand-all child fetches clobber each other
   Files: openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:227-241, openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx:421-429

   The new expand-all path fires `fetchChildTerms` for every expandable top-level term in a single `forEach` (lines 421-429), so multiple calls run concurrently. `fetchChildTerms` captures `glossaryChildTerms` from its render closure and commits with the non-functional `setGlossaryChildTerms(updatedTerms)` (line 269-270), while the store setter only accepts a plain array (no functional updater). Each concurrent resolution therefore overwrites the store based on a stale snapshot that lacks the siblings' just-added children, so only the last-resolving parent keeps its children — expand-all visibly fails to expand most branches on any glossary with several expandable top-level terms. The same stale-closure path is unguarded on glossary switch: a lingering child fetch from glossary A can resolve after navigation and re-commit A's term tree over B. Read the freshest store state before computing the update (as the `loadMore` branch already does via `useGlossaryStore.getState()`).

   Fix (Read the latest committed store state before applying the child-term update, replacing the stale closure read of `glossaryChildTerms`.):
   // Recursive function to update nested terms
   const updateNestedTerms = (
     terms: ModifiedGlossary[]
   ): ModifiedGlossary[] => { /* unchanged */ };
   
   // Read the freshest committed terms so concurrent child fetches (e.g.
   // expand-all) build on each other instead of clobbering, and a fetch
   // that resolves after a glossary switch becomes a no-op.
   const currentTerms = useGlossaryStore.getState().glossaryChildTerms;
   if (!Array.isArray(currentTerms)) {
     return;
   }
   const updatedTerms = updateNestedTerms(currentTerms);
   setGlossaryChildTerms(updatedTerms);

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

(term.childrenCount ?? 0) > 0
) {
// eslint-disable-next-line openmetadata-imports/no-api-calls-in-iteration
fetchChildTerms(term.fullyQualifiedName ?? '');

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.

P1 Stale child requests overwrite glossary

When a user starts Expand All for glossary A and switches to glossary B while one of A's lazy child requests is pending, the unguarded child response updates the shared term tree after B loads, replacing B's displayed terms with A's hierarchy.

Knowledge Base Used: Governance and collaboration experience

auto-merge was automatically disabled August 24, 2026 13:50

Pull request was closed

@sonarqubecloud

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 UI UI specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove high limit usage of API_RES_MAX_SIZE in GlossaryTermTab

1 participant