Skip to content

Commit 133ec36

Browse files
authored
Fix behaviour clicking old conversations in sidebar (#26)
1 parent 298fcb4 commit 133ec36

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

ui/src/components/Sidebar/Sidebar.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,13 @@ export function Sidebar({
479479
? location.pathname.split("/")[2]
480480
: null;
481481

482+
// Check if a conversation matches the active URL (may be local id or server remoteId)
483+
const isActive = useCallback(
484+
(conv: Conversation) =>
485+
activeConversationId === conv.id || activeConversationId === conv.remoteId,
486+
[activeConversationId]
487+
);
488+
482489
const filteredConversations = searchQuery
483490
? conversations.filter((c) => c.title.toLowerCase().includes(searchQuery.toLowerCase()))
484491
: conversations;
@@ -528,7 +535,7 @@ export function Sidebar({
528535

529536
const handleDeleteConversation = (conv: Conversation) => {
530537
deleteConversation(conv.id);
531-
if (activeConversationId === conv.id) {
538+
if (isActive(conv)) {
532539
navigate("/chat");
533540
}
534541
};
@@ -814,7 +821,7 @@ export function Sidebar({
814821
<SortablePinnedItem
815822
key={conv.id}
816823
conv={conv}
817-
isActive={activeConversationId === conv.id && isChatRoute}
824+
isActive={isActive(conv) && isChatRoute}
818825
isEditing={editingId === conv.id}
819826
editTitle={editTitle}
820827
onEditTitleChange={setEditTitle}
@@ -904,7 +911,7 @@ export function Sidebar({
904911
className={cn(
905912
"group flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-sm",
906913
"hover:bg-accent/50",
907-
activeConversationId === conv.id && isChatRoute
914+
isActive(conv) && isChatRoute
908915
? "bg-accent text-accent-foreground font-medium"
909916
: "text-foreground/80"
910917
)}
@@ -925,7 +932,7 @@ export function Sidebar({
925932
className={cn(
926933
"inline-flex items-center justify-center h-6 w-6 shrink-0 rounded-md p-0 opacity-0 transition-opacity hover:bg-muted",
927934
"group-hover:opacity-100",
928-
activeConversationId === conv.id && "opacity-100"
935+
isActive(conv) && "opacity-100"
929936
)}
930937
>
931938
<MoreHorizontal className="h-4 w-4" />
@@ -1059,7 +1066,7 @@ export function Sidebar({
10591066
className={cn(
10601067
"group flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left text-sm",
10611068
"hover:bg-accent/50",
1062-
activeConversationId === conv.id && isChatRoute
1069+
isActive(conv) && isChatRoute
10631070
? "bg-accent text-accent-foreground font-medium"
10641071
: "text-muted-foreground"
10651072
)}

ui/src/hooks/useConversationSync.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ export function useConversationSync(conversationId: string | undefined) {
9595
// triggers the save effect, but nothing actually changed — saving would bump updatedAt
9696
// and cause the conversation to jump to the top of the sidebar)
9797
const skipNextSaveRef = useRef(false);
98+
// Ref for currentConversationId so the save effect doesn't re-trigger on conversation
99+
// switch (which would consume the skipNextSaveRef before the real message-load render)
100+
const currentConversationIdRef = useRef(currentConversation?.id);
98101

99102
// Load conversation when it changes
100103
useEffect(() => {
@@ -127,11 +130,15 @@ export function useConversationSync(conversationId: string | undefined) {
127130
}
128131
}, [currentConversation?.id]); // eslint-disable-line react-hooks/exhaustive-deps
129132

130-
// Save conversation when messages change (debounced)
131-
const currentConversationId = currentConversation?.id;
133+
// Save conversation when messages change (debounced).
134+
// currentConversationId is accessed via ref so that switching conversations doesn't
135+
// trigger this effect — otherwise it fires before the message-load render and
136+
// consumes skipNextSaveRef too early, causing a spurious save that bumps updatedAt.
137+
currentConversationIdRef.current = currentConversation?.id;
132138
useEffect(() => {
133-
if (isStreaming || !currentConversationId || messages.length === 0) return;
134-
if (loadedConversationIdRef.current !== currentConversationId) return;
139+
const convId = currentConversationIdRef.current;
140+
if (isStreaming || !convId || messages.length === 0) return;
141+
if (loadedConversationIdRef.current !== convId) return;
135142

136143
// After loading a conversation, the messages store changes which triggers this effect.
137144
// Skip that first save to avoid bumping updatedAt (which reorders the sidebar).
@@ -145,15 +152,15 @@ export function useConversationSync(conversationId: string | undefined) {
145152
}
146153

147154
saveTimeoutRef.current = setTimeout(() => {
148-
updateConversation(currentConversationId, messages, selectedModels);
155+
updateConversation(currentConversationIdRef.current!, messages, selectedModels);
149156
}, 100);
150157

151158
return () => {
152159
if (saveTimeoutRef.current) {
153160
clearTimeout(saveTimeoutRef.current);
154161
}
155162
};
156-
}, [messages, isStreaming, currentConversationId, selectedModels, updateConversation]);
163+
}, [messages, isStreaming, selectedModels, updateConversation]);
157164

158165
/**
159166
* Fork a conversation, optionally up to a specific message.

0 commit comments

Comments
 (0)