diff --git a/packages/app/src/context/global-sync/event-reducer.test.ts b/packages/app/src/context/global-sync/event-reducer.test.ts index 06d536618e05..4a1f4055357b 100644 --- a/packages/app/src/context/global-sync/event-reducer.test.ts +++ b/packages/app/src/context/global-sync/event-reducer.test.ts @@ -208,7 +208,7 @@ describe("applyDirectoryEvent", () => { expect(store.sessionTotal).toBe(2) }) - test("cleans session caches when archived", () => { + test("removes an archived session from the list but keeps its caches for open tabs", () => { const message = userMessage("msg_1", "ses_1") const [store, setStore] = createStore( baseState({ @@ -235,13 +235,13 @@ describe("applyDirectoryEvent", () => { expect(store.session.map((x) => x.id)).toEqual(["ses_2"]) expect(store.sessionTotal).toBe(1) - expect(store.message.ses_1).toBeUndefined() - expect(store.part[message.id]).toBeUndefined() - expect(store.session_diff.ses_1).toBeUndefined() - expect(store.todo.ses_1).toBeUndefined() - expect(store.permission.ses_1).toBeUndefined() - expect(store.question.ses_1).toBeUndefined() - expect(store.session_status.ses_1).toBeUndefined() + expect(store.message.ses_1).toHaveLength(1) + expect(store.part[message.id]).toHaveLength(1) + expect(store.session_diff.ses_1).toHaveLength(0) + expect(store.todo.ses_1).toHaveLength(0) + expect(store.permission.ses_1).toHaveLength(0) + expect(store.question.ses_1).toHaveLength(0) + expect(store.session_status.ses_1).toEqual({ type: "busy" }) }) test("ignores an archived session absent from a passive directory store", () => { diff --git a/packages/app/src/context/global-sync/event-reducer.ts b/packages/app/src/context/global-sync/event-reducer.ts index b84d5201cf55..79de5f7c42bb 100644 --- a/packages/app/src/context/global-sync/event-reducer.ts +++ b/packages/app/src/context/global-sync/event-reducer.ts @@ -155,7 +155,7 @@ export function applyDirectoryEvent(input: { draft.splice(result.index, 1) }), ) - cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) + // Caches survive archiving so open tabs keep rendering the session. if (info.parentID) break input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) break diff --git a/packages/app/src/context/server-session.ts b/packages/app/src/context/server-session.ts index c5d98682f03c..d0cd3839254d 100644 --- a/packages/app/src/context/server-session.ts +++ b/packages/app/src/context/server-session.ts @@ -1002,7 +1002,6 @@ export function createServerSession( case "session.updated": { const info = (event.properties as { info: Session }).info remember(info) - if (info.time.archived) evict([info.id]) return } case "session.deleted": { diff --git a/packages/app/src/pages/home-session-archive.test.ts b/packages/app/src/pages/home-session-archive.test.ts index 2d04e808f46c..9ea81bebf678 100644 --- a/packages/app/src/pages/home-session-archive.test.ts +++ b/packages/app/src/pages/home-session-archive.test.ts @@ -1,24 +1,16 @@ import { expect, test } from "bun:test" -import { SESSION_TABS_REMOVED_EVENT, readSessionTabsRemovedDetail } from "@/components/titlebar-session-events" +import { SESSION_TABS_REMOVED_EVENT } from "@/components/titlebar-session-events" import { archiveHomeSession } from "./home-session-archive" -import type { ServerConnection } from "@/context/server" -const remote = "remote" as ServerConnection.Key +test("archiving a Home session updates the list without touching open tabs", async () => { + let tabsRemovedEvent = false + window.addEventListener(SESSION_TABS_REMOVED_EVENT, () => { + tabsRemovedEvent = true + }) -test("archiving a Home session removes its open titlebar tab", async () => { - let detail: ReturnType let removed = false - window.addEventListener( - SESSION_TABS_REMOVED_EVENT, - (event) => { - detail = readSessionTabsRemovedDetail(event) - }, - { once: true }, - ) - await archiveHomeSession({ - server: remote, - session: { id: "ses_1", directory: "/workspace" }, + sessionID: "ses_1", archive: async () => undefined, remove: () => { removed = true @@ -26,7 +18,7 @@ test("archiving a Home session removes its open titlebar tab", async () => { }) expect(removed).toBe(true) - expect(detail).toEqual({ server: remote, directory: "/workspace", sessionIDs: ["ses_1"] }) + expect(tabsRemovedEvent).toBe(false) }) test("reports archive failures without removing the session", async () => { @@ -35,8 +27,7 @@ test("reports archive failures without removing the session", async () => { let removed = false await archiveHomeSession({ - server: remote, - session: { id: "ses_1", directory: "/workspace" }, + sessionID: "ses_1", archive: async () => Promise.reject(failure), remove: () => { removed = true diff --git a/packages/app/src/pages/home-session-archive.ts b/packages/app/src/pages/home-session-archive.ts index bafca66e72df..3d57ee7f3a96 100644 --- a/packages/app/src/pages/home-session-archive.ts +++ b/packages/app/src/pages/home-session-archive.ts @@ -1,27 +1,13 @@ -import { notifySessionTabsRemoved } from "@/components/titlebar-session-events" -import type { ServerConnection } from "@/context/server" - -type HomeSession = { - id: string - directory: string -} - export async function archiveHomeSession(input: { - server: ServerConnection.Key - session: HomeSession + sessionID: string archive: (sessionID: string) => Promise remove: () => void onError?: (error: unknown) => void }) { await input - .archive(input.session.id) + .archive(input.sessionID) .then(() => { input.remove() - notifySessionTabsRemoved({ - server: input.server, - directory: input.session.directory, - sessionIDs: [input.session.id], - }) }) .catch((error) => input.onError?.(error)) } diff --git a/packages/app/src/pages/home/home-sessions-controller.tsx b/packages/app/src/pages/home/home-sessions-controller.tsx index 25d896393ca6..dcdd0f3c1369 100644 --- a/packages/app/src/pages/home/home-sessions-controller.tsx +++ b/packages/app/src/pages/home/home-sessions-controller.tsx @@ -211,8 +211,7 @@ export function createHomeSessionsController(home: HomeController) { const [, setStore] = ctx.sync.child(session.directory) if ((await ctx.sdk.protocol) !== "v1") return await archiveHomeSession({ - server: ServerConnection.key(conn), - session, + sessionID: session.id, archive: (sessionID) => ctx.sdk.client.session.update({ sessionID, diff --git a/packages/app/src/pages/session/session-archive.ts b/packages/app/src/pages/session/session-archive.ts index 5e1314dbd14d..c7fce8adccc5 100644 --- a/packages/app/src/pages/session/session-archive.ts +++ b/packages/app/src/pages/session/session-archive.ts @@ -1,6 +1,5 @@ import { useNavigate } from "@solidjs/router" import { produce } from "solid-js/store" -import { notifySessionTabsRemoved } from "@/components/titlebar-session-events" import { useLanguage } from "@/context/language" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" @@ -37,15 +36,12 @@ export function useSessionArchive() { navigate(`/${params.dir}/session`) } + // Archive is a data operation only — open tabs keep rendering the session. Only deletion navigates. const archive = async (sessionID: string) => { const session = sync().session.get(sessionID) if (!session) return if ((await sdk().protocol) !== "v1") return - const sessions = sync().data.session ?? [] - const index = sessions.findIndex((s) => s.id === sessionID) - const nextSession = index === -1 ? undefined : (sessions[index + 1] ?? sessions[index - 1]) - await sdk() .client.session.update({ sessionID, directory: sdk().directory, time: { archived: Date.now() } }) .then(() => { @@ -55,9 +51,6 @@ export function useSessionArchive() { if (index !== -1) draft.session.splice(index, 1) }), ) - sync().session.evict(sessionID) - navigateAfterRemoval(sessionID, session.parentID, nextSession?.id) - notifySessionTabsRemoved({ directory: sdk().directory, sessionIDs: [sessionID] }) }) .catch((err) => { showToast({