Templating: Changing between variables with the same name now correctly triggers a dashboard refresh (#51490)

* user essentials mob! 🔱

* user essentials mob! 🔱

lastFile:public/app/features/variables/pickers/OptionsPicker/actions.ts

* user essentials mob! 🔱

lastFile:public/app/features/variables/pickers/OptionsPicker/actions.test.ts

* linting

* update betterer

Co-authored-by: kay delaney <kay@grafana.com>
This commit is contained in:
Ashley Harrison
2022-06-29 09:10:55 +01:00
committed by GitHub
parent 9595fd6b66
commit 683bbc7373
4 changed files with 70 additions and 19 deletions

View File

@@ -190,6 +190,41 @@ describe('options picker actions', () => {
});
});
it('supports having variables with the same label and different values', async () => {
const options = [createOption('sameLabel', 'A'), createOption('sameLabel', 'B')];
const variable = createMultiVariable({
options,
current: createOption(['sameLabel'], ['A'], true),
includeAll: false,
});
const clearOthers = false;
const key = NavigationKey.selectAndClose;
// Open the menu and select the second option
const tester = await reduxTester<RootReducerType>()
.givenRootReducer(getRootReducer())
.whenActionIsDispatched(
toKeyedAction('key', addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
)
.whenActionIsDispatched(toKeyedAction('key', showOptions(variable)))
.whenActionIsDispatched(navigateOptions('key', NavigationKey.moveDown, clearOthers))
.whenActionIsDispatched(navigateOptions('key', NavigationKey.moveDown, clearOthers))
.whenAsyncActionIsDispatched(navigateOptions('key', key, clearOthers), true);
const option = createOption(['sameLabel'], ['B'], true);
// Check selecting the second option triggers variables to update
tester.thenDispatchedActionsShouldEqual(
toKeyedAction('key', toggleOption({ option: options[1], forceSelect: true, clearOthers })),
toKeyedAction('key', setCurrentVariableValue(toVariablePayload(variable, { option }))),
toKeyedAction('key', changeVariableProp(toVariablePayload(variable, { propName: 'queryValue', propValue: '' }))),
toKeyedAction('key', hideOptions()),
toKeyedAction('key', setCurrentVariableValue(toVariablePayload(variable, { option })))
);
expect(locationService.partial).toHaveBeenLastCalledWith({ 'var-Constant': ['B'] });
});
describe('when navigateOptions is dispatched with navigation key selectAndClose after highlighting the second option', () => {
it('then correct actions are dispatched', async () => {
const options = [createOption('A'), createOption('B'), createOption('C')];

View File

@@ -8,7 +8,7 @@ import { getVariable, getVariablesState } from '../../state/selectors';
import { changeVariableProp, setCurrentVariableValue } from '../../state/sharedReducer';
import { KeyedVariableIdentifier } from '../../state/types';
import { VariableOption, VariableWithMultiSupport, VariableWithOptions } from '../../types';
import { containsSearchFilter, getCurrentText, toVariablePayload } from '../../utils';
import { containsSearchFilter, getCurrentValue, toVariablePayload } from '../../utils';
import { NavigationKey } from '../types';
import {
@@ -90,7 +90,7 @@ export const commitChangesToVariable = (key: string, callback?: (updated: any) =
const updated = getVariable<VariableWithMultiSupport>(identifier, getState());
dispatch(toKeyedAction(key, hideOptions()));
if (getCurrentText(existing) === getCurrentText(updated)) {
if (getCurrentValue(existing) === getCurrentValue(updated)) {
return;
}

View File

@@ -12,7 +12,7 @@ import { variableAdapters } from './adapters';
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from './constants';
import { getVariablesState } from './state/selectors';
import { KeyedVariableIdentifier, VariableIdentifier, VariablePayload } from './state/types';
import { QueryVariableModel, TransactionStatus, VariableModel, VariableRefresh } from './types';
import { QueryVariableModel, TransactionStatus, VariableModel, VariableRefresh, VariableWithOptions } from './types';
/*
* This regex matches 3 types of variable reference with an optional format specifier
@@ -130,6 +130,22 @@ export const getCurrentText = (variable: any): string => {
return variable.current.text;
};
export const getCurrentValue = (variable: VariableWithOptions): string | null => {
if (!variable || !variable.current || variable.current.value === undefined || variable.current.value === null) {
return null;
}
if (Array.isArray(variable.current.value)) {
return variable.current.value.toString();
}
if (typeof variable.current.value !== 'string') {
return null;
}
return variable.current.value;
};
export function getTemplatedRegex(variable: QueryVariableModel, templateSrv = getTemplateSrv()): string {
if (!variable) {
return '';