Move SearchResult from @backstage/plugin-search to @backstage/plugin-search-react and deprecate it in @backstage/plugin-search
Signed-off-by: Anders Näsman <andersn@spotify.com>
This commit is contained in:
committed by
Eric Peterson
parent
d7044784f0
commit
01abb3bc7e
@@ -12,6 +12,7 @@ import { PropsWithChildren } from 'react';
|
||||
import { default as React_2 } from 'react';
|
||||
import { ReactElement } from 'react';
|
||||
import { SearchQuery } from '@backstage/plugin-search-common';
|
||||
import { SearchResult as SearchResult_2 } from '@backstage/plugin-search-common';
|
||||
import { SearchResultSet } from '@backstage/plugin-search-common';
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -120,6 +121,14 @@ export type SearchFilterWrapperProps = SearchFilterComponentProps & {
|
||||
debug?: boolean;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const SearchResult: ({ children }: SearchResultProps) => JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export type SearchResultProps = {
|
||||
children: (results: { results: SearchResult_2[] }) => JSX.Element;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const SelectFilter: (props: SearchFilterComponentProps) => JSX.Element;
|
||||
|
||||
|
||||
@@ -31,13 +31,16 @@
|
||||
"start": "backstage-cli package start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/plugin-search": "0.8.2-next.1",
|
||||
"@backstage/plugin-search-common": "^0.3.5-next.0",
|
||||
"@backstage/core-components": "^0.9.5-next.1",
|
||||
"@backstage/core-plugin-api": "^1.0.3-next.0",
|
||||
"@backstage/version-bridge": "^1.0.1",
|
||||
"react-use": "^17.3.2",
|
||||
"@backstage/types": "^1.0.0",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/lab": "4.0.0-alpha.57"
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-use": "^17.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.13.1 || ^17.0.0",
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Link } from '@backstage/core-components';
|
||||
import { List, ListItem } from '@material-ui/core';
|
||||
import React, { ComponentType } from 'react';
|
||||
import { MemoryRouter } from 'react-router';
|
||||
import { DefaultResultListItem } from '@backstage/plugin-search';
|
||||
|
||||
import { searchApiRef, MockSearchApi } from '../../api';
|
||||
import { SearchContextProvider } from '../../context';
|
||||
import { SearchResult } from './SearchResult';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
|
||||
const mockResults = {
|
||||
results: [
|
||||
{
|
||||
type: 'custom-result-item',
|
||||
document: {
|
||||
location: 'search/search-result-1',
|
||||
title: 'Search Result 1',
|
||||
text: 'some text from the search result',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'no-custom-result-item',
|
||||
document: {
|
||||
location: 'search/search-result-2',
|
||||
title: 'Search Result 2',
|
||||
text: 'some text from the search result',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'no-custom-result-item',
|
||||
document: {
|
||||
location: 'search/search-result-3',
|
||||
title: 'Search Result 3',
|
||||
text: 'some text from the search result',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Plugins/Search/SearchResult',
|
||||
component: SearchResult,
|
||||
decorators: [
|
||||
(Story: ComponentType<{}>) => (
|
||||
<MemoryRouter>
|
||||
<TestApiProvider
|
||||
apis={[[searchApiRef, new MockSearchApi(mockResults)]]}
|
||||
>
|
||||
<SearchContextProvider>
|
||||
<Story />
|
||||
</SearchContextProvider>
|
||||
</TestApiProvider>
|
||||
</MemoryRouter>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
export const Default = () => {
|
||||
return (
|
||||
<SearchResult>
|
||||
{({ results }) => (
|
||||
<List>
|
||||
{results.map(({ type, document }) => {
|
||||
switch (type) {
|
||||
case 'custom-result-item':
|
||||
return (
|
||||
<DefaultResultListItem
|
||||
key={document.location}
|
||||
result={document}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<ListItem>
|
||||
<Link to={document.location}>
|
||||
{document.title} - {document.text}
|
||||
</Link>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</List>
|
||||
)}
|
||||
</SearchResult>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { useSearch } from '../../context';
|
||||
import { SearchResult } from './SearchResult';
|
||||
|
||||
jest.mock('../../context', () => ({
|
||||
...jest.requireActual('../../context'),
|
||||
useSearch: jest.fn().mockReturnValue({
|
||||
result: {},
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('SearchResult', () => {
|
||||
it('Progress rendered on Loading state', async () => {
|
||||
(useSearch as jest.Mock).mockReturnValueOnce({
|
||||
result: { loading: true },
|
||||
});
|
||||
|
||||
const { getByRole } = await renderInTestApp(
|
||||
<SearchResult>{() => <></>}</SearchResult>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByRole('progressbar')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Alert rendered on Error state', async () => {
|
||||
const error = new Error('some error');
|
||||
(useSearch as jest.Mock).mockReturnValueOnce({
|
||||
result: { loading: false, error },
|
||||
});
|
||||
|
||||
const { getByRole } = await renderInTestApp(
|
||||
<SearchResult>{() => <></>}</SearchResult>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByRole('alert')).toHaveTextContent(
|
||||
new RegExp(`Error encountered while fetching search results.*${error}`),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('On no result value state', async () => {
|
||||
(useSearch as jest.Mock).mockReturnValueOnce({
|
||||
result: { loading: false, error: '', value: undefined },
|
||||
});
|
||||
|
||||
const { getByRole } = await renderInTestApp(
|
||||
<SearchResult>{() => <></>}</SearchResult>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
getByRole('heading', { name: 'Sorry, no results were found' }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('On empty result value state', async () => {
|
||||
(useSearch as jest.Mock).mockReturnValueOnce({
|
||||
result: { loading: false, error: '', value: { results: [] } },
|
||||
});
|
||||
|
||||
const { getByRole } = await renderInTestApp(
|
||||
<SearchResult>{() => <></>}</SearchResult>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
getByRole('heading', { name: 'Sorry, no results were found' }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Calls children with results set to result.value', async () => {
|
||||
(useSearch as jest.Mock).mockReturnValueOnce({
|
||||
result: {
|
||||
loading: false,
|
||||
error: '',
|
||||
value: {
|
||||
totalCount: 1,
|
||||
results: [
|
||||
{
|
||||
type: 'some-type',
|
||||
document: {
|
||||
title: 'some-title',
|
||||
text: 'some-text',
|
||||
location: 'some-location',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { getByText } = await renderInTestApp(
|
||||
<SearchResult>
|
||||
{({ results }) => {
|
||||
return <>Results {results.length}</>;
|
||||
}}
|
||||
</SearchResult>,
|
||||
);
|
||||
|
||||
expect(getByText('Results 1')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
EmptyState,
|
||||
Progress,
|
||||
ResponseErrorPanel,
|
||||
} from '@backstage/core-components';
|
||||
import { SearchResult } from '@backstage/plugin-search-common';
|
||||
import React from 'react';
|
||||
import { useSearch } from '../../context';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type SearchResultProps = {
|
||||
children: (results: { results: SearchResult[] }) => JSX.Element;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const SearchResultComponent = ({ children }: SearchResultProps) => {
|
||||
const {
|
||||
result: { loading, error, value },
|
||||
} = useSearch();
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
}
|
||||
if (error) {
|
||||
return (
|
||||
<ResponseErrorPanel
|
||||
title="Error encountered while fetching search results"
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!value?.results.length) {
|
||||
return <EmptyState missing="data" title="Sorry, no results were found" />;
|
||||
}
|
||||
|
||||
return <>{children({ results: value.results })}</>;
|
||||
};
|
||||
|
||||
export { SearchResultComponent as SearchResult };
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { SearchResult } from './SearchResult';
|
||||
export type { SearchResultProps } from './SearchResult';
|
||||
@@ -16,3 +16,4 @@
|
||||
|
||||
export * from './HighlightedSearchResultText';
|
||||
export * from './SearchFilter';
|
||||
export * from './SearchResult';
|
||||
|
||||
Reference in New Issue
Block a user