refactor(search-react): apply review suggestions
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
@@ -8,20 +8,22 @@
|
||||
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
|
||||
import { Extension } from '@backstage/frontend-plugin-api';
|
||||
import { ListItemProps } from '@material-ui/core';
|
||||
import { PortableSchema } from '@backstage/frontend-plugin-api';
|
||||
import { SearchDocument } from '@backstage/plugin-search-common';
|
||||
import { SearchResult } from '@backstage/plugin-search-common';
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type BaseSearchResultListItemProps = {
|
||||
export type BaseSearchResultListItemProps<T = {}> = T & {
|
||||
rank?: number;
|
||||
result?: SearchDocument;
|
||||
noTrack?: boolean;
|
||||
} & Omit<ListItemProps, 'button'>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const createSearchResultListItemExtension: (
|
||||
options: SearchResultItemExtensionOptions,
|
||||
) => Extension<never>;
|
||||
export function createSearchResultListItemExtension<
|
||||
TConfig extends {
|
||||
noTrack?: boolean;
|
||||
},
|
||||
>(options: SearchResultItemExtensionOptions<TConfig>): Extension<TConfig>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type SearchResultItemExtensionComponent = <
|
||||
@@ -40,10 +42,17 @@ export const searchResultItemExtensionData: ConfigurableExtensionDataRef<
|
||||
>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type SearchResultItemExtensionOptions = {
|
||||
export type SearchResultItemExtensionOptions<
|
||||
TConfig extends {
|
||||
noTrack?: boolean;
|
||||
},
|
||||
> = {
|
||||
id: string;
|
||||
at: string;
|
||||
component: () => Promise<SearchResultItemExtensionComponent>;
|
||||
configSchema?: PortableSchema<TConfig>;
|
||||
component: (options: {
|
||||
config: TConfig;
|
||||
}) => Promise<SearchResultItemExtensionComponent>;
|
||||
predicate?: SearchResultItemExtensionPredicate;
|
||||
};
|
||||
|
||||
|
||||
@@ -391,11 +391,6 @@ export const SearchResultList: (
|
||||
props: SearchResultListProps,
|
||||
) => React_2.JSX.Element;
|
||||
|
||||
// @public
|
||||
export const SearchResultListItemExtension: (
|
||||
props: SearchResultListItemExtensionProps,
|
||||
) => React_2.JSX.Element;
|
||||
|
||||
// @public
|
||||
export type SearchResultListItemExtensionOptions<
|
||||
Component extends (props: any) => JSX.Element | null,
|
||||
|
||||
@@ -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 = (
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user