fix(search): compile possible filter options from available entities (#3370)
* load filters from entities * fix(search): compile possible filter options from available entities * rename filter state and add text in case no filter can be applied
This commit is contained in:
@@ -49,8 +49,14 @@ export type FiltersState = {
|
||||
checked: Array<string>;
|
||||
};
|
||||
|
||||
export type FilterOptions = {
|
||||
kind: Array<string>;
|
||||
lifecycle: Array<string>;
|
||||
};
|
||||
|
||||
type FiltersProps = {
|
||||
filters: FiltersState;
|
||||
filterOptions: FilterOptions;
|
||||
resetFilters: () => void;
|
||||
updateSelected: (filter: string) => void;
|
||||
updateChecked: (filter: string) => void;
|
||||
@@ -58,16 +64,13 @@ type FiltersProps = {
|
||||
|
||||
export const Filters = ({
|
||||
filters,
|
||||
filterOptions,
|
||||
resetFilters,
|
||||
updateSelected,
|
||||
updateChecked,
|
||||
}: FiltersProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
// TODO: move mocked filters out of filters component to make it more generic
|
||||
const filter1 = ['All', 'API', 'Component', 'Location', 'Template'];
|
||||
const filter2 = ['deprecated', 'recommended', 'experimental', 'production'];
|
||||
|
||||
return (
|
||||
<Card className={classes.filters}>
|
||||
<CardHeader
|
||||
@@ -79,54 +82,65 @@ export const Filters = ({
|
||||
}
|
||||
/>
|
||||
<Divider />
|
||||
<CardContent>
|
||||
<Typography variant="subtitle2">Kind</Typography>
|
||||
<Select
|
||||
id="outlined-select"
|
||||
onChange={(e: React.ChangeEvent<any>) =>
|
||||
updateSelected(e?.target?.value)
|
||||
}
|
||||
variant="outlined"
|
||||
className={classes.dropdown}
|
||||
value={filters.selected}
|
||||
>
|
||||
{filter1.map(filter => (
|
||||
<MenuItem
|
||||
selected={filter === 'All'}
|
||||
dense
|
||||
key={filter}
|
||||
value={filter}
|
||||
>
|
||||
{filter}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</CardContent>
|
||||
<CardContent>
|
||||
<Typography variant="subtitle2">Lifecycle</Typography>
|
||||
<List disablePadding dense>
|
||||
{filter2.map(filter => (
|
||||
<ListItem
|
||||
key={filter}
|
||||
dense
|
||||
button
|
||||
onClick={() => updateChecked(filter)}
|
||||
>
|
||||
<Checkbox
|
||||
edge="start"
|
||||
disableRipple
|
||||
className={classes.checkbox}
|
||||
color="primary"
|
||||
checked={filters.checked.includes(filter)}
|
||||
tabIndex={-1}
|
||||
{filterOptions.kind.length === 0 && filterOptions.lifecycle.length === 0 && (
|
||||
<CardContent>
|
||||
<Typography variant="subtitle2">
|
||||
Filters cannot be applied to available results
|
||||
</Typography>
|
||||
</CardContent>
|
||||
)}
|
||||
{filterOptions.kind.length > 0 && (
|
||||
<CardContent>
|
||||
<Typography variant="subtitle2">Kind</Typography>
|
||||
<Select
|
||||
id="outlined-select"
|
||||
onChange={(e: React.ChangeEvent<any>) =>
|
||||
updateSelected(e?.target?.value)
|
||||
}
|
||||
variant="outlined"
|
||||
className={classes.dropdown}
|
||||
value={filters.selected}
|
||||
>
|
||||
{filterOptions.kind.map(filter => (
|
||||
<MenuItem
|
||||
selected={filter === 'All'}
|
||||
dense
|
||||
key={filter}
|
||||
value={filter}
|
||||
name={filter}
|
||||
/>
|
||||
<ListItemText id={filter} primary={filter} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</CardContent>
|
||||
>
|
||||
{filter}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</CardContent>
|
||||
)}
|
||||
{filterOptions.lifecycle.length > 0 && (
|
||||
<CardContent>
|
||||
<Typography variant="subtitle2">Lifecycle</Typography>
|
||||
<List disablePadding dense>
|
||||
{filterOptions.lifecycle.map(filter => (
|
||||
<ListItem
|
||||
key={filter}
|
||||
dense
|
||||
button
|
||||
onClick={() => updateChecked(filter)}
|
||||
>
|
||||
<Checkbox
|
||||
edge="start"
|
||||
disableRipple
|
||||
className={classes.checkbox}
|
||||
color="primary"
|
||||
checked={filters.checked.includes(filter)}
|
||||
tabIndex={-1}
|
||||
value={filter}
|
||||
name={filter}
|
||||
/>
|
||||
<ListItemText id={filter} primary={filter} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -126,7 +126,7 @@ export const SearchResult = ({ searchQuery }: SearchResultProps) => {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
|
||||
const [showFilters, toggleFilters] = useState(false);
|
||||
const [filters, setFilters] = useState<FiltersState>({
|
||||
const [selectedFilters, setSelectedFilters] = useState<FiltersState>({
|
||||
selected: 'All',
|
||||
checked: [],
|
||||
});
|
||||
@@ -146,17 +146,18 @@ export const SearchResult = ({ searchQuery }: SearchResultProps) => {
|
||||
// apply filters
|
||||
|
||||
// filter on selected
|
||||
if (filters.selected !== 'All') {
|
||||
if (selectedFilters.selected !== 'All') {
|
||||
withFilters = results.filter((result: Result) =>
|
||||
filters.selected.includes(result.kind),
|
||||
selectedFilters.selected.includes(result.kind),
|
||||
);
|
||||
}
|
||||
|
||||
// filter on checked
|
||||
if (filters.checked.length > 0) {
|
||||
if (selectedFilters.checked.length > 0) {
|
||||
withFilters = withFilters.filter(
|
||||
(result: Result) =>
|
||||
result.lifecycle && filters.checked.includes(result.lifecycle),
|
||||
result.lifecycle &&
|
||||
selectedFilters.checked.includes(result.lifecycle),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,7 +175,7 @@ export const SearchResult = ({ searchQuery }: SearchResultProps) => {
|
||||
|
||||
setFilteredResults(withFilters);
|
||||
}
|
||||
}, [filters, searchQuery, results]);
|
||||
}, [selectedFilters, searchQuery, results]);
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
}
|
||||
@@ -190,41 +191,58 @@ export const SearchResult = ({ searchQuery }: SearchResultProps) => {
|
||||
}
|
||||
|
||||
const resetFilters = () => {
|
||||
setFilters({
|
||||
setSelectedFilters({
|
||||
selected: 'All',
|
||||
checked: [],
|
||||
});
|
||||
};
|
||||
|
||||
const updateSelected = (filter: string) => {
|
||||
setFilters(prevState => ({
|
||||
setSelectedFilters(prevState => ({
|
||||
...prevState,
|
||||
selected: filter,
|
||||
}));
|
||||
};
|
||||
|
||||
const updateChecked = (filter: string) => {
|
||||
if (filters.checked.includes(filter)) {
|
||||
setFilters(prevState => ({
|
||||
if (selectedFilters.checked.includes(filter)) {
|
||||
setSelectedFilters(prevState => ({
|
||||
...prevState,
|
||||
checked: prevState.checked.filter(item => item !== filter),
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
setFilters(prevState => ({
|
||||
setSelectedFilters(prevState => ({
|
||||
...prevState,
|
||||
checked: [...prevState.checked, filter],
|
||||
}));
|
||||
};
|
||||
|
||||
const filterOptions = results.reduce(
|
||||
(acc, curr) => {
|
||||
if (curr.kind && acc.kind.indexOf(curr.kind) < 0) {
|
||||
acc.kind.push(curr.kind);
|
||||
}
|
||||
if (curr.lifecycle && acc.lifecycle.indexOf(curr.lifecycle) < 0) {
|
||||
acc.lifecycle.push(curr.lifecycle);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
kind: [] as Array<string>,
|
||||
lifecycle: [] as Array<string>,
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container>
|
||||
{showFilters && (
|
||||
<Grid item xs={3}>
|
||||
<Filters
|
||||
filters={filters}
|
||||
filters={selectedFilters}
|
||||
filterOptions={filterOptions}
|
||||
resetFilters={resetFilters}
|
||||
updateSelected={updateSelected}
|
||||
updateChecked={updateChecked}
|
||||
@@ -241,7 +259,8 @@ export const SearchResult = ({ searchQuery }: SearchResultProps) => {
|
||||
searchQuery={searchQuery}
|
||||
numberOfResults={filteredResults.length}
|
||||
numberOfSelectedFilters={
|
||||
(filters.selected !== 'All' ? 1 : 0) + filters.checked.length
|
||||
(selectedFilters.selected !== 'All' ? 1 : 0) +
|
||||
selectedFilters.checked.length
|
||||
}
|
||||
handleToggleFilters={() => toggleFilters(!showFilters)}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user