/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ import React, { useState, useEffect } from 'react'; import { EuiLoadingSpinner, EuiFormControlLayout, EuiPopoverTitle, EuiButtonEmpty, EuiPopover, EuiSelectable, EuiTextColor, } from '@elastic/eui'; import './searchable_dropdown.scss'; export interface SearchableDropdownOption { id: string; label: string; searchableLabel: string; prepend: any; } interface SearchableDropdownProps { selected?: SearchableDropdownOption; onChange: (selection) => void; options: SearchableDropdownOption[]; loading: boolean; error?: Error; prepend: string; // not just the first time! onOpen?: () => void; equality: (A, B) => boolean; } type DisplayError = any; function displayError(error: DisplayError) { return typeof error === 'object' ? error.toString() : <>{error}; } export const SearchableDropdown = ({ onChange, equality, selected, options, error, loading, prepend, onOpen, }: SearchableDropdownProps) => { const [localOptions, setLocalOptions] = useState(undefined); const [isPopoverOpen, setIsPopoverOpen] = useState(false); const onButtonClick = () => { if (!isPopoverOpen && typeof onOpen === 'function') { onOpen(); } setIsPopoverOpen(!isPopoverOpen); }; const closePopover = () => setIsPopoverOpen(false); function selectNewOption(newOptions) { // alright, the EUI Selectable is pretty ratchet // this is as smarmy as it is because it needs to be // first go through and count all the "checked" options const selectedCount = newOptions.filter((o) => o.checked === 'on').length; // if the count is 0, the user just "unchecked" our selection and we can just do nothing if (selectedCount === 0) { setIsPopoverOpen(false); return; } // then, if there's more than two selections, the Selectable left the previous selection as "checked" // so we need to go and "uncheck" it for (let i = 0; i < newOptions.length; i++) { if (equality(newOptions[i], selected) && selectedCount > 1) { delete newOptions[i].checked; } } // finally, we can pick the checked option as the actual selection const newSelection = newOptions.filter((o) => o.checked === 'on')[0]; setLocalOptions(newOptions); setIsPopoverOpen(false); onChange(newSelection); } useEffect(() => { setLocalOptions( options.map((o) => ({ ...o, checked: equality(o, selected) ? 'on' : undefined, })) ); }, [selected, options, equality]); const listDisplay = (list, search) => loading ? (
) : error !== undefined ? ( displayError(error) ) : ( <> {search} {list} ); const selectable = (
{listDisplay}
); const selectedText = selected === undefined ? ( {loading ? 'Loading' : 'Select an option'} ) : ( <> {selected.prepend} {selected.label} ); const selectedView = ( {selectedText} ); const formControl = ( {selectedView} ); return (
{selectable}
); };