Merge pull request #10842 from backstage/emmaindal/search-clean-up-deprecated-context
[Search] clean up deprecated context from '@backstage/plugin-search'
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
imports `useSearch` hook from new `@backstage/plugin-search-react` package.
|
||||
|
||||
To upgrade existing Apps:
|
||||
|
||||
1. Change the import to the following:
|
||||
|
||||
`packages/app/src/components/search/SearchPage.tsx`
|
||||
|
||||
```diff
|
||||
import {
|
||||
...
|
||||
SearchType,
|
||||
- useSearch,
|
||||
} from '@backstage/plugin-search';
|
||||
+import { useSearch } from '@backstage/plugin-search-react';
|
||||
```
|
||||
|
||||
2. Add `@backstage/plugin-search-react` as a dependency to the app.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/plugin-search': minor
|
||||
---
|
||||
|
||||
The following exports has now been fully deleted from this package and can be import from `@backstage/plugin-search-react` instead.
|
||||
|
||||
`SearchApi` interface.
|
||||
`searchApiRef`
|
||||
`SearchContextProvider`
|
||||
`useSearch`
|
||||
|
||||
`SearchContext` has now been fully deleted from this package and is no longer exported publicly. Use `SearchContextProvider` when access to the context is needed.
|
||||
@@ -41,8 +41,8 @@ import {
|
||||
SearchResult,
|
||||
SearchResultPager,
|
||||
SearchType,
|
||||
useSearch,
|
||||
} from '@backstage/plugin-search';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
|
||||
@@ -36,8 +36,8 @@ import {
|
||||
SearchResult,
|
||||
SearchResultPager,
|
||||
SearchType,
|
||||
useSearch,
|
||||
} from '@backstage/plugin-search';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs';
|
||||
import { Grid, List, makeStyles, Paper, Theme } from '@material-ui/core';
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
"@backstage/plugin-scaffolder": "",
|
||||
"@backstage/plugin-scaffolder-backend": "",
|
||||
"@backstage/plugin-search": "",
|
||||
"@backstage/plugin-search-react": "",
|
||||
"@backstage/plugin-search-backend": "",
|
||||
"@backstage/plugin-search-backend-module-pg": "",
|
||||
"@backstage/plugin-search-backend-node": "",
|
||||
|
||||
@@ -69,6 +69,7 @@ import { version as pluginRollbarBackend } from '../../../../plugins/rollbar-bac
|
||||
import { version as pluginScaffolder } from '../../../../plugins/scaffolder/package.json';
|
||||
import { version as pluginScaffolderBackend } from '../../../../plugins/scaffolder-backend/package.json';
|
||||
import { version as pluginSearch } from '../../../../plugins/search/package.json';
|
||||
import { version as pluginSearchReact } from '../../../../plugins/search-react/package.json';
|
||||
import { version as pluginSearchBackend } from '../../../../plugins/search-backend/package.json';
|
||||
import { version as pluginSearchBackendModulePg } from '../../../../plugins/search-backend-module-pg/package.json';
|
||||
import { version as pluginSearchBackendNode } from '../../../../plugins/search-backend-node/package.json';
|
||||
@@ -113,6 +114,7 @@ export const packageVersions = {
|
||||
'@backstage/plugin-scaffolder': pluginScaffolder,
|
||||
'@backstage/plugin-scaffolder-backend': pluginScaffolderBackend,
|
||||
'@backstage/plugin-search': pluginSearch,
|
||||
'@backstage/plugin-search-react': pluginSearchReact,
|
||||
'@backstage/plugin-search-backend': pluginSearchBackend,
|
||||
'@backstage/plugin-search-backend-module-pg': pluginSearchBackendModulePg,
|
||||
'@backstage/plugin-search-backend-node': pluginSearchBackendNode,
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@backstage/plugin-permission-react": "^{{version '@backstage/plugin-permission-react'}}",
|
||||
"@backstage/plugin-scaffolder": "^{{version '@backstage/plugin-scaffolder'}}",
|
||||
"@backstage/plugin-search": "^{{version '@backstage/plugin-search'}}",
|
||||
"@backstage/plugin-search-react": "^{{version '@backstage/plugin-search-react'}}",
|
||||
"@backstage/plugin-tech-radar": "^{{version '@backstage/plugin-tech-radar'}}",
|
||||
"@backstage/plugin-techdocs": "^{{version '@backstage/plugin-techdocs'}}",
|
||||
"@backstage/plugin-user-settings": "^{{version '@backstage/plugin-user-settings'}}",
|
||||
|
||||
+1
-1
@@ -14,8 +14,8 @@ import {
|
||||
SearchResult,
|
||||
SearchType,
|
||||
DefaultResultListItem,
|
||||
useSearch,
|
||||
} from '@backstage/plugin-search';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import {
|
||||
CatalogIcon,
|
||||
Content,
|
||||
|
||||
@@ -5,20 +5,14 @@
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { AsyncState } from 'react-use/lib/useAsync';
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import { InputBaseProps } from '@material-ui/core';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { default as React_2 } from 'react';
|
||||
import { ReactElement } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { SearchDocument } from '@backstage/plugin-search-common';
|
||||
import { SearchQuery } from '@backstage/plugin-search-common';
|
||||
import { SearchResult as SearchResult_2 } from '@backstage/plugin-search-common';
|
||||
import { SearchResultSet } from '@backstage/plugin-search-common';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "DefaultResultListItem" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
@@ -81,19 +75,6 @@ export type HomePageSearchBarProps = Partial<
|
||||
// @public (undocumented)
|
||||
export const Router: () => JSX.Element;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public @deprecated (undocumented)
|
||||
export interface SearchApi {
|
||||
// (undocumented)
|
||||
query(query: SearchQuery): Promise<SearchResultSet>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "searchApiRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public @deprecated (undocumented)
|
||||
export const searchApiRef: ApiRef<SearchApi>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type SearchAutocompleteFilterProps = SearchFilterComponentProps & {
|
||||
filterSelectedOptions?: boolean;
|
||||
@@ -138,24 +119,6 @@ export const SearchBarNext: ({
|
||||
// @public
|
||||
export type SearchBarProps = Partial<SearchBarBaseProps>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchContextProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public @deprecated (undocumented)
|
||||
export const SearchContextProvider: ({
|
||||
initialState,
|
||||
children,
|
||||
}: React_2.PropsWithChildren<{
|
||||
initialState?: SearchContextState | undefined;
|
||||
}>) => JSX.Element;
|
||||
|
||||
// @public
|
||||
export type SearchContextState = {
|
||||
term: string;
|
||||
types: string[];
|
||||
filters: JsonObject;
|
||||
pageCursor?: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SearchFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -330,13 +293,6 @@ export type SidebarSearchProps = {
|
||||
icon?: IconComponent;
|
||||
};
|
||||
|
||||
// Warning: (tsdoc-at-sign-in-word) The "@" character looks like part of a TSDoc tag; use a backslash to escape it
|
||||
// Warning: (ae-forgotten-export) The symbol "SearchContextValue" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "useSearch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public @deprecated (undocumented)
|
||||
export const useSearch: () => SearchContextValue;
|
||||
|
||||
// @public
|
||||
export function useSearchModal(initialState?: boolean): {
|
||||
state: {
|
||||
|
||||
@@ -14,30 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createApiRef,
|
||||
DiscoveryApi,
|
||||
IdentityApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import { SearchApi } from '@backstage/plugin-search-react';
|
||||
import { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';
|
||||
|
||||
import qs from 'qs';
|
||||
|
||||
/**
|
||||
* @deprecated import from `@backstage/plugin-search-react` instead
|
||||
*/
|
||||
export const searchApiRef = createApiRef<SearchApi>({
|
||||
id: 'plugin.search.queryservice',
|
||||
});
|
||||
|
||||
/**
|
||||
* @deprecated import from `@backstage/plugin-search-react` instead
|
||||
*/
|
||||
export interface SearchApi {
|
||||
query(query: SearchQuery): Promise<SearchResultSet>;
|
||||
}
|
||||
|
||||
export class SearchClient implements SearchApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
private readonly identityApi: IdentityApi;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { rootRouteRef, HomePageSearchBar } from '../../plugin';
|
||||
import { searchApiRef } from '../../apis';
|
||||
import { searchApiRef } from '@backstage/plugin-search-react';
|
||||
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import { Grid, makeStyles } from '@material-ui/core';
|
||||
import React, { ComponentType } from 'react';
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
import { SearchBarBase, SearchBarBaseProps } from '../SearchBar';
|
||||
import { useNavigateToQuery } from '../util';
|
||||
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
import React from 'react';
|
||||
import { screen, render, waitFor, act } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { SearchContextProvider } from '../SearchContext';
|
||||
|
||||
import { SearchBar } from './SearchBar';
|
||||
import { configApiRef, analyticsApiRef } from '@backstage/core-plugin-api';
|
||||
import { ApiProvider, ConfigReader } from '@backstage/core-app-api';
|
||||
import { searchApiRef } from '../../apis';
|
||||
import { MockAnalyticsApi, TestApiRegistry } from '@backstage/test-utils';
|
||||
import {
|
||||
SearchContextProvider,
|
||||
searchApiRef,
|
||||
} from '@backstage/plugin-search-react';
|
||||
|
||||
import { SearchBar } from './SearchBar';
|
||||
|
||||
jest.mock('@backstage/core-plugin-api', () => ({
|
||||
...jest.requireActual('@backstage/core-plugin-api'),
|
||||
|
||||
@@ -20,7 +20,6 @@ import React, {
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
useContext,
|
||||
} from 'react';
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
@@ -34,10 +33,9 @@ import SearchIcon from '@material-ui/icons/Search';
|
||||
import ClearButton from '@material-ui/icons/Clear';
|
||||
|
||||
import {
|
||||
SearchContext,
|
||||
SearchContextProvider,
|
||||
useSearch,
|
||||
} from '../SearchContext';
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { TrackSearch } from '../SearchTracker';
|
||||
|
||||
/**
|
||||
@@ -53,11 +51,6 @@ export type SearchBarBaseProps = Omit<InputBaseProps, 'onChange'> & {
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
const useSearchContextCheck = () => {
|
||||
const context = useContext(SearchContext);
|
||||
return context !== undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* All search boxes exported by the search plugin are based on the <SearchBarBase />,
|
||||
* and this one is based on the <InputBase /> component from Material UI.
|
||||
@@ -79,7 +72,7 @@ export const SearchBarBase = ({
|
||||
}: SearchBarBaseProps) => {
|
||||
const configApi = useApi(configApiRef);
|
||||
const [value, setValue] = useState<string>(defaultValue as string);
|
||||
const hasSearchContext = useSearchContextCheck();
|
||||
const hasSearchContext = useSearch();
|
||||
|
||||
useEffect(() => {
|
||||
setValue(prevValue =>
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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 { JsonObject } from '@backstage/types';
|
||||
import { useApi, AnalyticsContext } from '@backstage/core-plugin-api';
|
||||
import { SearchResultSet } from '@backstage/plugin-search-common';
|
||||
import React, {
|
||||
createContext,
|
||||
PropsWithChildren,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import useAsync, { AsyncState } from 'react-use/lib/useAsync';
|
||||
import usePrevious from 'react-use/lib/usePrevious';
|
||||
import { searchApiRef } from '../../apis';
|
||||
|
||||
type SearchContextValue = {
|
||||
result: AsyncState<SearchResultSet>;
|
||||
setTerm: React.Dispatch<React.SetStateAction<string>>;
|
||||
setTypes: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
setFilters: React.Dispatch<React.SetStateAction<JsonObject>>;
|
||||
setPageCursor: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
fetchNextPage?: React.DispatchWithoutAction;
|
||||
fetchPreviousPage?: React.DispatchWithoutAction;
|
||||
} & SearchContextState;
|
||||
|
||||
/**
|
||||
* The initial state of `SearchContextProvider`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SearchContextState = {
|
||||
term: string;
|
||||
types: string[];
|
||||
filters: JsonObject;
|
||||
pageCursor?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated import from `@backstage/plugin-search-react` instead
|
||||
*/
|
||||
export const SearchContext = createContext<SearchContextValue | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
const searchInitialState: SearchContextState = {
|
||||
term: '',
|
||||
pageCursor: undefined,
|
||||
filters: {},
|
||||
types: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated import from `@backstage/plugin-search-react` instead
|
||||
*/
|
||||
export const SearchContextProvider = ({
|
||||
initialState = searchInitialState,
|
||||
children,
|
||||
}: PropsWithChildren<{ initialState?: SearchContextState }>) => {
|
||||
const searchApi = useApi(searchApiRef);
|
||||
const [pageCursor, setPageCursor] = useState<string | undefined>(
|
||||
initialState.pageCursor,
|
||||
);
|
||||
const [filters, setFilters] = useState<JsonObject>(initialState.filters);
|
||||
const [term, setTerm] = useState<string>(initialState.term);
|
||||
const [types, setTypes] = useState<string[]>(initialState.types);
|
||||
|
||||
const prevTerm = usePrevious(term);
|
||||
|
||||
const result = useAsync(
|
||||
() =>
|
||||
searchApi.query({
|
||||
term,
|
||||
filters,
|
||||
pageCursor,
|
||||
types,
|
||||
}),
|
||||
[term, filters, types, pageCursor],
|
||||
);
|
||||
|
||||
const hasNextPage =
|
||||
!result.loading && !result.error && result.value?.nextPageCursor;
|
||||
const hasPreviousPage =
|
||||
!result.loading && !result.error && result.value?.previousPageCursor;
|
||||
const fetchNextPage = useCallback(() => {
|
||||
setPageCursor(result.value?.nextPageCursor);
|
||||
}, [result.value?.nextPageCursor]);
|
||||
const fetchPreviousPage = useCallback(() => {
|
||||
setPageCursor(result.value?.previousPageCursor);
|
||||
}, [result.value?.previousPageCursor]);
|
||||
|
||||
useEffect(() => {
|
||||
// Any time a term is reset, we want to start from page 0.
|
||||
if (term && prevTerm && term !== prevTerm) {
|
||||
setPageCursor(undefined);
|
||||
}
|
||||
}, [term, prevTerm, initialState.pageCursor]);
|
||||
|
||||
const value: SearchContextValue = {
|
||||
result,
|
||||
filters,
|
||||
setFilters,
|
||||
term,
|
||||
setTerm,
|
||||
types,
|
||||
setTypes,
|
||||
pageCursor,
|
||||
setPageCursor,
|
||||
fetchNextPage: hasNextPage ? fetchNextPage : undefined,
|
||||
fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : undefined,
|
||||
};
|
||||
|
||||
return (
|
||||
<AnalyticsContext attributes={{ searchTypes: types.sort().join(',') }}>
|
||||
<SearchContext.Provider value={value} children={children} />
|
||||
</AnalyticsContext>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated import from "@backstage/plugin-search-react" instead
|
||||
*/
|
||||
export const useSearch = () => {
|
||||
const context = useContext(SearchContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useSearch must be used within a SearchContextProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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 {
|
||||
SearchContextProvider,
|
||||
SearchContext,
|
||||
useSearch,
|
||||
} from './SearchContext';
|
||||
|
||||
export type { SearchContextState } from './SearchContext';
|
||||
@@ -18,8 +18,11 @@ import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { screen, render, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { searchApiRef } from '../../apis';
|
||||
import { SearchContextProvider, useSearch } from '../SearchContext';
|
||||
import {
|
||||
SearchContextProvider,
|
||||
useSearch,
|
||||
searchApiRef,
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { SearchFilter } from './SearchFilter';
|
||||
|
||||
const SearchContextFilterSpy = ({ name }: { name: string }) => {
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
AutocompleteGetTagProps,
|
||||
AutocompleteRenderInputParams,
|
||||
} from '@material-ui/lab';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { useAsyncFilterValues, useDefaultFilterValue } from './hooks';
|
||||
import { SearchFilterComponentProps } from './SearchFilter';
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { screen, render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { SearchFilter } from './SearchFilter';
|
||||
|
||||
import { SearchContextProvider } from '../SearchContext';
|
||||
import { SearchContextProvider } from '@backstage/plugin-search-react';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
jest.mock('@backstage/core-plugin-api', () => ({
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
AutocompleteFilter,
|
||||
SearchAutocompleteFilterProps,
|
||||
} from './SearchFilter.Autocomplete';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { useAsyncFilterValues, useDefaultFilterValue } from './hooks';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
|
||||
@@ -17,9 +17,12 @@ import React from 'react';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { TestApiRegistry } from '@backstage/test-utils';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { SearchContextProvider, useSearch } from '../SearchContext';
|
||||
import {
|
||||
SearchContextProvider,
|
||||
useSearch,
|
||||
searchApiRef,
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { useDefaultFilterValue, useAsyncFilterValues } from './hooks';
|
||||
import { searchApiRef } from '../../apis';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import useAsyncFn from 'react-use/lib/useAsyncFn';
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
|
||||
/**
|
||||
* Utility hook for either asynchronously loading filter values from a given
|
||||
|
||||
@@ -21,7 +21,7 @@ import userEvent from '@testing-library/user-event';
|
||||
import { configApiRef } from '@backstage/core-plugin-api';
|
||||
import { ApiProvider, ConfigReader } from '@backstage/core-app-api';
|
||||
import { rootRouteRef } from '../../plugin';
|
||||
import { searchApiRef } from '../../apis';
|
||||
import { searchApiRef } from '@backstage/plugin-search-react';
|
||||
|
||||
import { SearchModal } from './SearchModal';
|
||||
|
||||
|
||||
@@ -31,7 +31,10 @@ import { makeStyles } from '@material-ui/core/styles';
|
||||
import { SearchBar } from '../SearchBar';
|
||||
import { DefaultResultListItem } from '../DefaultResultListItem';
|
||||
import { SearchResult } from '../SearchResult';
|
||||
import { SearchContextProvider, useSearch } from '../SearchContext';
|
||||
import {
|
||||
SearchContextProvider,
|
||||
useSearch,
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { SearchResultPager } from '../SearchResultPager';
|
||||
import { useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { Link, useContent } from '@backstage/core-components';
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import React from 'react';
|
||||
import { useLocation, useOutlet } from 'react-router';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { SearchPage } from './SearchPage';
|
||||
|
||||
jest.mock('react-router', () => ({
|
||||
@@ -33,8 +33,8 @@ const setTypesMock = jest.fn();
|
||||
const setFiltersMock = jest.fn();
|
||||
const setPageCursorMock = jest.fn();
|
||||
|
||||
jest.mock('../SearchContext', () => ({
|
||||
...jest.requireActual('../SearchContext'),
|
||||
jest.mock('@backstage/plugin-search-react', () => ({
|
||||
...jest.requireActual('@backstage/plugin-search-react'),
|
||||
SearchContextProvider: jest
|
||||
.fn()
|
||||
.mockImplementation(({ children }) => children),
|
||||
@@ -51,7 +51,7 @@ jest.mock('../SearchContext', () => ({
|
||||
}));
|
||||
|
||||
jest.mock('../LegacySearchPage', () => ({
|
||||
...jest.requireActual('../SearchContext'),
|
||||
...jest.requireActual('@backstage/plugin-search-react'),
|
||||
LegacySearchPage: jest.fn().mockReturnValue('LegacySearchPageMock'),
|
||||
}));
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ import React, { useEffect } from 'react';
|
||||
import usePrevious from 'react-use/lib/usePrevious';
|
||||
import qs from 'qs';
|
||||
import { useLocation, useOutlet } from 'react-router';
|
||||
import { SearchContextProvider, useSearch } from '../SearchContext';
|
||||
import {
|
||||
SearchContextProvider,
|
||||
useSearch,
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { LegacySearchPage } from '../LegacySearchPage';
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { SearchResult } from './SearchResult';
|
||||
|
||||
jest.mock('../SearchContext', () => ({
|
||||
...jest.requireActual('../SearchContext'),
|
||||
jest.mock('@backstage/plugin-search-react', () => ({
|
||||
...jest.requireActual('@backstage/plugin-search-react'),
|
||||
useSearch: jest.fn().mockReturnValue({
|
||||
result: {},
|
||||
}),
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from '@backstage/core-components';
|
||||
import { SearchResult } from '@backstage/plugin-search-common';
|
||||
import React from 'react';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
|
||||
type Props = {
|
||||
children: (results: { results: SearchResult[] }) => JSX.Element;
|
||||
|
||||
@@ -18,11 +18,11 @@ import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { SearchResultPager } from './SearchResultPager';
|
||||
|
||||
jest.mock('../SearchContext', () => ({
|
||||
...jest.requireActual('../SearchContext'),
|
||||
jest.mock('@backstage/plugin-search-react', () => ({
|
||||
...jest.requireActual('@backstage/plugin-search-react'),
|
||||
useSearch: jest.fn().mockReturnValue({
|
||||
result: {},
|
||||
}),
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Button, makeStyles } from '@material-ui/core';
|
||||
import ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';
|
||||
import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
|
||||
import React from 'react';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { useAnalytics } from '@backstage/core-plugin-api';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
|
||||
/**
|
||||
* Capture search event on term change.
|
||||
|
||||
@@ -15,29 +15,30 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { TestApiRegistry } from '@backstage/test-utils';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { act, render } from '@testing-library/react';
|
||||
import user from '@testing-library/user-event';
|
||||
|
||||
import { searchApiRef } from '../../apis';
|
||||
import { SearchContext, SearchContextProvider } from '../SearchContext';
|
||||
import {
|
||||
searchApiRef,
|
||||
SearchContextProvider,
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { SearchType } from './SearchType';
|
||||
|
||||
const setTypesMock = jest.fn();
|
||||
const setPageCursorMock = jest.fn();
|
||||
|
||||
jest.mock('@backstage/plugin-search-react', () => ({
|
||||
...jest.requireActual('@backstage/plugin-search-react'),
|
||||
useSearch: jest.fn().mockReturnValue({
|
||||
types: [],
|
||||
setTypes: (types: any) => setTypesMock(types),
|
||||
pageCursor: '',
|
||||
setPageCursor: (pageCursor: any) => setPageCursorMock(pageCursor),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('SearchType.Accordion', () => {
|
||||
const query = jest.fn();
|
||||
const mockApis = TestApiRegistry.from([searchApiRef, { query }]);
|
||||
|
||||
const contextSpy = {
|
||||
result: { loading: false, value: { results: [] } },
|
||||
term: '',
|
||||
types: [],
|
||||
filters: {},
|
||||
setTerm: jest.fn(),
|
||||
setTypes: jest.fn(),
|
||||
setFilters: jest.fn(),
|
||||
setPageCursor: jest.fn(),
|
||||
};
|
||||
|
||||
const expectedLabel = 'Expected Label';
|
||||
const expectedType = {
|
||||
@@ -50,17 +51,19 @@ describe('SearchType.Accordion', () => {
|
||||
query.mockResolvedValue({ results: [] });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<TestApiProvider apis={[[searchApiRef, { query }]]}>
|
||||
<SearchContextProvider>{children}</SearchContextProvider>
|
||||
</TestApiProvider>
|
||||
);
|
||||
};
|
||||
|
||||
it('should render as expected', async () => {
|
||||
const { getByText } = render(
|
||||
<ApiProvider apis={mockApis}>
|
||||
<SearchContextProvider>
|
||||
<SearchType.Accordion name={expectedLabel} types={[expectedType]} />
|
||||
</SearchContextProvider>
|
||||
</ApiProvider>,
|
||||
<Wrapper>
|
||||
<SearchType.Accordion name={expectedLabel} types={[expectedType]} />
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
// The given label should be rendered.
|
||||
@@ -80,49 +83,49 @@ describe('SearchType.Accordion', () => {
|
||||
|
||||
it('should set entire types array when a type is selected', async () => {
|
||||
const { getByText } = render(
|
||||
<SearchContext.Provider value={contextSpy}>
|
||||
<Wrapper>
|
||||
<SearchType.Accordion name={expectedLabel} types={[expectedType]} />
|
||||
</SearchContext.Provider>,
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
await user.click(getByText(expectedType.name));
|
||||
|
||||
expect(contextSpy.setTypes).toHaveBeenCalledWith([expectedType.value]);
|
||||
expect(setTypesMock).toHaveBeenCalledWith([expectedType.value]);
|
||||
});
|
||||
|
||||
it('should reset types array when all is selected', async () => {
|
||||
const { getByText } = render(
|
||||
<SearchContext.Provider value={contextSpy}>
|
||||
<Wrapper>
|
||||
<SearchType.Accordion
|
||||
name={expectedLabel}
|
||||
defaultValue={expectedType.value}
|
||||
types={[expectedType]}
|
||||
/>
|
||||
</SearchContext.Provider>,
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
await user.click(getByText('All'));
|
||||
|
||||
expect(contextSpy.setTypes).toHaveBeenCalledWith([]);
|
||||
expect(setTypesMock).toHaveBeenCalledWith([]);
|
||||
});
|
||||
|
||||
it('should reset page cursor when a new type is selected', async () => {
|
||||
const { getByText } = render(
|
||||
<SearchContext.Provider value={contextSpy}>
|
||||
<Wrapper>
|
||||
<SearchType.Accordion name={expectedLabel} types={[expectedType]} />
|
||||
</SearchContext.Provider>,
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
await user.click(getByText(expectedType.name));
|
||||
|
||||
expect(contextSpy.setPageCursor).toHaveBeenCalledWith(undefined);
|
||||
expect(setPageCursorMock).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
it('should collapse when a new type is selected', async () => {
|
||||
const { getByText, queryByText } = render(
|
||||
<SearchContext.Provider value={contextSpy}>
|
||||
<Wrapper>
|
||||
<SearchType.Accordion name={expectedLabel} types={[expectedType]} />
|
||||
</SearchContext.Provider>,
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
await user.click(getByText(expectedType.name));
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React, { cloneElement, Fragment, useEffect, useState } from 'react';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
|
||||
@@ -15,50 +15,49 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { TestApiRegistry } from '@backstage/test-utils';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { act, render } from '@testing-library/react';
|
||||
import user from '@testing-library/user-event';
|
||||
|
||||
import { searchApiRef } from '../../apis';
|
||||
import { SearchContext, SearchContextProvider } from '../SearchContext';
|
||||
import {
|
||||
SearchContextProvider,
|
||||
searchApiRef,
|
||||
} from '@backstage/plugin-search-react';
|
||||
import { SearchType } from './SearchType';
|
||||
|
||||
describe('SearchType.Tabs', () => {
|
||||
const query = jest.fn();
|
||||
const mockApis = TestApiRegistry.from([searchApiRef, { query }]);
|
||||
const setTypesMock = jest.fn();
|
||||
const setPageCursorMock = jest.fn();
|
||||
|
||||
const contextSpy = {
|
||||
result: { loading: false, value: { results: [] } },
|
||||
term: '',
|
||||
jest.mock('@backstage/plugin-search-react', () => ({
|
||||
...jest.requireActual('@backstage/plugin-search-react'),
|
||||
useSearch: jest.fn().mockReturnValue({
|
||||
types: [],
|
||||
filters: {},
|
||||
setTerm: jest.fn(),
|
||||
setTypes: jest.fn(),
|
||||
setFilters: jest.fn(),
|
||||
setPageCursor: jest.fn(),
|
||||
};
|
||||
setTypes: (types: any) => setTypesMock(types),
|
||||
pageCursor: '',
|
||||
setPageCursor: (pageCursor: any) => setPageCursorMock(pageCursor),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('SearchType.Tabs', () => {
|
||||
const query = jest.fn().mockResolvedValue({});
|
||||
|
||||
const expectedType = {
|
||||
value: 'expected-type',
|
||||
name: 'Expected Type',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
query.mockResolvedValue({ results: [] });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<TestApiProvider apis={[[searchApiRef, { query }]]}>
|
||||
<SearchContextProvider>{children}</SearchContextProvider>
|
||||
</TestApiProvider>
|
||||
);
|
||||
};
|
||||
|
||||
it('should render as expected', async () => {
|
||||
const { getByText } = render(
|
||||
<ApiProvider apis={mockApis}>
|
||||
<SearchContextProvider>
|
||||
<SearchType.Tabs types={[expectedType]} />
|
||||
</SearchContextProvider>
|
||||
</ApiProvider>,
|
||||
<Wrapper>
|
||||
<SearchType.Tabs types={[expectedType]} />
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
// The default "all" type should be rendered.
|
||||
@@ -72,40 +71,40 @@ describe('SearchType.Tabs', () => {
|
||||
|
||||
it('should set entire types array when a type is selected', async () => {
|
||||
const { getByText } = render(
|
||||
<SearchContext.Provider value={contextSpy}>
|
||||
<Wrapper>
|
||||
<SearchType.Tabs types={[expectedType]} />
|
||||
</SearchContext.Provider>,
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
await user.click(getByText(expectedType.name));
|
||||
|
||||
expect(contextSpy.setTypes).toHaveBeenCalledWith([expectedType.value]);
|
||||
expect(setTypesMock).toHaveBeenCalledWith([expectedType.value]);
|
||||
});
|
||||
|
||||
it('should reset types array when all is selected', async () => {
|
||||
const { getByText } = render(
|
||||
<SearchContext.Provider value={contextSpy}>
|
||||
<Wrapper>
|
||||
<SearchType.Tabs
|
||||
defaultValue={expectedType.value}
|
||||
types={[expectedType]}
|
||||
/>
|
||||
</SearchContext.Provider>,
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
await user.click(getByText('All'));
|
||||
|
||||
expect(contextSpy.setTypes).toHaveBeenCalledWith([]);
|
||||
expect(setTypesMock).toHaveBeenCalledWith([]);
|
||||
});
|
||||
|
||||
it('should reset page cursor when a new type is selected', async () => {
|
||||
const { getByText } = render(
|
||||
<SearchContext.Provider value={contextSpy}>
|
||||
<Wrapper>
|
||||
<SearchType.Tabs types={[expectedType]} />
|
||||
</SearchContext.Provider>,
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
await user.click(getByText(expectedType.name));
|
||||
|
||||
expect(contextSpy.setPageCursor).toHaveBeenCalledWith(undefined);
|
||||
expect(setPageCursorMock).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles, Tab, Tabs } from '@material-ui/core';
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useApi } from '@backstage/core-plugin-api';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { SearchContextProvider } from '../SearchContext';
|
||||
import { SearchContextProvider } from '@backstage/plugin-search-react';
|
||||
import { SearchType } from './SearchType';
|
||||
|
||||
jest.mock('@backstage/core-plugin-api', () => ({
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
SearchTypeAccordionProps,
|
||||
} from './SearchType.Accordion';
|
||||
import { SearchTypeTabs, SearchTypeTabsProps } from './SearchType.Tabs';
|
||||
import { useSearch } from '../SearchContext';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
label: {
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { searchApiRef } from './apis';
|
||||
export type { SearchApi } from './apis';
|
||||
|
||||
export { Filters, FiltersButton } from './components/Filters';
|
||||
export type { FiltersState } from './components/Filters';
|
||||
export type { HomePageSearchBarProps } from './components/HomePageComponent';
|
||||
@@ -31,8 +28,6 @@ export type {
|
||||
SearchBarBaseProps,
|
||||
SearchBarProps,
|
||||
} from './components/SearchBar';
|
||||
export { SearchContextProvider, useSearch } from './components/SearchContext';
|
||||
export type { SearchContextState } from './components/SearchContext';
|
||||
export { SearchFilter, SearchFilterNext } from './components/SearchFilter';
|
||||
export type {
|
||||
SearchAutocompleteFilterProps,
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { SearchClient, searchApiRef } from './apis';
|
||||
import { SearchClient } from './apis';
|
||||
import { searchApiRef } from '@backstage/plugin-search-react';
|
||||
import {
|
||||
createApiFactory,
|
||||
createPlugin,
|
||||
|
||||
Reference in New Issue
Block a user