From 69e5a2bdf923cad0ab9d31a98625a4fc968a3139 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Mon, 24 Apr 2023 16:32:04 +0100 Subject: [PATCH] NestedFolders: Basic search view (#67093) * First stab and reusing SearchView for new Browse Dashboards * NestedFolders: Basic SearchView * last bits of cleanup --- .../BrowseDashboardsPage.tsx | 2 +- .../components/SearchView.tsx | 92 +++++++++++++++++-- .../browse-dashboards/state/reducers.ts | 5 +- .../app/features/browse-dashboards/types.ts | 4 +- 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx b/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx index dc6fe30d9c9..976df59e66b 100644 --- a/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx +++ b/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx @@ -50,7 +50,7 @@ const BrowseDashboardsPage = memo(({ match, location }: Props) => { {({ width, height }) => searchState.query ? ( - + ) : ( ) diff --git a/public/app/features/browse-dashboards/components/SearchView.tsx b/public/app/features/browse-dashboards/components/SearchView.tsx index b789d99a6e9..481fc7926b0 100644 --- a/public/app/features/browse-dashboards/components/SearchView.tsx +++ b/public/app/features/browse-dashboards/components/SearchView.tsx @@ -1,17 +1,91 @@ -import React from 'react'; +import React, { useCallback, useEffect } from 'react'; -import { parseRouteParams } from 'app/features/search/utils'; +import { Spinner } from '@grafana/ui'; +import { useKeyNavigationListener } from 'app/features/search/hooks/useSearchKeyboardSelection'; +import { SearchResultsProps, SearchResultsTable } from 'app/features/search/page/components/SearchResultsTable'; +import { getSearchStateManager } from 'app/features/search/state/SearchStateManager'; +import { DashboardViewItemKind } from 'app/features/search/types'; +import { useDispatch, useSelector } from 'app/types'; + +import { setItemSelectionState } from '../state'; interface SearchViewProps { - searchState: ReturnType; + height: number; + width: number; + folderUID: string | undefined; } -export function SearchView({ searchState }: SearchViewProps) { - return ( -
-

SearchView

+export function SearchView({ folderUID, width, height }: SearchViewProps) { + const dispatch = useDispatch(); + const selectedItems = useSelector((wholeState) => wholeState.browseDashboards.selectedItems); -
{JSON.stringify(searchState, null, 2)}
-
+ const { keyboardEvents } = useKeyNavigationListener(); + + const stateManager = getSearchStateManager(); + useEffect(() => stateManager.initStateFromUrl(folderUID), [folderUID, stateManager]); + + const state = stateManager.useState(); + const value = state.result; + + const selectionChecker = useCallback( + (kind: string | undefined, uid: string): boolean => { + if (!kind || kind === '*') { + return false; + } + + return selectedItems[assertDashboardViewItemKind(kind)][uid] ?? false; + }, + [selectedItems] ); + + const clearSelection = useCallback(() => { + console.log('TODO: clearSelection'); + }, []); + + const handleItemSelectionChange = useCallback( + (kind: string, uid: string) => { + const newIsSelected = !selectionChecker(kind, uid); + + dispatch( + setItemSelectionState({ item: { kind: assertDashboardViewItemKind(kind), uid }, isSelected: newIsSelected }) + ); + }, + [selectionChecker, dispatch] + ); + + if (!value) { + return ( +
+ +
+ ); + } + + const props: SearchResultsProps = { + response: value, + selection: selectionChecker, + selectionToggle: handleItemSelectionChange, + clearSelection, + width: width, + height: height, + onTagSelected: stateManager.onAddTag, + keyboardEvents, + onDatasourceChange: state.datasource ? stateManager.onDatasourceChange : undefined, + onClickItem: stateManager.onSearchItemClicked, + }; + + return ; +} + +function assertDashboardViewItemKind(kind: string): DashboardViewItemKind { + switch (kind) { + case 'folder': + return 'folder'; + case 'dashboard': + return 'dashboard'; + case 'panel': + return 'panel'; + } + + throw new Error('Unsupported kind' + kind); } diff --git a/public/app/features/browse-dashboards/state/reducers.ts b/public/app/features/browse-dashboards/state/reducers.ts index 85b75ca675d..5d6f6674163 100644 --- a/public/app/features/browse-dashboards/state/reducers.ts +++ b/public/app/features/browse-dashboards/state/reducers.ts @@ -38,7 +38,10 @@ export function setFolderOpenState( export function setItemSelectionState( state: BrowseDashboardsState, - action: PayloadAction<{ item: DashboardViewItem; isSelected: boolean }> + + // SearchView doesn't use DashboardViewItemKind (yet), so we pick just the specific properties + // we're interested in + action: PayloadAction<{ item: Pick; isSelected: boolean }> ) { const { item, isSelected } = action.payload; diff --git a/public/app/features/browse-dashboards/types.ts b/public/app/features/browse-dashboards/types.ts index 499927f979f..e3b08f17d6c 100644 --- a/public/app/features/browse-dashboards/types.ts +++ b/public/app/features/browse-dashboards/types.ts @@ -1,5 +1,7 @@ import { DashboardViewItem as DashboardViewItem, DashboardViewItemKind } from 'app/features/search/types'; +export type DashboardTreeSelection = Record>; + export interface BrowseDashboardsState { rootItems: DashboardViewItem[]; childrenByParentUID: Record; @@ -22,6 +24,4 @@ export interface DashboardsTreeItem>; - export const INDENT_AMOUNT_CSS_VAR = '--dashboards-tree-indentation';