From f5025c3684bf1e073801436a6d3d9bdca5986e39 Mon Sep 17 00:00:00 2001 From: Ida Date: Wed, 27 May 2026 10:25:09 +0200 Subject: [PATCH] feat: New Chat, moved new chat button, fixed reloading animation to be more user friendly --- src/components/UnifiedDataBar/ChatsTab.tsx | 78 ++++++++++++++----- .../UnifiedDataBar/UnifiedDataBar.tsx | 6 +- src/pages/views/workspace/WorkspacePage.tsx | 34 +++++++- 3 files changed, 92 insertions(+), 26 deletions(-) diff --git a/src/components/UnifiedDataBar/ChatsTab.tsx b/src/components/UnifiedDataBar/ChatsTab.tsx index 86e474e..5599615 100644 --- a/src/components/UnifiedDataBar/ChatsTab.tsx +++ b/src/components/UnifiedDataBar/ChatsTab.tsx @@ -29,7 +29,7 @@ interface ChatsTabProps { onSelectChat?: (chatId: string, featureInstanceId: string) => void; onDragStart?: (chatId: string, event: React.DragEvent) => void; activeWorkflowId?: string; - onCreateNew?: () => void; + chatListRefreshKey?: number; onRenameChat?: (chatId: string, newName: string) => void | Promise; onDeleteChat?: (chatId: string) => void | Promise; } @@ -72,7 +72,7 @@ const ChatsTab: React.FC = ({ context, onSelectChat, onDragStart, activeWorkflowId, - onCreateNew, + chatListRefreshKey, onRenameChat, onDeleteChat, }) => { @@ -82,13 +82,14 @@ const ChatsTab: React.FC = ({ context, const [search, setSearch] = useState(''); const [filter, setFilter] = useState('active'); const [expandedGroups, setExpandedGroups] = useState>(new Set()); - const [loading, setLoading] = useState(true); + const [hasLoadedOnce, setHasLoadedOnce] = useState(false); const [editingId, setEditingId] = useState(null); const [editName, setEditName] = useState(''); const renameInputRef = useRef(null); + const groupsRef = useRef(groups); + groupsRef.current = groups; const _loadChats = useCallback(async (serverSearch?: string) => { - setLoading(true); try { const params: Record = { includeArchived: true }; if (serverSearch) params.search = serverSearch; @@ -140,7 +141,7 @@ const ChatsTab: React.FC = ({ context, } catch (err) { console.error('Failed to load chats:', err); } finally { - setLoading(false); + setHasLoadedOnce(true); } }, [context.instanceId, t]); @@ -163,6 +164,12 @@ const ChatsTab: React.FC = ({ context, } }, [activeWorkflowId]); + useEffect(() => { + if (chatListRefreshKey) { + _loadChats(); + } + }, [chatListRefreshKey, _loadChats]); + useEffect(() => { if (editingId && renameInputRef.current) { renameInputRef.current.focus(); @@ -188,8 +195,18 @@ const ChatsTab: React.FC = ({ context, const trimmed = editName.trim(); setEditingId(null); if (!trimmed || !onRenameChat) return; - await onRenameChat(chatId, trimmed); - _loadChats(); + const prev = groupsRef.current; + setGroups(gs => gs.map(g => ({ + ...g, + chats: g.chats.map(c => (c.id === chatId ? { ...c, label: trimmed } : c)), + }))); + try { + await onRenameChat(chatId, trimmed); + _loadChats(); + } catch (err) { + console.error('Failed to rename chat:', err); + setGroups(prev); + } }; const _handleRenameKeyDown = (e: React.KeyboardEvent, chatId: string) => { @@ -201,23 +218,41 @@ const ChatsTab: React.FC = ({ context, } }; + const _setChatStatus = useCallback((chatId: string, status: string) => { + setGroups(gs => gs.map(g => ({ + ...g, + chats: g.chats.map(c => (c.id === chatId ? { ...c, status } : c)), + }))); + }, []); + + const _removeChat = useCallback((chatId: string) => { + setGroups(gs => gs.map(g => ({ + ...g, + chats: g.chats.filter(c => c.id !== chatId), + })).filter(g => g.chats.length > 0)); + }, []); + const _archiveChat = useCallback(async (chatId: string) => { + const prev = groupsRef.current; + _setChatStatus(chatId, 'archived'); try { await api.patch(`/api/workspace/${context.instanceId}/workflows/${chatId}`, { status: 'archived' }); - _loadChats(); } catch (err) { console.error('Failed to archive chat:', err); + setGroups(prev); } - }, [context.instanceId, _loadChats]); + }, [context.instanceId, _setChatStatus]); const _restoreChat = useCallback(async (chatId: string) => { + const prev = groupsRef.current; + _setChatStatus(chatId, 'active'); try { await api.patch(`/api/workspace/${context.instanceId}/workflows/${chatId}`, { status: 'active' }); - _loadChats(); } catch (err) { console.error('Failed to restore chat:', err); + setGroups(prev); } - }, [context.instanceId, _loadChats]); + }, [context.instanceId, _setChatStatus]); const _isArchived = (chat: ChatItem) => chat.status === 'archived'; @@ -311,7 +346,17 @@ const ChatsTab: React.FC = ({ context, {onDeleteChat && ( - )} +
+ + +
{_leftPanelBody} @@ -604,7 +629,10 @@ export const WorkspacePage: React.FC = ({ persistentInstance >
{t('Workspace')} - +
+ + +
{_leftPanelBody}