From c571185a91f281bfc35c12008cf902144341c80d Mon Sep 17 00:00:00 2001 From: lyzno1 Date: Mon, 13 Oct 2025 13:03:55 +0800 Subject: [PATCH] fix: extract @mention highlighting from content in real-time to persist after edit --- .../components/workflow/comment/thread.tsx | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/web/app/components/workflow/comment/thread.tsx b/web/app/components/workflow/comment/thread.tsx index e42e4fe6c7..338c4debda 100644 --- a/web/app/components/workflow/comment/thread.tsx +++ b/web/app/components/workflow/comment/thread.tsx @@ -2,6 +2,7 @@ import type { FC, ReactNode } from 'react' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useParams } from 'next/navigation' import { useReactFlow, useViewport } from 'reactflow' import { useTranslation } from 'react-i18next' import { RiArrowDownSLine, RiArrowUpSLine, RiCheckboxCircleFill, RiCheckboxCircleLine, RiCloseLine, RiDeleteBinLine, RiMoreFill } from '@remixicon/react' @@ -16,6 +17,7 @@ import type { WorkflowCommentDetail, WorkflowCommentDetailReply } from '@/servic import { useAppContext } from '@/context/app-context' import { MentionInput } from './mention-input' import { getUserColor } from '@/app/components/workflow/collaboration/utils/user-color' +import { useStore } from '../store' type CommentThreadProps = { comment: WorkflowCommentDetail @@ -41,9 +43,9 @@ const ThreadMessage: FC<{ avatarUrl?: string | null createdAt: number content: string - mentionedNames?: string[] + mentionableNames: string[] className?: string -}> = ({ authorId, authorName, avatarUrl, createdAt, content, mentionedNames, className }) => { +}> = ({ authorId, authorName, avatarUrl, createdAt, content, mentionableNames, className }) => { const { formatTimeFromNow } = useFormatTimeFromNow() const { userProfile } = useAppContext() const currentUserId = userProfile?.id @@ -54,9 +56,11 @@ const ThreadMessage: FC<{ if (!content) return '' - const normalizedNames = Array.from(new Set((mentionedNames || []) + // Extract valid user names from mentionableNames, sorted by length (longest first) + const normalizedNames = Array.from(new Set(mentionableNames .map(name => name.trim()) .filter(Boolean))) + normalizedNames.sort((a, b) => b.length - a.length) if (normalizedNames.length === 0) return content @@ -111,7 +115,7 @@ const ThreadMessage: FC<{ segments.push({content.slice(cursor)}) return segments - }, [content, mentionedNames]) + }, [content, mentionableNames]) return (
@@ -154,6 +158,8 @@ export const CommentThread: FC = memo(({ onReplyDelete, onReplyDeleteDirect, }) => { + const params = useParams() + const appId = params.appId as string const { flowToScreenPosition } = useReactFlow() const viewport = useViewport() const { userProfile } = useAppContext() @@ -168,6 +174,20 @@ export const CommentThread: FC = memo(({ const replyInputRef = useRef(null) const threadRef = useRef(null) + // Get mentionable users from store + const mentionUsersFromStore = useStore(state => ( + appId ? state.mentionableUsersCache[appId] : undefined + )) + const mentionUsers = mentionUsersFromStore ?? [] + + // Extract all mentionable names for highlighting + const mentionableNames = useMemo(() => { + const names = mentionUsers + .map(user => user.name?.trim()) + .filter((name): name is string => Boolean(name)) + return Array.from(new Set(names)) + }, [mentionUsers]) + useEffect(() => { setReplyContent('') }, [comment.id]) @@ -307,25 +327,6 @@ export const CommentThread: FC = memo(({ previousReplyCountRef.current = replies.length }, [comment.id, replies.length]) - const mentionsByTarget = useMemo(() => { - const map = new Map() - for (const mention of comment.mentions || []) { - const name = mention.mentioned_user_account?.name?.trim() - if (!name) - continue - const key = mention.reply_id ?? 'root' - const existing = map.get(key) - if (existing) { - if (!existing.includes(name)) - existing.push(name) - } - else { - map.set(key, [name]) - } - } - return map - }, [comment.mentions]) - return (
= memo(({ avatarUrl={comment.created_by_account?.avatar_url || null} createdAt={comment.created_at} content={comment.content} - mentionedNames={mentionsByTarget.get('root')} + mentionableNames={mentionableNames} />
{replies.length > 0 && ( @@ -563,7 +564,7 @@ export const CommentThread: FC = memo(({ avatarUrl={reply.created_by_account?.avatar_url || null} createdAt={reply.created_at} content={reply.content} - mentionedNames={mentionsByTarget.get(reply.id)} + mentionableNames={mentionableNames} /> )}