codeant-ai-for-open-source[bot] commented on code in PR #37229:
URL: https://github.com/apache/superset/pull/37229#discussion_r2702162587
##########
superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts:
##########
@@ -135,14 +136,21 @@ export default function transformProps(
let focusedSeries: string | null = null;
const {
- verboseMap = {},
+ verboseMap: originalVerboseMap = {},
currencyFormats = {},
columnFormats = {},
} = datasource;
const { label_map: labelMap } =
queriesData[0] as TimeseriesChartDataResponseResult;
const { label_map: labelMapB } =
queriesData[1] as TimeseriesChartDataResponseResult;
+
+ const verboseMapWithLabelMap = addLabelMapToVerboseMap(
+ labelMap,
+ originalVerboseMap,
+ );
+ const verboseMap = addLabelMapToVerboseMap(labelMapB,
verboseMapWithLabelMap);
Review Comment:
**Suggestion:** Passing `labelMap`/`labelMapB` directly into
`addLabelMapToVerboseMap` can throw if either `label_map` is undefined
(Object.entries in the helper will receive undefined). Use a safe fallback
(empty object) when calling the helper so the code won't crash when a query
result omits `label_map`. [null pointer]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ MixedTimeseries charts crash at render when label_map missing.
- ⚠️ Tooltips fail to display metric labels correctly.
- ⚠️ UI shows blank chart area instead of visualization.
```
</details>
```suggestion
labelMap || {},
originalVerboseMap,
);
const verboseMap = addLabelMapToVerboseMap(labelMapB || {},
verboseMapWithLabelMap);
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Render a MixedTimeseries chart that uses transformProps: open the chart
which triggers
transformProps in
superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts
(function export default transformProps). The local assignment of label
maps occurs at
lines 143-146 where labelMap / labelMapB are read from queriesData:
"const { label_map: labelMap } = queriesData[0] as
TimeseriesChartDataResponseResult;"
and
"const { label_map: labelMapB } = queriesData[1] as
TimeseriesChartDataResponseResult;".
2. Provide query results where one of the query results omits label_map
(i.e.,
queriesData[0].label_map === undefined).
This is realistic when the backend response doesn't include a label_map
for a given
query.
3. transformProps then calls addLabelMapToVerboseMap at lines 148-152
("const verboseMapWithLabelMap = addLabelMapToVerboseMap(labelMap,
originalVerboseMap);"),
passing the undefined labelMap into the helper.
4. Inside the helper at
superset-frontend/plugins/plugin-chart-echarts/src/utils/forecast.ts
(addLabelMapToVerboseMap, lines ~36-62),
the implementation does Object.entries(label_map). If label_map is
undefined this
throws a TypeError
("Cannot convert undefined or null to object"), causing transformProps to
crash and the
chart to fail rendering.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:**
superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts
**Line:** 149:152
**Comment:**
*Null Pointer: Passing `labelMap`/`labelMapB` directly into
`addLabelMapToVerboseMap` can throw if either `label_map` is undefined
(Object.entries in the helper will receive undefined). Use a safe fallback
(empty object) when calling the helper so the code won't crash when a query
result omits `label_map`.
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.
```
</details>
##########
superset-frontend/plugins/plugin-chart-echarts/src/utils/forecast.ts:
##########
@@ -26,6 +26,41 @@ import {
} from '../types';
import { sanitizeHtml } from './series';
+/**
+ * Enriches the verbose map by creating human-readable versions of compound
field names.
+ *
+ * @param label_map — a mapping of compound keys to arrays of component labels
(e.g., { "revenue_total_usd": ["revenue", "total", "usd"] })
+ * @param verboseMap — the existing mapping of field names to their display
labels
+ * @returns an updated verbose map that includes human-readable versions of
the compound keys
+ */
+export const addLabelMapToVerboseMap = (
+ label_map: Record<string, string[]>,
+ verboseMap: Record<string, string> = {},
+): Record<string, string> => {
+ /**
+ * Logic:
+ * 1. Iterates through each entry in label_map
+ * 2. For each compound key and its component labels, filters to only labels
that have verbose mappings
+ * 3. Replaces each component label in the key with its verbose name from
verboseMap
+ * 4. Stores the transformed key in a new map
+ * 5. Returns the original verboseMap merged with the new transformed entries
+ */
+ const newVerboseMap: Record<string, string> = {};
+
+ Object.entries(label_map).forEach(([key, labels]) => {
+ if (labels) {
+ labels
+ .filter(l => verboseMap[l])
+ .forEach(l => {
+ const newKey = key.replaceAll(l, verboseMap[l]);
+ newVerboseMap[key] = newKey;
+ });
Review Comment:
**Suggestion:** Logic bug: when a compound key has multiple component labels
the current code replaces each label against the original `key` and writes
`newVerboseMap[key]` inside the inner loop, so only the last processed label
replacement is preserved; this causes partially transformed labels (missing
earlier replacements). Apply the replacements sequentially to a working copy of
the key and only store the fully transformed result once. [logic error]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Forecast tooltip shows partially transformed metric labels.
- ⚠️ Chart UX displays confusing series names.
- ⚠️ Affects functions that consume enriched verbose maps.
```
</details>
```suggestion
const eligible = labels.filter(l => verboseMap[l]);
if (eligible.length) {
let transformedKey = key;
eligible.forEach(l => {
transformedKey = transformedKey.split(l).join(verboseMap[l]);
});
newVerboseMap[key] = transformedKey;
}
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Open superset-frontend/plugins/plugin-chart-echarts/src/utils/forecast.ts
and find
addLabelMapToVerboseMap (hunk lines ~36-62). The inner loop that performs
replacements
runs at lines 52-56 and assigns newVerboseMap[key] repeatedly.
2. Write a small unit test or run in REPL:
const label_map = { 'revenue_total_usd': ['revenue','total','usd'] };
const verboseMap = { revenue: 'Revenue', total: 'Total', usd: 'USD' };
const out = addLabelMapToVerboseMap(label_map, verboseMap);
3. Observe the returned mapping newVerboseMap entry for key
'revenue_total_usd' — because
each replacement is applied against the original key and newVerboseMap[key]
is overwritten
on each iteration, only the replacement from the last iterated label (likely
'usd') is
preserved rather than a fully transformed 'RevenueTotalUSD'. This
demonstrates the logic
bug at forecast.ts lines 53-56.
4. The incorrect partial transformation means downstream code consuming
verboseMap (e.g.,
chart tooltip label resolution and rebaseForecastDatum usage) will show
incomplete or
incorrect human-readable names for multi-component metric keys.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:**
superset-frontend/plugins/plugin-chart-echarts/src/utils/forecast.ts
**Line:** 52:57
**Comment:**
*Logic Error: Logic bug: when a compound key has multiple component
labels the current code replaces each label against the original `key` and
writes `newVerboseMap[key]` inside the inner loop, so only the last processed
label replacement is preserved; this causes partially transformed labels
(missing earlier replacements). Apply the replacements sequentially to a
working copy of the key and only store the fully transformed result once.
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.
```
</details>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]