Commit cace879c by Torkel Ödegaard Committed by GitHub

Templating: Fixed recursive queries triggered when switching dashboard settings view (#26137)

* Templating: Fixed recursive queries triggered when going into dashboard settings

* Fixed unused import

* use locationUtil
parent 8ab5d2dd
...@@ -40,4 +40,14 @@ describe('when checking template variables', () => { ...@@ -40,4 +40,14 @@ describe('when checking template variables', () => {
expect(findTemplateVarChanges(b, a)).toBeUndefined(); expect(findTemplateVarChanges(b, a)).toBeUndefined();
expect(findTemplateVarChanges(a, b)).toBeUndefined(); expect(findTemplateVarChanges(a, b)).toBeUndefined();
}); });
it('then should ignore empty array values', () => {
const a: UrlQueryMap = {
'var-adhoc': [],
};
const b: UrlQueryMap = {};
expect(findTemplateVarChanges(b, a)).toBeUndefined();
expect(findTemplateVarChanges(a, b)).toBeUndefined();
});
}); });
...@@ -8,6 +8,7 @@ import { GrafanaRootScope } from 'app/routes/GrafanaCtrl'; ...@@ -8,6 +8,7 @@ import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
import { locationUtil, UrlQueryMap } from '@grafana/data'; import { locationUtil, UrlQueryMap } from '@grafana/data';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { templateVarsChangedInUrl } from 'app/features/variables/state/actions'; import { templateVarsChangedInUrl } from 'app/features/variables/state/actions';
import { isArray, isEqual } from 'lodash';
// Services that handles angular -> redux store sync & other react <-> angular sync // Services that handles angular -> redux store sync & other react <-> angular sync
export class BridgeSrv { export class BridgeSrv {
...@@ -15,6 +16,7 @@ export class BridgeSrv { ...@@ -15,6 +16,7 @@ export class BridgeSrv {
private lastQuery: UrlQueryMap = {}; private lastQuery: UrlQueryMap = {};
private lastPath = ''; private lastPath = '';
private angularUrl: string; private angularUrl: string;
private lastUrl: string | null = null;
/** @ngInject */ /** @ngInject */
constructor( constructor(
...@@ -62,6 +64,11 @@ export class BridgeSrv { ...@@ -62,6 +64,11 @@ export class BridgeSrv {
const state = store.getState(); const state = store.getState();
const url = state.location.url; const url = state.location.url;
// No url change ignore redux store change
if (url === this.lastUrl) {
return;
}
if (this.angularUrl !== url) { if (this.angularUrl !== url) {
// store angular url right away as otherwise we end up syncing multiple times // store angular url right away as otherwise we end up syncing multiple times
this.angularUrl = url; this.angularUrl = url;
...@@ -90,7 +97,9 @@ export class BridgeSrv { ...@@ -90,7 +97,9 @@ export class BridgeSrv {
} else { } else {
this.lastQuery = {}; this.lastQuery = {};
} }
this.lastPath = state.location.path; this.lastPath = state.location.path;
this.lastUrl = state.location.url;
}); });
appEvents.on(CoreEvents.locationChange, payload => { appEvents.on(CoreEvents.locationChange, payload => {
...@@ -111,19 +120,45 @@ export class BridgeSrv { ...@@ -111,19 +120,45 @@ export class BridgeSrv {
export function findTemplateVarChanges(query: UrlQueryMap, old: UrlQueryMap): UrlQueryMap | undefined { export function findTemplateVarChanges(query: UrlQueryMap, old: UrlQueryMap): UrlQueryMap | undefined {
let count = 0; let count = 0;
const changes: UrlQueryMap = {}; const changes: UrlQueryMap = {};
for (const key in query) { for (const key in query) {
if (!key.startsWith('var-')) { if (!key.startsWith('var-')) {
continue; continue;
} }
if (query[key] !== old[key]) {
changes[key] = query[key]; let oldValue = getUrlValueForComparison(old[key]);
let newValue = getUrlValueForComparison(query[key]);
if (!isEqual(newValue, oldValue)) {
changes[key] = newValue;
count++; count++;
} }
} }
function getUrlValueForComparison(value: any): any {
if (isArray(value)) {
if (value.length === 0) {
value = undefined;
} else if (value.length === 1) {
value = value[0];
}
}
return value;
}
for (const key in old) { for (const key in old) {
if (!key.startsWith('var-')) { if (!key.startsWith('var-')) {
continue; continue;
} }
const value = old[key];
// ignore empty array values
if (isArray(value) && value.length === 0) {
continue;
}
if (!query.hasOwnProperty(key)) { if (!query.hasOwnProperty(key)) {
changes[key] = ''; // removed changes[key] = ''; // removed
count++; count++;
......
import $ from 'jquery';
import _ from 'lodash'; import _ from 'lodash';
import angular, { ILocationService, IScope } from 'angular'; import angular, { ILocationService, IScope } from 'angular';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { appEvents, contextSrv, coreModule } from 'app/core/core'; import { appEvents, contextSrv, coreModule } from 'app/core/core';
import { DashboardModel } from '../../state/DashboardModel'; import { DashboardModel } from '../../state/DashboardModel';
import { getConfig } from 'app/core/config';
import { DashboardSrv } from '../../services/DashboardSrv'; import { DashboardSrv } from '../../services/DashboardSrv';
import { CoreEvents } from 'app/types'; import { CoreEvents } from 'app/types';
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl'; import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
import { AppEvents, locationUtil, TimeZone } from '@grafana/data'; import { AppEvents, locationUtil, TimeZone, urlUtil } from '@grafana/data';
import { promiseToDigest } from '../../../../core/utils/promiseToDigest'; import { promiseToDigest } from '../../../../core/utils/promiseToDigest';
import { deleteDashboard } from 'app/features/manage-dashboards/state/actions'; import { deleteDashboard } from 'app/features/manage-dashboards/state/actions';
...@@ -121,8 +119,7 @@ export class SettingsCtrl { ...@@ -121,8 +119,7 @@ export class SettingsCtrl {
const url = this.$location.path(); const url = this.$location.path();
for (const section of this.sections) { for (const section of this.sections) {
const sectionParams = _.defaults({ editview: section.id }, params); section.url = locationUtil.assureBaseUrl(urlUtil.renderUrl(url, { ...params, editview: section.id }));
section.url = getConfig().appSubUrl + url + '?' + $.param(sectionParams);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment