StateTimeline: Improve auto migration from discrete panel (#104671)

This commit is contained in:
Ryan McKinley
2025-04-30 17:56:48 +03:00
committed by GitHub
parent cd5fa7943e
commit d0644d081f
3 changed files with 74 additions and 1 deletions
@@ -15,6 +15,7 @@ exports[`Timeline Migrations from discrete panel 1`] = `
"color": "#7EB26D",
},
"111": {
"color": "#F0F",
"text": "ONE",
},
"20": {
@@ -32,6 +33,12 @@ exports[`Timeline Migrations from discrete panel 1`] = `
"90": {
"color": "#6ED0E0",
},
"AAA": {
"color": "#FF0",
},
"ONE": {
"color": "#F0F",
},
},
"type": "value",
},
@@ -39,6 +46,7 @@ exports[`Timeline Migrations from discrete panel 1`] = `
"options": {
"from": 1,
"result": {
"color": "#FF0",
"text": "AAA",
},
"to": 3,
@@ -47,6 +47,16 @@ const discreteInV8 = {
color: '#E24D42',
text: '5',
},
{
$$hashKey: 'object:369',
color: '#FF0', // Should get linked to the range map below
text: 'AAA',
},
{
$$hashKey: 'object:369',
color: '#F0F', // Should get linked to the range map below
text: 'ONE',
},
],
crosshairColor: '#8F070C',
display: 'timeline',
@@ -1,6 +1,6 @@
import { isArray } from 'lodash';
import { FieldConfigSource, MappingType, PanelModel, ValueMap } from '@grafana/data';
import { FieldConfigSource, MappingType, PanelModel, ValueMap, RangeMap, ValueMapping } from '@grafana/data';
import { FieldConfig, Options } from './panelcfg.gen';
@@ -74,9 +74,64 @@ export const timelinePanelChangedHandler = (
}
}
if (fieldConfig.defaults.mappings?.length) {
fieldConfig.defaults.mappings = expandColorMappings(fieldConfig.defaults.mappings);
}
// mutates the input
panel.fieldConfig = fieldConfig;
}
return options;
};
function expandColorMappings(mappings: ValueMapping[]): ValueMapping[] {
let keyToColor: Record<string, string> = {};
for (const m of mappings) {
if (isValueToText(m)) {
for (const key in m.options) {
const target = m.options[key];
if (target.color?.length) {
keyToColor[key] = target.color;
}
}
} else if (isRangeMap(m)) {
const { text, color } = m.options.result;
if (text?.length && color?.length && !keyToColor[text]) {
keyToColor[text] = color;
}
}
}
// Set a color for values that match
return mappings.map((m) => {
if (isValueToText(m)) {
for (const key in m.options) {
const target = m.options[key];
if (!target.color?.length) {
let c = keyToColor[key];
if (!c && target.text) {
c = keyToColor[target.text];
}
if (c) {
target.color = c; // link the mapped color
}
}
}
} else if (isRangeMap(m)) {
const { text, color } = m.options.result;
if (!color && text && keyToColor[text]) {
m.options.result.color = keyToColor[text];
}
}
return m;
});
}
function isValueToText(m: ValueMapping): m is ValueMap {
return m.type === MappingType.ValueToText;
}
function isRangeMap(m: ValueMapping): m is RangeMap {
return m.type === MappingType.RangeToText;
}