mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
feat(frontend/builder): add typing indicator animation to builder chat panel
Shows three bouncing dots in an assistant-style bubble while waiting for the first response token (status submitted, no assistant text yet). Disappears once streaming begins and text appears.
This commit is contained in:
@@ -96,6 +96,7 @@ export function BuilderChatPanel({ className, isGraphLoaded }: Props) {
|
||||
onRetry={retrySession}
|
||||
seedMessageId={seedMessageId}
|
||||
messagesEndRef={messagesEndRef}
|
||||
isStreaming={isStreaming}
|
||||
/>
|
||||
|
||||
<PanelInput
|
||||
@@ -177,6 +178,7 @@ interface MessageListProps {
|
||||
onRetry: () => void;
|
||||
seedMessageId: string | null;
|
||||
messagesEndRef: React.RefObject<HTMLDivElement>;
|
||||
isStreaming: boolean;
|
||||
}
|
||||
|
||||
function MessageList({
|
||||
@@ -191,11 +193,15 @@ function MessageList({
|
||||
onRetry,
|
||||
seedMessageId,
|
||||
messagesEndRef,
|
||||
isStreaming,
|
||||
}: MessageListProps) {
|
||||
const visibleMessages = messages.filter(
|
||||
(msg) =>
|
||||
msg.id !== seedMessageId && Boolean(extractTextFromParts(msg.parts)),
|
||||
);
|
||||
const lastVisibleRole = visibleMessages.at(-1)?.role;
|
||||
const showTypingIndicator =
|
||||
isStreaming && (!lastVisibleRole || lastVisibleRole === "user");
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -273,6 +279,20 @@ function MessageList({
|
||||
>
|
||||
{msg.role === "assistant" ? (
|
||||
<ReactMarkdown
|
||||
allowedElements={[
|
||||
"p",
|
||||
"strong",
|
||||
"em",
|
||||
"code",
|
||||
"pre",
|
||||
"ul",
|
||||
"ol",
|
||||
"li",
|
||||
"blockquote",
|
||||
"a",
|
||||
"br",
|
||||
]}
|
||||
unwrapDisallowed
|
||||
components={{
|
||||
p: ({ children }) => (
|
||||
<p className="mb-1 last:mb-0">{children}</p>
|
||||
@@ -287,16 +307,20 @@ function MessageList({
|
||||
{children}
|
||||
</pre>
|
||||
),
|
||||
a: ({ href, children }) => (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline hover:no-underline"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
a: ({ href, children }) => {
|
||||
const safeHref =
|
||||
href && /^https?:\/\//i.test(href) ? href : undefined;
|
||||
return (
|
||||
<a
|
||||
href={safeHref}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline hover:no-underline"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{textParts}
|
||||
@@ -308,6 +332,8 @@ function MessageList({
|
||||
);
|
||||
})}
|
||||
|
||||
{showTypingIndicator && <TypingIndicator />}
|
||||
|
||||
{parsedActions.length > 0 && (
|
||||
<ActionList
|
||||
parsedActions={parsedActions}
|
||||
@@ -445,3 +471,13 @@ function PanelInput({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TypingIndicator() {
|
||||
return (
|
||||
<div className="flex max-w-[85%] items-center gap-1 rounded-lg bg-slate-100 px-3 py-3">
|
||||
<span className="h-2 w-2 animate-bounce rounded-full bg-slate-400 [animation-delay:-0.3s]" />
|
||||
<span className="h-2 w-2 animate-bounce rounded-full bg-slate-400 [animation-delay:-0.15s]" />
|
||||
<span className="h-2 w-2 animate-bounce rounded-full bg-slate-400" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user