@backstage/plugin-search-react 1.1.0-next.2 → 1.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 CHANGED
@@ -1,5 +1,361 @@
1
1
  # @backstage/plugin-search-react
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 97f2b8f3fd: The `<SearchResult/>` component now accepts a optional `query` prop to request results from the search api:
8
+
9
+ > Note: If a query prop is not defined, the results will by default be consumed from the context.
10
+
11
+ Example:
12
+
13
+ ```jsx
14
+ import React, { useState, useCallback } from 'react';
15
+
16
+ import { Grid, List, Paper } from '@material-ui/core';
17
+
18
+ import { Page, Header, Content, Lifecycle } from '@backstage/core-components';
19
+ import {
20
+ DefaultResultListItem,
21
+ SearchBarBase,
22
+ SearchResult,
23
+ } from '@backstage/plugin-search-react';
24
+
25
+ const SearchPage = () => {
26
+ const [query, setQuery] = useState({
27
+ term: '',
28
+ types: [],
29
+ filters: {},
30
+ });
31
+
32
+ const handleChange = useCallback(
33
+ (term: string) => {
34
+ setQuery(prevQuery => ({ ...prevQuery, term }));
35
+ },
36
+ [setQuery],
37
+ );
38
+
39
+ return (
40
+ <Page themeId="home">
41
+ <Header title="Search" subtitle={<Lifecycle alpha />} />
42
+ <Content>
43
+ <Grid container direction="row">
44
+ <Grid item xs={12}>
45
+ <Paper>
46
+ <SearchBarBase debounceTime={100} onChange={handleChange} />
47
+ </Paper>
48
+ </Grid>
49
+ <Grid item xs>
50
+ <SearchResult query={query}>
51
+ {({ results }) => (
52
+ <List>
53
+ {results.map(({ document }) => (
54
+ <DefaultResultListItem
55
+ key={document.location}
56
+ result={document}
57
+ />
58
+ ))}
59
+ </List>
60
+ )}
61
+ </SearchResult>
62
+ </Grid>
63
+ </Grid>
64
+ </Content>
65
+ </Page>
66
+ );
67
+ };
68
+ ```
69
+
70
+ Additionally, a search page can also be composed using these two new results layout components:
71
+
72
+ ```jsx
73
+ // Example rendering results as list
74
+ <SearchResult>
75
+ {({ results }) => (
76
+ <SearchResultListLayout
77
+ resultItems={results}
78
+ renderResultItem={({ type, document }) => {
79
+ switch (type) {
80
+ case 'custom-result-item':
81
+ return (
82
+ <CustomResultListItem
83
+ key={document.location}
84
+ result={document}
85
+ />
86
+ );
87
+ default:
88
+ return (
89
+ <DefaultResultListItem
90
+ key={document.location}
91
+ result={document}
92
+ />
93
+ );
94
+ }
95
+ }}
96
+ />
97
+ )}
98
+ </SearchResult>
99
+ ```
100
+
101
+ ```jsx
102
+ // Example rendering results as groups
103
+ <SearchResult>
104
+ {({ results }) => (
105
+ <>
106
+ <SearchResultGroupLayout
107
+ icon={<CustomIcon />}
108
+ title="Custom"
109
+ link="See all custom results"
110
+ resultItems={results.filter(
111
+ ({ type }) => type === 'custom-result-item',
112
+ )}
113
+ renderResultItem={({ document }) => (
114
+ <CustomResultListItem key={document.location} result={document} />
115
+ )}
116
+ />
117
+ <SearchResultGroupLayout
118
+ icon={<DefaultIcon />}
119
+ title="Default"
120
+ resultItems={results.filter(
121
+ ({ type }) => type !== 'custom-result-item',
122
+ )}
123
+ renderResultItem={({ document }) => (
124
+ <DefaultResultListItem key={document.location} result={document} />
125
+ )}
126
+ />
127
+ </>
128
+ )}
129
+ </SearchResult>
130
+ ```
131
+
132
+ A `SearchResultList` and `SearchResultGroup` components were also created for users who have search pages with multiple queries, both are specializations of `SearchResult` and also accept a `query` as a prop as well:
133
+
134
+ ```jsx
135
+ // Example using the <SearchResultList />
136
+ const SearchPage = () => {
137
+ const query = {
138
+ term: 'example',
139
+ };
140
+
141
+ return (
142
+ <SearchResultList
143
+ query={query}
144
+ renderResultItem={({ type, document, highlight, rank }) => {
145
+ switch (type) {
146
+ case 'custom':
147
+ return (
148
+ <CustomResultListItem
149
+ key={document.location}
150
+ icon={<CatalogIcon />}
151
+ result={document}
152
+ highlight={highlight}
153
+ rank={rank}
154
+ />
155
+ );
156
+ default:
157
+ return (
158
+ <DefaultResultListItem
159
+ key={document.location}
160
+ result={document}
161
+ />
162
+ );
163
+ }
164
+ }}
165
+ />
166
+ );
167
+ };
168
+ ```
169
+
170
+ ```jsx
171
+ // Example using the <SearchResultGroup /> for creating a component that search and group software catalog results
172
+ import React, { useState, useCallback } from 'react';
173
+
174
+ import { MenuItem } from '@material-ui/core';
175
+
176
+ import { JsonValue } from '@backstage/types';
177
+ import { CatalogIcon } from '@backstage/core-components';
178
+ import { CatalogSearchResultListItem } from '@backstage/plugin-catalog';
179
+ import {
180
+ SearchResultGroup,
181
+ SearchResultGroupTextFilterField,
182
+ SearchResultGroupSelectFilterField,
183
+ } from @backstage/plugin-search-react;
184
+ import { SearchQuery } from '@backstage/plugin-search-common';
185
+
186
+ const CatalogResultsGroup = () => {
187
+ const [query, setQuery] = useState<Partial<SearchQuery>>({
188
+ types: ['software-catalog'],
189
+ });
190
+
191
+ const filterOptions = [
192
+ {
193
+ label: 'Lifecycle',
194
+ value: 'lifecycle',
195
+ },
196
+ {
197
+ label: 'Owner',
198
+ value: 'owner',
199
+ },
200
+ ];
201
+
202
+ const handleFilterAdd = useCallback(
203
+ (key: string) => () => {
204
+ setQuery(prevQuery => {
205
+ const { filters: prevFilters, ...rest } = prevQuery;
206
+ const newFilters = { ...prevFilters, [key]: undefined };
207
+ return { ...rest, filters: newFilters };
208
+ });
209
+ },
210
+ [],
211
+ );
212
+
213
+ const handleFilterChange = useCallback(
214
+ (key: string) => (value: JsonValue) => {
215
+ setQuery(prevQuery => {
216
+ const { filters: prevFilters, ...rest } = prevQuery;
217
+ const newFilters = { ...prevFilters, [key]: value };
218
+ return { ...rest, filters: newFilters };
219
+ });
220
+ },
221
+ [],
222
+ );
223
+
224
+ const handleFilterDelete = useCallback(
225
+ (key: string) => () => {
226
+ setQuery(prevQuery => {
227
+ const { filters: prevFilters, ...rest } = prevQuery;
228
+ const newFilters = { ...prevFilters };
229
+ delete newFilters[key];
230
+ return { ...rest, filters: newFilters };
231
+ });
232
+ },
233
+ [],
234
+ );
235
+
236
+ return (
237
+ <SearchResultGroup
238
+ query={query}
239
+ icon={<CatalogIcon />}
240
+ title="Software Catalog"
241
+ link="See all software catalog results"
242
+ filterOptions={filterOptions}
243
+ renderFilterOption={({ label, value }) => (
244
+ <MenuItem key={value} onClick={handleFilterAdd(value)}>
245
+ {label}
246
+ </MenuItem>
247
+ )}
248
+ renderFilterField={(key: string) => {
249
+ switch (key) {
250
+ case 'lifecycle':
251
+ return (
252
+ <SearchResultGroupSelectFilterField
253
+ key={key}
254
+ label="Lifecycle"
255
+ value={query.filters?.lifecycle}
256
+ onChange={handleFilterChange('lifecycle')}
257
+ onDelete={handleFilterDelete('lifecycle')}
258
+ >
259
+ <MenuItem value="production">Production</MenuItem>
260
+ <MenuItem value="experimental">Experimental</MenuItem>
261
+ </SearchResultGroupSelectFilterField>
262
+ );
263
+ case 'owner':
264
+ return (
265
+ <SearchResultGroupTextFilterField
266
+ key={key}
267
+ label="Owner"
268
+ value={query.filters?.owner}
269
+ onChange={handleFilterChange('owner')}
270
+ onDelete={handleFilterDelete('owner')}
271
+ />
272
+ );
273
+ default:
274
+ return null;
275
+ }
276
+ }
277
+ renderResultItem={({ document, highlight, rank }) => (
278
+ <CatalogSearchResultListItem
279
+ key={document.location}
280
+ result={document}
281
+ highlight={highlight}
282
+ rank={rank}
283
+ />
284
+ )}
285
+ />
286
+ );
287
+ };
288
+ ```
289
+
290
+ - 18f60427f2: Provides search autocomplete functionality through a `SearchAutocomplete` component.
291
+ A `SearchAutocompleteDefaultOption` can also be used to render options with icons, primary texts, and secondary texts.
292
+ Example:
293
+
294
+ ```jsx
295
+ import React, { ChangeEvent, useState, useCallback } from 'react';
296
+ import useAsync from 'react-use/lib/useAsync';
297
+
298
+ import { Grid, Paper } from '@material-ui/core';
299
+
300
+ import { Page, Content } from '@backstage/core-components';
301
+ import { SearchAutocomplete, SearchAutocompleteDefaultOption} from '@backstage/plugin-search-react';
302
+
303
+ const OptionsIcon = () => <svg />
304
+
305
+ const SearchPage = () => {
306
+ const [inputValue, setInputValue] = useState('');
307
+
308
+ const options = useAsync(async () => {
309
+ // Gets and returns autocomplete options
310
+ }, [inputValue])
311
+
312
+ const useCallback((_event: ChangeEvent<{}>, newInputValue: string) => {
313
+ setInputValue(newInputValue);
314
+ }, [setInputValue])
315
+
316
+ return (
317
+ <Page themeId="home">
318
+ <Content>
319
+ <Grid container direction="row">
320
+ <Grid item xs={12}>
321
+ <Paper>
322
+ <SearchAutocomplete
323
+ options={options}
324
+ inputValue={inputValue}
325
+ inputDebounceTime={100}
326
+ onInputChange={handleInputChange}
327
+ getOptionLabel={option => option.title}
328
+ renderOption={option => (
329
+ <SearchAutocompleteDefaultOption
330
+ icon={<OptionIcon />}
331
+ primaryText={option.title}
332
+ secondaryText={option.text}
333
+ />
334
+ )}
335
+ />
336
+ </Paper>
337
+ </Grid>
338
+ </Grid>
339
+ {'/* Filters and results are omitted */'}
340
+ </Content>
341
+ </Page>
342
+ );
343
+ };
344
+ ```
345
+
346
+ - ca8d5a6eae: We noticed a repeated check for the existence of a parent context before creating a child search context in more the one component such as Search Modal and Search Bar and to remove code duplication we extract the conditional to the context provider, now you can use it passing an `inheritParentContextIfAvailable` prop to the `SearchContextProvider`.
347
+
348
+ Note: This added property does not create a local context if there is a parent context and in this case, you cannot use it together with `initialState`, it will result in a type error because the parent context is already initialized.
349
+
350
+ ### Patch Changes
351
+
352
+ - 817f3196f6: Updated React Router dependencies to be peer dependencies.
353
+ - d3737da337: Reset page cursor on search filter change
354
+ - Updated dependencies
355
+ - @backstage/core-components@0.11.1
356
+ - @backstage/core-plugin-api@1.0.6
357
+ - @backstage/plugin-search-common@1.0.1
358
+
3
359
  ## 1.1.0-next.2
4
360
 
5
361
  ### Minor Changes