mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Browse Dashboards: Imported dashboards now display immediately in the dashboard list (#81819)
* create importDashboard method in rtk query
* fix unit tests
* Revert "fix unit tests"
This reverts commit 72cd81c803
.
* fix unit test
This commit is contained in:
parent
8c38ebfeae
commit
e2c2704296
@ -3947,7 +3947,7 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "6"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
||||
@ -3955,9 +3955,7 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "14"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "15"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "16"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "14"]
|
||||
],
|
||||
"public/app/features/manage-dashboards/state/reducers.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
|
@ -3,12 +3,20 @@ import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { isTruthy, locationUtil } from '@grafana/data';
|
||||
import { BackendSrvRequest, getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { notifyApp } from 'app/core/actions';
|
||||
import { createSuccessNotification } from 'app/core/copy/appNotification';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import { SaveDashboardCommand } from 'app/features/dashboard/components/SaveDashboard/types';
|
||||
import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
|
||||
import { DashboardDTO, DescendantCount, DescendantCountDTO, FolderDTO, SaveDashboardResponseDTO } from 'app/types';
|
||||
import {
|
||||
DashboardDTO,
|
||||
DescendantCount,
|
||||
DescendantCountDTO,
|
||||
FolderDTO,
|
||||
ImportDashboardResponseDTO,
|
||||
SaveDashboardResponseDTO,
|
||||
} from 'app/types';
|
||||
|
||||
import { refetchChildren, refreshParents } from '../state';
|
||||
import { DashboardTreeSelection } from '../types';
|
||||
@ -28,6 +36,20 @@ interface MoveItemsArgs extends DeleteItemsArgs {
|
||||
destinationUID: string;
|
||||
}
|
||||
|
||||
export interface ImportInputs {
|
||||
name: string;
|
||||
type: string;
|
||||
value: string;
|
||||
pluginId?: string;
|
||||
}
|
||||
|
||||
interface ImportOptions {
|
||||
dashboard: Dashboard;
|
||||
overwrite: boolean;
|
||||
inputs: ImportInputs[];
|
||||
folderUid: string;
|
||||
}
|
||||
|
||||
function createBackendSrvBaseQuery({ baseURL }: { baseURL: string }): BaseQueryFn<RequestOptions> {
|
||||
async function backendSrvBaseQuery(requestOptions: RequestOptions) {
|
||||
try {
|
||||
@ -299,6 +321,30 @@ export const browseDashboardsAPI = createApi({
|
||||
});
|
||||
},
|
||||
}),
|
||||
importDashboard: builder.mutation<ImportDashboardResponseDTO, ImportOptions>({
|
||||
query: ({ dashboard, overwrite, inputs, folderUid }) => ({
|
||||
method: 'POST',
|
||||
url: '/dashboards/import',
|
||||
data: {
|
||||
dashboard,
|
||||
overwrite,
|
||||
inputs,
|
||||
folderUid,
|
||||
},
|
||||
}),
|
||||
onQueryStarted: ({ folderUid }, { queryFulfilled, dispatch }) => {
|
||||
queryFulfilled.then(async (response) => {
|
||||
dispatch(
|
||||
refetchChildren({
|
||||
parentUID: folderUid,
|
||||
pageSize: PAGE_SIZE,
|
||||
})
|
||||
);
|
||||
const dashboardUrl = locationUtil.stripBaseFromUrl(response.data.importedUrl);
|
||||
locationService.push(dashboardUrl);
|
||||
});
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { thunkTester } from 'test/core/thunk/thunkTester';
|
||||
|
||||
import { DataSourceInstanceSettings, ThresholdsMode } from '@grafana/data';
|
||||
import { BackendSrv, setBackendSrv } from '@grafana/runtime';
|
||||
import { defaultDashboard, FieldColorModeId } from '@grafana/schema';
|
||||
import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
|
||||
import { getLibraryPanel } from 'app/features/library-panels/state/api';
|
||||
|
||||
import { PanelModel } from '../../dashboard/state';
|
||||
@ -20,6 +20,15 @@ const mocks = {
|
||||
|
||||
describe('importDashboard', () => {
|
||||
it('Should send data source uid', async () => {
|
||||
// note: the actual action returned is more complicated
|
||||
// but we don't really care about the return type in this test
|
||||
// we're only testing that the correct data is passed to initiate
|
||||
const mockAction = jest.fn().mockImplementation(() => ({
|
||||
type: 'foo',
|
||||
}));
|
||||
const importDashboardRtkQueryMock = jest
|
||||
.spyOn(browseDashboardsAPI.endpoints.importDashboard, 'initiate')
|
||||
.mockImplementation(mockAction);
|
||||
const form: ImportDashboardDTO = {
|
||||
title: 'Asda',
|
||||
uid: '12',
|
||||
@ -40,17 +49,6 @@ describe('importDashboard', () => {
|
||||
},
|
||||
};
|
||||
|
||||
let postArgs: unknown;
|
||||
|
||||
setBackendSrv({
|
||||
post: (url, args) => {
|
||||
postArgs = args;
|
||||
return Promise.resolve({
|
||||
importedUrl: '/my/dashboard',
|
||||
});
|
||||
},
|
||||
} as BackendSrv);
|
||||
|
||||
await thunkTester({
|
||||
importDashboard: {
|
||||
...initialImportDashboardState,
|
||||
@ -70,7 +68,7 @@ describe('importDashboard', () => {
|
||||
.givenThunk(importDashboard)
|
||||
.whenThunkIsDispatched(form);
|
||||
|
||||
expect(postArgs).toEqual({
|
||||
expect(importDashboardRtkQueryMock).toHaveBeenCalledWith({
|
||||
dashboard: {
|
||||
title: 'Asda',
|
||||
uid: '12',
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { DataSourceInstanceSettings, locationUtil } from '@grafana/data';
|
||||
import { getBackendSrv, getDataSourceSrv, isFetchError, locationService } from '@grafana/runtime';
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { getBackendSrv, getDataSourceSrv, isFetchError } from '@grafana/runtime';
|
||||
import { notifyApp } from 'app/core/actions';
|
||||
import { createErrorNotification } from 'app/core/copy/appNotification';
|
||||
import { browseDashboardsAPI, ImportInputs } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
|
||||
import { SaveDashboardCommand } from 'app/features/dashboard/components/SaveDashboard/types';
|
||||
import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
|
||||
import { FolderInfo, PermissionLevelString, SearchQueryType, ThunkResult } from 'app/types';
|
||||
@ -200,7 +201,7 @@ export function importDashboard(importDashboardForm: ImportDashboardDTO): ThunkR
|
||||
const dashboard = getState().importDashboard.dashboard;
|
||||
const inputs = getState().importDashboard.inputs;
|
||||
|
||||
let inputsToPersist = [] as any[];
|
||||
const inputsToPersist: ImportInputs[] = [];
|
||||
importDashboardForm.dataSources?.forEach((dataSource: DataSourceInstanceSettings, index: number) => {
|
||||
const input = inputs.dataSources[index];
|
||||
inputsToPersist.push({
|
||||
@ -221,18 +222,17 @@ export function importDashboard(importDashboardForm: ImportDashboardDTO): ThunkR
|
||||
});
|
||||
});
|
||||
|
||||
const result = await getBackendSrv().post('api/dashboards/import', {
|
||||
// uid: if user changed it, take the new uid from importDashboardForm,
|
||||
// else read it from original dashboard
|
||||
// by default the uid input is disabled, onSubmit ignores values from disabled inputs
|
||||
dashboard: { ...dashboard, title: importDashboardForm.title, uid: importDashboardForm.uid || dashboard.uid },
|
||||
overwrite: true,
|
||||
inputs: inputsToPersist,
|
||||
folderUid: importDashboardForm.folder.uid,
|
||||
});
|
||||
|
||||
const dashboardUrl = locationUtil.stripBaseFromUrl(result.importedUrl);
|
||||
locationService.push(dashboardUrl);
|
||||
dispatch(
|
||||
browseDashboardsAPI.endpoints.importDashboard.initiate({
|
||||
// uid: if user changed it, take the new uid from importDashboardForm,
|
||||
// else read it from original dashboard
|
||||
// by default the uid input is disabled, onSubmit ignores values from disabled inputs
|
||||
dashboard: { ...dashboard, title: importDashboardForm.title, uid: importDashboardForm.uid || dashboard.uid },
|
||||
overwrite: true,
|
||||
inputs: inputsToPersist,
|
||||
folderUid: importDashboardForm.folder.uid,
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,23 @@ export interface DashboardDTO {
|
||||
meta: DashboardMeta;
|
||||
}
|
||||
|
||||
export interface ImportDashboardResponseDTO {
|
||||
uid: string;
|
||||
pluginId: string;
|
||||
title: string;
|
||||
imported: boolean;
|
||||
importedRevision?: number;
|
||||
importedUri: string;
|
||||
importedUrl: string;
|
||||
slug: string;
|
||||
dashboardId: number;
|
||||
folderId: number;
|
||||
folderUid: string;
|
||||
description: string;
|
||||
path: string;
|
||||
removed: boolean;
|
||||
}
|
||||
|
||||
export interface SaveDashboardResponseDTO {
|
||||
id: number;
|
||||
slug: string;
|
||||
|
Loading…
Reference in New Issue
Block a user