@backstage/plugin-search-react 1.7.10 → 1.7.11-next.1
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 +21 -0
- package/alpha/package.json +1 -1
- package/dist/alpha.esm.js +1 -10
- package/dist/alpha.esm.js.map +1 -1
- package/dist/api.esm.js +16 -0
- package/dist/api.esm.js.map +1 -0
- package/dist/components/DefaultResultListItem/DefaultResultListItem.esm.js +70 -0
- package/dist/components/DefaultResultListItem/DefaultResultListItem.esm.js.map +1 -0
- package/dist/components/HighlightedSearchResultText/HighlightedSearchResultText.esm.js +23 -0
- package/dist/components/HighlightedSearchResultText/HighlightedSearchResultText.esm.js.map +1 -0
- package/dist/components/SearchAutocomplete/SearchAutocomplete.esm.js +107 -0
- package/dist/components/SearchAutocomplete/SearchAutocomplete.esm.js.map +1 -0
- package/dist/components/SearchAutocomplete/SearchAutocompleteDefaultOption.esm.js +27 -0
- package/dist/components/SearchAutocomplete/SearchAutocompleteDefaultOption.esm.js.map +1 -0
- package/dist/components/SearchBar/SearchBar.esm.js +161 -0
- package/dist/components/SearchBar/SearchBar.esm.js.map +1 -0
- package/dist/components/SearchFilter/SearchFilter.Autocomplete.esm.js +72 -0
- package/dist/components/SearchFilter/SearchFilter.Autocomplete.esm.js.map +1 -0
- package/dist/components/SearchFilter/SearchFilter.esm.js +157 -0
- package/dist/components/SearchFilter/SearchFilter.esm.js.map +1 -0
- package/dist/components/SearchFilter/hooks.esm.js +52 -0
- package/dist/components/SearchFilter/hooks.esm.js.map +1 -0
- package/dist/components/SearchPagination/SearchPagination.esm.js +82 -0
- package/dist/components/SearchPagination/SearchPagination.esm.js.map +1 -0
- package/dist/components/SearchResult/SearchResult.esm.js +70 -0
- package/dist/components/SearchResult/SearchResult.esm.js.map +1 -0
- package/dist/components/SearchResultGroup/SearchResultGroup.esm.js +259 -0
- package/dist/components/SearchResultGroup/SearchResultGroup.esm.js.map +1 -0
- package/dist/components/SearchResultList/SearchResultList.esm.js +67 -0
- package/dist/components/SearchResultList/SearchResultList.esm.js.map +1 -0
- package/dist/components/SearchResultPager/SearchResultPager.esm.js +44 -0
- package/dist/components/SearchResultPager/SearchResultPager.esm.js.map +1 -0
- package/dist/context/SearchContext.esm.js +126 -0
- package/dist/context/SearchContext.esm.js.map +1 -0
- package/dist/extensions.esm.js +123 -0
- package/dist/extensions.esm.js.map +1 -0
- package/dist/index.esm.js +15 -1153
- package/dist/index.esm.js.map +1 -1
- package/package.json +8 -8
- package/dist/esm/extensions-COgIMweE.esm.js +0 -205
- package/dist/esm/extensions-COgIMweE.esm.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchFilter.Autocomplete.esm.js","sources":["../../../src/components/SearchFilter/SearchFilter.Autocomplete.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 React, { ChangeEvent, useState } from 'react';\nimport Chip from '@material-ui/core/Chip';\nimport TextField from '@material-ui/core/TextField';\nimport Autocomplete, {\n AutocompleteGetTagProps,\n AutocompleteRenderInputParams,\n} from '@material-ui/lab/Autocomplete';\n\nimport { useSearch } from '../../context';\nimport { useAsyncFilterValues, useDefaultFilterValue } from './hooks';\nimport { SearchFilterComponentProps } from './SearchFilter';\n\n/**\n * @public\n */\nexport type SearchAutocompleteFilterProps = SearchFilterComponentProps & {\n filterSelectedOptions?: boolean;\n limitTags?: number;\n multiple?: boolean;\n};\n\n/**\n * @public\n */\nexport const AutocompleteFilter = (props: SearchAutocompleteFilterProps) => {\n const {\n className,\n defaultValue,\n name,\n values: givenValues,\n valuesDebounceMs,\n label,\n filterSelectedOptions,\n limitTags,\n multiple,\n } = props;\n const [inputValue, setInputValue] = useState<string>('');\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values, loading } = useAsyncFilterValues(\n asyncValues,\n inputValue,\n defaultValues,\n valuesDebounceMs,\n );\n const { filters, setFilters } = useSearch();\n const filterValue =\n (filters[name] as string | string[] | undefined) || (multiple ? [] : null);\n\n // Set new filter values on input change.\n const handleChange = (\n _: ChangeEvent<{}>,\n newValue: string | string[] | null,\n ) => {\n setFilters(prevState => {\n const { [name]: filter, ...others } = prevState;\n\n if (newValue) {\n return { ...others, [name]: newValue };\n }\n return { ...others };\n });\n };\n\n // Provide the input field.\n const renderInput = (params: AutocompleteRenderInputParams) => (\n <TextField\n {...params}\n name=\"search\"\n variant=\"outlined\"\n label={label}\n fullWidth\n />\n );\n\n // Render tags as primary-colored chips.\n const renderTags = (\n tagValue: string[],\n getTagProps: AutocompleteGetTagProps,\n ) =>\n tagValue.map((option: string, index: number) => (\n <Chip label={option} color=\"primary\" {...getTagProps({ index })} />\n ));\n\n return (\n <Autocomplete\n filterSelectedOptions={filterSelectedOptions}\n limitTags={limitTags}\n multiple={multiple}\n className={className}\n id={`${multiple ? 'multi-' : ''}select-filter-${name}--select`}\n options={values || []}\n loading={loading}\n value={filterValue}\n onChange={handleChange}\n onInputChange={(_, newValue) => setInputValue(newValue)}\n renderInput={renderInput}\n renderTags={renderTags}\n />\n );\n};\n"],"names":[],"mappings":";;;;;;;AAwCa,MAAA,kBAAA,GAAqB,CAAC,KAAyC,KAAA;AAC1E,EAAM,MAAA;AAAA,IACJ,SAAA;AAAA,IACA,YAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAQ,EAAA,WAAA;AAAA,IACR,gBAAA;AAAA,IACA,KAAA;AAAA,IACA,qBAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,GACE,GAAA,KAAA,CAAA;AACJ,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAAiB,EAAE,CAAA,CAAA;AACvD,EAAA,qBAAA,CAAsB,MAAM,YAAY,CAAA,CAAA;AACxC,EAAA,MAAM,WACJ,GAAA,OAAO,WAAgB,KAAA,UAAA,GAAa,WAAc,GAAA,KAAA,CAAA,CAAA;AACpD,EAAA,MAAM,aACJ,GAAA,OAAO,WAAgB,KAAA,UAAA,GAAa,KAAY,CAAA,GAAA,WAAA,CAAA;AAClD,EAAA,MAAM,EAAE,KAAA,EAAO,MAAQ,EAAA,OAAA,EAAY,GAAA,oBAAA;AAAA,IACjC,WAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,gBAAA;AAAA,GACF,CAAA;AACA,EAAA,MAAM,EAAE,OAAA,EAAS,UAAW,EAAA,GAAI,SAAU,EAAA,CAAA;AAC1C,EAAA,MAAM,cACH,OAAQ,CAAA,IAAI,CAAwC,KAAA,QAAA,GAAW,EAAK,GAAA,IAAA,CAAA,CAAA;AAGvE,EAAM,MAAA,YAAA,GAAe,CACnB,CAAA,EACA,QACG,KAAA;AACH,IAAA,UAAA,CAAW,CAAa,SAAA,KAAA;AACtB,MAAA,MAAM,EAAE,CAAC,IAAI,GAAG,MAAQ,EAAA,GAAG,QAAW,GAAA,SAAA,CAAA;AAEtC,MAAA,IAAI,QAAU,EAAA;AACZ,QAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,CAAC,IAAI,GAAG,QAAS,EAAA,CAAA;AAAA,OACvC;AACA,MAAO,OAAA,EAAE,GAAG,MAAO,EAAA,CAAA;AAAA,KACpB,CAAA,CAAA;AAAA,GACH,CAAA;AAGA,EAAM,MAAA,WAAA,GAAc,CAAC,MACnB,qBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACE,GAAG,MAAA;AAAA,MACJ,IAAK,EAAA,QAAA;AAAA,MACL,OAAQ,EAAA,UAAA;AAAA,MACR,KAAA;AAAA,MACA,SAAS,EAAA,IAAA;AAAA,KAAA;AAAA,GACX,CAAA;AAIF,EAAM,MAAA,UAAA,GAAa,CACjB,QACA,EAAA,WAAA,KAEA,SAAS,GAAI,CAAA,CAAC,QAAgB,KAC5B,qBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,KAAO,EAAA,MAAA,EAAQ,OAAM,SAAW,EAAA,GAAG,YAAY,EAAE,KAAA,EAAO,CAAA,EAAG,CAClE,CAAA,CAAA;AAEH,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,qBAAA;AAAA,MACA,SAAA;AAAA,MACA,QAAA;AAAA,MACA,SAAA;AAAA,MACA,IAAI,CAAG,EAAA,QAAA,GAAW,QAAW,GAAA,EAAE,iBAAiB,IAAI,CAAA,QAAA,CAAA;AAAA,MACpD,OAAA,EAAS,UAAU,EAAC;AAAA,MACpB,OAAA;AAAA,MACA,KAAO,EAAA,WAAA;AAAA,MACP,QAAU,EAAA,YAAA;AAAA,MACV,aAAe,EAAA,CAAC,CAAG,EAAA,QAAA,KAAa,cAAc,QAAQ,CAAA;AAAA,MACtD,WAAA;AAAA,MACA,UAAA;AAAA,KAAA;AAAA,GACF,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import FormControl from '@material-ui/core/FormControl';
|
|
3
|
+
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
|
4
|
+
import InputLabel from '@material-ui/core/InputLabel';
|
|
5
|
+
import Checkbox from '@material-ui/core/Checkbox';
|
|
6
|
+
import Select from '@material-ui/core/Select';
|
|
7
|
+
import MenuItem from '@material-ui/core/MenuItem';
|
|
8
|
+
import FormLabel from '@material-ui/core/FormLabel';
|
|
9
|
+
import Typography from '@material-ui/core/Typography';
|
|
10
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
11
|
+
import { useSearch } from '../../context/SearchContext.esm.js';
|
|
12
|
+
import { AutocompleteFilter } from './SearchFilter.Autocomplete.esm.js';
|
|
13
|
+
import { useDefaultFilterValue, useAsyncFilterValues } from './hooks.esm.js';
|
|
14
|
+
|
|
15
|
+
const useStyles = makeStyles({
|
|
16
|
+
label: {
|
|
17
|
+
textTransform: "capitalize"
|
|
18
|
+
},
|
|
19
|
+
checkboxWrapper: {
|
|
20
|
+
display: "flex",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
width: "100%"
|
|
23
|
+
},
|
|
24
|
+
textWrapper: {
|
|
25
|
+
overflow: "hidden",
|
|
26
|
+
textOverflow: "ellipsis",
|
|
27
|
+
whiteSpace: "nowrap"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const CheckboxFilter = (props) => {
|
|
31
|
+
const {
|
|
32
|
+
className,
|
|
33
|
+
defaultValue,
|
|
34
|
+
label,
|
|
35
|
+
name,
|
|
36
|
+
values: givenValues = [],
|
|
37
|
+
valuesDebounceMs
|
|
38
|
+
} = props;
|
|
39
|
+
const classes = useStyles();
|
|
40
|
+
const { filters, setFilters } = useSearch();
|
|
41
|
+
useDefaultFilterValue(name, defaultValue);
|
|
42
|
+
const asyncValues = typeof givenValues === "function" ? givenValues : void 0;
|
|
43
|
+
const defaultValues = typeof givenValues === "function" ? void 0 : givenValues;
|
|
44
|
+
const { value: values = [], loading } = useAsyncFilterValues(
|
|
45
|
+
asyncValues,
|
|
46
|
+
"",
|
|
47
|
+
defaultValues,
|
|
48
|
+
valuesDebounceMs
|
|
49
|
+
);
|
|
50
|
+
const handleChange = (e) => {
|
|
51
|
+
const {
|
|
52
|
+
target: { value, checked }
|
|
53
|
+
} = e;
|
|
54
|
+
setFilters((prevFilters) => {
|
|
55
|
+
const { [name]: filter, ...others } = prevFilters;
|
|
56
|
+
const rest = (filter || []).filter((i) => i !== value);
|
|
57
|
+
const items = checked ? [...rest, value] : rest;
|
|
58
|
+
return items.length ? { ...others, [name]: items } : others;
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
return /* @__PURE__ */ React.createElement(
|
|
62
|
+
FormControl,
|
|
63
|
+
{
|
|
64
|
+
className,
|
|
65
|
+
disabled: loading,
|
|
66
|
+
fullWidth: true,
|
|
67
|
+
"data-testid": "search-checkboxfilter-next"
|
|
68
|
+
},
|
|
69
|
+
label ? /* @__PURE__ */ React.createElement(FormLabel, { className: classes.label }, label) : null,
|
|
70
|
+
values.map((value) => {
|
|
71
|
+
var _a;
|
|
72
|
+
return /* @__PURE__ */ React.createElement(
|
|
73
|
+
FormControlLabel,
|
|
74
|
+
{
|
|
75
|
+
key: value,
|
|
76
|
+
classes: {
|
|
77
|
+
root: classes.checkboxWrapper,
|
|
78
|
+
label: classes.textWrapper
|
|
79
|
+
},
|
|
80
|
+
label: value,
|
|
81
|
+
control: /* @__PURE__ */ React.createElement(
|
|
82
|
+
Checkbox,
|
|
83
|
+
{
|
|
84
|
+
color: "primary",
|
|
85
|
+
inputProps: { "aria-labelledby": value },
|
|
86
|
+
value,
|
|
87
|
+
name: value,
|
|
88
|
+
onChange: handleChange,
|
|
89
|
+
checked: ((_a = filters[name]) != null ? _a : []).includes(value)
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
const SelectFilter = (props) => {
|
|
98
|
+
const {
|
|
99
|
+
className,
|
|
100
|
+
defaultValue,
|
|
101
|
+
label,
|
|
102
|
+
name,
|
|
103
|
+
values: givenValues,
|
|
104
|
+
valuesDebounceMs
|
|
105
|
+
} = props;
|
|
106
|
+
const classes = useStyles();
|
|
107
|
+
useDefaultFilterValue(name, defaultValue);
|
|
108
|
+
const asyncValues = typeof givenValues === "function" ? givenValues : void 0;
|
|
109
|
+
const defaultValues = typeof givenValues === "function" ? void 0 : givenValues;
|
|
110
|
+
const { value: values = [], loading } = useAsyncFilterValues(
|
|
111
|
+
asyncValues,
|
|
112
|
+
"",
|
|
113
|
+
defaultValues,
|
|
114
|
+
valuesDebounceMs
|
|
115
|
+
);
|
|
116
|
+
const { filters, setFilters } = useSearch();
|
|
117
|
+
const handleChange = (e) => {
|
|
118
|
+
const {
|
|
119
|
+
target: { value }
|
|
120
|
+
} = e;
|
|
121
|
+
setFilters((prevFilters) => {
|
|
122
|
+
const { [name]: filter, ...others } = prevFilters;
|
|
123
|
+
return value ? { ...others, [name]: value } : others;
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
return /* @__PURE__ */ React.createElement(
|
|
127
|
+
FormControl,
|
|
128
|
+
{
|
|
129
|
+
disabled: loading,
|
|
130
|
+
className,
|
|
131
|
+
variant: "filled",
|
|
132
|
+
fullWidth: true,
|
|
133
|
+
"data-testid": "search-selectfilter-next"
|
|
134
|
+
},
|
|
135
|
+
label ? /* @__PURE__ */ React.createElement(InputLabel, { className: classes.label, margin: "dense" }, label) : null,
|
|
136
|
+
/* @__PURE__ */ React.createElement(
|
|
137
|
+
Select,
|
|
138
|
+
{
|
|
139
|
+
variant: "outlined",
|
|
140
|
+
value: filters[name] || "",
|
|
141
|
+
onChange: handleChange
|
|
142
|
+
},
|
|
143
|
+
/* @__PURE__ */ React.createElement(MenuItem, { value: "" }, /* @__PURE__ */ React.createElement("em", null, "All")),
|
|
144
|
+
values.map((value) => /* @__PURE__ */ React.createElement(MenuItem, { key: value, value }, /* @__PURE__ */ React.createElement(Typography, { variant: "inherit", noWrap: true }, value)))
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
const SearchFilter = (props) => {
|
|
149
|
+
const { component: Element, ...elementProps } = props;
|
|
150
|
+
return /* @__PURE__ */ React.createElement(Element, { ...elementProps });
|
|
151
|
+
};
|
|
152
|
+
SearchFilter.Checkbox = (props) => /* @__PURE__ */ React.createElement(SearchFilter, { ...props, component: CheckboxFilter });
|
|
153
|
+
SearchFilter.Select = (props) => /* @__PURE__ */ React.createElement(SearchFilter, { ...props, component: SelectFilter });
|
|
154
|
+
SearchFilter.Autocomplete = (props) => /* @__PURE__ */ React.createElement(SearchFilter, { ...props, component: AutocompleteFilter });
|
|
155
|
+
|
|
156
|
+
export { CheckboxFilter, SearchFilter, SelectFilter };
|
|
157
|
+
//# sourceMappingURL=SearchFilter.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchFilter.esm.js","sources":["../../../src/components/SearchFilter/SearchFilter.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 React, { ReactElement, ChangeEvent } from 'react';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport Select from '@material-ui/core/Select';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport FormLabel from '@material-ui/core/FormLabel';\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\n\nimport { useSearch } from '../../context';\nimport {\n AutocompleteFilter,\n SearchAutocompleteFilterProps,\n} from './SearchFilter.Autocomplete';\nimport { useAsyncFilterValues, useDefaultFilterValue } from './hooks';\n\nconst useStyles = makeStyles({\n label: {\n textTransform: 'capitalize',\n },\n checkboxWrapper: {\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n },\n textWrapper: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n});\n\n/**\n * @public\n */\nexport type SearchFilterComponentProps = {\n className?: string;\n name: string;\n label?: string;\n /**\n * Either an array of values directly, or an async function to return a list\n * of values to be used in the filter. In the autocomplete filter, the last\n * input value is provided as an input to allow values to be filtered. This\n * function is debounced and values cached.\n */\n values?: string[] | ((partial: string) => Promise<string[]>);\n defaultValue?: string[] | string | null;\n /**\n * Debounce time in milliseconds, used when values is an async callback.\n * Defaults to 250ms.\n */\n valuesDebounceMs?: number;\n};\n\n/**\n * @public\n */\nexport type SearchFilterWrapperProps = SearchFilterComponentProps & {\n component: (props: SearchFilterComponentProps) => ReactElement;\n debug?: boolean;\n};\n\n/**\n * @public\n */\nexport const CheckboxFilter = (props: SearchFilterComponentProps) => {\n const {\n className,\n defaultValue,\n label,\n name,\n values: givenValues = [],\n valuesDebounceMs,\n } = props;\n const classes = useStyles();\n const { filters, setFilters } = useSearch();\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values = [], loading } = useAsyncFilterValues(\n asyncValues,\n '',\n defaultValues,\n valuesDebounceMs,\n );\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n const {\n target: { value, checked },\n } = e;\n\n setFilters(prevFilters => {\n const { [name]: filter, ...others } = prevFilters;\n const rest = ((filter as string[]) || []).filter(i => i !== value);\n const items = checked ? [...rest, value] : rest;\n return items.length ? { ...others, [name]: items } : others;\n });\n };\n\n return (\n <FormControl\n className={className}\n disabled={loading}\n fullWidth\n data-testid=\"search-checkboxfilter-next\"\n >\n {label ? <FormLabel className={classes.label}>{label}</FormLabel> : null}\n {values.map((value: string) => (\n <FormControlLabel\n key={value}\n classes={{\n root: classes.checkboxWrapper,\n label: classes.textWrapper,\n }}\n label={value}\n control={\n <Checkbox\n color=\"primary\"\n inputProps={{ 'aria-labelledby': value }}\n value={value}\n name={value}\n onChange={handleChange}\n checked={((filters[name] as string[]) ?? []).includes(value)}\n />\n }\n />\n ))}\n </FormControl>\n );\n};\n\n/**\n * @public\n */\nexport const SelectFilter = (props: SearchFilterComponentProps) => {\n const {\n className,\n defaultValue,\n label,\n name,\n values: givenValues,\n valuesDebounceMs,\n } = props;\n const classes = useStyles();\n useDefaultFilterValue(name, defaultValue);\n const asyncValues =\n typeof givenValues === 'function' ? givenValues : undefined;\n const defaultValues =\n typeof givenValues === 'function' ? undefined : givenValues;\n const { value: values = [], loading } = useAsyncFilterValues(\n asyncValues,\n '',\n defaultValues,\n valuesDebounceMs,\n );\n const { filters, setFilters } = useSearch();\n\n const handleChange = (e: ChangeEvent<{ value: unknown }>) => {\n const {\n target: { value },\n } = e;\n\n setFilters(prevFilters => {\n const { [name]: filter, ...others } = prevFilters;\n return value ? { ...others, [name]: value as string } : others;\n });\n };\n\n return (\n <FormControl\n disabled={loading}\n className={className}\n variant=\"filled\"\n fullWidth\n data-testid=\"search-selectfilter-next\"\n >\n {label ? (\n <InputLabel className={classes.label} margin=\"dense\">\n {label}\n </InputLabel>\n ) : null}\n <Select\n variant=\"outlined\"\n value={filters[name] || ''}\n onChange={handleChange}\n >\n <MenuItem value=\"\">\n <em>All</em>\n </MenuItem>\n {values.map((value: string) => (\n <MenuItem key={value} value={value}>\n <Typography variant=\"inherit\" noWrap>\n {value}\n </Typography>\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n );\n};\n\n/**\n * @public\n */\nconst SearchFilter = (props: SearchFilterWrapperProps) => {\n const { component: Element, ...elementProps } = props;\n return <Element {...elementProps} />;\n};\n\nSearchFilter.Checkbox = (\n props: Omit<SearchFilterWrapperProps, 'component'> &\n SearchFilterComponentProps,\n) => <SearchFilter {...props} component={CheckboxFilter} />;\n\nSearchFilter.Select = (\n props: Omit<SearchFilterWrapperProps, 'component'> &\n SearchFilterComponentProps,\n) => <SearchFilter {...props} component={SelectFilter} />;\n\n/**\n * A control surface for a given filter field name, rendered as an autocomplete\n * textfield. A hard-coded list of values may be provided, or an async function\n * which returns values may be provided instead.\n *\n * @public\n */\nSearchFilter.Autocomplete = (props: SearchAutocompleteFilterProps) => (\n <SearchFilter {...props} component={AutocompleteFilter} />\n);\n\nexport { SearchFilter };\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useRef, useEffect } from 'react';
|
|
2
|
+
import useAsyncFn from 'react-use/esm/useAsyncFn';
|
|
3
|
+
import useDebounce from 'react-use/esm/useDebounce';
|
|
4
|
+
import { useSearch } from '../../context/SearchContext.esm.js';
|
|
5
|
+
|
|
6
|
+
const useAsyncFilterValues = (fn, inputValue, defaultValues = [], debounce = 250) => {
|
|
7
|
+
const valuesMemo = useRef({});
|
|
8
|
+
const definiteFn = fn || (() => Promise.resolve([]));
|
|
9
|
+
const [state, callback] = useAsyncFn(definiteFn, [inputValue], {
|
|
10
|
+
loading: true
|
|
11
|
+
});
|
|
12
|
+
useDebounce(
|
|
13
|
+
() => {
|
|
14
|
+
if (valuesMemo.current[inputValue] === void 0) {
|
|
15
|
+
valuesMemo.current[inputValue] = callback(inputValue).then((values) => {
|
|
16
|
+
valuesMemo.current[inputValue] = values;
|
|
17
|
+
return values;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
debounce,
|
|
22
|
+
[callback, inputValue]
|
|
23
|
+
);
|
|
24
|
+
if (defaultValues.length) {
|
|
25
|
+
return {
|
|
26
|
+
loading: false,
|
|
27
|
+
value: defaultValues
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const possibleValue = valuesMemo.current[inputValue];
|
|
31
|
+
if (Array.isArray(possibleValue)) {
|
|
32
|
+
return {
|
|
33
|
+
loading: false,
|
|
34
|
+
value: possibleValue
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return state;
|
|
38
|
+
};
|
|
39
|
+
const useDefaultFilterValue = (name, defaultValue) => {
|
|
40
|
+
const { setFilters } = useSearch();
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (defaultValue && [defaultValue].flat().length > 0) {
|
|
43
|
+
setFilters((prevFilters) => ({
|
|
44
|
+
...prevFilters,
|
|
45
|
+
[name]: defaultValue
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
}, []);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { useAsyncFilterValues, useDefaultFilterValue };
|
|
52
|
+
//# sourceMappingURL=hooks.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.esm.js","sources":["../../../src/components/SearchFilter/hooks.ts"],"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 { useEffect, useRef } from 'react';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport useDebounce from 'react-use/esm/useDebounce';\n\nimport { useSearch } from '../../context';\n\n/**\n * Utility hook for either asynchronously loading filter values from a given\n * function or synchronously providing a given list of default values.\n *\n * @public\n */\nexport const useAsyncFilterValues = (\n fn: ((partial: string) => Promise<string[]>) | undefined,\n inputValue: string,\n defaultValues: string[] = [],\n debounce: number = 250,\n) => {\n const valuesMemo = useRef<Record<string, string[] | Promise<string[]>>>({});\n const definiteFn = fn || (() => Promise.resolve([]));\n\n const [state, callback] = useAsyncFn(definiteFn, [inputValue], {\n loading: true,\n });\n\n // Do not invoke the given function more than necessary.\n useDebounce(\n () => {\n // Performance optimization: only invoke the callback once per inputValue\n // for the lifetime of the hook/component.\n if (valuesMemo.current[inputValue] === undefined) {\n valuesMemo.current[inputValue] = callback(inputValue).then(values => {\n // Override the value for future immediate returns.\n valuesMemo.current[inputValue] = values;\n return values;\n });\n }\n },\n debounce,\n [callback, inputValue],\n );\n\n // Immediately return the default values if they are provided.\n if (defaultValues.length) {\n return {\n loading: false,\n value: defaultValues,\n };\n }\n\n // Immediately return a memoized value if it is set (and not a promise).\n const possibleValue = valuesMemo.current[inputValue];\n if (Array.isArray(possibleValue)) {\n return {\n loading: false,\n value: possibleValue,\n };\n }\n\n return state;\n};\n\n/**\n * Utility hook for applying a given default value to the search context.\n *\n * @public\n */\nexport const useDefaultFilterValue = (\n name: string,\n defaultValue?: string | string[] | null,\n) => {\n const { setFilters } = useSearch();\n\n useEffect(() => {\n if (defaultValue && [defaultValue].flat().length > 0) {\n setFilters(prevFilters => ({\n ...prevFilters,\n [name]: defaultValue,\n }));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n};\n"],"names":[],"mappings":";;;;;AA4Ba,MAAA,oBAAA,GAAuB,CAClC,EACA,EAAA,UAAA,EACA,gBAA0B,EAAC,EAC3B,WAAmB,GAChB,KAAA;AACH,EAAM,MAAA,UAAA,GAAa,MAAqD,CAAA,EAAE,CAAA,CAAA;AAC1E,EAAA,MAAM,aAAa,EAAO,KAAA,MAAM,OAAQ,CAAA,OAAA,CAAQ,EAAE,CAAA,CAAA,CAAA;AAElD,EAAM,MAAA,CAAC,OAAO,QAAQ,CAAA,GAAI,WAAW,UAAY,EAAA,CAAC,UAAU,CAAG,EAAA;AAAA,IAC7D,OAAS,EAAA,IAAA;AAAA,GACV,CAAA,CAAA;AAGD,EAAA,WAAA;AAAA,IACE,MAAM;AAGJ,MAAA,IAAI,UAAW,CAAA,OAAA,CAAQ,UAAU,CAAA,KAAM,KAAW,CAAA,EAAA;AAChD,QAAA,UAAA,CAAW,QAAQ,UAAU,CAAA,GAAI,SAAS,UAAU,CAAA,CAAE,KAAK,CAAU,MAAA,KAAA;AAEnE,UAAW,UAAA,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,MAAA,CAAA;AACjC,UAAO,OAAA,MAAA,CAAA;AAAA,SACR,CAAA,CAAA;AAAA,OACH;AAAA,KACF;AAAA,IACA,QAAA;AAAA,IACA,CAAC,UAAU,UAAU,CAAA;AAAA,GACvB,CAAA;AAGA,EAAA,IAAI,cAAc,MAAQ,EAAA;AACxB,IAAO,OAAA;AAAA,MACL,OAAS,EAAA,KAAA;AAAA,MACT,KAAO,EAAA,aAAA;AAAA,KACT,CAAA;AAAA,GACF;AAGA,EAAM,MAAA,aAAA,GAAgB,UAAW,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAA;AACnD,EAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,aAAa,CAAG,EAAA;AAChC,IAAO,OAAA;AAAA,MACL,OAAS,EAAA,KAAA;AAAA,MACT,KAAO,EAAA,aAAA;AAAA,KACT,CAAA;AAAA,GACF;AAEA,EAAO,OAAA,KAAA,CAAA;AACT,EAAA;AAOa,MAAA,qBAAA,GAAwB,CACnC,IAAA,EACA,YACG,KAAA;AACH,EAAM,MAAA,EAAE,UAAW,EAAA,GAAI,SAAU,EAAA,CAAA;AAEjC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,gBAAgB,CAAC,YAAY,EAAE,IAAK,EAAA,CAAE,SAAS,CAAG,EAAA;AACpD,MAAA,UAAA,CAAW,CAAgB,WAAA,MAAA;AAAA,QACzB,GAAG,WAAA;AAAA,QACH,CAAC,IAAI,GAAG,YAAA;AAAA,OACR,CAAA,CAAA,CAAA;AAAA,KACJ;AAAA,GAEF,EAAG,EAAE,CAAA,CAAA;AACP;;;;"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React, { useMemo, useCallback } from 'react';
|
|
2
|
+
import TablePagination from '@material-ui/core/TablePagination';
|
|
3
|
+
import { useSearch } from '../../context/SearchContext.esm.js';
|
|
4
|
+
|
|
5
|
+
const encodePageCursor = (pageCursor) => {
|
|
6
|
+
return Buffer.from(pageCursor.toString(), "utf-8").toString("base64");
|
|
7
|
+
};
|
|
8
|
+
const decodePageCursor = (pageCursor) => {
|
|
9
|
+
if (!pageCursor)
|
|
10
|
+
return 0;
|
|
11
|
+
return Number(Buffer.from(pageCursor, "base64").toString("utf-8"));
|
|
12
|
+
};
|
|
13
|
+
const SearchPaginationBase = (props) => {
|
|
14
|
+
const {
|
|
15
|
+
total: count = -1,
|
|
16
|
+
cursor: pageCursor,
|
|
17
|
+
hasNextPage,
|
|
18
|
+
onCursorChange: onPageCursorChange,
|
|
19
|
+
limit: rowsPerPage = 25,
|
|
20
|
+
limitLabel: labelRowsPerPage = "Results per page:",
|
|
21
|
+
limitText: labelDisplayedRows = ({ from, to }) => count > 0 ? `of ${count}` : `${from}-${to}`,
|
|
22
|
+
limitOptions: rowsPerPageOptions,
|
|
23
|
+
onLimitChange: onPageLimitChange,
|
|
24
|
+
...rest
|
|
25
|
+
} = props;
|
|
26
|
+
const page = useMemo(() => decodePageCursor(pageCursor), [pageCursor]);
|
|
27
|
+
const handlePageChange = useCallback(
|
|
28
|
+
(_, newValue) => {
|
|
29
|
+
onPageCursorChange == null ? void 0 : onPageCursorChange(encodePageCursor(newValue));
|
|
30
|
+
},
|
|
31
|
+
[onPageCursorChange]
|
|
32
|
+
);
|
|
33
|
+
const handleRowsPerPageChange = useCallback(
|
|
34
|
+
(e) => {
|
|
35
|
+
const newValue = e.target.value;
|
|
36
|
+
onPageLimitChange == null ? void 0 : onPageLimitChange(parseInt(newValue, 10));
|
|
37
|
+
},
|
|
38
|
+
[onPageLimitChange]
|
|
39
|
+
);
|
|
40
|
+
return /* @__PURE__ */ React.createElement(
|
|
41
|
+
TablePagination,
|
|
42
|
+
{
|
|
43
|
+
...rest,
|
|
44
|
+
component: "div",
|
|
45
|
+
count,
|
|
46
|
+
page,
|
|
47
|
+
nextIconButtonProps: {
|
|
48
|
+
...hasNextPage !== void 0 && { disabled: !hasNextPage }
|
|
49
|
+
},
|
|
50
|
+
onPageChange: handlePageChange,
|
|
51
|
+
rowsPerPage,
|
|
52
|
+
labelRowsPerPage,
|
|
53
|
+
labelDisplayedRows,
|
|
54
|
+
rowsPerPageOptions,
|
|
55
|
+
onRowsPerPageChange: handleRowsPerPageChange
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
const SearchPagination = (props) => {
|
|
60
|
+
const { pageLimit, setPageLimit, pageCursor, setPageCursor, fetchNextPage } = useSearch();
|
|
61
|
+
const handlePageLimitChange = useCallback(
|
|
62
|
+
(newPageLimit) => {
|
|
63
|
+
setPageLimit(newPageLimit);
|
|
64
|
+
setPageCursor(void 0);
|
|
65
|
+
},
|
|
66
|
+
[setPageLimit, setPageCursor]
|
|
67
|
+
);
|
|
68
|
+
return /* @__PURE__ */ React.createElement(
|
|
69
|
+
SearchPaginationBase,
|
|
70
|
+
{
|
|
71
|
+
...props,
|
|
72
|
+
hasNextPage: !!fetchNextPage,
|
|
73
|
+
limit: pageLimit,
|
|
74
|
+
onLimitChange: handlePageLimitChange,
|
|
75
|
+
cursor: pageCursor,
|
|
76
|
+
onCursorChange: setPageCursor
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export { SearchPagination, SearchPaginationBase };
|
|
82
|
+
//# sourceMappingURL=SearchPagination.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchPagination.esm.js","sources":["../../../src/components/SearchPagination/SearchPagination.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 React, {\n ReactNode,\n ChangeEvent,\n MouseEvent,\n useCallback,\n useMemo,\n} from 'react';\nimport TablePagination from '@material-ui/core/TablePagination';\nimport { useSearch } from '../../context';\n\nconst encodePageCursor = (pageCursor: number): string => {\n return Buffer.from(pageCursor.toString(), 'utf-8').toString('base64');\n};\n\nconst decodePageCursor = (pageCursor?: string): number => {\n if (!pageCursor) return 0;\n return Number(Buffer.from(pageCursor, 'base64').toString('utf-8'));\n};\n\n/**\n * A page limit option, this value must not be greater than 100.\n * @public\n */\nexport type SearchPaginationLimitOption<\n Current extends number = 101,\n Accumulator extends number[] = [],\n> = Accumulator['length'] extends Current\n ? Accumulator[number]\n : SearchPaginationLimitOption<\n Current,\n [...Accumulator, Accumulator['length']]\n >;\n\n/**\n * A page limit text, this function is called with a \"\\{ from, to, page, count \\}\" object.\n * @public\n */\nexport type SearchPaginationLimitText = (params: {\n from: number;\n to: number;\n page: number;\n count: number;\n}) => ReactNode;\n\n/**\n * Props for {@link SearchPaginationBase}.\n * @public\n */\nexport type SearchPaginationBaseProps = {\n /**\n * The component class name.\n */\n className?: string;\n /**\n * The total number of results.\n * For an unknown number of items, provide -1.\n * Defaults to -1.\n */\n total?: number;\n /**\n * The cursor for the current page.\n */\n cursor?: string;\n /**\n * Whether a next page exists\n */\n hasNextPage?: boolean;\n /**\n * Callback fired when the current page cursor is changed.\n */\n onCursorChange?: (pageCursor: string) => void;\n /**\n * The limit of results per page.\n * Set -1 to display all the results.\n */\n limit?: number;\n /**\n * Customize the results per page label.\n * Defaults to \"Results per page:\".\n */\n limitLabel?: ReactNode;\n /**\n * Customize the results per page text.\n * Defaults to \"(\\{ from, to, count \\}) =\\> count \\> 0 ? `of $\\{count\\}` : `$\\{from\\}-$\\{to\\}`\".\n */\n limitText?: SearchPaginationLimitText;\n /**\n * Options for setting how many results show per page.\n * If less than two options are available, no select field will be displayed.\n * Use -1 for the value with a custom label to show all the results.\n * Defaults to [10, 25, 50, 100].\n */\n limitOptions?: SearchPaginationLimitOption[];\n /**\n * Callback fired when the number of results per page is changed.\n */\n onLimitChange?: (value: number) => void;\n};\n\n/**\n * A component with controls for search results pagination.\n * @param props - See {@link SearchPaginationBaseProps}.\n * @public\n */\nexport const SearchPaginationBase = (props: SearchPaginationBaseProps) => {\n const {\n total: count = -1,\n cursor: pageCursor,\n hasNextPage,\n onCursorChange: onPageCursorChange,\n limit: rowsPerPage = 25,\n limitLabel: labelRowsPerPage = 'Results per page:',\n limitText: labelDisplayedRows = ({ from, to }) =>\n count > 0 ? `of ${count}` : `${from}-${to}`,\n limitOptions: rowsPerPageOptions,\n onLimitChange: onPageLimitChange,\n ...rest\n } = props;\n\n const page = useMemo(() => decodePageCursor(pageCursor), [pageCursor]);\n\n const handlePageChange = useCallback(\n (_: MouseEvent<HTMLButtonElement> | null, newValue: number) => {\n onPageCursorChange?.(encodePageCursor(newValue));\n },\n [onPageCursorChange],\n );\n\n const handleRowsPerPageChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {\n const newValue = e.target.value;\n onPageLimitChange?.(parseInt(newValue, 10));\n },\n [onPageLimitChange],\n );\n\n return (\n <TablePagination\n {...rest}\n component=\"div\"\n count={count}\n page={page}\n nextIconButtonProps={{\n ...(hasNextPage !== undefined && { disabled: !hasNextPage }),\n }}\n onPageChange={handlePageChange}\n rowsPerPage={rowsPerPage}\n labelRowsPerPage={labelRowsPerPage}\n labelDisplayedRows={labelDisplayedRows}\n rowsPerPageOptions={rowsPerPageOptions}\n onRowsPerPageChange={handleRowsPerPageChange}\n />\n );\n};\n\n/**\n * Props for {@link SearchPagination}.\n * @public\n */\nexport type SearchPaginationProps = Omit<\n SearchPaginationBaseProps,\n | 'pageLimit'\n | 'onLimitChange'\n | 'pageCursor'\n | 'onPageCursorChange'\n | 'hasNextPage'\n>;\n\n/**\n * A component for setting the search context page limit and cursor.\n * @param props - See {@link SearchPaginationProps}.\n * @public\n */\nexport const SearchPagination = (props: SearchPaginationProps) => {\n const { pageLimit, setPageLimit, pageCursor, setPageCursor, fetchNextPage } =\n useSearch();\n\n const handlePageLimitChange = useCallback(\n (newPageLimit: number) => {\n setPageLimit(newPageLimit);\n setPageCursor(undefined);\n },\n [setPageLimit, setPageCursor],\n );\n\n return (\n <SearchPaginationBase\n {...props}\n hasNextPage={!!fetchNextPage}\n limit={pageLimit}\n onLimitChange={handlePageLimitChange}\n cursor={pageCursor}\n onCursorChange={setPageCursor}\n />\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
3
|
+
import { isFunction } from 'lodash';
|
|
4
|
+
import { Progress, ResponseErrorPanel, EmptyState } from '@backstage/core-components';
|
|
5
|
+
import { useApi, AnalyticsContext } from '@backstage/core-plugin-api';
|
|
6
|
+
import { searchApiRef } from '../../api.esm.js';
|
|
7
|
+
import { useSearch } from '../../context/SearchContext.esm.js';
|
|
8
|
+
import { SearchResultListItemExtensions } from '../../extensions.esm.js';
|
|
9
|
+
|
|
10
|
+
const SearchResultContext = (props) => {
|
|
11
|
+
const { children } = props;
|
|
12
|
+
const context = useSearch();
|
|
13
|
+
const { result: state, ...query } = context;
|
|
14
|
+
return children(state, query);
|
|
15
|
+
};
|
|
16
|
+
const SearchResultApi = (props) => {
|
|
17
|
+
const { query, children } = props;
|
|
18
|
+
const searchApi = useApi(searchApiRef);
|
|
19
|
+
const state = useAsync(() => {
|
|
20
|
+
const { term = "", types = [], filters = {}, ...rest } = query;
|
|
21
|
+
return searchApi.query({ ...rest, term, types, filters });
|
|
22
|
+
}, [query]);
|
|
23
|
+
return children(state, query);
|
|
24
|
+
};
|
|
25
|
+
const SearchResultState = (props) => {
|
|
26
|
+
const { query, children } = props;
|
|
27
|
+
return query ? /* @__PURE__ */ React.createElement(SearchResultApi, { query }, children) : /* @__PURE__ */ React.createElement(SearchResultContext, null, children);
|
|
28
|
+
};
|
|
29
|
+
const SearchResultComponent = (props) => {
|
|
30
|
+
const {
|
|
31
|
+
query,
|
|
32
|
+
children,
|
|
33
|
+
noResultsComponent = /* @__PURE__ */ React.createElement(EmptyState, { missing: "data", title: "Sorry, no results were found" }),
|
|
34
|
+
...rest
|
|
35
|
+
} = props;
|
|
36
|
+
return /* @__PURE__ */ React.createElement(SearchResultState, { query }, ({ loading, error, value }) => {
|
|
37
|
+
if (loading) {
|
|
38
|
+
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
39
|
+
}
|
|
40
|
+
if (error) {
|
|
41
|
+
return /* @__PURE__ */ React.createElement(
|
|
42
|
+
ResponseErrorPanel,
|
|
43
|
+
{
|
|
44
|
+
title: "Error encountered while fetching search results",
|
|
45
|
+
error
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
if (!(value == null ? void 0 : value.results.length)) {
|
|
50
|
+
return noResultsComponent;
|
|
51
|
+
}
|
|
52
|
+
if (isFunction(children)) {
|
|
53
|
+
return children(value);
|
|
54
|
+
}
|
|
55
|
+
return /* @__PURE__ */ React.createElement(SearchResultListItemExtensions, { ...rest, results: value.results }, children);
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
const SearchResult = (props) => /* @__PURE__ */ React.createElement(
|
|
59
|
+
AnalyticsContext,
|
|
60
|
+
{
|
|
61
|
+
attributes: {
|
|
62
|
+
pluginId: "search",
|
|
63
|
+
extension: "SearchResult"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
/* @__PURE__ */ React.createElement(SearchResultComponent, { ...props })
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export { SearchResult, SearchResultApi, SearchResultComponent, SearchResultContext, SearchResultState };
|
|
70
|
+
//# sourceMappingURL=SearchResult.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchResult.esm.js","sources":["../../../src/components/SearchResult/SearchResult.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 React, { ReactNode } from 'react';\nimport useAsync, { AsyncState } from 'react-use/esm/useAsync';\nimport { isFunction } from 'lodash';\n\nimport {\n Progress,\n EmptyState,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport { useApi, AnalyticsContext } from '@backstage/core-plugin-api';\nimport { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';\n\nimport { searchApiRef } from '../../api';\nimport { useSearch } from '../../context';\nimport {\n SearchResultListItemExtensions,\n SearchResultListItemExtensionsProps,\n} from '../../extensions';\n\n/**\n * Props for {@link SearchResultContext}\n * @public\n */\nexport type SearchResultContextProps = {\n /**\n * A child function that receives an asynchronous result set and returns a react element.\n */\n children: (\n state: AsyncState<SearchResultSet>,\n query: Partial<SearchQuery>,\n ) => JSX.Element | null;\n};\n\n/**\n * Provides context-based results to a child function.\n * @param props - see {@link SearchResultContextProps}.\n * @example\n * ```\n * <SearchResultContext>\n * {({ loading, error, value }) => (\n * <List>\n * {value?.map(({ document }) => (\n * <DefaultSearchResultListItem\n * key={document.location}\n * result={document}\n * />\n * ))}\n * </List>\n * )}\n * </SearchResultContext>\n * ```\n * @public\n */\nexport const SearchResultContext = (props: SearchResultContextProps) => {\n const { children } = props;\n const context = useSearch();\n const { result: state, ...query } = context;\n return children(state, query);\n};\n\n/**\n * Props for {@link SearchResultApi}\n * @public\n */\nexport type SearchResultApiProps = SearchResultContextProps & {\n query: Partial<SearchQuery>;\n};\n\n/**\n * Request results through the search api and provide them to a child function.\n * @param props - see {@link SearchResultApiProps}.\n * @example\n * ```\n * <SearchResultApi>\n * {({ loading, error, value }) => (\n * <List>\n * {value?.map(({ document }) => (\n * <DefaultSearchResultListItem\n * key={document.location}\n * result={document}\n * />\n * ))}\n * </List>\n * )}\n * </SearchResultApi>\n * ```\n * @public\n */\nexport const SearchResultApi = (props: SearchResultApiProps) => {\n const { query, children } = props;\n const searchApi = useApi(searchApiRef);\n\n const state = useAsync(() => {\n const { term = '', types = [], filters = {}, ...rest } = query;\n return searchApi.query({ ...rest, term, types, filters });\n }, [query]);\n\n return children(state, query);\n};\n\n/**\n * Props for {@link SearchResultState}\n * @public\n */\nexport type SearchResultStateProps = SearchResultContextProps &\n Partial<SearchResultApiProps>;\n\n/**\n * Call a child render function passing a search state as an argument.\n * @remarks By default, results are taken from context, but when a \"query\" prop is set, results are requested from the search api.\n * @param props - see {@link SearchResultStateProps}.\n * @example\n * Consuming results from context:\n * ```\n * <SearchResultState>\n * {({ loading, error, value }) => (\n * <List>\n * {value?.map(({ document }) => (\n * <DefaultSearchResultListItem\n * key={document.location}\n * result={document}\n * />\n * ))}\n * </List>\n * )}\n * </SearchResultState>\n * ```\n * @example\n * Requesting results using the search api:\n * ```\n * <SearchResultState query={{ term: 'documentation' }}>\n * {({ loading, error, value }) => (\n * <List>\n * {value?.map(({ document }) => (\n * <DefaultSearchResultListItem\n * key={document.location}\n * result={document}\n * />\n * ))}\n * </List>\n * )}\n * </SearchResultState>\n * ```\n * @public\n */\nexport const SearchResultState = (props: SearchResultStateProps) => {\n const { query, children } = props;\n\n return query ? (\n <SearchResultApi query={query}>{children}</SearchResultApi>\n ) : (\n <SearchResultContext>{children}</SearchResultContext>\n );\n};\n\n/**\n * Props for {@link SearchResult}\n * @public\n */\nexport type SearchResultProps = Pick<SearchResultStateProps, 'query'> &\n Omit<SearchResultListItemExtensionsProps, 'results' | 'children'> & {\n children?: ReactNode | ((resultSet: SearchResultSet) => JSX.Element);\n noResultsComponent?: JSX.Element;\n };\n\n/**\n * Renders results from a parent search context or api.\n * @remarks default components for loading, error and empty variants are returned.\n * @param props - see {@link SearchResultProps}.\n * @public\n */\nexport const SearchResultComponent = (props: SearchResultProps) => {\n const {\n query,\n children,\n noResultsComponent = (\n <EmptyState missing=\"data\" title=\"Sorry, no results were found\" />\n ),\n ...rest\n } = props;\n\n return (\n <SearchResultState query={query}>\n {({ loading, error, value }) => {\n if (loading) {\n return <Progress />;\n }\n\n if (error) {\n return (\n <ResponseErrorPanel\n title=\"Error encountered while fetching search results\"\n error={error}\n />\n );\n }\n\n if (!value?.results.length) {\n return noResultsComponent;\n }\n\n if (isFunction(children)) {\n return children(value);\n }\n\n return (\n <SearchResultListItemExtensions {...rest} results={value.results}>\n {children}\n </SearchResultListItemExtensions>\n );\n }}\n </SearchResultState>\n );\n};\n\n/**\n * A component returning the search result from a parent search context or api.\n * @param props - see {@link SearchResultProps}.\n * @public\n */\nexport const SearchResult = (props: SearchResultProps) => (\n <AnalyticsContext\n attributes={{\n pluginId: 'search',\n extension: 'SearchResult',\n }}\n >\n <SearchResultComponent {...props} />\n </AnalyticsContext>\n);\n"],"names":[],"mappings":"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"}
|