mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-23 10:46:12 +01:00
🐛 fix: Resolve 'Icon is Not a Function' Error in PresetItems (#5260)
* refactor: improve typing * fix: "TypeError: Icon is not a function" with proper use of Functional Component and Improved Typing
This commit is contained in:
parent
0855677a36
commit
24beda3d69
6 changed files with 57 additions and 49 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import type { IconMapProps, AgentIconMapProps } from '~/common';
|
||||
import type { IconMapProps, AgentIconMapProps, IconsRecord } from '~/common';
|
||||
import { Feather } from 'lucide-react';
|
||||
import {
|
||||
MinimalPlugin,
|
||||
|
|
@ -42,7 +42,7 @@ const AssistantAvatar = ({
|
|||
};
|
||||
|
||||
const AgentAvatar = ({ className = '', avatar = '', agentName, size }: AgentIconMapProps) => {
|
||||
if (agentName && avatar) {
|
||||
if (agentName != null && agentName && avatar) {
|
||||
return (
|
||||
<img
|
||||
src={avatar}
|
||||
|
|
@ -61,7 +61,7 @@ const Bedrock = ({ className = '' }: IconMapProps) => {
|
|||
return <BedrockIcon className={cn(className, 'h-full w-full')} />;
|
||||
};
|
||||
|
||||
export const icons = {
|
||||
export const icons: IconsRecord = {
|
||||
[EModelEndpoint.azureOpenAI]: AzureMinimalIcon,
|
||||
[EModelEndpoint.openAI]: GPTIcon,
|
||||
[EModelEndpoint.gptPlugins]: MinimalPlugin,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { cn } from '~/utils';
|
|||
import store from '~/store';
|
||||
|
||||
const PresetItems: FC<{
|
||||
presets: TPreset[];
|
||||
presets?: Array<TPreset | undefined>;
|
||||
onSetDefaultPreset: (preset: TPreset, remove?: boolean) => void;
|
||||
onSelectPreset: (preset: TPreset) => void;
|
||||
onChangePreset: (preset: TPreset) => void;
|
||||
|
|
@ -110,11 +110,17 @@ const PresetItems: FC<{
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Flipper flipKey={presets.map(({ presetId }) => presetId).join('.')}>
|
||||
<Flipper
|
||||
flipKey={presets
|
||||
?.map((preset) => preset?.presetId)
|
||||
.filter((p) => p)
|
||||
.join('.')}
|
||||
>
|
||||
{presets &&
|
||||
presets.length > 0 &&
|
||||
presets.map((preset, i) => {
|
||||
if (!preset || !preset.presetId) {
|
||||
const presetId = preset?.presetId ?? '';
|
||||
if (!preset || !presetId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -122,22 +128,23 @@ const PresetItems: FC<{
|
|||
const Icon = icons[iconKey];
|
||||
|
||||
return (
|
||||
<Close asChild key={`preset-${preset.presetId}`}>
|
||||
<div key={`preset-${preset.presetId}`}>
|
||||
<Flipped flipId={preset.presetId}>
|
||||
<Close asChild key={`preset-${presetId}`}>
|
||||
<div key={`preset-${presetId}`}>
|
||||
<Flipped flipId={presetId}>
|
||||
<MenuItem
|
||||
key={`preset-item-${preset.presetId}`}
|
||||
key={`preset-item-${presetId}`}
|
||||
textClassName="text-xs max-w-[150px] sm:max-w-[200px] truncate md:max-w-full "
|
||||
title={getPresetTitle(preset)}
|
||||
onClick={() => onSelectPreset(preset)}
|
||||
icon={
|
||||
Icon &&
|
||||
Icon({
|
||||
context: 'menu-item',
|
||||
iconURL: getEndpointField(endpointsConfig, preset.endpoint, 'iconURL'),
|
||||
className: 'icon-md mr-1 dark:text-white',
|
||||
endpoint: preset.endpoint,
|
||||
})
|
||||
Icon != null && (
|
||||
<Icon
|
||||
context="menu-item"
|
||||
iconURL={getEndpointField(endpointsConfig, preset.endpoint, 'iconURL')}
|
||||
className="icon-md mr-1 dark:text-white"
|
||||
endpoint={preset.endpoint}
|
||||
/>
|
||||
)
|
||||
}
|
||||
selected={false}
|
||||
data-testid={`preset-item-${preset}`}
|
||||
|
|
@ -146,17 +153,17 @@ const PresetItems: FC<{
|
|||
<button
|
||||
className={cn(
|
||||
'm-0 h-full rounded-md bg-transparent p-2 text-gray-400 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200',
|
||||
defaultPreset?.presetId === preset.presetId
|
||||
defaultPreset?.presetId === presetId
|
||||
? ''
|
||||
: 'sm:invisible sm:group-hover:visible',
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onSetDefaultPreset(preset, defaultPreset?.presetId === preset.presetId);
|
||||
onSetDefaultPreset(preset, defaultPreset?.presetId === presetId);
|
||||
}}
|
||||
>
|
||||
<PinIcon unpin={defaultPreset?.presetId === preset.presetId} />
|
||||
<PinIcon unpin={defaultPreset?.presetId === presetId} />
|
||||
</button>
|
||||
<button
|
||||
className="m-0 h-full rounded-md p-2 text-gray-400 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 sm:invisible sm:group-hover:visible"
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ const PresetsMenu: FC = () => {
|
|||
exportPreset,
|
||||
} = usePresets();
|
||||
const { preset } = useChatContext();
|
||||
|
||||
const presets = presetsQuery.data || [];
|
||||
return (
|
||||
<Root>
|
||||
<Trigger asChild>
|
||||
|
|
@ -54,7 +52,7 @@ const PresetsMenu: FC = () => {
|
|||
className="mt-2 max-h-[495px] overflow-x-hidden rounded-lg border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-700 dark:text-white md:min-w-[400px]"
|
||||
>
|
||||
<PresetItems
|
||||
presets={presets}
|
||||
presets={presetsQuery.data}
|
||||
onSetDefaultPreset={onSetDefaultPreset}
|
||||
onSelectPreset={onSelectPreset}
|
||||
onChangePreset={onChangePreset}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue