Skip to content

fix(charts): reject long-format results in bar and line (#1400) - #1468

Merged
alfredo1996 merged 2 commits into
release/1.5from
fix/issue-1400-long-format-reject
Aug 5, 2026
Merged

fix(charts): reject long-format results in bar and line (#1400)#1468
alfredo1996 merged 2 commits into
release/1.5from
fix/issue-1400-long-format-reject

Conversation

@alfredo1996

@alfredo1996 alfredo1996 commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Closes #1400

The bug

A long-format result — category, series, value, what GROUP BY a, b naturally produces — rendered a chart that looked plausible and was wrong.

Bar: 12 bars with duplicated x labels, a ghost series legend swatch with no bars, and no stacking at all despite stackMode being set.
Line: worse — a single revenue line drawn across duplicated x values, interleaving delivered → shipped → delivered, which reads as a violently spiky time series but is pure artifact.

resolveValueKeys treats every non-label column as a value series, so series became a series of its own; toSeriesNumber turned 'delivered' into null, which is why the legend entry existed with no bars. validateBarData only counted columns, so nothing rejected it.

The fix — reject, don't pivot

validateNumericValueColumns in transforms/shared-utils.ts, wired into both validators. Rejection rule: a column is flagged only when it has at least one non-null cell and none that parse. An entirely null column stays legal — that is a sparse series, what a LEFT JOIN produces, and the reason collectAllKeys unions keys in the first place.

Resolution goes through resolveValueKeys — the same call the transform makes — so the validator cannot disagree with what is actually plotted.

Pivoting long→wide (the issue's option 2) is deliberately not here: it's a new feature against the no-new-features directive and overlaps #1425, already in v1.6. Even with a pivot, a genuinely non-numeric value column must still be rejected rather than coerced to null, so this lands either way.

Two things the issue didn't anticipate

1. validate couldn't see the column mapping. Its signature was (data: unknown), so a validator had to assume positional defaults and would wrongly reject a result whose text columns the user had already mapped away. columnMapping was already in scope at both card-container call sites — used on the very next line for the transform — so the signature is widened to (data, mapping?) to match transformWithMapping.

2. 11 reference tiles used this exact shape (5 bar, 6 line). Left alone they would have gone from wrong chart to "Incompatible data format", which is worse for a reference dashboard. All 11 are rewritten to wide format with SUM(...) FILTER (WHERE ...), so the stackMode tiles finally demonstrate real stacking. Side effect: page-line-v-28 sets rightAxisSeries: "shipped", a column that did not exist under the old query — that tile starts working too.

Tests

19 new: 10 for the helper (including both mapping paths and the sparse-column cases), 3 per validator, 3 jsdom.

Note

jsdom coverage of any validator was fictional before this PR. chart-helpers registers lightweight stub plugins when the real plugin modules haven't loaded, and LightDef carries no validate field — so chartConfig.validate is undefined in every jsdom test. My first attempt passed a long-format result straight through to a rendered chart for exactly that reason. The test now attaches the real validateBarData via importActual and says why; importing the plugin module itself would drag ECharts into jsdom for no benefit.

Verification

app 3499/3499 · typecheck + lint clean · chart E2E (charts, chart-export, heavy-widgets, widget-editor) 48 passed, 3 skipped, 1 flaky — chart-export PNG-download timing, unrelated spec, green on retry.

Follow-up worth filing

ColumnMapping.groupBy exists to designate a series column but resolveValueKeys only excludes the label key — so even a user who correctly declares groupBy: "series" gets it plotted as a series. This PR rejects that case with a clear message rather than rendering garbage, which is the right outcome while no pivot exists. Wiring groupBy up properly belongs with the long→wide pivot in #1425.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Bar and line charts now detect non-numeric plotted values and identify the affected columns.
    • Validation respects selected chart mappings, improving support for explicitly configured axes and value fields.
    • Entirely null sparse series remain valid.
    • Clear guidance is provided when long-format data requires conversion to wide format.
  • Documentation

    • Added an Unreleased changelog entry describing the chart validation improvements.
  • Examples

    • Updated reference chart tiles to use separate status series for clearer stacked, legend, palette, and dual-axis visualizations.

@alfredo1996 alfredo1996 added bug Something isn't working pkg:app Next.js application package area:charts Chart rendering priority:P1 Ship-but-fix before release labels Aug 4, 2026
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@alfredo1996, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f1b6e67-dda2-4907-b430-d3399e0d6fd8

📥 Commits

Reviewing files that changed from the base of the PR and between 62c8b15 and d89f356.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • scripts/demo/chart-reference.json

Walkthrough

Bar and line charts now validate mapped plotted columns for numeric values. Long-format results with non-numeric series columns show validation errors. Tests cover mappings and sparse data. Chart Reference queries now return separate wide-format series columns.

Changes

Chart validation and reference updates

Layer / File(s) Summary
Mapped numeric-column validation
app/src/lib/plugin/chart-plugin-registry.ts, app/src/plugins/transforms/shared-utils.ts, app/src/plugins/transforms/__tests__/shared.test.ts
Validators accept column mappings. Shared validation reports non-numeric plotted columns while preserving entirely null sparse series.
Bar and line validation integration
app/src/plugins/bar/transform.ts, app/src/plugins/line/transform.ts, app/src/components/card-container.tsx, app/src/components/__tests__/card-container-states.test.tsx, app/src/plugins/transforms/__tests__/bar.test.ts, app/src/plugins/transforms/__tests__/line.test.ts
Bar and line validators check mapped value columns. Preview and query validation pass mappings. Tests cover invalid long-format and valid wide-format data.
Reference query and release documentation
scripts/demo/chart-reference.json, CHANGELOG.md
Reference bar and line queries use separate conditional aggregate series columns. The changelog documents the validation and query-shape updates.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: type: fix

Suggested reviewers: alfredorubin96

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: rejecting long-format results in bar and line charts.
Linked Issues check ✅ Passed The changes satisfy issue #1400 by validating mapped value columns, naming offending columns, adding error-state tests, and updating stacking reference tiles.
Out of Scope Changes check ✅ Passed The changelog, tests, validation mapping, and reference tile updates directly support issue #1400 and its acceptance criteria.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-1400-long-format-reject

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@alfredo1996

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@alfredo1996

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 1 minute.

@alfredo1996

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 58 minutes.

A `category, series, value` result — what GROUP BY a, b naturally
produces — rendered a chart that looked plausible and was wrong.
resolveValueKeys treats every non-label column as a value series, so
`series` became a series whose cells all coerced to null: duplicated x
labels, a ghost legend entry with no bars, and no stacking despite
stackMode being set. Line drew one value line zig-zagging across
repeated x values, which reads as a spiky time series but is artifact.

validateNumericValueColumns rejects a value column that has non-null
cells and none that parse, naming it and showing the pivot that fixes
it. An all-null column stays legal — that is a sparse series, what a
LEFT JOIN produces, and the reason collectAllKeys unions keys.

Resolution goes through resolveValueKeys, the same call the transform
makes, so the validator cannot disagree with what is plotted.

validate() now takes the column mapping, as transformWithMapping
already did. Without it the validator has to assume positional
defaults and would reject a result whose text columns the user had
already mapped away.

The 11 reference tiles using this shape are rewritten to wide format
so the stackMode tiles demonstrate real stacking. page-line-v-28's
rightAxisSeries: "shipped" now names a column that exists.

Closes #1400

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@alfredo1996
alfredo1996 force-pushed the fix/issue-1400-long-format-reject branch from dabf8a3 to 62c8b15 Compare August 4, 2026 20:27
@alfredo1996

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

…-long-format-reject

# Conflicts:
#	CHANGELOG.md
@alfredo1996
alfredo1996 merged commit 8dee489 into release/1.5 Aug 5, 2026
10 checks passed
@alfredo1996
alfredo1996 deleted the fix/issue-1400-long-format-reject branch August 5, 2026 10:42
@sonarqubecloud

sonarqubecloud Bot commented Aug 5, 2026

Copy link
Copy Markdown

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

Labels

area:charts Chart rendering bug Something isn't working pkg:app Next.js application package priority:P1 Ship-but-fix before release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants