Make sidebar search field work (#3362)

* Make sidebar search field work

Extend the search page to have the ability to react to query parameters. The search in the sidebar now navigates to the search page and passes the query parameter. The search box on the search page is now debounced.

Closes #3341

* Fix sidebar search while the search page is already open
This commit is contained in:
Oliver Sand
2020-11-20 15:14:18 +01:00
committed by GitHub
parent 1550cba47b
commit 475fc0aaa3
11 changed files with 99 additions and 19 deletions
+5 -4
View File
@@ -21,14 +21,15 @@
},
"dependencies": {
"@backstage/core": "^0.3.1",
"@backstage/plugin-catalog": "^0.2.2",
"@backstage/theme": "^0.2.1",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
"@backstage/plugin-catalog": "^0.2.2",
"react-router-dom": "6.0.0-beta.0",
"qs": "^6.9.4",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "6.0.0-beta.0",
"react-use": "^15.3.3"
},
"devDependencies": {
@@ -40,8 +41,8 @@
"@testing-library/user-event": "^12.0.7",
"@types/jest": "^26.0.7",
"@types/node": "^12.0.0",
"msw": "^0.21.2",
"cross-fetch": "^3.0.6"
"cross-fetch": "^3.0.6",
"msw": "^0.21.2"
},
"files": [
"dist"
@@ -13,22 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useState } from 'react';
import { Header, Content, Page } from '@backstage/core';
import { Content, Header, Page, useQueryParamState } from '@backstage/core';
import { Grid } from '@material-ui/core';
import React, { useEffect, useState } from 'react';
import { useDebounce } from 'react-use';
import { SearchBar } from '../SearchBar';
import { SearchResult } from '../SearchResult';
export const SearchPage = () => {
const [searchQuery, setSearchQuery] = useState('');
const [queryString, setQueryString] = useQueryParamState<string>('query');
const [searchQuery, setSearchQuery] = useState(queryString ?? '');
const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault();
setSearchQuery(event.target.value);
};
useEffect(() => setSearchQuery(queryString ?? ''), [queryString]);
useDebounce(
() => {
setQueryString(searchQuery);
},
200,
[searchQuery],
);
const handleClearSearchBar = () => {
setSearchQuery('');
};
@@ -46,7 +56,7 @@ export const SearchPage = () => {
/>
</Grid>
<Grid item xs={12}>
<SearchResult searchQuery={searchQuery.toLowerCase()} />
<SearchResult searchQuery={(queryString ?? '').toLowerCase()} />
</Grid>
</Grid>
</Content>
@@ -0,0 +1,35 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useCallback } from 'react';
import qs from 'qs';
import { useNavigate } from 'react-router-dom';
import { SidebarSearchField } from '@backstage/core';
export const SidebarSearch = () => {
const navigate = useNavigate();
const handleSearch = useCallback(
(query: string): void => {
const queryString = qs.stringify({ query }, { addQueryPrefix: true });
// TODO: Here the url to the search plugin is hardcoded. We need a way to query the route in the future.
// Maybe an API that I can just call from other places?
navigate(`/search${queryString}`);
},
[navigate],
);
return <SidebarSearchField onSearch={handleSearch} />;
};
@@ -0,0 +1,16 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { SidebarSearch } from './SidebarSearch';
+1
View File
@@ -18,3 +18,4 @@ export * from './Filters';
export * from './SearchBar';
export * from './SearchPage';
export * from './SearchResult';
export * from './SidebarSearch';
+1
View File
@@ -14,3 +14,4 @@
* limitations under the License.
*/
export { plugin } from './plugin';
export * from './components';