Skip to content

feat(chart): enable cross-filter on x-axis labels for bar, line, area and scatter charts - #41111

Merged
rusackas merged 14 commits into
apache:masterfrom
reveha:feat/xaxis-label-cross-filter
Jun 24, 2026
Merged

feat(chart): enable cross-filter on x-axis labels for bar, line, area and scatter charts#41111
rusackas merged 14 commits into
apache:masterfrom
reveha:feat/xaxis-label-cross-filter

Conversation

@reveha

@reveha reveha commented Jun 16, 2026

Copy link
Copy Markdown
Contributor
  • Add QueryEventHandlers type to support query-based ECharts event registration
  • Extend Echart.tsx wrapper to support chart.on(event, query, handler) pattern
  • Add handleXAxisLabelClick handler in EchartsTimeseries.tsx to capture x-axis label clicks and emit cross-filter via existing handleXAxisChange
  • Add triggerEvent: true to xAxis config in transformProps.ts when axis type is categorical and no dimensions are set

Closes #25334

… and scatter charts

- Add QueryEventHandlers type to support query-based ECharts event registration
- Extend Echart.tsx wrapper to support chart.on(event, query, handler) pattern
- Add handleXAxisLabelClick handler in EchartsTimeseries.tsx to capture x-axis label clicks and emit cross-filter via existing handleXAxisChange
- Add triggerEvent: true to xAxis config in transformProps.ts when axis type is categorical and no dimensions are set

Closes apache#25334
@bito-code-review

bito-code-review Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #6c2f19

Actionable Suggestions - 0
Additional Suggestions - 2
  • superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx - 1
    • Missing test coverage for queryEventHandlers · Line 205-208
      The `queryEventHandlers` implementation correctly uses ECharts' query-based event binding (`on(name, query, handler)`), but there are no unit tests verifying this behavior. The `Echart.test.tsx` mock doesn't capture query-based event calls, and `EchartsTimeseries.test.tsx` doesn't verify the x-axis label click cross-filter functionality.
  • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts - 1
    • Missing test for triggerEvent · Line 892-895
      The new `triggerEvent: true` behavior for category axes without groupBy lacks unit test coverage. The existing test at line 1542 only asserts `xAxis.type === AxisType.Category` but does not verify the `triggerEvent` property. Per rule [6262], tests should verify actual business logic behavior, not just component structure.
Review Details
  • Files reviewed - 4 · Commit Range: 830e954..830e954
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts
    • superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx
    • superset-frontend/plugins/plugin-chart-echarts/src/types.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 change:frontend Requires changing the frontend closes-issue explore:filter Related to filters in Explore viz:charts:echarts Related to Echarts labels Jun 16, 2026
@netlify

netlify Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 4ed7a72
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a3a687654301c0008ada739
😎 Deploy Preview https://deploy-preview-41111--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. In Echart.tsx, the useEffect hook re-binds query listeners on every render where queryEventHandlers changes. Because chartRef.current?.off(name, handler) is called with the current handler instance, if the handler was recreated (e.g., due to dependency changes in useCallback), the previous handler remains registered, leading to multiple event triggers.

To resolve this, you should clear all query listeners for the specific event name before re-binding, or ensure the handler reference is stable. A minimal fix is to use chartRef.current?.off(name) without the handler argument to remove all listeners for that event name before re-binding:

(queryEventHandlers || []).forEach(({ name, query, handler }) => {
  chartRef.current?.off(name);
  chartRef.current?.on(name, query, handler);
});

This ensures that any previously registered handlers for that event name are cleared, preventing duplicate triggers.

superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx

(queryEventHandlers || []).forEach(({ name, query, handler }) => {
        chartRef.current?.off(name);
        chartRef.current?.on(name, query, handler);
      });

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

bito-code-review Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #8b840e

Actionable Suggestions - 0
Filtered by Review Rules

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

  • superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx - 1
Review Details
  • Files reviewed - 2 · Commit Range: 830e954..048d27f
    • superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.test.tsx
    • superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.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

Comment thread superset-frontend/plugins/plugin-chart-echarts/src/types.ts Outdated
Comment on lines +340 to +349
const queryEventHandlers = useMemo(
() => [
{
name: 'click',
query: 'xAxis.category',
handler: handleXAxisLabelClick,
},
],
[handleXAxisLabelClick],
);

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: The query event is hardcoded to xAxis.category, so horizontal charts (where categorical labels are rendered on yAxis after axis swap) will never emit this handler. As a result, label-click cross-filter silently fails for horizontal bar configurations. Register the query dynamically based on chart orientation/actual categorical axis (e.g., yAxis.category for horizontal mode). [incorrect condition logic]

Severity Level: Major ⚠️
- ❌ Horizontal bar chart axis-label clicks emit no cross-filters.
- ⚠️ Generic Chart horizontal layouts lose label-driven filtering.
Steps of Reproduction ✅
1. In Explore, create a Bar Chart using the ECharts timeseries bar plugin, which is wired
to `EchartsTimeseries` via `loadChart: () => import('../../EchartsTimeseries')` in
`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts:8-25`.

2. In the Bar Chart control panel, set orientation to Horizontal (control wired through
`orientation` in `DEFAULT_FORM_DATA` and `OrientationType.Horizontal` usage in
`controlPanel.tsx:54-69`), and configure no groupby dimensions so `groupBy.length === 0`
and the x-axis is categorical, causing `canCrossFilterByXAxis` to be true in
`EchartsTimeseries`
(`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx:98-218`).

3. When the chart renders, `transformProps` builds a categorical axis and, after handling
orientation and axis swapping, returns the logical axis metadata `{ label: xAxisLabel,
type: xAxisType }` as `xAxis` in the transformed props (`transformProps.ts:188-196` and
return at `transformProps.ts:73-92`), while `EchartsTimeseries` installs
`queryEventHandlers` with `query: 'xAxis.category'` at `EchartsTimeseries.tsx:340-345` and
passes them to the `Echart` wrapper, which calls `chartRef.current?.on(name, query,
handler)` (`components/Echart.tsx:204-216`).

4. For horizontal charts, the categorical axis is rendered as `yAxis` after the swap in
`transformProps` (`transformProps.ts:79-81`), so axis label clicks are emitted with
`componentType: 'yAxis'`; because the handler is hardcoded to `query: 'xAxis.category'`,
ECharts never dispatches these label-click events to `handleXAxisLabelClick`,
`handleXAxisChange` is never called, and `setDataMask(getXAxisCrossFilterDataMask(...))`
at `EchartsTimeseries.tsx:205-211` is never invoked—clicking categorical labels in
horizontal charts does nothing and no cross-filter is emitted.

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/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
**Line:** 340:349
**Comment:**
	*Incorrect Condition Logic: The query event is hardcoded to `xAxis.category`, so horizontal charts (where categorical labels are rendered on `yAxis` after axis swap) will never emit this handler. As a result, label-click cross-filter silently fails for horizontal bar configurations. Register the query dynamically based on chart orientation/actual categorical axis (e.g., `yAxis.category` for horizontal mode).

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
👍 | 👎

Abdullah Sahin and others added 2 commits June 17, 2026 18:25
- Type query event handlers with ECharts event payloads instead of any
- Register axis-label click handlers against the rendered categorical axis
  so horizontal bar charts use yAxis.category
- Add regression coverage for vertical vs horizontal query event binding
- Assert categorical axes enable triggerEvent for label click handling
@bito-code-review

bito-code-review Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #bd5bbe

Actionable Suggestions - 0
Review Details
  • Files reviewed - 4 · Commit Range: 048d27f..4c235db
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.test.tsx
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
    • superset-frontend/plugins/plugin-chart-echarts/src/types.ts
    • superset-frontend/plugins/plugin-chart-echarts/test/Timeseries/transformProps.test.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

Comment thread superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx Outdated
@bito-code-review

bito-code-review Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #bb691b

Actionable Suggestions - 0
Review Details
  • Files reviewed - 3 · Commit Range: 4c235db..910eab7
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.test.tsx
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
    • superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.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

@rusackas
rusackas requested review from EnxDev and rusackas June 22, 2026 17:30
@rusackas rusackas added the review:checkpoint Last PR reviewed during the daily review standup label Jun 22, 2026

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

Nice work, @reveha, LGTM. The horizontal yAxis.category swap and the query-listener cleanup both look right, and the new Echart.test.tsx covers the stale-handler case well. Thanks!

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Translation Regression Detected

A source change in this PR renamed or reworded strings, invalidating existing translations (they are now #, fuzzy) in fi, it, ko, th. Please resolve the affected .po files before merging.

Note: intentionally deleting a translatable string is not a regression and is not flagged here — only translations invalidated by a renamed/reworded source string are.

Language Fuzzy before Fuzzy after New
fi 4815 4817 +2
it 1665 1667 +2
ko 1519 1521 +2
th 4815 4817 +2

How to fix

1. Install dependencies (if not already set up):

pip install -r superset/translations/requirements.txt
sudo apt-get install gettext   # or: brew install gettext

2. Re-extract strings and sync .po files:

./scripts/translations/babel_update.sh

This rewrites superset/translations/messages.pot from the current source files and merges the changes into every .po file. Strings whose msgid changed will be marked #, fuzzy.

3. Resolve the fuzzy entries in the affected language files (fi, it, ko, th):

grep -n '#, fuzzy' superset/translations/<lang>/LC_MESSAGES/messages.po

For each fuzzy entry, either rewrite the msgstr to match the new string and remove the #, fuzzy line, or clear the msgstr to "" if you cannot provide a translation.

4. Commit your changes to the .po files.

@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.78%. Comparing base (b94f90e) to head (0e5facf).
⚠️ Report is 34 commits behind head on master.

Files with missing lines Patch % Lines
...chart-echarts/src/Timeseries/EchartsTimeseries.tsx 87.50% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #41111      +/-   ##
==========================================
- Coverage   64.36%   63.78%   -0.59%     
==========================================
  Files        2653     2653              
  Lines      144965   145001      +36     
  Branches    33437    33455      +18     
==========================================
- Hits        93305    92483     -822     
- Misses      49974    50834     +860     
+ Partials     1686     1684       -2     
Flag Coverage Δ
javascript 68.62% <90.00%> (+<0.01%) ⬆️
mysql ?
unit ?

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.

Comment on lines +226 to +230
const getCategoryAxisValue = useCallback(
(data: unknown) =>
Array.isArray(data) ? data[categoryAxisValueIndex] : undefined,
[categoryAxisValueIndex],
);

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: The category extractor assumes event data is always an array, but ECharts often sends point objects like { value: [...] } (for example when color-by-primary-axis or styled points are used). In those cases this returns undefined, so point-click and context-menu cross-filtering silently stop working even though the chart is categorical. Read from both array data and object value payloads (or use the event name) so category extraction works across all ECharts payload shapes. [api mismatch]

Severity Level: Major ⚠️
- ❌ Color-by-primary-axis timeseries charts can't emit cross-filters.
- ❌ Context-menu X-axis cross-filter fails with styled point objects.
Steps of Reproduction ✅
1. Open Explore with the "Generic Chart" (Echarts timeseries) viz, which is wired via
`EchartsTimeseriesChartPlugin` in
`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts` and uses
`transformProps` + `EchartsTimeseries.tsx` for rendering.

2. Configure a categorical X-axis with no groupby (so `hasDimensions` is false and
`xAxis.type === AxisType.Category`), enable cross-filtering, set series type to bar, and
enable `colorByPrimaryAxis` (all handled in `transformProps` at
`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts`).

3. With `colorByPrimaryAxis` enabled, `transformSeries` in
`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformers.ts` replaces
each raw `[x, y]` tuple with an object `{ value: [x, y], itemStyle: … }` via
`applyColorByPrimaryAxis` (see `transformNegativeLabelsPosition` and
`applyColorByPrimaryAxis` around lines ~145–55 and ~179–55 in that file), so ECharts click
events deliver `props.data` as an object instead of an array.

4. Click any bar: `eventHandlers.click` in `EchartsTimeseries.tsx` (around lines 233–247)
calls `getCategoryAxisValue(props.data)` (lines 226–230), which only handles
`Array.isArray(data)` and returns `undefined` for the `{ value: [...] }` object; the
subsequent type guard fails, `handleXAxisChange` is never called, and no X-axis
cross-filter is emitted even though `canCrossFilterByXAxis` is true—confirming the bug
that object-shaped event payloads break categorical cross-filtering.

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/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
**Line:** 226:230
**Comment:**
	*Api Mismatch: The category extractor assumes event `data` is always an array, but ECharts often sends point objects like `{ value: [...] }` (for example when color-by-primary-axis or styled points are used). In those cases this returns `undefined`, so point-click and context-menu cross-filtering silently stop working even though the chart is categorical. Read from both array data and object `value` payloads (or use the event `name`) so category extraction works across all ECharts payload shapes.

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
👍 | 👎

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this. I updated the category extractor to read the orientation-specific array value first, and fall back to the ECharts event name when the payload is not an array or does not contain a string/number category value. This keeps the horizontal bar fix while preserving category cross-filtering for other ECharts payload shapes.

@bito-code-review

bito-code-review Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #ff2737

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 910eab7..b9e4272
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.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

Comment on lines +237 to +238
if (typeof name === 'string' || typeof name === 'number') {
return name;

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: Falling back to name without checking event source can convert non-category interactions (for example legend/component clicks that also carry a string name) into X-axis filters, producing incorrect filter values for the X-axis column. Only use name when the event is known to come from category-axis label clicks (or series points with verified category payload), otherwise ignore it. [logic error]

Severity Level: Major ⚠️
- ❌ Legend clicks can apply incorrect X-axis filters.
- ⚠️ Users see unexpected filters after legend toggles.
Steps of Reproduction ✅
1. Use an ECharts timeseries chart with no `groupby` and a categorical X-axis (`xAxis.type
=== AxisType.Category`), so `hasDimensions` is false and `canCrossFilterByXAxis` is true
as defined in
`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx:221-223`.
Cross-filtering is enabled via `emitCrossFilters` and `setDataMask` from
`CrossFilterTransformedProps` in
`superset-frontend/plugins/plugin-chart-echarts/src/types.ts:156-163`.

2. At render time, `Echart` registers a generic `click` handler for all chart clicks at
`superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx:90-93`, wiring
it to `eventHandlers.click` defined in `EchartsTimeseries.tsx:246-271`. The same
`eventHandlers` object also registers legend-related handlers (`legendselectchanged`,
`legendselectall`, `legendinverseselect`) at lines 281-289, indicating legend interactions
are part of this chart's behavior.

3. When the user clicks a legend item representing a metric (for example, legend entry
"Sales"), ECharts emits a `click` event for the legend component with a string `name` (the
series name) alongside legend-select events; this `click` is handled by the generic
`eventHandlers.click` registered in `Echart.tsx:90-93`. Because `hasDimensions` is false
and `canCrossFilterByXAxis` is true, the handler's timer branch in
`EchartsTimeseries.tsx:16-31` takes the `else if (canCrossFilterByXAxis)` path at line 21.

4. Inside that branch, `getCategoryAxisValue(props.data, props.name)` is called at lines
23-26; for a legend click, `props.data` is not an X-axis tuple (often undefined), while
`props.name` is the legend label "Sales". Since `Array.isArray(data)` is false,
`getCategoryAxisValue` falls through to the unscoped fallback at lines 237-238 (`if
(typeof name === 'string' || typeof name === 'number') { return name; }`), returning
`"Sales"` even though it is not an X-axis category value. The handler then calls
`handleXAxisChange(categoryAxisValue)` at line 27, which invokes
`setDataMask(getXAxisCrossFilterDataMask(xAxisValue).dataMask)` at lines 211-217, building
a filter on the X-axis column (`xAxis.label`) with value `"Sales"` via
`getXAxisCrossFilterDataMask` at lines 163-197. This produces an incorrect X-axis filter
derived from a legend interaction rather than a real category, so legend clicks can
unintentionally drive X-axis cross-filters with invalid values.

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/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
**Line:** 237:238
**Comment:**
	*Logic Error: Falling back to `name` without checking event source can convert non-category interactions (for example legend/component clicks that also carry a string `name`) into X-axis filters, producing incorrect filter values for the X-axis column. Only use `name` when the event is known to come from category-axis label clicks (or series points with verified category payload), otherwise ignore it.

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
👍 | 👎

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i didint change anything on the file, yesterday you approved my commit now seeing new issue?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I just changed the test file to make test build sucess

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.

Yes — this can happen even if you didn’t change that file.

What likely happened is:

  • A new review pass ran after your commit was already approved.
  • The reviewer/tool is now flagging a previously unnoticed edge case in the same logic.
  • So it’s not necessarily a regression from your latest change; it may just be a newly detected issue in the existing implementation.

In this case, the concern is valid: the fallback to name can accidentally treat non-x-axis clicks like legend/component clicks as if they were category clicks, which could create wrong cross-filters.

A safer fix is to only accept name when the event is known to come from the category axis click path, and otherwise ignore it.

For example, make the fallback more restrictive:

const getCategoryAxisValue = useCallback(
  (data: unknown, name: unknown) => {
    if (Array.isArray(data)) {
      const categoryAxisValue = data[categoryAxisValueIndex];
      if (
        typeof categoryAxisValue === 'string' ||
        typeof categoryAxisValue === 'number'
      ) {
        return categoryAxisValue;
      }
    }

    return undefined;
  },
  [categoryAxisValueIndex],
);

Since handleXAxisLabelClick already handles the axis-label click case using event.value, this removes the risky fallback while keeping the intended cross-filter behavior.

So in short: you didn’t necessarily “change” the issue; it was just newly surfaced by review.
If you want, I can also help apply the minimal fix for this comment and check the rest of the PR comments too.

Comment on lines +260 to +268
} else if (canCrossFilterByXAxis) {
// Cross-filter by X-axis value when no dimensions (issue #25334)
const categoryAxisValue = getCategoryAxisValue(
props.data,
props.name,
);
if (categoryAxisValue !== undefined) {
handleXAxisChange(categoryAxisValue);
}

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: The generic click handler now triggers X-axis cross-filtering for any click event when there are no dimensions, including axis-label clicks that are also handled by queryEventHandlers. This causes duplicate setDataMask updates for a single user action and can trigger redundant dashboard re-filter/query cycles. Restrict this branch to series data clicks (or skip axis component clicks) so axis-label clicks are handled only once by the query-based handler. [performance]

Severity Level: Major ⚠️
- ❌ Duplicate cross-filter queries on X-axis label clicks.
- ⚠️ Increased dashboard latency from redundant filter updates.
Steps of Reproduction ✅
1. Create or open an ECharts timeseries chart (plugin registered at
`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/index.ts:34-43`) with no
`groupby` (so `hasDimensions` is false) and a categorical X-axis (`xAxis.type ===
AxisType.Category`), which satisfies `canCrossFilterByXAxis` in
`EchartsTimeseries.tsx:221-223`.

2. Observe that `transformProps` enables axis-level click events for this configuration by
setting `triggerEvent: true` when `xAxisType === AxisType.Category && groupBy.length ===
0` in
`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:13-16`
(shown via `Read`), so X-axis labels emit `click` events.

3. When the chart renders, `Echart` registers both the generic click handler and the
query-based click handler: `chartRef.current?.on(name, handler)` for `eventHandlers` in
`superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx:90-93`, and
`chartRef.current?.on(name, query, handler)` for `queryEventHandlers` in
`Echart.tsx:95-97`, using the handlers defined in `EchartsTimeseries.tsx`
(`eventHandlers.click` at lines 246-271 and `queryEventHandlers` at 385-393).

4. Clicking an X-axis category label (e.g., "Product A") causes ECharts to fire a `click`
event on the axis label, which matches both the generic `click` listener and the filtered
`click` listener with query `${categoryAxis}.category`. The generic handler in
`EchartsTimeseries.tsx:246-271` enters the `else if (canCrossFilterByXAxis)` branch at
line 260, computes a category value via `getCategoryAxisValue(props.data, props.name)` at
lines 262-265, and calls `handleXAxisChange(categoryAxisValue)` at line 267, which in turn
calls `setDataMask(getXAxisCrossFilterDataMask(xAxisValue).dataMask)` at lines 211-217.
Independently, the query-based handler `handleXAxisLabelClick` registered in
`queryEventHandlers` at lines 369-393 receives the same axis-label `click` as an
`ECElementEvent` and calls `handleXAxisChange(event.value)` at lines 370-377. As a result,
a single axis-label click triggers `handleXAxisChange` twice, and thus `setDataMask`
twice, causing duplicate cross-filter updates and redundant downstream queries.

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/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
**Line:** 260:268
**Comment:**
	*Performance: The generic `click` handler now triggers X-axis cross-filtering for any click event when there are no dimensions, including axis-label clicks that are also handled by `queryEventHandlers`. This causes duplicate `setDataMask` updates for a single user action and can trigger redundant dashboard re-filter/query cycles. Restrict this branch to series data clicks (or skip axis component clicks) so axis-label clicks are handled only once by the query-based handler.

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
👍 | 👎

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i didint change anything on the file, yesterday you approved my commit now seeing new issue?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I just changed the test file to make test build sucess

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.

Yes — that can happen even if you didn’t change the file.

Why you’re seeing a new issue now

  • The code itself didn’t change, but the review context/tooling may have.
  • This PR now registers both:
    • the generic click handler, and
    • the new queryEventHandlers for axis-label clicks.
  • Because of that, a single x-axis label click can hit both paths, which means setDataMask may fire twice.

So was the comment correct?

Yes, the flagged issue is valid in the current diff.

Minimal fix

You should make sure the generic click handler only handles series/data clicks, and let axis-label clicks be handled only by the query-based handler.

For example, in EchartsTimeseries.tsx, tighten the generic branch so it skips axis label events:

click: props => {
  if (!hasDimensions && !canCrossFilterByXAxis) {
    return;
  }

  if (clickTimer.current) {
    clearTimeout(clickTimer.current);
  }

  clickTimer.current = setTimeout(() => {
    if (hasDimensions) {
      const { seriesName: name } = props;
      handleChange(name);
    } else if (canCrossFilterByXAxis && props.componentType === 'series') {
      const categoryAxisValue = getCategoryAxisValue(props.data, props.name);
      if (categoryAxisValue !== undefined) {
        handleXAxisChange(categoryAxisValue);
      }
    }
  }, TIMER_DURATION);
},

That keeps:

  • series clicks → generic handler
  • axis-label clicks → query handler only

Conclusion

So no, this doesn’t mean you changed something yesterday — it means the new cross-filter behavior exposed a duplicate path that the review caught now. If you want, I can also help check the rest of the PR comments and validate whether any others need fixes.

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.

Customized review instruction saved!

Instruction:

Avoid flagging production-performance or architecture issues in test files; scope these reviews to production code, not test-only changes.

Applied to:

  • **/test/**
  • **/tests/**
  • **/*test*.<ext>

💡 To manage or update this instruction, visit: CodeAnt AI Settings

@rusackas

Copy link
Copy Markdown
Member

LGTM, thanks for seeing this through! Happy it made it across the finish line :D

@rusackas
rusackas merged commit 8f22b71 into apache:master Jun 24, 2026
70 checks passed
@bito-code-review

Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped – PR Already Merged

Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.
No action is needed if you didn't intend to review it. To get a review, you can type /review in a comment and save it

shantanukhond pushed a commit to shantanukhond/superset that referenced this pull request Jun 24, 2026
… and scatter charts (apache#41111)

Co-authored-by: Abdullah Sahin <you@example.comclear>
@sadpandajoe sadpandajoe removed the review:checkpoint Last PR reviewed during the daily review standup label Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:frontend Requires changing the frontend closes-issue explore:filter Related to filters in Explore plugins size/XL viz:charts:echarts Related to Echarts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bar chart does not emit cross-filter if dimension is not set

3 participants