diff --git a/src/features/chat/thread-rename.ts b/src/features/chat/thread-rename.ts index 28c345b5..093032a4 100644 --- a/src/features/chat/thread-rename.ts +++ b/src/features/chat/thread-rename.ts @@ -78,6 +78,7 @@ export class ThreadRenameController { updateDraft(threadId: string, value: string): void { if (this.renameThreadId !== threadId) return; this.renameDraft = value; + this.host.render(); } cancel(threadId: string): void { diff --git a/src/features/threads-view/view.ts b/src/features/threads-view/view.ts index 485020f1..144363a8 100644 --- a/src/features/threads-view/view.ts +++ b/src/features/threads-view/view.ts @@ -242,6 +242,7 @@ export class CodexThreadsView extends ItemView { private updateRename(threadId: string, value: string): void { this.renameDrafts.set(threadId, value); + this.render(); } private cancelRename(threadId: string): void { diff --git a/tests/features/chat/thread-rename.test.ts b/tests/features/chat/thread-rename.test.ts new file mode 100644 index 00000000..99f09f40 --- /dev/null +++ b/tests/features/chat/thread-rename.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it, vi } from "vitest"; + +import { createChatStateStore } from "../../../src/features/chat/chat-state"; +import { ThreadRenameController } from "../../../src/features/chat/thread-rename"; +import type { Thread } from "../../../src/generated/app-server/v2/Thread"; +import { DEFAULT_SETTINGS } from "../../../src/settings/model"; + +describe("ThreadRenameController", () => { + it("rerenders after updating a controlled rename draft", () => { + const stateStore = createChatStateStore(); + stateStore.dispatch({ type: "thread/list-applied", threads: [threadFixture("thread")] }); + const render = vi.fn(); + const controller = new ThreadRenameController({ + stateStore, + vaultPath: "/vault", + settings: () => DEFAULT_SETTINGS, + ensureConnected: vi.fn().mockResolvedValue(undefined), + currentClient: () => null, + refreshThreads: vi.fn().mockResolvedValue(undefined), + render, + addSystemMessage: vi.fn(), + notifyThreadRenamed: vi.fn(), + }); + + controller.start("thread"); + render.mockClear(); + controller.updateDraft("thread", "New name"); + + expect(render).toHaveBeenCalledOnce(); + expect(controller.editState("thread")).toEqual({ draft: "New name", generating: false }); + }); +}); + +function threadFixture(id: string): Thread { + return { + id, + sessionId: "session", + forkedFromId: null, + preview: "Thread preview", + ephemeral: false, + modelProvider: "openai", + createdAt: 1, + updatedAt: 1, + status: { type: "idle" }, + path: null, + cwd: "/vault", + cliVersion: "0.0.0", + source: "appServer", + threadSource: null, + agentNickname: null, + agentRole: null, + gitInfo: null, + name: null, + turns: [], + }; +} diff --git a/tests/features/threads-view/view.test.ts b/tests/features/threads-view/view.test.ts index 4a6cf4da..3ff4bb39 100644 --- a/tests/features/threads-view/view.test.ts +++ b/tests/features/threads-view/view.test.ts @@ -5,7 +5,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { DEFAULT_SETTINGS } from "../../../src/settings/model"; import type { Turn } from "../../../src/generated/app-server/v2/Turn"; import type * as ThreadNamingModule from "../../../src/app-server/thread-naming"; -import { installObsidianDomShims } from "../chat/ui/dom-test-helpers"; +import { changeInputValue, installObsidianDomShims } from "../chat/ui/dom-test-helpers"; const connectionMock = vi.hoisted(() => { const state = { @@ -272,8 +272,10 @@ describe("CodexThreadsView", () => { const input = view.containerEl.querySelector(".codex-panel-threads__rename-input"); expect(input).not.toBeNull(); if (!input) return; - input.value = "Renamed thread"; - input.dispatchEvent(new FocusEvent("focusout", { bubbles: true })); + changeInputValue(input, "Renamed thread"); + view.containerEl + .querySelector(".codex-panel-threads__rename-input") + ?.dispatchEvent(new FocusEvent("focusout", { bubbles: true })); await vi.waitFor(() => { expect(setThreadName).toHaveBeenCalledWith("thread", "Renamed thread");