@backstage/plugin-search-react 0.1.0-next.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/index.d.ts +40 -12
- package/dist/index.esm.js +27 -23
- package/dist/index.esm.js.map +1 -1
- package/package.json +8 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @backstage/plugin-search-react
|
|
2
2
|
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ab230a433f: New search package to hold things the search plugin itself and other frontend plugins (e.g. techdocs, home) depend on.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 7c7919777e: build(deps-dev): bump `@testing-library/react-hooks` from 7.0.2 to 8.0.0
|
|
12
|
+
- 076b091113: api-report clean up - the package now exports following additional types:
|
|
13
|
+
|
|
14
|
+
`SearchContextProviderProps`
|
|
15
|
+
`SearchContextValue`
|
|
16
|
+
`SearchContextProviderForStorybookProps`
|
|
17
|
+
`SearchApiProviderForStorybookProps`
|
|
18
|
+
|
|
19
|
+
- e1de8526aa: Versioned search context managed through version-bridge
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @backstage/core-app-api@1.0.1
|
|
22
|
+
- @backstage/core-plugin-api@1.0.1
|
|
23
|
+
- @backstage/version-bridge@1.0.1
|
|
24
|
+
- @backstage/plugin-search-common@0.3.3
|
|
25
|
+
|
|
3
26
|
## 0.1.0-next.0
|
|
4
27
|
|
|
5
28
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
2
2
|
import { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';
|
|
3
3
|
import { JsonObject } from '@backstage/types';
|
|
4
|
-
import React, {
|
|
4
|
+
import React, { PropsWithChildren, ComponentProps } from 'react';
|
|
5
5
|
import { AsyncState } from 'react-use/lib/useAsync';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -15,6 +15,10 @@ interface SearchApi {
|
|
|
15
15
|
query(query: SearchQuery): Promise<SearchResultSet>;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
18
22
|
declare type SearchContextValue = {
|
|
19
23
|
result: AsyncState<SearchResultSet>;
|
|
20
24
|
setTerm: React.Dispatch<React.SetStateAction<string>>;
|
|
@@ -35,30 +39,54 @@ declare type SearchContextState = {
|
|
|
35
39
|
pageCursor?: string;
|
|
36
40
|
};
|
|
37
41
|
/**
|
|
42
|
+
* @public
|
|
43
|
+
*
|
|
44
|
+
* React hook which provides the search context
|
|
45
|
+
*/
|
|
46
|
+
declare const useSearch: () => SearchContextValue;
|
|
47
|
+
/**
|
|
48
|
+
* Props for {@link SearchContextProvider}
|
|
49
|
+
*
|
|
38
50
|
* @public
|
|
39
51
|
*/
|
|
40
|
-
declare
|
|
41
|
-
initialState?: SearchContextState
|
|
42
|
-
}
|
|
52
|
+
declare type SearchContextProviderProps = PropsWithChildren<{
|
|
53
|
+
initialState?: SearchContextState;
|
|
54
|
+
}>;
|
|
43
55
|
/**
|
|
44
56
|
* @public
|
|
57
|
+
*
|
|
58
|
+
* Search context provider which gives you access to shared state between search components
|
|
45
59
|
*/
|
|
46
|
-
declare const
|
|
60
|
+
declare const SearchContextProvider: (props: SearchContextProviderProps) => JSX.Element;
|
|
47
61
|
|
|
48
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Props for {@link SearchApiProviderForStorybook}
|
|
64
|
+
* @public
|
|
65
|
+
*/
|
|
66
|
+
declare type SearchApiProviderForStorybookProps = ComponentProps<typeof SearchContextProvider> & {
|
|
49
67
|
mockedResults?: SearchResultSet;
|
|
50
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* Props for {@link SearchContextProviderForStorybook}
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
declare type SearchContextProviderForStorybookProps = PropsWithChildren<{
|
|
74
|
+
mockedResults?: SearchResultSet;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Utility api provider only for use in Storybook stories.
|
|
78
|
+
*
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
declare function SearchApiProviderForStorybook(props: SearchApiProviderForStorybookProps): JSX.Element;
|
|
51
82
|
/**
|
|
52
83
|
* Utility context provider only for use in Storybook stories. You should use
|
|
53
84
|
* the real `<SearchContextProvider>` exported by `@backstage/plugin-search-react` in
|
|
54
85
|
* your app instead of this! In some cases (like the search page) it may
|
|
55
86
|
* already be provided on your behalf.
|
|
56
|
-
*/
|
|
57
|
-
declare const SearchContextProvider: (props: ComponentProps<typeof SearchContextProvider$1> & QueryResultProps) => JSX.Element;
|
|
58
|
-
/**
|
|
59
|
-
* Utility api provider only for use in Storybook stories.
|
|
60
87
|
*
|
|
88
|
+
* @public
|
|
61
89
|
*/
|
|
62
|
-
declare
|
|
90
|
+
declare const SearchContextProviderForStorybook: (props: SearchContextProviderForStorybookProps) => JSX.Element;
|
|
63
91
|
|
|
64
|
-
export { SearchApi,
|
|
92
|
+
export { SearchApi, SearchApiProviderForStorybook, SearchApiProviderForStorybookProps, SearchContextProvider, SearchContextProviderForStorybook, SearchContextProviderForStorybookProps, SearchContextProviderProps, SearchContextState, SearchContextValue, searchApiRef, useSearch };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createApiRef, useApi, AnalyticsContext } from '@backstage/core-plugin-api';
|
|
2
|
-
import
|
|
2
|
+
import { createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
|
|
3
|
+
import React, { useContext, useState, useCallback, useEffect } from 'react';
|
|
3
4
|
import useAsync from 'react-use/lib/useAsync';
|
|
4
5
|
import usePrevious from 'react-use/lib/usePrevious';
|
|
5
6
|
import { ApiProvider } from '@backstage/core-app-api';
|
|
@@ -9,18 +10,27 @@ const searchApiRef = createApiRef({
|
|
|
9
10
|
id: "plugin.search.queryservice"
|
|
10
11
|
});
|
|
11
12
|
|
|
12
|
-
const SearchContext =
|
|
13
|
+
const SearchContext = createVersionedContext("search-context");
|
|
14
|
+
const useSearch = () => {
|
|
15
|
+
const context = useContext(SearchContext);
|
|
16
|
+
if (!context) {
|
|
17
|
+
throw new Error("useSearch must be used within a SearchContextProvider");
|
|
18
|
+
}
|
|
19
|
+
const value = context.atVersion(1);
|
|
20
|
+
if (!value) {
|
|
21
|
+
throw new Error("No SearchContext v1 found");
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
13
25
|
const searchInitialState = {
|
|
14
26
|
term: "",
|
|
15
27
|
pageCursor: void 0,
|
|
16
28
|
filters: {},
|
|
17
29
|
types: []
|
|
18
30
|
};
|
|
19
|
-
const SearchContextProvider
|
|
20
|
-
initialState = searchInitialState,
|
|
21
|
-
children
|
|
22
|
-
}) => {
|
|
31
|
+
const SearchContextProvider = (props) => {
|
|
23
32
|
var _a, _b, _c, _d;
|
|
33
|
+
const { initialState = searchInitialState, children } = props;
|
|
24
34
|
const searchApi = useApi(searchApiRef);
|
|
25
35
|
const [pageCursor, setPageCursor] = useState(initialState.pageCursor);
|
|
26
36
|
const [filters, setFilters] = useState(initialState.filters);
|
|
@@ -61,29 +71,16 @@ const SearchContextProvider$1 = ({
|
|
|
61
71
|
fetchNextPage: hasNextPage ? fetchNextPage : void 0,
|
|
62
72
|
fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : void 0
|
|
63
73
|
};
|
|
74
|
+
const versionedValue = createVersionedValueMap({ 1: value });
|
|
64
75
|
return /* @__PURE__ */ React.createElement(AnalyticsContext, {
|
|
65
76
|
attributes: { searchTypes: types.sort().join(",") }
|
|
66
77
|
}, /* @__PURE__ */ React.createElement(SearchContext.Provider, {
|
|
67
|
-
value,
|
|
78
|
+
value: versionedValue,
|
|
68
79
|
children
|
|
69
80
|
}));
|
|
70
81
|
};
|
|
71
|
-
const useSearch = () => {
|
|
72
|
-
const context = useContext(SearchContext);
|
|
73
|
-
if (context === void 0) {
|
|
74
|
-
throw new Error("useSearch must be used within a SearchContextProvider");
|
|
75
|
-
}
|
|
76
|
-
return context;
|
|
77
|
-
};
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
return /* @__PURE__ */ React.createElement(SearchApiProvider, {
|
|
81
|
-
...props
|
|
82
|
-
}, /* @__PURE__ */ React.createElement(SearchContextProvider$1, {
|
|
83
|
-
children: props.children
|
|
84
|
-
}));
|
|
85
|
-
};
|
|
86
|
-
function SearchApiProvider(props) {
|
|
83
|
+
function SearchApiProviderForStorybook(props) {
|
|
87
84
|
const { mockedResults, children } = props;
|
|
88
85
|
const query = () => Promise.resolve(mockedResults || {});
|
|
89
86
|
const apiRegistry = TestApiRegistry.from([searchApiRef, { query }]);
|
|
@@ -92,6 +89,13 @@ function SearchApiProvider(props) {
|
|
|
92
89
|
children
|
|
93
90
|
});
|
|
94
91
|
}
|
|
92
|
+
const SearchContextProviderForStorybook = (props) => {
|
|
93
|
+
return /* @__PURE__ */ React.createElement(SearchApiProviderForStorybook, {
|
|
94
|
+
...props
|
|
95
|
+
}, /* @__PURE__ */ React.createElement(SearchContextProvider, {
|
|
96
|
+
children: props.children
|
|
97
|
+
}));
|
|
98
|
+
};
|
|
95
99
|
|
|
96
|
-
export {
|
|
100
|
+
export { SearchApiProviderForStorybook, SearchContextProvider, SearchContextProviderForStorybook, searchApiRef, useSearch };
|
|
97
101
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/api.ts","../src/context/SearchContext.tsx","../src/context/SearchContextForStorybook.stories.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * @public\n */\nexport const searchApiRef = createApiRef<SearchApi>({\n id: 'plugin.search.queryservice',\n});\n\n/**\n * @public\n */\nexport interface SearchApi {\n query(query: SearchQuery): Promise<SearchResultSet>;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { useApi, AnalyticsContext } from '@backstage/core-plugin-api';\nimport { SearchResultSet } from '@backstage/plugin-search-common';\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport useAsync, { AsyncState } from 'react-use/lib/useAsync';\nimport usePrevious from 'react-use/lib/usePrevious';\nimport { searchApiRef } from '../api';\n\ntype SearchContextValue = {\n result: AsyncState<SearchResultSet>;\n setTerm: React.Dispatch<React.SetStateAction<string>>;\n setTypes: React.Dispatch<React.SetStateAction<string[]>>;\n setFilters: React.Dispatch<React.SetStateAction<JsonObject>>;\n setPageCursor: React.Dispatch<React.SetStateAction<string | undefined>>;\n fetchNextPage?: React.DispatchWithoutAction;\n fetchPreviousPage?: React.DispatchWithoutAction;\n} & SearchContextState;\n\n/**\n *\n * @public\n */\nexport type SearchContextState = {\n term: string;\n types: string[];\n filters: JsonObject;\n pageCursor?: string;\n};\n\n/**\n * @public\n */\nexport const SearchContext = createContext<SearchContextValue | undefined>(\n undefined,\n);\n\n/**\n * The initial state of `SearchContextProvider`.\n *\n */\nconst searchInitialState: SearchContextState = {\n term: '',\n pageCursor: undefined,\n filters: {},\n types: [],\n};\n\n/**\n * @public\n */\nexport const SearchContextProvider = ({\n initialState = searchInitialState,\n children,\n}: PropsWithChildren<{ initialState?: SearchContextState }>) => {\n const searchApi = useApi(searchApiRef);\n const [pageCursor, setPageCursor] = useState<string | undefined>(\n initialState.pageCursor,\n );\n const [filters, setFilters] = useState<JsonObject>(initialState.filters);\n const [term, setTerm] = useState<string>(initialState.term);\n const [types, setTypes] = useState<string[]>(initialState.types);\n\n const prevTerm = usePrevious(term);\n\n const result = useAsync(\n () =>\n searchApi.query({\n term,\n filters,\n pageCursor,\n types,\n }),\n [term, filters, types, pageCursor],\n );\n\n const hasNextPage =\n !result.loading && !result.error && result.value?.nextPageCursor;\n const hasPreviousPage =\n !result.loading && !result.error && result.value?.previousPageCursor;\n const fetchNextPage = useCallback(() => {\n setPageCursor(result.value?.nextPageCursor);\n }, [result.value?.nextPageCursor]);\n const fetchPreviousPage = useCallback(() => {\n setPageCursor(result.value?.previousPageCursor);\n }, [result.value?.previousPageCursor]);\n\n useEffect(() => {\n // Any time a term is reset, we want to start from page 0.\n if (term && prevTerm && term !== prevTerm) {\n setPageCursor(undefined);\n }\n }, [term, prevTerm, initialState.pageCursor]);\n\n const value: SearchContextValue = {\n result,\n filters,\n setFilters,\n term,\n setTerm,\n types,\n setTypes,\n pageCursor,\n setPageCursor,\n fetchNextPage: hasNextPage ? fetchNextPage : undefined,\n fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : undefined,\n };\n\n return (\n <AnalyticsContext attributes={{ searchTypes: types.sort().join(',') }}>\n <SearchContext.Provider value={value} children={children} />\n </AnalyticsContext>\n );\n};\n\n/**\n * @public\n */\nexport const useSearch = () => {\n const context = useContext(SearchContext);\n if (context === undefined) {\n throw new Error('useSearch must be used within a SearchContextProvider');\n }\n return context;\n};\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ApiProvider } from '@backstage/core-app-api';\nimport { SearchResultSet } from '@backstage/plugin-search-common';\nimport { TestApiRegistry } from '@backstage/test-utils';\nimport React, { ComponentProps, PropsWithChildren } from 'react';\nimport { searchApiRef } from '../api';\nimport { SearchContextProvider as RealSearchContextProvider } from './SearchContext';\n\ntype QueryResultProps = {\n mockedResults?: SearchResultSet;\n};\n\n/**\n * Utility context provider only for use in Storybook stories. You should use\n * the real `<SearchContextProvider>` exported by `@backstage/plugin-search-react` in\n * your app instead of this! In some cases (like the search page) it may\n * already be provided on your behalf.\n */\nexport const SearchContextProvider = (\n props: ComponentProps<typeof RealSearchContextProvider> & QueryResultProps,\n) => {\n return (\n <SearchApiProvider {...props}>\n <RealSearchContextProvider children={props.children} />\n </SearchApiProvider>\n );\n};\n\n/**\n * Utility api provider only for use in Storybook stories.\n *\n */\nexport function SearchApiProvider(props: PropsWithChildren<QueryResultProps>) {\n const { mockedResults, children } = props;\n const query: any = () => Promise.resolve(mockedResults || {});\n const apiRegistry = TestApiRegistry.from([searchApiRef, { query }]);\n return <ApiProvider apis={apiRegistry} children={children} />;\n}\n"],"names":["SearchContextProvider","RealSearchContextProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/api.ts","../src/context/SearchContext.tsx","../src/context/SearchContextForStorybook.stories.tsx"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';\nimport { createApiRef } from '@backstage/core-plugin-api';\n\n/**\n * @public\n */\nexport const searchApiRef = createApiRef<SearchApi>({\n id: 'plugin.search.queryservice',\n});\n\n/**\n * @public\n */\nexport interface SearchApi {\n query(query: SearchQuery): Promise<SearchResultSet>;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { useApi, AnalyticsContext } from '@backstage/core-plugin-api';\nimport { SearchResultSet } from '@backstage/plugin-search-common';\nimport {\n createVersionedContext,\n createVersionedValueMap,\n} from '@backstage/version-bridge';\nimport React, {\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport useAsync, { AsyncState } from 'react-use/lib/useAsync';\nimport usePrevious from 'react-use/lib/usePrevious';\nimport { searchApiRef } from '../api';\n\n/**\n *\n * @public\n */\nexport type SearchContextValue = {\n result: AsyncState<SearchResultSet>;\n setTerm: React.Dispatch<React.SetStateAction<string>>;\n setTypes: React.Dispatch<React.SetStateAction<string[]>>;\n setFilters: React.Dispatch<React.SetStateAction<JsonObject>>;\n setPageCursor: React.Dispatch<React.SetStateAction<string | undefined>>;\n fetchNextPage?: React.DispatchWithoutAction;\n fetchPreviousPage?: React.DispatchWithoutAction;\n} & SearchContextState;\n\n/**\n *\n * @public\n */\nexport type SearchContextState = {\n term: string;\n types: string[];\n filters: JsonObject;\n pageCursor?: string;\n};\n\nconst SearchContext = createVersionedContext<{\n 1: SearchContextValue;\n}>('search-context');\n\n/**\n * @public\n *\n * React hook which provides the search context\n */\nexport const useSearch = () => {\n const context = useContext(SearchContext);\n if (!context) {\n throw new Error('useSearch must be used within a SearchContextProvider');\n }\n\n const value = context.atVersion(1);\n if (!value) {\n throw new Error('No SearchContext v1 found');\n }\n return value;\n};\n\n/**\n * The initial state of `SearchContextProvider`.\n *\n */\nconst searchInitialState: SearchContextState = {\n term: '',\n pageCursor: undefined,\n filters: {},\n types: [],\n};\n\n/**\n * Props for {@link SearchContextProvider}\n *\n * @public\n */\nexport type SearchContextProviderProps = PropsWithChildren<{\n initialState?: SearchContextState;\n}>;\n\n/**\n * @public\n *\n * Search context provider which gives you access to shared state between search components\n */\nexport const SearchContextProvider = (props: SearchContextProviderProps) => {\n const { initialState = searchInitialState, children } = props;\n const searchApi = useApi(searchApiRef);\n const [pageCursor, setPageCursor] = useState<string | undefined>(\n initialState.pageCursor,\n );\n const [filters, setFilters] = useState<JsonObject>(initialState.filters);\n const [term, setTerm] = useState<string>(initialState.term);\n const [types, setTypes] = useState<string[]>(initialState.types);\n\n const prevTerm = usePrevious(term);\n\n const result = useAsync(\n () =>\n searchApi.query({\n term,\n filters,\n pageCursor,\n types,\n }),\n [term, filters, types, pageCursor],\n );\n\n const hasNextPage =\n !result.loading && !result.error && result.value?.nextPageCursor;\n const hasPreviousPage =\n !result.loading && !result.error && result.value?.previousPageCursor;\n const fetchNextPage = useCallback(() => {\n setPageCursor(result.value?.nextPageCursor);\n }, [result.value?.nextPageCursor]);\n const fetchPreviousPage = useCallback(() => {\n setPageCursor(result.value?.previousPageCursor);\n }, [result.value?.previousPageCursor]);\n\n useEffect(() => {\n // Any time a term is reset, we want to start from page 0.\n if (term && prevTerm && term !== prevTerm) {\n setPageCursor(undefined);\n }\n }, [term, prevTerm, initialState.pageCursor]);\n\n const value: SearchContextValue = {\n result,\n filters,\n setFilters,\n term,\n setTerm,\n types,\n setTypes,\n pageCursor,\n setPageCursor,\n fetchNextPage: hasNextPage ? fetchNextPage : undefined,\n fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : undefined,\n };\n\n const versionedValue = createVersionedValueMap({ 1: value });\n\n return (\n <AnalyticsContext attributes={{ searchTypes: types.sort().join(',') }}>\n <SearchContext.Provider value={versionedValue} children={children} />\n </AnalyticsContext>\n );\n};\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ApiProvider } from '@backstage/core-app-api';\nimport { SearchResultSet } from '@backstage/plugin-search-common';\nimport { TestApiRegistry } from '@backstage/test-utils';\nimport React, { ComponentProps, PropsWithChildren } from 'react';\nimport { searchApiRef } from '../api';\nimport { SearchContextProvider } from './SearchContext';\n\n/**\n * Props for {@link SearchApiProviderForStorybook}\n * @public\n */\nexport type SearchApiProviderForStorybookProps = ComponentProps<\n typeof SearchContextProvider\n> & {\n mockedResults?: SearchResultSet;\n};\n\n/**\n * Props for {@link SearchContextProviderForStorybook}\n * @public\n */\nexport type SearchContextProviderForStorybookProps = PropsWithChildren<{\n mockedResults?: SearchResultSet;\n}>;\n\n/**\n * Utility api provider only for use in Storybook stories.\n *\n * @public\n */\nexport function SearchApiProviderForStorybook(\n props: SearchApiProviderForStorybookProps,\n) {\n const { mockedResults, children } = props;\n const query: any = () => Promise.resolve(mockedResults || {});\n const apiRegistry = TestApiRegistry.from([searchApiRef, { query }]);\n return <ApiProvider apis={apiRegistry} children={children} />;\n}\n\n/**\n * Utility context provider only for use in Storybook stories. You should use\n * the real `<SearchContextProvider>` exported by `@backstage/plugin-search-react` in\n * your app instead of this! In some cases (like the search page) it may\n * already be provided on your behalf.\n *\n * @public\n */\nexport const SearchContextProviderForStorybook = (\n props: SearchContextProviderForStorybookProps,\n) => {\n return (\n <SearchApiProviderForStorybook {...props}>\n <SearchContextProvider children={props.children} />\n </SearchApiProviderForStorybook>\n );\n};\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-search-react",
|
|
3
|
-
"version": "0.1.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"main": "dist/index.esm.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,10 +31,11 @@
|
|
|
31
31
|
"start": "backstage-cli package start"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@backstage/core-app-api": "^1.0.1
|
|
35
|
-
"@backstage/core-plugin-api": "^1.0.1
|
|
36
|
-
"@backstage/plugin-search-common": "^0.3.3
|
|
34
|
+
"@backstage/core-app-api": "^1.0.1",
|
|
35
|
+
"@backstage/core-plugin-api": "^1.0.1",
|
|
36
|
+
"@backstage/plugin-search-common": "^0.3.3",
|
|
37
37
|
"@backstage/types": "^1.0.0",
|
|
38
|
+
"@backstage/version-bridge": "^1.0.1",
|
|
38
39
|
"react-use": "^17.3.2"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
@@ -42,13 +43,13 @@
|
|
|
42
43
|
"react": "^16.13.1 || ^17.0.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
|
-
"@backstage/test-utils": "^1.0.1
|
|
46
|
+
"@backstage/test-utils": "^1.0.1",
|
|
46
47
|
"@testing-library/jest-dom": "^5.10.1",
|
|
47
48
|
"@testing-library/react": "^12.1.3",
|
|
48
|
-
"@testing-library/react-hooks": "^
|
|
49
|
+
"@testing-library/react-hooks": "^8.0.0"
|
|
49
50
|
},
|
|
50
51
|
"files": [
|
|
51
52
|
"dist"
|
|
52
53
|
],
|
|
53
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "e0e44c433319711c2fb8b175db411a621f7aaec2"
|
|
54
55
|
}
|