LibreChat/client/src/components/Chat/Messages/MessageIcon.tsx
Danny Avila ea28dbfa89
🧹 chore: Clean Up Config Fields (#12537)
* chore: remove unused `interface.endpointsMenu` config field

* chore: address review — restore JSDoc UI-only example, add Zod strip test

* chore: remove unused `interface.sidePanel` config field

* chore: restrict fileStrategy/fileStrategies schema to valid storage backends

* fix: use valid FileStorage value in AppService test

* chore: address review — version bump, exhaustiveness guard, JSDoc, configSchema test

* chore: remove debug logger.log from MessageIcon render path

* fix: rewrite MessageIcon render tests to use render counting instead of logger spying

* chore: bump librechat-data-provider to 0.8.407

* chore: sync example YAML version to 1.3.7
2026-04-03 12:22:58 -04:00

97 lines
3.1 KiB
TypeScript

import { useMemo, memo } from 'react';
import { getEndpointField } from 'librechat-data-provider';
import type { Assistant, Agent } from 'librechat-data-provider';
import type { TMessageIcon } from '~/common';
import ConvoIconURL from '~/components/Endpoints/ConvoIconURL';
import { useGetEndpointsQuery } from '~/data-provider';
import { getIconEndpoint } from '~/utils';
import Icon from '~/components/Endpoints/Icon';
type MessageIconProps = {
iconData?: TMessageIcon;
assistant?: Assistant;
agent?: Agent;
};
/**
* Compares only the fields MessageIcon actually renders.
* `agent.id` / `assistant.id` are intentionally omitted because
* this component renders display properties only, not identity-derived content.
*/
export function arePropsEqual(prev: MessageIconProps, next: MessageIconProps): boolean {
const checks: [unknown, unknown][] = [
[prev.iconData?.endpoint, next.iconData?.endpoint],
[prev.iconData?.model, next.iconData?.model],
[prev.iconData?.iconURL, next.iconData?.iconURL],
[prev.iconData?.modelLabel, next.iconData?.modelLabel],
[prev.iconData?.isCreatedByUser, next.iconData?.isCreatedByUser],
[prev.agent?.name, next.agent?.name],
[prev.agent?.avatar?.filepath, next.agent?.avatar?.filepath],
[prev.assistant?.name, next.assistant?.name],
[prev.assistant?.metadata?.avatar, next.assistant?.metadata?.avatar],
];
for (const [prevVal, nextVal] of checks) {
if (prevVal !== nextVal) {
return false;
}
}
return true;
}
const MessageIcon = memo(({ iconData, assistant, agent }: MessageIconProps) => {
const { data: endpointsConfig } = useGetEndpointsQuery();
const agentName = agent?.name ?? '';
const agentAvatar = agent?.avatar?.filepath ?? '';
const assistantName = assistant?.name ?? '';
const assistantAvatar = assistant?.metadata?.avatar ?? '';
let avatarURL = '';
if (assistant) {
avatarURL = assistantAvatar;
} else if (agent) {
avatarURL = agentAvatar;
}
const iconURL = iconData?.iconURL;
const endpoint = useMemo(
() => getIconEndpoint({ endpointsConfig, iconURL, endpoint: iconData?.endpoint }),
[endpointsConfig, iconURL, iconData?.endpoint],
);
const endpointIconURL = useMemo(
() => getEndpointField(endpointsConfig, endpoint, 'iconURL'),
[endpointsConfig, endpoint],
);
if (iconData?.isCreatedByUser !== true && iconURL != null && iconURL.includes('http')) {
return (
<ConvoIconURL
iconURL={iconURL}
modelLabel={iconData?.modelLabel}
context="message"
assistantAvatar={assistantAvatar}
agentAvatar={agentAvatar}
endpointIconURL={endpointIconURL}
assistantName={assistantName}
agentName={agentName}
/>
);
}
return (
<Icon
isCreatedByUser={iconData?.isCreatedByUser ?? false}
endpoint={endpoint}
iconURL={avatarURL || endpointIconURL}
model={iconData?.model}
assistantName={assistantName}
agentName={agentName}
size={28.8}
/>
);
}, arePropsEqual);
MessageIcon.displayName = 'MessageIcon';
export default MessageIcon;