diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 83672d659da4..ca7ce3a6b3f8 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -6703,7 +6703,11 @@ function ChatViewContent(props: ChatViewProps) { )} {threadSyncPhase && !activeEnvironmentUnavailable ? ( - + ) : null}
{ - it.each([ - ["loading", "Loading messages..."], - ["syncing", "Syncing messages..."], - ] as const)("renders the %s message sync phase", (phase, label) => { - const markup = renderToStaticMarkup(); + it("renders loading immediately without participating in composer layout", () => { + const markup = renderToStaticMarkup(); expect(markup).toContain('role="status"'); - expect(markup).toContain(label); + expect(markup).toContain("Loading messages..."); + expect(markup).toContain("absolute"); + expect(markup).toContain("calc(100% + 0.5rem)"); expect(markup).not.toContain("animate-"); }); + + it("withholds the cached-thread syncing phase initially", () => { + const markup = renderToStaticMarkup(); + + expect(markup).toBe(""); + }); + + it("moves above the scroll-to-end control when it is visible", () => { + const markup = renderToStaticMarkup(); + + expect(markup).toContain("calc(100% + 2.75rem)"); + }); }); diff --git a/apps/web/src/components/chat/ThreadSyncStatusPill.tsx b/apps/web/src/components/chat/ThreadSyncStatusPill.tsx index d920a6d1953d..02bbee8d191f 100644 --- a/apps/web/src/components/chat/ThreadSyncStatusPill.tsx +++ b/apps/web/src/components/chat/ThreadSyncStatusPill.tsx @@ -1,15 +1,33 @@ import { LoaderCircleIcon } from "lucide-react"; +import { useEffect, useState } from "react"; import { threadSyncLabel, type ThreadSyncPhase } from "../../threadSync"; -export function ThreadSyncStatusPill({ phase }: { readonly phase: ThreadSyncPhase }) { +export function ThreadSyncStatusPill({ + phase, + raised, +}: { + readonly phase: ThreadSyncPhase; + readonly raised: boolean; +}) { + const [syncingVisible, setSyncingVisible] = useState(phase === "loading"); + + useEffect(() => { + if (phase !== "syncing") return; + const timeoutId = globalThis.setTimeout(() => setSyncingVisible(true), 300); + return () => globalThis.clearTimeout(timeoutId); + }, [phase]); + + if (phase === "syncing" && !syncingVisible) return null; + const label = threadSyncLabel(phase); return (
{label}