mirror of https://github.com/stashapp/stash.git
Limiting how many options are shown in select dropdowns (#3062)
Introducing a limit to how many options are shown in select dropdowns. Fixes an issue I was experiencing where large numbers of options (5000 tags) was causing dropdown to be unresponsive. Does not effect filtering, always shows 'Create "..."' option if it exists, and shows a notice at the bottom of the dropdown of how many options were hidden from the list if any were.
This commit is contained in:
parent
d2743cf5fb
commit
404a68c994
|
@ -6,6 +6,8 @@ import Select, {
|
|||
components as reactSelectComponents,
|
||||
GroupedOptionsType,
|
||||
OptionsType,
|
||||
MenuListComponentProps,
|
||||
GroupTypeBase,
|
||||
} from "react-select";
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
import debounce from "lodash-es/debounce";
|
||||
|
@ -116,6 +118,55 @@ const getSelectedItems = (selectedItems: ValueType<Option, boolean>) =>
|
|||
const getSelectedValues = (selectedItems: ValueType<Option, boolean>) =>
|
||||
getSelectedItems(selectedItems).map((item) => item.value);
|
||||
|
||||
const LimitedSelectMenu = <T extends boolean>(
|
||||
props: MenuListComponentProps<Option, T, GroupTypeBase<Option>>
|
||||
) => {
|
||||
const maxOptionsShown = 200;
|
||||
const [hiddenCount, setHiddenCount] = useState<number>(0);
|
||||
const hiddenCountStyle = {
|
||||
padding: "8px 12px",
|
||||
opacity: "50%",
|
||||
};
|
||||
const menuChildren = useMemo(() => {
|
||||
if (Array.isArray(props.children)) {
|
||||
// limit the number of select options showing in the select dropdowns
|
||||
// always showing the 'Create "..."' option when it exists
|
||||
let creationOptionIndex = (props.children as React.ReactNodeArray).findIndex(
|
||||
(child: React.ReactNode) => {
|
||||
let maybeCreatableOption = child as React.ReactElement<
|
||||
OptionProps<
|
||||
Option & { __isNew__: boolean },
|
||||
T,
|
||||
GroupTypeBase<Option & { __isNew__: boolean }>
|
||||
>,
|
||||
""
|
||||
>;
|
||||
return maybeCreatableOption?.props?.data?.__isNew__;
|
||||
}
|
||||
);
|
||||
if (creationOptionIndex >= maxOptionsShown) {
|
||||
setHiddenCount(props.children.length - maxOptionsShown - 1);
|
||||
return props.children
|
||||
.slice(0, maxOptionsShown - 1)
|
||||
.concat([props.children[creationOptionIndex]]);
|
||||
} else {
|
||||
setHiddenCount(Math.max(props.children.length - maxOptionsShown, 0));
|
||||
return props.children.slice(0, maxOptionsShown);
|
||||
}
|
||||
}
|
||||
setHiddenCount(0);
|
||||
return props.children;
|
||||
}, [props.children]);
|
||||
return (
|
||||
<reactSelectComponents.MenuList {...props}>
|
||||
{menuChildren}
|
||||
{hiddenCount > 0 && (
|
||||
<div style={hiddenCountStyle}>{hiddenCount} Options Hidden</div>
|
||||
)}
|
||||
</reactSelectComponents.MenuList>
|
||||
);
|
||||
};
|
||||
|
||||
const SelectComponent = <T extends boolean>({
|
||||
type,
|
||||
initialIds,
|
||||
|
@ -191,6 +242,7 @@ const SelectComponent = <T extends boolean>({
|
|||
menuPortalTarget,
|
||||
components: {
|
||||
...components,
|
||||
MenuList: LimitedSelectMenu,
|
||||
IndicatorSeparator: () => null,
|
||||
...((!showDropdown || isDisabled) && { DropdownIndicator: () => null }),
|
||||
...(isDisabled && { MultiValueRemove: () => null }),
|
||||
|
|
Loading…
Reference in New Issue