mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Extract chat view state controller
This commit is contained in:
parent
47eb02aeb3
commit
ff82da37c4
3 changed files with 91 additions and 11 deletions
27
src/features/chat/view-state-controller.ts
Normal file
27
src/features/chat/view-state-controller.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { parseRestoredThreadState } from "./view-snapshot";
|
||||
import type { RestoredThreadState } from "./view-lifecycle";
|
||||
|
||||
export interface ChatViewStateControllerHost {
|
||||
invalidateResumeWork: () => void;
|
||||
clearRestoredThreadLifecycle: () => void;
|
||||
clearDeferredRestoredThreadHydration: () => void;
|
||||
scheduleDeferredAppServerWarmup: () => void;
|
||||
restoreThreadPlaceholder: (restoredThread: RestoredThreadState) => void;
|
||||
}
|
||||
|
||||
export class ChatViewStateController {
|
||||
constructor(private readonly host: ChatViewStateControllerHost) {}
|
||||
|
||||
applyState(state: unknown): void {
|
||||
const restoredThread = parseRestoredThreadState(state);
|
||||
if (!restoredThread) {
|
||||
this.host.invalidateResumeWork();
|
||||
this.host.clearRestoredThreadLifecycle();
|
||||
this.host.clearDeferredRestoredThreadHydration();
|
||||
this.host.scheduleDeferredAppServerWarmup();
|
||||
return;
|
||||
}
|
||||
|
||||
this.host.restoreThreadPlaceholder(restoredThread);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ import {
|
|||
statusSummaryLines as buildStatusSummaryLines,
|
||||
toolbarViewModel as buildToolbarViewModel,
|
||||
} from "./view-model";
|
||||
import { composerSlotSnapshot, openPanelTurnLifecycle, parseRestoredThreadState } from "./view-snapshot";
|
||||
import { composerSlotSnapshot, openPanelTurnLifecycle } from "./view-snapshot";
|
||||
import {
|
||||
ChatConnectionWorkTracker,
|
||||
ChatResumeWorkTracker,
|
||||
|
|
@ -60,6 +60,7 @@ import { ChatViewRenderController } from "./view-render-controller";
|
|||
import { ChatViewOpenCloseController } from "./view-open-close-controller";
|
||||
import { PlanImplementationController } from "./plan-implementation-controller";
|
||||
import { ThreadSelectionController } from "./thread-selection-controller";
|
||||
import { ChatViewStateController } from "./view-state-controller";
|
||||
|
||||
export interface CodexChatHost {
|
||||
readonly settings: CodexPanelSettings;
|
||||
|
|
@ -101,6 +102,7 @@ export class CodexChatView extends ItemView {
|
|||
private readonly messageRenderer: ChatMessageRenderer;
|
||||
private readonly renderController: ChatViewRenderController;
|
||||
private readonly openCloseController: ChatViewOpenCloseController;
|
||||
private readonly viewStateController: ChatViewStateController;
|
||||
private readonly messageScroll: ChatMessageScrollController;
|
||||
private readonly turnSubmission: TurnSubmissionController;
|
||||
private readonly slashCommands: SlashCommandController;
|
||||
|
|
@ -565,6 +567,23 @@ export class CodexChatView extends ItemView {
|
|||
this.refreshTabHeader();
|
||||
},
|
||||
});
|
||||
this.viewStateController = new ChatViewStateController({
|
||||
invalidateResumeWork: () => {
|
||||
this.invalidateResumeWork();
|
||||
},
|
||||
clearRestoredThreadLifecycle: () => {
|
||||
this.clearRestoredThreadLifecycle();
|
||||
},
|
||||
clearDeferredRestoredThreadHydration: () => {
|
||||
this.clearDeferredRestoredThreadHydration();
|
||||
},
|
||||
scheduleDeferredAppServerWarmup: () => {
|
||||
this.scheduleDeferredAppServerWarmup();
|
||||
},
|
||||
restoreThreadPlaceholder: (restoredThread) => {
|
||||
this.restoreThreadPlaceholder(restoredThread);
|
||||
},
|
||||
});
|
||||
this.threadResume = new ThreadResumeController({
|
||||
stateStore: this.chatState,
|
||||
vaultPath: this.plugin.vaultPath,
|
||||
|
|
@ -683,16 +702,7 @@ export class CodexChatView extends ItemView {
|
|||
|
||||
override async setState(state: unknown, result: ViewStateResult): Promise<void> {
|
||||
await super.setState(state, result);
|
||||
const restoredThread = parseRestoredThreadState(state);
|
||||
if (!restoredThread) {
|
||||
this.invalidateResumeWork();
|
||||
this.clearRestoredThreadLifecycle();
|
||||
this.clearDeferredRestoredThreadHydration();
|
||||
this.scheduleDeferredAppServerWarmup();
|
||||
return;
|
||||
}
|
||||
|
||||
this.restoreThreadPlaceholder(restoredThread);
|
||||
this.viewStateController.applyState(state);
|
||||
}
|
||||
|
||||
refreshSettings(): void {
|
||||
|
|
|
|||
43
tests/features/chat/view-state-controller.test.ts
Normal file
43
tests/features/chat/view-state-controller.test.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { ChatViewStateController, type ChatViewStateControllerHost } from "../../../src/features/chat/view-state-controller";
|
||||
|
||||
function createController(overrides: Partial<ChatViewStateControllerHost> = {}) {
|
||||
const host: ChatViewStateControllerHost = {
|
||||
invalidateResumeWork: vi.fn(),
|
||||
clearRestoredThreadLifecycle: vi.fn(),
|
||||
clearDeferredRestoredThreadHydration: vi.fn(),
|
||||
scheduleDeferredAppServerWarmup: vi.fn(),
|
||||
restoreThreadPlaceholder: vi.fn(),
|
||||
...overrides,
|
||||
};
|
||||
return { controller: new ChatViewStateController(host), host };
|
||||
}
|
||||
|
||||
describe("ChatViewStateController", () => {
|
||||
it("restores a thread placeholder from persisted view state", () => {
|
||||
const { controller, host } = createController();
|
||||
|
||||
controller.applyState({ threadId: "thread", threadTitle: "Title" });
|
||||
|
||||
expect(host.restoreThreadPlaceholder).toHaveBeenCalledWith({
|
||||
threadId: "thread",
|
||||
title: "Title",
|
||||
explicitName: null,
|
||||
});
|
||||
expect(host.invalidateResumeWork).not.toHaveBeenCalled();
|
||||
expect(host.scheduleDeferredAppServerWarmup).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clears restored lifecycle and schedules warmup when no thread is restored", () => {
|
||||
const { controller, host } = createController();
|
||||
|
||||
controller.applyState({ version: 1 });
|
||||
|
||||
expect(host.invalidateResumeWork).toHaveBeenCalledOnce();
|
||||
expect(host.clearRestoredThreadLifecycle).toHaveBeenCalledOnce();
|
||||
expect(host.clearDeferredRestoredThreadHydration).toHaveBeenCalledOnce();
|
||||
expect(host.scheduleDeferredAppServerWarmup).toHaveBeenCalledOnce();
|
||||
expect(host.restoreThreadPlaceholder).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue