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,
};
/**