fix(frontend): V1 Loading UI (#11630)

This commit is contained in:
sp.wack 2025-11-05 18:23:10 +04:00 committed by GitHub
parent 9a7002d817
commit 7e824ca5dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 20 deletions

View File

@ -97,24 +97,29 @@ export function ChatInterface() {
const isV1Conversation = conversation?.conversation_version === "V1";
// Instantly scroll to bottom when history loading completes
const prevLoadingHistoryRef = React.useRef(
// Track when we should show V1 messages (after DOM has rendered)
const [showV1Messages, setShowV1Messages] = React.useState(false);
const prevV1LoadingRef = React.useRef(
conversationWebSocket?.isLoadingHistory,
);
// Wait for DOM to render before showing V1 messages
React.useEffect(() => {
const wasLoading = prevLoadingHistoryRef.current;
const wasLoading = prevV1LoadingRef.current;
const isLoading = conversationWebSocket?.isLoadingHistory;
// When history loading transitions from true to false, instantly scroll to bottom
if (wasLoading && !isLoading && scrollRef.current) {
scrollRef.current.scrollTo({
top: scrollRef.current.scrollHeight,
behavior: "instant",
if (wasLoading && !isLoading) {
// Loading just finished - wait for next frame to ensure DOM is ready
requestAnimationFrame(() => {
setShowV1Messages(true);
});
} else if (isLoading) {
// Reset when loading starts
setShowV1Messages(false);
}
prevLoadingHistoryRef.current = isLoading;
}, [conversationWebSocket?.isLoadingHistory, scrollRef]);
prevV1LoadingRef.current = isLoading;
}, [conversationWebSocket?.isLoadingHistory]);
// Filter V0 events
const v0Events = storeEvents
@ -252,7 +257,7 @@ export function ChatInterface() {
</div>
)}
{conversationWebSocket?.isLoadingHistory &&
{(conversationWebSocket?.isLoadingHistory || !showV1Messages) &&
isV1Conversation &&
!isTask && (
<div className="flex justify-center">
@ -269,7 +274,7 @@ export function ChatInterface() {
/>
)}
{!conversationWebSocket?.isLoadingHistory && v1UserEventsExist && (
{showV1Messages && v1UserEventsExist && (
<V1Messages messages={v1UiEvents} allEvents={v1FullEvents} />
)}
</div>

View File

@ -1,4 +1,10 @@
import { RefObject, useEffect, useState, useCallback, useRef } from "react";
import {
RefObject,
useState,
useCallback,
useRef,
useLayoutEffect,
} from "react";
export function useScrollToBottom(scrollRef: RefObject<HTMLDivElement | null>) {
// Track whether we should auto-scroll to the bottom when content changes
@ -65,20 +71,20 @@ export function useScrollToBottom(scrollRef: RefObject<HTMLDivElement | null>) {
}, [scrollRef]);
// Auto-scroll effect that runs when content changes
useEffect(() => {
// Use useLayoutEffect to scroll after DOM updates but before paint
useLayoutEffect(() => {
// Only auto-scroll if autoscroll is enabled
if (autoscroll) {
const dom = scrollRef.current;
if (dom) {
requestAnimationFrame(() => {
dom.scrollTo({
top: dom.scrollHeight,
behavior: "smooth",
});
// Scroll to bottom - this will trigger on any DOM change
dom.scrollTo({
top: dom.scrollHeight,
behavior: "smooth",
});
}
}
});
}); // No dependency array - runs after every render to follow new content
return {
scrollRef,