diff --git a/public/app/features/variables/adhoc/AdHocVariableEditor.tsx b/public/app/features/variables/adhoc/AdHocVariableEditor.tsx index c3e46a37f72..387de6bb027 100644 --- a/public/app/features/variables/adhoc/AdHocVariableEditor.tsx +++ b/public/app/features/variables/adhoc/AdHocVariableEditor.tsx @@ -40,8 +40,8 @@ export class AdHocVariableEditorUnConnected extends PureComponent { const { variable, editor } = this.props; const dataSources = editor.extended?.dataSources ?? []; const infoText = editor.extended?.infoText ?? null; - const options = dataSources.map((ds) => ({ label: ds.text, value: { uid: ds.value } })); - const value = options.find((o) => o.value === variable.datasource) ?? options[0]; + const options = dataSources.map((ds) => ({ label: ds.text, value: ds.value })); + const value = options.find((o) => o.value?.uid === variable.datasource?.uid) ?? options[0]; return ( diff --git a/public/app/features/variables/adhoc/actions.test.ts b/public/app/features/variables/adhoc/actions.test.ts index 1ce5180a386..b65e3a58621 100644 --- a/public/app/features/variables/adhoc/actions.test.ts +++ b/public/app/features/variables/adhoc/actions.test.ts @@ -1,4 +1,4 @@ -import { DataSourcePluginMeta, DataSourceSelectItem } from '@grafana/data'; +import { DataSourceInstanceSettings, DataSourcePluginMeta } from '@grafana/data'; import { variableAdapters } from '../adapters'; import { createAdHocVariableAdapter } from './adapter'; @@ -22,14 +22,14 @@ import { changeVariableEditorExtended, setIdInEditor } from '../editor/reducer'; import { adHocBuilder } from '../shared/testing/builders'; import { locationService } from '@grafana/runtime'; -const getMetricSources = jest.fn().mockReturnValue([]); +const getList = jest.fn().mockReturnValue([]); const getDatasource = jest.fn().mockResolvedValue({}); locationService.partial = jest.fn(); jest.mock('app/features/plugins/datasource_srv', () => ({ getDatasourceSrv: jest.fn(() => ({ get: getDatasource, - getMetricSources, + getList, })), })); @@ -351,7 +351,7 @@ describe('adhoc actions', () => { describe('when initAdHocVariableEditor is dispatched', () => { it('then correct actions are dispatched', async () => { const datasources = [ - { ...createDatasource('default', true), value: null }, + { ...createDatasource('default', true, true), value: null }, createDatasource('elasticsearch-v1'), createDatasource('loki', false), createDatasource('influx'), @@ -359,19 +359,19 @@ describe('adhoc actions', () => { createDatasource('elasticsearch-v7'), ]; - getMetricSources.mockRestore(); - getMetricSources.mockReturnValue(datasources); + getList.mockRestore(); + getList.mockReturnValue(datasources); const tester = reduxTester() .givenRootReducer(getRootReducer()) .whenActionIsDispatched(initAdHocVariableEditor()); const expectedDatasources = [ - { text: '', value: '' }, - { text: 'default (default)', value: null }, - { text: 'elasticsearch-v1', value: 'elasticsearch-v1' }, - { text: 'influx', value: 'influx' }, - { text: 'elasticsearch-v7', value: 'elasticsearch-v7' }, + { text: '', value: {} }, + { text: 'default (default)', value: { uid: 'default', type: 'default' } }, + { text: 'elasticsearch-v1', value: { uid: 'elasticsearch-v1', type: 'elasticsearch-v1' } }, + { text: 'influx', value: { uid: 'influx', type: 'influx' } }, + { text: 'elasticsearch-v7', value: { uid: 'elasticsearch-v7', type: 'elasticsearch-v7' } }, ]; tester.thenDispatchedActionsShouldEqual( @@ -438,12 +438,14 @@ function createAddVariableAction(variable: VariableModel, index = 0) { return addVariable(toVariablePayload(identifier, data)); } -function createDatasource(name: string, selectable = true): DataSourceSelectItem { +function createDatasource(name: string, selectable = true, isDefault = false): DataSourceInstanceSettings { return { name, - value: name, meta: { mixed: !selectable, } as DataSourcePluginMeta, - }; + isDefault, + uid: name, + type: name, + } as DataSourceInstanceSettings; } diff --git a/public/app/features/variables/adhoc/actions.ts b/public/app/features/variables/adhoc/actions.ts index 9c90cadf5f1..2781dfb0e11 100644 --- a/public/app/features/variables/adhoc/actions.ts +++ b/public/app/features/variables/adhoc/actions.ts @@ -16,7 +16,7 @@ import { import { AdHocVariableFilter, AdHocVariableModel } from 'app/features/variables/types'; import { variableUpdated } from '../state/actions'; import { isAdHoc } from '../guard'; -import { DataSourceRef } from '@grafana/data'; +import { DataSourceRef, getDataSourceRef } from '@grafana/data'; export interface AdHocTableOptions { datasource: DataSourceRef; @@ -111,19 +111,20 @@ export const changeVariableDatasource = (datasource?: DataSourceRef): ThunkResul }; export const initAdHocVariableEditor = (): ThunkResult => (dispatch) => { - const dataSources = getDatasourceSrv().getMetricSources(); + const dataSources = getDatasourceSrv().getList({ metrics: true, variables: false }); const selectable = dataSources.reduce( - (all: Array<{ text: string; value: string | null }>, ds) => { + (all: Array<{ text: string; value: DataSourceRef | null }>, ds) => { if (ds.meta.mixed) { return all; } - const text = ds.value === null ? `${ds.name} (default)` : ds.name; - all.push({ text: text, value: ds.value }); + const text = ds.isDefault ? `${ds.name} (default)` : ds.name; + const value = getDataSourceRef(ds); + all.push({ text, value }); return all; }, - [{ text: '', value: '' }] + [{ text: '', value: {} }] ); dispatch( diff --git a/public/app/features/variables/adhoc/adapter.ts b/public/app/features/variables/adhoc/adapter.ts index 10adfce70b7..4ce13f78376 100644 --- a/public/app/features/variables/adhoc/adapter.ts +++ b/public/app/features/variables/adhoc/adapter.ts @@ -1,4 +1,6 @@ import { cloneDeep } from 'lodash'; +import { getDataSourceSrv } from '@grafana/runtime'; +import { getDataSourceRef } from '@grafana/data'; import { AdHocVariableModel } from '../types'; import { dispatch } from '../../../store/store'; @@ -8,6 +10,7 @@ import { adHocVariableReducer, initialAdHocVariableModelState } from './reducer' import { AdHocVariableEditor } from './AdHocVariableEditor'; import { setFiltersFromUrl } from './actions'; import * as urlParser from './urlParser'; +import { isAdHoc, isLegacyAdHocDataSource } from '../guard'; const noop = async () => {}; @@ -35,5 +38,24 @@ export const createAdHocVariableAdapter = (): VariableAdapter { + if (!isAdHoc(model)) { + return model; + } + + if (!isLegacyAdHocDataSource(model.datasource)) { + return model; + } + + const ds = getDataSourceSrv().getInstanceSettings(model.datasource); + if (!ds) { + return model; + } + + const clone = cloneDeep(model); + clone.datasource = getDataSourceRef(ds); + + return { ...clone }; + }, }; }; diff --git a/public/app/features/variables/adhoc/reducer.ts b/public/app/features/variables/adhoc/reducer.ts index 9b63e82d479..50cafae936a 100644 --- a/public/app/features/variables/adhoc/reducer.ts +++ b/public/app/features/variables/adhoc/reducer.ts @@ -1,6 +1,8 @@ -import { AdHocVariableFilter, AdHocVariableModel, initialVariableModelState } from 'app/features/variables/types'; -import { getInstanceState, VariablePayload, initialVariablesState, VariablesState } from '../state/types'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { DataSourceRef } from '@grafana/data'; + +import { AdHocVariableFilter, AdHocVariableModel, initialVariableModelState } from 'app/features/variables/types'; +import { getInstanceState, initialVariablesState, VariablePayload, VariablesState } from '../state/types'; export interface AdHocVariabelFilterUpdate { index: number; @@ -8,7 +10,7 @@ export interface AdHocVariabelFilterUpdate { } export interface AdHocVariableEditorState { infoText: string; - dataSources: Array<{ text: string; value: string }>; + dataSources: Array<{ text: string; value: DataSourceRef | null }>; } export const initialAdHocVariableModelState: AdHocVariableModel = { diff --git a/public/app/features/variables/guard.ts b/public/app/features/variables/guard.ts index bb42a3a1e42..95443a793e5 100644 --- a/public/app/features/variables/guard.ts +++ b/public/app/features/variables/guard.ts @@ -7,6 +7,7 @@ import { DataQueryResponse, DataSourceApi, DataSourceJsonData, + DataSourceRef, MetricFindValue, StandardVariableQuery, StandardVariableSupport, @@ -59,6 +60,14 @@ function hasObjectProperty(model: VariableModel, property: string): model is Var return withProperty.hasOwnProperty(property) && typeof withProperty[property] === 'object'; } +export function isLegacyAdHocDataSource(datasource: null | DataSourceRef | string): datasource is string { + if (datasource === null) { + return false; + } + + return typeof datasource === 'string'; +} + interface DataSourceWithLegacyVariableSupport< TQuery extends DataQuery = DataQuery, TOptions extends DataSourceJsonData = DataSourceJsonData