mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-03-26 17:51:54 +01:00
Improve lengthy chats (#4126)
* remove scroll * working well * nit * k * nit
This commit is contained in:
parent
d56177958f
commit
6f389dc100
@ -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
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user