mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-06-14 18:10:58 +02: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,
|
Dispatch,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
use,
|
use,
|
||||||
|
useCallback,
|
||||||
useContext,
|
useContext,
|
||||||
useEffect,
|
useEffect,
|
||||||
useLayoutEffect,
|
useLayoutEffect,
|
||||||
@ -893,24 +894,6 @@ export function ChatPage({
|
|||||||
);
|
);
|
||||||
const scrollDist = useRef<number>(0);
|
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 = () => {
|
const handleInputResize = () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (
|
if (
|
||||||
@ -962,33 +945,12 @@ export function ChatPage({
|
|||||||
if (isVisible) return;
|
if (isVisible) return;
|
||||||
|
|
||||||
// Check if all messages are currently rendered
|
// Check if all messages are currently rendered
|
||||||
if (currentVisibleRange.end < messageHistory.length) {
|
// If all messages are already rendered, scroll immediately
|
||||||
// Update visible range to include the last messages
|
endDivRef.current.scrollIntoView({
|
||||||
updateCurrentVisibleRange({
|
behavior: fast ? "auto" : "smooth",
|
||||||
start: Math.max(
|
});
|
||||||
0,
|
|
||||||
messageHistory.length -
|
|
||||||
(currentVisibleRange.end - currentVisibleRange.start)
|
|
||||||
),
|
|
||||||
end: messageHistory.length,
|
|
||||||
mostVisibleMessageId: currentVisibleRange.mostVisibleMessageId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Wait for the state update and re-render before scrolling
|
setHasPerformedInitialScroll(true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
// Reset waitForScrollRef after 1.5 seconds
|
// Reset waitForScrollRef after 1.5 seconds
|
||||||
@ -1009,11 +971,6 @@ export function ChatPage({
|
|||||||
handleInputResize();
|
handleInputResize();
|
||||||
}, [message]);
|
}, [message]);
|
||||||
|
|
||||||
// tracks scrolling
|
|
||||||
useEffect(() => {
|
|
||||||
updateScrollTracking();
|
|
||||||
}, [messageHistory]);
|
|
||||||
|
|
||||||
// used for resizing of the document sidebar
|
// used for resizing of the document sidebar
|
||||||
const masterFlexboxRef = useRef<HTMLDivElement>(null);
|
const masterFlexboxRef = useRef<HTMLDivElement>(null);
|
||||||
const [maxDocumentSidebarWidth, setMaxDocumentSidebarWidth] = useState<
|
const [maxDocumentSidebarWidth, setMaxDocumentSidebarWidth] = useState<
|
||||||
@ -1977,122 +1934,6 @@ export function ChatPage({
|
|||||||
|
|
||||||
// Virtualization + Scrolling related effects and functions
|
// Virtualization + Scrolling related effects and functions
|
||||||
const scrollInitialized = useRef(false);
|
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(() => {
|
const imageFileInMessageHistory = useMemo(() => {
|
||||||
return messageHistory
|
return messageHistory
|
||||||
@ -2102,11 +1943,6 @@ export function ChatPage({
|
|||||||
);
|
);
|
||||||
}, [messageHistory]);
|
}, [messageHistory]);
|
||||||
|
|
||||||
const currentVisibleRange = visibleRange.get(currentSessionId()) || {
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
mostVisibleMessageId: null,
|
|
||||||
};
|
|
||||||
useSendMessageToParent();
|
useSendMessageToParent();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -2146,6 +1982,15 @@ export function ChatPage({
|
|||||||
|
|
||||||
const currentPersona = alternativeAssistant || liveAssistant;
|
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(() => {
|
useEffect(() => {
|
||||||
const handleSlackChatRedirect = async () => {
|
const handleSlackChatRedirect = async () => {
|
||||||
if (!slackChatId) return;
|
if (!slackChatId) return;
|
||||||
@ -2596,6 +2441,7 @@ export function ChatPage({
|
|||||||
{...getRootProps()}
|
{...getRootProps()}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
onScroll={handleScroll}
|
||||||
className={`w-full h-[calc(100vh-160px)] flex flex-col default-scrollbar overflow-y-auto overflow-x-hidden relative`}
|
className={`w-full h-[calc(100vh-160px)] flex flex-col default-scrollbar overflow-y-auto overflow-x-hidden relative`}
|
||||||
ref={scrollableDivRef}
|
ref={scrollableDivRef}
|
||||||
>
|
>
|
||||||
@ -2653,18 +2499,7 @@ export function ChatPage({
|
|||||||
// NOTE: temporarily removing this to fix the scroll bug
|
// NOTE: temporarily removing this to fix the scroll bug
|
||||||
// (hasPerformedInitialScroll ? "" : "invisible")
|
// (hasPerformedInitialScroll ? "" : "invisible")
|
||||||
>
|
>
|
||||||
{(messageHistory.length < BUFFER_COUNT
|
{messageHistory.map((message, i) => {
|
||||||
? messageHistory
|
|
||||||
: messageHistory.slice(
|
|
||||||
currentVisibleRange.start,
|
|
||||||
currentVisibleRange.end
|
|
||||||
)
|
|
||||||
).map((message, fauxIndex) => {
|
|
||||||
const i =
|
|
||||||
messageHistory.length < BUFFER_COUNT
|
|
||||||
? fauxIndex
|
|
||||||
: fauxIndex + currentVisibleRange.start;
|
|
||||||
|
|
||||||
const messageMap = currentMessageMap(
|
const messageMap = currentMessageMap(
|
||||||
completeMessageDetail
|
completeMessageDetail
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user