From 6f998480bc7a312080d0a0c7778ac2b2afa9fa59 Mon Sep 17 00:00:00 2001 From: liangxu Date: Fri, 10 Jul 2026 22:42:41 +0800 Subject: [PATCH] feat(canvas): show loading state while agent history loads Track agent history loading in the workspace and render a spinner with a localized "loading conversation history" message in the assistant feed, so the empty state no longer flashes before history resolves. Co-Authored-By: Claude Opus 4.8 (1M context) --- frontend/src/i18n/locales/en-US.json | 1 + frontend/src/i18n/locales/zh-CN.json | 1 + .../src/ui/pages/CanvasWorkspace/index.tsx | 20 +++++++++++++++++-- frontend/src/ui/styles.css | 18 +++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/frontend/src/i18n/locales/en-US.json b/frontend/src/i18n/locales/en-US.json index c4f2959..4e010a9 100644 --- a/frontend/src/i18n/locales/en-US.json +++ b/frontend/src/i18n/locales/en-US.json @@ -341,6 +341,7 @@ "conversation": "Chat", "newChat": "New chat", "conversationHistory": "History", + "loadingConversationHistory": "Loading conversation history...", "scrollToLatest": "Scroll to latest", "searchConversationPlaceholder": "Search conversations", "deleteConversation": "Delete conversation", diff --git a/frontend/src/i18n/locales/zh-CN.json b/frontend/src/i18n/locales/zh-CN.json index 23e2d17..a840fcf 100644 --- a/frontend/src/i18n/locales/zh-CN.json +++ b/frontend/src/i18n/locales/zh-CN.json @@ -341,6 +341,7 @@ "conversation": "对话", "newChat": "新对话", "conversationHistory": "历史对话", + "loadingConversationHistory": "正在加载历史对话...", "scrollToLatest": "回到底部", "searchConversationPlaceholder": "请输入搜索关键词", "deleteConversation": "删除对话", diff --git a/frontend/src/ui/pages/CanvasWorkspace/index.tsx b/frontend/src/ui/pages/CanvasWorkspace/index.tsx index 54ad83a..33bbe22 100644 --- a/frontend/src/ui/pages/CanvasWorkspace/index.tsx +++ b/frontend/src/ui/pages/CanvasWorkspace/index.tsx @@ -575,6 +575,7 @@ export function CanvasWorkspace({ projectId, shareAccess = ownerWorkspaceAccess const { project, setProject, projectRef, viewport, setViewport, viewportRef, nodes, setNodes, nodesRef, applyProjectDocument } = useCanvasDocument(); const { selectedId, selectedIds, setSelectedIds, selectedNodes, selectedNode, selectOnlyNode, selectNodes, toggleNodeSelection } = useCanvasSelection(nodes); const [messages, setMessages] = useState([]); + const [agentHistoryLoading, setAgentHistoryLoading] = useState(canViewChat); const [prompt, setPrompt] = useState(""); const [agentStarterConfig, setAgentStarterConfig] = useState(() => defaultAgentStarterConfig(t)); const [agentThreads, setAgentThreads] = useState([]); @@ -901,17 +902,20 @@ export function CanvasWorkspace({ projectId, shareAccess = ownerWorkspaceAccess useEffect(() => { selectedAgentThreadIdRef.current = null; setSelectedAgentThreadId(null); + setAgentHistoryLoading(canViewChat); setAgentThreads([]); setAgentHistorySearch(""); setAgentHistoryOpen(false); autoScrollAgentFeedRef.current = false; - }, [projectId]); + }, [canViewChat, projectId]); useEffect(() => { if (agentHistoryOpen) void loadAgentThreads(); }, [agentHistoryOpen, loadAgentThreads]); useEffect(() => { + let active = true; + setAgentHistoryLoading(canViewChat); designGateway .getProject(projectId) .then(({ project: nextProject }) => { @@ -961,7 +965,13 @@ export function CanvasWorkspace({ projectId, shareAccess = ownerWorkspaceAccess return; } setError(toUserMessageText(err, "generateError")); + }) + .finally(() => { + if (active) setAgentHistoryLoading(false); }); + return () => { + active = false; + }; }, [applyProject, canViewChat, projectId, startProjectEvents]); useEffect(() => { @@ -2649,6 +2659,7 @@ export function CanvasWorkspace({ projectId, shareAccess = ownerWorkspaceAccess autoScrollAgentFeedRef.current = false; selectedAgentThreadIdRef.current = newAgentConversationId; setSelectedAgentThreadId(newAgentConversationId); + setAgentHistoryLoading(false); setAgentHistoryOpen(false); setPrompt(""); setMessages([]); @@ -4124,7 +4135,12 @@ export function CanvasWorkspace({ projectId, shareAccess = ownerWorkspaceAccess
- {!hasCurrentConversation && !agentTimelineActive ? ( + {agentHistoryLoading ? ( +
+
+ ) : !hasCurrentConversation && !agentTimelineActive ? ( ) : ( diff --git a/frontend/src/ui/styles.css b/frontend/src/ui/styles.css index 1bc9854..f8d16b2 100644 --- a/frontend/src/ui/styles.css +++ b/frontend/src/ui/styles.css @@ -3789,6 +3789,24 @@ button:disabled { background: #dfe0e2; } +.assistant-history-loading { + width: 100%; + min-height: 100%; + flex: 1 0 auto; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; + color: #8a9099; + font-size: 13px; + line-height: 20px; +} + +.assistant-history-loading svg { + color: #646a73; +} + .assistant-scroll-to-end { position: absolute; inset-inline: 0;