Variables: Selectively reload panels on URL update (#51003)

This commit is contained in:
Todd Treece 2022-06-24 13:06:36 -04:00 committed by GitHub
parent 7e1667ce87
commit 342344bb03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 9 deletions

View File

@ -4900,12 +4900,12 @@ exports[`no explicit any`] = {
[270, 29, 3, "Unexpected any. Specify a different type.", "193409811"],
[754, 26, 3, "Unexpected any. Specify a different type.", "193409811"]
],
"public/app/features/variables/state/actions.ts:2709491277": [
"public/app/features/variables/state/actions.ts:443730774": [
[601, 32, 3, "Unexpected any. Specify a different type.", "193409811"],
[678, 32, 3, "Unexpected any. Specify a different type.", "193409811"],
[716, 90, 3, "Unexpected any. Specify a different type.", "193409811"],
[860, 9, 3, "Unexpected any. Specify a different type.", "193409811"],
[934, 32, 3, "Unexpected any. Specify a different type.", "193409811"]
[731, 90, 3, "Unexpected any. Specify a different type.", "193409811"],
[875, 9, 3, "Unexpected any. Specify a different type.", "193409811"],
[949, 32, 3, "Unexpected any. Specify a different type.", "193409811"]
],
"public/app/features/variables/state/initVariableTransaction.test.ts:1177248976": [
[55, 29, 3, "Unexpected any. Specify a different type.", "193409811"],

View File

@ -678,7 +678,9 @@ export const templateVarsChangedInUrl =
async (dispatch, getState) => {
const update: Array<Promise<any>> = [];
const dashboard = getState().dashboard.getModel();
for (const variable of getVariablesByKey(key, getState())) {
const panelIds = new Set<number>();
const variables = getVariablesByKey(key, getState());
for (const variable of variables) {
const key = `var-${variable.name}`;
if (!vars.hasOwnProperty(key)) {
// key not found quick exit
@ -704,13 +706,26 @@ export const templateVarsChangedInUrl =
}
}
// for adhoc variables we don't know which panels that will be impacted
if (!isAdHoc(variable)) {
getAllAffectedPanelIdsForVariableChange(variable.id, variables, dashboard?.panels ?? []).forEach((id) =>
panelIds.add(id)
);
}
const promise = variableAdapters.get(variable.type).setValueFromUrl(variable, value);
update.push(promise);
}
if (update.length) {
await Promise.all(update);
events.publish(new VariablesChangedInUrl({ panelIds: [], refreshAll: true }));
events.publish(
new VariablesChangedInUrl({
refreshAll: panelIds.size === 0,
panelIds: Array.from(panelIds),
})
);
}
};

View File

@ -1,5 +1,5 @@
import { DashboardState, StoreState } from '../../../types';
import { DashboardModel } from '../../dashboard/state';
import { DashboardModel, PanelModel } from '../../dashboard/state';
import { initialState } from '../../dashboard/state/reducers';
import { variableAdapters } from '../adapters';
import { createConstantVariableAdapter } from '../constant/adapter';
@ -30,9 +30,62 @@ async function getTestContext(urlQueryMap: ExtendedUrlQueryMap = {}, variable: V
.build();
}
const variableB = customBuilder()
.withId('variableB')
.withRootStateKey(key)
.withName('variableB')
.withCurrent(['B'])
.withOptions('A', 'B', 'C')
.build();
const setValueFromUrlMock = jest.fn();
variableAdapters.get(variable.type).setValueFromUrl = setValueFromUrlMock;
const modelJson = {
id: 1,
type: 'table',
maxDataPoints: 100,
interval: '5m',
showColumns: true,
targets: [{ refId: 'A', queryType: '${variable}' }, { noRefId: true }],
options: null,
fieldConfig: {
defaults: {
unit: 'mpg',
thresholds: {
mode: 'absolute',
steps: [
{ color: 'green', value: null },
{ color: 'red', value: 80 },
],
},
},
overrides: [
{
matcher: {
id: '1',
options: {},
},
properties: [
{
id: 'thresholds',
value: {
mode: 'absolute',
steps: [
{ color: 'green', value: null },
{ color: 'red', value: 80 },
],
},
},
],
},
],
},
};
const panelModelA = new PanelModel(modelJson);
const panelModelB = new PanelModel({ ...modelJson, id: 2, targets: [{ refId: 'B', queryType: '${variableB}' }] });
const templateVariableValueUpdatedMock = jest.fn();
const startRefreshMock = jest.fn();
const dashboard: DashboardState = {
@ -41,11 +94,12 @@ async function getTestContext(urlQueryMap: ExtendedUrlQueryMap = {}, variable: V
dashboardModel.templateVariableValueUpdated = templateVariableValueUpdatedMock;
dashboardModel.startRefresh = startRefreshMock;
dashboardModel.templating = { list: [variable] };
dashboardModel.panels = [panelModelA, panelModelB];
return dashboardModel;
},
};
const variables: VariablesState = { variable };
const variables: VariablesState = { variable, variableB };
const state: Partial<StoreState> = {
dashboard,
...getPreloadedState(key, { variables }),
@ -57,7 +111,7 @@ async function getTestContext(urlQueryMap: ExtendedUrlQueryMap = {}, variable: V
await thunk(dispatch, getState, undefined);
return { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable };
return { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable, variableB };
}
describe('templateVarsChangedInUrl', () => {
@ -107,6 +161,20 @@ describe('templateVarsChangedInUrl', () => {
expect(setValueFromUrlMock).toHaveBeenCalledWith(variable, 'B');
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledWith({ refreshAll: false, panelIds: [1] });
});
it('should update URL value and only refresh panels with variableB dependency', async () => {
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variableB } =
await getTestContext({
'var-variableB': { value: 'A' },
});
expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
expect(setValueFromUrlMock).toHaveBeenCalledWith(variableB, 'A');
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledWith({ refreshAll: false, panelIds: [2] });
});
describe('but the values in url query map were removed', () => {