Improve lengthy chats (#4126)

* remove scroll

* working well

* nit

* k

* nit
This commit is contained in:
pablonyx 2025-02-25 19:22:21 -08:00 committed by GitHub
parent d56177958f
commit 6f389dc100
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -56,6 +56,7 @@ import {
Dispatch,
SetStateAction,
use,
useCallback,
useContext,
useEffect,
useLayoutEffect,
@ -893,24 +894,6 @@ export function ChatPage({
);
const scrollDist = useRef<number>(0);
const updateScrollTracking = () => {
const scrollDistance =
endDivRef?.current?.getBoundingClientRect()?.top! -
inputRef?.current?.getBoundingClientRect()?.top!;
scrollDist.current = scrollDistance;
setAboveHorizon(scrollDist.current > 500);
};
useEffect(() => {
const scrollableDiv = scrollableDivRef.current;
if (scrollableDiv) {
scrollableDiv.addEventListener("scroll", updateScrollTracking);
return () => {
scrollableDiv.removeEventListener("scroll", updateScrollTracking);
};
}
}, []);
const handleInputResize = () => {
setTimeout(() => {
if (
@ -962,33 +945,12 @@ export function ChatPage({
if (isVisible) return;
// Check if all messages are currently rendered
if (currentVisibleRange.end < messageHistory.length) {
// Update visible range to include the last messages
updateCurrentVisibleRange({
start: Math.max(
0,
messageHistory.length -
(currentVisibleRange.end - currentVisibleRange.start)
),
end: messageHistory.length,
mostVisibleMessageId: currentVisibleRange.mostVisibleMessageId,
});
// If all messages are already rendered, scroll immediately
endDivRef.current.scrollIntoView({
behavior: fast ? "auto" : "smooth",
});
// Wait for the state update and re-render before scrolling
setTimeout(() => {
endDivRef.current?.scrollIntoView({
behavior: fast ? "auto" : "smooth",
});
setHasPerformedInitialScroll(true);
}, 100);
} else {
// If all messages are already rendered, scroll immediately
endDivRef.current.scrollIntoView({
behavior: fast ? "auto" : "smooth",
});
setHasPerformedInitialScroll(true);
}
setHasPerformedInitialScroll(true);
}, 50);
// Reset waitForScrollRef after 1.5 seconds
@ -1009,11 +971,6 @@ export function ChatPage({
handleInputResize();
}, [message]);
// tracks scrolling
useEffect(() => {
updateScrollTracking();
}, [messageHistory]);
// used for resizing of the document sidebar
const masterFlexboxRef = useRef<HTMLDivElement>(null);
const [maxDocumentSidebarWidth, setMaxDocumentSidebarWidth] = useState<
@ -1977,122 +1934,6 @@ export function ChatPage({
// Virtualization + Scrolling related effects and functions
const scrollInitialized = useRef(false);
interface VisibleRange {
start: number;
end: number;
mostVisibleMessageId: number | null;
}
const [visibleRange, setVisibleRange] = useState<
Map<string | null, VisibleRange>
>(() => {
const initialRange: VisibleRange = {
start: 0,
end: BUFFER_COUNT,
mostVisibleMessageId: null,
};
return new Map([[chatSessionIdRef.current, initialRange]]);
});
// Function used to update current visible range. Only method for updating `visibleRange` state.
const updateCurrentVisibleRange = (
newRange: VisibleRange,
forceUpdate?: boolean
) => {
if (
scrollInitialized.current &&
visibleRange.get(loadedIdSessionRef.current) == undefined &&
!forceUpdate
) {
return;
}
setVisibleRange((prevState) => {
const newState = new Map(prevState);
newState.set(loadedIdSessionRef.current, newRange);
return newState;
});
};
// Set first value for visibleRange state on page load / refresh.
const initializeVisibleRange = () => {
const upToDatemessageHistory = buildLatestMessageChain(
currentMessageMap(completeMessageDetail)
);
if (!scrollInitialized.current && upToDatemessageHistory.length > 0) {
const newEnd = Math.max(upToDatemessageHistory.length, BUFFER_COUNT);
const newStart = Math.max(0, newEnd - BUFFER_COUNT);
const newMostVisibleMessageId =
upToDatemessageHistory[newEnd - 1]?.messageId;
updateCurrentVisibleRange(
{
start: newStart,
end: newEnd,
mostVisibleMessageId: newMostVisibleMessageId,
},
true
);
scrollInitialized.current = true;
}
};
const updateVisibleRangeBasedOnScroll = () => {
if (!scrollInitialized.current) return;
const scrollableDiv = scrollableDivRef.current;
if (!scrollableDiv) return;
const viewportHeight = scrollableDiv.clientHeight;
let mostVisibleMessageIndex = -1;
messageHistory.forEach((message, index) => {
const messageElement = document.getElementById(
`message-${message.messageId}`
);
if (messageElement) {
const rect = messageElement.getBoundingClientRect();
const isVisible = rect.bottom <= viewportHeight && rect.bottom > 0;
if (isVisible && index > mostVisibleMessageIndex) {
mostVisibleMessageIndex = index;
}
}
});
if (mostVisibleMessageIndex !== -1) {
const startIndex = Math.max(0, mostVisibleMessageIndex - BUFFER_COUNT);
const endIndex = Math.min(
messageHistory.length,
mostVisibleMessageIndex + BUFFER_COUNT + 1
);
updateCurrentVisibleRange({
start: startIndex,
end: endIndex,
mostVisibleMessageId: messageHistory[mostVisibleMessageIndex].messageId,
});
}
};
useEffect(() => {
initializeVisibleRange();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [router, messageHistory]);
useLayoutEffect(() => {
const scrollableDiv = scrollableDivRef.current;
const handleScroll = () => {
updateVisibleRangeBasedOnScroll();
};
scrollableDiv?.addEventListener("scroll", handleScroll);
return () => {
scrollableDiv?.removeEventListener("scroll", handleScroll);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [messageHistory]);
const imageFileInMessageHistory = useMemo(() => {
return messageHistory
@ -2102,11 +1943,6 @@ export function ChatPage({
);
}, [messageHistory]);
const currentVisibleRange = visibleRange.get(currentSessionId()) || {
start: 0,
end: 0,
mostVisibleMessageId: null,
};
useSendMessageToParent();
useEffect(() => {
@ -2146,6 +1982,15 @@ export function ChatPage({
const currentPersona = alternativeAssistant || liveAssistant;
const HORIZON_DISTANCE = 800;
const handleScroll = useCallback(() => {
const scrollDistance =
endDivRef?.current?.getBoundingClientRect()?.top! -
inputRef?.current?.getBoundingClientRect()?.top!;
scrollDist.current = scrollDistance;
setAboveHorizon(scrollDist.current > HORIZON_DISTANCE);
}, []);
useEffect(() => {
const handleSlackChatRedirect = async () => {
if (!slackChatId) return;
@ -2596,6 +2441,7 @@ export function ChatPage({
{...getRootProps()}
>
<div
onScroll={handleScroll}
className={`w-full h-[calc(100vh-160px)] flex flex-col default-scrollbar overflow-y-auto overflow-x-hidden relative`}
ref={scrollableDivRef}
>
@ -2653,18 +2499,7 @@ export function ChatPage({
// NOTE: temporarily removing this to fix the scroll bug
// (hasPerformedInitialScroll ? "" : "invisible")
>
{(messageHistory.length < BUFFER_COUNT
? messageHistory
: messageHistory.slice(
currentVisibleRange.start,
currentVisibleRange.end
)
).map((message, fauxIndex) => {
const i =
messageHistory.length < BUFFER_COUNT
? fauxIndex
: fauxIndex + currentVisibleRange.start;
{messageHistory.map((message, i) => {
const messageMap = currentMessageMap(
completeMessageDetail
);