Skip to content

Commit 455c43a

Browse files
claudeako
authored andcommitted
fix(widgets): null hidden chart-series textTemplates (TimeSeries markerColor)
A TimeSeries/LineChart with a default 'line' series tripped CE0463: the series' markerColor textTemplate was serialized as an empty Forms$ClientTemplate, but Studio Pro stores it as null when the property is hidden. chartSeriesTextTemplateVisible honored only the dataSet (static/dynamic) gate and missed the item-level editorConfig gates — markerColor is hidden unless lineStyle == 'lineWithMarkers' (default 'line'), and fillColor unless enableFillArea is truthy (default true). Add chartSeriesTextTemplateHiddenByItemConfig, mirroring the widget's hideNestedPropertiesIn rules, so a hidden series textTemplate serializes as null rather than an empty ClientTemplate. Verified: default TimeSeries line -> 0 errors, lineStyle 'lineWithMarkers' keeps markerColor visible, full chart example (all types) 0 errors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
1 parent 20f5a51 commit 455c43a

2 files changed

Lines changed: 94 additions & 1 deletion

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- ============================================================================
2+
-- Bug: TimeSeries/LineChart series markerColor emitted as empty ClientTemplate
3+
-- ============================================================================
4+
--
5+
-- Symptom:
6+
-- A TimeSeries (or LineChart) with a default `line` series failed mx check:
7+
-- [CE0463] "The definition of this widget has changed…" at Time series
8+
-- The series' `markerColor` textTemplate was serialized as an empty
9+
-- Forms$ClientTemplate, but Studio Pro stores it as null when markers are off.
10+
--
11+
-- Root cause:
12+
-- A chart-series textTemplate that is VISIBLE serializes as an empty
13+
-- ClientTemplate; one that is HIDDEN must be null. chartSeriesTextTemplateVisible
14+
-- honored only the dataSet (static/dynamic) gate — it missed the item-level
15+
-- editorConfig gates: `markerColor` is hidden unless lineStyle == "lineWithMarkers"
16+
-- (default "line"), and `fillColor` is hidden unless enableFillArea is truthy.
17+
--
18+
-- Fix:
19+
-- chartSeriesTextTemplateHiddenByItemConfig nulls markerColor / fillColor when the
20+
-- item's lineStyle / enableFillArea hides them, mirroring the widget's
21+
-- editorConfig hideNestedPropertiesIn rules.
22+
--
23+
-- Verify:
24+
-- mxcli exec mdl-examples/bug-tests/timeseries-marker-color-null.mdl -p app.mpr
25+
-- mx check app.mpr # 0 errors — markerColor null on the default line series
26+
-- Requires: Charts .mpk installed in the project's widgets/.
27+
-- ============================================================================
28+
29+
create module TSMarker;
30+
/
31+
create entity TSMarker.Sale ( SaleDate: DateTime, Total: Decimal );
32+
/
33+
create or replace page TSMarker.Home ( layout: Atlas_Core.Atlas_Default ) {
34+
-- default line style: markerColor is hidden -> must be null (not empty ClientTemplate)
35+
pluggablewidget 'com.mendix.widget.web.timeseries.TimeSeries' tsPlain {
36+
line lRev ( DataSet: 'static', DataSource: database from TSMarker.Sale,
37+
StaticXAttribute: SaleDate, StaticYAttribute: Total, StaticName: 'Revenue' )
38+
}
39+
-- lineWithMarkers: markerColor is visible -> empty ClientTemplate is correct
40+
pluggablewidget 'com.mendix.widget.web.timeseries.TimeSeries' tsMarkers {
41+
line lRev2 ( DataSet: 'static', lineStyle: 'lineWithMarkers',
42+
DataSource: database from TSMarker.Sale,
43+
StaticXAttribute: SaleDate, StaticYAttribute: Total, StaticName: 'Revenue' )
44+
}
45+
}

mdl/executor/widget_engine.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,42 @@ func chartSeriesTextTemplateVisible(ip ItemPropertyMapping, dataSetMode string,
808808
return true
809809
}
810810

811+
// chartSeriesTextTemplateHiddenByItemConfig reports whether a chart-series
812+
// textTemplate sub-property is hidden by the widget's editorConfig based on OTHER
813+
// item-level property values (beyond the dataSet gate). These mirror the
814+
// `hideNestedPropertiesIn` rules in the chart editorConfig.js:
815+
//
816+
// markerColor visible only when lineStyle == "lineWithMarkers" (default "line")
817+
// fillColor visible only when enableFillArea is truthy (default true)
818+
//
819+
// Without this, a hidden sub-property's empty-ClientTemplate default (which
820+
// chartSeriesTextTemplateVisible would otherwise emit) trips CE0463 — e.g.
821+
// markerColor on a default "line" TimeSeries/LineChart series. Absent keys use the
822+
// schema default.
823+
func chartSeriesTextTemplateHiddenByItemConfig(propertyKey string, itemConfig map[string]string) bool {
824+
switch propertyKey {
825+
case "markerColor":
826+
lineStyle := itemConfig["lineStyle"]
827+
if lineStyle == "" {
828+
lineStyle = "line"
829+
}
830+
return lineStyle != "lineWithMarkers"
831+
case "fillColor":
832+
enableFillArea := itemConfig["enableFillArea"]
833+
if enableFillArea == "" {
834+
enableFillArea = "true" // schema default
835+
}
836+
return !isTruthyPrimitive(enableFillArea)
837+
}
838+
return false
839+
}
840+
841+
// isTruthyPrimitive reports whether a primitive string value is truthy (non-empty,
842+
// not "false"/"0"). Mirrors the editorConfig's boolean gate semantics.
843+
func isTruthyPrimitive(v string) bool {
844+
return v != "" && v != "false" && v != "0"
845+
}
846+
811847
// seriesDataSourceMatchesMode reports whether a chart-series datasource property
812848
// key (staticDataSource / dynamicDataSource) is the one active for the given
813849
// dataSet mode — used to route the friendly `DataSource:` alias. Chart series (9a).
@@ -846,6 +882,17 @@ func (e *PluggableWidgetEngine) buildObjectListItem(mapping *ObjectListMapping,
846882
}
847883
}
848884

885+
// itemConfig holds the user-set item-level values that gate the visibility of
886+
// OTHER sub-properties in the widget's editorConfig (chart series: lineStyle
887+
// gates markerColor, enableFillArea gates fillColor). Absent keys fall back to
888+
// the schema default inside chartSeriesTextTemplateHiddenByItemConfig.
889+
itemConfig := map[string]string{}
890+
for _, key := range []string{"lineStyle", "enableFillArea"} {
891+
if v, ok := lookupProperty(child.Properties, key); ok {
892+
itemConfig[key] = stringifyAny(v)
893+
}
894+
}
895+
849896
// Pre-resolve any datasource-typed sub-property the MDL set, so attribute
850897
// sub-properties later in the loop resolve against the item's own entity
851898
// regardless of schema property order. The built DataSource is emitted in
@@ -934,7 +981,8 @@ func (e *PluggableWidgetEngine) buildObjectListItem(mapping *ObjectListMapping,
934981
// gate + dataSource binding. Scoped to chart series so non-chart
935982
// object lists (Accordion groups, DataGrid columns) are untouched. (9a)
936983
if ip.Operation == "texttemplate" && isChartSeriesContainer(mapping.MDLContainer) &&
937-
chartSeriesTextTemplateVisible(ip, itemDataSetMode, prebuiltDataSources) {
984+
chartSeriesTextTemplateVisible(ip, itemDataSetMode, prebuiltDataSources) &&
985+
!chartSeriesTextTemplateHiddenByItemConfig(ip.PropertyKey, itemConfig) {
938986
spec.Properties = append(spec.Properties, backend.ObjectListItemProperty{
939987
PropertyKey: ip.PropertyKey,
940988
Operation: "texttemplate",

0 commit comments

Comments
 (0)