@backstage/plugin-search 0.5.0 → 0.5.4

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,17 @@
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, ListItemIcon, ListItemText, Box, 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';
9
- import { usePrevious, useAsync, useDebounce, useEffectOnce } from 'react-use';
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, Tabs, Tab, Chip } from '@material-ui/core';
8
+ import useDebounce from 'react-use/lib/useDebounce';
10
9
  import SearchIcon from '@material-ui/icons/Search';
11
10
  import ClearButton from '@material-ui/icons/Clear';
11
+ import useAsync from 'react-use/lib/useAsync';
12
+ import usePrevious from 'react-use/lib/usePrevious';
12
13
  import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
14
+ import { Link, Progress, ResponseErrorPanel, EmptyState, Table, useQueryParamState, Page, Header, Content, SidebarSearchField } from '@backstage/core-components';
13
15
  import ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';
14
16
  import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
15
17
  import { createSvgIcon } from '@material-ui/core/utils';
@@ -19,11 +21,13 @@ import IconButton$1 from '@material-ui/core/IconButton';
19
21
  import { Alert } from '@material-ui/lab';
20
22
  import { catalogApiRef } from '@backstage/plugin-catalog-react';
21
23
  import { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';
24
+ import useEffectOnce from 'react-use/lib/useEffectOnce';
25
+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
26
+ import AllIcon from '@material-ui/icons/FontDownload';
22
27
  import { useNavigate } from 'react-router-dom';
23
28
 
24
29
  const searchApiRef = createApiRef({
25
- id: "plugin.search.queryservice",
26
- description: "Used to make requests against the search API"
30
+ id: "plugin.search.queryservice"
27
31
  });
28
32
  class SearchClient {
29
33
  constructor(options) {
@@ -35,7 +39,7 @@ class SearchClient {
35
39
  const queryString = qs.stringify(query);
36
40
  const url = `${await this.discoveryApi.getBaseUrl("search/query")}?${queryString}`;
37
41
  const response = await fetch(url, {
38
- headers: token ? {Authorization: `Bearer ${token}`} : {}
42
+ headers: token ? { Authorization: `Bearer ${token}` } : {}
39
43
  });
40
44
  if (!response.ok) {
41
45
  throw await ResponseError.fromResponse(response);
@@ -44,25 +48,7 @@ class SearchClient {
44
48
  }
45
49
  }
46
50
 
47
- const DefaultResultListItem$1 = ({
48
- result,
49
- icon,
50
- secondaryAction
51
- }) => {
52
- return /* @__PURE__ */ React__default.createElement(Link, {
53
- to: result.location
54
- }, /* @__PURE__ */ React__default.createElement(ListItem, {
55
- alignItems: "center"
56
- }, icon && /* @__PURE__ */ React__default.createElement(ListItemIcon, null, icon), /* @__PURE__ */ React__default.createElement(ListItemText, {
57
- primaryTypographyProps: {variant: "h6"},
58
- primary: result.title,
59
- secondary: result.text
60
- }), secondaryAction && /* @__PURE__ */ React__default.createElement(Box, {
61
- alignItems: "flex-end"
62
- }, secondaryAction)), /* @__PURE__ */ React__default.createElement(Divider, null));
63
- };
64
-
65
- const useStyles$9 = makeStyles((theme) => ({
51
+ const useStyles$b = makeStyles((theme) => ({
66
52
  filters: {
67
53
  width: "250px",
68
54
  display: "flex"
@@ -75,7 +61,7 @@ const FiltersButton$1 = ({
75
61
  numberOfSelectedFilters,
76
62
  handleToggleFilters
77
63
  }) => {
78
- const classes = useStyles$9();
64
+ const classes = useStyles$b();
79
65
  return /* @__PURE__ */ React__default.createElement("div", {
80
66
  className: classes.filters
81
67
  }, /* @__PURE__ */ React__default.createElement(IconButton, {
@@ -87,7 +73,7 @@ const FiltersButton$1 = ({
87
73
  }, "Filters (", numberOfSelectedFilters ? numberOfSelectedFilters : 0, ")"));
88
74
  };
89
75
 
90
- const useStyles$8 = makeStyles((theme) => ({
76
+ const useStyles$a = makeStyles((theme) => ({
91
77
  filters: {
92
78
  background: "transparent",
93
79
  boxShadow: "0px 0px 0px 0px"
@@ -106,7 +92,7 @@ const Filters$1 = ({
106
92
  updateSelected,
107
93
  updateChecked
108
94
  }) => {
109
- const classes = useStyles$8();
95
+ const classes = useStyles$a();
110
96
  return /* @__PURE__ */ React__default.createElement(Card, {
111
97
  className: classes.filters
112
98
  }, /* @__PURE__ */ React__default.createElement(CardHeader, {
@@ -215,10 +201,12 @@ const SearchContextProvider = ({
215
201
  fetchNextPage: hasNextPage ? fetchNextPage : void 0,
216
202
  fetchPreviousPage: hasPreviousPage ? fetchPreviousPage : void 0
217
203
  };
218
- return /* @__PURE__ */ React__default.createElement(SearchContext.Provider, {
204
+ return /* @__PURE__ */ React__default.createElement(AnalyticsContext, {
205
+ attributes: { searchTypes: types.sort().join(",") }
206
+ }, /* @__PURE__ */ React__default.createElement(SearchContext.Provider, {
219
207
  value,
220
208
  children
221
- });
209
+ }));
222
210
  };
223
211
  const useSearch = () => {
224
212
  const context = useContext(SearchContext);
@@ -228,78 +216,97 @@ const useSearch = () => {
228
216
  return context;
229
217
  };
230
218
 
219
+ const TrackSearch = ({ children }) => {
220
+ const analytics = useAnalytics();
221
+ const { term } = useSearch();
222
+ useEffect(() => {
223
+ if (term) {
224
+ analytics.captureEvent("search", term);
225
+ }
226
+ }, [analytics, term]);
227
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children);
228
+ };
229
+
230
+ const useSearchContextCheck = () => {
231
+ const context = useContext(SearchContext);
232
+ return context !== void 0;
233
+ };
231
234
  const SearchBarBase = ({
232
- autoFocus,
233
- value,
234
235
  onChange,
236
+ onKeyDown,
235
237
  onSubmit,
236
- className,
237
- placeholder: overridePlaceholder,
238
- clearButton = true
238
+ debounceTime = 200,
239
+ clearButton = true,
240
+ fullWidth = true,
241
+ value: defaultValue,
242
+ inputProps: defaultInputProps = {},
243
+ endAdornment: defaultEndAdornment,
244
+ ...props
239
245
  }) => {
240
246
  const configApi = useApi(configApiRef);
241
- const onKeyDown = React__default.useCallback((e) => {
247
+ const [value, setValue] = useState(defaultValue);
248
+ const hasSearchContext = useSearchContextCheck();
249
+ useEffect(() => {
250
+ setValue((prevValue) => prevValue !== defaultValue ? defaultValue : prevValue);
251
+ }, [defaultValue]);
252
+ useDebounce(() => onChange(value), debounceTime, [value]);
253
+ const handleChange = useCallback((e) => {
254
+ setValue(e.target.value);
255
+ }, [setValue]);
256
+ const handleKeyDown = useCallback((e) => {
257
+ if (onKeyDown)
258
+ onKeyDown(e);
242
259
  if (onSubmit && e.key === "Enter") {
243
260
  onSubmit();
244
261
  }
245
- }, [onSubmit]);
246
- const handleClear = React__default.useCallback(() => {
262
+ }, [onKeyDown, onSubmit]);
263
+ const handleClear = useCallback(() => {
247
264
  onChange("");
248
265
  }, [onChange]);
249
- const placeholder = overridePlaceholder != null ? overridePlaceholder : `Search in ${configApi.getOptionalString("app.title") || "Backstage"}`;
250
- return /* @__PURE__ */ React__default.createElement(InputBase, {
251
- autoFocus,
266
+ const placeholder = `Search in ${configApi.getOptionalString("app.title") || "Backstage"}`;
267
+ const startAdornment = /* @__PURE__ */ React__default.createElement(InputAdornment, {
268
+ position: "start"
269
+ }, /* @__PURE__ */ React__default.createElement(IconButton, {
270
+ "aria-label": "Query",
271
+ disabled: true
272
+ }, /* @__PURE__ */ React__default.createElement(SearchIcon, null)));
273
+ const endAdornment = /* @__PURE__ */ React__default.createElement(InputAdornment, {
274
+ position: "end"
275
+ }, /* @__PURE__ */ React__default.createElement(IconButton, {
276
+ "aria-label": "Clear",
277
+ onClick: handleClear
278
+ }, /* @__PURE__ */ React__default.createElement(ClearButton, null)));
279
+ const searchBar = /* @__PURE__ */ React__default.createElement(TrackSearch, null, /* @__PURE__ */ React__default.createElement(InputBase, {
252
280
  "data-testid": "search-bar-next",
253
- fullWidth: true,
254
- placeholder,
255
281
  value,
256
- onChange: (e) => onChange(e.target.value),
257
- inputProps: {"aria-label": "Search"},
258
- startAdornment: /* @__PURE__ */ React__default.createElement(InputAdornment, {
259
- position: "start"
260
- }, /* @__PURE__ */ React__default.createElement(IconButton, {
261
- "aria-label": "Query",
262
- disabled: true
263
- }, /* @__PURE__ */ React__default.createElement(SearchIcon, null))),
264
- endAdornment: clearButton && /* @__PURE__ */ React__default.createElement(InputAdornment, {
265
- position: "end"
266
- }, /* @__PURE__ */ React__default.createElement(IconButton, {
267
- "aria-label": "Clear",
268
- onClick: handleClear
269
- }, /* @__PURE__ */ React__default.createElement(ClearButton, null))),
270
- ...className && {className},
271
- ...onSubmit && {onKeyDown}
272
- });
282
+ placeholder,
283
+ startAdornment,
284
+ endAdornment: clearButton ? endAdornment : defaultEndAdornment,
285
+ inputProps: { "aria-label": "Search", ...defaultInputProps },
286
+ fullWidth,
287
+ onChange: handleChange,
288
+ onKeyDown: handleKeyDown,
289
+ ...props
290
+ }));
291
+ return hasSearchContext ? searchBar : /* @__PURE__ */ React__default.createElement(SearchContextProvider, null, searchBar);
273
292
  };
274
- const SearchBar$1 = ({
275
- autoFocus,
276
- className,
277
- debounceTime = 0,
278
- placeholder,
279
- clearButton = true
280
- }) => {
281
- const {term, setTerm} = useSearch();
282
- const [value, setValue] = useState(term);
283
- useEffect(() => {
284
- setValue((prevValue) => prevValue !== term ? term : prevValue);
285
- }, [term]);
286
- useDebounce(() => setTerm(value), debounceTime, [value]);
287
- const handleQuery = (newValue) => {
288
- setValue(newValue);
293
+ const SearchBar$1 = ({ onChange, ...props }) => {
294
+ const { term, setTerm } = useSearch();
295
+ const handleChange = (newValue) => {
296
+ if (onChange) {
297
+ onChange(newValue);
298
+ } else {
299
+ setTerm(newValue);
300
+ }
289
301
  };
290
- const handleClear = () => setValue("");
291
302
  return /* @__PURE__ */ React__default.createElement(SearchBarBase, {
292
- autoFocus,
293
- className,
294
- value,
295
- onChange: handleQuery,
296
- onClear: handleClear,
297
- placeholder,
298
- clearButton
303
+ value: term,
304
+ onChange: handleChange,
305
+ ...props
299
306
  });
300
307
  };
301
308
 
302
- const useStyles$7 = makeStyles({
309
+ const useStyles$9 = makeStyles({
303
310
  label: {
304
311
  textTransform: "capitalize"
305
312
  }
@@ -310,8 +317,8 @@ const CheckboxFilter = ({
310
317
  defaultValue,
311
318
  values = []
312
319
  }) => {
313
- const classes = useStyles$7();
314
- const {filters, setFilters} = useSearch();
320
+ const classes = useStyles$9();
321
+ const { filters, setFilters } = useSearch();
315
322
  useEffect(() => {
316
323
  if (Array.isArray(defaultValue)) {
317
324
  setFilters((prevFilters) => ({
@@ -322,13 +329,13 @@ const CheckboxFilter = ({
322
329
  }, []);
323
330
  const handleChange = (e) => {
324
331
  const {
325
- target: {value, checked}
332
+ target: { value, checked }
326
333
  } = e;
327
334
  setFilters((prevFilters) => {
328
- const {[name]: filter, ...others} = prevFilters;
335
+ const { [name]: filter, ...others } = prevFilters;
329
336
  const rest = (filter || []).filter((i) => i !== value);
330
337
  const items = checked ? [...rest, value] : rest;
331
- return items.length ? {...others, [name]: items} : others;
338
+ return items.length ? { ...others, [name]: items } : others;
332
339
  });
333
340
  };
334
341
  return /* @__PURE__ */ React__default.createElement(FormControl, {
@@ -344,7 +351,7 @@ const CheckboxFilter = ({
344
351
  control: /* @__PURE__ */ React__default.createElement(Checkbox, {
345
352
  color: "primary",
346
353
  tabIndex: -1,
347
- inputProps: {"aria-labelledby": value},
354
+ inputProps: { "aria-labelledby": value },
348
355
  value,
349
356
  name: value,
350
357
  onChange: handleChange,
@@ -360,8 +367,8 @@ const SelectFilter = ({
360
367
  defaultValue,
361
368
  values = []
362
369
  }) => {
363
- const classes = useStyles$7();
364
- const {filters, setFilters} = useSearch();
370
+ const classes = useStyles$9();
371
+ const { filters, setFilters } = useSearch();
365
372
  useEffect(() => {
366
373
  if (typeof defaultValue === "string") {
367
374
  setFilters((prevFilters) => ({
@@ -372,11 +379,11 @@ const SelectFilter = ({
372
379
  }, []);
373
380
  const handleChange = (e) => {
374
381
  const {
375
- target: {value}
382
+ target: { value }
376
383
  } = e;
377
384
  setFilters((prevFilters) => {
378
- const {[name]: filter, ...others} = prevFilters;
379
- return value ? {...others, [name]: value} : others;
385
+ const { [name]: filter, ...others } = prevFilters;
386
+ return value ? { ...others, [name]: value } : others;
380
387
  });
381
388
  };
382
389
  return /* @__PURE__ */ React__default.createElement(FormControl, {
@@ -398,7 +405,7 @@ const SelectFilter = ({
398
405
  value
399
406
  }, value))));
400
407
  };
401
- const SearchFilter = ({component: Element, ...props}) => /* @__PURE__ */ React__default.createElement(Element, {
408
+ const SearchFilter = ({ component: Element, ...props }) => /* @__PURE__ */ React__default.createElement(Element, {
402
409
  ...props
403
410
  });
404
411
  SearchFilter.Checkbox = (props) => /* @__PURE__ */ React__default.createElement(SearchFilter, {
@@ -415,9 +422,27 @@ var Launch = createSvgIcon( /*#__PURE__*/React.createElement("path", {
415
422
  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"
416
423
  }), 'Launch');
417
424
 
418
- const SearchResultComponent = ({children}) => {
425
+ const DefaultResultListItem$1 = ({
426
+ result,
427
+ icon,
428
+ secondaryAction
429
+ }) => {
430
+ return /* @__PURE__ */ React__default.createElement(Link, {
431
+ to: result.location
432
+ }, /* @__PURE__ */ React__default.createElement(ListItem, {
433
+ alignItems: "center"
434
+ }, icon && /* @__PURE__ */ React__default.createElement(ListItemIcon, null, icon), /* @__PURE__ */ React__default.createElement(ListItemText, {
435
+ primaryTypographyProps: { variant: "h6" },
436
+ primary: result.title,
437
+ secondary: result.text
438
+ }), secondaryAction && /* @__PURE__ */ React__default.createElement(Box, {
439
+ alignItems: "flex-end"
440
+ }, secondaryAction)), /* @__PURE__ */ React__default.createElement(Divider, null));
441
+ };
442
+
443
+ const SearchResultComponent = ({ children }) => {
419
444
  const {
420
- result: {loading, error, value}
445
+ result: { loading, error, value }
421
446
  } = useSearch();
422
447
  if (loading) {
423
448
  return /* @__PURE__ */ React__default.createElement(Progress, null);
@@ -434,10 +459,10 @@ const SearchResultComponent = ({children}) => {
434
459
  title: "Sorry, no results were found"
435
460
  });
436
461
  }
437
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children({results: value.results}));
462
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children({ results: value.results }));
438
463
  };
439
464
 
440
- const useStyles$6 = makeStyles((theme) => ({
465
+ const useStyles$8 = makeStyles((theme) => ({
441
466
  root: {
442
467
  display: "flex",
443
468
  justifyContent: "space-between",
@@ -446,8 +471,8 @@ const useStyles$6 = makeStyles((theme) => ({
446
471
  }
447
472
  }));
448
473
  const SearchResultPager = () => {
449
- const {fetchNextPage, fetchPreviousPage} = useSearch();
450
- const classes = useStyles$6();
474
+ const { fetchNextPage, fetchPreviousPage } = useSearch();
475
+ const classes = useStyles$8();
451
476
  if (!fetchNextPage && !fetchPreviousPage) {
452
477
  return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null);
453
478
  }
@@ -478,9 +503,9 @@ const searchPlugin = createPlugin({
478
503
  apis: [
479
504
  createApiFactory({
480
505
  api: searchApiRef,
481
- deps: {discoveryApi: discoveryApiRef, identityApi: identityApiRef},
482
- factory: ({discoveryApi, identityApi}) => {
483
- return new SearchClient({discoveryApi, identityApi});
506
+ deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef },
507
+ factory: ({ discoveryApi, identityApi }) => {
508
+ return new SearchClient({ discoveryApi, identityApi });
484
509
  }
485
510
  })
486
511
  ],
@@ -491,58 +516,58 @@ const searchPlugin = createPlugin({
491
516
  });
492
517
  const SearchPage$1 = searchPlugin.provide(createRoutableExtension({
493
518
  name: "SearchPage",
494
- component: () => import('./index-09bfa46d.esm.js').then((m) => m.SearchPage),
519
+ component: () => import('./index-5842ad6f.esm.js').then((m) => m.SearchPage),
495
520
  mountPoint: rootRouteRef
496
521
  }));
497
522
  const SearchPageNext = searchPlugin.provide(createRoutableExtension({
498
523
  name: "SearchPageNext",
499
- component: () => import('./index-09bfa46d.esm.js').then((m) => m.SearchPage),
524
+ component: () => import('./index-5842ad6f.esm.js').then((m) => m.SearchPage),
500
525
  mountPoint: rootNextRouteRef
501
526
  }));
502
527
  searchPlugin.provide(createComponentExtension({
503
528
  name: "SearchBar",
504
529
  component: {
505
- lazy: () => import('./index-1f69649c.esm.js').then((m) => m.SearchBar)
530
+ lazy: () => import('./index-05b04684.esm.js').then((m) => m.SearchBar)
506
531
  }
507
532
  }));
508
533
  const SearchBarNext = searchPlugin.provide(createComponentExtension({
509
534
  name: "SearchBarNext",
510
535
  component: {
511
- lazy: () => import('./index-1f69649c.esm.js').then((m) => m.SearchBar)
536
+ lazy: () => import('./index-05b04684.esm.js').then((m) => m.SearchBar)
512
537
  }
513
538
  }));
514
539
  const SearchResult$1 = searchPlugin.provide(createComponentExtension({
515
540
  name: "SearchResult",
516
541
  component: {
517
- lazy: () => import('./index-49a2f5d1.esm.js').then((m) => m.SearchResult)
542
+ lazy: () => import('./index-53fbff6a.esm.js').then((m) => m.SearchResult)
518
543
  }
519
544
  }));
520
545
  searchPlugin.provide(createComponentExtension({
521
546
  name: "SearchResultNext",
522
547
  component: {
523
- lazy: () => import('./index-49a2f5d1.esm.js').then((m) => m.SearchResult)
548
+ lazy: () => import('./index-53fbff6a.esm.js').then((m) => m.SearchResult)
524
549
  }
525
550
  }));
526
551
  const SidebarSearchModal = searchPlugin.provide(createComponentExtension({
527
552
  name: "SidebarSearchModal",
528
553
  component: {
529
- lazy: () => import('./index-859ff534.esm.js').then((m) => m.SidebarSearchModal)
554
+ lazy: () => import('./index-82c9eaed.esm.js').then((m) => m.SidebarSearchModal)
530
555
  }
531
556
  }));
532
557
  const DefaultResultListItem = searchPlugin.provide(createComponentExtension({
533
558
  name: "DefaultResultListItem",
534
559
  component: {
535
- lazy: () => import('./index-b647c19e.esm.js').then((m) => m.DefaultResultListItem)
560
+ lazy: () => import('./index-da49c2d7.esm.js').then((m) => m.DefaultResultListItem)
536
561
  }
537
562
  }));
538
563
  const HomePageSearchBar = searchPlugin.provide(createComponentExtension({
539
564
  name: "HomePageSearchBar",
540
565
  component: {
541
- lazy: () => import('./index-58cc0fcf.esm.js').then((m) => m.HomePageSearchBar)
566
+ lazy: () => import('./index-b090f4cf.esm.js').then((m) => m.HomePageSearchBar)
542
567
  }
543
568
  }));
544
569
 
545
- const useStyles$5 = makeStyles$1((theme) => ({
570
+ const useStyles$7 = makeStyles$1((theme) => ({
546
571
  container: {
547
572
  borderRadius: 30,
548
573
  display: "flex",
@@ -551,26 +576,16 @@ const useStyles$5 = makeStyles$1((theme) => ({
551
576
  input: {
552
577
  flex: 1
553
578
  },
554
- paperFullWidth: {height: "calc(100% - 128px)"},
555
- dialogActionsContainer: {padding: theme.spacing(1, 3)},
556
- viewResultsLink: {verticalAlign: "0.5em"}
579
+ paperFullWidth: { height: "calc(100% - 128px)" },
580
+ dialogActionsContainer: { padding: theme.spacing(1, 3) },
581
+ viewResultsLink: { verticalAlign: "0.5em" }
557
582
  }));
558
- const Modal = ({open = true, toggleModal}) => {
583
+ const Modal = ({ open = true, toggleModal }) => {
559
584
  const getSearchLink = useRouteRef(rootRouteRef);
560
- const classes = useStyles$5();
561
- const {term, setTerm} = useSearch();
562
- const [value, setValue] = useState(term);
563
- useEffect(() => {
564
- setValue((prevValue) => prevValue !== term ? term : prevValue);
565
- }, [term]);
566
- useDebounce(() => setTerm(value), 500, [value]);
567
- const handleQuery = (newValue) => {
568
- setValue(newValue);
569
- };
570
- const handleClear = () => setValue("");
585
+ const classes = useStyles$7();
586
+ const { term } = useSearch();
571
587
  const handleResultClick = () => {
572
588
  toggleModal();
573
- handleClear();
574
589
  };
575
590
  const handleKeyPress = () => {
576
591
  handleResultClick();
@@ -586,11 +601,8 @@ const Modal = ({open = true, toggleModal}) => {
586
601
  maxWidth: "lg"
587
602
  }, /* @__PURE__ */ React__default.createElement(DialogTitle, null, /* @__PURE__ */ React__default.createElement(Paper, {
588
603
  className: classes.container
589
- }, /* @__PURE__ */ React__default.createElement(SearchBarBase, {
590
- className: classes.input,
591
- value,
592
- onChange: handleQuery,
593
- onClear: handleClear
604
+ }, /* @__PURE__ */ React__default.createElement(SearchBar$1, {
605
+ className: classes.input
594
606
  }))), /* @__PURE__ */ React__default.createElement(DialogContent, null, /* @__PURE__ */ React__default.createElement(Grid, {
595
607
  container: true,
596
608
  direction: "row-reverse",
@@ -600,12 +612,12 @@ const Modal = ({open = true, toggleModal}) => {
600
612
  item: true
601
613
  }, /* @__PURE__ */ React__default.createElement(Link, {
602
614
  onClick: toggleModal,
603
- to: `${getSearchLink()}?query=${value}`
615
+ to: `${getSearchLink()}?query=${term}`
604
616
  }, /* @__PURE__ */ React__default.createElement("span", {
605
617
  className: classes.viewResultsLink
606
618
  }, "View Full Results"), /* @__PURE__ */ React__default.createElement(Launch, {
607
619
  color: "primary"
608
- })))), /* @__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", {
620
+ })))), /* @__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", {
609
621
  role: "button",
610
622
  tabIndex: 0,
611
623
  key: `${document.location}-btn`,
@@ -624,14 +636,14 @@ const Modal = ({open = true, toggleModal}) => {
624
636
  xs: 12
625
637
  }, /* @__PURE__ */ React__default.createElement(SearchResultPager, null)))));
626
638
  };
627
- const SearchModal = ({open = true, toggleModal}) => {
639
+ const SearchModal = ({ open = true, toggleModal }) => {
628
640
  return /* @__PURE__ */ React__default.createElement(SearchContextProvider, null, /* @__PURE__ */ React__default.createElement(Modal, {
629
641
  open,
630
642
  toggleModal
631
643
  }));
632
644
  };
633
645
 
634
- const useStyles$4 = makeStyles$1(() => ({
646
+ const useStyles$6 = makeStyles$1(() => ({
635
647
  root: {
636
648
  display: "flex",
637
649
  alignItems: "center"
@@ -645,7 +657,7 @@ const SearchBar = ({
645
657
  handleSearch,
646
658
  handleClearSearchBar
647
659
  }) => {
648
- const classes = useStyles$4();
660
+ const classes = useStyles$6();
649
661
  return /* @__PURE__ */ React__default.createElement(Paper, {
650
662
  component: "form",
651
663
  onSubmit: (e) => handleSearch(e),
@@ -659,14 +671,14 @@ const SearchBar = ({
659
671
  placeholder: "Search in Backstage",
660
672
  value: searchQuery,
661
673
  onChange: (e) => handleSearch(e),
662
- inputProps: {"aria-label": "search backstage"}
674
+ inputProps: { "aria-label": "search backstage" }
663
675
  }), /* @__PURE__ */ React__default.createElement(IconButton$1, {
664
676
  "aria-label": "search",
665
677
  onClick: () => handleClearSearchBar()
666
678
  }, /* @__PURE__ */ React__default.createElement(ClearButton, null)));
667
679
  };
668
680
 
669
- const useStyles$3 = makeStyles((theme) => ({
681
+ const useStyles$5 = makeStyles((theme) => ({
670
682
  filters: {
671
683
  width: "250px",
672
684
  display: "flex"
@@ -679,7 +691,7 @@ const FiltersButton = ({
679
691
  numberOfSelectedFilters,
680
692
  handleToggleFilters
681
693
  }) => {
682
- const classes = useStyles$3();
694
+ const classes = useStyles$5();
683
695
  return /* @__PURE__ */ React__default.createElement("div", {
684
696
  className: classes.filters
685
697
  }, /* @__PURE__ */ React__default.createElement(IconButton, {
@@ -691,7 +703,7 @@ const FiltersButton = ({
691
703
  }, "Filters (", numberOfSelectedFilters ? numberOfSelectedFilters : 0, ")"));
692
704
  };
693
705
 
694
- const useStyles$2 = makeStyles((theme) => ({
706
+ const useStyles$4 = makeStyles((theme) => ({
695
707
  filters: {
696
708
  background: "transparent",
697
709
  boxShadow: "0px 0px 0px 0px"
@@ -710,7 +722,7 @@ const Filters = ({
710
722
  updateSelected,
711
723
  updateChecked
712
724
  }) => {
713
- const classes = useStyles$2();
725
+ const classes = useStyles$4();
714
726
  return /* @__PURE__ */ React__default.createElement(Card, {
715
727
  className: classes.filters
716
728
  }, /* @__PURE__ */ React__default.createElement(CardHeader, {
@@ -764,7 +776,7 @@ const Filters = ({
764
776
  }))))));
765
777
  };
766
778
 
767
- const useStyles$1 = makeStyles((theme) => ({
779
+ const useStyles$3 = makeStyles((theme) => ({
768
780
  searchQuery: {
769
781
  color: theme.palette.text.primary,
770
782
  background: theme.palette.background.default,
@@ -812,7 +824,7 @@ const TableHeader = ({
812
824
  numberOfResults,
813
825
  handleToggleFilters
814
826
  }) => {
815
- const classes = useStyles$1();
827
+ const classes = useStyles$3();
816
828
  return /* @__PURE__ */ React__default.createElement("div", {
817
829
  className: classes.tableHeader
818
830
  }, /* @__PURE__ */ React__default.createElement(FiltersButton, {
@@ -832,7 +844,7 @@ const TableHeader = ({
832
844
  variant: "h6"
833
845
  }, `${numberOfResults} results`)));
834
846
  };
835
- const SearchResult = ({searchQuery}) => {
847
+ const SearchResult = ({ searchQuery }) => {
836
848
  const catalogApi = useApi(catalogApiRef);
837
849
  const [showFilters, toggleFilters] = useState(false);
838
850
  const [selectedFilters, setSelectedFilters] = useState({
@@ -942,7 +954,7 @@ const SearchResult = ({searchQuery}) => {
942
954
  item: true,
943
955
  xs: showFilters ? 9 : 12
944
956
  }, /* @__PURE__ */ React__default.createElement(Table, {
945
- options: {paging: true, pageSize: 20, search: false},
957
+ options: { paging: true, pageSize: 20, search: false },
946
958
  data: filteredResults,
947
959
  columns,
948
960
  title: /* @__PURE__ */ React__default.createElement(TableHeader, {
@@ -1007,7 +1019,7 @@ const UrlUpdater = () => {
1007
1019
  if (location.search === prevQueryParams) {
1008
1020
  return;
1009
1021
  }
1010
- const query = qs.parse(location.search.substring(1), {arrayLimit: 0}) || {};
1022
+ const query = qs.parse(location.search.substring(1), { arrayLimit: 0 }) || {};
1011
1023
  if (query.filters) {
1012
1024
  setFilters(query.filters);
1013
1025
  }
@@ -1027,7 +1039,7 @@ const UrlUpdater = () => {
1027
1039
  types,
1028
1040
  pageCursor,
1029
1041
  filters
1030
- }, {arrayFormat: "brackets"});
1042
+ }, { arrayFormat: "brackets" });
1031
1043
  const newUrl = `${window.location.pathname}?${newParams}`;
1032
1044
  window.history.replaceState(null, document.title, newUrl);
1033
1045
  }, [term, types, pageCursor, filters]);
@@ -1038,6 +1050,156 @@ const SearchPage = () => {
1038
1050
  return /* @__PURE__ */ React__default.createElement(SearchContextProvider, null, /* @__PURE__ */ React__default.createElement(UrlUpdater, null), outlet || /* @__PURE__ */ React__default.createElement(LegacySearchPage, null));
1039
1051
  };
1040
1052
 
1053
+ const useStyles$2 = makeStyles((theme) => ({
1054
+ card: {
1055
+ backgroundColor: "rgba(0, 0, 0, .11)"
1056
+ },
1057
+ cardContent: {
1058
+ paddingTop: theme.spacing(1)
1059
+ },
1060
+ icon: {
1061
+ color: theme.palette.common.black
1062
+ },
1063
+ list: {
1064
+ width: "100%"
1065
+ },
1066
+ listItemIcon: {
1067
+ width: "24px",
1068
+ height: "24px"
1069
+ },
1070
+ accordion: {
1071
+ backgroundColor: theme.palette.background.paper
1072
+ },
1073
+ accordionSummary: {
1074
+ minHeight: "auto",
1075
+ "&.Mui-expanded": {
1076
+ minHeight: "auto"
1077
+ }
1078
+ },
1079
+ accordionSummaryContent: {
1080
+ margin: theme.spacing(2, 0),
1081
+ "&.Mui-expanded": {
1082
+ margin: theme.spacing(2, 0)
1083
+ }
1084
+ },
1085
+ accordionDetails: {
1086
+ padding: theme.spacing(0, 0, 1)
1087
+ }
1088
+ }));
1089
+ const SearchTypeAccordion = (props) => {
1090
+ const classes = useStyles$2();
1091
+ const { setPageCursor, setTypes, types } = useSearch();
1092
+ const [expanded, setExpanded] = useState(true);
1093
+ const { defaultValue, name, types: givenTypes } = props;
1094
+ const toggleExpanded = () => setExpanded((prevState) => !prevState);
1095
+ const handleClick = (type) => {
1096
+ return () => {
1097
+ setTypes(type !== "" ? [type] : []);
1098
+ setPageCursor(void 0);
1099
+ setExpanded(false);
1100
+ };
1101
+ };
1102
+ useEffect(() => {
1103
+ if (defaultValue) {
1104
+ setTypes([defaultValue]);
1105
+ }
1106
+ }, []);
1107
+ const definedTypes = [
1108
+ {
1109
+ value: "",
1110
+ name: "All",
1111
+ icon: /* @__PURE__ */ React__default.createElement(AllIcon, null)
1112
+ },
1113
+ ...givenTypes
1114
+ ];
1115
+ const selected = types[0] || "";
1116
+ return /* @__PURE__ */ React__default.createElement(Card, {
1117
+ className: classes.card
1118
+ }, /* @__PURE__ */ React__default.createElement(CardHeader, {
1119
+ title: name,
1120
+ titleTypographyProps: { variant: "overline" }
1121
+ }), /* @__PURE__ */ React__default.createElement(CardContent, {
1122
+ className: classes.cardContent
1123
+ }, /* @__PURE__ */ React__default.createElement(Accordion, {
1124
+ className: classes.accordion,
1125
+ expanded,
1126
+ onChange: toggleExpanded
1127
+ }, /* @__PURE__ */ React__default.createElement(AccordionSummary, {
1128
+ classes: {
1129
+ root: classes.accordionSummary,
1130
+ content: classes.accordionSummaryContent
1131
+ },
1132
+ expandIcon: /* @__PURE__ */ React__default.createElement(ExpandMoreIcon, {
1133
+ className: classes.icon
1134
+ }),
1135
+ IconButtonProps: { size: "small" }
1136
+ }, expanded ? "Collapse" : definedTypes.filter((t) => t.value === selected)[0].name), /* @__PURE__ */ React__default.createElement(AccordionDetails, {
1137
+ classes: { root: classes.accordionDetails }
1138
+ }, /* @__PURE__ */ React__default.createElement(List, {
1139
+ className: classes.list,
1140
+ component: "nav",
1141
+ "aria-label": "filter by type",
1142
+ disablePadding: true,
1143
+ dense: true
1144
+ }, definedTypes.map((type) => /* @__PURE__ */ React__default.createElement(Fragment, {
1145
+ key: type.value
1146
+ }, /* @__PURE__ */ React__default.createElement(Divider, null), /* @__PURE__ */ React__default.createElement(ListItem, {
1147
+ selected: types[0] === type.value || types.length === 0 && type.value === "",
1148
+ onClick: handleClick(type.value),
1149
+ button: true
1150
+ }, /* @__PURE__ */ React__default.createElement(ListItemIcon, null, cloneElement(type.icon, {
1151
+ className: classes.listItemIcon
1152
+ })), /* @__PURE__ */ React__default.createElement(ListItemText, {
1153
+ primary: type.name
1154
+ })))))))));
1155
+ };
1156
+
1157
+ const useStyles$1 = makeStyles((theme) => ({
1158
+ tabs: {
1159
+ borderBottom: `1px solid ${theme.palette.textVerySubtle}`,
1160
+ padding: theme.spacing(0, 4)
1161
+ },
1162
+ tab: {
1163
+ height: "50px",
1164
+ fontWeight: theme.typography.fontWeightBold,
1165
+ fontSize: theme.typography.pxToRem(13),
1166
+ color: theme.palette.textSubtle,
1167
+ minWidth: "130px"
1168
+ }
1169
+ }));
1170
+ const SearchTypeTabs = (props) => {
1171
+ const classes = useStyles$1();
1172
+ const { setPageCursor, setTypes, types } = useSearch();
1173
+ const { defaultValue, types: givenTypes } = props;
1174
+ const changeTab = (_, newType) => {
1175
+ setTypes(newType !== "" ? [newType] : []);
1176
+ setPageCursor(void 0);
1177
+ };
1178
+ useEffect(() => {
1179
+ if (defaultValue) {
1180
+ setTypes([defaultValue]);
1181
+ }
1182
+ }, []);
1183
+ const definedTypes = [
1184
+ {
1185
+ value: "",
1186
+ name: "All"
1187
+ },
1188
+ ...givenTypes
1189
+ ];
1190
+ return /* @__PURE__ */ React__default.createElement(Tabs, {
1191
+ className: classes.tabs,
1192
+ indicatorColor: "primary",
1193
+ value: types.length === 0 ? "" : types[0],
1194
+ onChange: changeTab
1195
+ }, definedTypes.map((type) => /* @__PURE__ */ React__default.createElement(Tab, {
1196
+ className: classes.tab,
1197
+ disableRipple: true,
1198
+ label: type.name,
1199
+ value: type.value
1200
+ })));
1201
+ };
1202
+
1041
1203
  const useStyles = makeStyles((theme) => ({
1042
1204
  label: {
1043
1205
  textTransform: "capitalize"
@@ -1051,14 +1213,10 @@ const useStyles = makeStyles((theme) => ({
1051
1213
  margin: 2
1052
1214
  }
1053
1215
  }));
1054
- const SearchType = ({
1055
- values = [],
1056
- className,
1057
- name,
1058
- defaultValue
1059
- }) => {
1216
+ const SearchType = (props) => {
1217
+ const { className, defaultValue, name, values = [] } = props;
1060
1218
  const classes = useStyles();
1061
- const {types, setTypes} = useSearch();
1219
+ const { types, setTypes } = useSearch();
1062
1220
  useEffectOnce(() => {
1063
1221
  if (!types.length) {
1064
1222
  if (defaultValue && Array.isArray(defaultValue)) {
@@ -1103,19 +1261,30 @@ const SearchType = ({
1103
1261
  primary: value
1104
1262
  })))));
1105
1263
  };
1264
+ SearchType.Accordion = (props) => {
1265
+ return /* @__PURE__ */ React__default.createElement(SearchTypeAccordion, {
1266
+ ...props
1267
+ });
1268
+ };
1269
+ SearchType.Tabs = (props) => {
1270
+ return /* @__PURE__ */ React__default.createElement(SearchTypeTabs, {
1271
+ ...props
1272
+ });
1273
+ };
1106
1274
 
1107
- const SidebarSearch = () => {
1275
+ const SidebarSearch = (props) => {
1108
1276
  const searchRoute = useRouteRef(rootRouteRef);
1109
1277
  const navigate = useNavigate();
1110
1278
  const handleSearch = useCallback((query) => {
1111
- const queryString = qs.stringify({query}, {addQueryPrefix: true});
1279
+ const queryString = qs.stringify({ query }, { addQueryPrefix: true });
1112
1280
  navigate(`${searchRoute()}${queryString}`);
1113
1281
  }, [navigate, searchRoute]);
1114
1282
  return /* @__PURE__ */ React__default.createElement(SidebarSearchField, {
1283
+ icon: props.icon,
1115
1284
  onSearch: handleSearch,
1116
1285
  to: "/search"
1117
1286
  });
1118
1287
  };
1119
1288
 
1120
1289
  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 };
1121
- //# sourceMappingURL=index-8e7d7ce9.esm.js.map
1290
+ //# sourceMappingURL=index-9ed6d72a.esm.js.map