@backstage/plugin-search 0.4.18 → 0.5.3

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.
@@ -1,15 +1,15 @@
1
- import { createApiRef, useApi, configApiRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, createRoutableExtension, createComponentExtension, useRouteRef } from '@backstage/core-plugin-api';
1
+ import { createApiRef, useApi, AnalyticsContext, useAnalytics, configApiRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, identityApiRef, createRoutableExtension, createComponentExtension, useRouteRef } from '@backstage/core-plugin-api';
2
2
  import { ResponseError } from '@backstage/errors';
3
3
  import qs from 'qs';
4
4
  import * as React from 'react';
5
- import React__default, { createContext, useState, useCallback, useEffect, useContext } from 'react';
6
- import { ListItem, ListItemText, Divider, makeStyles, IconButton, Typography, Card, CardHeader, Button, CardContent, Select, MenuItem, List, Checkbox, InputBase, InputAdornment, FormControl, FormLabel, FormControlLabel, InputLabel, Dialog, DialogTitle, Paper, DialogContent, Grid, DialogActions, Chip } from '@material-ui/core';
7
- import { Link, Progress, ResponseErrorPanel, EmptyState, Table, useQueryParamState, Page, Header, Content, SidebarSearchField } from '@backstage/core-components';
5
+ import React__default, { createContext, useState, useCallback, useEffect, useContext, Fragment, cloneElement } from 'react';
8
6
  import FilterListIcon from '@material-ui/icons/FilterList';
7
+ import { makeStyles, IconButton, Typography, Card, CardHeader, Button, Divider, CardContent, Select, MenuItem, List, ListItem, Checkbox, ListItemText, InputBase, InputAdornment, FormControl, FormLabel, FormControlLabel, InputLabel, ListItemIcon, Box, Dialog, DialogTitle, Paper, DialogContent, Grid, DialogActions, Accordion, AccordionSummary, AccordionDetails, Chip } from '@material-ui/core';
9
8
  import { usePrevious, useAsync, useDebounce, useEffectOnce } from 'react-use';
10
9
  import SearchIcon from '@material-ui/icons/Search';
11
10
  import ClearButton from '@material-ui/icons/Clear';
12
11
  import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
12
+ import { Link, Progress, ResponseErrorPanel, EmptyState, Table, useQueryParamState, Page, Header, Content, SidebarSearchField } from '@backstage/core-components';
13
13
  import ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';
14
14
  import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
15
15
  import { createSvgIcon } from '@material-ui/core/utils';
@@ -19,11 +19,12 @@ import IconButton$1 from '@material-ui/core/IconButton';
19
19
  import { Alert } from '@material-ui/lab';
20
20
  import { catalogApiRef } from '@backstage/plugin-catalog-react';
21
21
  import { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';
22
+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
23
+ import AllIcon from '@material-ui/icons/FontDownload';
22
24
  import { useNavigate } from 'react-router-dom';
23
25
 
24
26
  const searchApiRef = createApiRef({
25
- id: "plugin.search.queryservice",
26
- description: "Used to make requests against the search API"
27
+ id: "plugin.search.queryservice"
27
28
  });
28
29
  class SearchClient {
29
30
  constructor(options) {
@@ -35,7 +36,7 @@ class SearchClient {
35
36
  const queryString = qs.stringify(query);
36
37
  const url = `${await this.discoveryApi.getBaseUrl("search/query")}?${queryString}`;
37
38
  const response = await fetch(url, {
38
- headers: token ? {Authorization: `Bearer ${token}`} : {}
39
+ headers: token ? { Authorization: `Bearer ${token}` } : {}
39
40
  });
40
41
  if (!response.ok) {
41
42
  throw await ResponseError.fromResponse(response);
@@ -44,19 +45,7 @@ class SearchClient {
44
45
  }
45
46
  }
46
47
 
47
- const DefaultResultListItem$1 = ({result}) => {
48
- return /* @__PURE__ */ React__default.createElement(Link, {
49
- to: result.location
50
- }, /* @__PURE__ */ React__default.createElement(ListItem, {
51
- alignItems: "flex-start"
52
- }, /* @__PURE__ */ React__default.createElement(ListItemText, {
53
- primaryTypographyProps: {variant: "h6"},
54
- primary: result.title,
55
- secondary: result.text
56
- })), /* @__PURE__ */ React__default.createElement(Divider, null));
57
- };
58
-
59
- const useStyles$9 = makeStyles((theme) => ({
48
+ const useStyles$a = makeStyles((theme) => ({
60
49
  filters: {
61
50
  width: "250px",
62
51
  display: "flex"
@@ -69,7 +58,7 @@ const FiltersButton$1 = ({
69
58
  numberOfSelectedFilters,
70
59
  handleToggleFilters
71
60
  }) => {
72
- const classes = useStyles$9();
61
+ const classes = useStyles$a();
73
62
  return /* @__PURE__ */ React__default.createElement("div", {
74
63
  className: classes.filters
75
64
  }, /* @__PURE__ */ React__default.createElement(IconButton, {
@@ -81,7 +70,7 @@ const FiltersButton$1 = ({
81
70
  }, "Filters (", numberOfSelectedFilters ? numberOfSelectedFilters : 0, ")"));
82
71
  };
83
72
 
84
- const useStyles$8 = makeStyles((theme) => ({
73
+ const useStyles$9 = makeStyles((theme) => ({
85
74
  filters: {
86
75
  background: "transparent",
87
76
  boxShadow: "0px 0px 0px 0px"
@@ -100,7 +89,7 @@ const Filters$1 = ({
100
89
  updateSelected,
101
90
  updateChecked
102
91
  }) => {
103
- const classes = useStyles$8();
92
+ const classes = useStyles$9();
104
93
  return /* @__PURE__ */ React__default.createElement(Card, {
105
94
  className: classes.filters
106
95
  }, /* @__PURE__ */ React__default.createElement(CardHeader, {
@@ -170,6 +159,8 @@ const SearchContextProvider = ({
170
159
  const [filters, setFilters] = useState(initialState.filters);
171
160
  const [term, setTerm] = useState(initialState.term);
172
161
  const [types, setTypes] = useState(initialState.types);
162
+ const [open, setOpen] = useState(false);
163
+ const toggleModal = useCallback(() => setOpen((prevState) => !prevState), []);
173
164
  const prevTerm = usePrevious(term);
174
165
  const result = useAsync(() => searchApi.query({
175
166
  term,
@@ -196,6 +187,8 @@ const SearchContextProvider = ({
196
187
  result,
197
188
  filters,
198
189
  setFilters,
190
+ open,
191
+ toggleModal,
199
192
  term,
200
193
  setTerm,
201
194
  types,
@@ -205,10 +198,12 @@ const SearchContextProvider = ({
205
198
  fetchNextPage: hasNextPage ? fetchNextPage : void 0,
206
199
  fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : void 0
207
200
  };
208
- return /* @__PURE__ */ React__default.createElement(SearchContext.Provider, {
201
+ return /* @__PURE__ */ React__default.createElement(AnalyticsContext, {
202
+ attributes: { searchTypes: types.sort().join(",") }
203
+ }, /* @__PURE__ */ React__default.createElement(SearchContext.Provider, {
209
204
  value,
210
205
  children
211
- });
206
+ }));
212
207
  };
213
208
  const useSearch = () => {
214
209
  const context = useContext(SearchContext);
@@ -218,75 +213,91 @@ const useSearch = () => {
218
213
  return context;
219
214
  };
220
215
 
216
+ const TrackSearch = ({ children }) => {
217
+ const analytics = useAnalytics();
218
+ const { term } = useSearch();
219
+ useEffect(() => {
220
+ if (term) {
221
+ analytics.captureEvent("search", term);
222
+ }
223
+ }, [analytics, term]);
224
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children);
225
+ };
226
+
221
227
  const SearchBarBase = ({
222
- autoFocus,
223
- value,
224
228
  onChange,
229
+ onKeyDown,
225
230
  onSubmit,
226
- className,
227
- placeholder: overridePlaceholder
231
+ debounceTime = 200,
232
+ clearButton = true,
233
+ fullWidth = true,
234
+ value: defaultValue,
235
+ inputProps: defaultInputProps = {},
236
+ endAdornment: defaultEndAdornment,
237
+ ...props
228
238
  }) => {
229
239
  const configApi = useApi(configApiRef);
230
- const onKeyDown = React__default.useCallback((e) => {
240
+ const [value, setValue] = useState(defaultValue);
241
+ useEffect(() => {
242
+ setValue((prevValue) => prevValue !== defaultValue ? defaultValue : prevValue);
243
+ }, [defaultValue]);
244
+ useDebounce(() => onChange(value), debounceTime, [value]);
245
+ const handleChange = useCallback((e) => {
246
+ setValue(e.target.value);
247
+ }, [setValue]);
248
+ const handleKeyDown = useCallback((e) => {
249
+ if (onKeyDown)
250
+ onKeyDown(e);
231
251
  if (onSubmit && e.key === "Enter") {
232
252
  onSubmit();
233
253
  }
234
- }, [onSubmit]);
235
- const handleClear = React__default.useCallback(() => {
254
+ }, [onKeyDown, onSubmit]);
255
+ const handleClear = useCallback(() => {
236
256
  onChange("");
237
257
  }, [onChange]);
238
- const placeholder = overridePlaceholder != null ? overridePlaceholder : `Search in ${configApi.getOptionalString("app.title") || "Backstage"}`;
239
- return /* @__PURE__ */ React__default.createElement(InputBase, {
240
- autoFocus,
258
+ const placeholder = `Search in ${configApi.getOptionalString("app.title") || "Backstage"}`;
259
+ const startAdornment = /* @__PURE__ */ React__default.createElement(InputAdornment, {
260
+ position: "start"
261
+ }, /* @__PURE__ */ React__default.createElement(IconButton, {
262
+ "aria-label": "Query",
263
+ disabled: true
264
+ }, /* @__PURE__ */ React__default.createElement(SearchIcon, null)));
265
+ const endAdornment = /* @__PURE__ */ React__default.createElement(InputAdornment, {
266
+ position: "end"
267
+ }, /* @__PURE__ */ React__default.createElement(IconButton, {
268
+ "aria-label": "Clear",
269
+ onClick: handleClear
270
+ }, /* @__PURE__ */ React__default.createElement(ClearButton, null)));
271
+ return /* @__PURE__ */ React__default.createElement(TrackSearch, null, /* @__PURE__ */ React__default.createElement(InputBase, {
241
272
  "data-testid": "search-bar-next",
242
- fullWidth: true,
243
- placeholder,
244
273
  value,
245
- onChange: (e) => onChange(e.target.value),
246
- inputProps: {"aria-label": "Search"},
247
- startAdornment: /* @__PURE__ */ React__default.createElement(InputAdornment, {
248
- position: "start"
249
- }, /* @__PURE__ */ React__default.createElement(IconButton, {
250
- "aria-label": "Query",
251
- disabled: true
252
- }, /* @__PURE__ */ React__default.createElement(SearchIcon, null))),
253
- endAdornment: /* @__PURE__ */ React__default.createElement(InputAdornment, {
254
- position: "end"
255
- }, /* @__PURE__ */ React__default.createElement(IconButton, {
256
- "aria-label": "Clear",
257
- onClick: handleClear
258
- }, /* @__PURE__ */ React__default.createElement(ClearButton, null))),
259
- ...className && {className},
260
- ...onSubmit && {onKeyDown}
261
- });
274
+ placeholder,
275
+ startAdornment,
276
+ endAdornment: clearButton ? endAdornment : defaultEndAdornment,
277
+ inputProps: { "aria-label": "Search", ...defaultInputProps },
278
+ fullWidth,
279
+ onChange: handleChange,
280
+ onKeyDown: handleKeyDown,
281
+ ...props
282
+ }));
262
283
  };
263
- const SearchBar$1 = ({
264
- autoFocus,
265
- className,
266
- debounceTime = 0,
267
- placeholder
268
- }) => {
269
- const {term, setTerm} = useSearch();
270
- const [value, setValue] = useState(term);
271
- useEffect(() => {
272
- setValue((prevValue) => prevValue !== term ? term : prevValue);
273
- }, [term]);
274
- useDebounce(() => setTerm(value), debounceTime, [value]);
275
- const handleQuery = (newValue) => {
276
- setValue(newValue);
284
+ const SearchBar$1 = ({ onChange, ...props }) => {
285
+ const { term, setTerm } = useSearch();
286
+ const handleChange = (newValue) => {
287
+ if (onChange) {
288
+ onChange(newValue);
289
+ } else {
290
+ setTerm(newValue);
291
+ }
277
292
  };
278
- const handleClear = () => setValue("");
279
293
  return /* @__PURE__ */ React__default.createElement(SearchBarBase, {
280
- autoFocus,
281
- className,
282
- value,
283
- onChange: handleQuery,
284
- onClear: handleClear,
285
- placeholder
294
+ value: term,
295
+ onChange: handleChange,
296
+ ...props
286
297
  });
287
298
  };
288
299
 
289
- const useStyles$7 = makeStyles({
300
+ const useStyles$8 = makeStyles({
290
301
  label: {
291
302
  textTransform: "capitalize"
292
303
  }
@@ -297,8 +308,8 @@ const CheckboxFilter = ({
297
308
  defaultValue,
298
309
  values = []
299
310
  }) => {
300
- const classes = useStyles$7();
301
- const {filters, setFilters} = useSearch();
311
+ const classes = useStyles$8();
312
+ const { filters, setFilters } = useSearch();
302
313
  useEffect(() => {
303
314
  if (Array.isArray(defaultValue)) {
304
315
  setFilters((prevFilters) => ({
@@ -309,13 +320,13 @@ const CheckboxFilter = ({
309
320
  }, []);
310
321
  const handleChange = (e) => {
311
322
  const {
312
- target: {value, checked}
323
+ target: { value, checked }
313
324
  } = e;
314
325
  setFilters((prevFilters) => {
315
- const {[name]: filter, ...others} = prevFilters;
326
+ const { [name]: filter, ...others } = prevFilters;
316
327
  const rest = (filter || []).filter((i) => i !== value);
317
328
  const items = checked ? [...rest, value] : rest;
318
- return items.length ? {...others, [name]: items} : others;
329
+ return items.length ? { ...others, [name]: items } : others;
319
330
  });
320
331
  };
321
332
  return /* @__PURE__ */ React__default.createElement(FormControl, {
@@ -331,7 +342,7 @@ const CheckboxFilter = ({
331
342
  control: /* @__PURE__ */ React__default.createElement(Checkbox, {
332
343
  color: "primary",
333
344
  tabIndex: -1,
334
- inputProps: {"aria-labelledby": value},
345
+ inputProps: { "aria-labelledby": value },
335
346
  value,
336
347
  name: value,
337
348
  onChange: handleChange,
@@ -347,8 +358,8 @@ const SelectFilter = ({
347
358
  defaultValue,
348
359
  values = []
349
360
  }) => {
350
- const classes = useStyles$7();
351
- const {filters, setFilters} = useSearch();
361
+ const classes = useStyles$8();
362
+ const { filters, setFilters } = useSearch();
352
363
  useEffect(() => {
353
364
  if (typeof defaultValue === "string") {
354
365
  setFilters((prevFilters) => ({
@@ -359,11 +370,11 @@ const SelectFilter = ({
359
370
  }, []);
360
371
  const handleChange = (e) => {
361
372
  const {
362
- target: {value}
373
+ target: { value }
363
374
  } = e;
364
375
  setFilters((prevFilters) => {
365
- const {[name]: filter, ...others} = prevFilters;
366
- return value ? {...others, [name]: value} : others;
376
+ const { [name]: filter, ...others } = prevFilters;
377
+ return value ? { ...others, [name]: value } : others;
367
378
  });
368
379
  };
369
380
  return /* @__PURE__ */ React__default.createElement(FormControl, {
@@ -385,7 +396,7 @@ const SelectFilter = ({
385
396
  value
386
397
  }, value))));
387
398
  };
388
- const SearchFilter = ({component: Element, ...props}) => /* @__PURE__ */ React__default.createElement(Element, {
399
+ const SearchFilter = ({ component: Element, ...props }) => /* @__PURE__ */ React__default.createElement(Element, {
389
400
  ...props
390
401
  });
391
402
  SearchFilter.Checkbox = (props) => /* @__PURE__ */ React__default.createElement(SearchFilter, {
@@ -402,9 +413,27 @@ var Launch = createSvgIcon( /*#__PURE__*/React.createElement("path", {
402
413
  d: "M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"
403
414
  }), 'Launch');
404
415
 
405
- const SearchResultComponent = ({children}) => {
416
+ const DefaultResultListItem$1 = ({
417
+ result,
418
+ icon,
419
+ secondaryAction
420
+ }) => {
421
+ return /* @__PURE__ */ React__default.createElement(Link, {
422
+ to: result.location
423
+ }, /* @__PURE__ */ React__default.createElement(ListItem, {
424
+ alignItems: "center"
425
+ }, icon && /* @__PURE__ */ React__default.createElement(ListItemIcon, null, icon), /* @__PURE__ */ React__default.createElement(ListItemText, {
426
+ primaryTypographyProps: { variant: "h6" },
427
+ primary: result.title,
428
+ secondary: result.text
429
+ }), secondaryAction && /* @__PURE__ */ React__default.createElement(Box, {
430
+ alignItems: "flex-end"
431
+ }, secondaryAction)), /* @__PURE__ */ React__default.createElement(Divider, null));
432
+ };
433
+
434
+ const SearchResultComponent = ({ children }) => {
406
435
  const {
407
- result: {loading, error, value}
436
+ result: { loading, error, value }
408
437
  } = useSearch();
409
438
  if (loading) {
410
439
  return /* @__PURE__ */ React__default.createElement(Progress, null);
@@ -421,10 +450,10 @@ const SearchResultComponent = ({children}) => {
421
450
  title: "Sorry, no results were found"
422
451
  });
423
452
  }
424
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children({results: value.results}));
453
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children({ results: value.results }));
425
454
  };
426
455
 
427
- const useStyles$6 = makeStyles((theme) => ({
456
+ const useStyles$7 = makeStyles((theme) => ({
428
457
  root: {
429
458
  display: "flex",
430
459
  justifyContent: "space-between",
@@ -433,8 +462,8 @@ const useStyles$6 = makeStyles((theme) => ({
433
462
  }
434
463
  }));
435
464
  const SearchResultPager = () => {
436
- const {fetchNextPage, fetchPreviousPage} = useSearch();
437
- const classes = useStyles$6();
465
+ const { fetchNextPage, fetchPreviousPage } = useSearch();
466
+ const classes = useStyles$7();
438
467
  if (!fetchNextPage && !fetchPreviousPage) {
439
468
  return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null);
440
469
  }
@@ -465,9 +494,9 @@ const searchPlugin = createPlugin({
465
494
  apis: [
466
495
  createApiFactory({
467
496
  api: searchApiRef,
468
- deps: {discoveryApi: discoveryApiRef, identityApi: identityApiRef},
469
- factory: ({discoveryApi, identityApi}) => {
470
- return new SearchClient({discoveryApi, identityApi});
497
+ deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef },
498
+ factory: ({ discoveryApi, identityApi }) => {
499
+ return new SearchClient({ discoveryApi, identityApi });
471
500
  }
472
501
  })
473
502
  ],
@@ -478,58 +507,58 @@ const searchPlugin = createPlugin({
478
507
  });
479
508
  const SearchPage$1 = searchPlugin.provide(createRoutableExtension({
480
509
  name: "SearchPage",
481
- component: () => import('./index-77205085.esm.js').then((m) => m.SearchPage),
510
+ component: () => import('./index-ff0c1c1c.esm.js').then((m) => m.SearchPage),
482
511
  mountPoint: rootRouteRef
483
512
  }));
484
513
  const SearchPageNext = searchPlugin.provide(createRoutableExtension({
485
514
  name: "SearchPageNext",
486
- component: () => import('./index-77205085.esm.js').then((m) => m.SearchPage),
515
+ component: () => import('./index-ff0c1c1c.esm.js').then((m) => m.SearchPage),
487
516
  mountPoint: rootNextRouteRef
488
517
  }));
489
518
  searchPlugin.provide(createComponentExtension({
490
519
  name: "SearchBar",
491
520
  component: {
492
- lazy: () => import('./index-b929d40d.esm.js').then((m) => m.SearchBar)
521
+ lazy: () => import('./index-00a7ba84.esm.js').then((m) => m.SearchBar)
493
522
  }
494
523
  }));
495
524
  const SearchBarNext = searchPlugin.provide(createComponentExtension({
496
525
  name: "SearchBarNext",
497
526
  component: {
498
- lazy: () => import('./index-b929d40d.esm.js').then((m) => m.SearchBar)
527
+ lazy: () => import('./index-00a7ba84.esm.js').then((m) => m.SearchBar)
499
528
  }
500
529
  }));
501
530
  const SearchResult$1 = searchPlugin.provide(createComponentExtension({
502
531
  name: "SearchResult",
503
532
  component: {
504
- lazy: () => import('./index-766e727c.esm.js').then((m) => m.SearchResult)
533
+ lazy: () => import('./index-c6d67b32.esm.js').then((m) => m.SearchResult)
505
534
  }
506
535
  }));
507
536
  searchPlugin.provide(createComponentExtension({
508
537
  name: "SearchResultNext",
509
538
  component: {
510
- lazy: () => import('./index-766e727c.esm.js').then((m) => m.SearchResult)
539
+ lazy: () => import('./index-c6d67b32.esm.js').then((m) => m.SearchResult)
511
540
  }
512
541
  }));
513
542
  const SidebarSearchModal = searchPlugin.provide(createComponentExtension({
514
543
  name: "SidebarSearchModal",
515
544
  component: {
516
- lazy: () => import('./index-01b40466.esm.js').then((m) => m.SidebarSearchModal)
545
+ lazy: () => import('./index-e62dadc4.esm.js').then((m) => m.SidebarSearchModal)
517
546
  }
518
547
  }));
519
548
  const DefaultResultListItem = searchPlugin.provide(createComponentExtension({
520
549
  name: "DefaultResultListItem",
521
550
  component: {
522
- lazy: () => import('./index-207637ef.esm.js').then((m) => m.DefaultResultListItem)
551
+ lazy: () => import('./index-fbbcf308.esm.js').then((m) => m.DefaultResultListItem)
523
552
  }
524
553
  }));
525
554
  const HomePageSearchBar = searchPlugin.provide(createComponentExtension({
526
555
  name: "HomePageSearchBar",
527
556
  component: {
528
- lazy: () => import('./index-b9474e70.esm.js').then((m) => m.HomePageSearchBar)
557
+ lazy: () => import('./index-384f7bcf.esm.js').then((m) => m.HomePageSearchBar)
529
558
  }
530
559
  }));
531
560
 
532
- const useStyles$5 = makeStyles$1((theme) => ({
561
+ const useStyles$6 = makeStyles$1((theme) => ({
533
562
  container: {
534
563
  borderRadius: 30,
535
564
  display: "flex",
@@ -538,26 +567,16 @@ const useStyles$5 = makeStyles$1((theme) => ({
538
567
  input: {
539
568
  flex: 1
540
569
  },
541
- paperFullWidth: {height: "calc(100% - 128px)"},
542
- dialogActionsContainer: {padding: theme.spacing(1, 3)},
543
- viewResultsLink: {verticalAlign: "0.5em"}
570
+ paperFullWidth: { height: "calc(100% - 128px)" },
571
+ dialogActionsContainer: { padding: theme.spacing(1, 3) },
572
+ viewResultsLink: { verticalAlign: "0.5em" }
544
573
  }));
545
- const Modal = ({open = true, toggleModal}) => {
574
+ const Modal = ({ open = true, toggleModal }) => {
546
575
  const getSearchLink = useRouteRef(rootRouteRef);
547
- const classes = useStyles$5();
548
- const {term, setTerm} = useSearch();
549
- const [value, setValue] = useState(term);
550
- useEffect(() => {
551
- setValue((prevValue) => prevValue !== term ? term : prevValue);
552
- }, [term]);
553
- useDebounce(() => setTerm(value), 500, [value]);
554
- const handleQuery = (newValue) => {
555
- setValue(newValue);
556
- };
557
- const handleClear = () => setValue("");
576
+ const classes = useStyles$6();
577
+ const { term } = useSearch();
558
578
  const handleResultClick = () => {
559
579
  toggleModal();
560
- handleClear();
561
580
  };
562
581
  const handleKeyPress = () => {
563
582
  handleResultClick();
@@ -573,11 +592,8 @@ const Modal = ({open = true, toggleModal}) => {
573
592
  maxWidth: "lg"
574
593
  }, /* @__PURE__ */ React__default.createElement(DialogTitle, null, /* @__PURE__ */ React__default.createElement(Paper, {
575
594
  className: classes.container
576
- }, /* @__PURE__ */ React__default.createElement(SearchBarBase, {
577
- className: classes.input,
578
- value,
579
- onChange: handleQuery,
580
- onClear: handleClear
595
+ }, /* @__PURE__ */ React__default.createElement(SearchBar$1, {
596
+ className: classes.input
581
597
  }))), /* @__PURE__ */ React__default.createElement(DialogContent, null, /* @__PURE__ */ React__default.createElement(Grid, {
582
598
  container: true,
583
599
  direction: "row-reverse",
@@ -587,12 +603,12 @@ const Modal = ({open = true, toggleModal}) => {
587
603
  item: true
588
604
  }, /* @__PURE__ */ React__default.createElement(Link, {
589
605
  onClick: toggleModal,
590
- to: `${getSearchLink()}?query=${value}`
606
+ to: `${getSearchLink()}?query=${term}`
591
607
  }, /* @__PURE__ */ React__default.createElement("span", {
592
608
  className: classes.viewResultsLink
593
609
  }, "View Full Results"), /* @__PURE__ */ React__default.createElement(Launch, {
594
610
  color: "primary"
595
- })))), /* @__PURE__ */ React__default.createElement(Divider, null), /* @__PURE__ */ React__default.createElement(SearchResultComponent, null, ({results}) => /* @__PURE__ */ React__default.createElement(List, null, results.map(({document}) => /* @__PURE__ */ React__default.createElement("div", {
611
+ })))), /* @__PURE__ */ React__default.createElement(Divider, null), /* @__PURE__ */ React__default.createElement(SearchResultComponent, null, ({ results }) => /* @__PURE__ */ React__default.createElement(List, null, results.map(({ document }) => /* @__PURE__ */ React__default.createElement("div", {
596
612
  role: "button",
597
613
  tabIndex: 0,
598
614
  key: `${document.location}-btn`,
@@ -611,14 +627,14 @@ const Modal = ({open = true, toggleModal}) => {
611
627
  xs: 12
612
628
  }, /* @__PURE__ */ React__default.createElement(SearchResultPager, null)))));
613
629
  };
614
- const SearchModal = ({open = true, toggleModal}) => {
630
+ const SearchModal = ({ open = true, toggleModal }) => {
615
631
  return /* @__PURE__ */ React__default.createElement(SearchContextProvider, null, /* @__PURE__ */ React__default.createElement(Modal, {
616
632
  open,
617
633
  toggleModal
618
634
  }));
619
635
  };
620
636
 
621
- const useStyles$4 = makeStyles$1(() => ({
637
+ const useStyles$5 = makeStyles$1(() => ({
622
638
  root: {
623
639
  display: "flex",
624
640
  alignItems: "center"
@@ -632,7 +648,7 @@ const SearchBar = ({
632
648
  handleSearch,
633
649
  handleClearSearchBar
634
650
  }) => {
635
- const classes = useStyles$4();
651
+ const classes = useStyles$5();
636
652
  return /* @__PURE__ */ React__default.createElement(Paper, {
637
653
  component: "form",
638
654
  onSubmit: (e) => handleSearch(e),
@@ -646,14 +662,14 @@ const SearchBar = ({
646
662
  placeholder: "Search in Backstage",
647
663
  value: searchQuery,
648
664
  onChange: (e) => handleSearch(e),
649
- inputProps: {"aria-label": "search backstage"}
665
+ inputProps: { "aria-label": "search backstage" }
650
666
  }), /* @__PURE__ */ React__default.createElement(IconButton$1, {
651
667
  "aria-label": "search",
652
668
  onClick: () => handleClearSearchBar()
653
669
  }, /* @__PURE__ */ React__default.createElement(ClearButton, null)));
654
670
  };
655
671
 
656
- const useStyles$3 = makeStyles((theme) => ({
672
+ const useStyles$4 = makeStyles((theme) => ({
657
673
  filters: {
658
674
  width: "250px",
659
675
  display: "flex"
@@ -666,7 +682,7 @@ const FiltersButton = ({
666
682
  numberOfSelectedFilters,
667
683
  handleToggleFilters
668
684
  }) => {
669
- const classes = useStyles$3();
685
+ const classes = useStyles$4();
670
686
  return /* @__PURE__ */ React__default.createElement("div", {
671
687
  className: classes.filters
672
688
  }, /* @__PURE__ */ React__default.createElement(IconButton, {
@@ -678,7 +694,7 @@ const FiltersButton = ({
678
694
  }, "Filters (", numberOfSelectedFilters ? numberOfSelectedFilters : 0, ")"));
679
695
  };
680
696
 
681
- const useStyles$2 = makeStyles((theme) => ({
697
+ const useStyles$3 = makeStyles((theme) => ({
682
698
  filters: {
683
699
  background: "transparent",
684
700
  boxShadow: "0px 0px 0px 0px"
@@ -697,7 +713,7 @@ const Filters = ({
697
713
  updateSelected,
698
714
  updateChecked
699
715
  }) => {
700
- const classes = useStyles$2();
716
+ const classes = useStyles$3();
701
717
  return /* @__PURE__ */ React__default.createElement(Card, {
702
718
  className: classes.filters
703
719
  }, /* @__PURE__ */ React__default.createElement(CardHeader, {
@@ -751,7 +767,7 @@ const Filters = ({
751
767
  }))))));
752
768
  };
753
769
 
754
- const useStyles$1 = makeStyles((theme) => ({
770
+ const useStyles$2 = makeStyles((theme) => ({
755
771
  searchQuery: {
756
772
  color: theme.palette.text.primary,
757
773
  background: theme.palette.background.default,
@@ -799,7 +815,7 @@ const TableHeader = ({
799
815
  numberOfResults,
800
816
  handleToggleFilters
801
817
  }) => {
802
- const classes = useStyles$1();
818
+ const classes = useStyles$2();
803
819
  return /* @__PURE__ */ React__default.createElement("div", {
804
820
  className: classes.tableHeader
805
821
  }, /* @__PURE__ */ React__default.createElement(FiltersButton, {
@@ -819,7 +835,7 @@ const TableHeader = ({
819
835
  variant: "h6"
820
836
  }, `${numberOfResults} results`)));
821
837
  };
822
- const SearchResult = ({searchQuery}) => {
838
+ const SearchResult = ({ searchQuery }) => {
823
839
  const catalogApi = useApi(catalogApiRef);
824
840
  const [showFilters, toggleFilters] = useState(false);
825
841
  const [selectedFilters, setSelectedFilters] = useState({
@@ -929,7 +945,7 @@ const SearchResult = ({searchQuery}) => {
929
945
  item: true,
930
946
  xs: showFilters ? 9 : 12
931
947
  }, /* @__PURE__ */ React__default.createElement(Table, {
932
- options: {paging: true, pageSize: 20, search: false},
948
+ options: { paging: true, pageSize: 20, search: false },
933
949
  data: filteredResults,
934
950
  columns,
935
951
  title: /* @__PURE__ */ React__default.createElement(TableHeader, {
@@ -994,7 +1010,7 @@ const UrlUpdater = () => {
994
1010
  if (location.search === prevQueryParams) {
995
1011
  return;
996
1012
  }
997
- const query = qs.parse(location.search.substring(1), {arrayLimit: 0}) || {};
1013
+ const query = qs.parse(location.search.substring(1), { arrayLimit: 0 }) || {};
998
1014
  if (query.filters) {
999
1015
  setFilters(query.filters);
1000
1016
  }
@@ -1014,7 +1030,7 @@ const UrlUpdater = () => {
1014
1030
  types,
1015
1031
  pageCursor,
1016
1032
  filters
1017
- }, {arrayFormat: "brackets"});
1033
+ }, { arrayFormat: "brackets" });
1018
1034
  const newUrl = `${window.location.pathname}?${newParams}`;
1019
1035
  window.history.replaceState(null, document.title, newUrl);
1020
1036
  }, [term, types, pageCursor, filters]);
@@ -1025,6 +1041,110 @@ const SearchPage = () => {
1025
1041
  return /* @__PURE__ */ React__default.createElement(SearchContextProvider, null, /* @__PURE__ */ React__default.createElement(UrlUpdater, null), outlet || /* @__PURE__ */ React__default.createElement(LegacySearchPage, null));
1026
1042
  };
1027
1043
 
1044
+ const useStyles$1 = makeStyles((theme) => ({
1045
+ card: {
1046
+ backgroundColor: "rgba(0, 0, 0, .11)"
1047
+ },
1048
+ cardContent: {
1049
+ paddingTop: theme.spacing(1)
1050
+ },
1051
+ icon: {
1052
+ color: theme.palette.common.black
1053
+ },
1054
+ list: {
1055
+ width: "100%"
1056
+ },
1057
+ listItemIcon: {
1058
+ width: "24px",
1059
+ height: "24px"
1060
+ },
1061
+ accordion: {
1062
+ backgroundColor: theme.palette.background.paper
1063
+ },
1064
+ accordionSummary: {
1065
+ minHeight: "auto",
1066
+ "&.Mui-expanded": {
1067
+ minHeight: "auto"
1068
+ }
1069
+ },
1070
+ accordionSummaryContent: {
1071
+ margin: theme.spacing(2, 0),
1072
+ "&.Mui-expanded": {
1073
+ margin: theme.spacing(2, 0)
1074
+ }
1075
+ },
1076
+ accordionDetails: {
1077
+ padding: theme.spacing(0, 0, 1)
1078
+ }
1079
+ }));
1080
+ const SearchTypeAccordion = (props) => {
1081
+ const classes = useStyles$1();
1082
+ const { setPageCursor, setTypes, types } = useSearch();
1083
+ const [expanded, setExpanded] = useState(true);
1084
+ const { defaultValue, name, types: givenTypes } = props;
1085
+ const toggleExpanded = () => setExpanded((prevState) => !prevState);
1086
+ const handleClick = (type) => {
1087
+ return () => {
1088
+ setTypes(type !== "" ? [type] : []);
1089
+ setPageCursor(void 0);
1090
+ setExpanded(false);
1091
+ };
1092
+ };
1093
+ useEffect(() => {
1094
+ if (defaultValue) {
1095
+ setTypes([defaultValue]);
1096
+ }
1097
+ }, []);
1098
+ const definedTypes = [
1099
+ {
1100
+ value: "",
1101
+ name: "All",
1102
+ icon: /* @__PURE__ */ React__default.createElement(AllIcon, null)
1103
+ },
1104
+ ...givenTypes
1105
+ ];
1106
+ const selected = types[0] || "";
1107
+ return /* @__PURE__ */ React__default.createElement(Card, {
1108
+ className: classes.card
1109
+ }, /* @__PURE__ */ React__default.createElement(CardHeader, {
1110
+ title: name,
1111
+ titleTypographyProps: { variant: "overline" }
1112
+ }), /* @__PURE__ */ React__default.createElement(CardContent, {
1113
+ className: classes.cardContent
1114
+ }, /* @__PURE__ */ React__default.createElement(Accordion, {
1115
+ className: classes.accordion,
1116
+ expanded,
1117
+ onChange: toggleExpanded
1118
+ }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1119
+ classes: {
1120
+ root: classes.accordionSummary,
1121
+ content: classes.accordionSummaryContent
1122
+ },
1123
+ expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, {
1124
+ className: classes.icon
1125
+ }),
1126
+ IconButtonProps: { size: "small" }
1127
+ }, expanded ? "Collapse" : definedTypes.filter((t) => t.value === selected)[0].name), /* @__PURE__ */ React__default.createElement(AccordionDetails, {
1128
+ classes: { root: classes.accordionDetails }
1129
+ }, /* @__PURE__ */ React__default.createElement(List, {
1130
+ className: classes.list,
1131
+ component: "nav",
1132
+ "aria-label": "filter by type",
1133
+ disablePadding: true,
1134
+ dense: true
1135
+ }, definedTypes.map((type) => /* @__PURE__ */ React__default.createElement(Fragment, {
1136
+ key: type.value
1137
+ }, /* @__PURE__ */ React__default.createElement(Divider, null), /* @__PURE__ */ React__default.createElement(ListItem, {
1138
+ selected: types[0] === type.value || types.length === 0 && type.value === "",
1139
+ onClick: handleClick(type.value),
1140
+ button: true
1141
+ }, /* @__PURE__ */ React__default.createElement(ListItemIcon, null, cloneElement(type.icon, {
1142
+ className: classes.listItemIcon
1143
+ })), /* @__PURE__ */ React__default.createElement(ListItemText, {
1144
+ primary: type.name
1145
+ })))))))));
1146
+ };
1147
+
1028
1148
  const useStyles = makeStyles((theme) => ({
1029
1149
  label: {
1030
1150
  textTransform: "capitalize"
@@ -1038,14 +1158,10 @@ const useStyles = makeStyles((theme) => ({
1038
1158
  margin: 2
1039
1159
  }
1040
1160
  }));
1041
- const SearchType = ({
1042
- values = [],
1043
- className,
1044
- name,
1045
- defaultValue
1046
- }) => {
1161
+ const SearchType = (props) => {
1162
+ const { className, defaultValue, name, values = [] } = props;
1047
1163
  const classes = useStyles();
1048
- const {types, setTypes} = useSearch();
1164
+ const { types, setTypes } = useSearch();
1049
1165
  useEffectOnce(() => {
1050
1166
  if (!types.length) {
1051
1167
  if (defaultValue && Array.isArray(defaultValue)) {
@@ -1090,19 +1206,25 @@ const SearchType = ({
1090
1206
  primary: value
1091
1207
  })))));
1092
1208
  };
1209
+ SearchType.Accordion = (props) => {
1210
+ return /* @__PURE__ */ React__default.createElement(SearchTypeAccordion, {
1211
+ ...props
1212
+ });
1213
+ };
1093
1214
 
1094
- const SidebarSearch = () => {
1215
+ const SidebarSearch = (props) => {
1095
1216
  const searchRoute = useRouteRef(rootRouteRef);
1096
1217
  const navigate = useNavigate();
1097
1218
  const handleSearch = useCallback((query) => {
1098
- const queryString = qs.stringify({query}, {addQueryPrefix: true});
1219
+ const queryString = qs.stringify({ query }, { addQueryPrefix: true });
1099
1220
  navigate(`${searchRoute()}${queryString}`);
1100
1221
  }, [navigate, searchRoute]);
1101
1222
  return /* @__PURE__ */ React__default.createElement(SidebarSearchField, {
1223
+ icon: props.icon,
1102
1224
  onSearch: handleSearch,
1103
1225
  to: "/search"
1104
1226
  });
1105
1227
  };
1106
1228
 
1107
1229
  export { DefaultResultListItem$1 as D, Filters$1 as F, HomePageSearchBar as H, SearchPage as S, SearchBar$1 as a, SearchBarBase as b, SearchResultComponent as c, SearchModal as d, FiltersButton$1 as e, SearchContextProvider as f, SearchFilter as g, SearchFilterNext as h, SearchResultPager as i, SearchType as j, SidebarSearch as k, DefaultResultListItem as l, SearchBarNext as m, SearchPage$1 as n, SearchPageNext as o, searchPlugin as p, SearchResult$1 as q, rootRouteRef as r, searchApiRef as s, SidebarSearchModal as t, useSearch as u };
1108
- //# sourceMappingURL=index-cdccd881.esm.js.map
1230
+ //# sourceMappingURL=index-ee953592.esm.js.map