refactor(search-react): apply review suggestions

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2023-09-27 14:29:54 +02:00
parent 703a4ffc5b
commit 184be50385
5 changed files with 86 additions and 30 deletions
+1 -1
View File
@@ -86,7 +86,7 @@ export type SearchResultListItemExtensionProps<Props extends {} = {}> = Props &
>;
/**
* @public
* @internal
* Extends children with extension capabilities.
* @param props - see {@link SearchResultListItemExtensionProps}.
*/
@@ -22,6 +22,7 @@ import {
createExtensionInput,
createPageExtension,
createPlugin,
createSchemaFromZod,
} from '@backstage/frontend-plugin-api';
import { SearchResult } from '@backstage/plugin-search-common';
import { createApp } from '@backstage/frontend-app-api';
@@ -43,16 +44,32 @@ jest.mock('@backstage/plugin-graphiql', () => ({
describe('createSearchResultListItemExtension', () => {
it('Should use the correct result component', async () => {
type TechDocsSearchReasulListItemProps = BaseSearchResultListItemProps<{
lineClamp: number;
}>;
const TechDocsSearchResultItemComponent = (
props: BaseSearchResultListItemProps,
) => <div>TechDocs - Rank: {props.rank}</div>;
props: TechDocsSearchReasulListItemProps,
) => (
<div>
TechDocs - Rank: {props.rank} - Line clamp: {props.lineClamp}
</div>
);
const TechDocsSearchResultItemExtension =
createSearchResultListItemExtension({
id: 'techdocs',
at: 'plugin.search.page/items',
configSchema: createSchemaFromZod(z =>
z.object({
noTrack: z.boolean().default(true),
lineClamp: z.number().default(5),
}),
),
predicate: result => result.type === 'techdocs',
component: async () => TechDocsSearchResultItemComponent,
component:
async ({ config }) =>
props =>
<TechDocsSearchResultItemComponent {...props} {...config} />,
});
const ExploreSearchResultItemComponent = (
@@ -129,7 +146,6 @@ describe('createSearchResultListItemExtension', () => {
key={index}
rank={result.rank}
result={result.document}
noTrack
/>
);
})}
@@ -153,7 +169,20 @@ describe('createSearchResultListItemExtension', () => {
const app = createApp({
plugins: [SearchPlugin],
configLoader: async () => new MockConfigApi({}),
configLoader: async () =>
new MockConfigApi({
app: {
extensions: [
{
'plugin.search.result.item.techdocs': {
config: {
lineClamp: 3,
},
},
},
],
},
}),
});
render(app.createRoot());
@@ -161,7 +190,9 @@ describe('createSearchResultListItemExtension', () => {
expect(await screen.findByText(/Search Page/)).toBeInTheDocument();
expect(
await screen.findByText(/TechDocs - Rank: 1/, { exact: false }),
await screen.findByText(/TechDocs - Rank: 1 - Line clamp: 3/, {
exact: false,
}),
).toBeInTheDocument();
expect(
@@ -20,8 +20,10 @@ import { ListItemProps } from '@material-ui/core';
import {
ExtensionBoundary,
PortableSchema,
createExtension,
createExtensionDataRef,
createSchemaFromZod,
} from '@backstage/frontend-plugin-api';
import { Progress } from '@backstage/core-components';
import { SearchDocument, SearchResult } from '@backstage/plugin-search-common';
@@ -47,7 +49,9 @@ export const searchResultItemExtensionData = createExtensionDataRef<{
}>('plugin.search.result.item.data');
/** @alpha */
export type SearchResultItemExtensionOptions = {
export type SearchResultItemExtensionOptions<
TConfig extends { noTrack?: boolean },
> = {
/**
* The extension id.
*/
@@ -56,10 +60,16 @@ export type SearchResultItemExtensionOptions = {
* The extension attachment point (e.g., search modal or page).
*/
at: string;
/**
* Optional extension config schema.
*/
configSchema?: PortableSchema<TConfig>;
/**
* The extension component.
*/
component: () => Promise<SearchResultItemExtensionComponent>;
component: (options: {
config: TConfig;
}) => Promise<SearchResultItemExtensionComponent>;
/**
* When an extension defines a predicate, it returns true if the result should be rendered by that extension.
* Defaults to a predicate that returns true, which means it renders all sorts of results.
@@ -68,25 +78,35 @@ export type SearchResultItemExtensionOptions = {
};
/** @alpha */
export type BaseSearchResultListItemProps = {
export type BaseSearchResultListItemProps<T = {}> = T & {
rank?: number;
result?: SearchDocument;
noTrack?: boolean;
} & Omit<ListItemProps, 'button'>;
/** @alpha */
export const createSearchResultListItemExtension = (
options: SearchResultItemExtensionOptions,
) =>
createExtension({
export function createSearchResultListItemExtension<
TConfig extends { noTrack?: boolean },
>(options: SearchResultItemExtensionOptions<TConfig>) {
const configSchema =
'configSchema' in options
? options.configSchema
: (createSchemaFromZod(z =>
z.object({
noTrack: z.boolean().default(true),
}),
) as PortableSchema<TConfig>);
return createExtension({
id: `plugin.search.result.item.${options.id}`,
at: options.at,
configSchema,
output: {
item: searchResultItemExtensionData,
},
factory({ bind, source }) {
factory({ bind, config, source }) {
const LazyComponent = lazy(() =>
options.component().then(component => ({ default: component })),
options
.component({ config })
.then(component => ({ default: component })),
) as unknown as SearchResultItemExtensionComponent;
bind({
@@ -98,7 +118,7 @@ export const createSearchResultListItemExtension = (
<SearchResultListItemExtension
rank={props.rank}
result={props.result}
noTrack={props.noTrack}
noTrack={config.noTrack}
>
<LazyComponent {...props} />
</SearchResultListItemExtension>
@@ -109,3 +129,4 @@ export const createSearchResultListItemExtension = (
});
},
});
}