Skip to content

feat(plugin-chart-echarts): allow decal patterns in custom ECharts options - #43427

Open
rlei-odes wants to merge 1 commit into
apache:masterfrom
rlei-odes:feat/echarts-decal-allowlist
Open

feat(plugin-chart-echarts): allow decal patterns in custom ECharts options#43427
rlei-odes wants to merge 1 commit into
apache:masterfrom
rlei-odes:feat/echarts-decal-allowlist

Conversation

@rlei-odes

Copy link
Copy Markdown
Contributor

SUMMARY

itemStyle.decal is the ECharts property for a patterned fill — hatching,
cross-hatching, dots — rather than a solid colour. It is the only member of
itemStyle missing from itemStyleSchema in eChartOptionsSchema.ts, so it is
stripped during validation while color, borderColor, borderWidth,
borderType, borderRadius, the shadow properties and opacity all pass.

That gap looks accidental. A decal is the same kind of value as its siblings — a
static data structure, which is what the safe parser exists to permit — and it
introduces no new type of input: symbol reuses the symbolTypeSchema string
already accepted for series symbols and legend icons. The schema mirrors
ECharts' DecalObject in full rather than a subset, in the same way
lineStyleSchema does, so there is no arbitrary line to defend later.

What this does not do. It does not make patterned fills usable. A decal is a
per-series property, and per-series options cannot be reached through this
control at all today: mergeCustomEChartOptions replaces arrays rather than
merging them, so supplying series discards the computed series, and the
replacement cannot carry its own data because data is deliberately not in
seriesSchema. Closing the allowlist gap is one half of making a decal
reachable; the merge behaviour is the other, and that is a larger question than
this PR.

So this is a small consistency fix rather than a feature. I am opening it
because it is a one-property gap that costs nothing, and because I am working
toward the other half — per-series visual treatments where the fill pattern
carries meaning independently of colour, which is a common convention in
business reporting. Background and the wider discussion:
#43426

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Not applicable — this widens what the options schema accepts and adds no
control. Nothing renders differently unless a chart opts in through the
existing ECharts Options control, which the testing instructions cover.

TESTING INSTRUCTIONS

Unit tests: npm run test -- plugins/plugin-chart-echarts/src/utils/safeEChartOptionsParser

The unit tests are the verification here, because a decal cannot currently be
exercised end to end through the control
, for reasons unrelated to this
change:

  • a decal is a per-series property, so reaching one means supplying series;
  • mergeCustomEChartOptions replaces arrays rather than merging them, so
    supplying series discards the computed series;
  • and the replacement cannot carry its own data, because data is not in
    seriesSchema — by design, since data comes from the query.

So the option is accepted and merged, and nothing in Superset sets one yet.
That is what makes this a prerequisite rather than a feature, and I would rather
say so than dress up a demo.

What is worth checking for regressions:

  1. Load an existing chart that already uses Customize → ECharts Options, with
    top-level keys such as xAxis / yAxis, and confirm it renders as before.
    Those merge as objects and are unaffected.
  2. Confirm validation still rejects a malformed decal —
    { series: { itemStyle: { decal: { rotation: 'sideways' } } } } raises a
    validation error rather than being silently dropped — and that unknown keys
    inside a decal are still stripped. Both are covered by the new unit tests.

ADDITIONAL INFORMATION

  • Has associated issue: Making per-series chart styling reachable #43426
  • 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

…tions

itemStyle.decal is how ECharts expresses a patterned fill — hatching rather
than a solid colour. It was the only member of itemStyle missing from the
custom-options allowlist, so it was silently stripped, while its siblings
borderColor, borderWidth and borderType were accepted.

Adds decalSchema, mirroring ECharts' DecalObject, and references it from
itemStyleSchema.
@dosubot dosubot Bot added change:frontend Requires changing the frontend viz:charts:echarts Related to Echarts labels Aug 22, 2026
@bito-code-review

bito-code-review Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #cfd8fa

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: 4c8856a..4c8856a
    • superset-frontend/plugins/plugin-chart-echarts/src/utils/eChartOptionsSchema.ts
    • superset-frontend/plugins/plugin-chart-echarts/src/utils/safeEChartOptionsParser.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 an incremental AI Review.

  • /review full - 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 +124 to +126
dashArrayX: z
.union([z.number(), z.array(z.union([z.number(), z.array(z.number())]))])
.optional(),

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 dashArrayX schema accepts heterogeneous arrays such as [1, [2, 3]] because each outer element independently allows either a number or a number array. ECharts expects this option to be one uniform representation—number, number[], or number[][]—so malformed mixed values pass validation and are forwarded to the renderer. Model the union at the array level to reject mixed nesting. [type error]

Severity Level: Minor 🧹
- ⚠️ Custom ECharts decal validation accepts malformed mixed arrays.
- ⚠️ Timeseries custom options can forward invalid decal geometry.
- ⚠️ ECharts may ignore or mishandle the affected pattern.

Use CodeAnt Skill

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

**Path:** superset-frontend/plugins/plugin-chart-echarts/src/utils/eChartOptionsSchema.ts
**Line:** 124:126
**Comment:**
	*Type Error: The `dashArrayX` schema accepts heterogeneous arrays such as `[1, [2, 3]]` because each outer element independently allows either a number or a number array. ECharts expects this option to be one uniform representation—`number`, `number[]`, or `number[][]`—so malformed mixed values pass validation and are forwarded to the renderer. Model the union at the array level to reject mixed nesting.

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 issue is correct. The current dashArrayX schema definition allows mixed types within the array because it uses z.union([z.number(), z.array(z.number())]) for each element, which permits heterogeneous arrays like [1, [2, 3]]. To enforce uniformity, you should define the schema as a union of the three allowed types (number, number[], or number[][]) rather than an array of unions.

To resolve this, update the dashArrayX schema in superset-frontend/plugins/plugin-chart-echarts/src/utils/eChartOptionsSchema.ts as follows:

  dashArrayX: z
    .union([z.number(), z.array(z.number()), z.array(z.array(z.number()))])
    .optional(),

This change ensures that dashArrayX must be either a single number, a flat array of numbers, or a nested array of numbers, rejecting mixed-type arrays. Would you like me to check the rest of the comments on this PR and implement fixes for them as well?

superset-frontend/plugins/plugin-chart-echarts/src/utils/eChartOptionsSchema.ts

dashArrayX: z
    .union([z.number(), z.array(z.number()), z.array(z.array(z.number()))])
    .optional(),

@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.85%. Comparing base (f2610e9) to head (4c8856a).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #43427   +/-   ##
=======================================
  Coverage   78.85%   78.85%           
=======================================
  Files        2876     2876           
  Lines      164581   164582    +1     
  Branches    38011    38011           
=======================================
+ Hits       129786   129787    +1     
  Misses      32348    32348           
  Partials     2447     2447           
Flag Coverage Δ
javascript 74.21% <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.

@rlei-odes

Copy link
Copy Markdown
Contributor Author

Thanks for the flag — I checked this against ECharts and I believe the current schema is correct, so I'd like to leave it as is.

ECharts types the option as a per-element union rather than a uniform one:

// echarts/types/dist/shared.d.ts
declare type DecalDashArrayX = number | (number | number[])[];

which is what z.union([z.number(), z.array(z.union([z.number(), z.array(z.number())]))]) models.

Mixed nesting is intentional rather than malformed. From normalizeDashArrayX in echarts/lib/util/decal.js:

/**
 * [20, 5] should be normalized into [[20, 5]],
 * while [20, [5, 10]] should be normalized into [[20, 20], [5, 10]]
 */

The loop below it branches per element — a number becomes a [n, n] row, an array becomes that row's dash pattern — so [1, [2, 3]] describes two rows with different patterns.

Narrowing to number | number[] | number[][] would reject that and make the allowlist stricter than ECharts itself, which runs against the intent of this PR. The schema mirrors DecalObject exactly, in the same way lineStyleSchema mirrors its own type.

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 plugins size/L viz:charts:echarts Related to Echarts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant