fix(room): resolve mention IDs to display names when rendering messages
- Pass members/repos/aiConfigs lists to MessageContentWithMentions - Add resolveName() that looks up ID → display name per mention type - RoomMessageBubble now resolves user/repository/AI mention UIDs to real names
This commit is contained in:
parent
a9fc6f9937
commit
9b966789fd
@ -1,4 +1,6 @@
|
||||
import { memo, useMemo } from 'react';
|
||||
import type { ProjectRepositoryItem, RoomMemberResponse } from '@/client';
|
||||
import type { RoomAiConfig } from '@/components/room/MentionPopover';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { parse, type Node, type MentionMentionType } from '@/lib/mention-ast';
|
||||
|
||||
@ -100,6 +102,12 @@ function extractFirstMentionName(text: string, type: MentionType): string | null
|
||||
|
||||
interface MessageContentWithMentionsProps {
|
||||
content: string;
|
||||
/** Members list for resolving user mention IDs to display names */
|
||||
members?: RoomMemberResponse[];
|
||||
/** Repository list for resolving repository mention IDs to display names */
|
||||
repos?: ProjectRepositoryItem[];
|
||||
/** AI configs for resolving AI mention IDs to display names */
|
||||
aiConfigs?: RoomAiConfig[];
|
||||
}
|
||||
|
||||
const mentionStyles: Record<string, string> = {
|
||||
@ -109,14 +117,19 @@ const mentionStyles: Record<string, string> = {
|
||||
notify: 'inline-flex items-center rounded bg-yellow-100/80 px-1.5 py-0.5 text-yellow-700 dark:bg-yellow-900/40 dark:text-yellow-300 font-medium cursor-pointer hover:bg-yellow-200 dark:hover:bg-yellow-900/60 transition-colors text-sm leading-5',
|
||||
};
|
||||
|
||||
function renderNode(node: Node, index: number): React.ReactNode {
|
||||
function renderNode(
|
||||
node: Node,
|
||||
index: number,
|
||||
resolveName: (type: string, id: string, label: string) => string,
|
||||
): React.ReactNode {
|
||||
if (node.type === 'text') {
|
||||
return <span key={index}>{node.text}</span>;
|
||||
}
|
||||
if (node.type === 'mention') {
|
||||
const displayName = resolveName(node.mentionType, node.id, node.label);
|
||||
return (
|
||||
<span key={index} className={mentionStyles[node.mentionType] ?? mentionStyles.user}>
|
||||
@{node.label}
|
||||
@{displayName}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@ -140,6 +153,9 @@ function renderNode(node: Node, index: number): React.ReactNode {
|
||||
*/
|
||||
export const MessageContentWithMentions = memo(function MessageContentWithMentions({
|
||||
content,
|
||||
members = [],
|
||||
repos = [],
|
||||
aiConfigs = [],
|
||||
}: MessageContentWithMentionsProps) {
|
||||
const nodes = useMemo(() => {
|
||||
// Try the new AST parser first (handles <mention> and <ai> tags)
|
||||
@ -172,6 +188,26 @@ export const MessageContentWithMentions = memo(function MessageContentWithMentio
|
||||
return parts;
|
||||
}, [content]);
|
||||
|
||||
// Resolve ID → display name for each mention type
|
||||
const resolveName = useCallback(
|
||||
(type: string, id: string, label: string): string => {
|
||||
if (type === 'user') {
|
||||
const member = members.find((m) => m.user === id);
|
||||
return member?.user_info?.username ?? member?.user ?? label;
|
||||
}
|
||||
if (type === 'repository') {
|
||||
const repo = repos.find((r) => r.uid === id);
|
||||
return repo?.repo_name ?? label;
|
||||
}
|
||||
if (type === 'ai') {
|
||||
const cfg = aiConfigs.find((c) => c.model === id);
|
||||
return cfg?.modelName ?? cfg?.model ?? label;
|
||||
}
|
||||
return label;
|
||||
},
|
||||
[members, repos, aiConfigs],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@ -181,7 +217,7 @@ export const MessageContentWithMentions = memo(function MessageContentWithMentio
|
||||
'[&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:overflow-x-auto',
|
||||
)}
|
||||
>
|
||||
{nodes.map((node, i) => renderNode(node, i))}
|
||||
{nodes.map((node, i) => renderNode(node, i, resolveName))}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@ -92,7 +92,7 @@ export const RoomMessageBubble = memo(function RoomMessageBubble({
|
||||
const isStreaming = !!message.is_streaming;
|
||||
const isEdited = !!message.edited_at;
|
||||
const { user } = useUser();
|
||||
const { wsClient, streamingMessages } = useRoom();
|
||||
const { wsClient, streamingMessages, members, projectRepos, roomAiConfigs } = useRoom();
|
||||
const isOwner = user?.uid === getSenderUserUid(message);
|
||||
const isRevoked = !!message.revoked;
|
||||
const isFailed = message.isOptimisticError === true;
|
||||
@ -315,7 +315,12 @@ export const RoomMessageBubble = memo(function RoomMessageBubble({
|
||||
))
|
||||
) : (
|
||||
<div className="max-w-full min-w-0 overflow-hidden whitespace-pre-wrap break-words">
|
||||
<MessageContentWithMentions content={displayContent} />
|
||||
<MessageContentWithMentions
|
||||
content={displayContent}
|
||||
members={members}
|
||||
repos={projectRepos}
|
||||
aiConfigs={roomAiConfigs}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user