mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: Variable without a current value in json model causes crash on load (#24261)
* Variables: Fixes variable initilization and default values * fixed failing tests. Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
This commit is contained in:
parent
a2363f4d0c
commit
cdc5203d8a
@ -196,7 +196,7 @@ describe('shared actions', () => {
|
|||||||
${['A', 'B', 'C']} | ${'B'} | ${'C'} | ${'B'}
|
${['A', 'B', 'C']} | ${'B'} | ${'C'} | ${'B'}
|
||||||
${['A', 'B', 'C']} | ${'X'} | ${undefined} | ${'A'}
|
${['A', 'B', 'C']} | ${'X'} | ${undefined} | ${'A'}
|
||||||
${['A', 'B', 'C']} | ${'X'} | ${'C'} | ${'C'}
|
${['A', 'B', 'C']} | ${'X'} | ${'C'} | ${'C'}
|
||||||
${undefined} | ${'B'} | ${undefined} | ${'A'}
|
${undefined} | ${'B'} | ${undefined} | ${'should not dispatch setCurrentVariableValue'}
|
||||||
`('then correct actions are dispatched', async ({ withOptions, withCurrent, defaultValue, expected }) => {
|
`('then correct actions are dispatched', async ({ withOptions, withCurrent, defaultValue, expected }) => {
|
||||||
let custom;
|
let custom;
|
||||||
|
|
||||||
|
@ -308,8 +308,10 @@ export const validateVariableSelectionState = (
|
|||||||
// 3. use the first value
|
// 3. use the first value
|
||||||
if (variableInState.options) {
|
if (variableInState.options) {
|
||||||
const option = variableInState.options[0];
|
const option = variableInState.options[0];
|
||||||
|
if (option) {
|
||||||
return setValue(variableInState, option);
|
return setValue(variableInState, option);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 4... give up
|
// 4... give up
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import { default as lodashDefaults } from 'lodash/defaults';
|
||||||
|
|
||||||
import { reducerTester } from '../../../../test/core/redux/reducerTester';
|
import { reducerTester } from '../../../../test/core/redux/reducerTester';
|
||||||
import {
|
import {
|
||||||
@ -29,15 +30,20 @@ variableAdapters.setInit(() => [createQueryVariableAdapter()]);
|
|||||||
describe('sharedReducer', () => {
|
describe('sharedReducer', () => {
|
||||||
describe('when addVariable is dispatched', () => {
|
describe('when addVariable is dispatched', () => {
|
||||||
it('then state should be correct', () => {
|
it('then state should be correct', () => {
|
||||||
const model = ({ name: 'name from model', type: 'type from model' } as unknown) as QueryVariableModel;
|
const model = ({
|
||||||
|
name: 'name from model',
|
||||||
|
type: 'type from model',
|
||||||
|
current: undefined,
|
||||||
|
} as unknown) as QueryVariableModel;
|
||||||
|
|
||||||
const payload = toVariablePayload({ id: '0', type: 'query' }, { global: true, index: 0, model });
|
const payload = toVariablePayload({ id: '0', type: 'query' }, { global: true, index: 0, model });
|
||||||
|
|
||||||
reducerTester<VariablesState>()
|
reducerTester<VariablesState>()
|
||||||
.givenReducer(sharedReducer, { ...initialVariablesState })
|
.givenReducer(sharedReducer, { ...initialVariablesState })
|
||||||
.whenActionIsDispatched(addVariable(payload))
|
.whenActionIsDispatched(addVariable(payload))
|
||||||
.thenStateShouldEqual({
|
.thenStateShouldEqual({
|
||||||
[0]: {
|
[0]: {
|
||||||
...initialQueryVariableModelState,
|
...lodashDefaults({}, model, initialQueryVariableModelState),
|
||||||
...model,
|
|
||||||
id: '0',
|
id: '0',
|
||||||
global: true,
|
global: true,
|
||||||
index: 0,
|
index: 0,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import { default as lodashDefaults } from 'lodash/defaults';
|
||||||
|
|
||||||
import { VariableType } from '@grafana/data';
|
import { VariableType } from '@grafana/data';
|
||||||
import { VariableModel, VariableOption, VariableWithOptions } from '../../templating/types';
|
import { VariableModel, VariableOption, VariableWithOptions } from '../../templating/types';
|
||||||
@ -16,13 +17,16 @@ const sharedReducerSlice = createSlice({
|
|||||||
reducers: {
|
reducers: {
|
||||||
addVariable: (state: VariablesState, action: PayloadAction<VariablePayload<AddVariable>>) => {
|
addVariable: (state: VariablesState, action: PayloadAction<VariablePayload<AddVariable>>) => {
|
||||||
const id = action.payload.id ?? action.payload.data.model.name; // for testing purposes we can call this with an id
|
const id = action.payload.id ?? action.payload.data.model.name; // for testing purposes we can call this with an id
|
||||||
|
const initialState = cloneDeep(variableAdapters.get(action.payload.type).initialState);
|
||||||
|
const model = cloneDeep(action.payload.data.model);
|
||||||
|
|
||||||
const variable = {
|
const variable = {
|
||||||
...cloneDeep(variableAdapters.get(action.payload.type).initialState),
|
...lodashDefaults({}, model, initialState),
|
||||||
...action.payload.data.model,
|
|
||||||
id: id,
|
id: id,
|
||||||
index: action.payload.data.index,
|
index: action.payload.data.index,
|
||||||
global: action.payload.data.global,
|
global: action.payload.data.global,
|
||||||
};
|
};
|
||||||
|
|
||||||
state[id] = variable;
|
state[id] = variable;
|
||||||
},
|
},
|
||||||
addInitLock: (state: VariablesState, action: PayloadAction<VariablePayload>) => {
|
addInitLock: (state: VariablesState, action: PayloadAction<VariablePayload>) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user