@@ -11,7 +11,6 @@ import { Alert } from "antd";
1111import { List , Set as immutableSet } from "immutable" ;
1212import { MutableRefObject , useEffect , useMemo , useRef } from "react" ;
1313import { Virtuoso , VirtuosoHandle } from "react-virtuoso" ;
14-
1514import { chatBotName , isChatBot } from "@cocalc/frontend/account/chatbot" ;
1615import {
1716 TypedMap ,
@@ -55,7 +54,6 @@ export function ChatLog(props: Readonly<Props>) {
5554 project_id ,
5655 path ,
5756 ) ;
58- const virtuosoHeightsRef = useRef < { [ index : number ] : number } > ( { } ) ;
5957
6058 // see similar code in task list:
6159 const selectedHashtags0 = useRedux ( [ "selectedHashtags" ] , project_id , path ) ;
@@ -132,11 +130,6 @@ export function ChatLog(props: Readonly<Props>) {
132130 } ;
133131 } , [ scrollToBottomRef != null ] ) ;
134132
135- const virtuosoScroll = useVirtuosoScrollHook ( {
136- cacheId : `${ project_id } ${ path } ` ,
137- initialState : { index : messages . size - 1 , offset : 0 } , // starts scrolled to the newest message.
138- } ) ;
139-
140133 return (
141134 < >
142135 { visibleHashtags . size > 0 && (
@@ -159,90 +152,23 @@ export function ChatLog(props: Readonly<Props>) {
159152 filterRecentH = { filterRecentH }
160153 />
161154 ) }
162- < Virtuoso
163- ref = { virtuosoRef }
164- totalCount = { sortedDates . length }
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- } }
175- itemContent = { ( index ) => {
176- const date = sortedDates [ index ] ;
177- const message : ChatMessageTyped | undefined = messages . get ( date ) ;
178- if ( message == null ) {
179- // shouldn't happen. But we should be robust to such a possibility.
180- return < div style = { { height : "1px" } } /> ;
181- }
182-
183- const is_thread = isThread ( messages , message ) ;
184- // if we search for a message, we treat all threads as unfolded
185- const force_unfold = ! ! search ;
186- const is_folded =
187- ! force_unfold && isFolded ( messages , message , account_id ) ;
188- const is_thread_body = message . get ( "reply_to" ) != null ;
189- const h = virtuosoHeightsRef . current [ index ] ;
190-
191- return (
192- < div style = { { overflow : "hidden" } } >
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 >
238- </ div >
239- ) ;
240- } }
241- rangeChanged = { ( { endIndex } ) => {
242- // manually scrolling if NOT at the bottom.
243- manualScrollRef . current = endIndex < sortedDates . length - 1 ;
155+ < MessageList
156+ { ...{
157+ virtuosoRef,
158+ sortedDates,
159+ messages,
160+ search,
161+ account_id,
162+ user_map,
163+ project_id,
164+ path,
165+ fontSize,
166+ selectedHashtags,
167+ actions,
168+ llm_cost_reply,
169+ manualScrollRef,
170+ mode,
244171 } }
245- { ...virtuosoScroll }
246172 />
247173 < Composing
248174 projectId = { project_id }
@@ -455,3 +381,133 @@ function NotShowing({ num, search, filterRecentH }: NotShowingProps) {
455381 />
456382 ) ;
457383}
384+
385+ export function MessageList ( {
386+ messages,
387+ account_id,
388+ virtuosoRef,
389+ sortedDates,
390+ search,
391+ user_map,
392+ project_id,
393+ path,
394+ fontSize,
395+ selectedHashtags,
396+ actions,
397+ llm_cost_reply,
398+ manualScrollRef,
399+ mode,
400+ } : {
401+ messages ;
402+ account_id ;
403+ user_map ;
404+ mode ;
405+ sortedDates ;
406+ virtuosoRef ?;
407+ search ?;
408+ project_id ?;
409+ path ?;
410+ fontSize ?;
411+ selectedHashtags ?;
412+ actions ?;
413+ llm_cost_reply ?;
414+ manualScrollRef ?;
415+ } ) {
416+ const virtuosoHeightsRef = useRef < { [ index : number ] : number } > ( { } ) ;
417+ const virtuosoScroll = useVirtuosoScrollHook ( {
418+ cacheId : `${ project_id } ${ path } ` ,
419+ initialState : { index : messages . size - 1 , offset : 0 } , // starts scrolled to the newest message.
420+ } ) ;
421+
422+ return (
423+ < Virtuoso
424+ ref = { virtuosoRef }
425+ totalCount = { sortedDates . length }
426+ itemSize = { ( el ) => {
427+ // see comment in jupyter/cell-list.tsx
428+ const h = el . getBoundingClientRect ( ) . height ;
429+ const data = el . getAttribute ( "data-item-index" ) ;
430+ if ( data != null ) {
431+ const index = parseInt ( data ) ;
432+ virtuosoHeightsRef . current [ index ] = h ;
433+ }
434+ return h ;
435+ } }
436+ itemContent = { ( index ) => {
437+ const date = sortedDates [ index ] ;
438+ const message : ChatMessageTyped | undefined = messages . get ( date ) ;
439+ if ( message == null ) {
440+ // shouldn't happen. But we should be robust to such a possibility.
441+ return < div style = { { height : "1px" } } /> ;
442+ }
443+
444+ const is_thread = isThread ( messages , message ) ;
445+ // if we search for a message, we treat all threads as unfolded
446+ const force_unfold = ! ! search ;
447+ const is_folded =
448+ ! force_unfold && isFolded ( messages , message , account_id ) ;
449+ const is_thread_body = message . get ( "reply_to" ) != null ;
450+ const h = virtuosoHeightsRef . current [ index ] ;
451+
452+ return (
453+ < div style = { { overflow : "hidden" } } >
454+ < DivTempHeight height = { h ? `${ h } px` : undefined } >
455+ < Message
456+ key = { date }
457+ index = { index }
458+ account_id = { account_id }
459+ user_map = { user_map }
460+ message = { message }
461+ project_id = { project_id }
462+ path = { path }
463+ font_size = { fontSize }
464+ selectedHashtags = { selectedHashtags }
465+ actions = { actions }
466+ is_thread = { is_thread }
467+ is_folded = { is_folded }
468+ force_unfold = { force_unfold }
469+ is_thread_body = { is_thread_body }
470+ is_prev_sender = { isPrevMessageSender (
471+ index ,
472+ sortedDates ,
473+ messages ,
474+ ) }
475+ is_next_sender = { isNextMessageSender (
476+ index ,
477+ sortedDates ,
478+ messages ,
479+ ) }
480+ show_avatar = { ! isNextMessageSender ( index , sortedDates , messages ) }
481+ mode = { mode }
482+ get_user_name = { ( account_id : string | undefined ) =>
483+ // ATTN: this also works for LLM chat bot IDs, not just account UUIDs
484+ typeof account_id === "string"
485+ ? getUserName ( user_map , account_id )
486+ : "Unknown name"
487+ }
488+ scroll_into_view = {
489+ virtuosoRef
490+ ? ( ) => virtuosoRef . current ?. scrollIntoView ( { index } )
491+ : undefined
492+ }
493+ allowReply = {
494+ messages . getIn ( [ sortedDates [ index + 1 ] , "reply_to" ] ) == null
495+ }
496+ llm_cost_reply = { llm_cost_reply }
497+ />
498+ </ DivTempHeight >
499+ </ div >
500+ ) ;
501+ } }
502+ rangeChanged = {
503+ manualScrollRef
504+ ? ( { endIndex } ) => {
505+ // manually scrolling if NOT at the bottom.
506+ manualScrollRef . current = endIndex < sortedDates . length - 1 ;
507+ }
508+ : undefined
509+ }
510+ { ...virtuosoScroll }
511+ />
512+ ) ;
513+ }
0 commit comments