From 6107616ad8d4c0e6c9370f767dec0c592d9ed383 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Thu, 26 May 2022 17:24:01 +0200 Subject: [PATCH 1/3] Adding a guide for integrating search into existing plugins. Signed-off-by: Eric Peterson --- .../features/search/search-for-plugin-devs.md | 187 ++++++++++++++++++ microsite/sidebars.json | 3 +- 2 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 docs/features/search/search-for-plugin-devs.md diff --git a/docs/features/search/search-for-plugin-devs.md b/docs/features/search/search-for-plugin-devs.md new file mode 100644 index 0000000000..d96b05c6c5 --- /dev/null +++ b/docs/features/search/search-for-plugin-devs.md @@ -0,0 +1,187 @@ +--- +id: for-plugin-devs +title: Search for Plugin Developers +description: How to integrate search into a Backstage plugin +--- + +The Backstage Search Platform was designed to give plugin developers the APIs +and interfaces needed to offer search experiences within their plugins, while +abstracting away (and instead empowering application integrators to choose) the +specific underlying search technologies. + +On this page, you'll find concepts, guides, and recipes for how to leverage the +Backstage Search Platform in your plugin. + +## Providing data to the search platform + +> A guide on how to create collators is coming soon! + +## Building a search experience into your plugin + +While the core Search plugin offers components and extensions that empower app +integrators to compose a global search experience, you may find that you want a +narrower search experience just within your plugin. This could be as literal as +an autocomplete-style search bar focused on documents provided by your plugin, +or as abstract as a widget that presents a list of links that relate in some +way to something else on the page. + +### Concepts + +Knowing these high-level concepts will help you as you craft your in-plugin +search experience. + +- All search experiences must be wrapped in a ``, which + is provided by `@backstage/plugin-search-react`. This context keeps track + of state necessary to perform search queries and display any results. As + inputs to the query are updated (e.g. a `term` or `filter` values), the + updated query is executed and `results` are refreshed. +- The aforementioned state can be modified and/or consumed via the + `useSearch()` hook, also exported by `@backstage/plugin-search-react`. +- For more literal search experiences, reusable components are available + to import and compose into a cohesive experience in your plugin (e.g. + `` or ``). You can see all such + components in [Backstage's storybook](https://backstage.io/storybook/?path=/story/plugins-search-searchbar--default). + +### Recipes + +#### Improved "404" page experience + +Imagine you have a plugin that allows users to manage _widgets_. Perhaps they +can be viewed at a URL like `backstage.example.biz/widgets/{widgetName}`. +At some point, a widget is renamed, and links to that widget's page from +chat systems, wikis, or browser bookmarks become stale, resulting in errors or +404s. + +What if instead of showing a broken page or the generic "looks like someone +dropped the mic" 404 page, you showed a list of possibly related widgets? + +```javascript +import { Link } from '@backstage/core-components'; +import { SearchResult } from '@backstage/plugin-search'; +import { SearchContextProvider } from '@backstage/plugin-search-react'; + +export const Widget404Page = ({ widgetName }) => { + // Supplying this to runs a pre-filtered search with + // the given widgetName as the search term, focused on search result of type + // "widget" with no other filters. + const preFiltered = { + term: widgetName, + types: ['widget'], + filters: {}, + }; + + return ( + + {/* The component allows us to iterate through results and + display them in whatever way fits best! */} + + {({ results }) => ( + {results.map(({ document }) => ( + + {document.title} + + ))} + )} + + + ); +); +``` + +Not all search experiences require user input! As you can see, it's possible to +leverage the Backstage Search Platform's frontend framework without necessarily +giving users input controls. + +#### Simple search page + +Of course, it's also possible to provide a more fully featured search +experience in your plugin. The simplest way is to leverage reusable components +provided by the `@backstage/plugin-search` package, like this: + +```javascript +import { useProfile } from '@internal/api'; +import { + Content, + ContentHeader, + PageWithHeader, +} from '@backstage/core-components'; +import { SearchBar, SearchResult } from '@backstage/plugin-search'; +import { SearchContextProvider } from '@backstage/plugin-search-react'; + +export const ManageMyWidgets = () => { + const { primaryTeam } = useProfile(); + // In this example, note how we are pre-filtering results down to a specific + // owner field value (the currently logged-in user's team), but allowing the + // search term to be controlled by the user via the component. + const preFiltered = { + types: ['widget'], + term: '', + filters: { + owner: primaryTeam, + }, + }; + + return ( + + + + + + + {/* Render results here, just like above */} + + + + + ); +}; +``` + +#### Custom search control surfaces + +If the reusable search components provided by `@backstage/plugin-search` aren't +adequate, no problem! There's an API in place that you can use to author your +own components to control the various parts of the search context. + +```javascript +import { useSearch } from '@backstage/plugin-search-react'; +import ChipInput from 'material-ui-chip-input'; + +export const CustomChipFilter = ({ name }) => { + const { filters, setFilters } = useSearch(); + const chipValues = filters[name] || []; + + // When a chip value is changed, update the filters value by calling the + // setFilters function from the search context. + const handleChipChange = (chip, index) => { + // There may be filters set for other fields. Be sure to maintain them. + setFilters(prevState => { + const { [name]: filter = [], ...others } = prevState; + + if (index === undefined) { + filter.push(chip); + } else { + filter.splice(index, 1); + } + + return { ...others, [name]: filter }; + }); + }; + + return ( + + ); +}; +``` + +Check out the [SearchContextValue type](https://github.com/backstage/backstage/blob/master/plugins/search-react/src/context/SearchContext.tsx) +for more details on what methods and values are available for manipulating and +reading the search context. + +If you produce something generic and reusable, consider contributing your +component upstream so that all users of the Backstage Search Platform can +benefit. Issues and pull requests welcome. diff --git a/microsite/sidebars.json b/microsite/sidebars.json index a8dc4e53ee..e85eba8ba1 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -99,7 +99,8 @@ "features/search/concepts", "features/search/architecture", "features/search/search-engines", - "features/search/how-to-guides" + "features/search/how-to-guides", + "features/search/for-plugin-devs" ] }, { From 9387626eeccef35f5a611aa256a5d6d02108e6c1 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Fri, 27 May 2022 13:23:05 +0200 Subject: [PATCH 2/3] Clearer, more precise language. Intro packages used. Signed-off-by: Eric Peterson --- .../features/search/search-for-plugin-devs.md | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/features/search/search-for-plugin-devs.md b/docs/features/search/search-for-plugin-devs.md index d96b05c6c5..70697cd91c 100644 --- a/docs/features/search/search-for-plugin-devs.md +++ b/docs/features/search/search-for-plugin-devs.md @@ -9,8 +9,8 @@ and interfaces needed to offer search experiences within their plugins, while abstracting away (and instead empowering application integrators to choose) the specific underlying search technologies. -On this page, you'll find concepts, guides, and recipes for how to leverage the -Backstage Search Platform in your plugin. +On this page, you'll find concepts and tutorials for leveraging the Backstage +Search Platform in your plugin. ## Providing data to the search platform @@ -21,11 +21,12 @@ Backstage Search Platform in your plugin. While the core Search plugin offers components and extensions that empower app integrators to compose a global search experience, you may find that you want a narrower search experience just within your plugin. This could be as literal as -an autocomplete-style search bar focused on documents provided by your plugin, -or as abstract as a widget that presents a list of links that relate in some -way to something else on the page. +an autocomplete-style search bar focused on documents provided by your plugin +(for example, the [TechDocsSearch](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/search/components/TechDocsSearch.tsx) +component), or as abstract as a widget that presents a list of links that +are contextually related to something else on the page. -### Concepts +### Search Experience Concepts Knowing these high-level concepts will help you as you craft your in-plugin search experience. @@ -34,7 +35,9 @@ search experience. is provided by `@backstage/plugin-search-react`. This context keeps track of state necessary to perform search queries and display any results. As inputs to the query are updated (e.g. a `term` or `filter` values), the - updated query is executed and `results` are refreshed. + updated query is executed and `results` are refreshed. Check out the + [SearchContextValue](https://backstage.io/docs/reference/plugin-search-react.searchcontextvalue) + for details. - The aforementioned state can be modified and/or consumed via the `useSearch()` hook, also exported by `@backstage/plugin-search-react`. - For more literal search experiences, reusable components are available @@ -42,7 +45,20 @@ search experience. `` or ``). You can see all such components in [Backstage's storybook](https://backstage.io/storybook/?path=/story/plugins-search-searchbar--default). -### Recipes +### Search Experience Tutorials + +The following tutorials make use of packages and plugins that you may not yet +have as dependencies for your plugin; be sure to add them before you use them! + +- [`@backstage/plugin-search-react`](https://www.npmjs.com/package/@backstage/plugin-search-react) - A + package containing components, hooks, and types that are shared across all + frontend plugins, including plugins like yours! +- [`@backstage/plugin-search`](https://www.npmjs.com/package/@backstage/plugin-search) - The + main search plugin, used by app integrators to compose global search + experiences. +- [`@backstage/core-components`](https://www.npmjs.com/package/@backstage/core-components) - A + package containing generic components useful for a variety of experiences + built in Backstage. #### Improved "404" page experience From eb6a4d40af15cba64b4853fb2fcff48d203c49be Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Fri, 27 May 2022 13:30:04 +0200 Subject: [PATCH 3/3] Move from under Search to under Plugins Signed-off-by: Eric Peterson --- .../integrating-search-into-plugins.md} | 6 +++--- microsite/sidebars.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename docs/{features/search/search-for-plugin-devs.md => plugins/integrating-search-into-plugins.md} (98%) diff --git a/docs/features/search/search-for-plugin-devs.md b/docs/plugins/integrating-search-into-plugins.md similarity index 98% rename from docs/features/search/search-for-plugin-devs.md rename to docs/plugins/integrating-search-into-plugins.md index 70697cd91c..77456dd5b4 100644 --- a/docs/features/search/search-for-plugin-devs.md +++ b/docs/plugins/integrating-search-into-plugins.md @@ -1,7 +1,7 @@ --- -id: for-plugin-devs -title: Search for Plugin Developers -description: How to integrate search into a Backstage plugin +id: integrating-search-into-plugins +title: Integrating Search into a plugin +description: How to integrate Search into a Backstage plugin --- The Backstage Search Platform was designed to give plugin developers the APIs diff --git a/microsite/sidebars.json b/microsite/sidebars.json index e85eba8ba1..d570205dd5 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -99,8 +99,7 @@ "features/search/concepts", "features/search/architecture", "features/search/search-engines", - "features/search/how-to-guides", - "features/search/for-plugin-devs" + "features/search/how-to-guides" ] }, { @@ -199,6 +198,7 @@ "plugins/plugin-development", "plugins/structure-of-a-plugin", "plugins/integrating-plugin-into-software-catalog", + "plugins/integrating-search-into-plugins", "plugins/composability", "plugins/analytics", {