mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: Select the last used data source by default when adding a panel to a dashboard (#71777)
Co-authored-by: Juan Cabanas <juan.cabanas@grafana.com>
This commit is contained in:
@@ -4,9 +4,16 @@ import { DataQuery, getDataSourceRef } from '@grafana/data';
|
|||||||
import { locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||||
import { QueryGroup } from 'app/features/query/components/QueryGroup';
|
import { QueryGroup } from 'app/features/query/components/QueryGroup';
|
||||||
|
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
||||||
import { QueryGroupDataSource, QueryGroupOptions } from 'app/types';
|
import { QueryGroupDataSource, QueryGroupOptions } from 'app/types';
|
||||||
|
|
||||||
|
import { getDashboardSrv } from '../../services/DashboardSrv';
|
||||||
import { PanelModel } from '../../state';
|
import { PanelModel } from '../../state';
|
||||||
|
import {
|
||||||
|
getLastUsedDatasourceFromStorage,
|
||||||
|
initLastUsedDatasourceKeyForDashboard,
|
||||||
|
setLastUsedDatasourceKeyForDashboard,
|
||||||
|
} from '../../utils/dashboard';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/** Current panel */
|
/** Current panel */
|
||||||
@@ -20,12 +27,28 @@ export class PanelEditorQueries extends PureComponent<Props> {
|
|||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// store last used datasource in local storage
|
||||||
|
updateLastUsedDatasource = (datasource: QueryGroupDataSource) => {
|
||||||
|
if (!datasource.uid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dashboardUid = getDashboardSrv().getCurrent()?.uid ?? '';
|
||||||
|
// if datasource is MIXED reset datasource uid in storage, because Mixed datasource can contain multiple ds
|
||||||
|
if (datasource.uid === MIXED_DATASOURCE_NAME) {
|
||||||
|
return initLastUsedDatasourceKeyForDashboard(dashboardUid!);
|
||||||
|
}
|
||||||
|
setLastUsedDatasourceKeyForDashboard(dashboardUid, datasource.uid);
|
||||||
|
};
|
||||||
|
|
||||||
buildQueryOptions(panel: PanelModel): QueryGroupOptions {
|
buildQueryOptions(panel: PanelModel): QueryGroupOptions {
|
||||||
const dataSource: QueryGroupDataSource = panel.datasource ?? {
|
const dataSource: QueryGroupDataSource = panel.datasource ?? {
|
||||||
default: true,
|
default: true,
|
||||||
};
|
};
|
||||||
const datasourceSettings = getDatasourceSrv().getInstanceSettings(dataSource);
|
const datasourceSettings = getDatasourceSrv().getInstanceSettings(dataSource);
|
||||||
|
|
||||||
|
// store last datasource used in local storage
|
||||||
|
this.updateLastUsedDatasource(dataSource);
|
||||||
return {
|
return {
|
||||||
cacheTimeout: datasourceSettings?.meta.queryOptions?.cacheTimeout ? panel.cacheTimeout : undefined,
|
cacheTimeout: datasourceSettings?.meta.queryOptions?.cacheTimeout ? panel.cacheTimeout : undefined,
|
||||||
dataSource: {
|
dataSource: {
|
||||||
@@ -51,7 +74,20 @@ export class PanelEditorQueries extends PureComponent<Props> {
|
|||||||
// If the panel model has no datasource property load the default data source property and update the persisted model
|
// If the panel model has no datasource property load the default data source property and update the persisted model
|
||||||
// Because this part of the panel model is not in redux yet we do a forceUpdate.
|
// Because this part of the panel model is not in redux yet we do a forceUpdate.
|
||||||
if (!panel.datasource) {
|
if (!panel.datasource) {
|
||||||
const ds = getDatasourceSrv().getInstanceSettings(null);
|
let ds;
|
||||||
|
// check if we have last used datasource from local storage
|
||||||
|
// get dashboard uid
|
||||||
|
const dashboardUid = getDashboardSrv().getCurrent()?.uid ?? '';
|
||||||
|
const lastUsedDatasource = getLastUsedDatasourceFromStorage(dashboardUid!);
|
||||||
|
// do we have a last used datasource for this dashboard
|
||||||
|
if (lastUsedDatasource?.datasourceUid !== null) {
|
||||||
|
// get datasource from uid
|
||||||
|
ds = getDatasourceSrv().getInstanceSettings(lastUsedDatasource?.datasourceUid);
|
||||||
|
}
|
||||||
|
// else load default datasource
|
||||||
|
if (!ds) {
|
||||||
|
ds = getDatasourceSrv().getInstanceSettings(null);
|
||||||
|
}
|
||||||
panel.datasource = getDataSourceRef(ds!);
|
panel.datasource = getDataSourceRef(ds!);
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import { saveDashboard as saveDashboardApiCall } from 'app/features/manage-dashb
|
|||||||
import { useDispatch } from 'app/types';
|
import { useDispatch } from 'app/types';
|
||||||
import { DashboardSavedEvent } from 'app/types/events';
|
import { DashboardSavedEvent } from 'app/types/events';
|
||||||
|
|
||||||
|
import { updateDashboardUidLastUsedDatasource } from '../../utils/dashboard';
|
||||||
|
|
||||||
import { SaveDashboardOptions } from './types';
|
import { SaveDashboardOptions } from './types';
|
||||||
|
|
||||||
const saveDashboard = async (
|
const saveDashboard = async (
|
||||||
@@ -60,6 +62,10 @@ export const useDashboardSave = (dashboard: DashboardModel, isCopy = false) => {
|
|||||||
// important that these happen before location redirect below
|
// important that these happen before location redirect below
|
||||||
appEvents.publish(new DashboardSavedEvent());
|
appEvents.publish(new DashboardSavedEvent());
|
||||||
notifyApp.success('Dashboard saved');
|
notifyApp.success('Dashboard saved');
|
||||||
|
|
||||||
|
//Update local storage dashboard to handle things like last used datasource
|
||||||
|
updateDashboardUidLastUsedDatasource(result.uid);
|
||||||
|
|
||||||
if (isCopy) {
|
if (isCopy) {
|
||||||
reportInteraction('grafana_dashboard_copied', {
|
reportInteraction('grafana_dashboard_copied', {
|
||||||
name: dashboard.title,
|
name: dashboard.title,
|
||||||
|
|||||||
78
public/app/features/dashboard/utils/dashboard.test.ts
Normal file
78
public/app/features/dashboard/utils/dashboard.test.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
updateDashboardUidLastUsedDatasource,
|
||||||
|
getLastUsedDatasourceFromStorage,
|
||||||
|
initLastUsedDatasourceKeyForDashboard,
|
||||||
|
setLastUsedDatasourceKeyForDashboard,
|
||||||
|
} from './dashboard'; // Replace with the path to your actual module
|
||||||
|
|
||||||
|
// Mock the store module
|
||||||
|
jest.mock('app/core/store', () => ({
|
||||||
|
exists: jest.fn(),
|
||||||
|
getObject: jest.fn(),
|
||||||
|
setObject: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const store = jest.requireMock('app/core/store');
|
||||||
|
|
||||||
|
describe('Last Used Datasource Local Storage', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrieve the last used datasource', () => {
|
||||||
|
store.exists.mockReturnValue(true);
|
||||||
|
store.getObject.mockReturnValue({
|
||||||
|
dashboardUid: '123',
|
||||||
|
datasourceUid: 'datasource1',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = getLastUsedDatasourceFromStorage('123');
|
||||||
|
expect(result).toEqual({ dashboardUid: '123', datasourceUid: 'datasource1' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update only the dashboard UID', () => {
|
||||||
|
store.exists.mockReturnValue(true);
|
||||||
|
store.getObject.mockReturnValue({
|
||||||
|
dashboardUid: '456',
|
||||||
|
datasourceUid: 'datasource2',
|
||||||
|
});
|
||||||
|
|
||||||
|
updateDashboardUidLastUsedDatasource('789');
|
||||||
|
expect(store.setObject).toHaveBeenCalledWith('grafana.dashboards.panelEdit.lastUsedDatasource', {
|
||||||
|
dashboardUid: '789',
|
||||||
|
datasourceUid: 'datasource2',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize local storage for a dashboard with empty datasource UID', () => {
|
||||||
|
initLastUsedDatasourceKeyForDashboard('999');
|
||||||
|
expect(store.setObject).toHaveBeenCalledWith('grafana.dashboards.panelEdit.lastUsedDatasource', {
|
||||||
|
dashboardUid: '999',
|
||||||
|
datasourceUid: '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set a new datasource UID and dashboard UID for a dashboard', () => {
|
||||||
|
store.exists.mockReturnValue(false);
|
||||||
|
|
||||||
|
setLastUsedDatasourceKeyForDashboard('111', 'datasource3');
|
||||||
|
expect(store.setObject).toHaveBeenCalledWith('grafana.dashboards.panelEdit.lastUsedDatasource', {
|
||||||
|
dashboardUid: '111',
|
||||||
|
datasourceUid: 'datasource3',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the datasource UID while keeping the existing dashboard UID', () => {
|
||||||
|
store.exists.mockReturnValue(true);
|
||||||
|
store.getObject.mockReturnValue({
|
||||||
|
dashboardUid: '222',
|
||||||
|
datasourceUid: 'datasource4',
|
||||||
|
});
|
||||||
|
|
||||||
|
setLastUsedDatasourceKeyForDashboard('222', 'datasource5');
|
||||||
|
expect(store.setObject).toHaveBeenCalledWith('grafana.dashboards.panelEdit.lastUsedDatasource', {
|
||||||
|
dashboardUid: '222',
|
||||||
|
datasourceUid: 'datasource5',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -104,3 +104,60 @@ export function getCopiedPanelPlugin(): (PanelPluginMeta & PanelPluginInfo) | un
|
|||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LastUsedDatasource =
|
||||||
|
| {
|
||||||
|
dashboardUid: string;
|
||||||
|
datasourceUid: string;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
const PANEL_EDIT_LAST_USED_DATASOURCE = 'grafana.dashboards.panelEdit.lastUsedDatasource';
|
||||||
|
|
||||||
|
// Function that returns last used datasource from local storage
|
||||||
|
export function getLastUsedDatasourceFromStorage(dashboardUid: string): LastUsedDatasource {
|
||||||
|
// Check if user has any local storage associated with this dashboard
|
||||||
|
if (store.exists(PANEL_EDIT_LAST_USED_DATASOURCE)) {
|
||||||
|
const lastUsedDatasource: LastUsedDatasource = store.getObject(PANEL_EDIT_LAST_USED_DATASOURCE);
|
||||||
|
if (lastUsedDatasource?.dashboardUid === dashboardUid) {
|
||||||
|
return lastUsedDatasource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that updates local storage with new dashboard uid and keeps existing datasource
|
||||||
|
export function updateDashboardUidLastUsedDatasource(dashUid: string) {
|
||||||
|
// Check if user has any datasource uid in local storage
|
||||||
|
if (!store.exists(PANEL_EDIT_LAST_USED_DATASOURCE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const oldRegistryLastUsedDatasource: LastUsedDatasource = store.getObject(PANEL_EDIT_LAST_USED_DATASOURCE);
|
||||||
|
//keep existing datasource uid
|
||||||
|
const datasourceUid = oldRegistryLastUsedDatasource?.datasourceUid ?? '';
|
||||||
|
updatePropsLastUsedDatasourceKey(dashUid, datasourceUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that updates local storage with new dashboard uid and resets datasource to empty
|
||||||
|
export function initLastUsedDatasourceKeyForDashboard(dashboardUid: string | undefined) {
|
||||||
|
store.setObject(PANEL_EDIT_LAST_USED_DATASOURCE, { dashboardUid: dashboardUid, datasourceUid: '' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that updates local storage with new datasource uid and keeps existing dashboard when there is dash uid key in local storage
|
||||||
|
// or sets new local storage with new dashboard uid and existing datasource
|
||||||
|
export function setLastUsedDatasourceKeyForDashboard(dashUid: string, dsUid: string) {
|
||||||
|
// Check if user has any datasource uid in local storage
|
||||||
|
const lastUsedDatasource = getLastUsedDatasourceFromStorage(dashUid);
|
||||||
|
if (!lastUsedDatasource) {
|
||||||
|
updatePropsLastUsedDatasourceKey(dashUid, dsUid);
|
||||||
|
} else {
|
||||||
|
// set new local storage with new dashboard uid and existing datasource
|
||||||
|
const dashboardUid = lastUsedDatasource?.dashboardUid ?? '';
|
||||||
|
updatePropsLastUsedDatasourceKey(dashboardUid, dsUid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that updates local storage with new dashboard uid and datasource uid
|
||||||
|
function updatePropsLastUsedDatasourceKey(dashboardUid: string | undefined, datasourceUid: string) {
|
||||||
|
store.setObject(PANEL_EDIT_LAST_USED_DATASOURCE, { dashboardUid: dashboardUid, datasourceUid: datasourceUid });
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user