mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 10:02:33 +08:00
Variables: Fixes loading with a custom all value in url (#28958)
This commit is contained in:
@ -10,4 +10,8 @@ export class MultiVariableBuilder<T extends VariableWithMultiSupport> extends Op
|
||||
this.variable.includeAll = includeAll;
|
||||
return this;
|
||||
}
|
||||
withAllValue(allValue: string) {
|
||||
this.variable.allValue = allValue;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import {
|
||||
initDashboardTemplating,
|
||||
initVariablesTransaction,
|
||||
processVariables,
|
||||
setOptionFromUrl,
|
||||
validateVariableSelectionState,
|
||||
} from './actions';
|
||||
import {
|
||||
@ -203,7 +202,6 @@ describe('shared actions', () => {
|
||||
const query = { orgId: '1', 'var-stats': 'response', 'var-substats': ALL_VARIABLE_TEXT };
|
||||
const tester = await reduxTester<{ templating: TemplatingState; location: { query: UrlQueryMap } }>({
|
||||
preloadedState: { templating: ({} as unknown) as TemplatingState, location: { query } },
|
||||
debug: true,
|
||||
})
|
||||
.givenRootReducer(getTemplatingAndLocationRootReducer())
|
||||
.whenActionIsDispatched(variablesInitTransaction({ uid: '' }))
|
||||
@ -241,46 +239,6 @@ describe('shared actions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when setOptionFromUrl is dispatched with a custom variable (no refresh property)', () => {
|
||||
it.each`
|
||||
urlValue | isMulti | expected
|
||||
${'B'} | ${false} | ${'B'}
|
||||
${['B']} | ${false} | ${'B'}
|
||||
${'X'} | ${false} | ${'X'}
|
||||
${''} | ${false} | ${''}
|
||||
${null} | ${false} | ${null}
|
||||
${undefined} | ${false} | ${undefined}
|
||||
${'B'} | ${true} | ${['B']}
|
||||
${['B']} | ${true} | ${['B']}
|
||||
${'X'} | ${true} | ${['X']}
|
||||
${''} | ${true} | ${['']}
|
||||
${['A', 'B']} | ${true} | ${['A', 'B']}
|
||||
${null} | ${true} | ${[null]}
|
||||
${undefined} | ${true} | ${[undefined]}
|
||||
`('and urlValue is $urlValue then correct actions are dispatched', async ({ urlValue, expected, isMulti }) => {
|
||||
const custom = customBuilder()
|
||||
.withId('0')
|
||||
.withMulti(isMulti)
|
||||
.withOptions('A', 'B', 'C')
|
||||
.withCurrent('A')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
.givenRootReducer(getTemplatingRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(custom, { global: false, index: 0, model: custom })))
|
||||
.whenAsyncActionIsDispatched(setOptionFromUrl(toVariableIdentifier(custom), urlValue), true);
|
||||
|
||||
await tester.thenDispatchedActionsShouldEqual(
|
||||
setCurrentVariableValue(
|
||||
toVariablePayload(
|
||||
{ type: 'custom', id: '0' },
|
||||
{ option: { text: expected, value: expected, selected: false } }
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when validateVariableSelectionState is dispatched with a custom variable (no dependencies)', () => {
|
||||
describe('and not multivalue', () => {
|
||||
it.each`
|
||||
|
@ -29,7 +29,13 @@ import {
|
||||
variableStateFetching,
|
||||
variableStateNotStarted,
|
||||
} from './sharedReducer';
|
||||
import { toVariableIdentifier, toVariablePayload, VariableIdentifier } from './types';
|
||||
import {
|
||||
ALL_VARIABLE_TEXT,
|
||||
ALL_VARIABLE_VALUE,
|
||||
toVariableIdentifier,
|
||||
toVariablePayload,
|
||||
VariableIdentifier,
|
||||
} from './types';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { getTemplateSrv, TemplateSrv } from '../../templating/template_srv';
|
||||
import { alignCurrentWithMulti } from '../shared/multiOptions';
|
||||
@ -287,6 +293,12 @@ export const setOptionFromUrl = (
|
||||
return op.text === urlValue || op.value === urlValue;
|
||||
});
|
||||
|
||||
if (!option && isMulti(variableFromState)) {
|
||||
if (variableFromState.allValue && urlValue === variableFromState.allValue) {
|
||||
option = { text: ALL_VARIABLE_TEXT, value: ALL_VARIABLE_VALUE, selected: false };
|
||||
}
|
||||
}
|
||||
|
||||
if (!option) {
|
||||
let defaultText = urlValue as string | string[];
|
||||
const defaultValue = urlValue as string | string[];
|
||||
|
154
public/app/features/variables/state/setOptionFromUrl.test.ts
Normal file
154
public/app/features/variables/state/setOptionFromUrl.test.ts
Normal file
@ -0,0 +1,154 @@
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createCustomVariableAdapter } from '../custom/adapter';
|
||||
import { customBuilder } from '../shared/testing/builders';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { TemplatingState } from './reducers';
|
||||
import { getTemplatingRootReducer } from './helpers';
|
||||
import { addVariable, setCurrentVariableValue } from './sharedReducer';
|
||||
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, toVariableIdentifier, toVariablePayload } from './types';
|
||||
import { setOptionFromUrl } from './actions';
|
||||
|
||||
variableAdapters.setInit(() => [createCustomVariableAdapter()]);
|
||||
|
||||
describe('when setOptionFromUrl is dispatched with a custom variable (no refresh property)', () => {
|
||||
it.each`
|
||||
urlValue | isMulti | expected
|
||||
${'B'} | ${false} | ${'B'}
|
||||
${['B']} | ${false} | ${'B'}
|
||||
${'X'} | ${false} | ${'X'}
|
||||
${''} | ${false} | ${''}
|
||||
${null} | ${false} | ${null}
|
||||
${undefined} | ${false} | ${undefined}
|
||||
${'B'} | ${true} | ${['B']}
|
||||
${['B']} | ${true} | ${['B']}
|
||||
${'X'} | ${true} | ${['X']}
|
||||
${''} | ${true} | ${['']}
|
||||
${['A', 'B']} | ${true} | ${['A', 'B']}
|
||||
${null} | ${true} | ${[null]}
|
||||
${undefined} | ${true} | ${[undefined]}
|
||||
`('and urlValue is $urlValue then correct actions are dispatched', async ({ urlValue, expected, isMulti }) => {
|
||||
const custom = customBuilder()
|
||||
.withId('0')
|
||||
.withMulti(isMulti)
|
||||
.withOptions('A', 'B', 'C')
|
||||
.withCurrent('A')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
.givenRootReducer(getTemplatingRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(custom, { global: false, index: 0, model: custom })))
|
||||
.whenAsyncActionIsDispatched(setOptionFromUrl(toVariableIdentifier(custom), urlValue), true);
|
||||
|
||||
await tester.thenDispatchedActionsShouldEqual(
|
||||
setCurrentVariableValue(
|
||||
toVariablePayload({ type: 'custom', id: '0' }, { option: { text: expected, value: expected, selected: false } })
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when setOptionFromUrl is dispatched for a variable with a custom all value', () => {
|
||||
it('and urlValue contains same all value then correct actions are dispatched', async () => {
|
||||
const allValue = '.*';
|
||||
const urlValue = allValue;
|
||||
const custom = customBuilder()
|
||||
.withId('0')
|
||||
.withMulti(false)
|
||||
.withIncludeAll()
|
||||
.withAllValue(allValue)
|
||||
.withOptions('A', 'B', 'C')
|
||||
.withCurrent('A')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
.givenRootReducer(getTemplatingRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(custom, { global: false, index: 0, model: custom })))
|
||||
.whenAsyncActionIsDispatched(setOptionFromUrl(toVariableIdentifier(custom), urlValue), true);
|
||||
|
||||
await tester.thenDispatchedActionsShouldEqual(
|
||||
setCurrentVariableValue(
|
||||
toVariablePayload(
|
||||
{ type: 'custom', id: '0' },
|
||||
{ option: { text: ALL_VARIABLE_TEXT, value: ALL_VARIABLE_VALUE, selected: false } }
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('and urlValue differs from all value then correct actions are dispatched', async () => {
|
||||
const allValue = '.*';
|
||||
const urlValue = 'X';
|
||||
const custom = customBuilder()
|
||||
.withId('0')
|
||||
.withMulti(false)
|
||||
.withIncludeAll()
|
||||
.withAllValue(allValue)
|
||||
.withOptions('A', 'B', 'C')
|
||||
.withCurrent('A')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
.givenRootReducer(getTemplatingRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(custom, { global: false, index: 0, model: custom })))
|
||||
.whenAsyncActionIsDispatched(setOptionFromUrl(toVariableIdentifier(custom), urlValue), true);
|
||||
|
||||
await tester.thenDispatchedActionsShouldEqual(
|
||||
setCurrentVariableValue(
|
||||
toVariablePayload({ type: 'custom', id: '0' }, { option: { text: 'X', value: 'X', selected: false } })
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('and urlValue differs but matches an option then correct actions are dispatched', async () => {
|
||||
const allValue = '.*';
|
||||
const urlValue = 'B';
|
||||
const custom = customBuilder()
|
||||
.withId('0')
|
||||
.withMulti(false)
|
||||
.withIncludeAll()
|
||||
.withAllValue(allValue)
|
||||
.withOptions('A', 'B', 'C')
|
||||
.withCurrent('A')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
.givenRootReducer(getTemplatingRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(custom, { global: false, index: 0, model: custom })))
|
||||
.whenAsyncActionIsDispatched(setOptionFromUrl(toVariableIdentifier(custom), urlValue), true);
|
||||
|
||||
await tester.thenDispatchedActionsShouldEqual(
|
||||
setCurrentVariableValue(
|
||||
toVariablePayload({ type: 'custom', id: '0' }, { option: { text: 'B', value: 'B', selected: false } })
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('and custom all value matches an option', async () => {
|
||||
const allValue = '.*';
|
||||
const urlValue = allValue;
|
||||
const custom = customBuilder()
|
||||
.withId('0')
|
||||
.withMulti(false)
|
||||
.withIncludeAll()
|
||||
.withAllValue(allValue)
|
||||
.withOptions('A', 'B', '.*')
|
||||
.withCurrent('A')
|
||||
.build();
|
||||
|
||||
custom.options[2].value = 'special value for .*';
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
.givenRootReducer(getTemplatingRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(custom, { global: false, index: 0, model: custom })))
|
||||
.whenAsyncActionIsDispatched(setOptionFromUrl(toVariableIdentifier(custom), urlValue), true);
|
||||
|
||||
await tester.thenDispatchedActionsShouldEqual(
|
||||
setCurrentVariableValue(
|
||||
toVariablePayload(
|
||||
{ type: 'custom', id: '0' },
|
||||
{ option: { text: '.*', value: 'special value for .*', selected: false } }
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user