From cf1d4775442b4de7cac10d91f96e6061f747512a Mon Sep 17 00:00:00 2001 From: jkozol Date: Mon, 9 Oct 2023 00:41:50 +0200 Subject: [PATCH] ShareImageModal: update the typeahead selector to pf5 This dropdown needed to be update as part of the overall pf5 upgrade. Each of the components in the select now need to be declared and handled. Also, some of the Select and SelectOption props come from the Menu props since Select inherits Menu. --- .../ShareImageModal/RegionsSelect.tsx | 231 ++++++++++++------ .../ShareImageModal/ShareImageModal.tsx | 22 +- .../ShareImageModal/ShareImageModal.test.js | 14 +- 3 files changed, 164 insertions(+), 103 deletions(-) diff --git a/src/Components/ShareImageModal/RegionsSelect.tsx b/src/Components/ShareImageModal/RegionsSelect.tsx index 647fc304..11167e78 100644 --- a/src/Components/ShareImageModal/RegionsSelect.tsx +++ b/src/Components/ShareImageModal/RegionsSelect.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { ActionGroup, @@ -9,14 +9,23 @@ import { HelperTextItem, FormHelperText, Popover, - ValidatedOptions, -} from '@patternfly/react-core'; -import { Select, SelectOption, - SelectVariant, -} from '@patternfly/react-core/deprecated'; -import { ExclamationCircleIcon, HelpIcon } from '@patternfly/react-icons'; + SelectList, + ValidatedOptions, + MenuToggle, + MenuToggleElement, + TextInputGroup, + TextInputGroupMain, + TextInputGroupUtilities, + ChipGroup, + Chip, +} from '@patternfly/react-core'; +import { + ExclamationCircleIcon, + HelpIcon, + TimesIcon, +} from '@patternfly/react-icons'; import { useNavigate } from 'react-router-dom'; import { AWS_REGIONS } from '../../constants'; @@ -55,28 +64,72 @@ const generateRequests = ( type RegionsSelectPropTypes = { composeId: string; handleClose: any; - handleToggle: any; - isOpen: boolean; - setIsOpen: any; }; -const RegionsSelect = ({ - composeId, - handleClose, - handleToggle, - isOpen, - setIsOpen, -}: RegionsSelectPropTypes) => { +const RegionsSelect = ({ composeId, handleClose }: RegionsSelectPropTypes) => { const navigate = useNavigate(); + + const [isOpen, setIsOpen] = useState(false); const [isSaving, setIsSaving] = useState(false); - const [selected, setSelected] = useState([]); - const titleId = 'Clone this image'; const [validated, setValidated] = useState( ValidatedOptions.default ); - const [helperTextInvalid] = useState( - 'Select at least one region to share to.' - ); + + const initialRegions = AWS_REGIONS; + + const [inputValue, setInputValue] = useState(''); + const [selected, setSelected] = useState([]); + const [selectOptions, setSelectOptions] = useState(initialRegions); + + // Filter dropdown items when there is a typed input + useEffect(() => { + let newSelectOptions = initialRegions; + + if (inputValue) { + newSelectOptions = initialRegions.filter((region) => + region.value.toLowerCase().includes(inputValue.toLowerCase()) + ); + + // When no options are found after filtering, display 'No results found' + if (!newSelectOptions.length) { + newSelectOptions = [ + { + disableRegion: false, + description: `No results found for "${inputValue}"`, + value: 'empty', + }, + ]; + } + + // Open the menu when the input value changes and the new value is not empty + if (!isOpen) { + setIsOpen(true); + } + } + + setSelectOptions(newSelectOptions); + }, [inputValue]); + + const onTextInputChange = ( + _event: React.FormEvent, + value: string + ) => { + setInputValue(value); + }; + + const onSelect = (value: string) => { + if (value && value !== 'no results') { + setSelected( + selected.includes(value) + ? selected.filter((selection) => selection !== value) + : [...selected, value] + ); + setValidated(ValidatedOptions.success); + } else { + setValidated(ValidatedOptions.error); + } + }; + const [cloneCompose] = useCloneComposeMutation(); const { data: composeStatus, isSuccess } = useGetComposeStatusQuery({ @@ -87,33 +140,6 @@ const RegionsSelect = ({ return undefined; } - const options = AWS_REGIONS; - - const handleSelect = ( - event: React.MouseEvent | React.ChangeEvent, - selection: string - ): void => { - let nextSelected; - if (selected.includes(selection)) { - nextSelected = selected.filter((region) => region !== selection); - setSelected(nextSelected); - setIsOpen(false); - } else { - nextSelected = [...selected, selection]; - setSelected(nextSelected); - setIsOpen(false); - } - nextSelected.length === 0 - ? setValidated(ValidatedOptions.error) - : setValidated(ValidatedOptions.default); - }; - - const handleClear = () => { - setSelected([]); - setIsOpen(false); - setValidated(ValidatedOptions.error); - }; - const handleSubmit = async () => { setIsSaving(true); const requests = generateRequests(composeId, composeStatus, selected); @@ -121,9 +147,63 @@ const RegionsSelect = ({ navigate(resolveRelPath('')); }; + const handleToggle = () => { + if (!selected.length) setValidated(ValidatedOptions.error); + setIsOpen(!isOpen); + }; + + const toggle = (toggleRef: React.Ref) => ( + + + + + {selected.map((selection, index) => ( + { + ev.stopPropagation(); + onSelect(selection); + }} + > + {selection} + + ))} + + + + {selected.length > 0 && ( + + )} + + + + ); + return (
-