File size: 3,826 Bytes
f0743f4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | import { useMemo, useState, useCallback } from 'react';
import type { DynamicSettingProps } from 'librechat-data-provider';
import { Label, HoverCard, HoverCardTrigger, ControlCombobox } from '@librechat/client';
import { TranslationKeys, useLocalize, useParameterEffects } from '~/hooks';
import { useChatContext } from '~/Providers';
import OptionHover from './OptionHover';
import { ESide } from '~/common';
import { cn } from '~/utils';
function DynamicCombobox({
label = '',
settingKey,
defaultValue,
description = '',
columnSpan,
setOption,
options: _options,
items: _items,
showLabel = true,
showDefault = false,
labelCode = false,
descriptionCode = false,
searchPlaceholderCode = false,
selectPlaceholderCode = false,
conversation,
isCollapsed = false,
SelectIcon = null,
selectPlaceholder = '',
searchPlaceholder = '',
}: DynamicSettingProps & { isCollapsed?: boolean; SelectIcon?: React.ReactNode }) {
const localize = useLocalize();
const { preset } = useChatContext();
const [inputValue, setInputValue] = useState<string | null>(null);
const selectedValue = useMemo(() => {
return conversation?.[settingKey] ?? defaultValue;
}, [conversation, defaultValue, settingKey]);
const items = useMemo(() => {
if (_items != null) {
return _items;
}
return (_options ?? []).map((option) => ({
label: option,
value: option,
}));
}, [_options, _items]);
const handleChange = useCallback(
(value: string) => {
setInputValue(value);
setOption(settingKey)(value);
},
[setOption, settingKey],
);
useParameterEffects({
preset,
settingKey,
defaultValue,
conversation,
inputValue,
setInputValue,
preventDelayedUpdate: true,
});
const options = items ?? _options ?? [];
if (options.length === 0) {
return null;
}
return (
<div
className={cn(
'flex flex-col items-center justify-start gap-6',
columnSpan != null ? `col-span-${columnSpan}` : 'col-span-full',
)}
>
<HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2">
{showLabel === true && (
<div className="flex w-full justify-between">
<Label
htmlFor={`${settingKey}-dynamic-combobox`}
className="text-left text-sm font-medium"
>
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}
{showDefault && (
<small className="opacity-40">
({localize('com_endpoint_default')}: {defaultValue})
</small>
)}
</Label>
</div>
)}
<ControlCombobox
displayValue={selectedValue}
selectPlaceholder={
selectPlaceholderCode === true
? localize(selectPlaceholder as TranslationKeys)
: selectPlaceholder
}
searchPlaceholder={
searchPlaceholderCode === true
? localize(searchPlaceholder as TranslationKeys)
: searchPlaceholder
}
isCollapsed={isCollapsed}
ariaLabel={settingKey}
selectedValue={selectedValue ?? ''}
setValue={handleChange}
items={items}
SelectIcon={SelectIcon}
/>
</HoverCardTrigger>
{description && (
<OptionHover
description={
descriptionCode
? (localize(description as TranslationKeys) ?? description)
: description
}
side={ESide.Left}
/>
)}
</HoverCard>
</div>
);
}
export default DynamicCombobox;
|