fix(ui): fix selection on dropdowns

Mantine's multiselect does not let you edit the search box with mouse, paste into it, etc. Normal select is fine.

I can't remember why I made Lora etc multiselects, but everything seems to work with normal selects, so I've change to that.
This commit is contained in:
psychedelicious 2023-07-08 23:37:34 +10:00 committed by Kent Keirsey
parent 81817532f8
commit be06d4c0af
5 changed files with 68 additions and 34 deletions

View File

@ -59,6 +59,7 @@ const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
onKeyDown={handleKeyDown}
onKeyUp={handleKeyUp}
searchable={searchable}
maxDropdownHeight={300}
styles={() => ({
label: {
color: mode(base700, base300)(colorMode),

View File

@ -3,7 +3,7 @@ import { Select, SelectProps } from '@mantine/core';
import { useAppDispatch } from 'app/store/storeHooks';
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice';
import { KeyboardEvent, memo, useCallback } from 'react';
import { KeyboardEvent, RefObject, memo, useCallback, useState } from 'react';
import { mode } from 'theme/util/mode';
export type IAISelectDataType = {
@ -14,10 +14,11 @@ export type IAISelectDataType = {
type IAISelectProps = SelectProps & {
tooltip?: string;
inputRef?: RefObject<HTMLInputElement>;
};
const IAIMantineSelect = (props: IAISelectProps) => {
const { searchable = true, tooltip, ...rest } = props;
const { searchable = true, tooltip, inputRef, onChange, ...rest } = props;
const dispatch = useAppDispatch();
const {
base50,
@ -38,7 +39,9 @@ const IAIMantineSelect = (props: IAISelectProps) => {
} = useChakraThemeTokens();
const { colorMode } = useColorMode();
const [searchValue, setSearchValue] = useState('');
// we want to capture shift keypressed even when an input is focused
const handleKeyDown = useCallback(
(e: KeyboardEvent<HTMLInputElement>) => {
if (e.shiftKey) {
@ -57,14 +60,33 @@ const IAIMantineSelect = (props: IAISelectProps) => {
[dispatch]
);
// wrap onChange to clear search value on select
const handleChange = useCallback(
(v: string | null) => {
setSearchValue('');
if (!onChange) {
return;
}
onChange(v);
},
[onChange]
);
const [boxShadow] = useToken('shadows', ['dark-lg']);
return (
<Tooltip label={tooltip} placement="top" hasArrow>
<Select
ref={inputRef}
searchValue={searchValue}
onSearchChange={setSearchValue}
onChange={handleChange}
onKeyDown={handleKeyDown}
onKeyUp={handleKeyUp}
searchable={searchable}
maxDropdownHeight={300}
styles={() => ({
label: {
color: mode(base700, base300)(colorMode),

View File

@ -9,7 +9,7 @@ import {
import { SelectItem } from '@mantine/core';
import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import IAIMantineMultiSelect from 'common/components/IAIMantineMultiSelect';
import IAIMantineSelect from 'common/components/IAIMantineSelect';
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
import { MODEL_TYPE_MAP } from 'features/system/components/ModelSelect';
import { forEach } from 'lodash-es';
@ -61,12 +61,12 @@ const ParamEmbeddingPopover = (props: Props) => {
}, [embeddingQueryData, currentMainModel?.base_model]);
const handleChange = useCallback(
(v: string[]) => {
if (v.length === 0) {
(v: string | null) => {
if (!v) {
return;
}
onSelect(v[0]);
onSelect(v);
},
[onSelect]
);
@ -106,16 +106,16 @@ const ParamEmbeddingPopover = (props: Props) => {
</Text>
</Flex>
) : (
<IAIMantineMultiSelect
<IAIMantineSelect
inputRef={inputRef}
autoFocus
placeholder={'Add Embedding'}
value={[]}
value={null}
data={data}
maxDropdownHeight={400}
nothingFound="No Matching Embeddings"
nothingFound="No matching Embeddings"
itemComponent={IAIMantineSelectItemWithTooltip}
disabled={data.length === 0}
filter={(value, selected, item: SelectItem) =>
filter={(value, item: SelectItem) =>
item.label
?.toLowerCase()
.includes(value.toLowerCase().trim()) ||

View File

@ -4,7 +4,7 @@ import { createSelector } from '@reduxjs/toolkit';
import { RootState, stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIMantineMultiSelect from 'common/components/IAIMantineMultiSelect';
import IAIMantineSelect from 'common/components/IAIMantineSelect';
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
import { loraAdded } from 'features/lora/store/loraSlice';
import { MODEL_TYPE_MAP } from 'features/system/components/ModelSelect';
@ -58,12 +58,15 @@ const ParamLoraSelect = () => {
}, [loras, lorasQueryData, currentMainModel?.base_model]);
const handleChange = useCallback(
(v: string[]) => {
const loraEntity = lorasQueryData?.entities[v[0]];
(v: string | null | undefined) => {
if (!v) {
return;
}
const loraEntity = lorasQueryData?.entities[v];
if (!loraEntity) {
return;
}
v[0] && dispatch(loraAdded(loraEntity));
dispatch(loraAdded(loraEntity));
},
[dispatch, lorasQueryData?.entities]
);
@ -79,15 +82,14 @@ const ParamLoraSelect = () => {
}
return (
<IAIMantineMultiSelect
<IAIMantineSelect
placeholder={data.length === 0 ? 'All LoRAs added' : 'Add LoRA'}
value={[]}
value={null}
data={data}
maxDropdownHeight={400}
nothingFound="No matching LoRAs"
itemComponent={IAIMantineSelectItemWithTooltip}
disabled={data.length === 0}
filter={(value, selected, item: SelectItem) =>
filter={(value, item: SelectItem) =>
item.label?.toLowerCase().includes(value.toLowerCase().trim()) ||
item.value.toLowerCase().includes(value.toLowerCase().trim())
}

View File

@ -1,15 +1,15 @@
import 'reactflow/dist/style.css';
import { useCallback, forwardRef } from 'react';
import { Flex, Text } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { nodeAdded, nodesSelector } from '../store/nodesSlice';
import { map } from 'lodash-es';
import { useBuildInvocation } from '../hooks/useBuildInvocation';
import { AnyInvocationType } from 'services/events/types';
import { useAppToaster } from 'app/components/Toaster';
import { createSelector } from '@reduxjs/toolkit';
import { useAppToaster } from 'app/components/Toaster';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIMantineMultiSelect from 'common/components/IAIMantineMultiSelect';
import IAIMantineSelect from 'common/components/IAIMantineSelect';
import { map } from 'lodash-es';
import { forwardRef, useCallback } from 'react';
import 'reactflow/dist/style.css';
import { AnyInvocationType } from 'services/events/types';
import { useBuildInvocation } from '../hooks/useBuildInvocation';
import { nodeAdded, nodesSelector } from '../store/nodesSlice';
type NodeTemplate = {
label: string;
@ -58,24 +58,33 @@ const AddNodeMenu = () => {
[dispatch, buildInvocation, toaster]
);
const handleChange = useCallback(
(v: string | null) => {
if (!v) {
return;
}
addNode(v as AnyInvocationType);
},
[addNode]
);
return (
<Flex sx={{ gap: 2, alignItems: 'center' }}>
<IAIMantineMultiSelect
<IAIMantineSelect
selectOnBlur={false}
placeholder="Add Node"
value={[]}
value={null}
data={data}
maxDropdownHeight={400}
nothingFound="No matching nodes"
itemComponent={SelectItem}
filter={(value, selected, item: NodeTemplate) =>
filter={(value, item: NodeTemplate) =>
item.label.toLowerCase().includes(value.toLowerCase().trim()) ||
item.value.toLowerCase().includes(value.toLowerCase().trim()) ||
item.description.toLowerCase().includes(value.toLowerCase().trim())
}
onChange={(v) => {
v[0] && addNode(v[0] as AnyInvocationType);
}}
onChange={handleChange}
sx={{
width: '18rem',
}}