[Release 12.0.1]SchemaV2 - Fix Import showing grafana ds(#104461) (#104828)

Dashboard: SchemaV2 - Fix Import showing grafana datasources (#104461)

* Fix: do not map when identifying default grafana ds

* add also datasource type

* Refactor code, add unit test

* Fix types references and linting

* Update public/app/features/manage-dashboards/state/actions.test.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit 26ce124208)
pull/104847/head
Alexa V 3 months ago committed by GitHub
parent 3b2165d787
commit 5ad33cb0a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 65
      public/app/features/manage-dashboards/state/actions.test.ts
  2. 15
      public/app/features/manage-dashboards/state/actions.ts

@ -3,11 +3,11 @@ import { thunkTester } from 'test/core/thunk/thunkTester';
import { DataSourceInstanceSettings, ThresholdsMode } from '@grafana/data'; import { DataSourceInstanceSettings, ThresholdsMode } from '@grafana/data';
import { defaultDashboard, FieldColorModeId } from '@grafana/schema'; import { defaultDashboard, FieldColorModeId } from '@grafana/schema';
import { import {
DashboardV2Spec, Spec as DashboardV2Spec,
defaultDashboardV2Spec, defaultSpec as defaultDashboardV2Spec,
defaultPanelSpec, defaultPanelSpec,
defaultQueryVariableSpec, defaultQueryVariableSpec,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0'; } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI'; import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
import { getLibraryPanel } from 'app/features/library-panels/state/api'; import { getLibraryPanel } from 'app/features/library-panels/state/api';
@ -16,7 +16,13 @@ import { LibraryElementDTO } from '../../library-panels/types';
import { DashboardJson } from '../types'; import { DashboardJson } from '../types';
import { validateDashboardJson } from '../utils/validation'; import { validateDashboardJson } from '../utils/validation';
import { getLibraryPanelInputs, importDashboard, processDashboard, processV2Datasources } from './actions'; import {
getLibraryPanelInputs,
importDashboard,
processDashboard,
processV2DatasourceInput,
processV2Datasources,
} from './actions';
import { DataSourceInput, ImportDashboardDTO, initialImportDashboardState, InputType } from './reducers'; import { DataSourceInput, ImportDashboardDTO, initialImportDashboardState, InputType } from './reducers';
jest.mock('app/features/library-panels/state/api'); jest.mock('app/features/library-panels/state/api');
@ -29,7 +35,7 @@ jest.mock('@grafana/runtime', () => ({
getDataSourceSrv: () => ({ getDataSourceSrv: () => ({
...jest.requireActual('@grafana/runtime').getDataSourceSrv(), ...jest.requireActual('@grafana/runtime').getDataSourceSrv(),
get: jest.fn().mockImplementation((dsType: { type: string }) => { get: jest.fn().mockImplementation((dsType: { type: string }) => {
const dsList: { const dsListTypeDSMock: {
[key: string]: { [key: string]: {
uid: string; uid: string;
name: string; name: string;
@ -55,8 +61,15 @@ jest.mock('@grafana/runtime', () => ({
type: 'grafana', type: 'grafana',
meta: { id: 'grafana' }, meta: { id: 'grafana' },
}, },
// "datasource" type is what we call "--Dashboard--" datasource
datasource: {
uid: '--Dashboard--',
name: '--Dashboard--',
type: 'datasource',
meta: { id: 'dashboard' },
},
}; };
return dsList[dsType.type]; return dsListTypeDSMock[dsType.type];
}), }),
}), }),
})); }));
@ -959,3 +972,43 @@ describe('processV2Datasources', () => {
); );
}); });
}); });
describe('processV2DatasourceInput', () => {
// should not map grafana datasource input or dashboard datasource input
it('Should not map grafana datasource input', async () => {
const queryVariable = {
kind: 'QueryVariable',
spec: {
...defaultQueryVariableSpec(),
name: 'var2WithGrafanaDs',
query: {
kind: 'grafana',
spec: {
panelId: 2,
},
},
},
};
const result = await processV2DatasourceInput(queryVariable.spec, {});
expect(result).toEqual({});
});
it('Should not map dashboard datasource input', async () => {
// create a panel with dashboard datasource input
const panelQuery = {
kind: 'PanelQuery',
spec: {
refId: 'A',
hidden: false,
query: {
kind: 'datasource',
spec: {
panelId: 2,
},
},
},
};
const result = await processV2DatasourceInput(panelQuery.spec, {});
expect(result).toEqual({});
});
});

@ -162,26 +162,26 @@ export function processV2Datasources(dashboard: DashboardV2Spec): ThunkResult<vo
const { elements, variables, annotations } = dashboard; const { elements, variables, annotations } = dashboard;
// get elements from dashboard // get elements from dashboard
// each element can only be a panel // each element can only be a panel
const inputs: Record<string, DataSourceInput> = {}; let inputs: Record<string, DataSourceInput> = {};
for (const element of Object.values(elements)) { for (const element of Object.values(elements)) {
if (element.kind !== 'Panel') { if (element.kind !== 'Panel') {
throw new Error('Only panels are currenlty supported in v2 dashboards'); throw new Error('Only panels are currenlty supported in v2 dashboards');
} }
if (element.spec.data.spec.queries.length > 0) { if (element.spec.data.spec.queries.length > 0) {
for (const query of element.spec.data.spec.queries) { for (const query of element.spec.data.spec.queries) {
await processV2DatasourceInput(query.spec, inputs); inputs = await processV2DatasourceInput(query.spec, inputs);
} }
} }
} }
for (const variable of variables) { for (const variable of variables) {
if (variable.kind === 'QueryVariable') { if (variable.kind === 'QueryVariable') {
await processV2DatasourceInput(variable.spec, inputs); inputs = await processV2DatasourceInput(variable.spec, inputs);
} }
} }
for (const annotation of annotations) { for (const annotation of annotations) {
await processV2DatasourceInput(annotation.spec, inputs); inputs = await processV2DatasourceInput(annotation.spec, inputs);
} }
dispatch(setInputs(Object.values(inputs))); dispatch(setInputs(Object.values(inputs)));
@ -337,6 +337,12 @@ export async function processV2DatasourceInput(
const datasourceRef = obj?.datasource; const datasourceRef = obj?.datasource;
if (!datasourceRef && obj?.query) { if (!datasourceRef && obj?.query) {
const dsType = obj.query.kind; const dsType = obj.query.kind;
// if dsType is grafana, it means we are using a built-in annotation or default grafana datasource, in those
// cases we don't need to map it
// "datasource" type is what we call "--Dashboard--" datasource <.-.>
if (dsType === 'grafana' || dsType === 'datasource') {
return inputs;
}
const datasource = await getDatasourceSrv().get({ type: dsType }); const datasource = await getDatasourceSrv().get({ type: dsType });
let dataSourceInput: DataSourceInput | undefined; let dataSourceInput: DataSourceInput | undefined;
if (datasource) { if (datasource) {
@ -363,4 +369,5 @@ export async function processV2DatasourceInput(
inputs[dsType] = dataSourceInput; inputs[dsType] = dataSourceInput;
} }
} }
return inputs;
} }

Loading…
Cancel
Save