diff --git a/packages/common/src/components/Filter/AutocompleteFilter.tsx b/packages/common/src/components/Filter/AutocompleteFilter.tsx new file mode 100644 index 000000000..3c0d5f349 --- /dev/null +++ b/packages/common/src/components/Filter/AutocompleteFilter.tsx @@ -0,0 +1,104 @@ +import React, { useState } from 'react'; + +import { + Select, + SelectOption, + SelectOptionObject, + SelectVariant, + ToolbarChip, + ToolbarFilter, +} from '@patternfly/react-core'; + +import { FilterTypeProps } from './types'; + +/** + * Typeahead filter inspired by Console's AutocompleteInput. + * + * **Key features**:
+ * 1) match the search pattern in the entire string (not only prefix)
+ * 2) reset the filter after selection - the selected item is visible in the chip list + + * + * **Enum contract**:
+ * 1) enum values passed as supportedValues param have id prop the same as the label prop.
+ * 2) values in supportedValues are unique (no de-duplication similar to EnumFilter). + * + * [ + * View component source on GitHub](https://github.com/kubev2v/forklift-console-plugin/blob/main/packages/common/src/components/Filter/AutocompleteFilter.tsx) + */ +export const AutocompleteFilter = ({ + selectedFilters = [], + onFilterUpdate, + supportedValues = [], + title, + placeholderLabel, + filterId, + showFilter = true, +}: FilterTypeProps) => { + const [isExpanded, setExpanded] = useState(false); + const validSupported = supportedValues.filter(({ label, id }) => id === label); + const validSelected = selectedFilters.filter( + (filterId) => validSupported.filter(({ id }) => id === filterId).length > 0, + ); + + const deleteFilter = (label: string | ToolbarChip | SelectOptionObject): void => + onFilterUpdate(validSelected.filter((filterLabel) => filterLabel !== label)); + + const hasFilter = (label: string | SelectOptionObject): boolean => + !!validSelected.find((filterLabel) => filterLabel === label); + + const addFilter = (label: string | SelectOptionObject): void => { + if (typeof label === 'string') { + onFilterUpdate([...validSelected, label]); + } + }; + + const options = validSupported.map(({ label }) => ); + + const onFilter = (_, textInput) => { + if (textInput === '') { + return options; + } + + return options.filter((child) => + child.props.value.toString().toLowerCase().includes(textInput.toLowerCase()), + ); + }; + + return ( + deleteFilter(option)} + deleteChipGroup={() => onFilterUpdate([])} + categoryName={title} + showToolbarItem={showFilter} + > + + + ); +}; diff --git a/packages/common/src/components/Filter/index.ts b/packages/common/src/components/Filter/index.ts index 14d0286fb..8cb410203 100644 --- a/packages/common/src/components/Filter/index.ts +++ b/packages/common/src/components/Filter/index.ts @@ -1,4 +1,5 @@ // @index(['./*', /__/g], f => `export * from '${f.path}';`) +export * from './AutocompleteFilter'; export * from './DateFilter'; export * from './DateRangeFilter'; export * from './EnumFilter'; diff --git a/packages/common/src/components/FilterGroup/matchers.ts b/packages/common/src/components/FilterGroup/matchers.ts index 7c3f172ac..7b7f52694 100644 --- a/packages/common/src/components/FilterGroup/matchers.ts +++ b/packages/common/src/components/FilterGroup/matchers.ts @@ -2,6 +2,7 @@ import jsonpath from 'jsonpath'; import { areSameDayInUTCZero, isInClosedRange, ResourceField } from '../../utils'; import { + AutocompleteFilter, DateFilter, DateRangeFilter, EnumFilter, @@ -109,6 +110,11 @@ const searchableGroupedEnumMatcher = { matchValue: enumMatcher.matchValue, }; +const autocompleteFilterMatcher = { + filterType: 'autocomplete', + matchValue: enumMatcher.matchValue, +}; + const dateMatcher = { filterType: 'date', matchValue: (value: string) => (filter: string) => areSameDayInUTCZero(value, filter), @@ -125,6 +131,7 @@ const sliderMatcher = { }; export const defaultValueMatchers: ValueMatcher[] = [ + autocompleteFilterMatcher, freetextMatcher, enumMatcher, groupedEnumMatcher, @@ -142,6 +149,7 @@ export const defaultSupportedFilters: Record = { groupedEnum: GroupedEnumFilter, slider: SwitchFilter, searchableGroupedEnum: SearchableGroupedEnumFilter, + autocomplete: AutocompleteFilter, }; /**