[Search] add search api how to guide + search bar custom placeholder (#7535)

This commit is contained in:
Emma Indal
2021-10-11 21:55:42 +02:00
committed by GitHub
parent a9564f20a9
commit 56bd537256
8 changed files with 105 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search': patch
---
SearchBar component to accept optional placeholder prop
+46
View File
@@ -0,0 +1,46 @@
---
id: how-to-guides
title: Search "HOW TO" guides
sidebar_label: "HOW TO" guides
description: Search "HOW TO" guides
---
## How to implement your own Search API
The Search plugin provides implementation of one primary API by default: the
[SearchApi](https://github.com/backstage/backstage/blob/db2666b980853c281b8fe77905d7639c5d255f13/plugins/search/src/apis.ts#L35),
which is responsible for talking to the search-backend to query search results.
There may be occasions where you need to implement this API yourself, to
customize it to your own needs - for example if you have your own search backend
that you want to talk to. The purpose of this guide is to walk you through how
to do that in two steps.
1. Implement the `SearchApi`
[interface](https://github.com/backstage/backstage/blob/db2666b980853c281b8fe77905d7639c5d255f13/plugins/search/src/apis.ts#L31)
according to your needs.
```typescript
export class SearchClient implements SearchApi {
// your implementation
}
```
2. Override the API ref `searchApiRef` with your new implemented API in the
`App.tsx` using `ApiFactories`.
[Read more about App APIs](https://backstage.io/docs/api/utility-apis#app-apis).
```typescript
const app = createApp({
apis: [
// SearchApi
createApiFactory({
api: searchApiRef,
deps: { discovery: discoveryApiRef },
factory({ discovery }) {
return new SearchClient({ discoveryApi: discovery });
},
}),
],
});
```
+2 -1
View File
@@ -90,7 +90,8 @@
"features/search/getting-started",
"features/search/concepts",
"features/search/architecture",
"features/search/search-engines"
"features/search/search-engines",
"features/search/how-to-guides"
]
},
{
+1
View File
@@ -68,6 +68,7 @@ nav:
- Concepts: 'features/search/concepts.md'
- Search Architecture: 'features/search/architecture.md'
- Search Engines: 'features/search/search-engines.md'
- HOW TO guides: 'features/search/how-to-guides.md'
- TechDocs:
- Overview: 'features/techdocs/README.md'
- Getting Started: 'features/techdocs/getting-started.md'
+7 -1
View File
@@ -79,7 +79,11 @@ export const searchApiRef: ApiRef<SearchApi>;
// Warning: (ae-missing-release-tag) "SearchBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const SearchBar: ({ className, debounceTime }: Props) => JSX.Element;
export const SearchBar: ({
className,
debounceTime,
placeholder,
}: Props) => JSX.Element;
// Warning: (ae-missing-release-tag) "SearchBarNext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -87,9 +91,11 @@ export const SearchBar: ({ className, debounceTime }: Props) => JSX.Element;
export const SearchBarNext: ({
className,
debounceTime,
placeholder,
}: {
className?: string | undefined;
debounceTime?: number | undefined;
placeholder?: string | undefined;
}) => JSX.Element;
// Warning: (ae-missing-release-tag) "SearchContextProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -45,3 +45,20 @@ export const Default = () => {
</MemoryRouter>
);
};
export const CustomPlaceholder = () => {
return (
<MemoryRouter>
{/* @ts-ignore (defaultValue requires more than what is used here) */}
<SearchContext.Provider value={defaultValue}>
<Grid container direction="row">
<Grid item xs={12}>
<Paper style={{ padding: '8px 0' }}>
<SearchBar placeholder="This is a custom placeholder" />
</Paper>
</Grid>
</Grid>
</SearchContext.Provider>
</MemoryRouter>
);
};
@@ -65,6 +65,26 @@ describe('SearchBar', () => {
await waitFor(() => {
expect(screen.getByRole('textbox', { name })).toBeInTheDocument();
expect(
screen.getByPlaceholderText('Search in Mock title'),
).toBeInTheDocument();
});
});
it('Renders with custom placeholder', async () => {
render(
<ApiProvider apis={apiRegistry}>
<SearchContextProvider initialState={{ ...initialState }}>
<SearchBar placeholder="This is a custom placeholder" />
</SearchContextProvider>
,
</ApiProvider>,
);
await waitFor(() => {
expect(
screen.getByPlaceholderText('This is a custom placeholder'),
).toBeInTheDocument();
});
});
@@ -89,9 +89,14 @@ export const SearchBarBase = ({
type Props = {
className?: string;
debounceTime?: number;
placeholder?: string;
};
export const SearchBar = ({ className, debounceTime = 0 }: Props) => {
export const SearchBar = ({
className,
debounceTime = 0,
placeholder,
}: Props) => {
const { term, setTerm } = useSearch();
const [value, setValue] = useState<string>(term);
@@ -113,6 +118,7 @@ export const SearchBar = ({ className, debounceTime = 0 }: Props) => {
value={value}
onChange={handleQuery}
onClear={handleClear}
placeholder={placeholder}
/>
);
};