[Search] add search api how to guide + search bar custom placeholder (#7535)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
SearchBar component to accept optional placeholder prop
|
||||
@@ -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 });
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user