diff --git a/public/app/features/dashboard-scene/scene/export/exporters.test.ts b/public/app/features/dashboard-scene/scene/export/exporters.test.ts index 5194233f54a..38cc91bf462 100644 --- a/public/app/features/dashboard-scene/scene/export/exporters.test.ts +++ b/public/app/features/dashboard-scene/scene/export/exporters.test.ts @@ -144,7 +144,7 @@ describe('dashboard exporter v1', () => { expect(exported.templating.list[0].datasource.uid).toBe('${DS_GFDB}'); }); - it('do not expose datasource name and id in a in a template variable of type datasource', async () => { + it('templateize datasource uid in a datasource variable that is used in a panel', async () => { const dashboard: Dashboard = { title: 'My dashboard', revision: 1, @@ -159,6 +159,10 @@ describe('dashboard exporter v1', () => { type: 'timeseries', title: 'My panel title', gridPos: { x: 0, y: 0, w: 1, h: 1 }, + datasource: { + type: 'prometheus', + uid: '${ds_var}', + }, }, ], templating: { @@ -172,7 +176,7 @@ describe('dashboard exporter v1', () => { hide: 0, includeAll: false, multi: false, - name: 'query1', + name: 'ds_var', options: [], query: 'prometheus', refresh: 1, @@ -188,7 +192,11 @@ describe('dashboard exporter v1', () => { }); const exported = (await makeExportableV1(dashboardModel)) as DashboardJson; const value = exported?.templating?.list ? exported?.templating?.list[0].current : ''; - expect(value).toEqual({}); + expect(value).toEqual({ + selected: true, + text: '', + value: '${DS_GFDB}', + }); }); it('replaces datasource ref in library panel', async () => { diff --git a/public/app/features/dashboard-scene/scene/export/exporters.ts b/public/app/features/dashboard-scene/scene/export/exporters.ts index 785cb8dd529..01a2ea9736b 100644 --- a/public/app/features/dashboard-scene/scene/export/exporters.ts +++ b/public/app/features/dashboard-scene/scene/export/exporters.ts @@ -19,7 +19,7 @@ import { buildPanelKind } from 'app/features/dashboard/api/ResponseTransformers' import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; import { PanelModel, GridPos } from 'app/features/dashboard/state/PanelModel'; import { getLibraryPanel } from 'app/features/library-panels/state/api'; -import { variableRegex } from 'app/features/variables/utils'; +import { variableRegexExec } from 'app/features/variables/utils'; import { dispatch } from 'app/store/store'; import { isPanelModelLibraryPanel } from '../../../library-panels/guard'; @@ -110,6 +110,8 @@ export async function makeExportableV1(dashboard: DashboardModel) { variableLookup[variable.name] = variable; } + const datasourceVariableRefNameMap: { [key: string]: string } = {}; + const templateizeDatasourceUsage = (obj: any, fallback?: DataSourceRef) => { if (obj.datasource === undefined) { obj.datasource = fallback; @@ -120,11 +122,11 @@ export async function makeExportableV1(dashboard: DashboardModel) { let datasourceVariable: any = null; const datasourceUid: string | undefined = datasource?.uid; - const match = datasourceUid && variableRegex.exec(datasourceUid); + const match = datasourceUid && variableRegexExec(datasourceUid); + let varName: string | undefined; - // ignore data source properties that contain a variable if (match) { - const varName = match[1] || match[2] || match[4]; + varName = match[1] || match[2] || match[4]; datasourceVariable = variableLookup[varName]; if (datasourceVariable && datasourceVariable.current) { datasource = datasourceVariable.current.value; @@ -146,14 +148,10 @@ export async function makeExportableV1(dashboard: DashboardModel) { version: ds.meta.info.version || '1.0.0', }; - // if used via variable we can skip templatizing usage - if (datasourceVariable) { - return; - } - const libraryPanel = obj.libraryPanel; const libraryPanelSuffix = !!libraryPanel ? '-for-library-panel' : ''; let refName = 'DS_' + ds.name.replace(' ', '_').toUpperCase() + libraryPanelSuffix.toUpperCase(); + const templatedUid = '${' + refName + '}'; datasources[refName] = { name: refName, @@ -174,7 +172,14 @@ export async function makeExportableV1(dashboard: DashboardModel) { }; } - obj.datasource = { type: ds.meta.id, uid: '${' + refName + '}' }; + // if it panel or query is relying on a datasource variable + // skip templating datasource uid but save the reference so we can set datasource variable's current prop + if (datasourceVariable && varName) { + datasourceVariableRefNameMap[varName] = '${' + refName + '}'; + return; + } + + obj.datasource = { type: ds.meta.id, uid: templatedUid }; }); }; @@ -240,7 +245,16 @@ export async function makeExportableV1(dashboard: DashboardModel) { variable.refresh = variable.refresh !== VariableRefresh.never ? variable.refresh : VariableRefresh.onDashboardLoad; } else if (variable.type === 'datasource') { - variable.current = {}; + const templateizedUID = datasourceVariableRefNameMap[variable.name]; + if (templateizedUID) { + variable.current = { + text: '', + value: templateizedUID, + selected: true, + }; + } else { + variable.current = {}; + } } else if (variable.type === 'adhoc') { await templateizeDatasourceUsage(variable); } diff --git a/public/app/features/dashboard-scene/v2schema/ImportDashboardFormV2.tsx b/public/app/features/dashboard-scene/v2schema/ImportDashboardFormV2.tsx index 0882b80310f..ed2e5760a49 100644 --- a/public/app/features/dashboard-scene/v2schema/ImportDashboardFormV2.tsx +++ b/public/app/features/dashboard-scene/v2schema/ImportDashboardFormV2.tsx @@ -97,7 +97,7 @@ export const ImportDashboardFormV2 = ({ return (