Skip to content

Conversation

@JayHealth
Copy link

@JayHealth JayHealth commented Jan 5, 2026

User description

SUMMARY

Makes it so that right clicking and using drill by on a bar in the bar chart, actually drills into that particular bar, replacing the x-axis of the bart chart, with what was selected as the drill by value. This is how drill-by functionality works in similar programs.

SCREENSHOTS OF HOW IT WORKS:

Screenshot 2025-12-17 at 15 54 54 Screenshot 2025-12-17 at 15 55 15 Screenshot 2025-12-17 at 15 55 29

TESTING INSTRUCTIONS

On a bar chart, right click a column and select a category. A pop up window will appear where the result is visible.

ADDITIONAL INFORMATION

  • Has associated issue: Bar chart drill-by should subset data #36766 (not exactly an issue, but I'm not sure how discussion turns into issues in this community)
  • 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

Drill-by focuses timeseries bar: replace x-axis and apply precise filters

What Changed

  • Right-click drill-by on a timeseries bar now targets the specific bar value instead of a generic series: the chart builds filters for the clicked x value and, for time axes, a precise temporal range covering that bucket.
  • When drilling from the modal into the "echarts_timeseries_bar" viz, the chart's x-axis is replaced with the selected drill column and the chart groups by that column (x-axis set categorical), so the drilled view shows only the chosen dimension.
  • Drill payloads now include a TEMPORAL_RANGE filter for time-granularity bars (start : end) when the x value is a timestamp, improving accuracy of downstream filters.

Impact

✅ Drill into a specific bar
✅ Temporal-range filters for time-based bars
✅ X-axis updated to drilled dimension for bar charts

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

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

CodeAnt AI is reviewing your PR.


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

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Jan 5, 2026

Code Review Agent Run #9c4206

Actionable Suggestions - 0
Additional Suggestions - 2
  • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx - 1
    • Approximate Time Grain Calculations · Line 222-226
      The time grain calculations for MONTH (31 days), QUARTER (93 days), and YEAR (372 days) are approximations that don't match actual calendar periods. This could lead to incorrect drill-down ranges when users click on time series data points. Consider using proper date manipulation libraries or calendar functions to calculate exact start/end times for these grains.
  • superset-frontend/src/components/Chart/DrillBy/DrillByModal.tsx - 1
    • Incorrect adhoc groupby labels in drill-by · Line 377-385
      The adhoc groupby object for echarts_timeseries_bar drill-by uses incorrect labels with a ' (label)' suffix, which may display poorly. Based on the breadcrumb code that uses `column.verbose_name || column.column_name` for display, the label should match this pattern for consistency.
Review Details
  • Files reviewed - 2 · Commit Range: c50ad65..c50ad65
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
    • superset-frontend/src/components/Chart/DrillBy/DrillByModal.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

@codeant-ai-for-open-source codeant-ai-for-open-source bot added the size:M This PR changes 30-99 lines, ignoring generated files label Jan 5, 2026
@codeant-ai-for-open-source
Copy link
Contributor

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Wrong groupby field
    The new code unconditionally writes to updatedFormData.groupby when applying the timeseries-bar drill-by. Many visualizations use a different groupby field name (the code already tracks groupbyFieldName). Writing to the literal groupby key can leave the actual groupby field unchanged, causing the drill-by to be ignored or produce unexpected results. The change should update the proper groupby field name and follow the same shape (string vs array) that the chart expects.

  • Groupby value shape mismatch
    The implementation builds and assigns an object-style groupby entry (with sqlExpression, expressionType, etc.). However, existing formData may expect a simple string or an array of strings for groupby. This mismatch in shape can break downstream logic that reads formData[groupbyFieldName]. Ensure the shape you assign matches the expected type for that field.

  • Possible undefined access
    The code accesses data[0] in several places (including when building xAxisDrillByFilter and pushing drillToDetailFilters) without a defensive check that data and data[0] exist. If eventParams.data is undefined or an empty array this will produce filters with undefined values (or formatted "undefined"), causing confusing or invalid drill filters. Consider guarding these accesses and skipping/adjusting filter creation when data is absent.

  • Timegrain mapping fallback
    The code uses TIMEGRAIN_TO_TIMESTAMP[formData.timeGrainSqla as keyof typeof TIMEGRAIN_TO_TIMESTAMP] and falls back to TIMEGRAIN_TO_TIMESTAMP[TimeGranularity.DAY]. If formData.timeGrainSqla is unexpected or missing, or TIMEGRAIN_TO_TIMESTAMP doesn't include a matching key, the fallback works but the resulting temporal range might be incorrect for the intended granularity. Also, using new Date(...).toISOString() may hide timezone considerations—validate that the mapping and timezone semantics are what callers expect.

  • Inconsistent groupby source
    The code computes groupBy from formData.groupby while the component also receives a groupby prop. Using formData.groupby here may be correct, but it creates potential inconsistency/confusion. Confirm which source is authoritative and prefer the already-destructured groupby prop to avoid mismatches.

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

CodeAnt AI finished reviewing your PR.

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Jan 5, 2026

Code Review Agent Run #6b1076

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: c50ad65..ba4e9ba
    • superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx
    • superset-frontend/src/components/Chart/DrillBy/DrillByModal.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
Copy link
Member

rusackas commented Jan 5, 2026

Interesting! I can 1000% see the utility of this, but it's also a very different animal than what we have today, which is supported by ALL charts (or at least the "main" ones). If we were able to do this for ALL charts, that'd be a very cool thing... but changing the behavior for one chart type seems like an antipattern from a UX perspective.

I wonder if this should be given a new name, and put alongside Drill By, e.g. Zoom By or something... then we can have it BOTH ways, which is nice, and start spreading this option around to other supported charts (I could see it working for Pie, Line, Area, whatever)

Curious what @kasiazjc or others like @michael-s-molina @kgabryje @yousoph think.

@JayHealth
Copy link
Author

@rusackas indeed. I like having my pie chart and eating it too.

Confusingly though, pie chart already kinda works like this, but the timeseries charts don't.

@yousoph
Copy link
Member

yousoph commented Jan 6, 2026

Agreed with @rusackas on both points - support for extra chart types and a new menu option/name

@JayHealth
Copy link
Author

@yousoph @rusackas Nice, nice. if it's implemented as an extra menu option, how would pie chart handle it? Since pie chart already functions like this, there would be two menu options that do the same thing. Or should pie chart only support the option, in order to work consistently?

I'm curious, the old functionality, where does that come from? I can't really imagine a real world scenario where one would like to run drill by and then see ALL the columns become subdivided. But perhaps the behaviour is based on a need I'm not seeing.

@michael-s-molina
Copy link
Member

Both the current behavior and the one expected by @JayHealth are valid. I think we should fix this by using the same strategy I used in Drill to detail by where a user can select what needs to be considered when drilling: x, y, or both.

Screen.Recording.2026-01-07.at.09.08.23.mov

Copy link
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 pull request implements drill-by functionality for bar charts in Superset, allowing users to right-click on a specific bar and drill into it by replacing the x-axis with the selected drill-by dimension. The implementation adds temporal range filters for time-based bars and updates the chart configuration to display the drilled data correctly.

Key Changes

  • Modified drill-by modal to replace x-axis with drill-by column for echarts_timeseries_bar charts
  • Added temporal range filter calculation for time-based bar charts using TIMEGRAIN_TO_TIMESTAMP mapping
  • Implemented x-axis filter logic to target specific bars during drill-by operations

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.

File Description
superset-frontend/src/components/Chart/DrillBy/DrillByModal.tsx Added logic to update formData for echarts_timeseries_bar charts, setting x_axis, groupby, and xAxisForceCategorical when drilling by
superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx Implemented xAxisDrillByFilter with temporal range calculation for time axes and equality filters for categorical axes to enable precise drill-by targeting

Comment on lines +225 to +227
const grainMs =
TIMEGRAIN_TO_TIMESTAMP[formData.timeGrainSqla as keyof typeof TIMEGRAIN_TO_TIMESTAMP] ??
TIMEGRAIN_TO_TIMESTAMP[TimeGranularity.DAY];
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

The TIMEGRAIN_TO_TIMESTAMP mapping is incomplete and does not cover all time granularities supported by Superset. The TimeGranularity type includes DATE, SECOND, MINUTE, FIVE_MINUTES, TEN_MINUTES, FIFTEEN_MINUTES, THIRTY_MINUTES, WEEK, WEEK_STARTING_SUNDAY, WEEK_STARTING_MONDAY, WEEK_ENDING_SATURDAY, and WEEK_ENDING_SUNDAY, but the mapping only includes HOUR, DAY, MONTH, QUARTER, and YEAR. When users drill by on bars with these missing granularities, the fallback to TimeGranularity.DAY will produce incorrect temporal ranges.

Copilot uses AI. Check for mistakes.
import { TimeseriesChartTransformedProps } from './types';
import { formatSeriesName } from '../utils/series';
import { ExtraControls } from '../components/ExtraControls';
import {TIMEGRAIN_TO_TIMESTAMP} from "../constants";
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

The import statement violates the project's style conventions by using double quotes instead of single quotes. All other imports in the file use single quotes, maintaining consistency is important for code maintainability.

Suggested change
import {TIMEGRAIN_TO_TIMESTAMP} from "../constants";
import { TIMEGRAIN_TO_TIMESTAMP } from '../constants';

Copilot uses AI. Check for mistakes.
Comment on lines +381 to +383
optionName: column.column_name + ' (label)',
hasCustomLabel: true,
label: column.column_name + ' (label)',
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

The label being constructed using string concatenation with " (label)" suffix appears arbitrary and potentially confusing. The label should either use the column's verbose_name if available, or just the column_name without appending " (label)". Additionally, the optionName field should not include the " (label)" suffix as it represents the actual option identifier.

Suggested change
optionName: column.column_name + ' (label)',
hasCustomLabel: true,
label: column.column_name + ' (label)',
optionName: column.column_name,
hasCustomLabel: true,
label: column.verbose_name || column.column_name,

Copilot uses AI. Check for mistakes.
Comment on lines +370 to +389
if (
updatedFormData.viz_type === 'echarts_timeseries_bar' &&
drillByConfigs?.length
) {
const column = drillByConfigs[drillByConfigs.length - 1]?.column;
if (column?.column_name) {
updatedFormData.x_axis = column.column_name;
updatedFormData.groupby = [
{
sqlExpression: column.column_name,
expressionType: 'SQL',
optionName: column.column_name + ' (label)',
hasCustomLabel: true,
label: column.column_name + ' (label)',
isColumnReference: true,
},
];
updatedFormData.xAxisForceCategorical = true;
}
}
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

The new drill-by functionality for echarts_timeseries_bar lacks test coverage. The changes modify the drilledFormData calculation and add complex logic for x_axis manipulation, groupby configuration, and xAxisForceCategorical setting, but no tests verify this behavior. Tests should cover scenarios like drilling into a bar chart with different column types, ensuring the x_axis is correctly set, and verifying that the drilled chart renders correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +377 to +386
updatedFormData.groupby = [
{
sqlExpression: column.column_name,
expressionType: 'SQL',
optionName: column.column_name + ' (label)',
hasCustomLabel: true,
label: column.column_name + ' (label)',
isColumnReference: true,
},
];
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

Setting both x_axis and groupby to the same column may lead to duplication in the query. Based on the buildQuery logic in Timeseries/buildQuery.ts (lines 76-79), columns are constructed from both getXAxisColumn(formData) and groupby arrays. If the same column appears in both x_axis and groupby, it may result in duplicate columns in the query, potentially causing incorrect data aggregation or visualization issues. Consider removing the column from groupby when it's set as x_axis, or verify that this duplication is intentional and handled correctly downstream.

Suggested change
updatedFormData.groupby = [
{
sqlExpression: column.column_name,
expressionType: 'SQL',
optionName: column.column_name + ' (label)',
hasCustomLabel: true,
label: column.column_name + ' (label)',
isColumnReference: true,
},
];
// Ensure the x_axis column is not also present in groupby to avoid
// duplicated query columns and potential aggregation issues.
if (updatedFormData.groupby) {
const currentGroupby = ensureIsArray(updatedFormData.groupby);
updatedFormData.groupby = currentGroupby.filter(group =>
typeof group === 'string'
? group !== column.column_name
: group?.column_name !== column.column_name &&
group?.label !== column.column_name &&
group?.sqlExpression !== column.column_name,
);
}

Copilot uses AI. Check for mistakes.
getNumberFormatter,
LegendState,
ensureIsArray,
ensureIsArray, TimeGranularity,
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

The TimeGranularity import is added to the existing import line without proper formatting. While functional, this makes the import less readable. Consider adding TimeGranularity on a new line or ensuring consistent spacing around the comma separator.

Copilot uses AI. Check for mistakes.
op: '==',
val: data[0],
formattedVal: String(data[0]),
}
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

Missing semicolon at the end of the object literal. While JavaScript allows this, it's inconsistent with the codebase style and could lead to unintended behavior in certain edge cases.

Suggested change
}
};

Copilot uses AI. Check for mistakes.
Comment on lines +225 to +227
const grainMs =
TIMEGRAIN_TO_TIMESTAMP[formData.timeGrainSqla as keyof typeof TIMEGRAIN_TO_TIMESTAMP] ??
TIMEGRAIN_TO_TIMESTAMP[TimeGranularity.DAY];
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

The TIMEGRAIN_TO_TIMESTAMP values for MONTH, QUARTER, and YEAR use fixed day counts (31 days per month, 313 days per quarter, 3112 days per year), which is mathematically incorrect and will produce inaccurate temporal ranges. Months vary between 28-31 days, quarters vary between 90-92 days, and years vary between 365-366 days. This simplified calculation will result in incorrect end times for temporal range filters, potentially excluding or including incorrect data points.

Copilot uses AI. Check for mistakes.
Comment on lines +370 to +389
if (
updatedFormData.viz_type === 'echarts_timeseries_bar' &&
drillByConfigs?.length
) {
const column = drillByConfigs[drillByConfigs.length - 1]?.column;
if (column?.column_name) {
updatedFormData.x_axis = column.column_name;
updatedFormData.groupby = [
{
sqlExpression: column.column_name,
expressionType: 'SQL',
optionName: column.column_name + ' (label)',
hasCustomLabel: true,
label: column.column_name + ' (label)',
isColumnReference: true,
},
];
updatedFormData.xAxisForceCategorical = true;
}
}
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

The complex drill-by behavior modification for echarts_timeseries_bar lacks inline documentation. The code modifies x_axis, groupby, and xAxisForceCategorical fields without explaining why these specific changes are necessary or how they work together to achieve the desired drill-by behavior. Adding a comment block explaining the purpose and interaction of these field changes would improve maintainability and help future developers understand the implementation.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dashboard:drill-by plugins size/M size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants