import { OptionsOrGroups } from 'react-select'; import _ from 'lodash'; import { AutomationTestingProps } from '@/types'; import { Select as ReactSelect } from '@@/form-components/ReactSelect'; export interface Option { value: TValue; label: string; } type Group = { label: string; options: Option[] }; type Options = OptionsOrGroups, Group>; interface SharedProps extends AutomationTestingProps { name?: string; inputId?: string; placeholder?: string; disabled?: boolean; isClearable?: boolean; bindToBody?: boolean; } interface MultiProps extends SharedProps { value: readonly TValue[]; onChange(value: readonly TValue[]): void; options: Options; isMulti: true; } interface SingleProps extends SharedProps { value: TValue; onChange(value: TValue | null): void; options: Options; isMulti?: never; } type Props = MultiProps | SingleProps; export function PortainerSelect(props: Props) { return isMultiProps(props) ? ( // eslint-disable-next-line react/jsx-props-no-spreading ) : ( // eslint-disable-next-line react/jsx-props-no-spreading ); } function isMultiProps( props: Props ): props is MultiProps { return 'isMulti' in props && !!props.isMulti; } export function SingleSelect({ name, options, onChange, value, 'data-cy': dataCy, disabled, inputId, placeholder, isClearable, bindToBody, }: SingleProps) { const selectedValue = value || (typeof value === 'number' && value === 0) ? _.first(findSelectedOptions(options, value)) : null; return ( > name={name} isClearable={isClearable} getOptionLabel={(option) => option.label} getOptionValue={(option) => String(option.value)} options={options} value={selectedValue} onChange={(option) => onChange(option ? option.value : null)} data-cy={dataCy} inputId={inputId} placeholder={placeholder} isDisabled={disabled} menuPortalTarget={bindToBody ? document.body : undefined} /> ); } function findSelectedOptions( options: Options, value: TValue | readonly TValue[] ) { const valueArr = Array.isArray(value) ? value : [value]; const values = _.compact( options.flatMap((option) => { if (isGroup(option)) { return option.options.find((option) => valueArr.includes(option.value)); } if (valueArr.includes(option.value)) { return option; } return null; }) ); return values; } export function MultiSelect({ name, value, onChange, options, 'data-cy': dataCy, inputId, placeholder, disabled, isClearable, bindToBody, }: Omit, 'isMulti'>) { const selectedOptions = findSelectedOptions(options, value); return ( option.label} getOptionValue={(option) => String(option.value)} options={options} value={selectedOptions} closeMenuOnSelect={false} onChange={(newValue) => onChange(newValue.map((option) => option.value))} data-cy={dataCy} inputId={inputId} placeholder={placeholder} isDisabled={disabled} menuPortalTarget={bindToBody ? document.body : undefined} /> ); } function isGroup( option: Option | Group ): option is Group { return 'options' in option; }