diff --git a/packages/tui/src/component/session-tabs.tsx b/packages/tui/src/component/session-tabs.tsx index 6c9c95eceb..3d2d979bbb 100644 --- a/packages/tui/src/component/session-tabs.tsx +++ b/packages/tui/src/component/session-tabs.tsx @@ -6,6 +6,7 @@ import { useSessionTabs } from "../context/session-tabs" import { useTheme, useThemes } from "../context/theme" import { adaptiveSessionTabLayout, + NEW_SESSION_TAB_TITLE, sessionTabComplete, seedSessionTabMotion, sessionTabOverflowWidth, @@ -36,7 +37,7 @@ export type SessionTabsController = Pick { const next = title() if (next === previous) return next + if (previous === NEW_SESSION_TAB_TITLE) { + setOutgoingTitle(undefined) + wipe.jump({ front: 1 }) + return next + } setOutgoingTitle(previous) wipe.jump({ front: 0 }) wipe.animate({ front: 1 }) diff --git a/packages/tui/src/context/session-tabs-model.ts b/packages/tui/src/context/session-tabs-model.ts index 0434da7922..dcf1a356d6 100644 --- a/packages/tui/src/context/session-tabs-model.ts +++ b/packages/tui/src/context/session-tabs-model.ts @@ -5,6 +5,8 @@ export type SessionTab = { export type SessionTabUnread = "activity" | "error" +export const NEW_SESSION_TAB_TITLE = "New session" + export type SessionTabHistory = { entries: readonly string[] index: number diff --git a/packages/tui/src/context/session-tabs.tsx b/packages/tui/src/context/session-tabs.tsx index 096804338f..df359f99a8 100644 --- a/packages/tui/src/context/session-tabs.tsx +++ b/packages/tui/src/context/session-tabs.tsx @@ -13,6 +13,7 @@ import { cycleSessionTab, moveSessionTab, moveSessionTabHistory, + NEW_SESSION_TAB_TITLE, openSessionTab, recordClosedSessionTab, recordSessionTabHistory, @@ -77,6 +78,12 @@ export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimp const root = (sessionID: string) => data.session.root(sessionID) const current = () => (route.data.type === "session" ? root(route.data.sessionID) : undefined) + const newTab = createMemo((open = false) => { + if (route.data.type === "home") return true + if (!open) return false + const sessionID = current() + return sessionID !== undefined && !state().tabs.some((tab) => tab.sessionID === sessionID) + }, false) const status = (sessionID: string) => { const session = root(sessionID) const members = data.session.family(session) @@ -107,7 +114,7 @@ export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimp if (route.data.type !== "session" || route.data.sessionID === "dummy") return const sessionID = root(route.data.sessionID) history = recordSessionTabHistory(history, sessionID) - const title = data.session.get(sessionID)?.title + const title = data.session.get(sessionID)?.title ?? (newTab() ? NEW_SESSION_TAB_TITLE : undefined) const tabs = openSessionTab(state().tabs, { sessionID, title }) if (tabs === state().tabs && !state().unread[sessionID]) return update((draft) => { @@ -233,7 +240,7 @@ export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimp return state().tabs }, newTab() { - return route.data.type === "home" + return newTab() }, current, status, diff --git a/packages/tui/test/context/session-tabs.test.tsx b/packages/tui/test/context/session-tabs.test.tsx index fa6b57d2f3..c3bd2e70a6 100644 --- a/packages/tui/test/context/session-tabs.test.tsx +++ b/packages/tui/test/context/session-tabs.test.tsx @@ -11,6 +11,7 @@ import { DataProvider } from "../../src/context/data" import { RouteProvider, useRoute } from "../../src/context/route" import { TuiAppProvider } from "../../src/context/runtime" import { SessionTabsProvider, useSessionTabs } from "../../src/context/session-tabs" +import { NEW_SESSION_TAB_TITLE } from "../../src/context/session-tabs-model" import { StorageProvider } from "../../src/context/storage" import { createApi, createEventStream, createFetch, directory } from "../fixture/tui-client" import { TestTuiContexts } from "../fixture/tui-environment" @@ -142,11 +143,13 @@ test("tracks a temporary new session tab across close and creation", async () => setup.route.navigate({ type: "home" }) await wait(() => setup.tabs.newTab()) setup.route.navigate({ type: "session", sessionID: "third" }) + expect(setup.tabs.newTab()).toBe(true) await wait( () => setup.tabs.current() === "third" && setup.tabs.tabs().some((tab) => tab.sessionID === "third"), ) expect(setup.tabs.newTab()).toBe(false) + expect(setup.tabs.tabs().find((tab) => tab.sessionID === "third")?.title).toBe(NEW_SESSION_TAB_TITLE) } finally { setup.destroy() }