mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-16 11:20:10 +01:00
Autoscroll to end of chat fix (#201)
bug fix for autoscrolling on message send/recieve
This commit is contained in:
parent
4a67cf2198
commit
b01e49bb3c
@ -1,66 +1,56 @@
|
||||
import { useEffect, useRef, memo } from "react";
|
||||
import { memo, forwardRef } from "react";
|
||||
import { AlertTriangle } from "react-feather";
|
||||
import Jazzicon from "../../../../UserIcon";
|
||||
import renderMarkdown from "../../../../../utils/chat/markdown";
|
||||
import { userFromStorage } from "../../../../../utils/request";
|
||||
import Citations from "../Citation";
|
||||
|
||||
function HistoricalMessage({
|
||||
message,
|
||||
role,
|
||||
workspace,
|
||||
sources = [],
|
||||
error = false,
|
||||
}) {
|
||||
const replyRef = useRef(null);
|
||||
useEffect(() => {
|
||||
if (replyRef.current)
|
||||
replyRef.current.scrollIntoView({ behavior: "smooth", block: "end" });
|
||||
}, [replyRef.current]);
|
||||
|
||||
if (role === "user") {
|
||||
return (
|
||||
<div className="flex justify-end mb-4 items-start">
|
||||
<div className="mr-2 py-1 px-4 w-fit md:max-w-[75%] bg-slate-200 dark:bg-amber-800 rounded-b-2xl rounded-tl-2xl rounded-tr-sm">
|
||||
<span
|
||||
className={`inline-block p-2 rounded-lg whitespace-pre-line text-slate-800 dark:text-slate-200 font-[500] md:font-semibold text-sm md:text-base`}
|
||||
>
|
||||
{message}
|
||||
</span>
|
||||
const HistoricalMessage = forwardRef(
|
||||
({ message, role, workspace, sources = [], error = false }, ref) => {
|
||||
if (role === "user") {
|
||||
return (
|
||||
<div className="flex justify-end mb-4 items-start">
|
||||
<div className="mr-2 py-1 px-4 w-fit md:max-w-[75%] bg-slate-200 dark:bg-amber-800 rounded-b-2xl rounded-tl-2xl rounded-tr-sm">
|
||||
<span
|
||||
className={`inline-block p-2 rounded-lg whitespace-pre-line text-slate-800 dark:text-slate-200 font-[500] md:font-semibold text-sm md:text-base`}
|
||||
>
|
||||
{message}
|
||||
</span>
|
||||
</div>
|
||||
<Jazzicon size={30} user={{ uid: userFromStorage()?.username }} />
|
||||
</div>
|
||||
<Jazzicon size={30} user={{ uid: userFromStorage()?.username }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex justify-start mb-4 items-end">
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<span
|
||||
className={`inline-block p-2 rounded-lg bg-red-50 text-red-500`}
|
||||
>
|
||||
<AlertTriangle className="h-4 w-4 mb-1 inline-block" /> Could not
|
||||
respond to message.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex justify-start mb-4 items-end">
|
||||
<div ref={ref} className="flex justify-start items-end mb-4">
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<div className="ml-2 py-3 px-4 overflow-x-scroll w-fit md:max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<span
|
||||
className={`inline-block p-2 rounded-lg bg-red-50 text-red-500`}
|
||||
>
|
||||
<AlertTriangle className="h-4 w-4 mb-1 inline-block" /> Could not
|
||||
respond to message.
|
||||
</span>
|
||||
className="no-scroll whitespace-pre-line text-slate-800 dark:text-slate-200 font-[500] md:font-semibold text-sm md:text-base flex flex-col gap-y-1"
|
||||
dangerouslySetInnerHTML={{ __html: renderMarkdown(message) }}
|
||||
/>
|
||||
<Citations sources={sources} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={replyRef} className="flex justify-start items-end mb-4">
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 py-3 px-4 overflow-x-scroll w-fit md:max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<span
|
||||
className="no-scroll whitespace-pre-line text-slate-800 dark:text-slate-200 font-[500] md:font-semibold text-sm md:text-base flex flex-col gap-y-1"
|
||||
dangerouslySetInnerHTML={{ __html: renderMarkdown(message) }}
|
||||
/>
|
||||
<Citations sources={sources} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default memo(HistoricalMessage);
|
||||
|
@ -1,71 +1,61 @@
|
||||
import { memo, useEffect, useRef } from "react";
|
||||
import { forwardRef, memo } from "react";
|
||||
import { AlertTriangle } from "react-feather";
|
||||
import Jazzicon from "../../../../UserIcon";
|
||||
import renderMarkdown from "../../../../../utils/chat/markdown";
|
||||
import Citations from "../Citation";
|
||||
|
||||
function PromptReply({
|
||||
uuid,
|
||||
reply,
|
||||
pending,
|
||||
error,
|
||||
workspace,
|
||||
sources = [],
|
||||
closed = true,
|
||||
}) {
|
||||
const replyRef = useRef(null);
|
||||
useEffect(() => {
|
||||
if (replyRef.current)
|
||||
replyRef.current.scrollIntoView({ behavior: "smooth", block: "end" });
|
||||
}, [replyRef.current]);
|
||||
|
||||
if (!reply && !sources.length === 0 && !pending && !error) return null;
|
||||
if (pending) {
|
||||
return (
|
||||
<div className="chat__message flex justify-start mb-4 items-end">
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 pt-2 px-6 w-fit md:max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<span className={`inline-block p-2`}>
|
||||
<div className="dot-falling"></div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="chat__message flex justify-start mb-4 items-center">
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 py-3 px-4 rounded-br-3xl rounded-tr-3xl rounded-tl-xl text-slate-100 ">
|
||||
<div className="bg-red-50 text-red-500 rounded-lg w-fit flex flex-col p-2">
|
||||
<span className={`inline-block`}>
|
||||
<AlertTriangle className="h-4 w-4 mb-1 inline-block" /> Could not
|
||||
respond to message.
|
||||
const PromptReply = forwardRef(
|
||||
(
|
||||
{ uuid, reply, pending, error, workspace, sources = [], closed = true },
|
||||
ref
|
||||
) => {
|
||||
if (!reply && !sources.length === 0 && !pending && !error) return null;
|
||||
if (pending) {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className="chat__message flex justify-start mb-4 items-end"
|
||||
>
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 pt-2 px-6 w-fit md:max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<span className={`inline-block p-2`}>
|
||||
<div className="dot-falling"></div>
|
||||
</span>
|
||||
<span className="text-xs">Reason: {error || "unknown"}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="chat__message flex justify-start mb-4 items-center">
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 py-3 px-4 rounded-br-3xl rounded-tr-3xl rounded-tl-xl text-slate-100 ">
|
||||
<div className="bg-red-50 text-red-500 rounded-lg w-fit flex flex-col p-2">
|
||||
<span className={`inline-block`}>
|
||||
<AlertTriangle className="h-4 w-4 mb-1 inline-block" /> Could
|
||||
not respond to message.
|
||||
</span>
|
||||
<span className="text-xs">Reason: {error || "unknown"}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={uuid} ref={ref} className="mb-4 flex justify-start items-end">
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 py-3 px-4 overflow-x-scroll w-fit md:max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<span
|
||||
className="whitespace-pre-line text-slate-800 dark:text-slate-200 flex flex-col gap-y-1 font-[500] md:font-semibold text-sm md:text-base"
|
||||
dangerouslySetInnerHTML={{ __html: renderMarkdown(reply) }}
|
||||
/>
|
||||
<Citations sources={sources} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={uuid}
|
||||
ref={replyRef}
|
||||
className="mb-4 flex justify-start items-end"
|
||||
>
|
||||
<Jazzicon size={30} user={{ uid: workspace.slug }} />
|
||||
<div className="ml-2 py-3 px-4 overflow-x-scroll w-fit md:max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-t-2xl rounded-br-2xl rounded-bl-sm">
|
||||
<span
|
||||
className="whitespace-pre-line text-slate-800 dark:text-slate-200 flex flex-col gap-y-1 font-[500] md:font-semibold text-sm md:text-base"
|
||||
dangerouslySetInnerHTML={{ __html: renderMarkdown(reply) }}
|
||||
/>
|
||||
<Citations sources={sources} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default memo(PromptReply);
|
||||
|
@ -1,8 +1,19 @@
|
||||
import { Frown } from "react-feather";
|
||||
import HistoricalMessage from "./HistoricalMessage";
|
||||
import PromptReply from "./PromptReply";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export default function ChatHistory({ history = [], workspace }) {
|
||||
const replyRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (replyRef.current) {
|
||||
setTimeout(() => {
|
||||
replyRef.current.scrollIntoView({ behavior: "smooth", block: "end" });
|
||||
}, 700);
|
||||
}
|
||||
}, [history]);
|
||||
|
||||
if (history.length === 0) {
|
||||
return (
|
||||
<div className="flex flex-col h-[89%] md:mt-0 pb-5 w-full justify-center items-center">
|
||||
@ -22,48 +33,37 @@ export default function ChatHistory({ history = [], workspace }) {
|
||||
className="h-[89%] pb-[100px] md:pt-[50px] md:pt-0 md:pb-5 mx-2 md:mx-0 overflow-y-scroll flex flex-col justify-start no-scroll"
|
||||
id="chat-history"
|
||||
>
|
||||
{history.map(
|
||||
(
|
||||
{
|
||||
uuid = null,
|
||||
content,
|
||||
sources = [],
|
||||
role,
|
||||
closed = true,
|
||||
pending = false,
|
||||
error = false,
|
||||
animate = false,
|
||||
},
|
||||
index
|
||||
) => {
|
||||
const isLastBotReply =
|
||||
index === history.length - 1 && role === "assistant";
|
||||
if (isLastBotReply && animate) {
|
||||
return (
|
||||
<PromptReply
|
||||
key={uuid}
|
||||
uuid={uuid}
|
||||
reply={content}
|
||||
pending={pending}
|
||||
sources={sources}
|
||||
error={error}
|
||||
workspace={workspace}
|
||||
closed={closed}
|
||||
/>
|
||||
);
|
||||
}
|
||||
{history.map((props, index) => {
|
||||
const isLastMessage = index === history.length - 1;
|
||||
|
||||
if (props.role === "assistant" && props.animate) {
|
||||
return (
|
||||
<HistoricalMessage
|
||||
key={index}
|
||||
message={content}
|
||||
role={role}
|
||||
<PromptReply
|
||||
key={props.uuid}
|
||||
ref={isLastMessage ? replyRef : null}
|
||||
uuid={props.uuid}
|
||||
reply={props.content}
|
||||
pending={props.pending}
|
||||
sources={props.sources}
|
||||
error={props.error}
|
||||
workspace={workspace}
|
||||
sources={sources}
|
||||
error={error}
|
||||
closed={props.closed}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
|
||||
return (
|
||||
<HistoricalMessage
|
||||
key={index}
|
||||
ref={isLastMessage ? replyRef : null}
|
||||
message={props.content}
|
||||
role={props.role}
|
||||
workspace={workspace}
|
||||
sources={props.sources}
|
||||
error={props.error}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user