Uh oh!
There was an error while loading. Please reload this page.
fix(charts): resolve select-dimension value→label so grouped charts don't zero out (cloud#667) - #2045
Merged
Merged
Conversation
…on't zero out (cloud#667) A dataset chart grouped by a `select` field whose stored value is English (active/lost/potential) but whose option labels are localized (合作中/已流失/潜在) rendered every bar at 0. The dataset chart path handed the dimension's stored value straight to the axis with no value→label resolution — unlike the legacy aggregate path's resolveGroupByLabels — relying on the analytics server to have resolved labels. When the server can't (an AI-built select whose options its resolveDimensionLabels never sees), rows arrive value-keyed: the axis shows raw enums and the option-keyed colour/category wiring no longer lines up with the value-keyed rows. Make the chart layer authoritative: resolve value→label from the object field options, keying chart data by VALUE (so grouped counts always attach) and displaying the LABEL. New shared `relabelDimensions` + `buildDimensionLabelMap` helpers in @object-ui/core, wired into DatasetWidget (dashboard) and ObjectChart (chart view) from the same object-schema fetch they already run for colours. - relabelDimensions is idempotent and never mutates input rows, so server- resolved labels and the raw drillRawRows both survive. - chartRows stay index-aligned with drillRawRows, so drill-through still maps to the raw stored value. Tests: core composition (value≠label single-dim + pivot) and a DatasetWidget regression asserting the chart receives label-keyed data with every count intact. Closesobjectstack-ai/cloud#667 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
An ObjectStack dashboard chart that groups a count by a
selectfield (e.g. a bar chart "客户数量按状态") rendered every bar at 0, even though the object's list clearly has rows.Real-machine root cause (DB ground truth): the
tk5f_customer.statusfield stores English values (active/lost/potential) with localized labels (合作中/已流失/潜在). The dataset groups by the stored value, so the grouped rows are value-keyed with correct counts. The chart, however, expected the analytics server to have already resolved the dimension value→label — when it hasn't, the raw enum values reach the axis, and the option-keyed colour/category wiring (built from the field labels) no longer lines up with the value-keyed rows, so categories read empty.This is the default product of the AI build agent (English value + localized label), so Chinese AI apps hit it constantly. It does not reproduce when a select's value == its label.
Root cause: chart layer, not dataset layer
The framework analytics service does have value→label resolution (
service-analytics/src/dimension-labels.ts), but it silently no-ops when it can't read the fieldoptions(common for AI-built selects) — thenrowsarrive value-keyed. The objectui dataset chart path (DatasetWidget+ObjectChart's dataset branch) does no value→label resolution of its own and assumes the server did it — unlike the legacy aggregate path, which already resolves labels viaresolveGroupByLabels. So the fix belongs in the chart layer.Fix
Make the chart layer authoritative: resolve value→label from the object field options, keying chart data by value (so grouped counts always attach) and displaying the label.
@object-ui/corechart-series.ts— two new shared, pure helpers:buildDimensionLabelMap(options)→{ value → label }(mirrorsbuildOptionColorMap; drops no-oplabel==valueentries).relabelDimensions(rows, labelMaps)→ rewrites each select-dimension value to its label, leaving measures attached. Idempotent (already-resolved labels / lookup ids / free text pass through) and never mutates the input, so server-resolved labels and the rawdrillRawRowsboth survive.plugin-dashboard/DatasetWidgetandplugin-charts/ObjectChart— build the{value→label}maps from the same object-schema fetch they already run for per-category colours (no extra request), thenrelabelDimensionsbeforebuildChartSeries.chartRowsstay index-aligned withdrillRawRows, so drill-through still filters by the raw stored value.No framework / dataset-server changes; no new network calls.
Verification
Honest about depth — verified at code + build + unit/component levels:
@object-ui/corechart-series.test.ts— 15 passed, incl. new tests forbuildDimensionLabelMap,relabelDimensions, and the composition withbuildChartSeriesfor the exact value≠label scenario (single dimension and pivoted second dimension): every count lands on its label category.plugin-dashboardDatasetWidget— 36 passed (34 existing + 2 new). The newDatasetWidget.relabel.test.tsxdrives the realDatasetWidget+SchemaRenderer: value-keyed rows{active:6, lost:2, potential:4}+ object-schema options ⇒ the chart receives label-keyed data{合作中:6, 已流失:2, 潜在:4}with the rawactivegone from the axis; and a no-options fallback that passes raw rows through without crashing.plugin-charts— 26 passed (no regression from theObjectChartchange).@object-ui/types+@object-ui/core+plugin-dashboard+plugin-chartsbuild clean (declaration files generated, so the TSX typechecks against the new core exports).Not done: live browser repro against
framework/examples/app-showcase(would need a standing backend + a value≠label seeded select + dashboard). The two new tests reproduce the bug deterministically at the component/data level instead, which is the layer the bug lives in.Notes / follow-ups
.objectui-sha. Not bumped here (separate cloud change).plugin-report'sDatasetReportRenderercharts dataset dimensions the same way (data: state.rowsstraight to the chart) and would benefit from the same relabel — left out to keep this PR focused on the reported dashboard surface.Closes objectstack-ai/cloud#667
🤖 Generated with Claude Code