Skip to content

Commit 4cf31a1

Browse files
committed
fix issue with scrolling chat, especially when there are images
1 parent 2e7394e commit 4cf31a1

File tree

2 files changed

+59
-43
lines changed

2 files changed

+59
-43
lines changed

src/packages/frontend/chat/chat-log.tsx

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import Composing from "./composing";
3535
import Message from "./message";
3636
import { ChatMessageTyped, ChatMessages, MessageHistory, Mode } from "./types";
3737
import { getSelectedHashtagsSearch, newest_content } from "./utils";
38+
import { DivTempHeight } from "@cocalc/frontend/jupyter/cell-list";
3839

3940
interface Props {
4041
project_id: string; // used to render links more effectively
@@ -54,6 +55,7 @@ export function ChatLog(props: Readonly<Props>) {
5455
project_id,
5556
path,
5657
);
58+
const virtuosoHeightsRef = useRef<{ [index: number]: number }>({});
5759

5860
// see similar code in task list:
5961
const selectedHashtags0 = useRedux(["selectedHashtags"], project_id, path);
@@ -160,7 +162,16 @@ export function ChatLog(props: Readonly<Props>) {
160162
<Virtuoso
161163
ref={virtuosoRef}
162164
totalCount={sortedDates.length}
163-
overscan={10000}
165+
itemSize={(el) => {
166+
// see comment in jupyter/cell-list.tsx
167+
const h = el.getBoundingClientRect().height;
168+
const data = el.getAttribute("data-item-index");
169+
if (data != null) {
170+
const index = parseInt(data);
171+
virtuosoHeightsRef.current[index] = h;
172+
}
173+
return h;
174+
}}
164175
itemContent={(index) => {
165176
const date = sortedDates[index];
166177
const message: ChatMessageTyped | undefined = messages.get(date);
@@ -175,50 +186,55 @@ export function ChatLog(props: Readonly<Props>) {
175186
const is_folded =
176187
!force_unfold && isFolded(messages, message, account_id);
177188
const is_thread_body = message.get("reply_to") != null;
189+
const h = virtuosoHeightsRef.current[index];
178190

179191
return (
180192
<div style={{ overflow: "hidden" }}>
181-
<Message
182-
key={date}
183-
index={index}
184-
account_id={account_id}
185-
user_map={user_map}
186-
message={message}
187-
project_id={project_id}
188-
path={path}
189-
font_size={fontSize}
190-
selectedHashtags={selectedHashtags}
191-
actions={actions}
192-
is_thread={is_thread}
193-
is_folded={is_folded}
194-
force_unfold={force_unfold}
195-
is_thread_body={is_thread_body}
196-
is_prev_sender={isPrevMessageSender(
197-
index,
198-
sortedDates,
199-
messages,
200-
)}
201-
is_next_sender={isNextMessageSender(
202-
index,
203-
sortedDates,
204-
messages,
205-
)}
206-
show_avatar={!isNextMessageSender(index, sortedDates, messages)}
207-
mode={mode}
208-
get_user_name={(account_id: string | undefined) =>
209-
// ATTN: this also works for LLM chat bot IDs, not just account UUIDs
210-
typeof account_id === "string"
211-
? getUserName(user_map, account_id)
212-
: "Unknown name"
213-
}
214-
scroll_into_view={() =>
215-
virtuosoRef.current?.scrollIntoView({ index })
216-
}
217-
allowReply={
218-
messages.getIn([sortedDates[index + 1], "reply_to"]) == null
219-
}
220-
llm_cost_reply={llm_cost_reply}
221-
/>
193+
<DivTempHeight height={h ? `${h}px` : undefined}>
194+
<Message
195+
key={date}
196+
index={index}
197+
account_id={account_id}
198+
user_map={user_map}
199+
message={message}
200+
project_id={project_id}
201+
path={path}
202+
font_size={fontSize}
203+
selectedHashtags={selectedHashtags}
204+
actions={actions}
205+
is_thread={is_thread}
206+
is_folded={is_folded}
207+
force_unfold={force_unfold}
208+
is_thread_body={is_thread_body}
209+
is_prev_sender={isPrevMessageSender(
210+
index,
211+
sortedDates,
212+
messages,
213+
)}
214+
is_next_sender={isNextMessageSender(
215+
index,
216+
sortedDates,
217+
messages,
218+
)}
219+
show_avatar={
220+
!isNextMessageSender(index, sortedDates, messages)
221+
}
222+
mode={mode}
223+
get_user_name={(account_id: string | undefined) =>
224+
// ATTN: this also works for LLM chat bot IDs, not just account UUIDs
225+
typeof account_id === "string"
226+
? getUserName(user_map, account_id)
227+
: "Unknown name"
228+
}
229+
scroll_into_view={() =>
230+
virtuosoRef.current?.scrollIntoView({ index })
231+
}
232+
allowReply={
233+
messages.getIn([sortedDates[index + 1], "reply_to"]) == null
234+
}
235+
llm_cost_reply={llm_cost_reply}
236+
/>
237+
</DivTempHeight>
222238
</div>
223239
);
224240
}}

src/packages/frontend/jupyter/cell-list.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ The easiest hack to deal with this, seems to be to record
756756
the last measured height, then set it for the initial render
757757
of each item, then remove it.
758758
*/
759-
function DivTempHeight({ children, height }) {
759+
export function DivTempHeight({ children, height }) {
760760
const divRef = useRef<HTMLDivElement>(null);
761761
useEffect(() => {
762762
if (divRef.current != null) {

0 commit comments

Comments
 (0)