Skip to content

feat(query-builder): migrate QueryBuilderWidgetV1 from antd to core-components - #29849

Open
chirag-madlani wants to merge 93 commits into
mainfrom
migrate-querybuilder-antd-to-core
Open

feat(query-builder): migrate QueryBuilderWidgetV1 from antd to core-components#29849
chirag-madlani wants to merge 93 commits into
mainfrom
migrate-querybuilder-antd-to-core

Conversation

@chirag-madlani

@chirag-madlani chirag-madlani commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replaces all @react-awesome-query-builder/antd imports with @react-awesome-query-builder/ui (API-identical, same version) across 14 production files and 8 test files
  • Builds a custom OMConfig from BasicConfig with new widget factories backed by openmetadata-ui-core-components, eliminating Ant Design widget rendering inside query builder rules
  • Migrates QueryBuilderWidgetV1 outer shell (Card, Alert, Skeleton, Divider, Typography) from antd to core-components
  • Migrates button renderers in AdvancedSearchUtils and QueryBuilderUtils from antd Button + @ant-design/icons to core Button + @untitledui/icons
  • All query logic, config structure, elasticsearch format utilities, operator definitions, and async autocomplete behavior are preserved unchanged

New widgets (src/utils/queryBuilderWidgets/)

Widget Core component
OMTextWidget Input
OMNumberWidget Input (numeric)
OMSelectWidget Select with async adapter
OMMultiSelectWidget MultiSelect + useListData from react-stately
OMBooleanWidget Toggle
OMDateWidget Native <input type="date/datetime-local/time"> (core DateInput is not publicly exported and requires @internationalized/date objects incompatible with RAQB string values)
OMFieldSelect Select (field/operator picker)
OMConjs ButtonGroup (AND/OR conjunction)

All assembled into src/utils/QueryBuilderOMConfig.tsx which exports OMConfig.

Test plan

  • All 27 QueryBuilderWidgetV1 tests pass
  • All 12 widget unit tests pass (src/utils/queryBuilderWidgets/)
  • Advanced Search modal opens and fields render correctly (no antd widget flash)
  • Adding/removing rules and groups works with the new button renderers
  • Async field autocomplete (owner, tags, tier) resolves correctly
  • JSON logic query builder (data contract) shows OM-styled widgets
  • TypeScript compiles with no new errors

🤖 Generated with Claude Code

Greptile Summary

This PR migrates the query-builder UI from Ant Design to core components. The main changes are:

  • Replaces React Awesome Query Builder Ant Design imports with UI package imports.
  • Adds OpenMetadata-styled query-builder widgets for fields, operators, values, booleans, dates, and conjunctions.
  • Updates async select and multiselect behavior for the new core component wrappers.
  • Migrates query-builder shell, buttons, and related tests to core-component selectors.

Confidence Score: 4/5

This is close, but the async multiselect paging path should be fixed before merging.

  • Saved async multiselect chips now reconcile when options arrive.
  • Async single-select results now use a live item collection.
  • Multiselect async fetching still drops paging metadata, so later values remain unreachable.

Files Needing Attention: openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMMultiSelectWidget.tsx

Important Files Changed

Filename Overview
openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMMultiSelectWidget.tsx Saved-chip reconciliation now reruns after async options load, but async paging still only loads the first result page.
openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMNumberWidget.tsx The widget keeps transient number input text local and avoids committing invalid intermediate values during normal editing.
openmetadata-ui-core-components/src/main/resources/ui/src/components/base/select/combobox.tsx ComboBox now receives live controlled items so async result updates can reach the dropdown.
openmetadata-ui/src/main/resources/ui/src/utils/QueryBuilderOMConfig.tsx The query-builder config routes field, operator, conjunction, and value rendering through the new core-component widget factories.

Reviews (32): Last reviewed commit: "fix unit test" | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used (3)

  • Context used - openmetadata-ui-core-components/CLAUDE.md (source)
  • Context used - CLAUDE.md (source)
  • Context used - AGENTS.md (source)

chirag-madlani and others added 13 commits July 8, 2026 14:55
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nput

Replace @react-awesome-query-builder/antd widgets with core-components. Two new widgets using Input component:
- OMTextWidget: string input values
- OMNumberWidget: numeric input with type="number"

All tests passing, TypeScript strict compilation verified.

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

Implements Task 3 of the query builder migration from Ant Design to
openmetadata-ui-core-components. Provides async-capable single-select
widget wrapping core Select component. Includes handling for both static
list values and async fetch callbacks, with proper TypeScript typing.

- Converts listValues (array or object format) to SelectItemType[]
- Supports async data loading via asyncFetch callback
- Properly disables when readonly
- Fully tested with 2 core test cases (render + disabled state)

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

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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…m core-component widgets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ate button renderers to core-components

- AdvancedSearchClassBase: replace BasicConfig value with OMConfig from QueryBuilderOMConfig;
  BasicConfig is now type-only
- AdvancedSearchUtils: renderAdvanceSearchButtons uses Button (core), X and Trash01 icons
  from @untitledui/icons; removes @ant-design/icons and antd Button imports
- QueryBuilderUtils: renderQueryBuilderFilterButtons and renderJSONLogicQueryBuilderButtons
  use Button (core) and X/Plus from @untitledui/icons; removes antd and @ant-design/icons imports

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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-components, clean up LESS

- Replace antd Card/Row/Col/Skeleton/Alert/Button/Divider/Typography with
  @openmetadata/ui-core-components equivalents
- Replace @ant-design/icons InfoCircleOutlined with @untitledui/icons InfoCircle
- Remove all .ant-* selectors from LESS; replace Less variable refs with
  CSS custom properties (--color-*)
- Update skeleton test selector from .ant-skeleton.ant-skeleton-active to
  [aria-hidden="true"] (core Skeleton uses aria-hidden)
- Update padding class test from .ant-col/.p-t-sm to .tw\\:pt-2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updated 7 test files to import from @react-awesome-query-builder/ui instead
of @react-awesome-query-builder/antd, and replaced AntdConfig with BasicConfig.
Applied UI checkstyle (organize-imports, lint:fix, prettier) on all modified
test files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…invalid type cast, wire JSONLogicSearchClassBase to OMConfig

- OMDateWidget: replace getInputType(operator) with fieldType prop — operator values like "equal"/"less" never contain "time"/"datetime"; fieldType is the correct discriminant
- OMDateWidget: fix tw:bg-disabled_subtle → tw:bg-disabled-subtle (underscore → dash matches CSS token)
- OMNumberWidget: remove impossible `as number & null` intersection cast; Number(v) is already number
- JSONLogicSearchClassBase: import OMConfig and set baseConfig = OMConfig so JSON-logic query builder uses OM-styled widgets consistently with AdvancedSearchClassBase

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chirag-madlani
chirag-madlani requested a review from a team as a code owner July 8, 2026 15:13
Copilot AI lite review requested due to automatic review settings July 8, 2026 15:13

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 commented Jul 8, 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 added safe to test Add this label to run secure Github workflows on PRs UI UI specific issues labels Jul 8, 2026
Comment on lines +78 to +91
async (search: string) => {
if (!asyncFetch) {
return;
}
const result = await asyncFetch(search);
setAllItems(
(result.values as ListItem[]).map((item) => ({
id: String(item.value),
label: String(item.title ?? item.value),
}))
);
},
[asyncFetch]
);

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 Async Pagination Is Dropped

The multi-select adapter always calls asyncFetch(search) and discards the returned hasMore state. Fetchers such as enum/custom-property autocomplete accept an offset and can return more pages, so values after the first page can never be loaded or selected in the query builder.

Comment on lines +58 to +75
useEffect(() => {
const currentIds = new Set(selectedItems.items.map((i) => i.id));
const targetIds = new Set(valueArray);

for (const id of targetIds) {
if (!currentIds.has(id)) {
const item = allItems.find((i) => i.id === id);
if (item) {
selectedItems.append(item);
}
}
}
for (const item of selectedItems.items) {
if (!targetIds.has(item.id)) {
selectedItems.remove(item.id);
}
}
}, [valueArray.join(',')]);

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 Saved Async Values Disappear

When a saved async multiselect filter is rendered, allItems is initially empty, so the sync effect cannot append chips for the current valueArray. After the async options arrive, the effect does not rerun for the same value, leaving persisted owner, tag, tier, or custom-property filters visually unselected even though the tree still contains their values.

Comment on lines +29 to +30
value={value !== null && value !== undefined ? String(value) : ''}
onChange={(v: string) => setValue(v === '' ? null : Number(v))}

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 Intermediate Numbers Store NaN

Number(v) is stored for every non-empty number-input string. Browser number inputs can emit intermediate values like 1e, -, or ., which convert to NaN; that value then enters the query tree and can produce an invalid or non-matching generated filter.

Suggested change
value={value !== null && value !== undefined ? String(value) : ''}
onChange={(v: string) => setValue(v === '' ? null : Number(v))}
value={value !== null && value !== undefined ? String(value) : ''}
onChange={(v: string) => {
if (v === '') {
setValue(null);
return;
}
const nextValue = Number(v);
if (Number.isFinite(nextValue)) {
setValue(nextValue);
}
}}

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 66%
66.22% (78350/118314) 50.23% (47329/94220) 51.43% (14266/27737)

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

The OMSelectWidget aggregate autocomplete calls the ES aggregate endpoint
which requires entities to be indexed. When the test ran immediately after
beforeAll created the schemas, ES hadn't finished ingesting them, so the
aggregate returned empty buckets and the dropdown never showed the expected
option — causing the "Database Schema" field tests to flake on first attempt
but pass on retry (by which time ES had caught up).

Poll the aggregate endpoint after entity creation and block until both
schemas appear in the index before the test body starts.

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

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Two bugs blocked the react-aria migration E2E suite:

1. DataContractsSemanticRules: locators referenced `.ant-select`
   (removed with the antd migration) — dropped to just `.group--field`
   and `.rule--operator` so RAQB's own CSS classes are used directly.

2. selectOption async timeout: the old antd implementation waited for
   a loading-spinner to detach (default 60s action timeout) on every
   call, which incidentally polled ES until a freshly-created entity
   was indexed. The new react-aria version fired one `loadAsync` from
   the initial `fill()` and only retried the _click_, so a slow ES
   index returned an empty popup for the full 30 s and timed out.

   Fix: re-fill `optionTitle` at the start of every retry iteration
   (fires a fresh `onInputChange` → `loadAsync`), raise the inner
   `click` timeout to 3 000 ms, and raise `toPass` to 60 000 ms to
   match the old spinner-wait budget.

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

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

The selectOption helper already retries for up to 30 s with toPass —
each retry re-fills the combobox which triggers a fresh aggregate fetch,
so the suite self-heals if ES hasn't indexed the schema yet.

The beforeAll block added up to 120 s of shard overhead (2 schemas ×
60 s worst-case) that timing-baseline.json doesn't capture, pushing
chromium-01 past the 1500 s execution budget and timing out the shard.

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

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 is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@gitar-bot

gitar-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 4 resolved / 6 findings

Migrates QueryBuilderWidgetV1 and its widgets from Ant Design to core-components with custom widget factories. Changes requested due to missing debounce on async select network fetches and dropped group labels in OMFieldSelect.

⚠️ Performance: Async select fires a network fetch on every keystroke (no debounce)

📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMSelectWidget.tsx:74-88 📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMSelectWidget.tsx:52-66

In OMSelectWidget.tsx the new async Select.ComboBox branch wires onInputChange={(v) => { loadAsync(v); }}, and loadAsync calls asyncFetch(search) which performs the /api/v1/search/aggregate request (owner/tag/tier autocomplete). There is no debounce/throttle, so every character typed issues a fresh backend request. The previous Ant Design RAQB widget debounced these lookups. This can produce a burst of aggregate queries per search, wasted work, and out-of-order responses where a slower earlier request overwrites items set by a later one (the last setItems to resolve wins, not the last request issued).

Suggested fix: debounce the input handler and/or guard against stale responses (e.g. track the latest request and ignore results from superseded searches).

Track the latest request and drop superseded responses; debounce onInputChange.
// debounce input + ignore stale responses
const latestReq = useRef(0);
const loadAsync = useCallback(async (search: string) => {
  if (!asyncFetch) return;
  const reqId = ++latestReq.current;
  const result = await asyncFetch(search);
  if (reqId !== latestReq.current) return; // stale
  setItems((result.values as ListItem[]).map((item) => ({
    id: String(item.value),
    label: String(item.title ?? item.value),
  })));
}, [asyncFetch]);
// then wrap the onInputChange call site in a debounce (e.g. lodash debounce, 300ms)
💡 Quality: OMFieldSelect drops group label (supportingText) from field picker

📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMFieldSelect.tsx:24-27

In OMFieldSelect.tsx the mapping previously set supportingText: item.grouplabel, which surfaced the field's group/entity context in the field picker dropdown. This commit removes it, so the field/operator selector no longer shows the group label. If this is an intentional simplification it can be ignored, but it is a user-facing regression from the prior behavior where grouped fields displayed their group as supporting text. Confirm whether losing the group label is intended; if not, restore supportingText: item.grouplabel.

✅ 4 resolved
Edge Case: OMDateWidget can't render ISO/Date values in native inputs

📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMDateWidget.tsx:32-45
OMDateWidget binds value={String(value ?? '')} directly to a native <input type="date|datetime-local|time">. These native inputs only accept strictly-formatted strings (yyyy-MM-dd, yyyy-MM-ddTHH:mm, HH:mm). If RAQB provides a full ISO timestamp (e.g. 2024-01-01T00:00:00.000Z) or a Date object for a preexisting value, String(value) will not match the required format and the input will silently render empty, dropping the previously-saved date when a rule is edited. Consider normalizing value to the format expected by each type before passing it to the input.

Bug: Async multiselect won't show preselected values as chips

📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMMultiSelectWidget.tsx:58-72 📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMMultiSelectWidget.tsx:77-91
In OMMultiSelectWidget, the effect that syncs selectedItems (from useListData) with the incoming valueArray only appends items it can find in allItems:

const item = allItems.find((i) => i.id === id);
if (item) {
  selectedItems.append(item);
}

and it is keyed only on [valueArray.join(',')].

For async fields (owner, tags, tier), listValues is empty at mount, so staticItems and the initial allItems are empty. When editing an existing filter that already has selected values, the sync effect runs once, fails to find the ids in the empty allItems, and appends nothing. loadAsync('') later populates allItems, but since allItems is not in the effect's dependency array the sync effect does not re-run — so the preselected values are never rendered as selected chips. This regresses the edit experience for async multiselect fields (a common case: editing a saved advanced-search / data-contract rule).

Suggested fix: include allItems in the effect dependencies, and/or fall back to a placeholder { id, label: id } when the item is not yet loaded so the selection is preserved.

Edge Case: Async single-select may not display label for preselected value

📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMSelectWidget.tsx:49-63
In OMSelectWidget, selectedKey is set to String(value) and the visible label is looked up from items. For async fields, items starts empty (listValues is empty) and is only populated after loadAsync('') resolves. If the resolved page does not include the currently-selected value, or before it resolves, the Select has a selectedKey with no matching item and will render without the human-readable label. Consider seeding items with the current value (e.g. { id: String(value), label: String(value) }) when it is not present in the loaded list, mirroring the fix needed for the multiselect widget.

Edge Case: Selecting an async option re-triggers a fetch via onInputChange

📄 openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMSelectWidget.tsx:86-91
In the async Select.ComboBox branch of OMSelectWidget.tsx, onInputChange unconditionally calls loadAsync(v). When a user selects an option, react-aria ComboBox typically updates the input text to the selected item's label, which fires onInputChange again and triggers an extra asyncFetch call with the selected label as the search term. This is an unnecessary request and can also cause the items list to be replaced right after selection. Consider ignoring input changes that are not user-driven typing (react-aria provides trigger context via onInputChange's second argument in some versions) or comparing against the current selection before re-fetching.

🤖 Prompt for agents
Code Review: Migrates QueryBuilderWidgetV1 and its widgets from Ant Design to core-components with custom widget factories. Changes requested due to missing debounce on async select network fetches and dropped group labels in OMFieldSelect.

1. ⚠️ Performance: Async select fires a network fetch on every keystroke (no debounce)
   Files: openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMSelectWidget.tsx:74-88, openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMSelectWidget.tsx:52-66

   In `OMSelectWidget.tsx` the new async `Select.ComboBox` branch wires `onInputChange={(v) => { loadAsync(v); }}`, and `loadAsync` calls `asyncFetch(search)` which performs the `/api/v1/search/aggregate` request (owner/tag/tier autocomplete). There is no debounce/throttle, so every character typed issues a fresh backend request. The previous Ant Design RAQB widget debounced these lookups. This can produce a burst of aggregate queries per search, wasted work, and out-of-order responses where a slower earlier request overwrites `items` set by a later one (the last `setItems` to resolve wins, not the last request issued).
   
   Suggested fix: debounce the input handler and/or guard against stale responses (e.g. track the latest request and ignore results from superseded searches).

   Fix (Track the latest request and drop superseded responses; debounce onInputChange.):
   // debounce input + ignore stale responses
   const latestReq = useRef(0);
   const loadAsync = useCallback(async (search: string) => {
     if (!asyncFetch) return;
     const reqId = ++latestReq.current;
     const result = await asyncFetch(search);
     if (reqId !== latestReq.current) return; // stale
     setItems((result.values as ListItem[]).map((item) => ({
       id: String(item.value),
       label: String(item.title ?? item.value),
     })));
   }, [asyncFetch]);
   // then wrap the onInputChange call site in a debounce (e.g. lodash debounce, 300ms)

2. 💡 Quality: OMFieldSelect drops group label (supportingText) from field picker
   Files: openmetadata-ui/src/main/resources/ui/src/utils/queryBuilderWidgets/OMFieldSelect.tsx:24-27

   In `OMFieldSelect.tsx` the mapping previously set `supportingText: item.grouplabel`, which surfaced the field's group/entity context in the field picker dropdown. This commit removes it, so the field/operator selector no longer shows the group label. If this is an intentional simplification it can be ignored, but it is a user-facing regression from the prior behavior where grouped fields displayed their group as supporting text. Confirm whether losing the group label is intended; if not, restore `supportingText: item.grouplabel`.

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

@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.

7 participants