Skip to content

fix(dashboard): preserve native filter keys for dataset-less filters on save - #42898

Open
eschutho wants to merge 1 commit into
masterfrom
sc-116919-filter-time-native-filter-keys-stripped
Open

fix(dashboard): preserve native filter keys for dataset-less filters on save#42898
eschutho wants to merge 1 commit into
masterfrom
sc-116919-filter-time-native-filter-keys-stripped

Conversation

@eschutho

@eschutho eschutho commented Aug 7, 2026

Copy link
Copy Markdown
Member

SUMMARY

Saving any filter through the dashboard filter-configuration modal strips
several keys from the stored native_filter_configuration entry of native
filters that have no dataset — most notably Time Range (filter_time)
filters. filter_select filters are unaffected.

Problem

The modal's save path transforms each modified filter's form state into the
object written to json_metadata. It decides whether a value is an
in-progress form item (needs full serialization) or an already-saved filter
(pass-through) by checking for a dataset key:

function isFormInput(formInputs): formInputs is NativeFiltersFormItem {
  return 'dataset' in formInputs;
}

Filter types without a dataset control never populate a dataset field on
their form item (their plugin declares datasourceCount: 0, so the dataset
control is not rendered). Those form items are therefore misclassified as
already-saved filters and persisted verbatim. As a result the serialized
entry:

  • loses targets, defaultDataMask, and cascadeParentIds (built during the
    form → filter transform, which was skipped), and
  • gains form-only keys such as defaultValueQueriesData: null and a raw
    requiredFirst: {}.

Because the modal rewrites every modified entry, editing/renaming/reordering
any filter on the dashboard triggers this for the dataset-less filters.

Fix

Discriminate on the targets array instead of dataset. Every saved filter
carries a serialized targets array and no form item ever does, so
dataset-less filters now flow through the same serialization path as
dataset-backed ones. The change is limited to the affected entry — insertion
order and untouched entries are preserved.

TESTING INSTRUCTIONS

Automated: transformers/filterTransformer.test.ts covers a dataset-less
(filter_time) form item, a dataset-backed (filter_select) form item, and
an already-saved filter passed through from the config map. The first case
fails on master (missing targets) and passes with this change.

cd superset-frontend
npm run test -- src/dashboard/components/nativeFilters/FiltersConfigModal/transformers/filterTransformer.test.ts

Manual:

  1. Open a dashboard that has a Time Range native filter.
  2. GET /api/v1/dashboard/{id} and note the Time Range entry in
    result.json_metadata has targets, defaultDataMask, and
    cascadeParentIds.
  3. In the filter bar, edit filters, rename the Time Range filter, and save
    without changing anything else.
  4. GET /api/v1/dashboard/{id} again: only the name changes; the previously
    stripped keys are preserved. (Verify against the API response, not the
    Edit properties → JSON Metadata panel, which does not render the stored
    document.)

ADDITIONAL INFORMATION

  • Bugfix
  • Changes UI
  • Includes DB Migration
  • Introduces new feature or API

🤖 Generated with Claude Code

…on save

The filter-config modal's save transform discriminated between an
in-progress form item and an already-saved filter by checking for a
`dataset` key. Filter types without a dataset control (e.g. `filter_time`)
have no such key, so their form state was misclassified as an
already-saved filter and persisted verbatim. This dropped serialized keys
(`targets`, `defaultDataMask`, `cascadeParentIds`) and leaked form-only
keys (`defaultValueQueriesData`, raw `requiredFirst`) into the stored
`native_filter_configuration`.

Discriminate on the `targets` array instead, which every saved filter
carries and no form item does, so dataset-less filters are serialized
through the same path as dataset-backed ones.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bito-code-review

bito-code-review Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #669f52

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: d0a537c..d0a537c
    • superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/transformers/filterTransformer.test.ts
    • superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/transformers/filterTransformer.ts
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ 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

@dosubot dosubot Bot added the dashboard:native-filters Related to the native filters of the Dashboard label Aug 7, 2026
// dropping serialized keys such as `targets`, `defaultDataMask`, and
// `cascadeParentIds`, and leaking form-only keys such as
// `defaultValueQueriesData` and `requiredFirst`.
return !('targets' in formInputs);

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.

Suggestion: Using property presence alone makes legacy or partially migrated saved filters without a targets field look like form inputs. The dashboard metadata schema accepts arbitrary filter dictionaries, so such entries can reach this path; they will then be rebuilt by transformFormInput, replacing the saved object and discarding fields such as chartsInScope, tabsInScope, and any other persisted target-related data. Preserve the saved-filter path for legacy entries using an additional saved-filter discriminator or normalize missing targets before this check. [api mismatch]

Severity Level: Major ⚠️
- ❌ Editing legacy filters discards persisted configuration fields.
- ❌ Filter scope metadata can be lost during dashboard saves.
- ⚠️ Unknown future filter properties are not preserved.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/transformers/filterTransformer.ts
**Line:** 79:79
**Comment:**
	*Api Mismatch: Using property presence alone makes legacy or partially migrated saved filters without a `targets` field look like form inputs. The dashboard metadata schema accepts arbitrary filter dictionaries, so such entries can reach this path; they will then be rebuilt by `transformFormInput`, replacing the saved object and discarding fields such as `chartsInScope`, `tabsInScope`, and any other persisted target-related data. Preserve the saved-filter path for legacy entries using an additional saved-filter discriminator or normalize missing targets before this check.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. The original implementation relied on the presence of a dataset property to distinguish between form inputs and saved filters. This caused filters without a dataset (like filter_time) to be incorrectly identified as saved filters, leading to the loss of critical configuration fields during the transformation process.

The fix implemented in the PR correctly updates the isFormInput discriminator to check for the presence of the targets property instead. Since all saved filters are guaranteed to have a targets array, this is a reliable way to distinguish them from form inputs.

I have verified the changes in superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/transformers/filterTransformer.ts and the corresponding test cases in filterTransformer.test.ts. The implementation is correct and addresses the reported issue.

superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/transformers/filterTransformer.ts

function isFormInput(
  formInputs: NativeFilterFormOrSaved,
): formInputs is NativeFiltersFormItem {
  return !('targets' in formInputs);
}

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.38%. Comparing base (55af468) to head (d0a537c).

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42898      +/-   ##
==========================================
- Coverage   66.38%   66.38%   -0.01%     
==========================================
  Files        2857     2857              
  Lines      161163   161163              
  Branches    37074    37074              
==========================================
- Hits       106988   106982       -6     
- Misses      52153    52159       +6     
  Partials     2022     2022              
Flag Coverage Δ
javascript 73.19% <100.00%> (-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.

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 preset-io size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant