diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx index 883171532a7..7e53679f84e 100644 --- a/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx +++ b/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx @@ -32,6 +32,7 @@ interface NestedFolderListProps { onFolderSelect: (item: DashboardViewItem) => void; isItemLoaded: (itemIndex: number) => boolean; requestLoadMore: (folderUid: string | undefined) => void; + emptyFolders: Set; } export function NestedFolderList({ @@ -44,6 +45,7 @@ export function NestedFolderList({ onFolderSelect, isItemLoaded, requestLoadMore, + emptyFolders, }: NestedFolderListProps) { const infiniteLoaderRef = useRef(null); const styles = useStyles2(getStyles); @@ -57,8 +59,18 @@ export function NestedFolderList({ onFolderExpand, onFolderSelect, idPrefix, + emptyFolders, }), - [items, focusedItemIndex, foldersAreOpenable, selectedFolder, onFolderExpand, onFolderSelect, idPrefix] + [ + items, + focusedItemIndex, + foldersAreOpenable, + selectedFolder, + onFolderExpand, + onFolderSelect, + idPrefix, + emptyFolders, + ] ); const handleIsItemLoaded = useCallback( @@ -119,8 +131,16 @@ interface RowProps { const SKELETON_WIDTHS = [100, 200, 130, 160, 150]; function Row({ index, style: virtualStyles, data }: RowProps) { - const { items, focusedItemIndex, foldersAreOpenable, selectedFolder, onFolderExpand, onFolderSelect, idPrefix } = - data; + const { + items, + focusedItemIndex, + foldersAreOpenable, + selectedFolder, + onFolderExpand, + onFolderSelect, + idPrefix, + emptyFolders, + } = data; const { item, isOpen, level, parentUID } = items[index]; const rowRef = useRef(null); const labelId = useId(); @@ -203,7 +223,7 @@ function Row({ index, style: virtualStyles, data }: RowProps) {
- {foldersAreOpenable ? ( + {foldersAreOpenable && !emptyFolders.has(item.uid) ? ( { }), folderButtonSpacer: css({ - paddingLeft: theme.spacing(0.5), + paddingLeft: theme.spacing(2.5), }), row: css({ diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx index 826f8ec5002..67c97879c19 100644 --- a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx +++ b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx @@ -111,6 +111,7 @@ export function NestedFolderPicker({ const isBrowsing = Boolean(overlayOpen && !(search && searchResults)); const { + emptyFolders, items: browseFlatTree, isLoading: isBrowseLoading, requestNextPage: fetchFolderPage, @@ -328,7 +329,7 @@ export function NestedFolderPicker({ : null} + prefix={label ? : } placeholder={label ?? t('browse-dashboards.folder-picker.search-placeholder', 'Search folders')} value={search} invalid={invalid} @@ -341,7 +342,6 @@ export function NestedFolderPicker({ aria-owns={overlayId} aria-activedescendant={getDOMId(overlayId, flatTree[focusedItemIndex]?.item.uid)} role="combobox" - suffix={} {...getReferenceProps()} onKeyDown={handleKeyDown} /> @@ -381,6 +381,7 @@ export function NestedFolderPicker({ foldersAreOpenable={!(search && searchResults)} isItemLoaded={isItemLoaded} requestLoadMore={handleLoadMore} + emptyFolders={emptyFolders} />
)} diff --git a/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts b/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts index 60ca40f798e..34d068589c9 100644 --- a/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts +++ b/public/app/core/components/NestedFolderPicker/useFoldersQueryAppPlatform.ts @@ -40,6 +40,9 @@ export function useFoldersQueryAppPlatform({ // Keep a list of all request subscriptions so we can unsubscribe from them when the component is unmounted const requestsRef = useRef([]); + // Set of UIDs for which children were requested but were empty. + const [emptyFolders, setEmptyFolders] = useState>(new Set()); + // Keep a list of selectors for dynamic state selection const [selectors, setSelectors] = useState>>( [] @@ -145,6 +148,14 @@ export function useFoldersQueryAppPlatform({ const childResponse = folderIsOpen && state.responseByParent[name]; if (childResponse) { + // If we finished loading and there are no children add to empty list + if ( + childResponse.data && + childResponse.status !== QueryStatus.pending && + childResponse.data.hits.length === 0 + ) { + setEmptyFolders((prev) => new Set(prev).add(name)); + } const childFlatItems = createFlatList(name, childResponse, level + 1); return [flatItem, ...childFlatItems]; } @@ -168,6 +179,7 @@ export function useFoldersQueryAppPlatform({ }, [state, isBrowsing, openFolders, rootFolderUID, rootFolderItem]); return { + emptyFolders, items: treeList, isLoading: state.isLoading, requestNextPage, diff --git a/public/app/core/components/NestedFolderPicker/useFoldersQueryLegacy.ts b/public/app/core/components/NestedFolderPicker/useFoldersQueryLegacy.ts index fa07abccf31..24eb4008b93 100644 --- a/public/app/core/components/NestedFolderPicker/useFoldersQueryLegacy.ts +++ b/public/app/core/components/NestedFolderPicker/useFoldersQueryLegacy.ts @@ -58,6 +58,9 @@ export function useFoldersQueryLegacy({ // Keep a list of all request subscriptions so we can unsubscribe from them when the component is unmounted const requestsRef = useRef([]); + // Set of UIDs for which children were requested but were empty. + const [emptyFolders, setEmptyFolders] = useState>(new Set()); + // Keep a list of selectors for dynamic state selection const [selectors, setSelectors] = useState< Array> @@ -165,8 +168,15 @@ export function useFoldersQueryLegacy({ }; const childPages = folderIsOpen && state.pagesByParent[item.uid]; + if (childPages) { const childFlatItems = createFlatList(item.uid, childPages, level + 1); + + // If we finished loading and there are no children add to empty list + if (childPages[0] && childPages[0].status !== PENDING_STATUS && childFlatItems.length === 0) { + setEmptyFolders((prev) => new Set(prev).add(item.uid)); + } + return [flatItem, ...childFlatItems]; } @@ -191,6 +201,7 @@ export function useFoldersQueryLegacy({ }, [state, isBrowsing, openFolders, rootFolderUID, rootFolderItem]); return { + emptyFolders, items: treeList, isLoading: state.isLoading, requestNextPage,