:lightning: further chat performance tweaks

This commit is contained in:
TC
2026-06-16 21:03:52 +10:00
parent 4f1fbec868
commit 5a2dfee268

View File

@@ -1,4 +1,5 @@
import { useRef, useEffect, useState } from 'react'
import { useRef, useEffect, useState, memo } from 'react'
import { useShallow } from 'zustand/react/shallow'
import { useEditorStore } from '../../store/editorStore'
import { ChatMessageItem } from './ChatMessageItem'
import { ChatInput } from './ChatInput'
@@ -7,6 +8,35 @@ import { parseAnnotationsFromAIResponse } from '../../utils/annotationParser'
import type { Attachment, TextAnnotation } from '../../types/editor'
import './Chat.css'
const StreamingBubble = memo(function StreamingBubble({ scrollContainerRef }: { scrollContainerRef: React.RefObject<HTMLDivElement> }) {
const streamingContent = useEditorStore(s => s.streamingContent)
const isAILoading = useEditorStore(s => s.isAILoading)
const rafRef = useRef<number | null>(null)
useEffect(() => {
if (!isAILoading) return
if (rafRef.current !== null) return
rafRef.current = requestAnimationFrame(() => {
rafRef.current = null
const el = scrollContainerRef.current
if (el) el.scrollTop = el.scrollHeight
})
}, [streamingContent, isAILoading, scrollContainerRef])
if (!isAILoading) return null
return (
<div className="chat-message chat-message-assistant">
<div className="chat-message-label">Editor AI</div>
<div className="chat-message-content">
{streamingContent
? <span>{streamingContent}</span>
: <div className="chat-typing"><span /><span /><span /></div>
}
</div>
</div>
)
})
function formatSessionTime(createdAt: number): string {
const date = new Date(createdAt)
const now = new Date()
@@ -34,7 +64,6 @@ export function ChatPanel(): JSX.Element {
addUserMessage,
finalizeAssistantMessage,
setStreamingContent,
streamingContent,
setAILoading,
setAIError,
setAnnotations,
@@ -43,7 +72,29 @@ export function ChatPanel(): JSX.Element {
setActiveSession,
rightPanelTab,
setRightPanelTab,
} = useEditorStore()
} = useEditorStore(useShallow(s => ({
chatHistory: s.chatHistory,
chatSessionsByFile: s.chatSessionsByFile,
activeSessionIdByFile: s.activeSessionIdByFile,
isAILoading: s.isAILoading,
aiError: s.aiError,
activeFileContent: s.activeFileContent,
activeFilePath: s.activeFilePath,
analysisMode: s.analysisMode,
annotations: s.annotations,
annotationsByFile: s.annotationsByFile,
addUserMessage: s.addUserMessage,
finalizeAssistantMessage: s.finalizeAssistantMessage,
setStreamingContent: s.setStreamingContent,
setAILoading: s.setAILoading,
setAIError: s.setAIError,
setAnnotations: s.setAnnotations,
linkAnnotationsToMessage: s.linkAnnotationsToMessage,
newChat: s.newChat,
setActiveSession: s.setActiveSession,
rightPanelTab: s.rightPanelTab,
setRightPanelTab: s.setRightPanelTab,
})))
const tab = rightPanelTab
const setTab = setRightPanelTab
@@ -138,7 +189,7 @@ export function ChatPanel(): JSX.Element {
}
}
// Auto-scroll to bottom when new content arrives
// Auto-scroll to bottom when a new chat message is added
useEffect(() => {
if (scrollRafRef.current !== null) return
scrollRafRef.current = requestAnimationFrame(() => {
@@ -146,7 +197,7 @@ export function ChatPanel(): JSX.Element {
const el = scrollRef.current
if (el) el.scrollTop = el.scrollHeight
})
}, [chatHistory, streamingContent])
}, [chatHistory])
const hasFile = Boolean(activeFilePath)
const allAnnotationsForFile: TextAnnotation[] =
@@ -252,17 +303,7 @@ export function ChatPanel(): JSX.Element {
/>
)
})}
{isAILoading && (
<div className="chat-message chat-message-assistant">
<div className="chat-message-label">Editor AI</div>
<div className="chat-message-content">
{streamingContent
? <span>{streamingContent}</span>
: <div className="chat-typing"><span /><span /><span /></div>
}
</div>
</div>
)}
<StreamingBubble scrollContainerRef={scrollRef} />
{aiError && (
<div className="chat-error">{aiError}</div>
)}