Skip to content

fix(native-filters): persist created/pasted default values in select filter#40984

Merged
rusackas merged 8 commits into
apache:masterfrom
preset-io:fix-native-filter-creatable-default
Jul 4, 2026
Merged

fix(native-filters): persist created/pasted default values in select filter#40984
rusackas merged 8 commits into
apache:masterfrom
preset-io:fix-native-filter-creatable-default

Conversation

@yousoph

@yousoph yousoph commented Jun 11, 2026

Copy link
Copy Markdown
Member

Summary

Fixes three compounding bugs that prevented native filter default values from persisting when typed or pasted (rather than selected from the dropdown) in a creatable multi-select filter.

Bug: A Value (filter_select) native filter with Allow creation of new values enabled silently dropped default values that were typed or pasted. The chips appeared in the config modal but after clicking Save the filter rendered empty on the dashboard, and reopening the config showed no default value.

Fix 1 — Select.tsx: trim whitespace from pasted tokens (primary fix)

"10107, 10121".split(",") previously produced ["10107", " 10121"] — the leading space caused label-match failure against the existing option {value: 10107, label: "10107"}, resulting in the value being stored as a new string literal " 10121" rather than the correct matched option value.

- const array = token ? uniq(pastedText.split(token)) : [pastedText];
+ const array = token
+   ? uniq(pastedText.split(token).map(s => s.trim()).filter(Boolean))
+   : [pastedText.trim()].filter(Boolean);

Fix 2 — SelectFilterPlugin.tsx: multi-select typed values in options (secondary fix)

!multiSelect guard prevented typed search terms from appearing as selectable new options in multi-select filters. Also fixed a mutation bug where unshift was called on the memoized uniqueOptions array.

- if (search && !multiSelect && !hasOption(search, uniqueOptions, true)) {
-   uniqueOptions.unshift({ label: search, value: search, isNewOption: true });
- }
- return uniqueOptions;
+ if (search && !hasOption(search, uniqueOptions, true)) {
+   return [{ label: search, value: search, isNewOption: true }, ...uniqueOptions];
+ }
+ return uniqueOptions;

Fix 3 — SelectFilterPlugin.tsx: include created values in uniqueOptions (tertiary fix)

uniqueOptions was built only from DB data. When filterState.value contained created values not in the dataset, they were absent from options and relied on the Select component's internal fullSelectOptions fallback which could lose them across re-renders.

+ if (creatable !== false && filterState.value) {
+   const existing = new Set(allOptions);
+   ensureIsArray(filterState.value)
+     .filter(v => v !== null && v !== undefined && !existing.has(v))
+     .forEach(v => {
+       baseOptions.push({ label: String(v), value: String(v), isNewOption: true });
+       existing.add(v);
+     });
+ }

Test plan

  • Reproduce with Vehicle Sales dataset, order_number column — paste 10107, 10121, 10134, 10145, 10159, 10168, 10180, 10188, 10201, 10211 as default value, Save, verify filter chips appear on dashboard
  • Verify individually typing and pressing Enter also works for multi-select creatable filters
  • Verify selecting from dropdown still works correctly
  • Run jest Select.test.tsx — new test 'trims whitespace from pasted comma-separated values' should pass
  • No regression in single-select creatable filter behavior

🤖 Generated with Claude Code

@dosubot dosubot Bot added the dashboard:native-filters Related to the native filters of the Dashboard label Jun 11, 2026
Comment thread superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx Outdated
@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.58824% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.55%. Comparing base (e58ce1c) to head (2e9ac5e).
⚠️ Report is 50 commits behind head on master.

Files with missing lines Patch % Lines
...c/filters/components/Select/SelectFilterPlugin.tsx 69.23% 4 Missing ⚠️
...rset-ui-core/src/components/Select/AsyncSelect.tsx 75.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master   #40984   +/-   ##
=======================================
  Coverage   64.55%   64.55%           
=======================================
  Files        2673     2673           
  Lines      147634   147647   +13     
  Branches    34090    34097    +7     
=======================================
+ Hits        95307    95318   +11     
- Misses      50595    50597    +2     
  Partials     1732     1732           
Flag Coverage Δ
javascript 69.35% <70.58%> (+<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 #5cfb3b

Actionable Suggestions - 1
  • superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx - 1
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx - 1
Review Details
  • Files reviewed - 3 · Commit Range: 9667ae5..f03ff98
    • superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
    • superset-frontend/packages/superset-ui-core/src/components/Select/Select.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 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

@netlify

netlify Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 98b0c00
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a459ecdb9edc80008d0ffa6
😎 Deploy Preview https://deploy-preview-40984--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.

Comment thread superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx Outdated
@bito-code-review

bito-code-review Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #fc7932

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: f03ff98..f966a12
    • superset-frontend/packages/superset-ui-core/src/components/Select/Select.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 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 Jun 17, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #06e0bc

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: f966a12..7bec758
    • superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.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 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

@yousoph
yousoph requested a review from kgabryje June 19, 2026 04:46
@kgabryje

Copy link
Copy Markdown
Member

Thanks for the fix — the three-part approach (trim pasted tokens, surface typed values as creatable options for multi-select, and retain created values as chips) is solid, and reusing the existing allowNewOptions={!searchAllOptions && creatable !== false} gating keeps the new logic consistent. One thing I'd tighten before merge:

Type coercion in the created-value dedup

In the new block in the uniqueOptions memo (superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx):

if (creatable !== false && filterState.value) {
  const existing = new Set(allOptions);
  ensureIsArray(filterState.value)
    .filter(v => v !== null && v !== undefined && !existing.has(v))
    .forEach(v => {
      baseOptions.push({ label: String(v), value: String(v), isNewOption: true });
      existing.add(v);
    });
}

The dedup uses a strict Set.has(v) against the raw DB values, but then appends the value as String(v). For numeric columns that's inconsistent with the Select's own loose matching (hasOption) and can bite in two ways:

  1. Duplicate option — if the dataset has 10107 (number) but filterState.value holds "10107" (string), existing.has("10107") is false, so the same logical value gets re-added as a separate option.
  2. Type flip — a value that should resolve to the numeric option 10107 instead becomes an option with value: "10107", so the emitted filter (and select‑all) can end up carrying both the string and numeric variants.

Suggestion: dedup with the same loose helper this file already uses for the typed-search case, and preserve the original value type:

ensureIsArray(filterState.value)
  .filter(v => v != null && !hasOption(v, baseOptions, true))
  .forEach(v => {
    baseOptions.push({ label: String(v), value: v, isNewOption: true });
  });

Minor / non-blocking

It'd be good to add plugin-level tests for the new behaviors — multi-select typed creatable option display, creatable: false, searchAllOptions: true, created values from filterState.value rendering as chips, and the numeric string-vs-number case — plus an AsyncSelect trimming test to mirror the new Select.test.tsx one.

Otherwise looks good 👍

@pull-request-size pull-request-size Bot added size/L and removed size/M labels Jun 24, 2026
@bito-code-review

bito-code-review Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #207094

Actionable Suggestions - 0
Additional Suggestions - 2
  • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx - 1
    • Test missing interactivity assertion · Line 1671-1683
      The test 'renders created filterState values not in dataset as selectable chips' verifies the chip renders via `findByTitle`, but does not assert that the chip is functional (e.g., that the value can be submitted as a filter). Per adaptive rule 6262, test assertions should verify actual behavior — a chip that renders but cannot be selected would pass this test but fail the user's intent. Consider adding a click assertion or `toBeEnabled()` check to confirm the chip is interactive.
  • superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.test.tsx - 1
    • Test BDD anti-pattern · Line 401-418
      The test wraps all assertions inside `async () => {}` within `waitFor`, which is a BDD anti-pattern. The `waitFor` callback should be synchronous; async work should be awaited before entering `waitFor`. See pattern at line 381 in `Select.test.tsx` for the equivalent test that correctly places assertions outside `waitFor`. This affects test reliability and may cause intermittent failures.
      Code suggestion
      --- a/superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.test.tsx
      +++ b/superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.test.tsx
       @@ -408,11 +408,9 @@ test('trims whitespace from pasted comma-separated values', async () => {
          fireEvent(input, paste);
          await waitFor(async () => {
            const values = await findAllSelectValues();
            expect(values.length).toBe(4);
      -    expect(values[0]).toHaveTextContent('a');
      -    expect(values[1]).toHaveTextContent('b');
      -    expect(values[2]).toHaveTextContent('c');
      -    expect(values[3]).toHaveTextContent('d');
          });
      +  const values = await findAllSelectValues();
      +  expect(values).toHaveLength(4);
      +  values.forEach((_, i) => expect(values[i]).toHaveTextContent(String.fromCharCode(97 + i)));
        });
Review Details
  • Files reviewed - 3 · Commit Range: 7bec758..254cad0
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
    • superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.test.tsx
    • superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.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 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

@yousoph
yousoph force-pushed the fix-native-filter-creatable-default branch from 254cad0 to 2250cf9 Compare June 26, 2026 17:19
yousoph and others added 6 commits June 30, 2026 12:00
Three bugs prevented default values typed/pasted into a creatable
native filter from being stored and rendered correctly:

1. Paste tokenization did not trim whitespace, so "10107, 10121"
   split into ["10107", " 10121"] — the leading space caused label
   mismatch and stored wrong option values.

2. The options useMemo in SelectFilterPlugin guarded new-option
   injection with !multiSelect, so typed search terms never appeared
   as selectable options in multi-select mode.  Also fixed the
   mutation bug (unshift on a memoized array).

3. uniqueOptions excluded values from filterState.value that are not
   in the dataset (i.e., user-created values).  Added them back when
   creatable !== false so the Select can display them correctly.

Adds a test for the whitespace-trimming fix.
The options useMemo was missing the `creatable !== false` check after the
multi-select guard was removed, allowing new option entries to appear in
the dropdown even when creatable=false.

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

Auto-formatted by prettier: wrapped long lines in Select.tsx
and SelectFilterPlugin.tsx to satisfy the prettier pre-commit hook.
- Add !searchAllOptions guard to options useMemo so new-option injection
  matches the allowNewOptions prop (consistent behavior in remote-search mode)
- Apply paste trim/filter fix to AsyncSelect.tsx for consistency with
  the same fix already in Select.tsx

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

Per kgabryje's review: use hasOption() for loose matching instead of
Set.has() to avoid string/number duplicate options, and preserve the
original value type (value: v, not String(v)) so numeric filters don't
flip type when creatable defaults are restored.

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

- SelectFilterPlugin: multi-select creatable shows create option, searchAllOptions
  suppresses it, filterState created values render as chips, no duplicate chip
  when value already in dataset
- AsyncSelect: mirror Select.test.tsx whitespace-trim test for paste tokenizer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sadpandajoe
sadpandajoe force-pushed the fix-native-filter-creatable-default branch from 2250cf9 to 943c0a1 Compare June 30, 2026 19:00
Comment thread superset-frontend/src/filters/components/Select/SelectFilterPlugin.test.tsx Outdated
@bito-code-review

bito-code-review Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #4ce338

Actionable Suggestions - 0
Review Details
  • Files reviewed - 5 · Commit Range: a3a7c5f..98b0c00
    • superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.test.tsx
    • superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.tsx
    • superset-frontend/packages/superset-ui-core/src/components/Select/Select.test.tsx
    • 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 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

…etWrapper scope

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

@rusackas rusackas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM — confirmed both plugin bugs on master (the unshift into a memoized array and the !multiSelect guard), and the fold-back of filterState.value dedupes correctly via hasOption's loose comparison, so dropdown selection is unaffected. Test coverage on the create/paste/searchAllOptions paths is solid.

Tiny note: the PR body still describes a Select.tsx change that's already on master, so the description is a touch stale... cosmetic only.

@rusackas
rusackas merged commit e08c2c1 into apache:master Jul 4, 2026
66 checks passed
@rusackas
rusackas deleted the fix-native-filter-creatable-default branch July 4, 2026 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dashboard:native-filters Related to the native filters of the Dashboard packages size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants