feat(search): create catalog, explore, tools, and search extensions

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2023-01-23 17:45:19 +01:00
parent a7ec5e7d78
commit 2f91e1684e
13 changed files with 82 additions and 49 deletions
@@ -25,7 +25,6 @@ import {
makeStyles,
} from '@material-ui/core';
import { Link } from '@backstage/core-components';
import { useAnalytics } from '@backstage/core-plugin-api';
import {
IndexableDocument,
ResultHighlight,
@@ -50,7 +49,7 @@ const useStyles = makeStyles({
*/
export interface CatalogSearchResultListItemProps {
icon?: ReactNode;
result: IndexableDocument;
result?: IndexableDocument;
highlight?: ResultHighlight;
rank?: number;
}
@@ -63,13 +62,8 @@ export function CatalogSearchResultListItem(
const highlight = props.highlight as ResultHighlight;
const classes = useStyles();
const analytics = useAnalytics();
const handleClick = () => {
analytics.captureEvent('discover', result.title, {
attributes: { to: result.location },
value: props.rank,
});
};
if (!result) return null;
return (
<>
@@ -80,7 +74,7 @@ export function CatalogSearchResultListItem(
className={classes.itemText}
primaryTypographyProps={{ variant: 'h6' }}
primary={
<Link noTrack to={result.location} onClick={handleClick}>
<Link noTrack to={result.location}>
{highlight?.fields.title ? (
<HighlightedSearchResultText
text={highlight.fields.title}
+2 -1
View File
@@ -29,7 +29,6 @@ export type {
} from './components/AboutCard';
export { AboutContent, AboutField } from './components/AboutCard';
export * from './components/CatalogKindHeader';
export * from './components/CatalogSearchResultListItem';
export * from './components/CatalogTable';
export * from './components/EntityLayout';
export * from './components/EntityOrphanWarning';
@@ -53,6 +52,7 @@ export {
EntityLinksCard,
EntityLabelsCard,
RelatedEntitiesCard,
CatalogSearchResultListItem,
} from './plugin';
export type { DependencyOfComponentsCardProps } from './components/DependencyOfComponentsCard';
@@ -72,3 +72,4 @@ export type { HasResourcesCardProps } from './components/HasResourcesCard';
export type { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard';
export type { HasSystemsCardProps } from './components/HasSystemsCard';
export type { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard';
export type { CatalogSearchResultListItemProps } from './components/CatalogSearchResultListItem';
+16
View File
@@ -31,6 +31,7 @@ import {
fetchApiRef,
storageApiRef,
} from '@backstage/core-plugin-api';
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react';
import { DefaultStarredEntitiesApi } from './apis';
import { AboutCardProps } from './components/AboutCard';
import { DefaultCatalogPageProps } from './components/CatalogPage';
@@ -42,6 +43,7 @@ import { HasResourcesCardProps } from './components/HasResourcesCard';
import { HasSubcomponentsCardProps } from './components/HasSubcomponentsCard';
import { HasSystemsCardProps } from './components/HasSystemsCard';
import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard';
import { CatalogSearchResultListItemProps } from './components/CatalogSearchResultListItem';
import { rootRouteRef } from './routes';
import { CatalogInputPluginOptions, CatalogPluginOptions } from './options';
@@ -249,3 +251,17 @@ export const RelatedEntitiesCard: <T extends Entity>(
},
}),
);
/** @public */
export const CatalogSearchResultListItem: (
props: CatalogSearchResultListItemProps,
) => JSX.Element | null = catalogPlugin.provide(
createSearchResultListItemExtension({
name: 'CatalogSearchResultListItem',
component: () =>
import('./components/CatalogSearchResultListItem').then(
m => m.CatalogSearchResultListItem,
),
predicate: result => result.type === 'software-catalog',
}),
);
@@ -25,7 +25,6 @@ import {
makeStyles,
} from '@material-ui/core';
import { Link } from '@backstage/core-components';
import { useAnalytics } from '@backstage/core-plugin-api';
import {
IndexableDocument,
ResultHighlight,
@@ -50,23 +49,18 @@ const useStyles = makeStyles({
*/
export interface ToolSearchResultListItemProps {
icon?: ReactNode;
result: IndexableDocument;
result?: IndexableDocument;
highlight?: ResultHighlight;
rank?: number;
}
/** @public */
/** @public */
export function ToolSearchResultListItem(props: ToolSearchResultListItemProps) {
const result = props.result as any;
const classes = useStyles();
const analytics = useAnalytics();
const handleClick = () => {
analytics.captureEvent('discover', result.title, {
attributes: { to: result.location },
value: props.rank,
});
};
if (!result) return null;
return (
<>
@@ -77,7 +71,7 @@ export function ToolSearchResultListItem(props: ToolSearchResultListItemProps) {
className={classes.itemText}
primaryTypographyProps={{ variant: 'h6' }}
primary={
<Link noTrack to={result.location} onClick={handleClick}>
<Link noTrack to={result.location}>
{props.highlight?.fields.title ? (
<HighlightedSearchResultText
text={props.highlight.fields.title}
-1
View File
@@ -16,4 +16,3 @@
export * from './DomainCard';
export * from './ExploreLayout';
export * from './ToolSearchResultListItem';
+7 -1
View File
@@ -23,5 +23,11 @@
export * from './api';
export * from './components';
export * from './extensions';
export { explorePlugin, explorePlugin as plugin } from './plugin';
export {
ToolSearchResultListItem,
explorePlugin,
explorePlugin as plugin,
} from './plugin';
export * from './routes';
export type { ToolSearchResultListItemProps } from './components/ToolSearchResultListItem';
+16
View File
@@ -22,7 +22,9 @@ import {
discoveryApiRef,
fetchApiRef,
} from '@backstage/core-plugin-api';
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react';
import { ExploreClient, exploreApiRef } from './api';
import { ToolSearchResultListItemProps } from './components/ToolSearchResultListItem';
// import { exampleTools } from './util/examples';
/** @public */
@@ -65,3 +67,17 @@ export const explorePlugin = createPlugin({
catalogEntity: catalogEntityRouteRef,
},
});
/** @public */
export const ToolSearchResultListItem: (
props: ToolSearchResultListItemProps,
) => JSX.Element | null = explorePlugin.provide(
createSearchResultListItemExtension({
name: 'ToolSearchResultListItem',
component: () =>
import('./components/ToolSearchResultListItem').then(
m => m.ToolSearchResultListItem,
),
predicate: result => result.type === 'tools',
}),
);
@@ -15,7 +15,7 @@
*/
import React, { ReactNode } from 'react';
import { AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api';
import { AnalyticsContext } from '@backstage/core-plugin-api';
import {
ResultHighlight,
SearchDocument,
@@ -39,7 +39,7 @@ import { Link } from '@backstage/core-components';
export type DefaultResultListItemProps = {
icon?: ReactNode;
secondaryAction?: ReactNode;
result: SearchDocument;
result?: SearchDocument;
highlight?: ResultHighlight;
rank?: number;
lineClamp?: number;
@@ -53,18 +53,11 @@ export type DefaultResultListItemProps = {
export const DefaultResultListItemComponent = ({
result,
highlight,
rank,
icon,
secondaryAction,
lineClamp = 5,
}: DefaultResultListItemProps) => {
const analytics = useAnalytics();
const handleClick = () => {
analytics.captureEvent('discover', result.title, {
attributes: { to: result.location },
value: rank,
});
};
if (!result) return null;
return (
<>
@@ -73,7 +66,7 @@ export const DefaultResultListItemComponent = ({
<ListItemText
primaryTypographyProps={{ variant: 'h6' }}
primary={
<Link noTrack to={result.location} onClick={handleClick}>
<Link noTrack to={result.location}>
{highlight?.fields.title ? (
<HighlightedSearchResultText
text={highlight?.fields.title || ''}
+1 -1
View File
@@ -47,7 +47,7 @@ export type { SidebarSearchModalProps } from './components/SidebarSearchModal';
export {
HomePageSearchBar,
SearchPage,
SidebarSearchModal,
searchPlugin as plugin,
searchPlugin,
SidebarSearchModal,
} from './plugin';
+3
View File
@@ -37,11 +37,14 @@ export {
TechDocsIndexPage,
TechdocsPage,
TechDocsReaderPage,
TechDocsSearchResultListItem,
techdocsPlugin as plugin,
techdocsPlugin,
} from './plugin';
export * from './Router';
export type { TechDocsSearchResultListItemProps } from './search/components/TechDocsSearchResultListItem';
/**
* @deprecated Import from `@backstage/plugin-techdocs-react` instead
*
+20
View File
@@ -33,6 +33,8 @@ import {
fetchApiRef,
identityApiRef,
} from '@backstage/core-plugin-api';
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react';
import { TechDocsSearchResultListItemProps } from './search/components/TechDocsSearchResultListItem';
/**
* The Backstage plugin that renders technical documentation for your components
@@ -153,3 +155,21 @@ export const TechDocsReaderPage = techdocsPlugin.provide(
mountPoint: rootDocsRouteRef,
}),
);
/**
* React extension used to render results on Search page or modal
*
* @public
*/
export const TechDocsSearchResultListItem: (
props: TechDocsSearchResultListItemProps,
) => JSX.Element | null = techdocsPlugin.provide(
createSearchResultListItemExtension({
name: 'TechDocsSearchResultListItem',
component: () =>
import('./search/components/TechDocsSearchResultListItem').then(
m => m.TechDocsSearchResultListItem,
),
predicate: result => result.type === 'techdocs',
}),
);
@@ -24,7 +24,6 @@ import {
} from '@material-ui/core';
import Typography from '@material-ui/core/Typography';
import { Link } from '@backstage/core-components';
import { useAnalytics } from '@backstage/core-plugin-api';
import { ResultHighlight } from '@backstage/plugin-search-common';
import { HighlightedSearchResultText } from '@backstage/plugin-search-react';
@@ -45,7 +44,7 @@ const useStyles = makeStyles({
*/
export type TechDocsSearchResultListItemProps = {
icon?: ReactNode;
result: any;
result?: any;
highlight?: ResultHighlight;
rank?: number;
lineClamp?: number;
@@ -65,7 +64,6 @@ export const TechDocsSearchResultListItem = (
const {
result,
highlight,
rank,
lineClamp = 5,
asListItem = true,
asLink = true,
@@ -74,17 +72,9 @@ export const TechDocsSearchResultListItem = (
} = props;
const classes = useStyles();
const analytics = useAnalytics();
const handleClick = () => {
analytics.captureEvent('discover', result.title, {
attributes: { to: result.location },
value: rank,
});
};
const LinkWrapper = ({ children }: PropsWithChildren<{}>) =>
asLink ? (
<Link noTrack to={result.location} onClick={handleClick}>
<Link noTrack to={result.location}>
{children}
</Link>
) : (
@@ -122,6 +112,8 @@ export const TechDocsSearchResultListItem = (
result.name
);
if (!result) return null;
return (
<ListItemText
className={classes.itemText}
@@ -14,5 +14,4 @@
* limitations under the License.
*/
export * from './TechDocsSearchResultListItem';
export * from './TechDocsSearch';