diff --git a/public/app/features/variables/state/actions.test.ts b/public/app/features/variables/state/actions.test.ts index a4fbbe56715..badb5ea7af9 100644 --- a/public/app/features/variables/state/actions.test.ts +++ b/public/app/features/variables/state/actions.test.ts @@ -12,6 +12,7 @@ import { cancelVariables, changeVariableMultiValue, cleanUpVariables, + fixSelectedInconsistency, initDashboardTemplating, initVariablesTransaction, processVariables, @@ -686,4 +687,92 @@ describe('shared actions', () => { }); }); }); + + describe('fixSelectedInconsistency', () => { + describe('when called for a single value variable', () => { + describe('and there is an inconsistency between current and selected in options', () => { + it('then it should set the correct selected', () => { + const variable = customBuilder().withId('custom').withCurrent('A').withOptions('A', 'B', 'C').build(); + variable.options[1].selected = true; + + expect(variable.options).toEqual([ + { text: 'A', value: 'A', selected: false }, + { text: 'B', value: 'B', selected: true }, + { text: 'C', value: 'C', selected: false }, + ]); + + fixSelectedInconsistency(variable); + + expect(variable.options).toEqual([ + { text: 'A', value: 'A', selected: true }, + { text: 'B', value: 'B', selected: false }, + { text: 'C', value: 'C', selected: false }, + ]); + }); + }); + + describe('and there is no matching option in options', () => { + it('then the first option should be selected', () => { + const variable = customBuilder().withId('custom').withCurrent('A').withOptions('X', 'Y', 'Z').build(); + + expect(variable.options).toEqual([ + { text: 'X', value: 'X', selected: false }, + { text: 'Y', value: 'Y', selected: false }, + { text: 'Z', value: 'Z', selected: false }, + ]); + + fixSelectedInconsistency(variable); + + expect(variable.options).toEqual([ + { text: 'X', value: 'X', selected: true }, + { text: 'Y', value: 'Y', selected: false }, + { text: 'Z', value: 'Z', selected: false }, + ]); + }); + }); + }); + + describe('when called for a multi value variable', () => { + describe('and there is an inconsistency between current and selected in options', () => { + it('then it should set the correct selected', () => { + const variable = customBuilder().withId('custom').withCurrent(['A', 'C']).withOptions('A', 'B', 'C').build(); + variable.options[1].selected = true; + + expect(variable.options).toEqual([ + { text: 'A', value: 'A', selected: false }, + { text: 'B', value: 'B', selected: true }, + { text: 'C', value: 'C', selected: false }, + ]); + + fixSelectedInconsistency(variable); + + expect(variable.options).toEqual([ + { text: 'A', value: 'A', selected: true }, + { text: 'B', value: 'B', selected: false }, + { text: 'C', value: 'C', selected: true }, + ]); + }); + }); + + describe('and there is no matching option in options', () => { + it('then the first option should be selected', () => { + const variable = customBuilder().withId('custom').withCurrent(['A', 'C']).withOptions('X', 'Y', 'Z').build(); + + expect(variable.options).toEqual([ + { text: 'X', value: 'X', selected: false }, + { text: 'Y', value: 'Y', selected: false }, + { text: 'Z', value: 'Z', selected: false }, + ]); + + fixSelectedInconsistency(variable); + + expect(variable.options).toEqual([ + { text: 'X', value: 'X', selected: true }, + { text: 'Y', value: 'Y', selected: false }, + { text: 'Z', value: 'Z', selected: false }, + ]); + }); + }); + }); + }); }); diff --git a/public/app/features/variables/state/actions.ts b/public/app/features/variables/state/actions.ts index d4d7dbd37e7..6bc96693666 100644 --- a/public/app/features/variables/state/actions.ts +++ b/public/app/features/variables/state/actions.ts @@ -39,7 +39,7 @@ import { import { contextSrv } from 'app/core/services/context_srv'; import { getTemplateSrv, TemplateSrv } from '../../templating/template_srv'; import { alignCurrentWithMulti } from '../shared/multiOptions'; -import { hasLegacyVariableSupport, hasStandardVariableSupport, isMulti, isQuery } from '../guard'; +import { hasLegacyVariableSupport, hasOptions, hasStandardVariableSupport, isMulti, isQuery } from '../guard'; import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { DashboardModel } from 'app/features/dashboard/state'; import { createErrorNotification } from '../../../core/copy/appNotification'; @@ -92,7 +92,7 @@ export const initDashboardTemplating = (list: VariableModel[]): ThunkResult { let orderIndex = 0; for (let index = 0; index < list.length; index++) { - const model = list[index]; + const model = fixSelectedInconsistency(list[index]); if (!variableAdapters.getIfExists(model.type)) { continue; } @@ -110,6 +110,32 @@ export const initDashboardTemplating = (list: VariableModel[]): ThunkResult => { return (dispatch) => { const dashboardModel: DashboardVariableModel = {