123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import {useMemo, useState} from 'react';
- import CompactSelect from 'sentry/components/compactSelect';
- import {GeneralSelectValue} from 'sentry/components/forms/controls/selectControl';
- import {valueIsEqual} from 'sentry/utils';
- type Section<OptionType> = {
-
- label: string;
-
- options: OptionType[];
-
- value: string;
- defaultValue?: any;
-
- multiple?: boolean;
- onChange?: (value: any) => void;
- };
- type ExtendedOptionType = GeneralSelectValue & {
- selectionMode?: 'multiple' | 'single';
- };
- type Props<OptionType> = Omit<
- React.ComponentProps<typeof CompactSelect>,
- 'multiple' | 'defaultValue' | 'onChange'
- > & {
-
- sections: Section<OptionType>[];
- };
- function CompositeSelect<OptionType extends GeneralSelectValue = GeneralSelectValue>({
- sections,
- ...props
- }: Props<OptionType>) {
- const [values, setValues] = useState(sections.map(section => section.defaultValue));
-
- const optionsMap = useMemo(() => {
- const allOptions = sections
- .map((section, i) => section.options.map(opt => [opt.value, i]))
- .flat();
- return Object.fromEntries(allOptions);
- }, [sections]);
-
- const options = useMemo(() => {
- return sections.map(section => ({
- ...section,
- options: section.options.map(
- opt =>
- ({
- ...opt,
- selectionMode: section.multiple ? 'multiple' : 'single',
- } as ExtendedOptionType)
- ),
- }));
- }, [sections]);
-
- function onChangeValueMap(selectedOptions: ExtendedOptionType[]) {
- const newValues = new Array(sections.length).fill(undefined);
- selectedOptions.forEach(option => {
- const parentSectionIndex = optionsMap[option.value];
- const parentSection = sections[parentSectionIndex];
-
-
- if (parentSection.multiple) {
- if (!newValues[parentSectionIndex]) {
- newValues[parentSectionIndex] = [];
- }
- newValues[parentSectionIndex].push(option.value);
- return;
- }
-
-
- if (option.value) {
- newValues[parentSectionIndex] = option.value;
- }
- });
- sections.forEach((section, i) => {
-
-
- if (!section.multiple && !newValues[i]) {
- newValues[i] = values[i];
-
- } else if (!newValues[i]) {
- newValues[i] = [];
- }
-
- if (!valueIsEqual(values[i], newValues[i])) {
- sections[i].onChange?.(newValues[i]);
- }
- });
- setValues(newValues);
-
-
- return newValues.flat();
- }
- return (
- <CompactSelect
- {...props}
- multiple
- options={options}
- defaultValue={sections.map(section => section.defaultValue).flat()}
- onChangeValueMap={onChangeValueMap}
- />
- );
- }
- export default CompositeSelect;
|