From ec34b535c044ce97f60ce422ecfcd315a43be3d9 Mon Sep 17 00:00:00 2001 From: Phil Kuang Date: Wed, 1 Feb 2023 14:23:32 -0500 Subject: [PATCH] feat(AdrSearchResultListItem): support displaying icon & hook up extensions Signed-off-by: Phil Kuang --- .changeset/nine-ravens-kiss.md | 5 +++ .changeset/proud-glasses-live.md | 5 +++ plugins/adr/api-report.md | 13 +++++-- plugins/adr/package.json | 1 + plugins/adr/src/index.ts | 4 +-- plugins/adr/src/plugin.ts | 20 +++++++++++ .../src/search/AdrSearchResultListItem.tsx | 35 ++++++++++--------- plugins/adr/src/search/index.ts | 2 +- yarn.lock | 1 + 9 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 .changeset/nine-ravens-kiss.md create mode 100644 .changeset/proud-glasses-live.md diff --git a/.changeset/nine-ravens-kiss.md b/.changeset/nine-ravens-kiss.md new file mode 100644 index 0000000000..a507db6b03 --- /dev/null +++ b/.changeset/nine-ravens-kiss.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-adr': minor +--- + +The `AdrSearchResultListItem` component is now a search result extension. This means that when rendered as a child of components that render search extensions, the `result`, `rank`, and `highlight` properties are optional. See the [documentation](https://backstage.io/docs/features/search/how-to-guides#how-to-render-search-results-using-extensions) for more details. diff --git a/.changeset/proud-glasses-live.md b/.changeset/proud-glasses-live.md new file mode 100644 index 0000000000..ded7a53ce7 --- /dev/null +++ b/.changeset/proud-glasses-live.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-adr': patch +--- + +Support displaying an icon on `AdrSearchResultListItem` diff --git a/plugins/adr/api-report.md b/plugins/adr/api-report.md index d6480cd090..4ced4e9416 100644 --- a/plugins/adr/api-report.md +++ b/plugins/adr/api-report.md @@ -11,6 +11,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { isAdrAvailable } from '@backstage/plugin-adr-common'; +import { ReactNode } from 'react'; import { ResultHighlight } from '@backstage/plugin-search-common'; import { RouteRef } from '@backstage/core-plugin-api'; @@ -82,12 +83,18 @@ export type AdrReadResult = { }; // @public -export function AdrSearchResultListItem(props: { +export const AdrSearchResultListItem: ( + props: AdrSearchResultListItemProps, +) => JSX.Element | null; + +// @public (undocumented) +export type AdrSearchResultListItemProps = { lineClamp?: number; highlight?: ResultHighlight; + icon?: ReactNode; rank?: number; - result: AdrDocument; -}): JSX.Element; + result?: AdrDocument; +}; // @public export const EntityAdrContent: (props: { diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 9d915b7af7..5f3d3ba12a 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -39,6 +39,7 @@ "remark-gfm": "^3.0.1" }, "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0", "react": "^16.13.1 || ^17.0.0", "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, diff --git a/plugins/adr/src/index.ts b/plugins/adr/src/index.ts index 2ec76b0fd6..f24b3ac531 100644 --- a/plugins/adr/src/index.ts +++ b/plugins/adr/src/index.ts @@ -30,5 +30,5 @@ export type { } from './api'; export { isAdrAvailable } from '@backstage/plugin-adr-common'; export * from './components/AdrReader'; -export { adrPlugin, EntityAdrContent } from './plugin'; -export * from './search'; +export { adrPlugin, AdrSearchResultListItem, EntityAdrContent } from './plugin'; +export type { AdrSearchResultListItemProps } from './search'; diff --git a/plugins/adr/src/plugin.ts b/plugins/adr/src/plugin.ts index f23df826cd..05e4adec4a 100644 --- a/plugins/adr/src/plugin.ts +++ b/plugins/adr/src/plugin.ts @@ -21,7 +21,9 @@ import { createRoutableExtension, discoveryApiRef, } from '@backstage/core-plugin-api'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react'; import { rootRouteRef } from './routes'; +import { AdrSearchResultListItemProps } from './search'; /** * The Backstage plugin that holds ADR specific components @@ -57,3 +59,21 @@ export const EntityAdrContent = adrPlugin.provide( mountPoint: rootRouteRef, }), ); + +/** + * React extension used to render results on Search page or modal + * + * @public + */ +export const AdrSearchResultListItem: ( + props: AdrSearchResultListItemProps, +) => JSX.Element | null = adrPlugin.provide( + createSearchResultListItemExtension({ + name: 'AdrSearchResultListItem', + component: () => + import('./search/AdrSearchResultListItem').then( + m => m.AdrSearchResultListItem, + ), + predicate: result => result.type === 'adr', + }), +); diff --git a/plugins/adr/src/search/AdrSearchResultListItem.tsx b/plugins/adr/src/search/AdrSearchResultListItem.tsx index 3a11b5cf9a..118333a439 100644 --- a/plugins/adr/src/search/AdrSearchResultListItem.tsx +++ b/plugins/adr/src/search/AdrSearchResultListItem.tsx @@ -14,19 +14,19 @@ * limitations under the License. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import { Box, Chip, Divider, ListItem, + ListItemIcon, ListItemText, makeStyles, } from '@material-ui/core'; import Typography from '@material-ui/core/Typography'; import { parseEntityRef } from '@backstage/catalog-model'; import { Link } from '@backstage/core-components'; -import { useAnalytics } from '@backstage/core-plugin-api'; import { AdrDocument } from '@backstage/plugin-adr-common'; import { humanizeEntityRef } from '@backstage/plugin-catalog-react'; import { ResultHighlight } from '@backstage/plugin-search-common'; @@ -43,35 +43,36 @@ const useStyles = makeStyles({ }, }); +/** + * @public + */ +export type AdrSearchResultListItemProps = { + lineClamp?: number; + highlight?: ResultHighlight; + icon?: ReactNode; + rank?: number; + result?: AdrDocument; +}; + /** * A component to display an ADR search result. * @public */ -export function AdrSearchResultListItem(props: { - lineClamp?: number; - highlight?: ResultHighlight; - rank?: number; - result: AdrDocument; -}) { - const { lineClamp = 5, highlight, rank, result } = props; +export function AdrSearchResultListItem(props: AdrSearchResultListItemProps) { + const { lineClamp = 5, highlight, icon, result } = props; const classes = useStyles(); - const analytics = useAnalytics(); - const handleClick = () => { - analytics.captureEvent('discover', result.title, { - attributes: { to: result.location }, - value: rank, - }); - }; + if (!result) return null; return ( <> + {icon && {icon}} + {highlight?.fields.title ? (