Variables: Fix adding variables to an unsaved dashboard (#45722)

* 🚧: Mob session work 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* 🚧: Mob session work 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
Co-authored-by: Alexandra Vargas <alexa1866@gmail.com>
This commit is contained in:
Ashley Harrison 2022-02-22 13:21:01 +00:00 committed by GitHub
parent ded53e8e0e
commit 5e3be8b17f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 22 deletions

View File

@ -1,5 +1,14 @@
import { variableAdapters } from '../adapters';
import { initialConstantVariableModelState } from '../constant/reducer';
import { constantBuilder, customBuilder } from '../shared/testing/builders';
import { getNextAvailableId } from './actions';
import { initialKeyedVariablesState, toKeyedAction } from '../state/keyedVariablesReducer';
import * as selectors from '../state/selectors';
import * as inspectUtils from '../inspect/utils';
import { addVariable } from '../state/sharedReducer';
import { createConstantVariableAdapter } from '../constant/adapter';
import { getNextAvailableId, switchToListMode, switchToNewMode } from './actions';
import { setIdInEditor } from './reducer';
import { initialState } from '../../dashboard/state/reducers';
describe('getNextAvailableId', () => {
describe('when called with a custom type and there is already 2 variables', () => {
@ -15,3 +24,40 @@ describe('getNextAvailableId', () => {
});
});
});
describe('switchToNewMode', () => {
variableAdapters.setInit(() => [createConstantVariableAdapter()]);
it('should dispatch with the correct rootStateKey', () => {
jest.spyOn(selectors, 'getVariablesByKey').mockReturnValue([]);
jest.spyOn(selectors, 'getNewVariableIndex').mockReturnValue(0);
const mockId = 'constant0';
const mockGetState = jest.fn().mockReturnValue({ templating: initialKeyedVariablesState });
const mockDispatch = jest.fn();
const model = { ...initialConstantVariableModelState, name: mockId, id: mockId, rootStateKey: 'null' };
switchToNewMode(null, 'constant')(mockDispatch, mockGetState, undefined);
expect(mockDispatch).toHaveBeenCalledTimes(2);
expect(mockDispatch.mock.calls[0][0]).toEqual(
toKeyedAction('null', addVariable({ data: { global: false, index: 0, model }, type: 'constant', id: mockId }))
);
expect(mockDispatch.mock.calls[1][0]).toEqual(toKeyedAction('null', setIdInEditor({ id: mockId })));
});
});
describe('switchToListMode', () => {
variableAdapters.setInit(() => [createConstantVariableAdapter()]);
it('should dispatch with the correct rootStateKey', () => {
jest.spyOn(selectors, 'getEditorVariables').mockReturnValue([]);
jest.spyOn(inspectUtils, 'createUsagesNetwork').mockReturnValue({ usages: [], unUsed: [] });
jest.spyOn(inspectUtils, 'transformUsagesToNetwork').mockReturnValue([]);
const mockGetState = jest.fn().mockReturnValue({ templating: initialKeyedVariablesState, dashboard: initialState });
const mockDispatch = jest.fn();
switchToListMode(null)(mockDispatch, mockGetState, undefined);
expect(mockDispatch).toHaveBeenCalledTimes(2);
expect(mockDispatch.mock.calls[0][0]).toEqual(toKeyedAction('null', expect.any(Object)));
expect(mockDispatch.mock.calls[1][0]).toEqual(toKeyedAction('null', expect.any(Object)));
});
});

View File

@ -1,5 +1,16 @@
import { VariableType } from '@grafana/data';
import { cloneDeep } from 'lodash';
import { ThunkResult } from '../../../types';
import { variableAdapters } from '../adapters';
import { initInspect } from '../inspect/reducer';
import { createUsagesNetwork, transformUsagesToNetwork } from '../inspect/utils';
import { updateOptions } from '../state/actions';
import { toKeyedAction } from '../state/keyedVariablesReducer';
import { getEditorVariables, getNewVariableIndex, getVariable, getVariablesByKey } from '../state/selectors';
import { addVariable, removeVariable } from '../state/sharedReducer';
import { AddVariable, KeyedVariableIdentifier, VariableIdentifier } from '../state/types';
import { VariableModel } from '../types';
import { toKeyedVariableIdentifier, toStateKey, toVariablePayload } from '../utils';
import {
changeVariableNameFailed,
changeVariableNameSucceeded,
@ -8,17 +19,6 @@ import {
variableEditorMounted,
variableEditorUnMounted,
} from './reducer';
import { variableAdapters } from '../adapters';
import { AddVariable, KeyedVariableIdentifier, VariableIdentifier } from '../state/types';
import { cloneDeep } from 'lodash';
import { VariableType } from '@grafana/data';
import { addVariable, removeVariable } from '../state/sharedReducer';
import { updateOptions } from '../state/actions';
import { VariableModel } from '../types';
import { initInspect } from '../inspect/reducer';
import { createUsagesNetwork, transformUsagesToNetwork } from '../inspect/utils';
import { toKeyedAction } from '../state/keyedVariablesReducer';
import { toKeyedVariableIdentifier, toVariablePayload } from '../utils';
export const variableEditorMount = (identifier: KeyedVariableIdentifier): ThunkResult<void> => {
return async (dispatch) => {
@ -92,18 +92,21 @@ export const completeChangeVariableName =
};
export const switchToNewMode =
(key: string, type: VariableType = 'query'): ThunkResult<void> =>
(key: string | null | undefined, type: VariableType = 'query'): ThunkResult<void> =>
(dispatch, getState) => {
const id = getNextAvailableId(type, getVariablesByKey(key, getState()));
const rootStateKey = toStateKey(key);
const id = getNextAvailableId(type, getVariablesByKey(rootStateKey, getState()));
const identifier: VariableIdentifier = { type, id };
const global = false;
const index = getNewVariableIndex(key, getState());
const index = getNewVariableIndex(rootStateKey, getState());
const model: VariableModel = cloneDeep(variableAdapters.get(type).initialState);
model.id = id;
model.name = id;
model.rootStateKey = key;
dispatch(toKeyedAction(key, addVariable(toVariablePayload<AddVariable>(identifier, { global, model, index }))));
dispatch(toKeyedAction(key, setIdInEditor({ id: identifier.id })));
model.rootStateKey = rootStateKey;
dispatch(
toKeyedAction(rootStateKey, addVariable(toVariablePayload<AddVariable>(identifier, { global, model, index })))
);
dispatch(toKeyedAction(rootStateKey, setIdInEditor({ id: identifier.id })));
};
export const switchToEditMode =
@ -114,16 +117,17 @@ export const switchToEditMode =
};
export const switchToListMode =
(key: string): ThunkResult<void> =>
(key: string | null | undefined): ThunkResult<void> =>
(dispatch, getState) => {
dispatch(toKeyedAction(key, clearIdInEditor()));
const rootStateKey = toStateKey(key);
dispatch(toKeyedAction(rootStateKey, clearIdInEditor()));
const state = getState();
const variables = getEditorVariables(key, state);
const variables = getEditorVariables(rootStateKey, state);
const dashboard = state.dashboard.getModel();
const { usages } = createUsagesNetwork(variables, dashboard);
const usagesNetwork = transformUsagesToNetwork(usages);
dispatch(toKeyedAction(key, initInspect({ usages, usagesNetwork })));
dispatch(toKeyedAction(rootStateKey, initInspect({ usages, usagesNetwork })));
};
export function getNextAvailableId(type: VariableType, variables: VariableModel[]): string {