diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts
index 9fc4503803a..01a1b238e1c 100644
--- a/public/app/core/angular_wrappers.ts
+++ b/public/app/core/angular_wrappers.ts
@@ -28,7 +28,7 @@ import {
SaveDashboardAsButtonConnected,
SaveDashboardButtonConnected,
} from '../features/dashboard/components/SaveDashboard/SaveDashboardButton';
-import { VariableEditorContainer } from '../features/templating/editor/VariableEditorContainer';
+import { VariableEditorContainer } from '../features/variables/editor/VariableEditorContainer';
export function registerAngularDirectives() {
react2AngularDirective('footer', Footer, []);
diff --git a/public/app/core/reducers/root.ts b/public/app/core/reducers/root.ts
index 35492dc6d15..3914e14a412 100644
--- a/public/app/core/reducers/root.ts
+++ b/public/app/core/reducers/root.ts
@@ -13,7 +13,7 @@ import usersReducers from 'app/features/users/state/reducers';
import userReducers from 'app/features/profile/state/reducers';
import organizationReducers from 'app/features/org/state/reducers';
import ldapReducers from 'app/features/admin/state/reducers';
-import templatingReducers from 'app/features/templating/state/reducers';
+import templatingReducers from 'app/features/variables/state/reducers';
const rootReducers = {
...sharedReducers,
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
index 5fa5c35e8ca..e46c257fefa 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react';
import { connect, MapStateToProps } from 'react-redux';
import { StoreState } from '../../../../types';
-import { getVariableClones } from '../../../templating/state/selectors';
+import { getVariableClones } from '../../../variables/state/selectors';
import { VariableHide, VariableModel } from '../../../templating/variable';
import { DashboardModel } from '../../state';
import { AngularDashboardLinks } from './AngularDashboardLinks';
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
index af1c37f2bcc..78d035cbcd6 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent, useEffect, useState } from 'react';
import { VariableHide, VariableModel } from '../../../templating/variable';
import { e2e } from '@grafana/e2e';
-import { PickerRenderer } from '../../../templating/pickers/PickerRenderer';
+import { PickerRenderer } from '../../../variables/pickers/PickerRenderer';
interface Props {
variables: VariableModel[];
diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts
index 8471375bdbe..04042daa77d 100644
--- a/public/app/features/dashboard/state/DashboardModel.ts
+++ b/public/app/features/dashboard/state/DashboardModel.ts
@@ -15,8 +15,8 @@ import { UrlQueryValue } from '@grafana/runtime';
import { CoreEvents, DashboardMeta, KIOSK_MODE_TV } from 'app/types';
import { VariableModel } from '../../templating/variable';
import { getConfig } from '../../../core/config';
-import { getVariables } from 'app/features/templating/state/selectors';
-import { variableAdapters } from 'app/features/templating/adapters';
+import { getVariables } from 'app/features/variables/state/selectors';
+import { variableAdapters } from 'app/features/variables/adapters';
export interface CloneOptions {
saveVariables?: boolean;
diff --git a/public/app/features/dashboard/state/initDashboard.ts b/public/app/features/dashboard/state/initDashboard.ts
index 8a8fed2d09a..45f59d4c382 100644
--- a/public/app/features/dashboard/state/initDashboard.ts
+++ b/public/app/features/dashboard/state/initDashboard.ts
@@ -23,8 +23,8 @@ import { DashboardDTO, DashboardRouteInfo, StoreState, ThunkDispatch, ThunkResul
import { DashboardModel } from './DashboardModel';
import { DataQuery } from '@grafana/data';
import { getConfig } from '../../../core/config';
-import { initDashboardTemplating, processVariables } from '../../templating/state/actions';
-import { variableAdapters } from '../../templating/adapters';
+import { initDashboardTemplating, processVariables } from '../../variables/state/actions';
+import { variableAdapters } from '../../variables/adapters';
export interface InitDashboardArgs {
$injector: any;
diff --git a/public/app/features/panel/repeat_option.ts b/public/app/features/panel/repeat_option.ts
index 2fab9e695ad..9d847807a93 100644
--- a/public/app/features/panel/repeat_option.ts
+++ b/public/app/features/panel/repeat_option.ts
@@ -1,7 +1,7 @@
import { coreModule } from 'app/core/core';
import { VariableSrv } from 'app/features/templating/variable_srv';
import { getConfig } from '../../core/config';
-import { getVariables } from '../templating/state/selectors';
+import { getVariables } from '../variables/state/selectors';
const template = `
+
+
+ >
+ );
+ }
+}
+
+const mapStateToProps: MapStateToProps = (state, ownProps) => ({
+ editor: state.templating.editor as VariableEditorState,
+});
+
+const mapDispatchToProps: MapDispatchToProps = {
+ initDataSourceVariableEditor,
+};
+
+export const DataSourceVariableEditor = connectWithStore(
+ DataSourceVariableEditorUnConnected,
+ mapStateToProps,
+ mapDispatchToProps
+);
diff --git a/public/app/features/variables/datasource/actions.test.ts b/public/app/features/variables/datasource/actions.test.ts
new file mode 100644
index 00000000000..a2e5ed4e036
--- /dev/null
+++ b/public/app/features/variables/datasource/actions.test.ts
@@ -0,0 +1,175 @@
+import { reduxTester } from '../../../../test/core/redux/reduxTester';
+import { TemplatingState } from '../state/reducers';
+import { getTemplatingRootReducer, variableMockBuilder } from '../state/helpers';
+import { initDashboardTemplating } from '../state/actions';
+import { toVariableIdentifier, toVariablePayload } from '../state/types';
+import { variableAdapters } from '../adapters';
+import { createDataSourceVariableAdapter } from './adapter';
+import {
+ DataSourceVariableActionDependencies,
+ initDataSourceVariableEditor,
+ updateDataSourceVariableOptions,
+} from './actions';
+import { DataSourcePluginMeta, DataSourceSelectItem } from '@grafana/data';
+import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
+import { createDataSourceOptions } from './reducer';
+import { setCurrentVariableValue } from '../state/sharedReducer';
+import { changeVariableEditorExtended } from '../editor/reducer';
+
+describe('data source actions', () => {
+ variableAdapters.set('datasource', createDataSourceVariableAdapter());
+
+ describe('when updateDataSourceVariableOptions is dispatched', () => {
+ describe('and there is no regex', () => {
+ it('then the correct actions are dispatched', async () => {
+ const sources: DataSourceSelectItem[] = [
+ {
+ name: 'first-name',
+ value: 'first-value',
+ meta: getMockPlugin({ name: 'mock-data-name', id: 'mock-data-id' }),
+ sort: '',
+ },
+ {
+ name: 'second-name',
+ value: 'second-value',
+ meta: getMockPlugin({ name: 'mock-data-name', id: 'mock-data-id' }),
+ sort: '',
+ },
+ ];
+
+ const getMetricSourcesMock = jest.fn().mockResolvedValue(sources);
+ const getDatasourceSrvMock = jest.fn().mockReturnValue({ getMetricSources: getMetricSourcesMock });
+ const dependencies: DataSourceVariableActionDependencies = { getDatasourceSrv: getDatasourceSrvMock };
+ const datasource = variableMockBuilder('datasource')
+ .withUuid('0')
+ .withQuery('mock-data-id')
+ .create();
+ const tester = await reduxTester<{ templating: TemplatingState }>()
+ .givenRootReducer(getTemplatingRootReducer())
+ .whenActionIsDispatched(initDashboardTemplating([datasource]))
+ .whenAsyncActionIsDispatched(
+ updateDataSourceVariableOptions(toVariableIdentifier(datasource), dependencies),
+ true
+ );
+
+ await tester.thenDispatchedActionShouldEqual(
+ createDataSourceOptions(
+ toVariablePayload({ type: 'datasource', uuid: '0' }, { sources, regex: (undefined as unknown) as RegExp })
+ ),
+ setCurrentVariableValue(
+ toVariablePayload(
+ { type: 'datasource', uuid: '0' },
+ { option: { text: 'first-name', value: 'first-name', selected: false } }
+ )
+ )
+ );
+
+ expect(getMetricSourcesMock).toHaveBeenCalledTimes(1);
+ expect(getMetricSourcesMock).toHaveBeenCalledWith({ skipVariables: true });
+ expect(getDatasourceSrvMock).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('and there is a regex', () => {
+ it('then the correct actions are dispatched', async () => {
+ const sources: DataSourceSelectItem[] = [
+ {
+ name: 'first-name',
+ value: 'first-value',
+ meta: getMockPlugin({ name: 'mock-data-name', id: 'mock-data-id' }),
+ sort: '',
+ },
+ {
+ name: 'second-name',
+ value: 'second-value',
+ meta: getMockPlugin({ name: 'mock-data-name', id: 'mock-data-id' }),
+ sort: '',
+ },
+ ];
+
+ const getMetricSourcesMock = jest.fn().mockResolvedValue(sources);
+ const getDatasourceSrvMock = jest.fn().mockReturnValue({ getMetricSources: getMetricSourcesMock });
+ const dependencies: DataSourceVariableActionDependencies = { getDatasourceSrv: getDatasourceSrvMock };
+ const datasource = variableMockBuilder('datasource')
+ .withUuid('0')
+ .withQuery('mock-data-id')
+ .withRegEx('/.*(second-name).*/')
+ .create();
+ const tester = await reduxTester<{ templating: TemplatingState }>()
+ .givenRootReducer(getTemplatingRootReducer())
+ .whenActionIsDispatched(initDashboardTemplating([datasource]))
+ .whenAsyncActionIsDispatched(
+ updateDataSourceVariableOptions(toVariableIdentifier(datasource), dependencies),
+ true
+ );
+
+ await tester.thenDispatchedActionShouldEqual(
+ createDataSourceOptions(
+ toVariablePayload({ type: 'datasource', uuid: '0' }, { sources, regex: /.*(second-name).*/ })
+ ),
+ setCurrentVariableValue(
+ toVariablePayload(
+ { type: 'datasource', uuid: '0' },
+ { option: { text: 'second-name', value: 'second-name', selected: false } }
+ )
+ )
+ );
+
+ expect(getMetricSourcesMock).toHaveBeenCalledTimes(1);
+ expect(getMetricSourcesMock).toHaveBeenCalledWith({ skipVariables: true });
+ expect(getDatasourceSrvMock).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+
+ describe('when initDataSourceVariableEditor is dispatched', () => {
+ it('then the correct actions are dispatched', async () => {
+ const sources: DataSourceSelectItem[] = [
+ {
+ name: 'first-name',
+ value: 'first-value',
+ meta: getMockPlugin({ name: 'mock-data-name', id: 'mock-data-id' }),
+ sort: '',
+ },
+ {
+ name: 'second-name',
+ value: 'second-value',
+ meta: getMockPlugin({ name: 'mock-data-name', id: 'mock-data-id' }),
+ sort: '',
+ },
+ {
+ name: 'mixed-name',
+ value: 'mixed-value',
+ meta: getMockPlugin(({
+ name: 'mixed-data-name',
+ id: 'mixed-data-id',
+ mixed: true,
+ } as unknown) as DataSourcePluginMeta),
+ sort: '',
+ },
+ ];
+
+ const getMetricSourcesMock = jest.fn().mockResolvedValue(sources);
+ const getDatasourceSrvMock = jest.fn().mockReturnValue({ getMetricSources: getMetricSourcesMock });
+ const dependencies: DataSourceVariableActionDependencies = { getDatasourceSrv: getDatasourceSrvMock };
+
+ const tester = await reduxTester<{ templating: TemplatingState }>()
+ .givenRootReducer(getTemplatingRootReducer())
+ .whenAsyncActionIsDispatched(initDataSourceVariableEditor(dependencies));
+
+ await tester.thenDispatchedActionShouldEqual(
+ changeVariableEditorExtended({
+ propName: 'dataSourceTypes',
+ propValue: [
+ { text: '', value: '' },
+ { text: 'mock-data-name', value: 'mock-data-id' },
+ ],
+ })
+ );
+
+ expect(getMetricSourcesMock).toHaveBeenCalledTimes(1);
+ expect(getMetricSourcesMock).toHaveBeenCalledWith();
+ expect(getDatasourceSrvMock).toHaveBeenCalledTimes(1);
+ });
+ });
+});
diff --git a/public/app/features/variables/datasource/actions.ts b/public/app/features/variables/datasource/actions.ts
new file mode 100644
index 00000000000..27e3534bd52
--- /dev/null
+++ b/public/app/features/variables/datasource/actions.ts
@@ -0,0 +1,54 @@
+import { toVariablePayload, VariableIdentifier } from '../state/types';
+import { ThunkResult } from '../../../types';
+import { createDataSourceOptions } from './reducer';
+import { validateVariableSelectionState } from '../state/actions';
+import { DataSourceSelectItem, stringToJsRegex } from '@grafana/data';
+import { getDatasourceSrv } from '../../plugins/datasource_srv';
+import { getVariable } from '../state/selectors';
+import { DataSourceVariableModel } from '../../templating/variable';
+import templateSrv from '../../templating/template_srv';
+import _ from 'lodash';
+import { changeVariableEditorExtended } from '../editor/reducer';
+
+export interface DataSourceVariableActionDependencies {
+ getDatasourceSrv: typeof getDatasourceSrv;
+}
+
+export const updateDataSourceVariableOptions = (
+ identifier: VariableIdentifier,
+ dependencies: DataSourceVariableActionDependencies = { getDatasourceSrv: getDatasourceSrv }
+): ThunkResult => async (dispatch, getState) => {
+ const sources = await dependencies.getDatasourceSrv().getMetricSources({ skipVariables: true });
+ const variableInState = getVariable(identifier.uuid!, getState());
+ let regex;
+
+ if (variableInState.regex) {
+ regex = templateSrv.replace(variableInState.regex, undefined, 'regex');
+ regex = stringToJsRegex(regex);
+ }
+
+ await dispatch(createDataSourceOptions(toVariablePayload(identifier, { sources, regex })));
+ await dispatch(validateVariableSelectionState(identifier));
+};
+
+export const initDataSourceVariableEditor = (
+ dependencies: DataSourceVariableActionDependencies = { getDatasourceSrv: getDatasourceSrv }
+): ThunkResult => async dispatch => {
+ const dataSources: DataSourceSelectItem[] = await dependencies.getDatasourceSrv().getMetricSources();
+ const filtered = dataSources.filter(ds => !ds.meta.mixed && ds.value !== null);
+ const dataSourceTypes = _(filtered)
+ .uniqBy('meta.id')
+ .map((ds: any) => {
+ return { text: ds.meta.name, value: ds.meta.id };
+ })
+ .value();
+
+ dataSourceTypes.unshift({ text: '', value: '' });
+
+ dispatch(
+ changeVariableEditorExtended({
+ propName: 'dataSourceTypes',
+ propValue: dataSourceTypes,
+ })
+ );
+};
diff --git a/public/app/features/variables/datasource/adapter.ts b/public/app/features/variables/datasource/adapter.ts
new file mode 100644
index 00000000000..2991b137d92
--- /dev/null
+++ b/public/app/features/variables/datasource/adapter.ts
@@ -0,0 +1,46 @@
+import cloneDeep from 'lodash/cloneDeep';
+import { containsVariable, DataSourceVariableModel } from '../../templating/variable';
+import { dispatch } from '../../../store/store';
+import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
+import { VariableAdapter } from '../adapters';
+import { dataSourceVariableReducer, initialDataSourceVariableModelState } from './reducer';
+import { OptionsPicker } from '../pickers';
+import { ALL_VARIABLE_TEXT, toVariableIdentifier } from '../state/types';
+import { DataSourceVariableEditor } from './DataSourceVariableEditor';
+import { updateDataSourceVariableOptions } from './actions';
+
+export const createDataSourceVariableAdapter = (): VariableAdapter => {
+ return {
+ description: 'Enabled you to dynamically switch the datasource for multiple panels',
+ label: 'Datasource',
+ initialState: initialDataSourceVariableModelState,
+ reducer: dataSourceVariableReducer,
+ picker: OptionsPicker,
+ editor: DataSourceVariableEditor,
+ dependsOn: (variable, variableToTest) => {
+ if (variable.regex) {
+ return containsVariable(variable.regex, variableToTest.name);
+ }
+ return false;
+ },
+ setValue: async (variable, option, emitChanges = false) => {
+ await dispatch(setOptionAsCurrent(toVariableIdentifier(variable), option, emitChanges));
+ },
+ setValueFromUrl: async (variable, urlValue) => {
+ await dispatch(setOptionFromUrl(toVariableIdentifier(variable), urlValue));
+ },
+ updateOptions: async variable => {
+ await dispatch(updateDataSourceVariableOptions(toVariableIdentifier(variable)));
+ },
+ getSaveModel: variable => {
+ const { index, uuid, initLock, global, ...rest } = cloneDeep(variable);
+ return { ...rest, options: [] };
+ },
+ getValueForUrl: variable => {
+ if (variable.current.text === ALL_VARIABLE_TEXT) {
+ return ALL_VARIABLE_TEXT;
+ }
+ return variable.current.value;
+ },
+ };
+};
diff --git a/public/app/features/variables/datasource/reducer.test.ts b/public/app/features/variables/datasource/reducer.test.ts
new file mode 100644
index 00000000000..f27d3ce3ce5
--- /dev/null
+++ b/public/app/features/variables/datasource/reducer.test.ts
@@ -0,0 +1,64 @@
+import { reducerTester } from '../../../../test/core/redux/reducerTester';
+import { VariablesState } from '../state/variablesReducer';
+import { createDataSourceOptions, dataSourceVariableReducer } from './reducer';
+import { DataSourceVariableModel } from '../../templating/variable';
+import { getVariableTestContext } from '../state/helpers';
+import cloneDeep from 'lodash/cloneDeep';
+import { createDataSourceVariableAdapter } from './adapter';
+import { DataSourceSelectItem } from '@grafana/data';
+import { toVariablePayload } from '../state/types';
+import { getMockPlugins } from '../../plugins/__mocks__/pluginMocks';
+
+describe('dataSourceVariableReducer', () => {
+ const adapter = createDataSourceVariableAdapter();
+ describe('when createDataSourceOptions is dispatched', () => {
+ const plugins = getMockPlugins(3);
+ const sources: DataSourceSelectItem[] = plugins.map(p => ({
+ name: p.name,
+ value: `${p.name} value`,
+ meta: p,
+ sort: '',
+ }));
+
+ it.each`
+ query | regex | includeAll | expected
+ ${sources[1].meta.id} | ${undefined} | ${false} | ${[{ text: 'pretty cool plugin-1', value: 'pretty cool plugin-1', selected: false }]}
+ ${'not-found-plugin'} | ${undefined} | ${false} | ${[{ text: 'No data sources found', value: '', selected: false }]}
+ ${sources[1].meta.id} | ${/.*(pretty cool plugin-1).*/} | ${false} | ${[{ text: 'pretty cool plugin-1', value: 'pretty cool plugin-1', selected: false }]}
+ ${sources[1].meta.id} | ${/.*(pretty cool plugin-2).*/} | ${false} | ${[{ text: 'No data sources found', value: '', selected: false }]}
+ ${sources[1].meta.id} | ${undefined} | ${true} | ${[
+ { text: 'All', value: '$__all', selected: false },
+ { text: 'pretty cool plugin-1', value: 'pretty cool plugin-1', selected: false },
+]}
+ ${'not-found-plugin'} | ${undefined} | ${true} | ${[
+ { text: 'All', value: '$__all', selected: false },
+ { text: 'No data sources found', value: '', selected: false },
+]}
+ ${sources[1].meta.id} | ${/.*(pretty cool plugin-1).*/} | ${true} | ${[
+ { text: 'All', value: '$__all', selected: false },
+ { text: 'pretty cool plugin-1', value: 'pretty cool plugin-1', selected: false },
+]}
+ ${sources[1].meta.id} | ${/.*(pretty cool plugin-2).*/} | ${true} | ${[
+ { text: 'All', value: '$__all', selected: false },
+ { text: 'No data sources found', value: '', selected: false },
+]}
+ `(
+ "when called with query: '$query' and regex: '$regex' and includeAll: '$includeAll' then state should be correct",
+ ({ query, regex, includeAll, expected }) => {
+ const { initialState } = getVariableTestContext(adapter, { query, includeAll });
+ const payload = toVariablePayload({ uuid: '0', type: 'datasource' }, { sources, regex });
+
+ reducerTester()
+ .givenReducer(dataSourceVariableReducer, cloneDeep(initialState))
+ .whenActionIsDispatched(createDataSourceOptions(payload))
+ .thenStateShouldEqual({
+ ...initialState,
+ ['0']: ({
+ ...initialState['0'],
+ options: expected,
+ } as unknown) as DataSourceVariableModel,
+ });
+ }
+ );
+ });
+});
diff --git a/public/app/features/variables/datasource/reducer.ts b/public/app/features/variables/datasource/reducer.ts
new file mode 100644
index 00000000000..2ded552ef40
--- /dev/null
+++ b/public/app/features/variables/datasource/reducer.ts
@@ -0,0 +1,70 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { DataSourceVariableModel, VariableHide, VariableOption, VariableRefresh } from '../../templating/variable';
+import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, EMPTY_UUID, getInstanceState, VariablePayload } from '../state/types';
+import { initialVariablesState, VariablesState } from '../state/variablesReducer';
+import { DataSourceSelectItem } from '@grafana/data';
+
+export interface DataSourceVariableEditorState {
+ dataSourceTypes: Array<{ text: string; value: string }>;
+}
+
+export const initialDataSourceVariableModelState: DataSourceVariableModel = {
+ uuid: EMPTY_UUID,
+ global: false,
+ type: 'datasource',
+ name: '',
+ hide: VariableHide.dontHide,
+ label: '',
+ current: {} as VariableOption,
+ regex: '',
+ options: [],
+ query: '',
+ multi: false,
+ includeAll: false,
+ refresh: VariableRefresh.onDashboardLoad,
+ skipUrlSync: false,
+ index: -1,
+ initLock: null,
+};
+
+export const dataSourceVariableSlice = createSlice({
+ name: 'templating/datasource',
+ initialState: initialVariablesState,
+ reducers: {
+ createDataSourceOptions: (
+ state: VariablesState,
+ action: PayloadAction>
+ ) => {
+ const { sources, regex } = action.payload.data;
+ const options: VariableOption[] = [];
+ const instanceState = getInstanceState(state, action.payload.uuid);
+ for (let i = 0; i < sources.length; i++) {
+ const source = sources[i];
+ // must match on type
+ if (source.meta.id !== instanceState.query) {
+ continue;
+ }
+
+ if (regex && !regex.exec(source.name)) {
+ continue;
+ }
+
+ options.push({ text: source.name, value: source.name, selected: false });
+ }
+
+ if (options.length === 0) {
+ options.push({ text: 'No data sources found', value: '', selected: false });
+ }
+
+ if (instanceState.includeAll) {
+ options.unshift({ text: ALL_VARIABLE_TEXT, value: ALL_VARIABLE_VALUE, selected: false });
+ }
+
+ instanceState.options = options;
+ },
+ },
+});
+
+export const dataSourceVariableReducer = dataSourceVariableSlice.reducer;
+
+export const { createDataSourceOptions } = dataSourceVariableSlice.actions;
diff --git a/public/app/features/templating/editor/SelectionOptionsEditor.tsx b/public/app/features/variables/editor/SelectionOptionsEditor.tsx
similarity index 97%
rename from public/app/features/templating/editor/SelectionOptionsEditor.tsx
rename to public/app/features/variables/editor/SelectionOptionsEditor.tsx
index 9505e320bfc..95d4d074fc1 100644
--- a/public/app/features/templating/editor/SelectionOptionsEditor.tsx
+++ b/public/app/features/variables/editor/SelectionOptionsEditor.tsx
@@ -2,7 +2,7 @@ import React, { FunctionComponent, useCallback } from 'react';
import { Switch } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
-import { VariableWithMultiSupport } from '../variable';
+import { VariableWithMultiSupport } from '../../templating/variable';
import { VariableEditorProps } from './types';
export interface SelectionOptionsEditorProps
diff --git a/public/app/features/templating/editor/VariableEditorContainer.tsx b/public/app/features/variables/editor/VariableEditorContainer.tsx
similarity index 96%
rename from public/app/features/templating/editor/VariableEditorContainer.tsx
rename to public/app/features/variables/editor/VariableEditorContainer.tsx
index dcc74f64da8..ca4d37f3e25 100644
--- a/public/app/features/templating/editor/VariableEditorContainer.tsx
+++ b/public/app/features/variables/editor/VariableEditorContainer.tsx
@@ -7,7 +7,7 @@ import { VariableEditorEditor } from './VariableEditorEditor';
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
import { connectWithStore } from '../../../core/utils/connectWithReduxStore';
import { getVariableClones } from '../state/selectors';
-import { VariableModel } from '../variable';
+import { VariableModel } from '../../templating/variable';
import { switchToEditMode, switchToListMode, switchToNewMode } from './actions';
import { changeVariableOrder, duplicateVariable, removeVariable } from '../state/sharedReducer';
@@ -53,7 +53,7 @@ class VariableEditorContainerUnconnected extends PureComponent {
};
onDuplicateVariable = (identifier: VariableIdentifier) => {
- this.props.duplicateVariable(toVariablePayload(identifier));
+ this.props.duplicateVariable(toVariablePayload(identifier, { newUuid: (undefined as unknown) as string }));
};
onRemoveVariable = (identifier: VariableIdentifier) => {
diff --git a/public/app/features/templating/editor/VariableEditorEditor.tsx b/public/app/features/variables/editor/VariableEditorEditor.tsx
similarity index 99%
rename from public/app/features/templating/editor/VariableEditorEditor.tsx
rename to public/app/features/variables/editor/VariableEditorEditor.tsx
index ad817b24ea8..a03f34a084f 100644
--- a/public/app/features/templating/editor/VariableEditorEditor.tsx
+++ b/public/app/features/variables/editor/VariableEditorEditor.tsx
@@ -5,7 +5,7 @@ import { FormLabel } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
import { variableAdapters } from '../adapters';
import { EMPTY_UUID, toVariablePayload, VariableIdentifier } from '../state/types';
-import { VariableHide, VariableModel, VariableType } from '../variable';
+import { VariableHide, VariableModel, VariableType } from '../../templating/variable';
import { appEvents } from '../../../core/core';
import { VariableValuesPreview } from './VariableValuesPreview';
import { changeVariableName, onEditorAdd, onEditorUpdate, variableEditorMount, variableEditorUnMount } from './actions';
diff --git a/public/app/features/templating/editor/VariableEditorList.tsx b/public/app/features/variables/editor/VariableEditorList.tsx
similarity index 98%
rename from public/app/features/templating/editor/VariableEditorList.tsx
rename to public/app/features/variables/editor/VariableEditorList.tsx
index 9cfb670b358..b6472773956 100644
--- a/public/app/features/templating/editor/VariableEditorList.tsx
+++ b/public/app/features/variables/editor/VariableEditorList.tsx
@@ -1,7 +1,7 @@
import React, { MouseEvent, PureComponent } from 'react';
import { e2e } from '@grafana/e2e';
import EmptyListCTA from '../../../core/components/EmptyListCTA/EmptyListCTA';
-import { QueryVariableModel, VariableModel } from '../variable';
+import { QueryVariableModel, VariableModel } from '../../templating/variable';
import { toVariableIdentifier, VariableIdentifier } from '../state/types';
export interface Props {
diff --git a/public/app/features/templating/editor/VariableValuesPreview.tsx b/public/app/features/variables/editor/VariableValuesPreview.tsx
similarity index 98%
rename from public/app/features/templating/editor/VariableValuesPreview.tsx
rename to public/app/features/variables/editor/VariableValuesPreview.tsx
index 945eb8b812d..37fea9ea96d 100644
--- a/public/app/features/templating/editor/VariableValuesPreview.tsx
+++ b/public/app/features/variables/editor/VariableValuesPreview.tsx
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from 'react';
-import { VariableModel, VariableOption, VariableWithOptions } from '../variable';
+import { VariableModel, VariableOption, VariableWithOptions } from '../../templating/variable';
import { e2e } from '@grafana/e2e';
export interface VariableValuesPreviewProps {
diff --git a/public/app/features/templating/editor/actions.ts b/public/app/features/variables/editor/actions.ts
similarity index 98%
rename from public/app/features/templating/editor/actions.ts
rename to public/app/features/variables/editor/actions.ts
index cfa498639d2..7b37fcab9bc 100644
--- a/public/app/features/templating/editor/actions.ts
+++ b/public/app/features/variables/editor/actions.ts
@@ -12,7 +12,7 @@ import { variableAdapters } from '../adapters';
import { v4 } from 'uuid';
import { AddVariable, EMPTY_UUID, toVariablePayload, VariableIdentifier } from '../state/types';
import cloneDeep from 'lodash/cloneDeep';
-import { VariableType } from '../variable';
+import { VariableType } from '../../templating/variable';
import { addVariable, removeVariable, storeNewVariable } from '../state/sharedReducer';
export const variableEditorMount = (identifier: VariableIdentifier): ThunkResult => {
diff --git a/public/app/features/templating/editor/reducer.test.ts b/public/app/features/variables/editor/reducer.test.ts
similarity index 100%
rename from public/app/features/templating/editor/reducer.test.ts
rename to public/app/features/variables/editor/reducer.test.ts
diff --git a/public/app/features/templating/editor/reducer.ts b/public/app/features/variables/editor/reducer.ts
similarity index 100%
rename from public/app/features/templating/editor/reducer.ts
rename to public/app/features/variables/editor/reducer.ts
diff --git a/public/app/features/templating/editor/types.ts b/public/app/features/variables/editor/types.ts
similarity index 84%
rename from public/app/features/templating/editor/types.ts
rename to public/app/features/variables/editor/types.ts
index 73ff373cc47..674926c22f1 100644
--- a/public/app/features/templating/editor/types.ts
+++ b/public/app/features/variables/editor/types.ts
@@ -1,4 +1,4 @@
-import { VariableModel } from '../variable';
+import { VariableModel } from '../../templating/variable';
export interface OnPropChangeArguments {
propName: keyof Model;
diff --git a/public/app/features/templating/guard.ts b/public/app/features/variables/guard.ts
similarity index 60%
rename from public/app/features/templating/guard.ts
rename to public/app/features/variables/guard.ts
index 8235a6957ac..8b93cc5764e 100644
--- a/public/app/features/templating/guard.ts
+++ b/public/app/features/variables/guard.ts
@@ -1,4 +1,4 @@
-import { VariableModel, QueryVariableModel } from './variable';
+import { QueryVariableModel, VariableModel } from '../templating/variable';
export const isQuery = (model: VariableModel): model is QueryVariableModel => {
return model.type === 'query';
diff --git a/public/app/features/templating/pickers/OptionsPicker/OptionsPicker.tsx b/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx
similarity index 97%
rename from public/app/features/templating/pickers/OptionsPicker/OptionsPicker.tsx
rename to public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx
index f85b132d656..f44b9fdc26d 100644
--- a/public/app/features/templating/pickers/OptionsPicker/OptionsPicker.tsx
+++ b/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx
@@ -6,7 +6,12 @@ import { VariableLink } from '../shared/VariableLink';
import { VariableInput } from '../shared/VariableInput';
import { commitChangesToVariable, filterOrSearchOptions, navigateOptions, toggleAndFetchTag } from './actions';
import { OptionsPickerState, showOptions, toggleAllOptions, toggleOption } from './reducer';
-import { VariableOption, VariableTag, VariableWithMultiSupport, VariableWithOptions } from '../../variable';
+import {
+ VariableOption,
+ VariableTag,
+ VariableWithMultiSupport,
+ VariableWithOptions,
+} from '../../../templating/variable';
import { VariableOptions } from '../shared/VariableOptions';
import { isQuery } from '../../guard';
import { VariablePickerProps } from '../types';
diff --git a/public/app/features/templating/pickers/OptionsPicker/actions.test.ts b/public/app/features/variables/pickers/OptionsPicker/actions.test.ts
similarity index 98%
rename from public/app/features/templating/pickers/OptionsPicker/actions.test.ts
rename to public/app/features/variables/pickers/OptionsPicker/actions.test.ts
index 3ed63c972ca..ffa8c39567a 100644
--- a/public/app/features/templating/pickers/OptionsPicker/actions.test.ts
+++ b/public/app/features/variables/pickers/OptionsPicker/actions.test.ts
@@ -2,7 +2,7 @@ import { reduxTester } from '../../../../../test/core/redux/reduxTester';
import { getTemplatingRootReducer } from '../../state/helpers';
import { initDashboardTemplating } from '../../state/actions';
import { TemplatingState } from '../../state/reducers';
-import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../../variable';
+import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../../../templating/variable';
import {
hideOptions,
showOptions,
@@ -374,8 +374,7 @@ describe('options picker actions', () => {
const variable = createVariable({ options, includeAll: false, tags: [tag] });
datasource.metricFindQuery.mockReset();
- // @ts-ignore couldn't wrap my head around this
- // error TS2345: Argument of type '() => Promise<{ value: string; text: string; }[]>' is not assignable to parameter of type '() => Promise'.
+ // @ts-ignore strict null error TS2345: Argument of type '() => Promise<{ value: string; text: string; }[]>' is not assignable to parameter of type '() => Promise'
datasource.metricFindQuery.mockImplementation(() => Promise.resolve(values));
const tester = await reduxTester<{ templating: TemplatingState }>()
diff --git a/public/app/features/templating/pickers/OptionsPicker/actions.ts b/public/app/features/variables/pickers/OptionsPicker/actions.ts
similarity index 98%
rename from public/app/features/templating/pickers/OptionsPicker/actions.ts
rename to public/app/features/variables/pickers/OptionsPicker/actions.ts
index 2f7e4486181..97346726b90 100644
--- a/public/app/features/templating/pickers/OptionsPicker/actions.ts
+++ b/public/app/features/variables/pickers/OptionsPicker/actions.ts
@@ -8,7 +8,7 @@ import {
VariableTag,
VariableWithMultiSupport,
VariableWithOptions,
-} from '../../variable';
+} from '../../../templating/variable';
import { variableAdapters } from '../../adapters';
import { getVariable } from '../../state/selectors';
import { NavigationKey } from '../types';
@@ -24,7 +24,7 @@ import {
} from './reducer';
import { getDataSourceSrv } from '@grafana/runtime';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
-import { setCurrentVariableValue, changeVariableProp } from '../../state/sharedReducer';
+import { changeVariableProp, setCurrentVariableValue } from '../../state/sharedReducer';
import { toVariablePayload } from '../../state/types';
export const navigateOptions = (key: NavigationKey, clearOthers: boolean): ThunkResult => {
diff --git a/public/app/features/templating/pickers/OptionsPicker/reducer.test.ts b/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts
similarity index 99%
rename from public/app/features/templating/pickers/OptionsPicker/reducer.test.ts
rename to public/app/features/variables/pickers/OptionsPicker/reducer.test.ts
index cf39b0bf877..4e4eaeadc89 100644
--- a/public/app/features/templating/pickers/OptionsPicker/reducer.test.ts
+++ b/public/app/features/variables/pickers/OptionsPicker/reducer.test.ts
@@ -14,7 +14,7 @@ import {
updateSearchQuery,
} from './reducer';
import { reducerTester } from '../../../../../test/core/redux/reducerTester';
-import { QueryVariableModel, VariableTag } from '../../variable';
+import { QueryVariableModel, VariableTag } from '../../../templating/variable';
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from '../../state/types';
const getVariableTestContext = (extend: Partial) => {
diff --git a/public/app/features/templating/pickers/OptionsPicker/reducer.ts b/public/app/features/variables/pickers/OptionsPicker/reducer.ts
similarity index 97%
rename from public/app/features/templating/pickers/OptionsPicker/reducer.ts
rename to public/app/features/variables/pickers/OptionsPicker/reducer.ts
index 5a866a5868d..7d99df621fe 100644
--- a/public/app/features/templating/pickers/OptionsPicker/reducer.ts
+++ b/public/app/features/variables/pickers/OptionsPicker/reducer.ts
@@ -1,6 +1,11 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { cloneDeep } from 'lodash';
-import { containsSearchFilter, VariableOption, VariableTag, VariableWithMultiSupport } from '../../variable';
+import {
+ containsSearchFilter,
+ VariableOption,
+ VariableTag,
+ VariableWithMultiSupport,
+} from '../../../templating/variable';
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from '../../state/types';
import { isQuery } from '../../guard';
import { applyStateChanges } from '../../../../core/utils/applyStateChanges';
diff --git a/public/app/features/templating/pickers/PickerRenderer.tsx b/public/app/features/variables/pickers/PickerRenderer.tsx
similarity index 93%
rename from public/app/features/templating/pickers/PickerRenderer.tsx
rename to public/app/features/variables/pickers/PickerRenderer.tsx
index 6b59a17a5cd..523046a14a5 100644
--- a/public/app/features/templating/pickers/PickerRenderer.tsx
+++ b/public/app/features/variables/pickers/PickerRenderer.tsx
@@ -1,5 +1,5 @@
import React, { FunctionComponent, useMemo } from 'react';
-import { VariableHide, VariableModel } from '../variable';
+import { VariableHide, VariableModel } from '../../templating/variable';
import { e2e } from '@grafana/e2e';
import { variableAdapters } from '../adapters';
diff --git a/public/app/features/templating/pickers/index.ts b/public/app/features/variables/pickers/index.ts
similarity index 100%
rename from public/app/features/templating/pickers/index.ts
rename to public/app/features/variables/pickers/index.ts
diff --git a/public/app/features/templating/pickers/shared/VariableInput.tsx b/public/app/features/variables/pickers/shared/VariableInput.tsx
similarity index 100%
rename from public/app/features/templating/pickers/shared/VariableInput.tsx
rename to public/app/features/variables/pickers/shared/VariableInput.tsx
diff --git a/public/app/features/templating/pickers/shared/VariableLink.tsx b/public/app/features/variables/pickers/shared/VariableLink.tsx
similarity index 95%
rename from public/app/features/templating/pickers/shared/VariableLink.tsx
rename to public/app/features/variables/pickers/shared/VariableLink.tsx
index a298be8c0fe..313f460754d 100644
--- a/public/app/features/templating/pickers/shared/VariableLink.tsx
+++ b/public/app/features/variables/pickers/shared/VariableLink.tsx
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react';
import { getTagColorsFromName } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
-import { VariableTag } from '../../variable';
+import { VariableTag } from '../../../templating/variable';
interface Props {
onClick: () => void;
diff --git a/public/app/features/templating/pickers/shared/VariableOptions.tsx b/public/app/features/variables/pickers/shared/VariableOptions.tsx
similarity index 98%
rename from public/app/features/templating/pickers/shared/VariableOptions.tsx
rename to public/app/features/variables/pickers/shared/VariableOptions.tsx
index 3bc2bba9af4..3c71d546881 100644
--- a/public/app/features/templating/pickers/shared/VariableOptions.tsx
+++ b/public/app/features/variables/pickers/shared/VariableOptions.tsx
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react';
import { getTagColorsFromName, Tooltip } from '@grafana/ui';
import { e2e } from '@grafana/e2e';
-import { VariableOption, VariableTag } from '../../variable';
+import { VariableOption, VariableTag } from '../../../templating/variable';
export interface Props {
multi: boolean;
diff --git a/public/app/features/templating/pickers/types.ts b/public/app/features/variables/pickers/types.ts
similarity index 79%
rename from public/app/features/templating/pickers/types.ts
rename to public/app/features/variables/pickers/types.ts
index b69546c562f..f3e2e8c7aa7 100644
--- a/public/app/features/templating/pickers/types.ts
+++ b/public/app/features/variables/pickers/types.ts
@@ -1,4 +1,4 @@
-import { VariableModel } from '../variable';
+import { VariableModel } from '../../templating/variable';
export interface VariablePickerProps {
variable: Model;
diff --git a/public/app/features/templating/query/QueryVariableEditor.tsx b/public/app/features/variables/query/QueryVariableEditor.tsx
similarity index 99%
rename from public/app/features/templating/query/QueryVariableEditor.tsx
rename to public/app/features/variables/query/QueryVariableEditor.tsx
index b1c97d54479..f6ad57d664b 100644
--- a/public/app/features/templating/query/QueryVariableEditor.tsx
+++ b/public/app/features/variables/query/QueryVariableEditor.tsx
@@ -2,9 +2,9 @@ import React, { ChangeEvent, PureComponent } from 'react';
import { e2e } from '@grafana/e2e';
import { FormLabel, Switch } from '@grafana/ui';
-import templateSrv from '../template_srv';
+import templateSrv from '../../templating/template_srv';
import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor';
-import { QueryVariableModel, VariableRefresh, VariableSort, VariableWithMultiSupport } from '../variable';
+import { QueryVariableModel, VariableRefresh, VariableSort, VariableWithMultiSupport } from '../../templating/variable';
import { QueryVariableEditorState } from './reducer';
import { changeQueryVariableDataSource, changeQueryVariableQuery, initQueryVariableEditor } from './actions';
import { VariableEditorState } from '../editor/reducer';
diff --git a/public/app/features/templating/query/actions.test.ts b/public/app/features/variables/query/actions.test.ts
similarity index 99%
rename from public/app/features/templating/query/actions.test.ts
rename to public/app/features/variables/query/actions.test.ts
index 15af7c73c53..be03b31e955 100644
--- a/public/app/features/templating/query/actions.test.ts
+++ b/public/app/features/variables/query/actions.test.ts
@@ -2,7 +2,7 @@ import { variableAdapters } from '../adapters';
import { createQueryVariableAdapter } from './adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { getTemplatingRootReducer } from '../state/helpers';
-import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../variable';
+import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../../templating/variable';
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, toVariablePayload } from '../state/types';
import { changeVariableProp, setCurrentVariableValue } from '../state/sharedReducer';
import { initDashboardTemplating } from '../state/actions';
@@ -20,7 +20,7 @@ import {
removeVariableEditorError,
setIdInEditor,
} from '../editor/reducer';
-import DefaultVariableQueryEditor from '../DefaultVariableQueryEditor';
+import DefaultVariableQueryEditor from '../../templating/DefaultVariableQueryEditor';
import { expect } from 'test/lib/common';
const mocks: Record = {
diff --git a/public/app/features/templating/query/actions.ts b/public/app/features/variables/query/actions.ts
similarity index 96%
rename from public/app/features/templating/query/actions.ts
rename to public/app/features/variables/query/actions.ts
index 3f856ffcf57..3db647700ad 100644
--- a/public/app/features/templating/query/actions.ts
+++ b/public/app/features/variables/query/actions.ts
@@ -1,13 +1,13 @@
import { AppEvents, DataSourcePluginMeta, DataSourceSelectItem } from '@grafana/data';
import { validateVariableSelectionState } from '../state/actions';
-import { QueryVariableModel, VariableRefresh } from '../variable';
+import { QueryVariableModel, VariableRefresh } from '../../templating/variable';
import { ThunkResult } from '../../../types';
import { getDatasourceSrv } from '../../plugins/datasource_srv';
import { getTimeSrv } from '../../dashboard/services/TimeSrv';
import appEvents from '../../../core/app_events';
import { importDataSourcePlugin } from '../../plugins/plugin_loader';
-import DefaultVariableQueryEditor from '../DefaultVariableQueryEditor';
+import DefaultVariableQueryEditor from '../../templating/DefaultVariableQueryEditor';
import { getVariable } from '../state/selectors';
import { addVariableEditorError, changeVariableEditorExtended, removeVariableEditorError } from '../editor/reducer';
import { variableAdapters } from '../adapters';
diff --git a/public/app/features/templating/query/adapter.ts b/public/app/features/variables/query/adapter.ts
similarity index 98%
rename from public/app/features/templating/query/adapter.ts
rename to public/app/features/variables/query/adapter.ts
index d0f5b6078c8..d6f9bf94b89 100644
--- a/public/app/features/templating/query/adapter.ts
+++ b/public/app/features/variables/query/adapter.ts
@@ -1,6 +1,6 @@
import cloneDeep from 'lodash/cloneDeep';
-import { containsVariable, QueryVariableModel, VariableRefresh } from '../variable';
+import { containsVariable, QueryVariableModel, VariableRefresh } from '../../templating/variable';
import { initialQueryVariableModelState, queryVariableReducer } from './reducer';
import { dispatch } from '../../../store/store';
import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
diff --git a/public/app/features/templating/query/reducer.test.ts b/public/app/features/variables/query/reducer.test.ts
similarity index 98%
rename from public/app/features/templating/query/reducer.test.ts
rename to public/app/features/variables/query/reducer.test.ts
index 589f6b65c77..94ba78b5a95 100644
--- a/public/app/features/templating/query/reducer.test.ts
+++ b/public/app/features/variables/query/reducer.test.ts
@@ -1,6 +1,6 @@
import { reducerTester } from '../../../../test/core/redux/reducerTester';
import { queryVariableReducer, updateVariableOptions, updateVariableTags } from './reducer';
-import { QueryVariableModel, VariableOption } from '../variable';
+import { QueryVariableModel, VariableOption } from '../../templating/variable';
import cloneDeep from 'lodash/cloneDeep';
import { VariablesState } from '../state/variablesReducer';
import { getVariableTestContext } from '../state/helpers';
diff --git a/public/app/features/templating/query/reducer.ts b/public/app/features/variables/query/reducer.ts
similarity index 98%
rename from public/app/features/templating/query/reducer.ts
rename to public/app/features/variables/query/reducer.ts
index 799e3128257..f8cad8227a7 100644
--- a/public/app/features/templating/query/reducer.ts
+++ b/public/app/features/variables/query/reducer.ts
@@ -9,8 +9,8 @@ import {
VariableRefresh,
VariableSort,
VariableTag,
-} from '../variable';
-import templateSrv from '../template_srv';
+} from '../../templating/variable';
+import templateSrv from '../../templating/template_srv';
import {
ALL_VARIABLE_TEXT,
ALL_VARIABLE_VALUE,
diff --git a/public/app/features/templating/state/actions.test.ts b/public/app/features/variables/state/actions.test.ts
similarity index 99%
rename from public/app/features/templating/state/actions.test.ts
rename to public/app/features/variables/state/actions.test.ts
index 5849c44bfe0..8903a5bfdd7 100644
--- a/public/app/features/templating/state/actions.test.ts
+++ b/public/app/features/variables/state/actions.test.ts
@@ -7,7 +7,7 @@ import { createCustomVariableAdapter } from '../custom/adapter';
import { createTextBoxVariableAdapter } from '../textbox/adapter';
import { createConstantVariableAdapter } from '../constant/adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester';
-import { TemplatingState } from 'app/features/templating/state/reducers';
+import { TemplatingState } from 'app/features/variables/state/reducers';
import { initDashboardTemplating, processVariables, setOptionFromUrl, validateVariableSelectionState } from './actions';
import { addInitLock, addVariable, removeInitLock, resolveInitLock, setCurrentVariableValue } from './sharedReducer';
import { toVariableIdentifier, toVariablePayload } from './types';
diff --git a/public/app/features/templating/state/actions.ts b/public/app/features/variables/state/actions.ts
similarity index 98%
rename from public/app/features/templating/state/actions.ts
rename to public/app/features/variables/state/actions.ts
index c803f44339a..e4babb0ec0c 100644
--- a/public/app/features/templating/state/actions.ts
+++ b/public/app/features/variables/state/actions.ts
@@ -1,7 +1,13 @@
import castArray from 'lodash/castArray';
import { UrlQueryMap, UrlQueryValue } from '@grafana/runtime';
-import { QueryVariableModel, VariableModel, VariableOption, VariableRefresh, VariableWithOptions } from '../variable';
+import {
+ QueryVariableModel,
+ VariableModel,
+ VariableOption,
+ VariableRefresh,
+ VariableWithOptions,
+} from '../../templating/variable';
import { StoreState, ThunkResult } from '../../../types';
import { getVariable, getVariables } from './selectors';
import { variableAdapters } from '../adapters';
diff --git a/public/app/features/templating/state/helpers.ts b/public/app/features/variables/state/helpers.ts
similarity index 96%
rename from public/app/features/templating/state/helpers.ts
rename to public/app/features/variables/state/helpers.ts
index 52f44fefc23..188b18668d3 100644
--- a/public/app/features/templating/state/helpers.ts
+++ b/public/app/features/variables/state/helpers.ts
@@ -2,7 +2,7 @@ import { combineReducers } from '@reduxjs/toolkit';
import cloneDeep from 'lodash/cloneDeep';
import { EMPTY_UUID } from './types';
-import { VariableHide, VariableModel, VariableRefresh, VariableType } from '../variable';
+import { VariableHide, VariableModel, VariableRefresh, VariableType } from '../../templating/variable';
import { variablesReducer, VariablesState } from './variablesReducer';
import { optionsPickerReducer } from '../pickers/OptionsPicker/reducer';
import { variableEditorReducer } from '../editor/reducer';
@@ -106,6 +106,11 @@ export const variableMockBuilder = (type: VariableType) => {
return instance;
};
+ const withRegEx = (regex: any) => {
+ model.regex = regex;
+ return instance;
+ };
+
const create = () => model;
const instance = {
@@ -116,6 +121,7 @@ export const variableMockBuilder = (type: VariableType) => {
withRefresh,
withQuery,
withMulti,
+ withRegEx,
create,
};
diff --git a/public/app/features/templating/state/processVariable.test.ts b/public/app/features/variables/state/processVariable.test.ts
similarity index 99%
rename from public/app/features/templating/state/processVariable.test.ts
rename to public/app/features/variables/state/processVariable.test.ts
index f18dcb62ac7..766d4595342 100644
--- a/public/app/features/templating/state/processVariable.test.ts
+++ b/public/app/features/variables/state/processVariable.test.ts
@@ -5,11 +5,11 @@ import { variableAdapters } from '../adapters';
import { createQueryVariableAdapter } from '../query/adapter';
import { createCustomVariableAdapter } from '../custom/adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester';
-import { TemplatingState } from 'app/features/templating/state/reducers';
+import { TemplatingState } from 'app/features/variables/state/reducers';
import { initDashboardTemplating, processVariable } from './actions';
import { resolveInitLock, setCurrentVariableValue } from './sharedReducer';
import { toVariableIdentifier, toVariablePayload } from './types';
-import { VariableRefresh } from '../variable';
+import { VariableRefresh } from '../../templating/variable';
import { updateVariableOptions } from '../query/reducer';
jest.mock('app/features/dashboard/services/TimeSrv', () => ({
diff --git a/public/app/features/templating/state/reducers.test.ts b/public/app/features/variables/state/reducers.test.ts
similarity index 98%
rename from public/app/features/templating/state/reducers.test.ts
rename to public/app/features/variables/state/reducers.test.ts
index b387722dc4b..aa9dc686635 100644
--- a/public/app/features/templating/state/reducers.test.ts
+++ b/public/app/features/variables/state/reducers.test.ts
@@ -1,6 +1,6 @@
import { reducerTester } from '../../../../test/core/redux/reducerTester';
import { cleanUpDashboard } from 'app/features/dashboard/state/reducers';
-import { VariableHide, VariableModel } from '../variable';
+import { VariableHide, VariableModel } from '../../templating/variable';
import { VariableAdapter, variableAdapters } from '../adapters';
import { createAction } from '@reduxjs/toolkit';
import { variablesReducer, VariablesState } from './variablesReducer';
diff --git a/public/app/features/templating/state/reducers.ts b/public/app/features/variables/state/reducers.ts
similarity index 91%
rename from public/app/features/templating/state/reducers.ts
rename to public/app/features/variables/state/reducers.ts
index a89733af8ed..26c439ee8ae 100644
--- a/public/app/features/templating/state/reducers.ts
+++ b/public/app/features/variables/state/reducers.ts
@@ -2,7 +2,7 @@ import { combineReducers } from '@reduxjs/toolkit';
import { optionsPickerReducer, OptionsPickerState } from '../pickers/OptionsPicker/reducer';
import { variableEditorReducer, VariableEditorState } from '../editor/reducer';
import { variablesReducer } from './variablesReducer';
-import { VariableModel } from '../variable';
+import { VariableModel } from '../../templating/variable';
export interface TemplatingState {
variables: Record;
diff --git a/public/app/features/templating/state/selectors.ts b/public/app/features/variables/state/selectors.ts
similarity index 95%
rename from public/app/features/templating/state/selectors.ts
rename to public/app/features/variables/state/selectors.ts
index e84f54f6af6..2b5e0374d6c 100644
--- a/public/app/features/templating/state/selectors.ts
+++ b/public/app/features/variables/state/selectors.ts
@@ -1,7 +1,7 @@
import { cloneDeep } from 'lodash';
import { StoreState } from '../../../types';
-import { VariableModel } from '../variable';
+import { VariableModel } from '../../templating/variable';
import { getState } from '../../../store/store';
import { EMPTY_UUID } from './types';
diff --git a/public/app/features/templating/state/sharedReducer.test.ts b/public/app/features/variables/state/sharedReducer.test.ts
similarity index 99%
rename from public/app/features/templating/state/sharedReducer.test.ts
rename to public/app/features/variables/state/sharedReducer.test.ts
index 5cd8d6906fc..8e22d5dad21 100644
--- a/public/app/features/templating/state/sharedReducer.test.ts
+++ b/public/app/features/variables/state/sharedReducer.test.ts
@@ -14,7 +14,7 @@ import {
sharedReducer,
storeNewVariable,
} from './sharedReducer';
-import { QueryVariableModel, VariableHide } from '../variable';
+import { QueryVariableModel, VariableHide } from '../../templating/variable';
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, EMPTY_UUID, toVariablePayload } from './types';
import { variableAdapters } from '../adapters';
import { createQueryVariableAdapter } from '../query/adapter';
diff --git a/public/app/features/templating/state/sharedReducer.ts b/public/app/features/variables/state/sharedReducer.ts
similarity index 98%
rename from public/app/features/templating/state/sharedReducer.ts
rename to public/app/features/variables/state/sharedReducer.ts
index 325e5223e4e..4764d70b00c 100644
--- a/public/app/features/templating/state/sharedReducer.ts
+++ b/public/app/features/variables/state/sharedReducer.ts
@@ -1,7 +1,7 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import cloneDeep from 'lodash/cloneDeep';
-import { VariableModel, VariableOption, VariableType, VariableWithOptions } from '../variable';
+import { VariableModel, VariableOption, VariableType, VariableWithOptions } from '../../templating/variable';
import { AddVariable, ALL_VARIABLE_VALUE, EMPTY_UUID, getInstanceState, VariablePayload } from './types';
import { variableAdapters } from '../adapters';
import { changeVariableNameSucceeded } from '../editor/reducer';
@@ -100,8 +100,12 @@ const sharedReducerSlice = createSlice({
},
setCurrentVariableValue: (
state: VariablesState,
- action: PayloadAction>
+ action: PayloadAction>
) => {
+ if (!action.payload.data.option) {
+ return;
+ }
+
const instanceState = getInstanceState(state, action.payload.uuid);
const current = { ...action.payload.data.option };
diff --git a/public/app/features/templating/state/types.ts b/public/app/features/variables/state/types.ts
similarity index 95%
rename from public/app/features/templating/state/types.ts
rename to public/app/features/variables/state/types.ts
index 4215e8898c2..3bad148b500 100644
--- a/public/app/features/templating/state/types.ts
+++ b/public/app/features/variables/state/types.ts
@@ -1,4 +1,4 @@
-import { VariableModel, VariableType } from '../variable';
+import { VariableModel, VariableType } from '../../templating/variable';
import { VariablesState } from './variablesReducer';
export const EMPTY_UUID = '00000000-0000-0000-0000-000000000000';
diff --git a/public/app/features/templating/state/variablesReducer.ts b/public/app/features/variables/state/variablesReducer.ts
similarity index 96%
rename from public/app/features/templating/state/variablesReducer.ts
rename to public/app/features/variables/state/variablesReducer.ts
index f454b3c8855..d1625ebf4c5 100644
--- a/public/app/features/templating/state/variablesReducer.ts
+++ b/public/app/features/variables/state/variablesReducer.ts
@@ -2,7 +2,7 @@ import { PayloadAction } from '@reduxjs/toolkit';
import { cleanUpDashboard } from '../../dashboard/state/reducers';
import { variableAdapters } from '../adapters';
import { sharedReducer } from './sharedReducer';
-import { VariableModel } from '../variable';
+import { VariableModel } from '../../templating/variable';
import { VariablePayload } from './types';
export interface VariablesState extends Record {}
diff --git a/public/app/features/templating/textbox/TextBoxVariableEditor.tsx b/public/app/features/variables/textbox/TextBoxVariableEditor.tsx
similarity index 94%
rename from public/app/features/templating/textbox/TextBoxVariableEditor.tsx
rename to public/app/features/variables/textbox/TextBoxVariableEditor.tsx
index 6a3b773462e..7390e1537de 100644
--- a/public/app/features/templating/textbox/TextBoxVariableEditor.tsx
+++ b/public/app/features/variables/textbox/TextBoxVariableEditor.tsx
@@ -1,5 +1,5 @@
import React, { ChangeEvent, PureComponent } from 'react';
-import { TextBoxVariableModel } from '../variable';
+import { TextBoxVariableModel } from '../../templating/variable';
import { VariableEditorProps } from '../editor/types';
export interface Props extends VariableEditorProps {}
diff --git a/public/app/features/templating/textbox/TextBoxVariablePicker.tsx b/public/app/features/variables/textbox/TextBoxVariablePicker.tsx
similarity index 95%
rename from public/app/features/templating/textbox/TextBoxVariablePicker.tsx
rename to public/app/features/variables/textbox/TextBoxVariablePicker.tsx
index fbc0dd1f234..878a9158d25 100644
--- a/public/app/features/templating/textbox/TextBoxVariablePicker.tsx
+++ b/public/app/features/variables/textbox/TextBoxVariablePicker.tsx
@@ -1,6 +1,6 @@
import React, { ChangeEvent, FocusEvent, KeyboardEvent, PureComponent } from 'react';
-import { TextBoxVariableModel } from '../variable';
+import { TextBoxVariableModel } from '../../templating/variable';
import { toVariablePayload } from '../state/types';
import { dispatch } from '../../../store/store';
import { variableAdapters } from '../adapters';
diff --git a/public/app/features/templating/textbox/actions.test.ts b/public/app/features/variables/textbox/actions.test.ts
similarity index 92%
rename from public/app/features/templating/textbox/actions.test.ts
rename to public/app/features/variables/textbox/actions.test.ts
index 47ff72ed0fc..e8eb7adf162 100644
--- a/public/app/features/templating/textbox/actions.test.ts
+++ b/public/app/features/variables/textbox/actions.test.ts
@@ -1,10 +1,10 @@
import { variableAdapters } from '../adapters';
import { createTextBoxVariableAdapter } from './adapter';
import { reduxTester } from '../../../../test/core/redux/reduxTester';
-import { TemplatingState } from 'app/features/templating/state/reducers';
+import { TemplatingState } from 'app/features/variables/state/reducers';
import { updateTextBoxVariableOptions } from './actions';
import { getTemplatingRootReducer } from '../state/helpers';
-import { VariableOption, VariableHide, TextBoxVariableModel } from '../variable';
+import { TextBoxVariableModel, VariableHide, VariableOption } from '../../templating/variable';
import { toVariablePayload } from '../state/types';
import { createTextBoxOptions } from './reducer';
import { setCurrentVariableValue } from '../state/sharedReducer';
diff --git a/public/app/features/templating/textbox/actions.ts b/public/app/features/variables/textbox/actions.ts
similarity index 91%
rename from public/app/features/templating/textbox/actions.ts
rename to public/app/features/variables/textbox/actions.ts
index 58fdc9e73af..b7141f0f803 100644
--- a/public/app/features/templating/textbox/actions.ts
+++ b/public/app/features/variables/textbox/actions.ts
@@ -1,4 +1,4 @@
-import { TextBoxVariableModel } from '../variable';
+import { TextBoxVariableModel } from '../../templating/variable';
import { ThunkResult } from '../../../types';
import { getVariable } from '../state/selectors';
import { variableAdapters } from '../adapters';
diff --git a/public/app/features/templating/textbox/adapter.ts b/public/app/features/variables/textbox/adapter.ts
similarity index 96%
rename from public/app/features/templating/textbox/adapter.ts
rename to public/app/features/variables/textbox/adapter.ts
index 30143f128ea..62388de283f 100644
--- a/public/app/features/templating/textbox/adapter.ts
+++ b/public/app/features/variables/textbox/adapter.ts
@@ -1,6 +1,6 @@
import cloneDeep from 'lodash/cloneDeep';
-import { TextBoxVariableModel } from '../variable';
+import { TextBoxVariableModel } from '../../templating/variable';
import { initialTextBoxVariableModelState, textBoxVariableReducer } from './reducer';
import { dispatch } from '../../../store/store';
import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
diff --git a/public/app/features/templating/textbox/reducer.test.ts b/public/app/features/variables/textbox/reducer.test.ts
similarity index 94%
rename from public/app/features/templating/textbox/reducer.test.ts
rename to public/app/features/variables/textbox/reducer.test.ts
index f06b2b52fb4..b253a62e0a4 100644
--- a/public/app/features/templating/textbox/reducer.test.ts
+++ b/public/app/features/variables/textbox/reducer.test.ts
@@ -2,9 +2,9 @@ import { reducerTester } from '../../../../test/core/redux/reducerTester';
import cloneDeep from 'lodash/cloneDeep';
import { getVariableTestContext } from '../state/helpers';
import { toVariablePayload } from '../state/types';
-import { textBoxVariableReducer, createTextBoxOptions } from './reducer';
+import { createTextBoxOptions, textBoxVariableReducer } from './reducer';
import { VariablesState } from '../state/variablesReducer';
-import { TextBoxVariableModel } from '../variable';
+import { TextBoxVariableModel } from '../../templating/variable';
import { createTextBoxVariableAdapter } from './adapter';
describe('textBoxVariableReducer', () => {
diff --git a/public/app/features/templating/textbox/reducer.ts b/public/app/features/variables/textbox/reducer.ts
similarity index 97%
rename from public/app/features/templating/textbox/reducer.ts
rename to public/app/features/variables/textbox/reducer.ts
index f5f0d5ff43a..247fa753485 100644
--- a/public/app/features/templating/textbox/reducer.ts
+++ b/public/app/features/variables/textbox/reducer.ts
@@ -1,6 +1,6 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { TextBoxVariableModel, VariableHide, VariableOption } from '../variable';
+import { TextBoxVariableModel, VariableHide, VariableOption } from '../../templating/variable';
import { EMPTY_UUID, getInstanceState, VariablePayload } from '../state/types';
import { initialVariablesState, VariablesState } from '../state/variablesReducer';
diff --git a/public/app/types/store.ts b/public/app/types/store.ts
index 1f8a94841f9..cae98a5405e 100644
--- a/public/app/types/store.ts
+++ b/public/app/types/store.ts
@@ -18,7 +18,7 @@ import { LdapState } from './ldap';
import { PanelEditorState } from '../features/dashboard/panel_editor/state/reducers';
import { PanelEditorStateNew } from '../features/dashboard/components/PanelEditor/state/reducers';
import { ApiKeysState } from './apiKeys';
-import { TemplatingState } from '../features/templating/state/reducers';
+import { TemplatingState } from '../features/variables/state/reducers';
export interface StoreState {
navIndex: NavIndex;