(null);
const setRefs = useCallback(
(element: HTMLDivElement | null) => {
containerRef.current = element;
if (typeof ref === 'function') {
ref(element);
} else if (ref) {
ref.current = element;
}
},
[ref],
);
const handleScroll = () => {
if (!containerRef.current) {
return;
}
const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
setShowJumpToBottom(distanceFromBottom > 50);
};
const scrollToBottom = () => {
if (!containerRef.current) {
return;
}
containerRef.current.scrollTo({
top: containerRef.current.scrollHeight,
behavior: 'smooth',
});
};
useEffect(() => {
const container = containerRef.current;
if (container) {
container.addEventListener('scroll', handleScroll);
return () => container.removeEventListener('scroll', handleScroll);
}
return undefined;
}, []);
useEffect(() => {
if (!showJumpToBottom) {
scrollToBottom();
}
}, [messages, showJumpToBottom]);
// Get the last user response before a given message, or null if there is
// no user response between this and the last user message.
const getLastUserResponse = (index: number) => {
for (let i = index - 1; i >= 0; i--) {
if (messages[i].category === USER_RESPONSE_CATEGORY) {
return messages[i];
}
if (messages[i].role === 'user') {
return null;
}
}
return null;
};
// Return whether the app summary at index is the last for the associated user response.
const isLastAppSummary = (index: number) => {
let lastIndex = -1;
for (let i = index; i < messages.length; i++) {
const { category } = messages[i];
if (category === USER_RESPONSE_CATEGORY) {
return lastIndex === index;
}
if (category === APP_SUMMARY_CATEGORY) {
lastIndex = i;
}
}
return lastIndex === index;
};
const renderMessage = (message: Message, index: number) => {
const { role, repositoryId } = message;
const isUserMessage = role === 'user';
const isFirst = index === 0;
const isLast = index === messages.length - 1;
if (!isUserMessage && message.category && message.category !== USER_RESPONSE_CATEGORY) {
const lastUserResponse = getLastUserResponse(index);
const showDetails = !lastUserResponse || showDetailMessageIds.includes(lastUserResponse.id);
if (message.category === APP_SUMMARY_CATEGORY) {
// The default view only shows the last app summary for each user response.
if (!isLastAppSummary(index) && !showDetails) {
return null;
}
return renderAppSummary(message, index);
}
if (!showDetails) {
return null;
}
}
return (
}
>
{isUserMessage && (
)}
{!isUserMessage && message.category === 'UserResponse' && showDetailMessageIds.includes(message.id) && (
)}
{!isUserMessage && message.category === 'UserResponse' && !showDetailMessageIds.includes(message.id) && (
)}
{repositoryId && (
)}
);
};
return (
{messages.length > 0 ? messages.map(renderMessage) : null}
{hasPendingMessage && (
{pendingMessageStatus ? `${pendingMessageStatus}...` : ''}
)}
);
},
);