mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
122 lines
2.9 KiB
TypeScript
122 lines
2.9 KiB
TypeScript
import {Fragment, useMemo} from 'react';
|
|
import styled from '@emotion/styled';
|
|
|
|
import type {
|
|
MultipleSelectProps,
|
|
SelectOption,
|
|
SingleSelectProps,
|
|
} from 'sentry/components/compactSelect';
|
|
import {CompactSelect} from 'sentry/components/compactSelect';
|
|
import FeatureBadge from 'sentry/components/featureBadge';
|
|
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
|
|
option.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.
|
|
(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;
|