import {useState} from 'react'; import SelectAsyncControl, { Result, SelectAsyncControlProps, } from 'sentry/components/forms/controls/selectAsyncControl'; // projects can be passed as a direct prop as well import {GeneralSelectValue} from 'sentry/components/forms/controls/selectControl'; import FormField from 'sentry/components/forms/formField'; // XXX(epurkhiser): This is wrong, it should not be inheriting these props import {InputFieldProps} from './inputField'; export interface SelectAsyncFieldProps extends Omit, SelectAsyncControlProps { /** * Similar to onChange, except it provides the entire option object (including label) when a * change is made to the field. Occurs after onChange. */ onChangeOption?: (option: GeneralSelectValue, event: any) => void; } function SelectAsyncField({onChangeOption, ...props}: SelectAsyncFieldProps) { const [results, setResults] = useState([]); const [latestSelection, setLatestSelection] = useState< GeneralSelectValue | undefined >(); return ( {({ required: _required, children: _children, onBlur, onChange, onResults, value, ...fieldProps }) => { const {defaultOptions} = props; // We don't use defaultOptions if it is undefined or a boolean const options = typeof defaultOptions === 'object' ? defaultOptions : []; // The propsValue is the `id` of the object (user, team, etc), and // react-select expects a full value object: {value: "id", label: "name"} const resolvedValue = // When rendering the selected value, first look at the API results... results.find(({value: v}) => v === value) ?? // Then at the defaultOptions passed in props... options?.find(({value: v}) => v === value) ?? // Then at the latest value selected in the form (latestSelection as GeneralSelectValue); return ( { const resultValue = !option ? option : props.multiple && Array.isArray(option) ? // List of optionObjs option.map(({value: val}) => val) : !Array.isArray(option) ? option.value : option; setLatestSelection(option); onChange?.(resultValue, e); onChangeOption?.(option, e); onBlur?.(resultValue, e); }} onResults={data => { const newResults = onResults(data); const resultSelection = newResults.find(result => result.value === value); setResults(newResults); if (resultSelection) { setLatestSelection(resultSelection); } return newResults; }} onSelectResetsInput onCloseResetsInput={false} onBlurResetsInput={false} value={resolvedValue} /> ); }} ); } export default SelectAsyncField;