From 36c090416aa67fcd4a736da5352e55158cca127c Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Thu, 9 Feb 2023 16:31:05 +0000 Subject: [PATCH] Command palette: Enable folder searching (#62663) search folders as well as dashboards in the command palette --- .../commandPalette/CommandPalette.tsx | 45 +++++++++++++------ .../actions/dashboardActions.ts | 39 ++++++++-------- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/public/app/features/commandPalette/CommandPalette.tsx b/public/app/features/commandPalette/CommandPalette.tsx index 66d5b94f472..82036481739 100644 --- a/public/app/features/commandPalette/CommandPalette.tsx +++ b/public/app/features/commandPalette/CommandPalette.tsx @@ -21,7 +21,7 @@ import { t } from 'app/core/internationalization'; import { KBarResults } from './KBarResults'; import { ResultItem } from './ResultItem'; -import { useDashboardResults } from './actions/dashboardActions'; +import { useSearchResults } from './actions/dashboardActions'; import useActions from './actions/useActions'; import { CommandPaletteAction } from './types'; import { useMatches } from './useMatches'; @@ -36,7 +36,7 @@ export function CommandPalette() { const actions = useActions(searchQuery); useRegisterActions(actions, [actions]); - const { dashboardResults, isFetchingDashboardResults } = useDashboardResults(searchQuery, showing); + const { searchResults, isFetchingSearchResults } = useSearchResults(searchQuery, showing); const ref = useRef(null); const { overlayProps } = useOverlay( @@ -58,14 +58,14 @@ export function CommandPalette() {
- {isFetchingDashboardResults ? : } + {isFetchingSearchResults ? : }
- +
@@ -76,24 +76,43 @@ export function CommandPalette() { } interface RenderResultsProps { - dashboardResults: CommandPaletteAction[]; + searchResults: CommandPaletteAction[]; } -const RenderResults = ({ dashboardResults }: RenderResultsProps) => { - const { results, rootActionId } = useMatches(); +const RenderResults = ({ searchResults }: RenderResultsProps) => { + const { results: kbarResults, rootActionId } = useMatches(); const styles = useStyles2(getSearchStyles); const dashboardsSectionTitle = t('command-palette.section.dashboard-search-results', 'Dashboards'); + const foldersSectionTitle = t('command-palette.section.folder-search-results', 'Folders'); // because dashboard search results aren't registered as actions, we need to manually // convert them to ActionImpls before passing them as items to KBarResults const dashboardResultItems = useMemo( - () => dashboardResults.map((dashboard) => new ActionImpl(dashboard, { store: {} })), - [dashboardResults] + () => + searchResults + .filter((item) => item.id.startsWith('go/dashboard')) + .map((dashboard) => new ActionImpl(dashboard, { store: {} })), + [searchResults] + ); + const folderResultItems = useMemo( + () => + searchResults + .filter((item) => item.id.startsWith('go/folder')) + .map((folder) => new ActionImpl(folder, { store: {} })), + [searchResults] ); - const items = useMemo( - () => (dashboardResultItems.length > 0 ? [...results, dashboardsSectionTitle, ...dashboardResultItems] : results), - [results, dashboardsSectionTitle, dashboardResultItems] - ); + const items = useMemo(() => { + const results = [...kbarResults]; + if (folderResultItems.length > 0) { + results.push(foldersSectionTitle); + results.push(...folderResultItems); + } + if (dashboardResultItems.length > 0) { + results.push(dashboardsSectionTitle); + results.push(...dashboardResultItems); + } + return results; + }, [kbarResults, dashboardsSectionTitle, dashboardResultItems, foldersSectionTitle, folderResultItems]); return ( { const recentUids = (await impressionSrv.getDashboardOpened()).slice(0, MAX_RECENT_DASHBOARDS); @@ -44,51 +44,54 @@ export async function getRecentDashboardActions(): Promise { +export async function getSearchResultActions(searchQuery: string): Promise { // Empty strings should not come through to here if (searchQuery.length === 0) { return []; } const data = await getGrafanaSearcher().search({ - kind: ['dashboard'], + kind: ['dashboard', 'folder'], query: searchQuery, limit: MAX_SEARCH_RESULTS, }); - const goToDashboardActions: CommandPaletteAction[] = data.view.map((item) => { - const { url, name } = item; // items are backed by DataFrameView, so must hold the url in a closure + const goToSearchResultActions: CommandPaletteAction[] = data.view.map((item) => { + const { url, name, kind } = item; // items are backed by DataFrameView, so must hold the url in a closure return { - id: `go/dashboard${url}`, + id: `go/${kind}${url}`, name: `${name}`, - section: t('command-palette.section.dashboard-search-results', 'Dashboards'), + section: + kind === 'dashboard' + ? t('command-palette.section.dashboard-search-results', 'Dashboards') + : t('command-palette.section.folder-search-results', 'Folders'), priority: SEARCH_RESULTS_PRORITY, url: locationUtil.stripBaseFromUrl(url), }; }); - return goToDashboardActions; + return goToSearchResultActions; } -export function useDashboardResults(searchQuery: string, isShowing: boolean) { - const [dashboardResults, setDashboardResults] = useState([]); - const [isFetchingDashboardResults, setIsFetchingDashboardResults] = useState(false); +export function useSearchResults(searchQuery: string, isShowing: boolean) { + const [searchResults, setSearchResults] = useState([]); + const [isFetchingSearchResults, setIsFetchingSearchResults] = useState(false); // Hit dashboards API useEffect(() => { if (isShowing && searchQuery.length > 0) { - setIsFetchingDashboardResults(true); - debouncedDashboardSearch(searchQuery).then((resultActions) => { - setDashboardResults(resultActions); - setIsFetchingDashboardResults(false); + setIsFetchingSearchResults(true); + debouncedSearch(searchQuery).then((resultActions) => { + setSearchResults(resultActions); + setIsFetchingSearchResults(false); }); } else { - setDashboardResults([]); + setSearchResults([]); } }, [isShowing, searchQuery]); return { - dashboardResults, - isFetchingDashboardResults, + searchResults, + isFetchingSearchResults, }; }