FolderPicker: Allow customizing root item display (#110319)
FolderPicker: Allow customize root item display item
This commit is contained in:
@@ -39,6 +39,9 @@ export interface NestedFolderPickerProps {
|
||||
/* Start tree from this folder instead of root */
|
||||
rootFolderUID?: string;
|
||||
|
||||
/* Custom root folder item, default is "Dashboards" */
|
||||
rootFolderItem?: DashboardsTreeItem;
|
||||
|
||||
/* Show folders matching this permission, mainly used to also show folders user can view. Defaults to showing only folders user has Edit */
|
||||
permission?: 'view' | 'edit';
|
||||
|
||||
@@ -73,6 +76,7 @@ export function NestedFolderPicker({
|
||||
clearable = false,
|
||||
excludeUIDs,
|
||||
rootFolderUID,
|
||||
rootFolderItem,
|
||||
permission = 'edit',
|
||||
onChange,
|
||||
id,
|
||||
@@ -110,7 +114,13 @@ export function NestedFolderPicker({
|
||||
items: browseFlatTree,
|
||||
isLoading: isBrowseLoading,
|
||||
requestNextPage: fetchFolderPage,
|
||||
} = useFoldersQuery(isBrowsing, foldersOpenState, permissionLevel, rootFolderUID);
|
||||
} = useFoldersQuery({
|
||||
isBrowsing,
|
||||
openFolders: foldersOpenState,
|
||||
permission: permissionLevel,
|
||||
rootFolderUID,
|
||||
rootFolderItem,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!search) {
|
||||
|
||||
@@ -5,11 +5,12 @@ import * as runtime from '@grafana/runtime';
|
||||
import { setupMockServer } from '@grafana/test-utils/server';
|
||||
import { getFolderFixtures } from '@grafana/test-utils/unstable';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { ManagerKind } from 'app/features/apiserver/types';
|
||||
|
||||
import { DashboardViewItem } from '../../../features/search/types';
|
||||
|
||||
import { useFoldersQuery } from './useFoldersQuery';
|
||||
import { getRootFolderItem } from './utils';
|
||||
import { getCustomRootFolderItem, getRootFolderItem } from './utils';
|
||||
|
||||
const [_, { folderA, folderB, folderC }] = getFolderFixtures();
|
||||
|
||||
@@ -47,11 +48,42 @@ describe('useFoldersQuery', () => {
|
||||
|
||||
expect(sortedItemTitles).toEqual(expectedTitles);
|
||||
});
|
||||
|
||||
it('uses custom root folder display name when rootFolderItem is provided', async () => {
|
||||
runtime.config.featureToggles.foldersAppPlatformAPI = featureToggleState;
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useFoldersQuery({
|
||||
isBrowsing: true,
|
||||
openFolders: {},
|
||||
rootFolderItem: getCustomRootFolderItem({
|
||||
title: 'Test Repo',
|
||||
managedBy: ManagerKind.Repo,
|
||||
}),
|
||||
}),
|
||||
{ wrapper }
|
||||
);
|
||||
|
||||
// Test that root folder item uses the custom display name
|
||||
expect(result.current.items[0]).toEqual(
|
||||
getCustomRootFolderItem({
|
||||
title: 'Test Repo',
|
||||
managedBy: ManagerKind.Repo,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function testFn() {
|
||||
const { result } = renderHook(() => useFoldersQuery(true, {}), { wrapper });
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useFoldersQuery({
|
||||
isBrowsing: true,
|
||||
openFolders: {},
|
||||
}),
|
||||
{ wrapper }
|
||||
);
|
||||
|
||||
expect(result.current.items[0]).toEqual(getRootFolderItem());
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
import { DashboardsTreeItem } from 'app/features/browse-dashboards/types';
|
||||
import { PermissionLevelString } from 'app/types/acl';
|
||||
|
||||
import { useFoldersQueryAppPlatform } from './useFoldersQueryAppPlatform';
|
||||
import { useFoldersQueryLegacy } from './useFoldersQueryLegacy';
|
||||
|
||||
export function useFoldersQuery(
|
||||
isBrowsing: boolean,
|
||||
openFolders: Record<string, boolean>,
|
||||
permission?: PermissionLevelString,
|
||||
export interface UseFoldersQueryProps {
|
||||
isBrowsing: boolean;
|
||||
openFolders: Record<string, boolean>;
|
||||
permission?: PermissionLevelString;
|
||||
rootFolderUID?: string;
|
||||
rootFolderItem?: DashboardsTreeItem;
|
||||
}
|
||||
|
||||
export function useFoldersQuery({
|
||||
isBrowsing,
|
||||
openFolders,
|
||||
permission,
|
||||
/* Start tree from this folder instead of root */
|
||||
rootFolderUID?: string
|
||||
) {
|
||||
const resultLegacy = useFoldersQueryLegacy(isBrowsing, openFolders, permission, rootFolderUID);
|
||||
const resultAppPlatform = useFoldersQueryAppPlatform(isBrowsing, openFolders, rootFolderUID);
|
||||
rootFolderUID,
|
||||
rootFolderItem,
|
||||
}: UseFoldersQueryProps) {
|
||||
const resultLegacy = useFoldersQueryLegacy({ isBrowsing, openFolders, permission, rootFolderUID, rootFolderItem });
|
||||
const resultAppPlatform = useFoldersQueryAppPlatform({ isBrowsing, openFolders, rootFolderUID, rootFolderItem });
|
||||
|
||||
// Running the hooks themselves don't have any side effects, so we can just conditionally use one or the other
|
||||
// requestNextPage function from the result
|
||||
|
||||
@@ -10,6 +10,7 @@ import { AnnoKeyManagerKind, ManagerKind } from '../../../features/apiserver/typ
|
||||
import { PAGE_SIZE } from '../../../features/browse-dashboards/api/services';
|
||||
import { getPaginationPlaceholders } from '../../../features/browse-dashboards/state/utils';
|
||||
|
||||
import { UseFoldersQueryProps } from './useFoldersQuery';
|
||||
import { getRootFolderItem } from './utils';
|
||||
|
||||
type GetFolderChildrenQuery = ReturnType<ReturnType<typeof dashboardAPIv0alpha1.endpoints.getSearch.select>>;
|
||||
@@ -25,12 +26,15 @@ const collator = new Intl.Collator();
|
||||
* This version uses the getFolderChildren API from the folder v1beta1 API. Compared to legacy API, the v1beta1 API
|
||||
* does not have pagination at the moment.
|
||||
*/
|
||||
export function useFoldersQueryAppPlatform(
|
||||
isBrowsing: boolean,
|
||||
openFolders: Record<string, boolean>,
|
||||
|
||||
type Props = Omit<UseFoldersQueryProps, 'permission'>;
|
||||
export function useFoldersQueryAppPlatform({
|
||||
isBrowsing,
|
||||
openFolders,
|
||||
/* rootFolderUID: configure which folder to start browsing from */
|
||||
rootFolderUID?: string
|
||||
) {
|
||||
rootFolderUID,
|
||||
rootFolderItem,
|
||||
}: Props) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Keep a list of all request subscriptions so we can unsubscribe from them when the component is unmounted
|
||||
@@ -157,10 +161,10 @@ export function useFoldersQueryAppPlatform(
|
||||
|
||||
const startingToken = rootFolderUID ?? rootFolderToken;
|
||||
const rootFlatTree = createFlatList(startingToken, state.responseByParent[startingToken], 1);
|
||||
rootFlatTree.unshift(getRootFolderItem());
|
||||
rootFlatTree.unshift(rootFolderItem || getRootFolderItem());
|
||||
|
||||
return rootFlatTree;
|
||||
}, [state, isBrowsing, openFolders, rootFolderUID]);
|
||||
}, [state, isBrowsing, openFolders, rootFolderUID, rootFolderItem]);
|
||||
|
||||
return {
|
||||
items: treeList,
|
||||
|
||||
@@ -7,10 +7,10 @@ import { ListFolderQueryArgs, browseDashboardsAPI } from 'app/features/browse-da
|
||||
import { PAGE_SIZE } from 'app/features/browse-dashboards/api/services';
|
||||
import { getPaginationPlaceholders } from 'app/features/browse-dashboards/state/utils';
|
||||
import { DashboardViewItemWithUIItems, DashboardsTreeItem } from 'app/features/browse-dashboards/types';
|
||||
import { PermissionLevelString } from 'app/types/acl';
|
||||
import { FolderListItemDTO } from 'app/types/folders';
|
||||
import { useDispatch, useSelector } from 'app/types/store';
|
||||
|
||||
import { UseFoldersQueryProps } from './useFoldersQuery';
|
||||
import { getRootFolderItem } from './utils';
|
||||
|
||||
type ListFoldersQuery = ReturnType<ReturnType<typeof browseDashboardsAPI.endpoints.listFolders.select>>;
|
||||
@@ -45,13 +45,14 @@ function getPagesLoadStatus(pages: ListFoldersQuery[]): [boolean, number | undef
|
||||
/**
|
||||
* Returns a loaded folder hierarchy as a flat list and a function to load more pages.
|
||||
*/
|
||||
export function useFoldersQueryLegacy(
|
||||
isBrowsing: boolean,
|
||||
openFolders: Record<string, boolean>,
|
||||
permission?: PermissionLevelString,
|
||||
export function useFoldersQueryLegacy({
|
||||
isBrowsing,
|
||||
openFolders,
|
||||
permission,
|
||||
/* rootFolderUID: configure which folder to start browsing from */
|
||||
rootFolderUID?: string
|
||||
) {
|
||||
rootFolderUID,
|
||||
rootFolderItem,
|
||||
}: UseFoldersQueryProps) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Keep a list of all request subscriptions so we can unsubscribe from them when the component is unmounted
|
||||
@@ -183,10 +184,10 @@ export function useFoldersQueryLegacy(
|
||||
const startingPages = rootFolderUID ? state.pagesByParent[rootFolderUID] : state.rootPages;
|
||||
|
||||
const rootFlatTree = createFlatList(rootFolderUID ?? undefined, startingPages ?? [], 1);
|
||||
rootFlatTree.unshift(getRootFolderItem());
|
||||
rootFlatTree.unshift(rootFolderItem || getRootFolderItem());
|
||||
|
||||
return rootFlatTree;
|
||||
}, [state, isBrowsing, openFolders, rootFolderUID]);
|
||||
}, [state, isBrowsing, openFolders, rootFolderUID, rootFolderItem]);
|
||||
|
||||
return {
|
||||
items: treeList,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { t } from '@grafana/i18n';
|
||||
import { ManagerKind } from 'app/features/apiserver/types';
|
||||
import { DashboardsTreeItem } from 'app/features/browse-dashboards/types';
|
||||
|
||||
export const getRootFolderItem = () => ({
|
||||
export const getRootFolderItem = (): DashboardsTreeItem => ({
|
||||
isOpen: true,
|
||||
level: 0,
|
||||
item: {
|
||||
@@ -9,3 +11,22 @@ export const getRootFolderItem = () => ({
|
||||
uid: '',
|
||||
},
|
||||
});
|
||||
|
||||
export const getCustomRootFolderItem = ({
|
||||
title,
|
||||
managedBy,
|
||||
uid,
|
||||
}: {
|
||||
title: string;
|
||||
managedBy?: ManagerKind;
|
||||
uid?: string;
|
||||
}): DashboardsTreeItem => ({
|
||||
isOpen: true,
|
||||
level: 0,
|
||||
item: {
|
||||
kind: 'folder' as const,
|
||||
title,
|
||||
uid: uid || '',
|
||||
managedBy,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user