Commit c7ffc119 by Hugo Häggmark Committed by GitHub

Variables: turns on newVariables as a new default (#23272)

* Variables: turns on newVariables as default

* Chore: adds default templating state

* Some small refactorings to get the template_srv tests to get green when toggle is enabled by default.

* Refactor: adds getVariables dependency to DashboardModel

* Tests: fixes StackDriver tests

* Tests: updates snapshots

* Tests: updates snapshot for DashboardGrid.test.tsx

* Tests: fixes DashboardModel.test.ts

* fixed initDashboard tests.

* renamed variable.

* changed so we use the templating.list when running the migration work.

* changed so we always returns the variables in sorted order.

* Tests: fixed cloudwatch tests

* added so we set the global template variable props.

* Fixed tests and added moved logic to complete templateSrv variables.

* removed unneccesary updateIndex.

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
parent bf046d75
...@@ -71,7 +71,7 @@ export class GrafanaBootConfig { ...@@ -71,7 +71,7 @@ export class GrafanaBootConfig {
expressions: false, expressions: false,
newEdit: false, newEdit: false,
meta: false, meta: false,
newVariables: false, newVariables: true,
tracingIntegration: false, tracingIntegration: false,
}; };
licenseInfo: LicenseInfo = {} as LicenseInfo; licenseInfo: LicenseInfo = {} as LicenseInfo;
......
...@@ -29,6 +29,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` ...@@ -29,6 +29,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -118,7 +119,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` ...@@ -118,7 +119,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
<div <div
className="dashboard-container" className="dashboard-container"
> >
<AngularSubMenu <SubMenu
dashboard={ dashboard={
DashboardModel { DashboardModel {
"annotations": Object { "annotations": Object {
...@@ -144,6 +145,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` ...@@ -144,6 +145,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -239,6 +241,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1` ...@@ -239,6 +241,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -364,6 +367,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ...@@ -364,6 +367,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -453,7 +457,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ...@@ -453,7 +457,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
<div <div
className="dashboard-container" className="dashboard-container"
> >
<AngularSubMenu <SubMenu
dashboard={ dashboard={
DashboardModel { DashboardModel {
"annotations": Object { "annotations": Object {
...@@ -479,6 +483,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ...@@ -479,6 +483,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -574,6 +579,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ...@@ -574,6 +579,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -675,6 +681,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti ...@@ -675,6 +681,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
......
...@@ -106,6 +106,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ...@@ -106,6 +106,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -354,6 +355,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ...@@ -354,6 +355,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -602,6 +604,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ...@@ -602,6 +604,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
...@@ -850,6 +853,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = ` ...@@ -850,6 +853,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
}, },
}, },
"getVariables": [Function], "getVariables": [Function],
"getVariablesFromState": [Function],
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
......
...@@ -127,9 +127,8 @@ export class DashboardMigrator { ...@@ -127,9 +127,8 @@ export class DashboardMigrator {
} }
// update template variables // update template variables
const variables = this.dashboard.getVariables(); for (i = 0; i < this.dashboard.templating.list.length; i++) {
for (i = 0; i < variables.length; i++) { const variable = this.dashboard.templating.list[i];
const variable = variables[i];
if (variable.datasource === void 0) { if (variable.datasource === void 0) {
variable.datasource = null; variable.datasource = null;
} }
......
import _ from 'lodash'; import _ from 'lodash';
import { DashboardModel } from '../state/DashboardModel'; import { DashboardModel } from '../state/DashboardModel';
import { expect } from 'test/lib/common'; import { expect } from 'test/lib/common';
import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
jest.mock('app/core/services/context_srv', () => ({})); jest.mock('app/core/services/context_srv', () => ({}));
...@@ -31,7 +32,7 @@ describe('given dashboard with panel repeat', () => { ...@@ -31,7 +32,7 @@ describe('given dashboard with panel repeat', () => {
], ],
}, },
}; };
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
}); });
...@@ -59,7 +60,7 @@ describe('given dashboard with panel repeat in horizontal direction', () => { ...@@ -59,7 +60,7 @@ describe('given dashboard with panel repeat in horizontal direction', () => {
let dashboard: any; let dashboard: any;
beforeEach(() => { beforeEach(() => {
dashboard = new DashboardModel({ const dashboardJSON = {
panels: [ panels: [
{ {
id: 2, id: 2,
...@@ -85,7 +86,8 @@ describe('given dashboard with panel repeat in horizontal direction', () => { ...@@ -85,7 +86,8 @@ describe('given dashboard with panel repeat in horizontal direction', () => {
}, },
], ],
}, },
}); };
dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
}); });
...@@ -191,7 +193,7 @@ describe('given dashboard with panel repeat in vertical direction', () => { ...@@ -191,7 +193,7 @@ describe('given dashboard with panel repeat in vertical direction', () => {
let dashboard: any; let dashboard: any;
beforeEach(() => { beforeEach(() => {
dashboard = new DashboardModel({ const dashboardJSON = {
panels: [ panels: [
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, h: 1, w: 24 } }, { id: 1, type: 'row', gridPos: { x: 0, y: 0, h: 1, w: 24 } },
{ id: 2, repeat: 'apps', repeatDirection: 'v', gridPos: { x: 5, y: 1, h: 2, w: 8 } }, { id: 2, repeat: 'apps', repeatDirection: 'v', gridPos: { x: 5, y: 1, h: 2, w: 8 } },
...@@ -214,7 +216,8 @@ describe('given dashboard with panel repeat in vertical direction', () => { ...@@ -214,7 +216,8 @@ describe('given dashboard with panel repeat in vertical direction', () => {
}, },
], ],
}, },
}); };
dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
}); });
...@@ -230,7 +233,7 @@ describe('given dashboard with panel repeat in vertical direction', () => { ...@@ -230,7 +233,7 @@ describe('given dashboard with panel repeat in vertical direction', () => {
}); });
describe('given dashboard with row repeat and panel repeat in horizontal direction', () => { describe('given dashboard with row repeat and panel repeat in horizontal direction', () => {
let dashboard: any, dashboardJSON; let dashboard: any, dashboardJSON: any;
beforeEach(() => { beforeEach(() => {
dashboardJSON = { dashboardJSON = {
...@@ -269,7 +272,7 @@ describe('given dashboard with row repeat and panel repeat in horizontal directi ...@@ -269,7 +272,7 @@ describe('given dashboard with row repeat and panel repeat in horizontal directi
], ],
}, },
}; };
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(false); dashboard.processRepeats(false);
}); });
...@@ -348,7 +351,7 @@ describe('given dashboard with row repeat', () => { ...@@ -348,7 +351,7 @@ describe('given dashboard with row repeat', () => {
], ],
}, },
}; };
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
}); });
...@@ -359,7 +362,7 @@ describe('given dashboard with row repeat', () => { ...@@ -359,7 +362,7 @@ describe('given dashboard with row repeat', () => {
it('should set scopedVars for each panel', () => { it('should set scopedVars for each panel', () => {
dashboardJSON.templating.list[0].options[2].selected = true; dashboardJSON.templating.list[0].options[2].selected = true;
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
expect(dashboard.panels[1].scopedVars).toMatchObject({ expect(dashboard.panels[1].scopedVars).toMatchObject({
...@@ -399,7 +402,7 @@ describe('given dashboard with row repeat', () => { ...@@ -399,7 +402,7 @@ describe('given dashboard with row repeat', () => {
{ id: 4, type: 'row', gridPos: { x: 0, y: 1, h: 1, w: 24 } }, { id: 4, type: 'row', gridPos: { x: 0, y: 1, h: 1, w: 24 } },
{ id: 5, type: 'graph', gridPos: { x: 0, y: 2, h: 1, w: 12 } }, { id: 5, type: 'graph', gridPos: { x: 0, y: 2, h: 1, w: 12 } },
]; ];
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
const panelTypes = _.map(dashboard.panels, 'type'); const panelTypes = _.map(dashboard.panels, 'type');
...@@ -441,7 +444,7 @@ describe('given dashboard with row repeat', () => { ...@@ -441,7 +444,7 @@ describe('given dashboard with row repeat', () => {
{ text: 'backend03', value: 'backend03', selected: false }, { text: 'backend03', value: 'backend03', selected: false },
], ],
}); });
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
const panelTypes = _.map(dashboard.panels, 'type'); const panelTypes = _.map(dashboard.panels, 'type');
...@@ -488,7 +491,7 @@ describe('given dashboard with row repeat', () => { ...@@ -488,7 +491,7 @@ describe('given dashboard with row repeat', () => {
{ id: 4, type: 'row', gridPos: { x: 0, y: 1, h: 1, w: 24 } }, { id: 4, type: 'row', gridPos: { x: 0, y: 1, h: 1, w: 24 } },
{ id: 5, type: 'graph', gridPos: { x: 0, y: 2, h: 1, w: 12 } }, { id: 5, type: 'graph', gridPos: { x: 0, y: 2, h: 1, w: 12 } },
]; ];
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
const panelIds = _.flattenDeep( const panelIds = _.flattenDeep(
...@@ -511,7 +514,7 @@ describe('given dashboard with row repeat', () => { ...@@ -511,7 +514,7 @@ describe('given dashboard with row repeat', () => {
{ id: 3, type: 'graph', gridPos: { x: 6, y: 1, h: 4, w: 12 } }, { id: 3, type: 'graph', gridPos: { x: 6, y: 1, h: 4, w: 12 } },
{ id: 4, type: 'graph', gridPos: { x: 0, y: 5, h: 2, w: 12 } }, { id: 4, type: 'graph', gridPos: { x: 0, y: 5, h: 2, w: 12 } },
]; ];
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
const panelTypes = _.map(dashboard.panels, 'type'); const panelTypes = _.map(dashboard.panels, 'type');
...@@ -564,7 +567,7 @@ describe('given dashboard with row and panel repeat', () => { ...@@ -564,7 +567,7 @@ describe('given dashboard with row and panel repeat', () => {
], ],
}, },
}; };
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
}); });
...@@ -592,7 +595,7 @@ describe('given dashboard with row and panel repeat', () => { ...@@ -592,7 +595,7 @@ describe('given dashboard with row and panel repeat', () => {
}, },
{ id: 12, type: 'graph', repeatPanelId: 2, repeatIteration: 101, gridPos: { x: 0, y: 3, h: 1, w: 6 } }, { id: 12, type: 'graph', repeatPanelId: 2, repeatIteration: 101, gridPos: { x: 0, y: 3, h: 1, w: 6 } },
]; ];
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
const panelTypes = _.map(dashboard.panels, 'type'); const panelTypes = _.map(dashboard.panels, 'type');
...@@ -600,7 +603,7 @@ describe('given dashboard with row and panel repeat', () => { ...@@ -600,7 +603,7 @@ describe('given dashboard with row and panel repeat', () => {
}); });
it('should set scopedVars for each row', () => { it('should set scopedVars for each row', () => {
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
expect(dashboard.panels[0].scopedVars).toMatchObject({ expect(dashboard.panels[0].scopedVars).toMatchObject({
...@@ -612,7 +615,7 @@ describe('given dashboard with row and panel repeat', () => { ...@@ -612,7 +615,7 @@ describe('given dashboard with row and panel repeat', () => {
}); });
it('should set panel-repeat variable for each panel', () => { it('should set panel-repeat variable for each panel', () => {
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
expect(dashboard.panels[1].scopedVars).toMatchObject({ expect(dashboard.panels[1].scopedVars).toMatchObject({
...@@ -631,7 +634,7 @@ describe('given dashboard with row and panel repeat', () => { ...@@ -631,7 +634,7 @@ describe('given dashboard with row and panel repeat', () => {
}); });
it('should set row-repeat variable for each panel', () => { it('should set row-repeat variable for each panel', () => {
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
expect(dashboard.panels[1].scopedVars).toMatchObject({ expect(dashboard.panels[1].scopedVars).toMatchObject({
...@@ -650,7 +653,7 @@ describe('given dashboard with row and panel repeat', () => { ...@@ -650,7 +653,7 @@ describe('given dashboard with row and panel repeat', () => {
}); });
it('should repeat panels when row is expanding', () => { it('should repeat panels when row is expanding', () => {
dashboard = new DashboardModel(dashboardJSON); dashboard = getDashboardModel(dashboardJSON);
dashboard.processRepeats(); dashboard.processRepeats();
expect(dashboard.panels.length).toBe(6); expect(dashboard.panels.length).toBe(6);
......
import _ from 'lodash'; import _ from 'lodash';
import { DashboardModel } from '../state/DashboardModel'; import { DashboardModel } from '../state/DashboardModel';
import { PanelModel } from '../state/PanelModel'; import { PanelModel } from '../state/PanelModel';
import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
import { variableAdapters } from '../../variables/adapters';
import { createAdHocVariableAdapter } from '../../variables/adhoc/adapter';
import { createQueryVariableAdapter } from '../../variables/query/adapter';
jest.mock('app/core/services/context_srv', () => ({})); jest.mock('app/core/services/context_srv', () => ({}));
variableAdapters.setInit(() => [createQueryVariableAdapter(), createAdHocVariableAdapter()]);
describe('DashboardModel', () => { describe('DashboardModel', () => {
describe('when creating new dashboard model defaults only', () => { describe('when creating new dashboard model defaults only', () => {
...@@ -498,7 +503,7 @@ describe('DashboardModel', () => { ...@@ -498,7 +503,7 @@ describe('DashboardModel', () => {
let model: DashboardModel; let model: DashboardModel;
beforeEach(() => { beforeEach(() => {
model = new DashboardModel({ const json = {
templating: { templating: {
list: [ list: [
{ {
...@@ -512,7 +517,8 @@ describe('DashboardModel', () => { ...@@ -512,7 +517,8 @@ describe('DashboardModel', () => {
}, },
], ],
}, },
}); };
model = getDashboardModel(json);
expect(model.hasVariableValuesChanged()).toBeFalsy(); expect(model.hasVariableValuesChanged()).toBeFalsy();
}); });
...@@ -562,7 +568,7 @@ describe('DashboardModel', () => { ...@@ -562,7 +568,7 @@ describe('DashboardModel', () => {
let model: DashboardModel; let model: DashboardModel;
beforeEach(() => { beforeEach(() => {
model = new DashboardModel({ const json = {
templating: { templating: {
list: [ list: [
{ {
...@@ -578,7 +584,8 @@ describe('DashboardModel', () => { ...@@ -578,7 +584,8 @@ describe('DashboardModel', () => {
}, },
], ],
}, },
}); };
model = getDashboardModel(json);
expect(model.hasVariableValuesChanged()).toBeFalsy(); expect(model.hasVariableValuesChanged()).toBeFalsy();
}); });
......
...@@ -14,7 +14,7 @@ import { AppEvent, dateTime, DateTimeInput, isDateTime, PanelEvents, TimeRange, ...@@ -14,7 +14,7 @@ import { AppEvent, dateTime, DateTimeInput, isDateTime, PanelEvents, TimeRange,
import { UrlQueryValue } from '@grafana/runtime'; import { UrlQueryValue } from '@grafana/runtime';
import { CoreEvents, DashboardMeta, KIOSK_MODE_TV } from 'app/types'; import { CoreEvents, DashboardMeta, KIOSK_MODE_TV } from 'app/types';
import { getConfig } from '../../../core/config'; import { getConfig } from '../../../core/config';
import { getVariables } from 'app/features/variables/state/selectors'; import { GetVariables, getVariables } from 'app/features/variables/state/selectors';
import { variableAdapters } from 'app/features/variables/adapters'; import { variableAdapters } from 'app/features/variables/adapters';
import { onTimeRangeUpdated } from 'app/features/variables/state/actions'; import { onTimeRangeUpdated } from 'app/features/variables/state/actions';
import { dispatch } from '../../../store/store'; import { dispatch } from '../../../store/store';
...@@ -69,9 +69,10 @@ export class DashboardModel { ...@@ -69,9 +69,10 @@ export class DashboardModel {
originalTime: true, originalTime: true,
originalTemplating: true, originalTemplating: true,
panelInEdit: true, panelInEdit: true,
getVariablesFromState: true,
}; };
constructor(data: any, meta?: DashboardMeta) { constructor(data: any, meta?: DashboardMeta, private getVariablesFromState: GetVariables = getVariables) {
if (!data) { if (!data) {
data = {}; data = {};
} }
...@@ -238,7 +239,7 @@ export class DashboardModel { ...@@ -238,7 +239,7 @@ export class DashboardModel {
defaults: { saveTimerange: boolean; saveVariables: boolean } & CloneOptions defaults: { saveTimerange: boolean; saveVariables: boolean } & CloneOptions
) { ) {
const originalVariables = this.originalTemplating; const originalVariables = this.originalTemplating;
const currentVariables = getVariables(); const currentVariables = this.getVariablesFromState();
copy.templating = { copy.templating = {
list: currentVariables.map(variable => variableAdapters.get(variable.type).getSaveModel(variable)), list: currentVariables.map(variable => variableAdapters.get(variable.type).getSaveModel(variable)),
...@@ -940,12 +941,12 @@ export class DashboardModel { ...@@ -940,12 +941,12 @@ export class DashboardModel {
return; return;
} }
this.originalTemplating = this.cloneVariablesFrom(getVariables()); this.originalTemplating = this.cloneVariablesFrom(this.getVariablesFromState());
} }
hasVariableValuesChanged() { hasVariableValuesChanged() {
if (getConfig().featureToggles.newVariables) { if (getConfig().featureToggles.newVariables) {
return this.hasVariablesChanged(this.originalTemplating, getVariables()); return this.hasVariablesChanged(this.originalTemplating, this.getVariablesFromState());
} }
return this.hasVariablesChanged(this.originalTemplating, this.templating.list); return this.hasVariablesChanged(this.originalTemplating, this.templating.list);
...@@ -1019,7 +1020,7 @@ export class DashboardModel { ...@@ -1019,7 +1020,7 @@ export class DashboardModel {
getVariables = () => { getVariables = () => {
if (getConfig().featureToggles.newVariables) { if (getConfig().featureToggles.newVariables) {
return getVariables(); return this.getVariablesFromState();
} }
return this.templating.list; return this.templating.list;
}; };
...@@ -1029,7 +1030,7 @@ export class DashboardModel { ...@@ -1029,7 +1030,7 @@ export class DashboardModel {
return _.find(this.templating.list, { name: panel.repeat } as any); return _.find(this.templating.list, { name: panel.repeat } as any);
} }
return getVariables().find(variable => variable.name === panel.repeat); return this.getVariablesFromState().find(variable => variable.name === panel.repeat);
} }
private isSnapshotTruthy() { private isSnapshotTruthy() {
...@@ -1038,7 +1039,7 @@ export class DashboardModel { ...@@ -1038,7 +1039,7 @@ export class DashboardModel {
private hasVariables() { private hasVariables() {
if (getConfig().featureToggles.newVariables) { if (getConfig().featureToggles.newVariables) {
return getVariables().length > 0; return this.getVariablesFromState().length > 0;
} }
return this.templating.list.length > 0; return this.templating.list.length > 0;
} }
......
...@@ -7,9 +7,30 @@ import { dashboardInitCompleted, dashboardInitFetching, dashboardInitServices } ...@@ -7,9 +7,30 @@ import { dashboardInitCompleted, dashboardInitFetching, dashboardInitServices }
import { updateLocation } from '../../../core/actions'; import { updateLocation } from '../../../core/actions';
import { setEchoSrv } from '@grafana/runtime'; import { setEchoSrv } from '@grafana/runtime';
import { Echo } from '../../../core/services/echo/Echo'; import { Echo } from '../../../core/services/echo/Echo';
import { getConfig } from 'app/core/config';
import { variableAdapters } from 'app/features/variables/adapters';
import { createConstantVariableAdapter } from 'app/features/variables/constant/adapter';
import { addVariable } from 'app/features/variables/state/sharedReducer';
import { constantBuilder } from 'app/features/variables/shared/testing/builders';
jest.mock('app/core/services/backend_srv'); jest.mock('app/core/services/backend_srv');
jest.mock('app/features/dashboard/services/TimeSrv', () => {
const original = jest.requireActual('app/features/dashboard/services/TimeSrv');
return {
...original,
getTimeSrv: () => ({
...original.getTimeSrv(),
timeRange: jest.fn().mockReturnValue(undefined),
}),
};
});
jest.mock('app/core/services/context_srv', () => ({
contextSrv: {
user: { orgId: 1, orgName: 'TestOrg' },
},
}));
variableAdapters.register(createConstantVariableAdapter());
const mockStore = configureMockStore([thunk]); const mockStore = configureMockStore([thunk]);
interface ScenarioContext { interface ScenarioContext {
...@@ -61,6 +82,9 @@ function describeInitScenario(description: string, scenarioFn: ScenarioFn) { ...@@ -61,6 +82,9 @@ function describeInitScenario(description: string, scenarioFn: ScenarioFn) {
], ],
}, },
], ],
templating: {
list: [constantBuilder().build()],
},
}, },
})), })),
}; };
...@@ -118,6 +142,9 @@ function describeInitScenario(description: string, scenarioFn: ScenarioFn) { ...@@ -118,6 +142,9 @@ function describeInitScenario(description: string, scenarioFn: ScenarioFn) {
queries: [], queries: [],
}, },
}, },
templating: {
variables: {},
},
}, },
setup: (fn: () => void) => { setup: (fn: () => void) => {
setupFn = fn; setupFn = fn;
...@@ -166,11 +193,17 @@ describeInitScenario('Initializing new dashboard', ctx => { ...@@ -166,11 +193,17 @@ describeInitScenario('Initializing new dashboard', ctx => {
it('Should initialize services', () => { it('Should initialize services', () => {
expect(ctx.timeSrv.init).toBeCalled(); expect(ctx.timeSrv.init).toBeCalled();
expect(ctx.annotationsSrv.init).toBeCalled(); expect(ctx.annotationsSrv.init).toBeCalled();
expect(ctx.variableSrv.init).toBeCalled();
expect(ctx.unsavedChangesSrv.init).toBeCalled(); expect(ctx.unsavedChangesSrv.init).toBeCalled();
expect(ctx.keybindingSrv.setupDashboardBindings).toBeCalled(); expect(ctx.keybindingSrv.setupDashboardBindings).toBeCalled();
expect(ctx.dashboardSrv.setCurrent).toBeCalled(); expect(ctx.dashboardSrv.setCurrent).toBeCalled();
}); });
it('Should initialize variableSrv if newVariables is disabled', () => {
if (getConfig().featureToggles.newVariables) {
return expect.assertions(0);
}
expect(ctx.variableSrv.init).toBeCalled();
});
}); });
describeInitScenario('Initializing home dashboard', ctx => { describeInitScenario('Initializing home dashboard', ctx => {
...@@ -224,16 +257,30 @@ describeInitScenario('Initializing existing dashboard', ctx => { ...@@ -224,16 +257,30 @@ describeInitScenario('Initializing existing dashboard', ctx => {
}); });
it('Should send action dashboardInitCompleted', () => { it('Should send action dashboardInitCompleted', () => {
expect(ctx.actions[3].type).toBe(dashboardInitCompleted.type); const index = getConfig().featureToggles.newVariables ? 4 : 3;
expect(ctx.actions[3].payload.title).toBe('My cool dashboard'); expect(ctx.actions[index].type).toBe(dashboardInitCompleted.type);
expect(ctx.actions[index].payload.title).toBe('My cool dashboard');
}); });
it('Should initialize services', () => { it('Should initialize services', () => {
expect(ctx.timeSrv.init).toBeCalled(); expect(ctx.timeSrv.init).toBeCalled();
expect(ctx.annotationsSrv.init).toBeCalled(); expect(ctx.annotationsSrv.init).toBeCalled();
expect(ctx.variableSrv.init).toBeCalled();
expect(ctx.unsavedChangesSrv.init).toBeCalled(); expect(ctx.unsavedChangesSrv.init).toBeCalled();
expect(ctx.keybindingSrv.setupDashboardBindings).toBeCalled(); expect(ctx.keybindingSrv.setupDashboardBindings).toBeCalled();
expect(ctx.dashboardSrv.setCurrent).toBeCalled(); expect(ctx.dashboardSrv.setCurrent).toBeCalled();
}); });
it('Should initialize variableSrv if newVariables is disabled', () => {
if (getConfig().featureToggles.newVariables) {
return expect.assertions(0);
}
expect(ctx.variableSrv.init).toBeCalled();
});
it('Should initialize redux variables if newVariables is enabled', () => {
if (!getConfig().featureToggles.newVariables) {
return expect.assertions(0);
}
expect(ctx.actions[3].type).toBe(addVariable.type);
});
}); });
...@@ -23,7 +23,7 @@ import { DashboardDTO, DashboardRouteInfo, StoreState, ThunkDispatch, ThunkResul ...@@ -23,7 +23,7 @@ import { DashboardDTO, DashboardRouteInfo, StoreState, ThunkDispatch, ThunkResul
import { DashboardModel } from './DashboardModel'; import { DashboardModel } from './DashboardModel';
import { DataQuery } from '@grafana/data'; import { DataQuery } from '@grafana/data';
import { getConfig } from '../../../core/config'; import { getConfig } from '../../../core/config';
import { initDashboardTemplating, processVariables } from '../../variables/state/actions'; import { initDashboardTemplating, processVariables, completeDashboardTemplating } from '../../variables/state/actions';
import { emitDashboardViewEvent } from './analyticsProcessor'; import { emitDashboardViewEvent } from './analyticsProcessor';
export interface InitDashboardArgs { export interface InitDashboardArgs {
...@@ -185,8 +185,9 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult<void> { ...@@ -185,8 +185,9 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult<void> {
await variableSrv.init(dashboard); await variableSrv.init(dashboard);
} }
if (getConfig().featureToggles.newVariables) { if (getConfig().featureToggles.newVariables) {
await dispatch(initDashboardTemplating(dashboard.templating.list)); dispatch(initDashboardTemplating(dashboard.templating.list));
await dispatch(processVariables()); await dispatch(processVariables());
dispatch(completeDashboardTemplating(dashboard));
} }
} catch (err) { } catch (err) {
dispatch(notifyApp(createErrorNotification('Templating init failed', err))); dispatch(notifyApp(createErrorNotification('Templating init failed', err)));
......
import { TemplateSrv } from '../template_srv'; import { TemplateSrv } from '../template_srv';
import { convertToStoreState } from 'test/helpers/convertToStoreState';
import { getTemplateSrvDependencies } from '../../../../test/helpers/getTemplateSrvDependencies';
describe('templateSrv', () => { describe('templateSrv', () => {
let _templateSrv: any; let _templateSrv: any;
function initTemplateSrv(variables: any) { function initTemplateSrv(variables: any[]) {
_templateSrv = new TemplateSrv(); const state = convertToStoreState(variables);
_templateSrv = new TemplateSrv(getTemplateSrvDependencies(state));
_templateSrv.init(variables); _templateSrv.init(variables);
} }
......
...@@ -16,6 +16,18 @@ interface FieldAccessorCache { ...@@ -16,6 +16,18 @@ interface FieldAccessorCache {
[key: string]: (obj: any) => any; [key: string]: (obj: any) => any;
} }
export interface TemplateSrvDependencies {
getFilteredVariables: typeof getFilteredVariables;
getVariables: typeof getVariables;
getVariableWithName: typeof getVariableWithName;
}
const runtimeDependencies: TemplateSrvDependencies = {
getFilteredVariables,
getVariables,
getVariableWithName,
};
export class TemplateSrv { export class TemplateSrv {
private _variables: any[]; private _variables: any[];
private regex = variableRegex; private regex = variableRegex;
...@@ -25,7 +37,7 @@ export class TemplateSrv { ...@@ -25,7 +37,7 @@ export class TemplateSrv {
private timeRange?: TimeRange | null = null; private timeRange?: TimeRange | null = null;
private fieldAccessorCache: FieldAccessorCache = {}; private fieldAccessorCache: FieldAccessorCache = {};
constructor() { constructor(private dependencies: TemplateSrvDependencies = runtimeDependencies) {
this.builtIns['__interval'] = { text: '1s', value: '1s' }; this.builtIns['__interval'] = { text: '1s', value: '1s' };
this.builtIns['__interval_ms'] = { text: '100', value: '100' }; this.builtIns['__interval_ms'] = { text: '100', value: '100' };
this._variables = []; this._variables = [];
...@@ -53,7 +65,7 @@ export class TemplateSrv { ...@@ -53,7 +65,7 @@ export class TemplateSrv {
getVariables(): VariableModel[] { getVariables(): VariableModel[] {
if (getConfig().featureToggles.newVariables) { if (getConfig().featureToggles.newVariables) {
return getVariables(); return this.dependencies.getVariables();
} }
return this._variables; return this._variables;
...@@ -419,7 +431,7 @@ export class TemplateSrv { ...@@ -419,7 +431,7 @@ export class TemplateSrv {
} }
if (getConfig().featureToggles.newVariables && !this.index[name]) { if (getConfig().featureToggles.newVariables && !this.index[name]) {
return getVariableWithName(name); return this.dependencies.getVariableWithName(name);
} }
return this.index[name]; return this.index[name];
...@@ -427,7 +439,7 @@ export class TemplateSrv { ...@@ -427,7 +439,7 @@ export class TemplateSrv {
private getAdHocVariables = (): any[] => { private getAdHocVariables = (): any[] => {
if (getConfig().featureToggles.newVariables) { if (getConfig().featureToggles.newVariables) {
return getFilteredVariables(isAdHoc); return this.dependencies.getFilteredVariables(isAdHoc);
} }
if (Array.isArray(this._variables)) { if (Array.isArray(this._variables)) {
return this._variables.filter(isAdHoc); return this._variables.filter(isAdHoc);
......
...@@ -3,12 +3,11 @@ import { createConstantVariableAdapter } from './adapter'; ...@@ -3,12 +3,11 @@ import { createConstantVariableAdapter } from './adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester'; import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { TemplatingState } from 'app/features/variables/state/reducers'; import { TemplatingState } from 'app/features/variables/state/reducers';
import { updateConstantVariableOptions } from './actions'; import { updateConstantVariableOptions } from './actions';
import { getTemplatingRootReducer } from '../state/helpers'; import { getRootReducer } from '../state/helpers';
import { ConstantVariableModel, VariableHide, VariableOption } from '../../templating/types'; import { ConstantVariableModel, VariableHide, VariableOption } from '../../templating/types';
import { toVariablePayload } from '../state/types'; import { toVariablePayload } from '../state/types';
import { createConstantOptionsFromQuery } from './reducer'; import { createConstantOptionsFromQuery } from './reducer';
import { setCurrentVariableValue } from '../state/sharedReducer'; import { setCurrentVariableValue, addVariable } from '../state/sharedReducer';
import { initDashboardTemplating } from '../state/actions';
describe('constant actions', () => { describe('constant actions', () => {
variableAdapters.setInit(() => [createConstantVariableAdapter()]); variableAdapters.setInit(() => [createConstantVariableAdapter()]);
...@@ -40,8 +39,8 @@ describe('constant actions', () => { ...@@ -40,8 +39,8 @@ describe('constant actions', () => {
}; };
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(updateConstantVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateConstantVariableOptions(toVariablePayload(variable)), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
......
...@@ -2,11 +2,10 @@ import { variableAdapters } from '../adapters'; ...@@ -2,11 +2,10 @@ import { variableAdapters } from '../adapters';
import { updateCustomVariableOptions } from './actions'; import { updateCustomVariableOptions } from './actions';
import { createCustomVariableAdapter } from './adapter'; import { createCustomVariableAdapter } from './adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester'; import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { getTemplatingRootReducer } from '../state/helpers'; import { getRootReducer } from '../state/helpers';
import { CustomVariableModel, VariableHide, VariableOption } from '../../templating/types'; import { CustomVariableModel, VariableHide, VariableOption } from '../../templating/types';
import { toVariablePayload } from '../state/types'; import { toVariablePayload } from '../state/types';
import { setCurrentVariableValue } from '../state/sharedReducer'; import { setCurrentVariableValue, addVariable } from '../state/sharedReducer';
import { initDashboardTemplating } from '../state/actions';
import { TemplatingState } from '../state/reducers'; import { TemplatingState } from '../state/reducers';
import { createCustomOptionsFromQuery } from './reducer'; import { createCustomOptionsFromQuery } from './reducer';
...@@ -53,8 +52,8 @@ describe('custom actions', () => { ...@@ -53,8 +52,8 @@ describe('custom actions', () => {
}; };
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(updateCustomVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateCustomVariableOptions(toVariablePayload(variable)), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
......
import { reduxTester } from '../../../../test/core/redux/reduxTester'; import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { TemplatingState } from '../state/reducers'; import { TemplatingState } from '../state/reducers';
import { getTemplatingRootReducer } from '../state/helpers'; import { getRootReducer } from '../state/helpers';
import { initDashboardTemplating } from '../state/actions';
import { toVariableIdentifier, toVariablePayload } from '../state/types'; import { toVariableIdentifier, toVariablePayload } from '../state/types';
import { variableAdapters } from '../adapters'; import { variableAdapters } from '../adapters';
import { createDataSourceVariableAdapter } from './adapter'; import { createDataSourceVariableAdapter } from './adapter';
...@@ -13,7 +12,7 @@ import { ...@@ -13,7 +12,7 @@ import {
import { DataSourcePluginMeta, DataSourceSelectItem } from '@grafana/data'; import { DataSourcePluginMeta, DataSourceSelectItem } from '@grafana/data';
import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks'; import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
import { createDataSourceOptions } from './reducer'; import { createDataSourceOptions } from './reducer';
import { setCurrentVariableValue } from '../state/sharedReducer'; import { setCurrentVariableValue, addVariable } from '../state/sharedReducer';
import { changeVariableEditorExtended } from '../editor/reducer'; import { changeVariableEditorExtended } from '../editor/reducer';
import { datasourceBuilder } from '../shared/testing/builders'; import { datasourceBuilder } from '../shared/testing/builders';
...@@ -47,8 +46,10 @@ describe('data source actions', () => { ...@@ -47,8 +46,10 @@ describe('data source actions', () => {
.build(); .build();
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([datasource])) .whenActionIsDispatched(
addVariable(toVariablePayload(datasource, { global: false, index: 0, model: datasource }))
)
.whenAsyncActionIsDispatched( .whenAsyncActionIsDispatched(
updateDataSourceVariableOptions(toVariableIdentifier(datasource), dependencies), updateDataSourceVariableOptions(toVariableIdentifier(datasource), dependencies),
true true
...@@ -98,8 +99,10 @@ describe('data source actions', () => { ...@@ -98,8 +99,10 @@ describe('data source actions', () => {
.withRegEx('/.*(second-name).*/') .withRegEx('/.*(second-name).*/')
.build(); .build();
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([datasource])) .whenActionIsDispatched(
addVariable(toVariablePayload(datasource, { global: false, index: 0, model: datasource }))
)
.whenAsyncActionIsDispatched( .whenAsyncActionIsDispatched(
updateDataSourceVariableOptions(toVariableIdentifier(datasource), dependencies), updateDataSourceVariableOptions(toVariableIdentifier(datasource), dependencies),
true true
...@@ -156,7 +159,7 @@ describe('data source actions', () => { ...@@ -156,7 +159,7 @@ describe('data source actions', () => {
const dependencies: DataSourceVariableActionDependencies = { getDatasourceSrv: getDatasourceSrvMock }; const dependencies: DataSourceVariableActionDependencies = { getDatasourceSrv: getDatasourceSrvMock };
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenAsyncActionIsDispatched(initDataSourceVariableEditor(dependencies)); .whenAsyncActionIsDispatched(initDataSourceVariableEditor(dependencies));
await tester.thenDispatchedActionsShouldEqual( await tester.thenDispatchedActionsShouldEqual(
......
import { getTemplatingRootReducer } from '../state/helpers'; import { getRootReducer } from '../state/helpers';
import { reduxTester } from '../../../../test/core/redux/reduxTester'; import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { TemplatingState } from '../state/reducers'; import { TemplatingState } from '../state/reducers';
import { initDashboardTemplating } from '../state/actions'; import { toVariableIdentifier, toVariablePayload } from '../state/types';
import { toVariableIdentifier } from '../state/types';
import { import {
updateAutoValue, updateAutoValue,
UpdateAutoValueDependencies, UpdateAutoValueDependencies,
...@@ -10,7 +9,7 @@ import { ...@@ -10,7 +9,7 @@ import {
UpdateIntervalVariableOptionsDependencies, UpdateIntervalVariableOptionsDependencies,
} from './actions'; } from './actions';
import { createIntervalOptions } from './reducer'; import { createIntervalOptions } from './reducer';
import { setCurrentVariableValue } from '../state/sharedReducer'; import { setCurrentVariableValue, addVariable } from '../state/sharedReducer';
import { variableAdapters } from '../adapters'; import { variableAdapters } from '../adapters';
import { createIntervalVariableAdapter } from './adapter'; import { createIntervalVariableAdapter } from './adapter';
import { Emitter } from 'app/core/core'; import { Emitter } from 'app/core/core';
...@@ -31,8 +30,8 @@ describe('interval actions', () => { ...@@ -31,8 +30,8 @@ describe('interval actions', () => {
.build(); .build();
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([interval])) .whenActionIsDispatched(addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
.whenAsyncActionIsDispatched(updateIntervalVariableOptions(toVariableIdentifier(interval)), true); .whenAsyncActionIsDispatched(updateIntervalVariableOptions(toVariableIdentifier(interval)), true);
tester.thenDispatchedActionsShouldEqual( tester.thenDispatchedActionsShouldEqual(
...@@ -74,8 +73,8 @@ describe('interval actions', () => { ...@@ -74,8 +73,8 @@ describe('interval actions', () => {
const dependencies: UpdateIntervalVariableOptionsDependencies = { appEvents: appEventMock }; const dependencies: UpdateIntervalVariableOptionsDependencies = { appEvents: appEventMock };
await reduxTester<{ templating: TemplatingState }>() await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([interval])) .whenActionIsDispatched(addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
.whenAsyncActionIsDispatched(updateIntervalVariableOptions(toVariableIdentifier(interval), dependencies), true); .whenAsyncActionIsDispatched(updateIntervalVariableOptions(toVariableIdentifier(interval), dependencies), true);
expect(appEventMock.emit).toHaveBeenCalledTimes(1); expect(appEventMock.emit).toHaveBeenCalledTimes(1);
...@@ -119,8 +118,10 @@ describe('interval actions', () => { ...@@ -119,8 +118,10 @@ describe('interval actions', () => {
}; };
await reduxTester<{ templating: TemplatingState }>() await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([interval])) .whenActionIsDispatched(
addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval }))
)
.whenAsyncActionIsDispatched(updateAutoValue(toVariableIdentifier(interval), dependencies), true); .whenAsyncActionIsDispatched(updateAutoValue(toVariableIdentifier(interval), dependencies), true);
expect(dependencies.kbn.calculateInterval).toHaveBeenCalledTimes(0); expect(dependencies.kbn.calculateInterval).toHaveBeenCalledTimes(0);
...@@ -163,8 +164,10 @@ describe('interval actions', () => { ...@@ -163,8 +164,10 @@ describe('interval actions', () => {
}; };
await reduxTester<{ templating: TemplatingState }>() await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([interval])) .whenActionIsDispatched(
addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval }))
)
.whenAsyncActionIsDispatched(updateAutoValue(toVariableIdentifier(interval), dependencies), true); .whenAsyncActionIsDispatched(updateAutoValue(toVariableIdentifier(interval), dependencies), true);
expect(dependencies.kbn.calculateInterval).toHaveBeenCalledTimes(1); expect(dependencies.kbn.calculateInterval).toHaveBeenCalledTimes(1);
......
import { reduxTester } from '../../../../../test/core/redux/reduxTester'; import { reduxTester } from '../../../../../test/core/redux/reduxTester';
import { getTemplatingRootReducer } from '../../state/helpers'; import { getRootReducer } from '../../state/helpers';
import { initDashboardTemplating } from '../../state/actions';
import { TemplatingState } from '../../state/reducers'; import { TemplatingState } from '../../state/reducers';
import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../../../templating/types'; import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../../../templating/types';
import { import {
...@@ -20,9 +19,10 @@ import { ...@@ -20,9 +19,10 @@ import {
} from './actions'; } from './actions';
import { NavigationKey } from '../types'; import { NavigationKey } from '../types';
import { toVariablePayload } from '../../state/types'; import { toVariablePayload } from '../../state/types';
import { changeVariableProp, setCurrentVariableValue } from '../../state/sharedReducer'; import { changeVariableProp, setCurrentVariableValue, addVariable } from '../../state/sharedReducer';
import { variableAdapters } from '../../adapters'; import { variableAdapters } from '../../adapters';
import { createQueryVariableAdapter } from '../../query/adapter'; import { createQueryVariableAdapter } from '../../query/adapter';
import { updateLocation } from 'app/core/actions';
const datasource = { const datasource = {
metricFindQuery: jest.fn(() => Promise.resolve([])), metricFindQuery: jest.fn(() => Promise.resolve([])),
...@@ -50,8 +50,8 @@ describe('options picker actions', () => { ...@@ -50,8 +50,8 @@ describe('options picker actions', () => {
const key = NavigationKey.cancel; const key = NavigationKey.cancel;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenAsyncActionIsDispatched(navigateOptions(key, clearOthers), true); .whenAsyncActionIsDispatched(navigateOptions(key, clearOthers), true);
...@@ -63,14 +63,15 @@ describe('options picker actions', () => { ...@@ -63,14 +63,15 @@ describe('options picker actions', () => {
}; };
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
const [setCurrentValue, changeQueryValue, updateOption, hideAction] = actions; const [setCurrentValue, changeQueryValue, updateOption, locationAction, hideAction] = actions;
const expectedNumberOfActions = 4; const expectedNumberOfActions = 5;
expect(setCurrentValue).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); expect(setCurrentValue).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
expect(changeQueryValue).toEqual( expect(changeQueryValue).toEqual(
changeVariableProp(toVariablePayload(variable, { propName: 'queryValue', propValue: '' })) changeVariableProp(toVariablePayload(variable, { propName: 'queryValue', propValue: '' }))
); );
expect(updateOption).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); expect(updateOption).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
expect(locationAction).toEqual(updateLocation({ query: { 'var-Constant': ['A'] } }));
expect(hideAction).toEqual(hideOptions()); expect(hideAction).toEqual(hideOptions());
return actions.length === expectedNumberOfActions; return actions.length === expectedNumberOfActions;
...@@ -87,8 +88,8 @@ describe('options picker actions', () => { ...@@ -87,8 +88,8 @@ describe('options picker actions', () => {
const key = NavigationKey.select; const key = NavigationKey.select;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, false)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, false))
.whenAsyncActionIsDispatched(navigateOptions(key, clearOthers), true); .whenAsyncActionIsDispatched(navigateOptions(key, clearOthers), true);
...@@ -112,8 +113,8 @@ describe('options picker actions', () => { ...@@ -112,8 +113,8 @@ describe('options picker actions', () => {
const key = NavigationKey.select; const key = NavigationKey.select;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
.whenAsyncActionIsDispatched(navigateOptions(key, clearOthers), true); .whenAsyncActionIsDispatched(navigateOptions(key, clearOthers), true);
...@@ -137,8 +138,8 @@ describe('options picker actions', () => { ...@@ -137,8 +138,8 @@ describe('options picker actions', () => {
const key = NavigationKey.select; const key = NavigationKey.select;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
...@@ -164,8 +165,8 @@ describe('options picker actions', () => { ...@@ -164,8 +165,8 @@ describe('options picker actions', () => {
const key = NavigationKey.select; const key = NavigationKey.select;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
...@@ -192,8 +193,8 @@ describe('options picker actions', () => { ...@@ -192,8 +193,8 @@ describe('options picker actions', () => {
const key = NavigationKey.selectAndClose; const key = NavigationKey.selectAndClose;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
...@@ -209,8 +210,15 @@ describe('options picker actions', () => { ...@@ -209,8 +210,15 @@ describe('options picker actions', () => {
}; };
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
const [toggleOptionAction, setCurrentValue, changeQueryValue, updateOption, hideAction] = actions; const [
const expectedNumberOfActions = 5; toggleOptionAction,
setCurrentValue,
changeQueryValue,
updateOption,
locationAction,
hideAction,
] = actions;
const expectedNumberOfActions = 6;
expect(toggleOptionAction).toEqual(toggleOption({ option: options[1], forceSelect: false, clearOthers })); expect(toggleOptionAction).toEqual(toggleOption({ option: options[1], forceSelect: false, clearOthers }));
expect(setCurrentValue).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); expect(setCurrentValue).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
...@@ -218,6 +226,7 @@ describe('options picker actions', () => { ...@@ -218,6 +226,7 @@ describe('options picker actions', () => {
changeVariableProp(toVariablePayload(variable, { propName: 'queryValue', propValue: '' })) changeVariableProp(toVariablePayload(variable, { propName: 'queryValue', propValue: '' }))
); );
expect(updateOption).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); expect(updateOption).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
expect(locationAction).toEqual(updateLocation({ query: { 'var-Constant': ['B'] } }));
expect(hideAction).toEqual(hideOptions()); expect(hideAction).toEqual(hideOptions());
return actions.length === expectedNumberOfActions; return actions.length === expectedNumberOfActions;
...@@ -232,8 +241,8 @@ describe('options picker actions', () => { ...@@ -232,8 +241,8 @@ describe('options picker actions', () => {
const filter = 'A'; const filter = 'A';
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenAsyncActionIsDispatched(filterOrSearchOptions(filter), true); .whenAsyncActionIsDispatched(filterOrSearchOptions(filter), true);
...@@ -255,8 +264,8 @@ describe('options picker actions', () => { ...@@ -255,8 +264,8 @@ describe('options picker actions', () => {
const variable = createVariable({ options, includeAll: false }); const variable = createVariable({ options, includeAll: false });
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenAsyncActionIsDispatched(commitChangesToVariable(), true); .whenAsyncActionIsDispatched(commitChangesToVariable(), true);
...@@ -289,8 +298,8 @@ describe('options picker actions', () => { ...@@ -289,8 +298,8 @@ describe('options picker actions', () => {
const clearOthers = false; const clearOthers = false;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
.whenActionIsDispatched(toggleOptionByHighlight(clearOthers)) .whenActionIsDispatched(toggleOptionByHighlight(clearOthers))
...@@ -304,14 +313,15 @@ describe('options picker actions', () => { ...@@ -304,14 +313,15 @@ describe('options picker actions', () => {
}; };
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
const [setCurrentValue, changeQueryValue, updateOption, hideAction] = actions; const [setCurrentValue, changeQueryValue, updateOption, locationAction, hideAction] = actions;
const expectedNumberOfActions = 4; const expectedNumberOfActions = 5;
expect(setCurrentValue).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); expect(setCurrentValue).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
expect(changeQueryValue).toEqual( expect(changeQueryValue).toEqual(
changeVariableProp(toVariablePayload(variable, { propName: 'queryValue', propValue: '' })) changeVariableProp(toVariablePayload(variable, { propName: 'queryValue', propValue: '' }))
); );
expect(updateOption).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); expect(updateOption).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
expect(locationAction).toEqual(updateLocation({ query: { 'var-Constant': ['A'] } }));
expect(hideAction).toEqual(hideOptions()); expect(hideAction).toEqual(hideOptions());
return actions.length === expectedNumberOfActions; return actions.length === expectedNumberOfActions;
...@@ -326,8 +336,8 @@ describe('options picker actions', () => { ...@@ -326,8 +336,8 @@ describe('options picker actions', () => {
const clearOthers = false; const clearOthers = false;
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers)) .whenActionIsDispatched(navigateOptions(NavigationKey.moveDown, clearOthers))
.whenActionIsDispatched(toggleOptionByHighlight(clearOthers), true); .whenActionIsDispatched(toggleOptionByHighlight(clearOthers), true);
...@@ -351,8 +361,8 @@ describe('options picker actions', () => { ...@@ -351,8 +361,8 @@ describe('options picker actions', () => {
const variable = createVariable({ options, includeAll: false, tags: [tag] }); const variable = createVariable({ options, includeAll: false, tags: [tag] });
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenAsyncActionIsDispatched(toggleAndFetchTag(tag), true); .whenAsyncActionIsDispatched(toggleAndFetchTag(tag), true);
...@@ -378,8 +388,8 @@ describe('options picker actions', () => { ...@@ -378,8 +388,8 @@ describe('options picker actions', () => {
datasource.metricFindQuery.mockImplementation(() => Promise.resolve(values)); datasource.metricFindQuery.mockImplementation(() => Promise.resolve(values));
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(showOptions(variable)) .whenActionIsDispatched(showOptions(variable))
.whenAsyncActionIsDispatched(toggleAndFetchTag(tag), true); .whenAsyncActionIsDispatched(toggleAndFetchTag(tag), true);
......
import { variableAdapters } from '../adapters'; import { variableAdapters } from '../adapters';
import { createQueryVariableAdapter } from './adapter'; import { createQueryVariableAdapter } from './adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester'; import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { getTemplatingRootReducer } from '../state/helpers'; import { getRootReducer } from '../state/helpers';
import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../../templating/types'; import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../../templating/types';
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, toVariablePayload } from '../state/types'; import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, toVariablePayload } from '../state/types';
import { changeVariableProp, setCurrentVariableValue } from '../state/sharedReducer'; import { changeVariableProp, setCurrentVariableValue, addVariable } from '../state/sharedReducer';
import { initDashboardTemplating } from '../state/actions';
import { TemplatingState } from '../state/reducers'; import { TemplatingState } from '../state/reducers';
import { import {
changeQueryVariableDataSource, changeQueryVariableDataSource,
...@@ -62,8 +61,8 @@ describe('query actions', () => { ...@@ -62,8 +61,8 @@ describe('query actions', () => {
mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics); mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE); const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE);
...@@ -90,8 +89,8 @@ describe('query actions', () => { ...@@ -90,8 +89,8 @@ describe('query actions', () => {
mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics); mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
const option = createOption('A'); const option = createOption('A');
...@@ -117,8 +116,8 @@ describe('query actions', () => { ...@@ -117,8 +116,8 @@ describe('query actions', () => {
mockDatasourceMetrics(variable, optionsMetrics, []); mockDatasourceMetrics(variable, optionsMetrics, []);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
const option = createOption('A'); const option = createOption('A');
...@@ -143,8 +142,8 @@ describe('query actions', () => { ...@@ -143,8 +142,8 @@ describe('query actions', () => {
mockDatasourceMetrics(variable, optionsMetrics, []); mockDatasourceMetrics(variable, optionsMetrics, []);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE); const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE);
...@@ -169,8 +168,8 @@ describe('query actions', () => { ...@@ -169,8 +168,8 @@ describe('query actions', () => {
mockDatasourceMetrics(variable, optionsMetrics, []); mockDatasourceMetrics(variable, optionsMetrics, []);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(setIdInEditor({ id: variable.id! })) .whenActionIsDispatched(setIdInEditor({ id: variable.id! }))
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
...@@ -197,8 +196,8 @@ describe('query actions', () => { ...@@ -197,8 +196,8 @@ describe('query actions', () => {
mocks[variable.datasource!].metricFindQuery = jest.fn(() => Promise.reject(error)); mocks[variable.datasource!].metricFindQuery = jest.fn(() => Promise.reject(error));
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenActionIsDispatched(setIdInEditor({ id: variable.id! })) .whenActionIsDispatched(setIdInEditor({ id: variable.id! }))
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
...@@ -226,8 +225,8 @@ describe('query actions', () => { ...@@ -226,8 +225,8 @@ describe('query actions', () => {
}); });
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
...@@ -259,8 +258,8 @@ describe('query actions', () => { ...@@ -259,8 +258,8 @@ describe('query actions', () => {
}); });
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
...@@ -291,8 +290,8 @@ describe('query actions', () => { ...@@ -291,8 +290,8 @@ describe('query actions', () => {
}); });
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
...@@ -317,8 +316,8 @@ describe('query actions', () => { ...@@ -317,8 +316,8 @@ describe('query actions', () => {
const ds = { name: '', value: '', meta: {}, sort: '' }; const ds = { name: '', value: '', meta: {}, sort: '' };
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
...@@ -341,8 +340,8 @@ describe('query actions', () => { ...@@ -341,8 +340,8 @@ describe('query actions', () => {
}); });
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(changeQueryVariableDataSource(toVariablePayload(variable), 'datasource'), true); .whenAsyncActionIsDispatched(changeQueryVariableDataSource(toVariablePayload(variable), 'datasource'), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
...@@ -371,8 +370,8 @@ describe('query actions', () => { ...@@ -371,8 +370,8 @@ describe('query actions', () => {
}); });
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(changeQueryVariableDataSource(toVariablePayload(variable), 'datasource'), true); .whenAsyncActionIsDispatched(changeQueryVariableDataSource(toVariablePayload(variable), 'datasource'), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
...@@ -403,8 +402,8 @@ describe('query actions', () => { ...@@ -403,8 +402,8 @@ describe('query actions', () => {
mockDatasourceMetrics({ ...variable, query }, optionsMetrics, tagsMetrics); mockDatasourceMetrics({ ...variable, query }, optionsMetrics, tagsMetrics);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true); .whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE); const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE);
...@@ -441,8 +440,8 @@ describe('query actions', () => { ...@@ -441,8 +440,8 @@ describe('query actions', () => {
mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []); mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true); .whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE); const option = createOption(ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE);
...@@ -477,8 +476,8 @@ describe('query actions', () => { ...@@ -477,8 +476,8 @@ describe('query actions', () => {
mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []); mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []);
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true); .whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
const option = createOption('A'); const option = createOption('A');
...@@ -510,8 +509,8 @@ describe('query actions', () => { ...@@ -510,8 +509,8 @@ describe('query actions', () => {
const definition = 'depends on datasource variable'; const definition = 'depends on datasource variable';
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true); .whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
const errorText = 'Query cannot contain a reference to itself. Variable: $' + variable.name; const errorText = 'Query cannot contain a reference to itself. Variable: $' + variable.name;
......
...@@ -43,6 +43,12 @@ variableAdapters.setInit(() => [ ...@@ -43,6 +43,12 @@ variableAdapters.setInit(() => [
createConstantVariableAdapter(), createConstantVariableAdapter(),
]); ]);
jest.mock('app/features/dashboard/services/TimeSrv', () => ({
getTimeSrv: () => ({
timeRange: jest.fn().mockReturnValue(undefined),
}),
}));
describe('shared actions', () => { describe('shared actions', () => {
describe('when initDashboardTemplating is dispatched', () => { describe('when initDashboardTemplating is dispatched', () => {
it('then correct actions are dispatched', () => { it('then correct actions are dispatched', () => {
......
...@@ -25,10 +25,13 @@ import { ...@@ -25,10 +25,13 @@ import {
changeVariableProp, changeVariableProp,
} from './sharedReducer'; } from './sharedReducer';
import { toVariableIdentifier, toVariablePayload, VariableIdentifier } from './types'; import { toVariableIdentifier, toVariablePayload, VariableIdentifier } from './types';
import { appEvents } from '../../../core/core'; import { appEvents } from 'app/core/core';
import { contextSrv } from 'app/core/services/context_srv';
import templateSrv from '../../templating/template_srv'; import templateSrv from '../../templating/template_srv';
import { alignCurrentWithMulti } from '../shared/multiOptions'; import { alignCurrentWithMulti } from '../shared/multiOptions';
import { isMulti } from '../guard'; import { isMulti } from '../guard';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { DashboardModel } from 'app/features/dashboard/state';
// process flow queryVariable // process flow queryVariable
// thunk => processVariables // thunk => processVariables
...@@ -72,12 +75,37 @@ export const initDashboardTemplating = (list: VariableModel[]): ThunkResult<void ...@@ -72,12 +75,37 @@ export const initDashboardTemplating = (list: VariableModel[]): ThunkResult<void
dispatch(addVariable(toVariablePayload(model, { global: false, index: orderIndex++, model }))); dispatch(addVariable(toVariablePayload(model, { global: false, index: orderIndex++, model })));
} }
templateSrv.updateTimeRange(getTimeSrv().timeRange());
for (let index = 0; index < getVariables(getState()).length; index++) { for (let index = 0; index < getVariables(getState()).length; index++) {
dispatch(addInitLock(toVariablePayload(getVariables(getState())[index]))); dispatch(addInitLock(toVariablePayload(getVariables(getState())[index])));
} }
}; };
}; };
export const completeDashboardTemplating = (dashboard: DashboardModel): ThunkResult<void> => {
return (dispatch, getState) => {
templateSrv.setGlobalVariable('__dashboard', {
value: {
name: dashboard.title,
uid: dashboard.uid,
toString: function() {
return this.uid;
},
},
});
templateSrv.setGlobalVariable('__org', {
value: {
name: contextSrv.user.orgName,
id: contextSrv.user.id,
toString: function() {
return this.id;
},
},
});
};
};
export const changeVariableMultiValue = (identifier: VariableIdentifier, multi: boolean): ThunkResult<void> => { export const changeVariableMultiValue = (identifier: VariableIdentifier, multi: boolean): ThunkResult<void> => {
return (dispatch, getState) => { return (dispatch, getState) => {
const variable = getVariable<VariableWithMultiSupport>(identifier.id!, getState()); const variable = getVariable<VariableWithMultiSupport>(identifier.id!, getState());
...@@ -106,7 +134,10 @@ export const processVariableDependencies = async (variable: VariableModel, state ...@@ -106,7 +134,10 @@ export const processVariableDependencies = async (variable: VariableModel, state
await Promise.all(dependencies); await Promise.all(dependencies);
}; };
export const processVariable = (identifier: VariableIdentifier, queryParams: UrlQueryMap): ThunkResult<void> => { export const processVariable = (
identifier: VariableIdentifier,
queryParams: UrlQueryMap
): ThunkResult<Promise<void>> => {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const variable = getVariable(identifier.id!, getState()); const variable = getVariable(identifier.id!, getState());
await processVariableDependencies(variable, getState()); await processVariableDependencies(variable, getState());
...@@ -114,7 +145,7 @@ export const processVariable = (identifier: VariableIdentifier, queryParams: Url ...@@ -114,7 +145,7 @@ export const processVariable = (identifier: VariableIdentifier, queryParams: Url
const urlValue = queryParams['var-' + variable.name]; const urlValue = queryParams['var-' + variable.name];
if (urlValue !== void 0) { if (urlValue !== void 0) {
await variableAdapters.get(variable.type).setValueFromUrl(variable, urlValue ?? ''); await variableAdapters.get(variable.type).setValueFromUrl(variable, urlValue ?? '');
await dispatch(resolveInitLock(toVariablePayload(variable))); dispatch(resolveInitLock(toVariablePayload(variable)));
return; return;
} }
...@@ -125,16 +156,16 @@ export const processVariable = (identifier: VariableIdentifier, queryParams: Url ...@@ -125,16 +156,16 @@ export const processVariable = (identifier: VariableIdentifier, queryParams: Url
refreshableVariable.refresh === VariableRefresh.onTimeRangeChanged refreshableVariable.refresh === VariableRefresh.onTimeRangeChanged
) { ) {
await variableAdapters.get(variable.type).updateOptions(refreshableVariable); await variableAdapters.get(variable.type).updateOptions(refreshableVariable);
await dispatch(resolveInitLock(toVariablePayload(variable))); dispatch(resolveInitLock(toVariablePayload(variable)));
return; return;
} }
} }
await dispatch(resolveInitLock(toVariablePayload(variable))); dispatch(resolveInitLock(toVariablePayload(variable)));
}; };
}; };
export const processVariables = (): ThunkResult<void> => { export const processVariables = (): ThunkResult<Promise<void>> => {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const queryParams = getState().location.query; const queryParams = getState().location.query;
const promises = getVariables(getState()).map( const promises = getVariables(getState()).map(
...@@ -144,12 +175,15 @@ export const processVariables = (): ThunkResult<void> => { ...@@ -144,12 +175,15 @@ export const processVariables = (): ThunkResult<void> => {
await Promise.all(promises); await Promise.all(promises);
for (let index = 0; index < getVariables(getState()).length; index++) { for (let index = 0; index < getVariables(getState()).length; index++) {
await dispatch(removeInitLock(toVariablePayload(getVariables(getState())[index]))); dispatch(removeInitLock(toVariablePayload(getVariables(getState())[index])));
} }
}; };
}; };
export const setOptionFromUrl = (identifier: VariableIdentifier, urlValue: UrlQueryValue): ThunkResult<void> => { export const setOptionFromUrl = (
identifier: VariableIdentifier,
urlValue: UrlQueryValue
): ThunkResult<Promise<void>> => {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const variable = getVariable(identifier.id!, getState()); const variable = getVariable(identifier.id!, getState());
if (variable.hasOwnProperty('refresh') && (variable as QueryVariableModel).refresh !== VariableRefresh.never) { if (variable.hasOwnProperty('refresh') && (variable as QueryVariableModel).refresh !== VariableRefresh.never) {
...@@ -233,8 +267,8 @@ export const selectOptionsForCurrentValue = (variable: VariableWithOptions): Var ...@@ -233,8 +267,8 @@ export const selectOptionsForCurrentValue = (variable: VariableWithOptions): Var
export const validateVariableSelectionState = ( export const validateVariableSelectionState = (
identifier: VariableIdentifier, identifier: VariableIdentifier,
defaultValue?: string defaultValue?: string
): ThunkResult<void> => { ): ThunkResult<Promise<void>> => {
return async (dispatch, getState) => { return (dispatch, getState) => {
const variableInState = getVariable<VariableWithOptions>(identifier.id!, getState()); const variableInState = getVariable<VariableWithOptions>(identifier.id!, getState());
const current = variableInState.current || (({} as unknown) as VariableOption); const current = variableInState.current || (({} as unknown) as VariableOption);
const setValue = variableAdapters.get(variableInState.type).setValue; const setValue = variableAdapters.get(variableInState.type).setValue;
...@@ -287,8 +321,8 @@ export const setOptionAsCurrent = ( ...@@ -287,8 +321,8 @@ export const setOptionAsCurrent = (
identifier: VariableIdentifier, identifier: VariableIdentifier,
current: VariableOption, current: VariableOption,
emitChanges: boolean emitChanges: boolean
): ThunkResult<void> => { ): ThunkResult<Promise<void>> => {
return async dispatch => { return dispatch => {
dispatch(setCurrentVariableValue(toVariablePayload(identifier, { option: current }))); dispatch(setCurrentVariableValue(toVariablePayload(identifier, { option: current })));
return dispatch(variableUpdated(identifier, emitChanges)); return dispatch(variableUpdated(identifier, emitChanges));
}; };
...@@ -316,7 +350,10 @@ const createGraph = (variables: VariableModel[]) => { ...@@ -316,7 +350,10 @@ const createGraph = (variables: VariableModel[]) => {
return g; return g;
}; };
export const variableUpdated = (identifier: VariableIdentifier, emitChangeEvents: boolean): ThunkResult<void> => { export const variableUpdated = (
identifier: VariableIdentifier,
emitChangeEvents: boolean
): ThunkResult<Promise<void>> => {
return (dispatch, getState) => { return (dispatch, getState) => {
// if there is a variable lock ignore cascading update because we are in a boot up scenario // if there is a variable lock ignore cascading update because we are in a boot up scenario
const variable = getVariable(identifier.id!, getState()); const variable = getVariable(identifier.id!, getState());
...@@ -358,7 +395,7 @@ export interface OnTimeRangeUpdatedDependencies { ...@@ -358,7 +395,7 @@ export interface OnTimeRangeUpdatedDependencies {
export const onTimeRangeUpdated = ( export const onTimeRangeUpdated = (
timeRange: TimeRange, timeRange: TimeRange,
dependencies: OnTimeRangeUpdatedDependencies = { templateSrv: templateSrv, appEvents: appEvents } dependencies: OnTimeRangeUpdatedDependencies = { templateSrv: templateSrv, appEvents: appEvents }
): ThunkResult<void> => async (dispatch, getState) => { ): ThunkResult<Promise<void>> => async (dispatch, getState) => {
dependencies.templateSrv.updateTimeRange(timeRange); dependencies.templateSrv.updateTimeRange(timeRange);
const variablesThatNeedRefresh = getVariables(getState()).filter(variable => { const variablesThatNeedRefresh = getVariables(getState()).filter(variable => {
if (variable.hasOwnProperty('refresh') && variable.hasOwnProperty('options')) { if (variable.hasOwnProperty('refresh') && variable.hasOwnProperty('options')) {
......
...@@ -19,21 +19,21 @@ export const getVariable = <T extends VariableModel = VariableModel>( ...@@ -19,21 +19,21 @@ export const getVariable = <T extends VariableModel = VariableModel>(
}; };
export const getFilteredVariables = (filter: (model: VariableModel) => boolean, state: StoreState = getState()) => { export const getFilteredVariables = (filter: (model: VariableModel) => boolean, state: StoreState = getState()) => {
return Object.values(state.templating.variables).filter(filter); return Object.values(state.templating.variables)
.filter(filter)
.sort((s1, s2) => s1.index! - s2.index!);
}; };
export const getVariableWithName = (name: string) => { export const getVariableWithName = (name: string, state: StoreState = getState()) => {
return getVariable(name, getState(), false); return getVariable(name, state, false);
}; };
export const getVariables = (state: StoreState = getState(), includeNewVariable = false): VariableModel[] => { export const getVariables = (state: StoreState = getState(), includeNewVariable = false): VariableModel[] => {
const variables = getFilteredVariables( return getFilteredVariables(variable => (includeNewVariable ? true : variable.id! !== NEW_VARIABLE_ID), state);
variable => (includeNewVariable ? true : variable.id! !== NEW_VARIABLE_ID),
state
);
return variables.sort((s1, s2) => s1.index! - s2.index!);
}; };
export type GetVariables = typeof getVariables;
export const getNewVariabelIndex = (state: StoreState = getState()): number => { export const getNewVariabelIndex = (state: StoreState = getState()): number => {
return Object.values(state.templating.variables).length; return Object.values(state.templating.variables).length;
}; };
...@@ -3,12 +3,12 @@ import { createTextBoxVariableAdapter } from './adapter'; ...@@ -3,12 +3,12 @@ import { createTextBoxVariableAdapter } from './adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester'; import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { TemplatingState } from 'app/features/variables/state/reducers'; import { TemplatingState } from 'app/features/variables/state/reducers';
import { updateTextBoxVariableOptions } from './actions'; import { updateTextBoxVariableOptions } from './actions';
import { getTemplatingRootReducer } from '../state/helpers'; import { getRootReducer } from '../state/helpers';
import { TextBoxVariableModel, VariableHide, VariableOption } from '../../templating/types'; import { TextBoxVariableModel, VariableHide, VariableOption } from '../../templating/types';
import { toVariablePayload } from '../state/types'; import { toVariablePayload } from '../state/types';
import { createTextBoxOptions } from './reducer'; import { createTextBoxOptions } from './reducer';
import { setCurrentVariableValue } from '../state/sharedReducer'; import { setCurrentVariableValue, addVariable } from '../state/sharedReducer';
import { initDashboardTemplating } from '../state/actions'; import { updateLocation } from 'app/core/actions';
describe('textbox actions', () => { describe('textbox actions', () => {
variableAdapters.setInit(() => [createTextBoxVariableAdapter()]); variableAdapters.setInit(() => [createTextBoxVariableAdapter()]);
...@@ -40,16 +40,18 @@ describe('textbox actions', () => { ...@@ -40,16 +40,18 @@ describe('textbox actions', () => {
}; };
const tester = await reduxTester<{ templating: TemplatingState }>() const tester = await reduxTester<{ templating: TemplatingState }>()
.givenRootReducer(getTemplatingRootReducer()) .givenRootReducer(getRootReducer())
.whenActionIsDispatched(initDashboardTemplating([variable])) .whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
.whenAsyncActionIsDispatched(updateTextBoxVariableOptions(toVariablePayload(variable)), true); .whenAsyncActionIsDispatched(updateTextBoxVariableOptions(toVariablePayload(variable)), true);
tester.thenDispatchedActionsPredicateShouldEqual(actions => { tester.thenDispatchedActionsPredicateShouldEqual(actions => {
const [createAction, setCurrentAction] = actions; const [createAction, setCurrentAction, locationAction] = actions;
const expectedNumberOfActions = 2; const expectedNumberOfActions = 3;
expect(createAction).toEqual(createTextBoxOptions(toVariablePayload(variable))); expect(createAction).toEqual(createTextBoxOptions(toVariablePayload(variable)));
expect(setCurrentAction).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option }))); expect(setCurrentAction).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
expect(locationAction).toEqual(updateLocation({ query: { 'var-textbox': 'A' } }));
return actions.length === expectedNumberOfActions; return actions.length === expectedNumberOfActions;
}); });
}); });
......
import '../datasource'; import '../datasource';
import CloudWatchDatasource from '../datasource'; import CloudWatchDatasource from '../datasource';
import * as redux from 'app/store/store'; import * as redux from 'app/store/store';
import { dateMath } from '@grafana/data'; import { DataSourceInstanceSettings, dateMath } from '@grafana/data';
import { TemplateSrv } from 'app/features/templating/template_srv'; import { TemplateSrv } from 'app/features/templating/template_srv';
import { CustomVariable } from 'app/features/templating/all'; import { CustomVariable } from 'app/features/templating/all';
import _ from 'lodash';
import { CloudWatchQuery } from '../types'; import { CloudWatchQuery } from '../types';
import { DataSourceInstanceSettings } from '@grafana/data';
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__ import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { convertToStoreState } from '../../../../../test/helpers/convertToStoreState';
import { getTemplateSrvDependencies } from 'test/helpers/getTemplateSrvDependencies';
jest.mock('@grafana/runtime', () => ({ jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'), ...jest.requireActual('@grafana/runtime'),
...@@ -23,7 +23,7 @@ describe('CloudWatchDatasource', () => { ...@@ -23,7 +23,7 @@ describe('CloudWatchDatasource', () => {
name: 'TestDatasource', name: 'TestDatasource',
} as DataSourceInstanceSettings; } as DataSourceInstanceSettings;
const templateSrv = new TemplateSrv(); let templateSrv = new TemplateSrv();
const start = 1483196400 * 1000; const start = 1483196400 * 1000;
const defaultTimeRange = { from: new Date(start), to: new Date(start + 3600 * 1000) }; const defaultTimeRange = { from: new Date(start), to: new Date(start + 3600 * 1000) };
...@@ -465,7 +465,7 @@ describe('CloudWatchDatasource', () => { ...@@ -465,7 +465,7 @@ describe('CloudWatchDatasource', () => {
describe('When performing CloudWatch query with template variables', () => { describe('When performing CloudWatch query with template variables', () => {
let requestParams: { queries: CloudWatchQuery[] }; let requestParams: { queries: CloudWatchQuery[] };
beforeEach(() => { beforeEach(() => {
templateSrv.init([ const variables = [
new CustomVariable( new CustomVariable(
{ {
name: 'var1', name: 'var1',
...@@ -516,7 +516,11 @@ describe('CloudWatchDatasource', () => { ...@@ -516,7 +516,11 @@ describe('CloudWatchDatasource', () => {
}, },
{} as any {} as any
), ),
]); ];
const state = convertToStoreState(variables);
const _templateSrv = new TemplateSrv(getTemplateSrvDependencies(state));
_templateSrv.init(variables);
ctx.ds = new CloudWatchDatasource(instanceSettings, _templateSrv, timeSrv);
datasourceRequestMock.mockImplementation(params => { datasourceRequestMock.mockImplementation(params => {
requestParams = params.data; requestParams = params.data;
......
...@@ -11,6 +11,21 @@ jest.mock('../functions', () => ({ ...@@ -11,6 +11,21 @@ jest.mock('../functions', () => ({
extractServicesFromMetricDescriptors: (): any[] => [], extractServicesFromMetricDescriptors: (): any[] => [],
})); }));
jest.mock('../../../../core/config', () => {
console.warn('[This test uses old variable system, needs a rewrite]');
const original = jest.requireActual('../../../../core/config');
const config = original.getConfig();
return {
getConfig: () => ({
...config,
featureToggles: {
...config.featureToggles,
newVariables: false,
},
}),
};
});
const props: VariableQueryProps = { const props: VariableQueryProps = {
onChange: (query, definition) => {}, onChange: (query, definition) => {},
query: {}, query: {},
......
...@@ -9,7 +9,11 @@ export function setStore(newStore: Store<StoreState>) { ...@@ -9,7 +9,11 @@ export function setStore(newStore: Store<StoreState>) {
export function getState(): StoreState { export function getState(): StoreState {
if (!store || !store.getState) { if (!store || !store.getState) {
return {} as StoreState; // used by tests return {
templating: {
variables: {},
},
} as StoreState; // used by tests
} }
return store.getState(); return store.getState();
......
import { StoreState } from '../../app/types';
export const convertToStoreState = (variables: any[]): StoreState => {
return {
templating: {
variables: variables.reduce((byName, variable) => {
byName[variable.name] = variable;
return byName;
}, {}),
},
} as StoreState;
};
import { DashboardModel } from '../../app/features/dashboard/state';
export const getDashboardModel = (json: any, meta: any = {}) => {
const getVariablesFromState = () => json.templating.list;
return new DashboardModel(json, meta, getVariablesFromState);
};
import { getFilteredVariables, getVariables, getVariableWithName } from '../../app/features/variables/state/selectors';
import { StoreState } from '../../app/types';
import { TemplateSrvDependencies } from 'app/features/templating/template_srv';
export const getTemplateSrvDependencies = (state: StoreState): TemplateSrvDependencies => ({
getFilteredVariables: filter => getFilteredVariables(filter, state),
getVariableWithName: name => getVariableWithName(name, state),
getVariables: () => getVariables(state),
});
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