Dashboards: Fix moving to root folder (#111515)

This commit is contained in:
Stephanie Hingtgen
2025-09-24 04:45:00 -06:00
committed by GitHub
parent 46adb9a158
commit 17c3f34688
4 changed files with 132 additions and 3 deletions
+70 -1
View File
@@ -1,6 +1,6 @@
import { GrafanaConfig, locationUtil } from '@grafana/data';
import { backendSrv } from 'app/core/services/backend_srv';
import { AnnoKeyFolder, AnnoReloadOnParamsChange } from 'app/features/apiserver/types';
import { AnnoKeyFolder, AnnoKeyMessage, AnnoReloadOnParamsChange } from 'app/features/apiserver/types';
import { DashboardDataDTO } from 'app/types/dashboard';
import { DashboardWithAccessInfo } from './types';
@@ -316,6 +316,75 @@ describe('v1 dashboard API', () => {
expect(result.url).toBe('/grafana/d/adh59cn/new-dashboard-saved');
});
});
it('should handle empty string folderUid for root folder', async () => {
const api = new K8sDashboardAPI();
const saveCommand = {
dashboard: {
uid: 'test-dash',
title: 'Test Dashboard',
tags: [],
timezone: 'browser',
panels: [],
time: { from: 'now-6h', to: 'now' },
timepicker: {},
templating: { list: [] },
annotations: { list: [] },
refresh: '5s',
schemaVersion: 16,
version: 0,
links: [],
},
folderUid: '',
message: 'Move to root folder',
};
await api.saveDashboard(saveCommand);
expect(mockPut).toHaveBeenCalledTimes(1);
expect(mockPut).toHaveBeenCalledWith(
'/apis/dashboard.grafana.app/v1beta1/namespaces/default/dashboards/test-dash',
expect.objectContaining({
metadata: expect.objectContaining({
annotations: expect.objectContaining({
[AnnoKeyFolder]: '',
[AnnoKeyMessage]: 'Move to root folder',
}),
}),
}),
{ params: { fieldValidation: 'Ignore' } }
);
});
it('should not set folder annotation when folderUid is undefined', async () => {
const api = new K8sDashboardAPI();
const saveCommand = {
dashboard: {
uid: 'test-dash',
title: 'Test Dashboard',
tags: [],
timezone: 'browser',
panels: [],
time: { from: 'now-6h', to: 'now' },
timepicker: {},
templating: { list: [] },
annotations: { list: [] },
refresh: '5s',
schemaVersion: 16,
version: 0,
links: [],
},
message: 'Save without folder',
};
await api.saveDashboard(saveCommand);
expect(mockPut).toHaveBeenCalledTimes(1);
const callArgs = mockPut.mock.calls[0];
const requestBody = callArgs[1];
expect(requestBody.metadata.annotations).not.toHaveProperty(AnnoKeyFolder);
expect(requestBody.metadata.annotations[AnnoKeyMessage]).toBe('Save without folder');
});
});
describe('version error handling', () => {
+1 -1
View File
@@ -64,7 +64,7 @@ export class K8sDashboardAPI implements DashboardAPI<DashboardDTO, Dashboard> {
delete obj.metadata.annotations[AnnoKeyMessage];
}
if (options.folderUid) {
if (options.folderUid !== undefined) {
obj.metadata.annotations = {
...obj.metadata.annotations,
[AnnoKeyFolder]: options.folderUid,
@@ -252,6 +252,66 @@ describe('v2 dashboard API', () => {
{ params: undefined }
);
});
it('should handle empty string folderUid for root folder', async () => {
const api = new K8sDashboardV2API();
const saveCommand = {
dashboard: defaultDashboardV2Spec(),
folderUid: '',
message: 'Move to root folder',
k8s: {
name: 'existing-dash',
annotations: {
[AnnoKeyFolder]: 'some-previous-folder',
[AnnoKeyFolderUrl]: 'some-folder-url',
[AnnoKeyFolderTitle]: 'Some Folder Title',
},
},
};
await api.saveDashboard(saveCommand);
expect(mockPut).toHaveBeenCalledTimes(1);
expect(mockPut).toHaveBeenCalledWith(
'/apis/dashboard.grafana.app/v2beta1/namespaces/default/dashboards/existing-dash',
{
metadata: {
name: 'existing-dash',
annotations: {
[AnnoKeyFolder]: '',
[AnnoKeyMessage]: 'Move to root folder',
[AnnoKeySavedFromUI]: '10.0.0',
},
},
spec: defaultDashboardV2Spec(),
},
{ params: undefined }
);
const callArgs = mockPut.mock.calls[0];
const requestBody = callArgs[1];
expect(requestBody.metadata.annotations).not.toHaveProperty(AnnoKeyFolderUrl);
expect(requestBody.metadata.annotations).not.toHaveProperty(AnnoKeyFolderTitle);
});
it('should not set folder annotation when folderUid is undefined', async () => {
const api = new K8sDashboardV2API();
const saveCommand = {
dashboard: defaultDashboardV2Spec(),
message: 'Save without folder',
k8s: {
name: 'existing-dash',
},
};
await api.saveDashboard(saveCommand);
expect(mockPut).toHaveBeenCalledTimes(1);
const callArgs = mockPut.mock.calls[0];
const requestBody = callArgs[1];
expect(requestBody.metadata.annotations).not.toHaveProperty(AnnoKeyFolder);
expect(requestBody.metadata.annotations[AnnoKeyMessage]).toBe('Save without folder');
});
});
describe('version error handling', () => {
+1 -1
View File
@@ -130,7 +130,7 @@ export class K8sDashboardV2API
}
// add folder annotation
if (options.folderUid) {
if (options.folderUid !== undefined) {
// remove frontend folder annotations
delete obj.metadata.annotations?.[AnnoKeyFolderTitle];
delete obj.metadata.annotations?.[AnnoKeyFolderUrl];