Skip to content

feat(dashboard): chart customizations modal and plugins#36062

Merged
geido merged 20 commits into
apache:masterfrom
DamianPendrak:filters-and-customizations-modal
Jan 14, 2026
Merged

feat(dashboard): chart customizations modal and plugins#36062
geido merged 20 commits into
apache:masterfrom
DamianPendrak:filters-and-customizations-modal

Conversation

@DamianPendrak
Copy link
Copy Markdown
Member

@DamianPendrak DamianPendrak commented Nov 10, 2025

User description

SUMMARY

  1. Adds Chart Customizations to the "Edit filters" modal. Time Grain and Time Column moved from Filters to the Chart Customizations. Chart Customizations can now be added using plugins just like Filters. Continuation of feat(dashboard): chart customization/dynamic group by in dashboards #33831.
  2. Add deck.gl Layer Visibility chart customization - allows for hiding layers in Multi Layer Deck.gl Chart

Requirements for chart customizations:
Replace current structure (separate "Add filter" / "Add customization" / "Add divider" buttons)
With: Single dropdown button

  • Button label: "+ New" (secondary button)
  • Dropdown options:
    • Filter
    • Customization
    • Divider

Add collapsible sections (like dataset folders in Explore):

Section 1: Filters

  • Contains all filter items
  • User can reorder items within this section only

Section 2: Customization

  • Contains all customization controls:
  • Dynamic group by
  • Time column
  • Time grain
  • Hide layers (deck.gl)

User can reorder items within this section only
Important constraint: Customization controls cannot be moved to Filters section and vice versa

Screenshot 2025-11-19 at 17 37 02

Requirements for Deck.gl Layer Visibility customization:
BY DEFAULT IT’S A MULTISELECT

  • Functions as an inverse selection filter with multiselect field
  • By default, all available layers from deck.gl charts are displayed
  • User selects layers to exclude from charts
  • Shows tooltip on hover always for this typeomization settings)
  • Applies to all deck.gl Multiple Layer charts in the dashboard

Design and requirements for reordering layers:
Screenshot 2025-11-19 at 17 35 12

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Screenshot 2025-11-11 at 00 40 07 Screenshot 2025-11-19 at 12 33 36

TESTING INSTRUCTIONS

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

CodeAnt-AI Description

Unify configuration: edit filters and chart customizations in one modal and persist changes

What Changed

  • The Filters modal is redesigned to include two collapsible sections (Filters and Customization) with a sidebar and content pane so you can add and edit chart customizations (dynamic group by, time grain, deck.gl layer visibility) alongside native filters in the same place.
  • Chart customizations are rendered in the filter bar as filter-like controls (cards) — selecting a column or value updates a pending customization state, shows loading/errors while loading dataset columns, and can be required; these pending customization changes are applied together with filters when you click Apply.
  • Apply now persists pending chart customization changes to the dashboard and triggers chart updates; Clear All resets customization selections and can clear saved customization columns/data masks.
  • Deck.gl layer visibility is supported as a chart customization and the query schema includes visible_deckgl_layers so multi-layer deck.gl charts respect hidden layers chosen in customization.

Impact

✅ Configure filters and chart customizations from one modal
✅ Persist chart customization changes when applying filters
✅ Hide layers in multi-layer deck.gl charts from dashboard

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@korbit-ai
Copy link
Copy Markdown

korbit-ai Bot commented Nov 10, 2025

Korbit doesn't automatically review large (3000+ lines changed) pull requests such as this one. If you want me to review anyway, use /korbit-review.

@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented Nov 10, 2025

Bito Automatic Review Skipped - Large PR

Bito didn't auto-review this change because the pull request exceeded the line limit. No action is needed if you didn't intend for the agent to review it. Otherwise, to manually trigger a review, type /review in a comment and save.

@github-actions github-actions Bot added api Related to the REST API packages labels Nov 10, 2025
@dosubot dosubot Bot added change:frontend Requires changing the frontend dashboard:editmode Related to te Dashboard edit mode labels Nov 10, 2025
@codecov
Copy link
Copy Markdown

codecov Bot commented Nov 10, 2025

Codecov Report

❌ Patch coverage is 82.08955% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.12%. Comparing base (459b4cb) to head (295103b).
⚠️ Report is 41 commits behind head on master.

Files with missing lines Patch % Lines
superset/dashboards/api.py 66.66% 9 Missing ⚠️
superset/daos/dashboard.py 88.88% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #36062       +/-   ##
===========================================
+ Coverage        0   68.12%   +68.12%     
===========================================
  Files           0      645      +645     
  Lines           0    48297    +48297     
  Branches        0     5237     +5237     
===========================================
+ Hits            0    32904    +32904     
- Misses          0    14109    +14109     
- Partials        0     1284     +1284     
Flag Coverage Δ
hive 42.89% <28.35%> (?)
mysql 65.96% <82.08%> (?)
postgres 66.01% <82.08%> (?)
presto 46.47% <28.35%> (?)
python 67.91% <82.08%> (?)
sqlite 65.73% <82.08%> (?)
superset-extensions-cli 94.98% <ø> (?)
unit 100.00% <ø> (?)

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

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds Chart Customizations functionality to the dashboard filters modal, enabling users to configure chart-specific customizations (like Time Grain and Time Column) through a unified interface. The implementation includes a plugin-based architecture for extensibility.

Key Changes:

  • Backend API endpoints for chart customization CRUD operations
  • Unified filters/customizations modal with collapsible sections
  • Plugin system for chart customizations (Time Grain, Time Column, Dynamic GroupBy)
  • Redux state refactoring to consolidate filter and customization management

Reviewed Changes

Copilot reviewed 96 out of 99 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/unit_tests/dashboards/test_chart_customizations_dao.py Comprehensive unit tests for chart customization DAO operations
tests/integration_tests/dashboards/api_tests.py API integration tests for customization endpoints
superset/dashboards/api.py New PUT endpoint for chart customizations configuration
superset/daos/dashboard.py DAO method to update chart customizations in dashboard metadata
superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx Major refactor to support both filters and customizations
superset-frontend/src/dataMask/reducer.ts Enhanced data mask handling for chart customizations
Comments suppressed due to low confidence (3)

superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/state.ts:1

  • Comment line removed contains 'TODO' marker without resolution. If the hack is still present, the comment should remain; if resolved, ensure the code is clean.
    superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/GroupByFilterCard.tsx:400
  • Dataset columns are fetched every time the component renders or dependencies change. Consider memoizing the fetch result or lifting this data fetching to a higher level component to avoid redundant API calls when multiple GroupByFilterCard components use the same dataset.
    superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/GroupByFilterCard.tsx:388
  • Variable 'datasetSource' is of type date, object or regular expression, but it is compared to an expression of type null.

Comment thread superset/daos/dashboard.py Outdated
Comment on lines +435 to +436
if attributes:
metadata = json.loads(dashboard.json_metadata or "{}")
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

The method doesn't handle the case when attributes is None or empty dict. If attributes is None, the function will return updated_configuration which is undefined, causing an UnboundLocalError. Add validation at the start or initialize updated_configuration = [] before the if attributes: block.

Copilot uses AI. Check for mistakes.
Comment on lines 179 to 183
const [renderedFilters, setRenderedFilters] = useState<string[]>(
initialCurrentFilterId && isFilterId(initialCurrentFilterId)
? [initialCurrentFilterId]
: [],
);
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

[nitpick] The initialization logic for renderedFilters and renderedCustomizations is duplicated. Consider extracting this into a helper function or consolidating the logic to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
Comment on lines +122 to +127
const behaviors = useMemo(
() => [
isCustomization ? Behavior.ChartCustomization : Behavior.NativeFilter,
],
[isCustomization],
);
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

[nitpick] The behaviors array should be defined outside the component or as a constant map since it has only two possible values. Creating a new array on every render (even with useMemo) is unnecessary. Consider: const behaviors = isCustomization ? [Behavior.ChartCustomization] : [Behavior.NativeFilter];

Copilot uses AI. Check for mistakes.
Comment on lines +248 to +254
const customizationFilterId = (item as { id: string }).id;

// Only set metadata default if not already loaded from backend
const customization = item.customization as {
column?: string | string[];
defaultDataMask?: { filterState?: { value?: string[] } };
};
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

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

Multiple type assertions with as suggest the types are not well-defined. Consider defining proper TypeScript interfaces for chart customization items to avoid repeated type casting and improve type safety throughout the codebase.

Copilot uses AI. Check for mistakes.
@DamianPendrak DamianPendrak force-pushed the filters-and-customizations-modal branch from 651d3bb to a828844 Compare November 13, 2025 09:55
type: typeof ChartCustomizationType.ChartCustomization;
name: string;
filterType: string;
targets: [Partial<NativeFilterTarget>];
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.

Is this type correct? Is it really a single item in an array?

Comment on lines +74 to +82
useEffect(() => {
handleChange(defaultValue ?? []);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(defaultValue)]);

useEffect(() => {
handleChange(filterState.value ?? []);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(filterState.value)]);
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.

Can't we just include handleChange in the dependency array.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It causes infinite re-renders, and I couldn't find a quick solution. This code is from the existing Dynamic Group By feature

@DamianPendrak DamianPendrak force-pushed the filters-and-customizations-modal branch 2 times, most recently from 9b5e27f to d57d604 Compare November 19, 2025 10:22
@DamianPendrak DamianPendrak force-pushed the filters-and-customizations-modal branch 2 times, most recently from 69572e9 to ad67edc Compare November 19, 2025 15:21
mask => mask?.extraFormData?.visible_deckgl_layers !== undefined,
);

const visibleDeckLayersFromRedux =
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.

Can we optimize this with createSelector?

if (!visibleDeckLayers) {
visibleDeckLayers = (
formData.extra_form_data as ExtraFormData & {
visible_deckgl_layers?: number[];
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.

You created a similar type in QueryFormData.ts, can we use that?

@codeant-ai-for-open-source
Copy link
Copy Markdown
Contributor

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

Copy link
Copy Markdown
Member

@kgabryje kgabryje left a comment

Choose a reason for hiding this comment

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

LGTM

@codeant-ai-for-open-source
Copy link
Copy Markdown
Contributor

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 10, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit ca60282
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/696212b176228200081c80b4
😎 Deploy Preview https://deploy-preview-36062--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@codeant-ai-for-open-source
Copy link
Copy Markdown
Contributor

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@vmcs29
Copy link
Copy Markdown

vmcs29 commented Jan 13, 2026

Hi @DamianPendrak

I have validated this ticket. Looks good on my side.
Thank you!

Copy link
Copy Markdown
Member

@geido geido left a comment

Choose a reason for hiding this comment

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

QA and code review passed. Stamping as a code owner to unblock.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Related to the REST API change:frontend Requires changing the frontend dashboard:editmode Related to te Dashboard edit mode packages plugins size/XXL size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants