Folders: Deprecate getFolderByUID method (#113173)
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEffect, useMemo } from 'react';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { config, getAppEvents } from '@grafana/runtime';
|
||||
import { DisplayList, iamAPIv0alpha1, useLazyGetDisplayMappingQuery } from 'app/api/clients/iam/v0alpha1';
|
||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||
import {
|
||||
useDeleteFolderMutation as useDeleteFolderMutationLegacy,
|
||||
@@ -17,9 +18,11 @@ import {
|
||||
MoveFoldersArgs,
|
||||
DeleteFoldersArgs,
|
||||
MoveFolderArgs,
|
||||
browseDashboardsAPI,
|
||||
} from 'app/features/browse-dashboards/api/browseDashboardsAPI';
|
||||
import { DashboardTreeSelection } from 'app/features/browse-dashboards/types';
|
||||
import { FolderDTO, NewFolder } from 'app/types/folders';
|
||||
import { dispatch } from 'app/types/store';
|
||||
|
||||
import kbn from '../../../../core/utils/kbn';
|
||||
import {
|
||||
@@ -36,12 +39,12 @@ import { refetchChildren, refreshParents } from '../../../../features/browse-das
|
||||
import { GENERAL_FOLDER_UID } from '../../../../features/search/constants';
|
||||
import { deletedDashboardsCache } from '../../../../features/search/service/deletedDashboardsCache';
|
||||
import { useDispatch } from '../../../../types/store';
|
||||
import { useLazyGetDisplayMappingQuery } from '../../iam/v0alpha1';
|
||||
|
||||
import { isProvisionedFolderCheck } from './utils';
|
||||
import { rootFolder, sharedWithMeFolder } from './virtualFolders';
|
||||
|
||||
import {
|
||||
folderAPIv1beta1,
|
||||
useGetFolderQuery,
|
||||
useGetFolderParentsQuery,
|
||||
useDeleteFolderMutation,
|
||||
@@ -52,6 +55,7 @@ import {
|
||||
useReplaceFolderMutation,
|
||||
ReplaceFolderApiArg,
|
||||
useGetAffectedItemsQuery,
|
||||
FolderInfo,
|
||||
} from './index';
|
||||
|
||||
function getFolderUrl(uid: string, title: string): string {
|
||||
@@ -62,6 +66,91 @@ function getFolderUrl(uid: string, title: string): string {
|
||||
return `${config.appSubUrl}/dashboards/f/${uid}/${slug}`;
|
||||
}
|
||||
|
||||
const combineFolderResponses = (
|
||||
folder: Folder,
|
||||
legacyFolder: FolderDTO,
|
||||
parents: FolderInfo[],
|
||||
userDisplay?: DisplayList
|
||||
) => {
|
||||
const updatedBy = folder.metadata.annotations?.[AnnoKeyUpdatedBy];
|
||||
const createdBy = folder.metadata.annotations?.[AnnoKeyCreatedBy];
|
||||
|
||||
const newData: FolderDTO = {
|
||||
canAdmin: legacyFolder.canAdmin,
|
||||
canDelete: legacyFolder.canDelete,
|
||||
canEdit: legacyFolder.canEdit,
|
||||
canSave: legacyFolder.canSave,
|
||||
accessControl: legacyFolder.accessControl,
|
||||
createdBy: (createdBy && userDisplay?.display[userDisplay?.keys.indexOf(createdBy)]?.displayName) || 'Anonymous',
|
||||
updatedBy: (updatedBy && userDisplay?.display[userDisplay?.keys.indexOf(updatedBy)]?.displayName) || 'Anonymous',
|
||||
...appPlatformFolderToLegacyFolder(folder),
|
||||
};
|
||||
|
||||
if (parents.length) {
|
||||
newData.parents = parents
|
||||
.filter((i) => i.name !== folder.metadata.name)
|
||||
.map(({ name, title }) => ({
|
||||
title: title,
|
||||
uid: name,
|
||||
// No idea how to make slug, on the server it uses a go lib: https://github.com/grafana/grafana/blob/aac66e91198004bc044754105e18bfff8fbfd383/pkg/infra/slugify/slugify.go#L56
|
||||
// Don't think slug is needed for the URL to work though
|
||||
url: getFolderUrl(name, title),
|
||||
}));
|
||||
}
|
||||
|
||||
return newData;
|
||||
};
|
||||
|
||||
export async function getFolderByUidFacade(uid: string): Promise<FolderDTO> {
|
||||
const isVirtualFolder = uid && [GENERAL_FOLDER_UID, config.sharedWithMeFolderUID].includes(uid);
|
||||
// We need the legacy API call regardless, for now
|
||||
const legacyApiCall = dispatch(browseDashboardsAPI.endpoints.getFolder.initiate(uid));
|
||||
|
||||
const shouldUseAppPlatformAPI = Boolean(config.featureToggles.foldersAppPlatformAPI);
|
||||
if (shouldUseAppPlatformAPI) {
|
||||
let virtualFolderResponse;
|
||||
if (isVirtualFolder) {
|
||||
virtualFolderResponse = GENERAL_FOLDER_UID === uid ? rootFolder : sharedWithMeFolder;
|
||||
}
|
||||
|
||||
const responses = await Promise.all([
|
||||
// We still need to call legacy endpoints for access control metadata
|
||||
legacyApiCall,
|
||||
isVirtualFolder
|
||||
? Promise.resolve({ data: virtualFolderResponse })
|
||||
: dispatch(folderAPIv1beta1.endpoints.getFolder.initiate({ name: uid })),
|
||||
dispatch(folderAPIv1beta1.endpoints.getFolderParents.initiate({ name: uid })),
|
||||
]);
|
||||
|
||||
const [legacyFolderResponse, folderResponse, parentsResponse] = responses;
|
||||
|
||||
if (!folderResponse?.data || !legacyFolderResponse?.data || !parentsResponse?.data) {
|
||||
throw new Error('One of the folder responses is undefined');
|
||||
}
|
||||
|
||||
const userKeys = getUserKeys(folderResponse.data);
|
||||
let userResponse;
|
||||
if (userKeys.length) {
|
||||
userResponse = await dispatch(iamAPIv0alpha1.endpoints.getDisplayMapping.initiate({ key: userKeys }));
|
||||
}
|
||||
|
||||
return combineFolderResponses(
|
||||
folderResponse.data,
|
||||
legacyFolderResponse.data,
|
||||
parentsResponse.data.items,
|
||||
userResponse?.data
|
||||
);
|
||||
}
|
||||
|
||||
const legacyFolderResponse = await legacyApiCall;
|
||||
|
||||
if (legacyFolderResponse.error || !legacyFolderResponse.data) {
|
||||
throw legacyFolderResponse.error || new Error('Legacy folder response is undefined');
|
||||
}
|
||||
|
||||
return legacyFolderResponse.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* A proxy function that uses either legacy folder client or the new app platform APIs to get the data in the same
|
||||
* format of a FolderDTO object. As the schema isn't the same, using the app platform needs multiple different calls
|
||||
@@ -84,12 +173,12 @@ export function useGetFolderQueryFacade(uid?: string) {
|
||||
const [triggerGetUserDisplayMapping, resultUserDisplay] = useLazyGetDisplayMappingQuery();
|
||||
|
||||
const needsUserData = useMemo(() => {
|
||||
const userKeys = getUserKeys(resultFolder);
|
||||
const userKeys = getUserKeys(resultFolder.data);
|
||||
return !isVirtualFolder && Boolean(userKeys.length);
|
||||
}, [isVirtualFolder, resultFolder]);
|
||||
|
||||
useEffect(() => {
|
||||
const userKeys = getUserKeys(resultFolder);
|
||||
const userKeys = getUserKeys(resultFolder.data);
|
||||
if (needsUserData && userKeys.length) {
|
||||
triggerGetUserDisplayMapping({ key: userKeys }, true);
|
||||
}
|
||||
@@ -125,39 +214,12 @@ export function useGetFolderQueryFacade(uid?: string) {
|
||||
legacyFolderResult.data &&
|
||||
(needsUserData ? resultUserDisplay.data : true)
|
||||
) {
|
||||
const updatedBy = resultFolder.data.metadata.annotations?.[AnnoKeyUpdatedBy];
|
||||
const createdBy = resultFolder.data.metadata.annotations?.[AnnoKeyCreatedBy];
|
||||
|
||||
const parsed = appPlatformFolderToLegacyFolder(resultFolder.data);
|
||||
|
||||
newData = {
|
||||
canAdmin: legacyFolderResult.data.canAdmin,
|
||||
canDelete: legacyFolderResult.data.canDelete,
|
||||
canEdit: legacyFolderResult.data.canEdit,
|
||||
canSave: legacyFolderResult.data.canSave,
|
||||
accessControl: legacyFolderResult.data.accessControl,
|
||||
|
||||
createdBy:
|
||||
(createdBy && resultUserDisplay.data?.display[resultUserDisplay.data?.keys.indexOf(createdBy)]?.displayName) ||
|
||||
'Anonymous',
|
||||
|
||||
updatedBy:
|
||||
(updatedBy && resultUserDisplay.data?.display[resultUserDisplay.data?.keys.indexOf(updatedBy)]?.displayName) ||
|
||||
'Anonymous',
|
||||
...parsed,
|
||||
};
|
||||
|
||||
if (resultParents.data.items?.length) {
|
||||
newData.parents = resultParents.data.items
|
||||
.filter((i) => i.name !== resultFolder.data!.metadata.name)
|
||||
.map((i) => ({
|
||||
title: i.title,
|
||||
uid: i.name,
|
||||
// No idea how to make slug, on the server it uses a go lib: https://github.com/grafana/grafana/blob/aac66e91198004bc044754105e18bfff8fbfd383/pkg/infra/slugify/slugify.go#L56
|
||||
// Don't think slug is needed for the URL to work though
|
||||
url: getFolderUrl(i.name, i.title),
|
||||
}));
|
||||
}
|
||||
newData = combineFolderResponses(
|
||||
resultFolder.data,
|
||||
legacyFolderResult.data,
|
||||
resultParents.data.items,
|
||||
resultUserDisplay.data
|
||||
);
|
||||
}
|
||||
|
||||
// Wrap the stitched data into single RTK query response type object so this looks like a single API call
|
||||
@@ -440,13 +502,10 @@ function combinedState(
|
||||
};
|
||||
}
|
||||
|
||||
function getUserKeys(resultFolder: ReturnType<typeof useGetFolderQuery>): string[] {
|
||||
return resultFolder.data
|
||||
? [
|
||||
resultFolder.data.metadata.annotations?.[AnnoKeyUpdatedBy],
|
||||
resultFolder.data.metadata.annotations?.[AnnoKeyCreatedBy],
|
||||
].filter((v) => v !== undefined)
|
||||
: [];
|
||||
function getUserKeys(folder?: Folder): string[] {
|
||||
return [folder?.metadata.annotations?.[AnnoKeyUpdatedBy], folder?.metadata.annotations?.[AnnoKeyCreatedBy]].filter(
|
||||
(v) => v !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
const appPlatformFolderToLegacyFolder = (
|
||||
|
||||
@@ -80,9 +80,4 @@ export const {
|
||||
} = folderAPIv1beta1;
|
||||
|
||||
// eslint-disable-next-line no-barrel-files/no-barrel-files
|
||||
export {
|
||||
type Folder,
|
||||
type FolderList,
|
||||
type CreateFolderApiArg,
|
||||
type ReplaceFolderApiArg,
|
||||
} from '@grafana/api-clients/rtkq/folder/v1beta1';
|
||||
export * from '@grafana/api-clients/rtkq/folder/v1beta1';
|
||||
|
||||
@@ -3,3 +3,6 @@ import { generatedAPI } from '@grafana/api-clients/rtkq/iam/v0alpha1';
|
||||
export const iamAPIv0alpha1 = generatedAPI.enhanceEndpoints({});
|
||||
|
||||
export const { useGetDisplayMappingQuery, useLazyGetDisplayMappingQuery } = iamAPIv0alpha1;
|
||||
|
||||
// eslint-disable-next-line no-barrel-files/no-barrel-files
|
||||
export type { DisplayList } from '@grafana/api-clients/rtkq/iam/v0alpha1';
|
||||
|
||||
@@ -654,7 +654,12 @@ export class BackendSrv implements BackendService {
|
||||
return this.get<DashboardDTO>(`/api/public/dashboards/${uid}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use getFolderByUidFacade from app/api/clients/folder/v1beta1/hooks instead
|
||||
* or manually handle calling legacy vs app platform API based on feature toggles
|
||||
*/
|
||||
getFolderByUid(uid: string, options: FolderRequestOptions = {}) {
|
||||
deprecationWarning('backend_srv', 'getFolderByUid(uid)', 'getFolderByUidFacade(uid)');
|
||||
const queryParams = new URLSearchParams();
|
||||
if (options.withAccessControl) {
|
||||
queryParams.set('accesscontrol', 'true');
|
||||
|
||||
+4
-6
@@ -4,7 +4,7 @@ import { ComponentProps } from 'react';
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { Alert, CodeEditor, ConfirmModal, Stack, useStyles2 } from '@grafana/ui';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { useGetFolderQueryFacade } from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import { getMessageFromError } from 'app/core/utils/errors';
|
||||
import { useAsync } from 'app/features/alerting/unified/hooks/useAsync';
|
||||
import { GrafanaRuleDefinition, RulerGrafanaRuleDTO, RulerRuleDTO } from 'app/types/unified-alerting-dto';
|
||||
@@ -32,6 +32,7 @@ export const ConfirmRestoreDeletedRuleModal = ({
|
||||
onRestoreError,
|
||||
}: ModalProps) => {
|
||||
const [restoreMethod, { error }] = useRestoreDeletedRule();
|
||||
const { data: folder } = useGetFolderQueryFacade(ruleToRestore?.grafana_alert.namespace_uid);
|
||||
|
||||
const title = t('alerting.deleted-rules.restore-modal.title', 'Restore deleted alert rule');
|
||||
const errorTitle = t('alerting.deleted-rules.restore-modal.error', 'Could not restore deleted alert rule');
|
||||
@@ -60,7 +61,7 @@ export const ConfirmRestoreDeletedRuleModal = ({
|
||||
if (!ruleToRestore) {
|
||||
return;
|
||||
}
|
||||
await redirectToRestoreForm(ruleToRestore);
|
||||
await redirectToRestoreForm(ruleToRestore, folder?.title ?? '');
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -141,11 +142,8 @@ export function useRestoreDeletedRule() {
|
||||
});
|
||||
}
|
||||
|
||||
const redirectToRestoreForm = async (ruleToRecover: RulerGrafanaRuleDTO) => {
|
||||
const redirectToRestoreForm = async (ruleToRecover: RulerGrafanaRuleDTO, namespaceName: string) => {
|
||||
let formValues: Partial<RuleFormValues> | undefined;
|
||||
const namespaceName = await backendSrv
|
||||
.getFolderByUid(ruleToRecover.grafana_alert.namespace_uid)
|
||||
.then((folder) => folder.title);
|
||||
|
||||
try {
|
||||
formValues = grafanaRuleDtoToFormValues(ruleToRecover, namespaceName);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import * as folderHooks from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { updateNavModel } from './utils';
|
||||
@@ -7,7 +7,7 @@ describe('utils', () => {
|
||||
it('Should update nav model', async () => {
|
||||
const reduxStore = configureStore();
|
||||
|
||||
jest.spyOn(backendSrv, 'getFolderByUid').mockResolvedValue({
|
||||
jest.spyOn(folderHooks, 'getFolderByUidFacade').mockResolvedValue({
|
||||
id: 1,
|
||||
uid: 'new-folder',
|
||||
title: 'NewFolder',
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { UrlQueryMap, getTimeZone, getDefaultTimeRange, dateMath } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { getFolderByUidFacade } from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import { updateNavIndex } from 'app/core/actions';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { buildNavModel } from 'app/features/folders/state/navModel';
|
||||
import { store } from 'app/store/store';
|
||||
|
||||
export async function updateNavModel(folderUid: string) {
|
||||
try {
|
||||
const folder = await backendSrv.getFolderByUid(folderUid);
|
||||
const folder = await getFolderByUidFacade(folderUid);
|
||||
store.dispatch(updateNavIndex(buildNavModel(folder)));
|
||||
} catch (err) {
|
||||
console.warn('Error fetching parent folder', folderUid, 'for dashboard', err);
|
||||
|
||||
-3
@@ -4,7 +4,6 @@ import { byTestId } from 'testing-library-selector';
|
||||
|
||||
import { PromOptions } from '@grafana/prometheus';
|
||||
import { config, locationService, setPluginLinksHook } from '@grafana/runtime';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import * as ruler from 'app/features/alerting/unified/api/ruler';
|
||||
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
|
||||
import * as alertingAbilities from 'app/features/alerting/unified/hooks/useAbilities';
|
||||
@@ -12,7 +11,6 @@ import { mockAlertRuleApi, setupMswServer } from 'app/features/alerting/unified/
|
||||
import {
|
||||
grantUserPermissions,
|
||||
mockDataSource,
|
||||
mockFolder,
|
||||
mockPromAlert,
|
||||
mockPromAlertingRule,
|
||||
mockRulerAlertingRule,
|
||||
@@ -190,7 +188,6 @@ describe('PanelAlertTabContent', () => {
|
||||
AccessControlAction.AlertingRuleExternalWrite,
|
||||
]);
|
||||
|
||||
jest.spyOn(backendSrv, 'getFolderByUid').mockResolvedValue(mockFolder());
|
||||
setupDataSources(...Object.values(dataSources));
|
||||
|
||||
mocks.rulerBuilderMock.mockReturnValue({
|
||||
|
||||
@@ -89,12 +89,7 @@ describe('UnifiedDashboardAPI', () => {
|
||||
};
|
||||
|
||||
v1Client.getDashboardDTO.mockRejectedValue(new DashboardVersionError('v2beta1', 'Dashboard is V1 format'));
|
||||
v2Client.getDashboardDTO.mockImplementation((params) => {
|
||||
const actualClient = jest.requireActual('./v2').K8sDashboardV2API;
|
||||
const client = new actualClient();
|
||||
return client.getDashboardDTO(params);
|
||||
});
|
||||
mockBackendSrvGet = mockV2Response;
|
||||
v2Client.getDashboardDTO.mockResolvedValue(mockV2Response as DashboardWithAccessInfo<DashboardV2Spec>);
|
||||
const result = await api.getDashboardDTO('123');
|
||||
expect(result).toEqual(mockV2Response);
|
||||
expect(v2Client.getDashboardDTO).toHaveBeenCalledWith('123');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { GrafanaConfig, locationUtil } from '@grafana/data';
|
||||
import * as folderHooks from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { AnnoKeyFolder, AnnoKeyMessage, AnnoReloadOnParamsChange } from 'app/features/apiserver/types';
|
||||
import { DashboardDataDTO } from 'app/types/dashboard';
|
||||
@@ -128,7 +129,7 @@ describe('v1 dashboard API', () => {
|
||||
},
|
||||
});
|
||||
|
||||
jest.spyOn(backendSrv, 'getFolderByUid').mockResolvedValueOnce({
|
||||
jest.spyOn(folderHooks, 'getFolderByUidFacade').mockResolvedValueOnce({
|
||||
id: 1,
|
||||
uid: 'new-folder',
|
||||
title: 'New Folder',
|
||||
@@ -174,7 +175,7 @@ describe('v1 dashboard API', () => {
|
||||
},
|
||||
});
|
||||
jest
|
||||
.spyOn(backendSrv, 'getFolderByUid')
|
||||
.spyOn(folderHooks, 'getFolderByUidFacade')
|
||||
.mockRejectedValueOnce({ message: 'folder not found', status: 'not-found' });
|
||||
|
||||
const api = new K8sDashboardAPI();
|
||||
@@ -186,7 +187,7 @@ describe('v1 dashboard API', () => {
|
||||
...mockDashboardDto,
|
||||
metadata: { ...mockDashboardDto.metadata, annotations: { [AnnoKeyFolder]: 'new-folder' } },
|
||||
});
|
||||
jest.spyOn(backendSrv, 'getFolderByUid').mockRejectedValueOnce({ message: 'folder not found', status: 403 });
|
||||
jest.spyOn(folderHooks, 'getFolderByUidFacade').mockRejectedValueOnce({ message: 'folder not found', status: 403 });
|
||||
|
||||
const api = new K8sDashboardAPI();
|
||||
const dashboardDTO = await api.getDashboardDTO('test');
|
||||
|
||||
@@ -2,7 +2,7 @@ import { locationUtil, UrlQueryMap } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { Status } from '@grafana/schema/src/schema/dashboard/v2';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { getFolderByUidFacade } from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import { getMessageFromError, getStatusFromError } from 'app/core/utils/errors';
|
||||
import { ScopedResourceClient } from 'app/features/apiserver/client';
|
||||
import {
|
||||
@@ -166,7 +166,7 @@ export class K8sDashboardAPI implements DashboardAPI<DashboardDTO, Dashboard> {
|
||||
|
||||
if (dash.metadata.annotations?.[AnnoKeyFolder]) {
|
||||
try {
|
||||
const folder = await backendSrv.getFolderByUid(dash.metadata.annotations[AnnoKeyFolder]);
|
||||
const folder = await getFolderByUidFacade(dash.metadata.annotations[AnnoKeyFolder]);
|
||||
result.meta.folderTitle = folder.title;
|
||||
result.meta.folderUrl = folder.url;
|
||||
result.meta.folderUid = folder.uid;
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
Spec as DashboardV2Spec,
|
||||
defaultSpec as defaultDashboardV2Spec,
|
||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import * as folderHooks from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import {
|
||||
AnnoKeyFolder,
|
||||
AnnoKeyFolderTitle,
|
||||
@@ -101,7 +101,7 @@ describe('v2 dashboard API', () => {
|
||||
},
|
||||
});
|
||||
|
||||
jest.spyOn(backendSrv, 'getFolderByUid').mockResolvedValue({
|
||||
jest.spyOn(folderHooks, 'getFolderByUidFacade').mockResolvedValue({
|
||||
id: 1,
|
||||
uid: 'new-folder',
|
||||
title: 'New Folder',
|
||||
@@ -136,7 +136,7 @@ describe('v2 dashboard API', () => {
|
||||
},
|
||||
});
|
||||
jest
|
||||
.spyOn(backendSrv, 'getFolderByUid')
|
||||
.spyOn(folderHooks, 'getFolderByUidFacade')
|
||||
.mockRejectedValueOnce({ message: 'folder not found', status: 'not-found' });
|
||||
|
||||
const api = new K8sDashboardV2API();
|
||||
@@ -148,7 +148,7 @@ describe('v2 dashboard API', () => {
|
||||
...mockDashboardDto,
|
||||
metadata: { ...mockDashboardDto.metadata, annotations: { [AnnoKeyFolder]: 'new-folder' } },
|
||||
});
|
||||
jest.spyOn(backendSrv, 'getFolderByUid').mockRejectedValueOnce({ message: 'folder not found', status: 403 });
|
||||
jest.spyOn(folderHooks, 'getFolderByUidFacade').mockRejectedValueOnce({ message: 'folder not found', status: 403 });
|
||||
|
||||
const api = new K8sDashboardV2API();
|
||||
const dashboardDTO = await api.getDashboardDTO('test');
|
||||
|
||||
@@ -2,7 +2,7 @@ import { locationUtil } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { Spec as DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2';
|
||||
import { Status } from '@grafana/schema/src/schema/dashboard/v2';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { getFolderByUidFacade } from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import { getMessageFromError, getStatusFromError } from 'app/core/utils/errors';
|
||||
import { ScopedResourceClient } from 'app/features/apiserver/client';
|
||||
import {
|
||||
@@ -59,7 +59,7 @@ export class K8sDashboardV2API
|
||||
// load folder info if available
|
||||
if (dashboard.metadata.annotations && dashboard.metadata.annotations[AnnoKeyFolder]) {
|
||||
try {
|
||||
const folder = await backendSrv.getFolderByUid(dashboard.metadata.annotations[AnnoKeyFolder]);
|
||||
const folder = await getFolderByUidFacade(dashboard.metadata.annotations[AnnoKeyFolder]);
|
||||
dashboard.metadata.annotations[AnnoKeyFolderTitle] = folder.title;
|
||||
dashboard.metadata.annotations[AnnoKeyFolderUrl] = folder.url;
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
|
||||
import { buildNavModel } from '../folders/state/navModel';
|
||||
|
||||
export const loadFolderPage = (uid: string) => {
|
||||
return backendSrv.getFolderByUid(uid, { withAccessControl: true }).then((folder) => {
|
||||
const navModel = buildNavModel(folder);
|
||||
navModel.children![0].active = true;
|
||||
|
||||
return { folder, folderNav: navModel };
|
||||
});
|
||||
};
|
||||
@@ -18,6 +18,7 @@ import { ThunkAction, ThunkDispatch as GenericThunkDispatch } from 'redux-thunk'
|
||||
|
||||
import type { createRootReducer } from 'app/core/reducers/root';
|
||||
import { AppDispatch, RootState } from 'app/store/configureStore';
|
||||
import { dispatch as storeDispatch } from 'app/store/store';
|
||||
|
||||
export type StoreState = ReturnType<ReturnType<typeof createRootReducer>>;
|
||||
|
||||
@@ -41,3 +42,4 @@ export const createAsyncThunk = <Returned, ThunkArg = void, ThunkApiConfig exten
|
||||
createAsyncThunkUntyped<Returned, ThunkArg, ThunkApiConfig>(typePrefix, payloadCreator, options);
|
||||
|
||||
export const addListener = addListenerUntyped as TypedAddListener<RootState, AppDispatch>;
|
||||
export const dispatch: AppDispatch = storeDispatch;
|
||||
|
||||
Reference in New Issue
Block a user