From a17311d33b7dfb9b6064612d233cdffe381f37ee Mon Sep 17 00:00:00 2001 From: ibolton336 Date: Fri, 19 Jan 2024 16:01:15 -0500 Subject: [PATCH 1/2] :ghost: Convert filter toolbar controls to pf-5 select menu style Signed-off-by: ibolton336 --- .../MultiselectFilterControl.tsx | 315 ++++++++++++++---- .../FilterToolbar/SelectFilterControl.tsx | 98 ++++-- 2 files changed, 313 insertions(+), 100 deletions(-) diff --git a/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx b/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx index 627faa55fc..9e82e336a5 100644 --- a/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx +++ b/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx @@ -1,19 +1,28 @@ import * as React from "react"; -import { ToolbarChip, ToolbarFilter, Tooltip } from "@patternfly/react-core"; import { + Badge, + Button, + MenuToggle, + MenuToggleElement, Select, - SelectOption, - SelectOptionObject, - SelectVariant, - SelectProps, SelectGroup, -} from "@patternfly/react-core/deprecated"; + SelectList, + SelectOption, + SelectOptionProps, + TextInputGroup, + TextInputGroupMain, + TextInputGroupUtilities, + ToolbarChip, + ToolbarFilter, + Tooltip, +} from "@patternfly/react-core"; import { IFilterControlProps } from "./FilterControl"; import { IMultiselectFilterCategory, FilterSelectOptionProps, } from "./FilterToolbar"; import { css } from "@patternfly/react-styles"; +import { TimesIcon } from "@patternfly/react-icons"; import "./select-overrides.css"; @@ -37,46 +46,44 @@ export const MultiselectFilterControl = ({ >): JSX.Element | null => { const [isFilterDropdownOpen, setIsFilterDropdownOpen] = React.useState(false); - const { selectOptions } = category; + const [selectOptions, setSelectOptions] = React.useState< + FilterSelectOptionProps[] + >(Array.isArray(category.selectOptions) ? category.selectOptions : []); const hasGroupings = !Array.isArray(selectOptions); - const flatOptions = !hasGroupings + const flatOptions: FilterSelectOptionProps[] = !hasGroupings ? selectOptions - : Object.values(selectOptions).flatMap((i) => i); + : (Object.values(selectOptions).flatMap( + (i) => i + ) as FilterSelectOptionProps[]); - const getOptionKeyFromOptionValue = ( - optionValue: string | SelectOptionObject - ) => flatOptions.find(({ value }) => value === optionValue)?.key; + React.useEffect(() => { + if (Array.isArray(category.selectOptions)) { + setSelectOptions(category.selectOptions); + } + }, [category.selectOptions]); - const getOptionKeyFromChip = (chip: string) => - flatOptions.find(({ value }) => value.toString() === chip)?.key; + const [focusedItemIndex, setFocusedItemIndex] = React.useState( + null + ); + + const [activeItem, setActiveItem] = React.useState(null); + const textInputRef = React.useRef(); + const [inputValue, setInputValue] = React.useState(""); + + const getOptionKeyFromOptionValue = ( + optionValue: string | SelectOptionProps + ) => flatOptions.find((option) => option?.value === optionValue)?.key; const getOptionValueFromOptionKey = (optionKey: string) => flatOptions.find(({ key }) => key === optionKey)?.value; - const onFilterSelect = (value: string | SelectOptionObject) => { - const optionKey = getOptionKeyFromOptionValue(value); - if (optionKey && filterValue?.includes(optionKey)) { - const updatedValues = filterValue.filter( - (item: string) => item !== optionKey - ); - setFilterValue(updatedValues); - } else { - if (filterValue) { - const updatedValues = [...filterValue, optionKey]; - setFilterValue(updatedValues as string[]); - } else { - setFilterValue([optionKey || ""]); - } - } - }; - const onFilterClear = (chip: string | ToolbarChip) => { const chipKey = typeof chip === "string" ? chip : chip.key; - const optionKey = getOptionKeyFromChip(chipKey); - const newValue = filterValue - ? filterValue.filter((val) => val !== optionKey) - : []; - setFilterValue(newValue.length > 0 ? newValue : null); + const newFilterValue = filterValue + ? filterValue.filter((selection) => selection !== chipKey) + : filterValue; + + setFilterValue(newFilterValue); }; // Select expects "selections" to be an array of the "value" props from the relevant optionProps @@ -110,7 +117,9 @@ export const MultiselectFilterControl = ({ filter: (option: FilterSelectOptionProps, groupName?: string) => boolean ) => hasGroupings - ? Object.entries(selectOptions) + ? Object.entries( + selectOptions as Record + ) .sort(([groupA], [groupB]) => groupA.localeCompare(groupB)) .map(([group, options], index) => { const groupFiltered = @@ -126,26 +135,207 @@ export const MultiselectFilterControl = ({ .filter(Boolean) : flatOptions .filter((o) => filter(o)) - .map((optionProps) => ( - + .map((optionProps, index) => ( + + {optionProps.value} + )); - /** - * Render options (with categories if available) where the option value OR key includes - * the filterInput. - */ - const onOptionsFilter: SelectProps["onFilter"] = (_event, textInput) => { - const input = textInput?.toLowerCase(); - - return renderSelectOptions((optionProps, groupName) => { - // TODO: Checking for a filter match against the key or the value may not be desirable. - return ( - groupName?.toLowerCase().includes(input) || - optionProps?.key?.toLowerCase().includes(input) || - optionProps?.value?.toString().toLowerCase().includes(input) - ); - }); + const onSelect = (value: string | undefined) => { + if (value && value !== "No results") { + const newFilterValue = filterValue ? [...filterValue, value] : [value]; + setFilterValue(newFilterValue); + } + + textInputRef.current?.focus(); + }; + + const handleMenuArrowKeys = (key: string) => { + if (isFilterDropdownOpen && Array.isArray(selectOptions)) { + let indexToFocus: number = focusedItemIndex ?? -1; + + if (key === "ArrowUp") { + indexToFocus = + indexToFocus <= 0 ? selectOptions.length - 1 : indexToFocus - 1; + } else if (key === "ArrowDown") { + indexToFocus = + indexToFocus >= selectOptions.length - 1 ? 0 : indexToFocus + 1; + } + + while (selectOptions[indexToFocus].isDisabled) { + indexToFocus = key === "ArrowUp" ? indexToFocus - 1 : indexToFocus + 1; + if (indexToFocus < 0) { + indexToFocus = selectOptions.length - 1; + } else if (indexToFocus >= selectOptions.length) { + indexToFocus = 0; + } + } + + setFocusedItemIndex(indexToFocus); + const focusedItem = selectOptions[indexToFocus]; + setActiveItem(`select-typeahead-${focusedItem.value.replace(" ", "-")}`); + } }; + React.useEffect(() => { + let newSelectOptions = Array.isArray(category.selectOptions) + ? category.selectOptions + : []; + + if (inputValue) { + newSelectOptions = Array.isArray(category.selectOptions) + ? category.selectOptions?.filter((menuItem) => + String(menuItem.value) + .toLowerCase() + .includes(inputValue.toLowerCase()) + ) + : []; + + if (!newSelectOptions.length) { + newSelectOptions = [ + { + key: "no-results", + isDisabled: true, + children: `No results found for "${inputValue}"`, + value: "No results", + }, + ]; + } + + if (!isFilterDropdownOpen) { + setIsFilterDropdownOpen(true); + } + } + + setSelectOptions(newSelectOptions); + setFocusedItemIndex(null); + setActiveItem(null); + }, [inputValue, isFilterDropdownOpen, category.selectOptions]); + + const onInputKeyDown = (event: React.KeyboardEvent) => { + const enabledMenuItems = Array.isArray(selectOptions) + ? selectOptions.filter((option) => !option.isDisabled) + : []; + const [firstMenuItem] = enabledMenuItems; + const focusedItem = focusedItemIndex + ? enabledMenuItems[focusedItemIndex] + : firstMenuItem; + + const newSelectOptions = flatOptions.filter((menuItem) => + menuItem.value.toLowerCase().includes(inputValue.toLowerCase()) + ); + const selectedItem = + newSelectOptions.find( + (option) => option.value.toLowerCase() === inputValue.toLowerCase() + ) || focusedItem; + + switch (event.key) { + case "Enter": + event.preventDefault(); + setSelectOptions(newSelectOptions); + setIsFilterDropdownOpen(true); + + if ( + isFilterDropdownOpen && + selectedItem && + selectedItem.value !== "no results" + ) { + setInputValue(""); + + const newFilterValue = [...(filterValue || [])]; + const optionValue = getOptionValueFromOptionKey(selectedItem.value); + + if (newFilterValue.includes(optionValue)) { + const indexToRemove = newFilterValue.indexOf(optionValue); + newFilterValue.splice(indexToRemove, 1); + } else { + newFilterValue.push(optionValue); + } + + setFilterValue(newFilterValue); + setIsFilterDropdownOpen(false); + } + + break; + case "Tab": + case "Escape": + setIsFilterDropdownOpen(false); + setActiveItem(null); + break; + case "ArrowUp": + case "ArrowDown": + event.preventDefault(); + handleMenuArrowKeys(event.key); + break; + } + }; + + const onTextInputChange = ( + _event: React.FormEvent, + value: string + ) => { + setInputValue(value); + }; + + const toggle = (toggleRef: React.Ref) => ( + { + setIsFilterDropdownOpen(!isFilterDropdownOpen); + }} + isExpanded={isFilterDropdownOpen} + isFullWidth + > + + { + setIsFilterDropdownOpen(!isFilterDropdownOpen); + }} + onChange={onTextInputChange} + onKeyDown={onInputKeyDown} + id="typeahead-select-input" + autoComplete="off" + innerRef={textInputRef} + placeholder={category.placeholderText} + {...(activeItem && { "aria-activedescendant": activeItem })} + role="combobox" + isExpanded={isFilterDropdownOpen} + aria-controls="select-typeahead-listbox" + /> + + + {!!inputValue && ( + + )} + {filterValue?.length ? ( + {filterValue.length} + ) : null} + + + + ); return ( ({ ); diff --git a/client/src/app/components/FilterToolbar/SelectFilterControl.tsx b/client/src/app/components/FilterToolbar/SelectFilterControl.tsx index 3e0ed1abb1..e8b6479dda 100644 --- a/client/src/app/components/FilterToolbar/SelectFilterControl.tsx +++ b/client/src/app/components/FilterToolbar/SelectFilterControl.tsx @@ -1,15 +1,15 @@ import * as React from "react"; -import { ToolbarFilter } from "@patternfly/react-core"; import { + MenuToggle, + MenuToggleElement, Select, + SelectList, SelectOption, - SelectOptionObject, -} from "@patternfly/react-core/deprecated"; + SelectOptionProps, + ToolbarFilter, +} from "@patternfly/react-core"; import { IFilterControlProps } from "./FilterControl"; -import { - ISelectFilterCategory, - FilterSelectOptionProps, -} from "./FilterToolbar"; +import { ISelectFilterCategory } from "./FilterToolbar"; import { css } from "@patternfly/react-styles"; import "./select-overrides.css"; @@ -34,29 +34,29 @@ export const SelectFilterControl = ({ >): JSX.Element | null => { const [isFilterDropdownOpen, setIsFilterDropdownOpen] = React.useState(false); - const getOptionKeyFromOptionValue = ( - optionValue: string | SelectOptionObject - ) => - category.selectOptions.find( - (optionProps) => optionProps.value === optionValue - )?.key; - const getChipFromOptionValue = ( - optionValue: string | SelectOptionObject | undefined - ) => (optionValue ? optionValue.toString() : ""); + optionValue: SelectOptionProps | undefined + ) => { + return optionValue ? optionValue.value : ""; + }; const getOptionKeyFromChip = (chip: string) => category.selectOptions.find( (optionProps) => optionProps.value.toString() === chip )?.key; - const getOptionValueFromOptionKey = (optionKey: string) => - category.selectOptions.find((optionProps) => optionProps.key === optionKey) - ?.value; + const getOptionValueFromOptionKey = ( + optionKey: string + ): SelectOptionProps => { + return ( + category.selectOptions.find((optionProps) => { + return optionProps.value === optionKey; + }) || { value: "", children: "", key: "" } + ); + }; - const onFilterSelect = (value: string | SelectOptionObject) => { - const optionKey = getOptionKeyFromOptionValue(value); - setFilterValue(optionKey ? [optionKey] : null); + const onFilterSelect = (value: string) => { + setFilterValue(value ? [value] : null); setIsFilterDropdownOpen(false); }; @@ -68,17 +68,29 @@ export const SelectFilterControl = ({ setFilterValue(newValue.length > 0 ? newValue : null); }; - // Select expects "selections" to be an array of the "value" props from the relevant optionProps - const selections = filterValue + const selections: SelectOptionProps[] = filterValue ? filterValue.map(getOptionValueFromOptionKey) - : null; + : []; const chips = selections ? selections.map(getChipFromOptionValue) : []; - const renderSelectOptions = (options: FilterSelectOptionProps[]) => - options.map((optionProps) => ( - - )); + const toggle = (toggleRef: React.Ref) => { + return ( + { + setIsFilterDropdownOpen(!isFilterDropdownOpen); + }} + isExpanded={isFilterDropdownOpen} + isDisabled={isDisabled || category.selectOptions.length === 0} + > + {filterValue || "Any"} + + ); + }; return ( ({ ); From fe9048f203480ee89ba608bd8871839c395ca54f Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Wed, 14 Feb 2024 14:56:44 -0500 Subject: [PATCH 2/2] - Address PR comment - Cleanup the single select - Disable if no selectable option - Cleanup multiselect filter control Signed-off-by: Ian Bolton --- .../MultiselectFilterControl.tsx | 183 +++++++++--------- .../FilterToolbar/SelectFilterControl.tsx | 60 +++--- 2 files changed, 121 insertions(+), 122 deletions(-) diff --git a/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx b/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx index 9e82e336a5..f88511099e 100644 --- a/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx +++ b/client/src/app/components/FilterToolbar/MultiselectFilterControl.tsx @@ -8,7 +8,6 @@ import { SelectGroup, SelectList, SelectOption, - SelectOptionProps, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, @@ -49,18 +48,24 @@ export const MultiselectFilterControl = ({ const [selectOptions, setSelectOptions] = React.useState< FilterSelectOptionProps[] >(Array.isArray(category.selectOptions) ? category.selectOptions : []); + const hasGroupings = !Array.isArray(selectOptions); + const flatOptions: FilterSelectOptionProps[] = !hasGroupings ? selectOptions : (Object.values(selectOptions).flatMap( (i) => i ) as FilterSelectOptionProps[]); - React.useEffect(() => { - if (Array.isArray(category.selectOptions)) { - setSelectOptions(category.selectOptions); - } - }, [category.selectOptions]); + const getOptionKeyFromOptionValue = (optionValue: string) => + flatOptions.find(({ value }) => value === optionValue)?.key; + + const getOptionValueFromOptionKey = (optionKey: string) => + flatOptions.find(({ key }) => key === optionKey)?.value; + + const getOptionKeyFromChip = (chipDisplayValue: string) => { + return flatOptions.find(({ value }) => value === chipDisplayValue)?.key; + }; const [focusedItemIndex, setFocusedItemIndex] = React.useState( null @@ -70,32 +75,24 @@ export const MultiselectFilterControl = ({ const textInputRef = React.useRef(); const [inputValue, setInputValue] = React.useState(""); - const getOptionKeyFromOptionValue = ( - optionValue: string | SelectOptionProps - ) => flatOptions.find((option) => option?.value === optionValue)?.key; - - const getOptionValueFromOptionKey = (optionKey: string) => - flatOptions.find(({ key }) => key === optionKey)?.value; - const onFilterClear = (chip: string | ToolbarChip) => { - const chipKey = typeof chip === "string" ? chip : chip.key; - const newFilterValue = filterValue - ? filterValue.filter((selection) => selection !== chipKey) - : filterValue; + const displayValue = typeof chip === "string" ? chip : chip.key; + const optionKey = getOptionKeyFromChip(displayValue); - setFilterValue(newFilterValue); + if (optionKey) { + const newValue = filterValue?.filter((val) => val !== optionKey) ?? []; + setFilterValue(newValue.length > 0 ? newValue : null); + } }; - // Select expects "selections" to be an array of the "value" props from the relevant optionProps - const selections = filterValue?.map(getOptionValueFromOptionKey) ?? []; - /* * Note: Chips can be a `ToolbarChip` or a plain `string`. Use a hack to split a * selected option in 2 parts. Assuming the option is in the format "Group / Item" * break the text and show a chip with the Item and the Group as a tooltip. */ - const chips = selections.map((s, index) => { - const chip: string = s?.toString() ?? ""; + const chips = filterValue?.map((s, index) => { + const displayValue = getOptionValueFromOptionKey(s); + const chip: string = displayValue?.toString() ?? ""; const idx = chip.indexOf(CHIP_BREAK_DELINEATOR); if (idx > 0) { @@ -124,69 +121,98 @@ export const MultiselectFilterControl = ({ .map(([group, options], index) => { const groupFiltered = options?.filter((o) => filter(o, group)) ?? []; - return groupFiltered.length == 0 ? undefined : ( + return groupFiltered.length === 0 ? undefined : ( - {groupFiltered.map((optionProps) => ( - - ))} + {groupFiltered.map((optionProps) => { + const optionKey = getOptionKeyFromOptionValue( + optionProps.value + ); + if (!optionKey) return null; + return ( + + ); + })} ); }) .filter(Boolean) : flatOptions .filter((o) => filter(o)) - .map((optionProps, index) => ( - - {optionProps.value} - - )); + .map((optionProps, index) => { + const optionKey = getOptionKeyFromOptionValue(optionProps.value); + if (!optionKey) return null; + return ( + + {optionProps.value} + + ); + }); const onSelect = (value: string | undefined) => { if (value && value !== "No results") { - const newFilterValue = filterValue ? [...filterValue, value] : [value]; - setFilterValue(newFilterValue); - } + const optionKey = getOptionKeyFromOptionValue(value); + if (optionKey) { + let newFilterValue: string[]; + + if (filterValue && filterValue.includes(optionKey)) { + newFilterValue = filterValue.filter((item) => item !== optionKey); + } else { + newFilterValue = filterValue + ? [...filterValue, optionKey] + : [optionKey]; + } + + setFilterValue(newFilterValue); + } + } textInputRef.current?.focus(); }; const handleMenuArrowKeys = (key: string) => { - if (isFilterDropdownOpen && Array.isArray(selectOptions)) { - let indexToFocus: number = focusedItemIndex ?? -1; + let indexToFocus = 0; + if (isFilterDropdownOpen) { if (key === "ArrowUp") { - indexToFocus = - indexToFocus <= 0 ? selectOptions.length - 1 : indexToFocus - 1; - } else if (key === "ArrowDown") { - indexToFocus = - indexToFocus >= selectOptions.length - 1 ? 0 : indexToFocus + 1; + if (focusedItemIndex === null || focusedItemIndex === 0) { + indexToFocus = selectOptions.length - 1; + } else { + indexToFocus = focusedItemIndex - 1; + } } - while (selectOptions[indexToFocus].isDisabled) { - indexToFocus = key === "ArrowUp" ? indexToFocus - 1 : indexToFocus + 1; - if (indexToFocus < 0) { - indexToFocus = selectOptions.length - 1; - } else if (indexToFocus >= selectOptions.length) { + if (key === "ArrowDown") { + if ( + focusedItemIndex === null || + focusedItemIndex === selectOptions.length - 1 + ) { indexToFocus = 0; + } else { + indexToFocus = focusedItemIndex + 1; } } setFocusedItemIndex(indexToFocus); - const focusedItem = selectOptions[indexToFocus]; - setActiveItem(`select-typeahead-${focusedItem.value.replace(" ", "-")}`); + const focusedItem = selectOptions.filter((option) => !option.isDisabled)[ + indexToFocus + ]; + setActiveItem( + `select-multi-typeahead-checkbox-${focusedItem.value.replace(" ", "-")}` + ); } }; + React.useEffect(() => { let newSelectOptions = Array.isArray(category.selectOptions) ? category.selectOptions @@ -197,7 +223,7 @@ export const MultiselectFilterControl = ({ ? category.selectOptions?.filter((menuItem) => String(menuItem.value) .toLowerCase() - .includes(inputValue.toLowerCase()) + .includes(inputValue.trim().toLowerCase()) ) : []; @@ -205,7 +231,7 @@ export const MultiselectFilterControl = ({ newSelectOptions = [ { key: "no-results", - isDisabled: true, + isDisabled: false, children: `No results found for "${inputValue}"`, value: "No results", }, @@ -220,7 +246,7 @@ export const MultiselectFilterControl = ({ setSelectOptions(newSelectOptions); setFocusedItemIndex(null); setActiveItem(null); - }, [inputValue, isFilterDropdownOpen, category.selectOptions]); + }, [inputValue]); const onInputKeyDown = (event: React.KeyboardEvent) => { const enabledMenuItems = Array.isArray(selectOptions) @@ -241,31 +267,11 @@ export const MultiselectFilterControl = ({ switch (event.key) { case "Enter": - event.preventDefault(); - setSelectOptions(newSelectOptions); - setIsFilterDropdownOpen(true); - - if ( - isFilterDropdownOpen && - selectedItem && - selectedItem.value !== "no results" - ) { - setInputValue(""); - - const newFilterValue = [...(filterValue || [])]; - const optionValue = getOptionValueFromOptionKey(selectedItem.value); - - if (newFilterValue.includes(optionValue)) { - const indexToRemove = newFilterValue.indexOf(optionValue); - newFilterValue.splice(indexToRemove, 1); - } else { - newFilterValue.push(optionValue); - } - - setFilterValue(newFilterValue); - setIsFilterDropdownOpen(false); + if (!isFilterDropdownOpen) { + setIsFilterDropdownOpen((prev) => !prev); + } else if (selectedItem && selectedItem.value !== "No results") { + onSelect(selectedItem.value); } - break; case "Tab": case "Escape": @@ -277,6 +283,8 @@ export const MultiselectFilterControl = ({ event.preventDefault(); handleMenuArrowKeys(event.key); break; + default: + break; } }; @@ -295,6 +303,7 @@ export const MultiselectFilterControl = ({ setIsFilterDropdownOpen(!isFilterDropdownOpen); }} isExpanded={isFilterDropdownOpen} + isDisabled={isDisabled || !category.selectOptions.length} isFullWidth > diff --git a/client/src/app/components/FilterToolbar/SelectFilterControl.tsx b/client/src/app/components/FilterToolbar/SelectFilterControl.tsx index e8b6479dda..55d077205b 100644 --- a/client/src/app/components/FilterToolbar/SelectFilterControl.tsx +++ b/client/src/app/components/FilterToolbar/SelectFilterControl.tsx @@ -5,7 +5,6 @@ import { Select, SelectList, SelectOption, - SelectOptionProps, ToolbarFilter, } from "@patternfly/react-core"; import { IFilterControlProps } from "./FilterControl"; @@ -34,47 +33,36 @@ export const SelectFilterControl = ({ >): JSX.Element | null => { const [isFilterDropdownOpen, setIsFilterDropdownOpen] = React.useState(false); - const getChipFromOptionValue = ( - optionValue: SelectOptionProps | undefined - ) => { - return optionValue ? optionValue.value : ""; - }; + const getOptionKeyFromOptionValue = (optionValue: string) => + category.selectOptions.find(({ value }) => value === optionValue)?.key; - const getOptionKeyFromChip = (chip: string) => - category.selectOptions.find( - (optionProps) => optionProps.value.toString() === chip - )?.key; + const getOptionValueFromOptionKey = (optionKey: string) => + category.selectOptions.find(({ key }) => key === optionKey)?.value; - const getOptionValueFromOptionKey = ( - optionKey: string - ): SelectOptionProps => { - return ( - category.selectOptions.find((optionProps) => { - return optionProps.value === optionKey; - }) || { value: "", children: "", key: "" } - ); - }; + const chips = filterValue?.map((key) => { + const displayValue = getOptionValueFromOptionKey(key); + return displayValue ? displayValue : key; + }); const onFilterSelect = (value: string) => { - setFilterValue(value ? [value] : null); + const optionKey = getOptionKeyFromOptionValue(value); + setFilterValue(optionKey ? [optionKey] : null); setIsFilterDropdownOpen(false); }; const onFilterClear = (chip: string) => { - const optionKey = getOptionKeyFromChip(chip); - const newValue = filterValue - ? filterValue.filter((val) => val !== optionKey) - : []; - setFilterValue(newValue.length > 0 ? newValue : null); + const newValue = filterValue?.filter((val) => val !== chip); + setFilterValue(newValue?.length ? newValue : null); }; - const selections: SelectOptionProps[] = filterValue - ? filterValue.map(getOptionValueFromOptionKey) - : []; - - const chips = selections ? selections.map(getChipFromOptionValue) : []; - const toggle = (toggleRef: React.Ref) => { + let displayText = "Any"; + if (filterValue && filterValue.length > 0) { + const selectedKey = filterValue[0]; + const selectedDisplayValue = getOptionValueFromOptionKey(selectedKey); + displayText = selectedDisplayValue ? selectedDisplayValue : selectedKey; + } + return ( ({ isExpanded={isFilterDropdownOpen} isDisabled={isDisabled || category.selectOptions.length === 0} > - {filterValue || "Any"} + {displayText} ); }; @@ -112,14 +100,16 @@ export const SelectFilterControl = ({ }} isOpen={isFilterDropdownOpen} placeholder="Any" + shouldFocusToggleOnSelect > - {category.selectOptions.map((o: SelectOptionProps, index) => { + {category.selectOptions.map((o, index) => { + const isSelected = filterValue?.includes(o.key); return ( {o.value}