diff --git a/public/app/plugins/panel/state-timeline/__snapshots__/migrations.test.ts.snap b/public/app/plugins/panel/state-timeline/__snapshots__/migrations.test.ts.snap index bf4852cfbe9..5ce47782afb 100644 --- a/public/app/plugins/panel/state-timeline/__snapshots__/migrations.test.ts.snap +++ b/public/app/plugins/panel/state-timeline/__snapshots__/migrations.test.ts.snap @@ -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, diff --git a/public/app/plugins/panel/state-timeline/migrations.test.ts b/public/app/plugins/panel/state-timeline/migrations.test.ts index 98b10d22a5a..d1511060df9 100644 --- a/public/app/plugins/panel/state-timeline/migrations.test.ts +++ b/public/app/plugins/panel/state-timeline/migrations.test.ts @@ -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', diff --git a/public/app/plugins/panel/state-timeline/migrations.ts b/public/app/plugins/panel/state-timeline/migrations.ts index c8762339409..30cb5eaaf95 100644 --- a/public/app/plugins/panel/state-timeline/migrations.ts +++ b/public/app/plugins/panel/state-timeline/migrations.ts @@ -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 = {}; + 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; +}