From 2c4b40893cdebe6092b3aedb80b10e717c0fc81e Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Sun, 12 Jul 2026 02:02:42 +0300 Subject: [PATCH] fix(sidebar): keep recent project ids referentially stable --- .../src/components/session/SessionSidebar.tsx | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/ui/src/components/session/SessionSidebar.tsx b/packages/ui/src/components/session/SessionSidebar.tsx index 86813fe4..026a3fad 100644 --- a/packages/ui/src/components/session/SessionSidebar.tsx +++ b/packages/ui/src/components/session/SessionSidebar.tsx @@ -1037,25 +1037,43 @@ export const SessionSidebar: React.FC = ({ const projectSortOrder = useSessionDisplayStore((state) => state.projectSortOrder); const manualProjectOrder = useProjectsStore((state) => state.manualProjectOrder); + const recentProjectIdsRef = React.useRef>(new Set()); const recentProjectIds = React.useMemo(() => { const recentSessions = deriveRecentSessions(sessions); - if (recentSessions.length === 0) return new Set(); - - const pathToId = new Map(); - for (const project of normalizedProjects) { - if (project.normalizedPath) { - pathToId.set(project.normalizedPath, project.id); - } - } - const ids = new Set(); - for (const session of recentSessions) { - const directory = normalizePath((session as Session & { directory?: string | null }).directory ?? null); - if (directory) { - const projectId = pathToId.get(directory); - if (projectId) ids.add(projectId); + + if (recentSessions.length > 0) { + const pathToId = new Map(); + for (const project of normalizedProjects) { + if (project.normalizedPath) { + pathToId.set(project.normalizedPath, project.id); + } + } + + for (const session of recentSessions) { + const directory = normalizePath((session as Session & { directory?: string | null }).directory ?? null); + if (directory) { + const projectId = pathToId.get(directory); + if (projectId) ids.add(projectId); + } } } + + // Sessions update on every SSE event; keep the previous Set reference when + // membership is unchanged so sortedProjects (and the sidebar sections built + // from it) do not recompute on every streaming event. + const previous = recentProjectIdsRef.current; + if (previous.size === ids.size) { + let unchanged = true; + for (const id of ids) { + if (!previous.has(id)) { + unchanged = false; + break; + } + } + if (unchanged) return previous; + } + recentProjectIdsRef.current = ids; return ids; }, [sessions, normalizedProjects]);