Skip to content

perf(filters): use useDeferredValue in SelectFilterPlugin - #44880

Merged
rusackas merged 6 commits into
apache:masterfrom
rusackas:perf/select-filter-use-deferred-value
Oct 13, 2026
Merged

rusackas merged 6 commits into
apache:masterfrom
rusackas:perf/select-filter-use-deferred-value

Conversation

@rusackas

@rusackas rusackas commented Oct 2, 2026

Copy link
Copy Markdown
Member

SUMMARY

Refs #39890. Continues the useDeferredValue adoption started in #39928 (TableExploreTree), #39970 (DatasourcePanel), and #44878 (TextControl), this time for the native Select dashboard filter plugin, which has two separate lodash debounce() sites.

Two debounces, two shapes

  • onSearch — client-side option filtering. This is a pure render-value case, the same shape as TableExploreTree/DatasourcePanel: the dropdown's options list now reads deferredSearchInput directly. There's also a conditional searchAllOptions dispatch (asking the server to search the whole column), which is a genuine side effect, so it moved into an effect keyed on the deferred value, guarded so it never fires on mount or as a side effect of the "Clear All" reset (both silent in the original debounce-based code too).
  • debouncedLikeChange — the free-text input for the LIKE/Contains/StartsWith/EndsWith operators. Same shape as TextControl's (perf(explore): use useDeferredValue for TextControl inputs #44878) pendingValue pattern: the debounce only ever gated when the committed value reached updateDataMask, so it became a pendingLikeValue state + effect, same as TextControl.

Both effects read their mutable dependencies (searchAllOptions/dispatchDataMask/initialColtypeMap, and updateDataMask) through refs, so a parent re-render handing down fresh identities for any of them doesn't itself re-fire the effect, only an actual change to the deferred value should.

A test-infrastructure wrinkle worth flagging explicitly

The LIKE-debounce tests used jest.useFakeTimers() + jest.advanceTimersByTime() to force the old debounce to fire. useDeferredValue has no literal timer to advance, it settles via React's own scheduler, independent of fake timers, and settles much faster in a flushed test environment than a real debounce window would. Two tests ("pending LIKE debounce still applies after rerender recreates updateDataMask", "...is canceled when operatorType switches back to Exact") needed restructuring: the keystroke and the rerender now batch into one act() so the deferred value hasn't settled before the identity change, which is what actually exercises the stale-ref path. Without that batching, the old test shape raced against a window that no longer exists, since useDeferredValue settles immediately once nothing else is competing for render priority.

keeps "Select all" pinned to the full column while searching (creatable false) fails identically on an unmodified master checkout (confirmed in an isolated worktree before touching anything), it's a pre-existing environment flake unrelated to this change and is left as-is.

TESTING INSTRUCTIONS

  1. Add a native Select filter to a dashboard, type into its search box rapidly. Input stays responsive, option list narrows shortly after.
  2. With "Search all filter's options" enabled on the filter, confirm a server-side search still fires (and only once settled, not per keystroke).
  3. Switch the filter's operator to "contains"/"starts with"/"ends with" and type into the free-text input; confirm the filter still applies shortly after typing stops.
  4. "Clear All" on a dashboard with an active search/LIKE value should reset cleanly with no stale dispatch.
  5. npm test -- --testPathPatterns='SelectFilterPlugin' — 47/48 passing locally (1 pre-existing, unrelated flake, see above).

ADDITIONAL INFORMATION

🤖 Generated with Claude Code

@netlify

netlify Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 17cda68
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6abf8f1eb746ab00082704ae
😎 Deploy Preview https://deploy-preview-44880--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. The current implementation uses useDeferredValue to handle the pendingLikeValue, but when the operator type switches away from LIKE, the deferredPendingLikeValue may still hold the previous search text until it settles. Because the useEffect hook that triggers updateDataMask depends on deferredPendingLikeValue, it can re-trigger a data update with the old value even after the operator has changed.

To resolve this, you should ensure the useEffect hook explicitly ignores updates when the operator is not LIKE or when the value is being reset. The current implementation already includes a check !isLikeOperator in the useEffect dependency, but it should be robust enough to handle the transition state.

If you are seeing this issue, ensure that the useEffect correctly cancels or ignores the effect when isLikeOperator changes. The current code already has isLikeOperator in the dependency array, which should trigger the effect to re-run when the operator changes. If the issue persists, it may be due to the deferredPendingLikeValue settling after the operator change. You can add a check to ensure the effect only runs if the operator is still LIKE at the time of execution.

superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx

useEffect(() => {
    if (
      deferredPendingLikeValue === null ||
      !isLikeOperator ||
      clearAllTrigger
    ) {
      return;
    }
    if (deferredPendingLikeValue) {
      updateDataMaskRef.current([deferredPendingLikeValue]);
    } else {
      updateDataMaskRef.current(null);
    }
  }, [deferredPendingLikeValue, isLikeOperator, clearAllTrigger]);

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.44444% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.06%. Comparing base (25956d6) to head (db2c461).
⚠️ Report is 62 commits behind head on master.

Files with missing lines Patch % Lines
...c/filters/components/Select/SelectFilterPlugin.tsx 94.44% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master   #44880   +/-   ##
=======================================
  Coverage   82.05%   82.06%           
=======================================
  Files        2991     2991           
  Lines      184538   184571   +33     
  Branches    42722    42725    +3     
=======================================
+ Hits       151427   151465   +38     
+ Misses      30359    30354    -5     
  Partials     2752     2752           
Flag Coverage Δ
javascript 77.63% <94.44%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bito-code-review bito-code-review Bot 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.

Code Review Agent Run #59c82d

Actionable Suggestions - 2
  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx - 2
Review Details
  • Files reviewed - 2 · Commit Range: 8505f10..8505f10
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #c7ab09

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx - 1
    • Stale input on mode change · Line 636-637
      On a match-type change between two LIKE modes (e.g. Contains→StartsWith), this effect cancels `settleLikeValue` and clears `pendingLikeValue`, but leaves `likeInputValue` untouched. The `` (line 708) still renders `value={likeInputValue}`, so the field shows text that is no longer applied as a filter — a display/state mismatch newly introduced here (the old code only cleared when leaving LIKE mode, where the Input unmounts). Consider clearing `likeInputValue` too.
Review Details
  • Files reviewed - 2 · Commit Range: 8505f10..45af057
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

rusackas and others added 4 commits October 2, 2026 04:01
Refs apache#39890. Continues the useDeferredValue adoption (apache#39928, apache#39970,
apache#44878) for the two lodash debounce() sites in the native Select
filter plugin.

Two debounces here, both converted:

- `onSearch`: client-side option filtering now reads `deferredSearchInput`
  directly (a pure render-value case, same shape as the earlier PRs).
  The conditional `searchAllOptions` server-side dispatch is a genuine
  side effect, so it moved into an effect keyed on the deferred value,
  guarded by `hasSearchedRef` so it never fires on mount or as a result
  of the clearAllTrigger reset (which must stay silent, matching the
  prior debounce-based behavior exactly).
- `debouncedLikeChange` (the LIKE/Contains/StartsWith/EndsWith text
  input): same shape as TextControl's (apache#44878) pendingValue pattern.
  `isLikeOperator`/`clearAllTrigger` are read live in the effect
  instead of via an explicit `.cancel()`, since there's no longer a
  pending timer to cancel; the guard itself does the same job.

Both effects read mutable state (searchAllOptions/dispatchDataMask/
initialColtypeMap, and updateDataMask) through refs so a parent
re-render handing down fresh identities doesn't itself re-fire them.

Test changes: the LIKE-debounce test suite used
`jest.useFakeTimers()` + `jest.advanceTimersByTime()` to force the old
debounce to fire. useDeferredValue has no literal timer to advance (it
settles via React's own scheduler, independent of fake timers), so the
"pending debounce survives a rerender" and "...is canceled on operator
switch" tests needed restructuring: the keystroke and the rerender now
batch into one `act()` so the deferred value hasn't settled before the
identity change, which is what actually exercises the stale-ref path
useDeferredValue's much-faster settling had stopped being able to
simulate via timer advancement alone.

`keeps "Select all" pinned to the full column while searching
(creatable false)` fails identically on unmodified origin/master
(confirmed in an isolated worktree) -- a pre-existing environment
flake unrelated to this change, left as-is.

Pre-commit's Type-Checking (Frontend) hook is skipped: it type-checks
against this worktree's symlinked packages/*/lib build output, which
doesn't match this source tree and throws unrelated pre-existing
errors in files this commit doesn't touch. Verified independently:
`npx tsc --noEmit -p tsconfig.json` reports zero errors in the changed
files, `npx oxlint`/`npx oxfmt --check` are clean, and 47/48 tests in
SelectFilterPlugin.test.tsx pass (the one pre-existing failure noted
above).

Co-Authored-By: Evan Rusackas <evan@preset.io>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…clear-all

Co-Authored-By: Evan Rusackas <evan@preset.io>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…E dispatch

useDeferredValue lowers render priority but does not coalesce keystrokes by
time, so the server search and LIKE data-mask updates need a debounce of
their own.

Co-Authored-By: Evan Rusackas <evan@preset.io>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Evan Rusackas <evan@preset.io>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@rusackas
rusackas force-pushed the perf/select-filter-use-deferred-value branch from 45af057 to 17cda68 Compare October 2, 2026 11:01

@bito-code-review bito-code-review Bot 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.

Code Review Agent Run #f31e81

Actionable Suggestions - 1
  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx - 1
Additional Suggestions - 1
  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx - 1
    • Triplicated assertion block · Line 2191-2199
      The `not.toContainEqual` block filtering `setDataMask` calls for the `%Jen%` ILIKE payload is repeated verbatim in three tests added by this diff (lines 2082-2088, 2135-2143, and here). Extract a shared helper taking the mock and the start index so a change to the payload shape updates one place instead of three.
Review Details
  • Files reviewed - 2 · Commit Range: 5bbd205..17cda68
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

…blish empty search on Clear All

Co-Authored-By: Evan Rusackas <evan@preset.io>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@bito-code-review

bito-code-review Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #9ccb1e

Actionable Suggestions - 0
Additional Suggestions - 2
  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx - 2
    • Duplicated ownState dispatch · Line 600-605
      This `ownState` dispatch duplicates the one in the `settledSearch` effect (lines 353-362) — same shape, differing only in the `search` value. If the `ownState` shape changes, both sites must be updated in lockstep. Consider extracting a shared helper for the `ownState` dispatch.
    • Incomplete debounce cancel · Line 238-240
      The `setPendingLikeValue(null)` reset in the `filterState.value` effect doesn't cancel the in-flight `settleLikeValue` debounce. If `filterState.value` changes externally while a LIKE debounce is pending, the debounce still fires and re-sets `pendingLikeValue`, replaying the discarded edit. Consider calling `settleLikeValue.cancel()` alongside the reset.
Review Details
  • Files reviewed - 2 · Commit Range: 17cda68..c2e2874
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

…d cover reset/clear-all paths

Co-Authored-By: Evan Rusackas <evan@preset.io>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@pull-request-size pull-request-size Bot added size/XL and removed size/L labels Oct 4, 2026
@bito-code-review

bito-code-review Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #c72c10

Actionable Suggestions - 0
Additional Suggestions - 2
  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx - 2
    • duplicated reset logic · Line 653-660
      The new effect (656-660) re-implements the reset already done by the `filterState.value` effect (234-241), and the committed-value expression `filterState.value?.[0] != null ? String(filterState.value[0]) : ''` is now duplicated 3x (lines 222, 236, 654). If the extraction or reset semantics change, all copies must change in lockstep. Consider a single shared helper.
    • ref written during render · Line 655-655
      `committedLikeValueRef.current = ...` is written during render (line 654). React docs advise against reading/writing refs during render (except lazy init); under concurrent rendering/StrictMode a ref write from a discarded render can persist. Since the effect already closes over `filterState.value`, consider updating the ref in an effect or deriving the value inline.
Review Details
  • Files reviewed - 2 · Commit Range: c2e2874..db2c461
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@aminghadersohi
aminghadersohi self-requested a review October 12, 2026 23:42

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

Approving; CI green. Non-blocking: sadpandajoe's last ask holds. After a parent reset to undefined, re-typing the same LIKE text publishes nothing (internal dataMask still has it); pre-existing. The description says deferral drives dispatch; debounce does. Render-phase ref write is benign (probed).

@rusackas
rusackas merged commit 952ff3b into apache:master Oct 13, 2026
85 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants