123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- import {Fragment, useMemo} from 'react';
- import styled from '@emotion/styled';
- import FeatureBadge from 'sentry/components/badge/featureBadge';
- import type {
- MultipleSelectProps,
- SelectOption,
- SingleSelectProps,
- } from 'sentry/components/compactSelect';
- import {CompactSelect} from 'sentry/components/compactSelect';
- import Truncate from 'sentry/components/truncate';
- import {defined} from 'sentry/utils';
- type BaseProps = {
- title: string;
- featureType?: 'alpha' | 'beta' | 'new';
- };
- interface SingleProps
- extends Omit<
- SingleSelectProps<string>,
- 'onChange' | 'defaultValue' | 'multiple' | 'title'
- >,
- BaseProps {
- onChange: (value: string) => void;
- selected: string;
- defaultValue?: string;
- multiple?: false;
- }
- interface MultipleProps
- extends Omit<
- MultipleSelectProps<string>,
- 'onChange' | 'defaultValue' | 'multiple' | 'title'
- >,
- BaseProps {
- multiple: true;
- onChange: (value: string[]) => void;
- selected: string[];
- defaultValue?: string[];
- }
- function OptionSelector({
- options,
- onChange,
- selected,
- title,
- featureType,
- multiple,
- defaultValue,
- closeOnSelect,
- ...rest
- }: SingleProps | MultipleProps) {
- const mappedOptions = useMemo(() => {
- return options.map(opt => ({
- ...opt,
- textValue: String(opt.label),
- label: <Truncate value={String(opt.label)} maxLength={60} expandDirection="left" />,
- }));
- }, [options]);
- const selectProps = useMemo(() => {
- // Use an if statement to help TS separate MultipleProps and SingleProps
- if (multiple) {
- return {
- multiple,
- value: selected,
- defaultValue,
- onChange: (sel: SelectOption<string>[]) => {
- onChange?.(sel.map(o => o.value));
- },
- closeOnSelect,
- };
- }
- return {
- multiple,
- value: selected,
- defaultValue,
- onChange: opt => onChange?.(opt.value),
- closeOnSelect,
- };
- }, [multiple, selected, defaultValue, onChange, closeOnSelect]);
- function isOptionDisabled(option) {
- return (
- // Option is explicitly marked as disabled
- // The user has reached the maximum number of selections (3), and the option hasn't
- // yet been selected. These options should be disabled to visually indicate that the
- // user has reached the max.
- option.disabled ||
- (multiple && selected.length === 3 && !selected.includes(option.value))
- );
- }
- return (
- <CompactSelect
- {...rest}
- {...selectProps}
- size="sm"
- options={mappedOptions}
- isOptionDisabled={isOptionDisabled}
- position="bottom-end"
- triggerProps={{
- borderless: true,
- prefix: (
- <Fragment>
- {title}
- {defined(featureType) ? <StyledFeatureBadge type={featureType} /> : null}
- </Fragment>
- ),
- }}
- />
- );
- }
- const StyledFeatureBadge = styled(FeatureBadge)`
- margin-left: 0px;
- `;
- export default OptionSelector;
|