Skip to content

fix(native-filters): populate granularity_sqla from datasource main_dttm_col for time-range parent cascade#39894

Open
jtjenkins wants to merge 2 commits intoapache:masterfrom
jtjenkins:fix/native-filter-granularity-sqla-cascade
Open

fix(native-filters): populate granularity_sqla from datasource main_dttm_col for time-range parent cascade#39894
jtjenkins wants to merge 2 commits intoapache:masterfrom
jtjenkins:fix/native-filter-granularity-sqla-cascade

Conversation

@jtjenkins
Copy link
Copy Markdown

SUMMARY

When a native Date Range filter is configured as the parent of a Select (Value)
filter, the child filter's dropdown values should be constrained to the selected
date range. This has never worked correctly due to three bugs in FilterValue.tsx:

Bug 1 — Missing granularity_sqla: getFormData sends the parent's
time_range via extra_form_data to the child's column-values API request, but
sends no granularity_sqla. The backend receives the temporal constraint but has
no column to apply it to and silently returns all values. Upstream PR #34137 fixed
the timing (child requests now wait for parent values) but did not address the
missing column.

Bug 2 — Datasource not in Redux cache: The fix for Bug 1 reads main_dttm_col
from state.datasources, but /api/v1/dashboard/:id/datasets only returns datasets
used by chart slices. Native-filter-only datasets are never in state.datasources.
fetchDatasourceMetadata is now dispatched at mount time to populate the cache for
those datasets.

Bug 3 — Stale React closure: datasourceMainDttmCol was not in the main
useEffect dependency array. Filters with a default date range would fire their
effect before the async fetch completed and never re-run once the datasource loaded.

Changes

  • FilterValue.tsx: import fetchDatasourceMetadata
  • FilterValue.tsx: dispatch fetchDatasourceMetadata at mount when datasetId is
    set, populating state.datasources for filter-only datasets
  • FilterValue.tsx: read main_dttm_col from the cache via useSelector and use it
    as a fallback granularity_sqla when dependencies.time_range is set
  • FilterValue.tsx: add datasourceMainDttmCol to the main useEffect dep array

TESTING INSTRUCTIONS

  1. Create a dashboard with no charts (so no datasets are loaded via the slice API)
  2. Add a Time range native filter (parent)
  3. Add a Value native filter targeting a dataset that has a main_dttm_col (e.g.
    birth_names), with the Time range filter set as its parent
  4. Without a date range set: the Value filter shows all options
  5. Set a date range that contains no data in the dataset: Value filter shows "No data"
  6. Set a date range that contains a subset of the data: Value filter shows only the
    matching options
  7. Clear the date range: Value filter restores all options

ADDITIONAL INFORMATION

@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented May 5, 2026

Code Review Agent Run #89855e

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 8b50b04..8b50b04
    • superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.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

@dosubot dosubot Bot added the dashboard:native-filters Related to the native filters of the Dashboard label May 5, 2026
Comment on lines +205 to +209
useEffect(() => {
if (datasetId != null) {
dispatch(fetchDatasourceMetadata(`${datasetId}__table`));
}
}, [datasetId, dispatch]);
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: Dispatching metadata fetch on mount without in-flight deduplication can trigger concurrent duplicate requests when multiple filters use the same dataset and mount together. Each instance sees an empty cache and fires its own request, causing avoidable API load and possible last-write-wins state churn; guard this with request deduplication (or a shared loading flag) before dispatching. [race condition]

Severity Level: Minor 🧹
- ⚠️ Extra GETs to /superset/fetch_datasource_metadata per shared dataset.
- ⚠️ Slightly slower dashboard load for filter-only datasets.
- ⚠️ Unnecessary backend load when many filters share one dataset.
Steps of Reproduction ✅
1. Open a dashboard that uses multiple native filters all pointing to the same dataset ID
(each filter's config provides the same `datasetId` in its `targets`), so multiple
`FilterControl` instances render. These controls render `FilterValue` from
`src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx:20-34`,
which in turn mounts multiple `FilterValue` components.

2. When each `FilterValue` mounts, its `useEffect` at `FilterValue.tsx:205-209` runs, and
for each instance with a non-null `datasetId` it dispatches
`fetchDatasourceMetadata(\`${datasetId}__table\`)` via `dispatch`.

3. The thunk `fetchDatasourceMetadata` is defined in
`src/dashboard/actions/datasources.ts:16-28`. It checks `getState().datasources[key]`, and
if the entry is missing it calls `SupersetClient.get({ endpoint:
\`/superset/fetch_datasource_metadata?datasourceKey=${key}\` })` without tracking
in-flight requests.

4. Because each `FilterValue` instance calls `dispatch(fetchDatasourceMetadata(...))` in a
separate effect but before any of the network calls resolve and populate
`state.datasources[key]`, all of them see an empty cache and issue parallel GET requests
to `/superset/fetch_datasource_metadata?datasourceKey=${datasetId}__table`. This results
in duplicate metadata fetches for the same dataset but does not cause functional race
conditions, since each response ultimately dispatches `setDatasource` with the same
payload.

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/FilterBar/FilterControls/FilterValue.tsx
**Line:** 205:209
**Comment:**
	*Race Condition: Dispatching metadata fetch on mount without in-flight deduplication can trigger concurrent duplicate requests when multiple filters use the same dataset and mount together. Each instance sees an empty cache and fires its own request, causing avoidable API load and possible last-write-wins state churn; guard this with request deduplication (or a shared loading flag) before dispatching.

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

Yes, the suggestion is valid — the race condition can occur when multiple FilterValue components mount simultaneously, each dispatching fetchDatasourceMetadata without deduplication, leading to duplicate API requests. To resolve this, modify the fetchDatasourceMetadata thunk in src/dashboard/actions/datasources.ts to track in-flight requests using a module-level Map. There are no other comments on this PR.

superset-frontend/src/dashboard/actions/datasources.ts

const pendingFetches = new Map();

export const fetchDatasourceMetadata = (key) => (dispatch, getState) => {
  if (getState().datasources[key]) return;
  if (pendingFetches.has(key)) return;
  const promise = SupersetClient.get({ endpoint: `/superset/fetch_datasource_metadata?datasourceKey=${key}` })
    .then(data => {
      dispatch(setDatasource(key, data));
      pendingFetches.delete(key);
    })
    .catch(() => pendingFetches.delete(key));
  pendingFetches.set(key, promise);
};

…quests

When multiple FilterValue components share the same datasetId and mount
simultaneously, each sees an empty Redux cache and dispatches
fetchDatasourceMetadata. The thunk already short-circuits once the
datasource is cached, but has no guard for concurrent in-flight requests.

Add a module-level Set to track keys currently being fetched so that
parallel dispatches for the same key skip the network call. The Set entry
is cleared on both success and error so a failed request can be retried.

Addresses review feedback on the FilterValue granularity_sqla fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented May 5, 2026

Code Review Agent Run #e7c400

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 8b50b04..b582c8a
    • superset-frontend/src/dashboard/actions/datasources.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

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 size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant