From f97c15b7ed8a98a2a07bad6a99d64c1716bc56cc Mon Sep 17 00:00:00 2001 From: WangzJi Date: Mon, 30 Jun 2025 10:42:32 +0800 Subject: [PATCH] fix(web): Fix auto-scroll issue in chat dashboard --- web/components/chat/completion.tsx | 51 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/web/components/chat/completion.tsx b/web/components/chat/completion.tsx index df16e3216..494dce490 100644 --- a/web/components/chat/completion.tsx +++ b/web/components/chat/completion.tsx @@ -98,12 +98,15 @@ const Completion = ({ messages, onSubmit, onFormatContent }: Props) => { // Process message content - if onFormatContent is provided and this is a dashboard chat, // we'll extract the thinking part from vis-thinking code blocks - const processMessageContent = (content: any) => { - if (isChartChat && onFormatContent && typeof content === 'string') { - return onFormatContent(content); - } - return content; - }; + const processMessageContent = useCallback( + (content: any) => { + if (isChartChat && onFormatContent && typeof content === 'string') { + return onFormatContent(content); + } + return content; + }, + [isChartChat, onFormatContent], + ); const [messageApi, contextHolder] = message.useMessage(); @@ -198,9 +201,9 @@ const Completion = ({ messages, onSubmit, onFormatContent }: Props) => { useEffect(() => { console.log('Completion updating prevMessageCountRef:', { currentLength: showMessages.length, - prevCount: prevMessageCountRef.current + prevCount: prevMessageCountRef.current, }); - + // Only update if this is the first time (count is 0) if (prevMessageCountRef.current === 0) { prevMessageCountRef.current = showMessages.length; @@ -213,9 +216,9 @@ const Completion = ({ messages, onSubmit, onFormatContent }: Props) => { if (isAutoScrollingRef.current) { return; } - + lastScrollTimeRef.current = Date.now(); - + if (scrollableRef.current) { const scrollElement = scrollableRef.current; const { scrollTop, scrollHeight, clientHeight } = scrollElement; @@ -241,7 +244,7 @@ const Completion = ({ messages, onSubmit, onFormatContent }: Props) => { showMessagesLength: showMessages.length, userRecentlyScrolled, isUserScrolling: isUserScrollingRef.current, - isAutoScrolling: isAutoScrollingRef.current + isAutoScrolling: isAutoScrollingRef.current, }); // Always handle new messages first - this is the highest priority @@ -249,54 +252,54 @@ const Completion = ({ messages, onSubmit, onFormatContent }: Props) => { console.log('Completion: New message detected, forcing scroll to bottom'); // New message - always scroll to bottom regardless of user position isAutoScrollingRef.current = true; - + // Reset states IMMEDIATELY to ensure streaming can work lastScrollTimeRef.current = Date.now() - 3000; // Allow streaming immediately isUserScrollingRef.current = false; lastContentHeightRef.current = scrollElement.scrollHeight; // Set current height as baseline - + scrollElement.scrollTo({ top: scrollElement.scrollHeight, behavior: 'smooth', }); - + // Reset auto scroll flag after animation setTimeout(() => { isAutoScrollingRef.current = false; }, 100); - + prevMessageCountRef.current = currentMessageCount; // Update count immediately return; // Exit early for new messages } - + // Handle streaming content updates (only if user hasn't manually scrolled recently) if (!userRecentlyScrolled && !isUserScrollingRef.current && !isAutoScrollingRef.current) { // Streaming content - scroll based on content height change const currentHeight = scrollElement.scrollHeight; - + // Initialize lastContentHeightRef if not set if (lastContentHeightRef.current === 0) { lastContentHeightRef.current = currentHeight; } - + const heightDiff = currentHeight - lastContentHeightRef.current; - + console.log('Completion streaming check:', { currentHeight, lastHeight: lastContentHeightRef.current, heightDiff, - threshold: 12 + threshold: 12, }); - + // Only scroll if content height increased by at least ~0.5 lines (12px) for smoother experience if (heightDiff >= 12) { // Clear any pending scroll timeout if (scrollTimeoutRef.current) { clearTimeout(scrollTimeoutRef.current); } - + console.log('Completion: Triggering streaming scroll, heightDiff:', heightDiff); - + // Debounce scroll calls to avoid conflicts scrollTimeoutRef.current = setTimeout(() => { isAutoScrollingRef.current = true; @@ -314,7 +317,7 @@ const Completion = ({ messages, onSubmit, onFormatContent }: Props) => { console.log('Completion streaming blocked:', { userRecentlyScrolled, isUserScrolling: isUserScrollingRef.current, - isAutoScrolling: isAutoScrollingRef.current + isAutoScrolling: isAutoScrollingRef.current, }); } }, [showMessages, scene]);