Search: Fixes searching by current folder when opened by clicking dashboard folder name (#57716)

* Search: Read from url on mount no on app boot

* Fixed tests

* Remove unused type
This commit is contained in:
Torkel Ödegaard 2022-11-01 10:11:42 +01:00 committed by GitHub
parent 1f7c84f125
commit 3991be4c1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 23 deletions

View File

@ -349,7 +349,7 @@ export const DashNav = React.memo<Props>((props) => {
// this ensures the component rerenders when the location changes
const location = useLocation();
const titleHref = locationUtil.getUrlForPartial(location, { search: 'open' });
const parentHref = locationUtil.getUrlForPartial(location, { search: 'open', folder: 'current' });
const parentHref = locationUtil.getUrlForPartial(location, { search: 'open', query: 'folder:current' });
const onGoBack = isFullscreen ? onClose : undefined;
if (config.featureToggles.topnav) {

View File

@ -1,5 +1,5 @@
import { debounce } from 'lodash';
import { FormEvent } from 'react';
import { FormEvent, useEffect } from 'react';
import { SelectableValue } from '@grafana/data';
import { locationService } from '@grafana/runtime';
@ -16,6 +16,7 @@ import {
clearFilters,
toggleSort,
layoutChange,
initStateFromUrl,
} from '../reducers/searchQueryReducer';
import { DashboardQuery, SearchLayout } from '../types';
import { hasFilters } from '../utils';
@ -26,6 +27,10 @@ export const useSearchQuery = (defaults: Partial<DashboardQuery>) => {
const query = useSelector((state) => state.searchQuery);
const dispatch = useDispatch();
useEffect(() => {
dispatch(initStateFromUrl(locationService.getSearchObject()));
}, [dispatch]);
const onQueryChange = (query: string) => {
dispatch(queryChange(query));
updateLocation({ query });

View File

@ -7,11 +7,10 @@ import { Observable } from 'rxjs';
import { ArrayVector, DataFrame, DataFrameView, FieldType } from '@grafana/data';
import { config } from '@grafana/runtime';
import { StoreState } from 'app/types';
import { defaultQuery } from '../../reducers/searchQueryReducer';
import { initialState } from '../../reducers/searchQueryReducer';
import { DashboardQueryResult, getGrafanaSearcher, QueryResponse } from '../../service';
import { DashboardSearchItemType, SearchLayout } from '../../types';
import { DashboardQuery, DashboardSearchItemType, SearchLayout } from '../../types';
import { SearchView, SearchViewProps } from './SearchView';
@ -29,7 +28,7 @@ jest.mock('@grafana/runtime', () => {
};
});
const setup = (propOverrides?: Partial<SearchViewProps>, storeOverrides?: Partial<StoreState>) => {
const setup = (propOverrides?: Partial<SearchViewProps>, storeOverrides?: Partial<DashboardQuery>) => {
const props: SearchViewProps = {
showManage: false,
includePanels: false,
@ -39,7 +38,7 @@ const setup = (propOverrides?: Partial<SearchViewProps>, storeOverrides?: Partia
};
const mockStore = configureMockStore();
const store = mockStore({ searchQuery: defaultQuery, ...storeOverrides });
const store = mockStore({ searchQuery: { ...initialState, ...storeOverrides } });
render(
<Provider store={store}>
<SearchView {...props} />
@ -75,22 +74,21 @@ describe('SearchView', () => {
beforeEach(() => {
config.featureToggles.panelTitleSearch = false;
defaultQuery.layout = SearchLayout.Folders;
});
it('does not show checkboxes or manage actions if showManage is false', async () => {
setup();
setup({}, { layout: SearchLayout.Folders });
await waitFor(() => expect(screen.queryAllByRole('checkbox')).toHaveLength(0));
expect(screen.queryByTestId('manage-actions')).not.toBeInTheDocument();
});
it('shows checkboxes if showManage is true', async () => {
setup({ showManage: true });
setup({ showManage: true }, { layout: SearchLayout.Folders });
await waitFor(() => expect(screen.queryAllByRole('checkbox')).toHaveLength(2));
});
it('shows the manage actions if show manage is true and the user clicked a checkbox', async () => {
setup({ showManage: true });
setup({ showManage: true }, { layout: SearchLayout.Folders });
await waitFor(() => userEvent.click(screen.getAllByRole('checkbox')[0]));
expect(screen.queryByTestId('manage-actions')).toBeInTheDocument();
@ -103,10 +101,8 @@ describe('SearchView', () => {
view: new DataFrameView<DashboardQueryResult>({ fields: [], length: 0 }),
});
setup(undefined, {
searchQuery: {
...defaultQuery,
query: 'asdfasdfasdf',
},
query: 'asdfasdfasdf',
layout: SearchLayout.Folders,
});
await waitFor(() => expect(screen.queryByText('No results found for your query.')).toBeInTheDocument());
expect(screen.getByRole('button', { name: 'Clear search and filters' })).toBeInTheDocument();
@ -115,15 +111,15 @@ describe('SearchView', () => {
describe('include panels', () => {
it('should be enabled when layout is list', async () => {
config.featureToggles.panelTitleSearch = true;
defaultQuery.layout = SearchLayout.List;
setup();
setup({}, { layout: SearchLayout.List });
await waitFor(() => expect(screen.getByLabelText(/include panels/i)).toBeInTheDocument());
expect(screen.getByTestId('include-panels')).toBeEnabled();
});
it('should be disabled when layout is folder', async () => {
config.featureToggles.panelTitleSearch = true;
setup();
setup({}, { layout: SearchLayout.Folders });
await waitFor(() => expect(screen.getByLabelText(/include panels/i)).toBeInTheDocument());
expect(screen.getByTestId('include-panels')).toBeDisabled();

View File

@ -1,17 +1,17 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { SelectableValue } from '@grafana/data';
import { SelectableValue, UrlQueryMap } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { SEARCH_SELECTED_LAYOUT } from '../constants';
import { DashboardQuery, SearchQueryParams, SearchLayout } from '../types';
import { DashboardQuery, SearchLayout, SearchQueryParams } from '../types';
import { parseRouteParams } from '../utils';
export const defaultQuery: DashboardQuery = {
export const initialState: DashboardQuery = {
query: '',
tag: [],
starred: false,
sort: null,
starred: false,
layout: SearchLayout.Folders,
prevSort: null,
};
@ -25,8 +25,8 @@ export const defaultQueryParams: SearchQueryParams = {
};
const queryParams = parseRouteParams(locationService.getSearchObject());
const initialState = { ...defaultQuery, ...queryParams };
const selectedLayout = localStorage.getItem(SEARCH_SELECTED_LAYOUT) as SearchLayout;
if (!queryParams.layout?.length && selectedLayout?.length) {
initialState.layout = selectedLayout;
}
@ -35,6 +35,10 @@ const searchQuerySlice = createSlice({
name: 'searchQuery',
initialState,
reducers: {
initStateFromUrl(state, action: PayloadAction<UrlQueryMap>) {
const queryParams = parseRouteParams(action.payload);
Object.assign(state, queryParams);
},
queryChange: (state, action: PayloadAction<string>) => {
state.query = action.payload;
},
@ -99,6 +103,7 @@ export const {
clearFilters,
toggleSort,
layoutChange,
initStateFromUrl,
} = searchQuerySlice.actions;
export const searchQueryReducer = searchQuerySlice.reducer;