Frontend brain dump.
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
@@ -10,12 +10,16 @@ Backstage Search is _blah_.
|
||||
|
||||
To get started, you should get familiar with these core concepts:
|
||||
|
||||
TODO: Link these like a real TOC
|
||||
|
||||
- Search Engines
|
||||
- Query Translators
|
||||
- Documents and Indices
|
||||
- Collators
|
||||
- Decorators
|
||||
- The Scheduler
|
||||
- The Search Page
|
||||
- Search Context and Components
|
||||
|
||||
### Search Engines
|
||||
|
||||
@@ -23,8 +27,8 @@ Backstage Search isn't a search engine itself, rather, it provides an interface
|
||||
between your Backstage instance and a Search Engine of your choice. More
|
||||
concretely, a `SearchEngine` is an interface whose concrete implementations
|
||||
facilitate communication with different search engines (like ElasticSearch,
|
||||
Solr, Algolia, etc). This abstraction exists in order to support your
|
||||
organization's needs.
|
||||
Solr, etc). This abstraction exists in order to support your organization's
|
||||
needs.
|
||||
|
||||
Out of the box, Backstage Search comes pre-packaged with an in-memory search
|
||||
engine implementation built on top of Lunr.
|
||||
@@ -39,7 +43,7 @@ search engine.
|
||||
|
||||
Search Engines come pre-packaged with simple translators that do rudimentary
|
||||
transformations of search terms and filters, but you may want to provide your
|
||||
own to help tune seearch results in the context of your organization.
|
||||
own to help tune search results in the context of your organization.
|
||||
|
||||
### Documents and Indices
|
||||
|
||||
@@ -78,11 +82,30 @@ Search chooses to completely rebuild indices on a schedule. Different collators
|
||||
can be configured to refresh at different intervals, depending on how often the
|
||||
source information is updated.
|
||||
|
||||
TODO: There should probably be some front-end concepts here too?
|
||||
### The Search Page
|
||||
|
||||
- Search Page
|
||||
- Search Components
|
||||
- Search Context
|
||||
Search pages are very custom things. Not every Backstage instance will want the
|
||||
same interface! In order to allow you to customize your search experience to
|
||||
your heart's content, the Search Plugin takes care of state management and other
|
||||
search logic for you, but most of the layout of a search page lives in a search
|
||||
page component defined in your Backstage App.
|
||||
|
||||
[Primarily solves for “As an App Integrator, I should know how to add do uments
|
||||
to the search index”]
|
||||
For an example of a simple search page, check [getting started](TODO)
|
||||
|
||||
### Search Context and Components
|
||||
|
||||
A search experience, like a page, is composed of any number of search
|
||||
components, which are all wired up using a search context.
|
||||
|
||||
Each search experience's context consists of details like a search term,
|
||||
filters, types, results, and a page cursor for handling pagination. Different
|
||||
components use this context in different ways, for example the `<SearchBar />`
|
||||
can set the search term, `<SearchFilter />` components can set filters, and
|
||||
search results can be displayed using the `<SearchResult />` component.
|
||||
|
||||
The `<SearchResult />` and `<SearchFilter />` components are special, in that
|
||||
they themselves are extensible. For an example of how to extend these
|
||||
components, [check this out](TODO).
|
||||
|
||||
If you need even more customization, you can use the search context like any
|
||||
other React context to create custom search components of your own.
|
||||
|
||||
@@ -12,9 +12,9 @@ use Search.
|
||||
If you haven't setup Backstage already, start
|
||||
[here](../../getting-started/index.md).
|
||||
|
||||
> If you used `npx @backstage/create-app`, Search may already be present.
|
||||
>
|
||||
> You should skip to [`Customizing Search`](#customizing-search) below.
|
||||
> If you used `npx @backstage/create-app`, and you have a search page defined in
|
||||
> `packages/app/src/components/search`, skip to
|
||||
> [`Customizing Search`](#customizing-search) below.
|
||||
|
||||
## Adding Search to the Frontend
|
||||
|
||||
@@ -24,7 +24,92 @@ cd packages/app
|
||||
yarn add @backstage/plugin-search
|
||||
```
|
||||
|
||||
TODO: Add frontend instructions here.
|
||||
Create a new `packages/app/src/components/search/SearchPage.tsx` file in your
|
||||
Backstage app with the following contents:
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { Content, Header, Page } from '@backstage/core';
|
||||
import { Grid, List, Card, CardContent } from '@material-ui/core';
|
||||
import {
|
||||
SearchBar,
|
||||
SearchResult,
|
||||
DefaultResultListItem,
|
||||
SearchFilter,
|
||||
} from '@backstage/plugin-search';
|
||||
import { CatalogResultListItem } from '@backstage/plugin-catalog';
|
||||
|
||||
export const searchPage = (
|
||||
<Page themeId="home">
|
||||
<Header title="Search" />
|
||||
<Content>
|
||||
<Grid container direction="row">
|
||||
<Grid item xs={12}>
|
||||
<SearchBar />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<SearchFilter.Select
|
||||
name="kind"
|
||||
values={['Component', 'Template']}
|
||||
/>
|
||||
</CardContent>
|
||||
<CardContent>
|
||||
<SearchFilter.Checkbox
|
||||
name="lifecycle"
|
||||
values={['experimental', 'production']}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<SearchResult>
|
||||
{({ results }) => (
|
||||
<List>
|
||||
{results.map(result => {
|
||||
switch (result.type) {
|
||||
case 'software-catalog':
|
||||
return (
|
||||
<CatalogResultListItem
|
||||
key={result.document.location}
|
||||
result={result.document}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<DefaultResultListItem
|
||||
key={result.document.location}
|
||||
result={result.document}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</List>
|
||||
)}
|
||||
</SearchResult>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
```
|
||||
|
||||
Bind the above Search Page to the `/search` route in your
|
||||
`packages/app/src/App.tsx` file, like this:
|
||||
|
||||
```tsx
|
||||
import { SearchPage } from '@backstage/plugin-search';
|
||||
import { searchPage } from './components/search/SearchPage';
|
||||
|
||||
const routes = (
|
||||
<FlatRoutes>
|
||||
<Route path="/search" element={<SearchPage />}>
|
||||
{searchPage}
|
||||
</Route>
|
||||
</FlatRoutes>
|
||||
);
|
||||
```
|
||||
|
||||
## Adding Search to the Backend
|
||||
|
||||
@@ -96,6 +181,75 @@ apiRouter.use('/search', await search(searchEnv));
|
||||
|
||||
## Customizing Search
|
||||
|
||||
### Frontend
|
||||
|
||||
The Search Plugin exposes several default filter types as static properties,
|
||||
including `<SearchFilter.Select />` and `<SearchFilter.Checkbox />`. These allow
|
||||
you to provide values relevant to your Backstage instance that, when selected,
|
||||
get passed to the backend.
|
||||
|
||||
```tsx {2-5,8-11}
|
||||
<CardContent>
|
||||
<SearchFilter.Select
|
||||
name="kind"
|
||||
values={['Component', 'Template']}
|
||||
/>
|
||||
</CardContent>
|
||||
<CardContent>
|
||||
<SearchFilter.Checkbox
|
||||
name="lifecycle"
|
||||
values={['production', 'experimental']}
|
||||
/>
|
||||
</CardContent>
|
||||
```
|
||||
|
||||
If you have advanced filter needs, you can specify your own filter component
|
||||
like this (although contributions are welcome):
|
||||
|
||||
```tsx
|
||||
import { useSearch, SearchFilter } from '@backstage/plugin-search';
|
||||
|
||||
const MyCustomFilter = () => {
|
||||
// Note: filters contain filter data from other filter components. Be sure
|
||||
// not to clobber other filters' data!
|
||||
const { filters, setFilters } = useSearch();
|
||||
|
||||
return (/* ... */);
|
||||
};
|
||||
|
||||
// Which could be rendered like this:
|
||||
<SearchFilter component={MyCustomFilter} />
|
||||
```
|
||||
|
||||
It's good practice for search results to highlight information that was used to
|
||||
return it in the first place! The code below highlights how you might specify a
|
||||
custom result item component, using the `<CatalogResultListItem />` component as
|
||||
an example:
|
||||
|
||||
```tsx {7-13}
|
||||
<SearchResult>
|
||||
{({ results }) => (
|
||||
<List>
|
||||
{results.map(result => {
|
||||
// result.type is the index type defined by the collator.
|
||||
switch (result.type) {
|
||||
case 'software-catalog':
|
||||
return (
|
||||
<CatalogResultListItem
|
||||
key={result.document.location}
|
||||
result={result.document}
|
||||
/>
|
||||
);
|
||||
// ...
|
||||
}
|
||||
})}
|
||||
</List>
|
||||
)}
|
||||
</SearchResult>
|
||||
```
|
||||
|
||||
### Backend
|
||||
|
||||
Backstage Search isn't a search engine itself, rather, it provides an interface
|
||||
between your Backstage instance and a Search Engine of your choice. Currently,
|
||||
we only support one, in-memory search Engine called Lunr. It can be instantiated
|
||||
@@ -139,17 +293,3 @@ indexBuilder.addCollator({
|
||||
collator: new DefaultCatalogCollator({ discovery }),
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
[Primarily solves for “As an App Integrator, I should be able to install out-of
|
||||
the-box Search”]
|
||||
|
||||
Backend: Different for new Backstage instances (created via create-app) vs.
|
||||
people enabling search on existing Backstage instances (see catalog install for
|
||||
example).
|
||||
|
||||
Frontend: Search Page Route…? Customizing result components…?
|
||||
|
||||
Conceptually… What’s the difference between “out-of-the-box” or “basic” and the
|
||||
recommended deployment (which will come)
|
||||
|
||||
Reference in New Issue
Block a user