mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-21 02:33:34 +01:00
fix: dynamically determine the chat window height (#1588)
The AI chat window was not allowing the user to resize it due to an interacting scss class being removed. This replaces the max-height from the removed class with a dynamic calculation to resize properly.
This commit is contained in:
parent
fca868e597
commit
9f9190b93c
@ -4,6 +4,7 @@
|
||||
import { Button } from "@/app/element/button";
|
||||
import { Markdown } from "@/app/element/markdown";
|
||||
import { TypingIndicator } from "@/app/element/typingindicator";
|
||||
import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions";
|
||||
import { RpcResponseHelper, WshClient } from "@/app/store/wshclient";
|
||||
import { RpcApi } from "@/app/store/wshclientapi";
|
||||
import { makeFeBlockRouteId } from "@/app/store/wshrouter";
|
||||
@ -506,84 +507,88 @@ interface ChatWindowProps {
|
||||
messages: ChatMessageType[];
|
||||
msgWidths: Object;
|
||||
model: WaveAiModel;
|
||||
height: number;
|
||||
}
|
||||
|
||||
const ChatWindow = memo(
|
||||
forwardRef<OverlayScrollbarsComponentRef, ChatWindowProps>(({ chatWindowRef, messages, msgWidths, model }, ref) => {
|
||||
const [isUserScrolling, setIsUserScrolling] = useState(false);
|
||||
forwardRef<OverlayScrollbarsComponentRef, ChatWindowProps>(
|
||||
({ chatWindowRef, messages, msgWidths, model, height }, ref) => {
|
||||
const [isUserScrolling, setIsUserScrolling] = useState(false);
|
||||
|
||||
const osRef = useRef<OverlayScrollbarsComponentRef>(null);
|
||||
const prevMessagesLenRef = useRef(messages.length);
|
||||
const osRef = useRef<OverlayScrollbarsComponentRef>(null);
|
||||
const prevMessagesLenRef = useRef(messages.length);
|
||||
|
||||
useImperativeHandle(ref, () => osRef.current as OverlayScrollbarsComponentRef);
|
||||
useImperativeHandle(ref, () => osRef.current as OverlayScrollbarsComponentRef);
|
||||
|
||||
useEffect(() => {
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
const curMessagesLen = messages.length;
|
||||
if (prevMessagesLenRef.current !== curMessagesLen || !isUserScrolling) {
|
||||
setIsUserScrolling(false);
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
}
|
||||
|
||||
prevMessagesLenRef.current = curMessagesLen;
|
||||
}
|
||||
}, [messages, isUserScrolling]);
|
||||
|
||||
useEffect(() => {
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
|
||||
const handleUserScroll = () => {
|
||||
setIsUserScrolling(true);
|
||||
};
|
||||
|
||||
viewport.addEventListener("wheel", handleUserScroll, { passive: true });
|
||||
viewport.addEventListener("touchmove", handleUserScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
viewport.removeEventListener("wheel", handleUserScroll);
|
||||
viewport.removeEventListener("touchmove", handleUserScroll);
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
osRef.current.osInstance().destroy();
|
||||
useEffect(() => {
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
const curMessagesLen = messages.length;
|
||||
if (prevMessagesLenRef.current !== curMessagesLen || !isUserScrolling) {
|
||||
setIsUserScrolling(false);
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleScrollbarInitialized = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
};
|
||||
prevMessagesLenRef.current = curMessagesLen;
|
||||
}
|
||||
}, [messages, isUserScrolling]);
|
||||
|
||||
const handleScrollbarUpdated = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
};
|
||||
useEffect(() => {
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
|
||||
return (
|
||||
<OverlayScrollbarsComponent
|
||||
ref={osRef}
|
||||
className="scrollable"
|
||||
options={{ scrollbars: { autoHide: "leave" } }}
|
||||
events={{ initialized: handleScrollbarInitialized, updated: handleScrollbarUpdated }}
|
||||
>
|
||||
<div ref={chatWindowRef} className="chat-window" style={msgWidths}>
|
||||
<div className="filler"></div>
|
||||
{messages.map((chitem, idx) => (
|
||||
<ChatItem key={idx} chatItem={chitem} model={model} />
|
||||
))}
|
||||
</div>
|
||||
</OverlayScrollbarsComponent>
|
||||
);
|
||||
})
|
||||
const handleUserScroll = () => {
|
||||
setIsUserScrolling(true);
|
||||
};
|
||||
|
||||
viewport.addEventListener("wheel", handleUserScroll, { passive: true });
|
||||
viewport.addEventListener("touchmove", handleUserScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
viewport.removeEventListener("wheel", handleUserScroll);
|
||||
viewport.removeEventListener("touchmove", handleUserScroll);
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
osRef.current.osInstance().destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleScrollbarInitialized = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
};
|
||||
|
||||
const handleScrollbarUpdated = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
};
|
||||
|
||||
return (
|
||||
<OverlayScrollbarsComponent
|
||||
ref={osRef}
|
||||
className="scrollable"
|
||||
options={{ scrollbars: { autoHide: "leave" } }}
|
||||
events={{ initialized: handleScrollbarInitialized, updated: handleScrollbarUpdated }}
|
||||
style={{ maxHeight: height }}
|
||||
>
|
||||
<div ref={chatWindowRef} className="chat-window" style={msgWidths}>
|
||||
<div className="filler"></div>
|
||||
{messages.map((chitem, idx) => (
|
||||
<ChatItem key={idx} chatItem={chitem} model={model} />
|
||||
))}
|
||||
</div>
|
||||
</OverlayScrollbarsComponent>
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
interface ChatInputProps {
|
||||
@ -657,6 +662,8 @@ const WaveAi = ({ model }: { model: WaveAiModel; blockId: string }) => {
|
||||
const chatWindowRef = useRef<HTMLDivElement>(null);
|
||||
const osRef = useRef<OverlayScrollbarsComponentRef>(null);
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||
const waveAiDims = useDimensionsWithExistingRef(waveaiRef);
|
||||
const chatInputDims = useDimensionsWithExistingRef(inputRef);
|
||||
|
||||
const [value, setValue] = useState("");
|
||||
const [selectedBlockIdx, setSelectedBlockIdx] = useState<number | null>(null);
|
||||
@ -829,6 +836,8 @@ const WaveAi = ({ model }: { model: WaveAiModel; blockId: string }) => {
|
||||
messages={messages}
|
||||
msgWidths={msgWidths}
|
||||
model={model}
|
||||
height={waveAiDims?.height - chatInputDims?.height - 28 ?? 400}
|
||||
// the 28 is a magic number it the moment but it makes the spacing look good
|
||||
/>
|
||||
</div>
|
||||
<div className="waveai-controls">
|
||||
|
Loading…
Reference in New Issue
Block a user