diff --git a/public/app/core/services/bridge_srv.test.ts b/public/app/core/services/bridge_srv.test.ts new file mode 100644 index 00000000000..7c141bdb2a1 --- /dev/null +++ b/public/app/core/services/bridge_srv.test.ts @@ -0,0 +1,15 @@ +import { UrlQueryMap } from '@grafana/runtime'; +import { findTemplateVarChanges } from './bridge_srv'; + +describe('when checking template variables', () => { + it('detect adding/removing a variable', () => { + const a: UrlQueryMap = {}; + const b: UrlQueryMap = { + 'var-xyz': 'hello', + aaa: 'ignore me', + }; + + expect(findTemplateVarChanges(b, a)).toEqual({ 'var-xyz': 'hello' }); + expect(findTemplateVarChanges(a, b)).toEqual({ 'var-xyz': '' }); + }); +}); diff --git a/public/app/core/services/bridge_srv.ts b/public/app/core/services/bridge_srv.ts index 20e6abe1b74..045b44beedc 100644 --- a/public/app/core/services/bridge_srv.ts +++ b/public/app/core/services/bridge_srv.ts @@ -6,10 +6,15 @@ import { updateLocation } from 'app/core/actions'; import { ITimeoutService, ILocationService, IWindowService } from 'angular'; import { CoreEvents } from 'app/types'; import { GrafanaRootScope } from 'app/routes/GrafanaCtrl'; +import { UrlQueryMap } from '@grafana/runtime'; +import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; +import { VariableSrv } from 'app/features/templating/all'; // Services that handles angular -> redux store sync & other react <-> angular sync export class BridgeSrv { private fullPageReloadRoutes: string[]; + private lastQuery: UrlQueryMap = {}; + private lastPath = ''; /** @ngInject */ constructor( @@ -17,7 +22,8 @@ export class BridgeSrv { private $timeout: ITimeoutService, private $window: IWindowService, private $rootScope: GrafanaRootScope, - private $route: any + private $route: any, + private variableSrv: VariableSrv ) { this.fullPageReloadRoutes = ['/logout']; } @@ -62,6 +68,21 @@ export class BridgeSrv { }); console.log('store updating angular $location.url', url); } + + // Check for template variable changes on a dashboard + if (state.location.path === this.lastPath) { + const changes = findTemplateVarChanges(state.location.query, this.lastQuery); + if (changes) { + const dash = getDashboardSrv().getCurrent(); + if (dash) { + this.variableSrv.templateVarsChangedInUrl(changes); + } + } + this.lastQuery = state.location.query; + } else { + this.lastQuery = {}; + } + this.lastPath = state.location.path; }); appEvents.on(CoreEvents.locationChange, payload => { @@ -79,4 +100,28 @@ export class BridgeSrv { } } +export function findTemplateVarChanges(query: UrlQueryMap, old: UrlQueryMap): UrlQueryMap | undefined { + let count = 0; + const changes: UrlQueryMap = {}; + for (const key in query) { + if (!key.startsWith('var-')) { + continue; + } + if (query[key] !== old[key]) { + changes[key] = query[key]; + count++; + } + } + for (const key in old) { + if (!key.startsWith('var-')) { + continue; + } + if (!query[key]) { + changes[key] = ''; // removed + count++; + } + } + return count ? changes : undefined; +} + coreModule.service('bridgeSrv', BridgeSrv); diff --git a/public/app/features/templating/variable_srv.ts b/public/app/features/templating/variable_srv.ts index 6d873b33fe0..25ee498a2e2 100644 --- a/public/app/features/templating/variable_srv.ts +++ b/public/app/features/templating/variable_srv.ts @@ -13,6 +13,7 @@ import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; // Types import { TimeRange } from '@grafana/data'; import { CoreEvents } from 'app/types'; +import { UrlQueryMap } from '@grafana/runtime'; export class VariableSrv { dashboard: DashboardModel; @@ -302,6 +303,22 @@ export class VariableSrv { return this.variableUpdated(variable); } + templateVarsChangedInUrl(vars: UrlQueryMap) { + const update: Array> = []; + for (const v of this.variables) { + const key = `var-${v.name}`; + if (vars.hasOwnProperty(key)) { + update.push(v.setValueFromUrl(vars[key])); + } + } + if (update.length) { + Promise.all(update).then(() => { + this.dashboard.templateVariableValueUpdated(); + this.dashboard.startRefresh(); + }); + } + } + updateUrlParamsWithCurrentVariables() { // update url const params = this.$location.search();