From 9b966789fd2854e6e2f52a43ec73db841491772a Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Sat, 18 Apr 2026 00:10:12 +0800 Subject: [PATCH] fix(room): resolve mention IDs to display names when rendering messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/components/room/MessageMentions.tsx | 44 ++++++++++++++++++++--- src/components/room/RoomMessageBubble.tsx | 9 +++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/components/room/MessageMentions.tsx b/src/components/room/MessageMentions.tsx index 4ef0950..324e6ef 100644 --- a/src/components/room/MessageMentions.tsx +++ b/src/components/room/MessageMentions.tsx @@ -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 = { @@ -109,14 +117,19 @@ const mentionStyles: Record = { 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 {node.text}; } if (node.type === 'mention') { + const displayName = resolveName(node.mentionType, node.id, node.label); return ( - @{node.label} + @{displayName} ); } @@ -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 and 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 (
- {nodes.map((node, i) => renderNode(node, i))} + {nodes.map((node, i) => renderNode(node, i, resolveName))}
); }); diff --git a/src/components/room/RoomMessageBubble.tsx b/src/components/room/RoomMessageBubble.tsx index 2382d06..07ab612 100644 --- a/src/components/room/RoomMessageBubble.tsx +++ b/src/components/room/RoomMessageBubble.tsx @@ -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({ )) ) : (
- +
)}