From a57230b80be1c3bffab71ac021d11b02fb2fbe6c Mon Sep 17 00:00:00 2001 From: Nathan Thomassin Date: Tue, 25 Aug 2026 09:34:24 +0200 Subject: [PATCH] fix(app): drop archived sessions from home list right away (#44905) Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> --- .../global-sync/home-session-index.test.ts | 33 ++++++++++++++++++- .../context/global-sync/home-session-index.ts | 14 +++++++- .../pages/home/home-sessions-controller.tsx | 6 ++-- .../app/src/pages/session/session-archive.ts | 3 ++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/app/src/context/global-sync/home-session-index.test.ts b/packages/app/src/context/global-sync/home-session-index.test.ts index 4e40cc78eae..9b94f1de212 100644 --- a/packages/app/src/context/global-sync/home-session-index.test.ts +++ b/packages/app/src/context/global-sync/home-session-index.test.ts @@ -1,8 +1,10 @@ import { describe, expect, test } from "bun:test" -import type { SessionV2Info } from "@opencode-ai/sdk/v2/client" +import { QueryClient } from "@tanstack/solid-query" +import type { Session, SessionV2Info } from "@opencode-ai/sdk/v2/client" import { applyHomeSessionEvent, appendHomeSessionEvent, + createHomeSessionIndexCache, HOME_V2_SESSION_PAGE_LIMIT, loadHomeSessionIndex, homeSessionIndexSessions, @@ -151,4 +153,33 @@ describe("Home V2 session index", () => { expect(homeSessionIndexRefresh("global.disposed", true).refetch).toBe(true) expect(homeSessionIndexRefresh("session.next.moved", true).refetch).toBe(true) }) + + test("removes a session from the loaded Home index", () => { + const queryClient = new QueryClient() + const cache = createHomeSessionIndexCache(queryClient, "server") + const sessions = [ + { id: "a", time: { created: 1, updated: 1 } }, + { id: "b", time: { created: 1, updated: 1 } }, + ] as Session[] + queryClient.setQueryData(cache.indexKey, { sessions, eventSequence: 0 }) + + cache.remove("a") + + const index = queryClient.getQueryData<{ sessions: Session[] }>(cache.indexKey) + expect(index?.sessions.map((item) => item.id)).toEqual(["b"]) + }) + + test("keeps the session out of the Home list when the index is not mounted", () => { + const queryClient = new QueryClient() + const cache = createHomeSessionIndexCache(queryClient, "server") + const sessions = [ + { id: "a", time: { created: 1, updated: 1 } }, + { id: "b", time: { created: 1, updated: 1 } }, + ] as Session[] + + cache.remove("a") + + expect(queryClient.getQueryData(cache.indexKey)).toBeUndefined() + expect(cache.sessions({ sessions, eventSequence: 0 }, undefined).map((item) => item.id)).toEqual(["b"]) + }) }) diff --git a/packages/app/src/context/global-sync/home-session-index.ts b/packages/app/src/context/global-sync/home-session-index.ts index 03a085e34d5..781c39c4501 100644 --- a/packages/app/src/context/global-sync/home-session-index.ts +++ b/packages/app/src/context/global-sync/home-session-index.ts @@ -85,6 +85,7 @@ export function createHomeSessionIndexCache(queryClient: QueryClient, server: st const indexKey = homeSessionIndexKey(server) const eventsKey = homeSessionEventsKey(server) let connected = false + const removed = new Set() return { indexKey, @@ -97,7 +98,8 @@ export function createHomeSessionIndexCache(queryClient: QueryClient, server: st queryClient.setQueryData(eventsKey, (current) => trimHomeSessionEvents(current, sequence)) }, sessions(index: HomeSessionIndex | undefined, events: HomeSessionEvents | undefined) { - return homeSessionIndexSessions(index, events) + const sessions = homeSessionIndexSessions(index, events) + return removed.size === 0 ? sessions : sessions.filter((session) => !removed.has(session.id)) }, apply(event: HomeSessionEvent) { if (!queryClient.getQueryState(indexKey)) return @@ -116,6 +118,16 @@ export function createHomeSessionIndexCache(queryClient: QueryClient, server: st } queryClient.setQueryData(eventsKey, { sequence: next.sequence, entries: [] }) }, + remove(sessionID: string) { + removed.add(sessionID) + if (!queryClient.getQueryState(indexKey)) return + queryClient.setQueryData(indexKey, (index) => { + if (!index) return index + const at = index.sessions.findIndex((session) => session.id === sessionID) + if (at === -1) return index + return { ...index, sessions: index.sessions.toSpliced(at, 1) } + }) + }, refresh(event: Event["type"]) { const result = homeSessionIndexRefresh(event, connected) connected = result.connected diff --git a/packages/app/src/pages/home/home-sessions-controller.tsx b/packages/app/src/pages/home/home-sessions-controller.tsx index 25d896393ca..f306f208cc8 100644 --- a/packages/app/src/pages/home/home-sessions-controller.tsx +++ b/packages/app/src/pages/home/home-sessions-controller.tsx @@ -219,13 +219,15 @@ export function createHomeSessionsController(home: HomeController) { directory: session.directory, time: { archived: Date.now() }, }), - remove: () => + remove: () => { setStore( produce((draft) => { const match = Binary.search(draft.session, session.id, (item) => item.id) if (match.found) draft.session.splice(match.index, 1) }), - ), + ) + homeSessions().remove(session.id) + }, onError: (cause) => showToast({ title: language.t("common.requestFailed"), diff --git a/packages/app/src/pages/session/session-archive.ts b/packages/app/src/pages/session/session-archive.ts index 5e1314dbd14..39688695395 100644 --- a/packages/app/src/pages/session/session-archive.ts +++ b/packages/app/src/pages/session/session-archive.ts @@ -3,6 +3,7 @@ import { produce } from "solid-js/store" import { notifySessionTabsRemoved } from "@/components/titlebar-session-events" import { useLanguage } from "@/context/language" import { useSDK } from "@/context/sdk" +import { useServerSync } from "@/context/server-sync" import { useSync } from "@/context/sync" import { useTabs } from "@/context/tabs" import { errorMessage } from "@/pages/layout/helpers" @@ -15,6 +16,7 @@ export function useSessionArchive() { const navigate = useNavigate() const sdk = useSDK() const sync = useSync() + const serverSync = useServerSync() const tabs = useTabs() const { params } = useSessionKey() @@ -56,6 +58,7 @@ export function useSessionArchive() { }), ) sync().session.evict(sessionID) + serverSync().homeSessions.remove(sessionID) navigateAfterRemoval(sessionID, session.parentID, nextSession?.id) notifySessionTabsRemoved({ directory: sdk().directory, sessionIDs: [sessionID] }) })