mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Remove plugin coordinator compatibility facade
This commit is contained in:
parent
2e76635430
commit
4a6f1a106b
6 changed files with 160 additions and 149 deletions
|
|
@ -7,13 +7,11 @@ export interface CodexChatHost {
|
|||
readonly settings: CodexPanelSettings;
|
||||
readonly vaultPath: string;
|
||||
openThreadInNewView(threadId: string): Promise<unknown>;
|
||||
openThreadInAvailableView(threadId: string): Promise<void>;
|
||||
focusThreadInOpenView(threadId: string): Promise<boolean>;
|
||||
openTurnDiff(state: ChatTurnDiffViewState): Promise<void>;
|
||||
notifyThreadArchived(threadId: string): void;
|
||||
notifyThreadRenamed(threadId: string, name: string | null): void;
|
||||
refreshThreadsViewLiveState(): void;
|
||||
refreshOpenViews(): void;
|
||||
refreshSharedThreadListFromOpenSurface(): void;
|
||||
applyThreadListSnapshot(threads: readonly Thread[]): void;
|
||||
refreshThreadList(fetchThreads: () => Promise<readonly Thread[]>): Promise<readonly Thread[]>;
|
||||
|
|
|
|||
219
src/main.ts
219
src/main.ts
|
|
@ -3,16 +3,13 @@ import { Plugin } from "obsidian";
|
|||
import { VIEW_TYPE_CODEX_PANEL, VIEW_TYPE_CODEX_THREADS, VIEW_TYPE_CODEX_TURN_DIFF } from "./constants";
|
||||
import { registerSelectionRewriteCommand } from "./features/selection-rewrite/command";
|
||||
import { CodexChatView } from "./features/chat/view";
|
||||
import type { CodexChatHost } from "./features/chat/chat-host";
|
||||
import { CodexChatTurnDiffView } from "./features/chat/chat-turn-diff-view";
|
||||
import { openThreadPicker } from "./features/thread-picker/modal";
|
||||
import type { OpenCodexPanelSnapshot } from "./runtime/open-panel-snapshot";
|
||||
import { CodexThreadsView } from "./features/threads-view/view";
|
||||
import type { Thread } from "./generated/app-server/v2/Thread";
|
||||
import type { Model } from "./generated/app-server/v2/Model";
|
||||
import type { SharedAppServerMetadata } from "./runtime/shared-app-server-state";
|
||||
import { openThreadPicker, type ThreadPickerHost } from "./features/thread-picker/modal";
|
||||
import { CodexThreadsView, type CodexThreadsHost } from "./features/threads-view/view";
|
||||
import { SharedAppServerCache } from "./runtime/shared-app-server-cache";
|
||||
import { DEFAULT_SETTINGS, getVaultPath, normalizeSettings, settingsMatchNormalizedData, type CodexPanelSettings } from "./settings/model";
|
||||
import { CodexPanelSettingTab } from "./settings/tab";
|
||||
import { CodexPanelSettingTab, type CodexPanelSettingTabHost } from "./settings/tab";
|
||||
import { persistedChatTurnDiffViewState, type ChatTurnDiffViewState } from "./features/chat/ui/turn-diff";
|
||||
import { WorkspacePanelCoordinator } from "./workspace/panel-coordinator";
|
||||
import { ThreadSurfaceCoordinator } from "./workspace/thread-surface-coordinator";
|
||||
|
|
@ -24,14 +21,14 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
private readonly panels = new WorkspacePanelCoordinator({
|
||||
app: this.app,
|
||||
refreshThreadsViewLiveState: () => {
|
||||
this.refreshThreadsViewLiveState();
|
||||
this.threadSurfaces.refreshThreadsViewLiveState();
|
||||
},
|
||||
});
|
||||
private readonly threadSurfaces = new ThreadSurfaceCoordinator({
|
||||
app: this.app,
|
||||
panels: this.panels,
|
||||
refreshThreadSurfaces: () => {
|
||||
this.refreshSharedThreadListFromOpenSurface();
|
||||
this.threadSurfaces.refreshSharedThreadListFromOpenSurface();
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -40,9 +37,9 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
this.vaultPath = getVaultPath(this.app);
|
||||
await this.loadSettings();
|
||||
|
||||
this.registerView(VIEW_TYPE_CODEX_PANEL, (leaf) => new CodexChatView(leaf, this));
|
||||
this.registerView(VIEW_TYPE_CODEX_PANEL, (leaf) => new CodexChatView(leaf, this.chatHost()));
|
||||
this.registerView(VIEW_TYPE_CODEX_TURN_DIFF, (leaf) => new CodexChatTurnDiffView(leaf));
|
||||
this.registerView(VIEW_TYPE_CODEX_THREADS, (leaf) => new CodexThreadsView(leaf, this));
|
||||
this.registerView(VIEW_TYPE_CODEX_THREADS, (leaf) => new CodexThreadsView(leaf, this.threadsHost()));
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("active-leaf-change", (leaf) => {
|
||||
this.panels.recordLastFocusedPanel(leaf);
|
||||
|
|
@ -50,19 +47,19 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
);
|
||||
|
||||
this.addRibbonIcon("bot-message-square", "Open panel", () => {
|
||||
void this.activateView();
|
||||
void this.panels.activateView();
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "open-panel",
|
||||
name: "Open panel",
|
||||
callback: () => void this.activateView(),
|
||||
callback: () => void this.panels.activateView(),
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "open-new-panel",
|
||||
name: "Open new panel",
|
||||
callback: () => void this.activateNewView(),
|
||||
callback: () => void this.panels.activateNewView(),
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
|
|
@ -74,21 +71,21 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
this.addCommand({
|
||||
id: "open-thread",
|
||||
name: "Open thread...",
|
||||
callback: () => void openThreadPicker(this),
|
||||
callback: () => void openThreadPicker(this.threadPickerHost()),
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "new-chat",
|
||||
name: "Start new chat",
|
||||
callback: async () => {
|
||||
const view = await this.activateView();
|
||||
const view = await this.panels.activateView();
|
||||
await view.startNewThread();
|
||||
},
|
||||
});
|
||||
|
||||
registerSelectionRewriteCommand(this);
|
||||
|
||||
this.addSettingTab(new CodexPanelSettingTab(this.app, this));
|
||||
this.addSettingTab(new CodexPanelSettingTab(this.app, this, this.settingTabHost()));
|
||||
|
||||
this.panels.scheduleBootRestoredPanelLoads();
|
||||
}
|
||||
|
|
@ -97,39 +94,7 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
this.panels.cancelBootRestoredPanelLoads();
|
||||
}
|
||||
|
||||
async activateView(): Promise<CodexChatView> {
|
||||
return this.panels.activateView();
|
||||
}
|
||||
|
||||
async activateNewView(options: { connect?: boolean } = {}): Promise<CodexChatView> {
|
||||
return this.panels.activateNewView(options);
|
||||
}
|
||||
|
||||
async openThreadInNewView(threadId: string): Promise<CodexChatView> {
|
||||
return this.panels.openThreadInNewView(threadId);
|
||||
}
|
||||
|
||||
async openNewPanel(): Promise<void> {
|
||||
await this.panels.openNewPanel();
|
||||
}
|
||||
|
||||
async openThreadInAvailableView(threadId: string): Promise<void> {
|
||||
await this.panels.openThreadInAvailableView(threadId);
|
||||
}
|
||||
|
||||
async openThreadInCurrentView(threadId: string): Promise<void> {
|
||||
await this.panels.openThreadInCurrentView(threadId);
|
||||
}
|
||||
|
||||
async focusThreadInOpenView(threadId: string): Promise<boolean> {
|
||||
return this.panels.focusThreadInOpenView(threadId);
|
||||
}
|
||||
|
||||
async openThreadInIdleEmptyView(threadId: string): Promise<boolean> {
|
||||
return this.panels.openThreadInIdleEmptyView(threadId);
|
||||
}
|
||||
|
||||
async activateThreadsView(): Promise<CodexThreadsView> {
|
||||
private async activateThreadsView(): Promise<CodexThreadsView> {
|
||||
const leaf = await this.app.workspace.ensureSideLeaf(VIEW_TYPE_CODEX_THREADS, "left", {
|
||||
active: true,
|
||||
reveal: true,
|
||||
|
|
@ -139,7 +104,7 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
return view;
|
||||
}
|
||||
|
||||
async openTurnDiff(state: ChatTurnDiffViewState): Promise<void> {
|
||||
private async openTurnDiff(state: ChatTurnDiffViewState): Promise<void> {
|
||||
const existing = this.app.workspace.getLeavesOfType(VIEW_TYPE_CODEX_TURN_DIFF).at(0);
|
||||
const leaf = existing ?? this.app.workspace.getLeaf("tab");
|
||||
await leaf.setViewState({ type: VIEW_TYPE_CODEX_TURN_DIFF, active: true, state: { ...persistedChatTurnDiffViewState(state) } });
|
||||
|
|
@ -150,67 +115,6 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
await this.app.workspace.revealLeaf(leaf);
|
||||
}
|
||||
|
||||
refreshOpenViews(): void {
|
||||
this.threadSurfaces.refreshOpenViews();
|
||||
}
|
||||
|
||||
refreshSharedThreadListFromOpenSurface(): void {
|
||||
this.threadSurfaces.refreshSharedThreadListFromOpenSurface();
|
||||
}
|
||||
|
||||
refreshThreadList(fetchThreads: () => Promise<readonly Thread[]>): Promise<readonly Thread[]> {
|
||||
return this.sharedAppServerCache.refreshThreadList(fetchThreads, (threads) => {
|
||||
this.threadSurfaces.applyThreadListSnapshot(threads);
|
||||
});
|
||||
}
|
||||
|
||||
applyThreadListSnapshot(threads: readonly Thread[]): void {
|
||||
this.sharedAppServerCache.applyThreadListSnapshot(threads);
|
||||
this.threadSurfaces.applyThreadListSnapshot(threads);
|
||||
}
|
||||
|
||||
cachedThreadList(): readonly Thread[] | null {
|
||||
return this.sharedAppServerCache.cachedThreadList();
|
||||
}
|
||||
|
||||
publishAppServerMetadata(metadata: SharedAppServerMetadata): void {
|
||||
this.sharedAppServerCache.applyAppServerMetadataSnapshot(metadata);
|
||||
this.threadSurfaces.publishAppServerMetadata(metadata);
|
||||
}
|
||||
|
||||
publishModels(models: readonly Model[]): void {
|
||||
this.sharedAppServerCache.applyModelsSnapshot(models);
|
||||
this.threadSurfaces.publishModels(models);
|
||||
}
|
||||
|
||||
cachedAppServerMetadata(): SharedAppServerMetadata | null {
|
||||
return this.sharedAppServerCache.cachedAppServerMetadata();
|
||||
}
|
||||
|
||||
cachedModels(): Model[] {
|
||||
return this.sharedAppServerCache.cachedModels();
|
||||
}
|
||||
|
||||
refreshThreadsViewLiveState(): void {
|
||||
this.threadSurfaces.refreshThreadsViewLiveState();
|
||||
}
|
||||
|
||||
notifyThreadArchived(threadId: string, options: { closeOpenPanels?: boolean } = {}): void {
|
||||
this.threadSurfaces.notifyThreadArchived(threadId, options);
|
||||
}
|
||||
|
||||
notifyThreadRenamed(threadId: string, name: string | null): void {
|
||||
this.threadSurfaces.notifyThreadRenamed(threadId, name);
|
||||
}
|
||||
|
||||
getOpenPanelSnapshots(): OpenCodexPanelSnapshot[] {
|
||||
return this.panels.getOpenPanelSnapshots();
|
||||
}
|
||||
|
||||
async focusOpenPanel(viewId: string, threadId: string | null = null): Promise<boolean> {
|
||||
return this.panels.focusOpenPanel(viewId, threadId);
|
||||
}
|
||||
|
||||
async loadSettings(): Promise<void> {
|
||||
const data: unknown = await this.loadData();
|
||||
this.settings = normalizeSettings(data);
|
||||
|
|
@ -222,4 +126,95 @@ export default class CodexPanelPlugin extends Plugin {
|
|||
async saveSettings(): Promise<void> {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
private chatHost(): CodexChatHost {
|
||||
return {
|
||||
settings: this.settings,
|
||||
vaultPath: this.vaultPath,
|
||||
openThreadInNewView: (threadId) => this.panels.openThreadInNewView(threadId),
|
||||
focusThreadInOpenView: (threadId) => this.panels.focusThreadInOpenView(threadId),
|
||||
openTurnDiff: (state) => this.openTurnDiff(state),
|
||||
notifyThreadArchived: (threadId) => {
|
||||
this.threadSurfaces.notifyThreadArchived(threadId);
|
||||
},
|
||||
notifyThreadRenamed: (threadId, name) => {
|
||||
this.threadSurfaces.notifyThreadRenamed(threadId, name);
|
||||
},
|
||||
refreshThreadsViewLiveState: () => {
|
||||
this.threadSurfaces.refreshThreadsViewLiveState();
|
||||
},
|
||||
refreshSharedThreadListFromOpenSurface: () => {
|
||||
this.threadSurfaces.refreshSharedThreadListFromOpenSurface();
|
||||
},
|
||||
applyThreadListSnapshot: (threads) => {
|
||||
this.sharedAppServerCache.applyThreadListSnapshot(threads);
|
||||
this.threadSurfaces.applyThreadListSnapshot(threads);
|
||||
},
|
||||
refreshThreadList: (fetchThreads) =>
|
||||
this.sharedAppServerCache.refreshThreadList(fetchThreads, (threads) => {
|
||||
this.threadSurfaces.applyThreadListSnapshot(threads);
|
||||
}),
|
||||
cachedThreadList: () => this.sharedAppServerCache.cachedThreadList(),
|
||||
publishAppServerMetadata: (metadata) => {
|
||||
this.sharedAppServerCache.applyAppServerMetadataSnapshot(metadata);
|
||||
this.threadSurfaces.publishAppServerMetadata(metadata);
|
||||
},
|
||||
cachedAppServerMetadata: () => this.sharedAppServerCache.cachedAppServerMetadata(),
|
||||
};
|
||||
}
|
||||
|
||||
private threadsHost(): CodexThreadsHost {
|
||||
return {
|
||||
settings: this.settings,
|
||||
vaultPath: this.vaultPath,
|
||||
openNewPanel: () => this.panels.openNewPanel(),
|
||||
openThreadInAvailableView: (threadId) => this.panels.openThreadInAvailableView(threadId),
|
||||
getOpenPanelSnapshots: () => this.panels.getOpenPanelSnapshots(),
|
||||
notifyThreadArchived: (threadId, options) => {
|
||||
this.threadSurfaces.notifyThreadArchived(threadId, options);
|
||||
},
|
||||
notifyThreadRenamed: (threadId, name) => {
|
||||
this.threadSurfaces.notifyThreadRenamed(threadId, name);
|
||||
},
|
||||
refreshThreadList: (fetchThreads) =>
|
||||
this.sharedAppServerCache.refreshThreadList(fetchThreads, (threads) => {
|
||||
this.threadSurfaces.applyThreadListSnapshot(threads);
|
||||
}),
|
||||
cachedThreadList: () => this.sharedAppServerCache.cachedThreadList(),
|
||||
};
|
||||
}
|
||||
|
||||
private threadPickerHost(): ThreadPickerHost {
|
||||
return {
|
||||
app: this.app,
|
||||
settings: this.settings,
|
||||
vaultPath: this.vaultPath,
|
||||
cachedThreadList: () => this.sharedAppServerCache.cachedThreadList(),
|
||||
refreshThreadList: (fetchThreads) =>
|
||||
this.sharedAppServerCache.refreshThreadList(fetchThreads, (threads) => {
|
||||
this.threadSurfaces.applyThreadListSnapshot(threads);
|
||||
}),
|
||||
openThreadInCurrentView: (threadId) => this.panels.openThreadInCurrentView(threadId),
|
||||
openThreadInAvailableView: (threadId) => this.panels.openThreadInAvailableView(threadId),
|
||||
};
|
||||
}
|
||||
|
||||
private settingTabHost(): CodexPanelSettingTabHost {
|
||||
return {
|
||||
settings: this.settings,
|
||||
vaultPath: this.vaultPath,
|
||||
saveSettings: () => this.saveSettings(),
|
||||
refreshOpenViews: () => {
|
||||
this.threadSurfaces.refreshOpenViews();
|
||||
},
|
||||
refreshSharedThreadListFromOpenSurface: () => {
|
||||
this.threadSurfaces.refreshSharedThreadListFromOpenSurface();
|
||||
},
|
||||
cachedModels: () => this.sharedAppServerCache.cachedModels(),
|
||||
publishModels: (models) => {
|
||||
this.sharedAppServerCache.applyModelsSnapshot(models);
|
||||
this.threadSurfaces.publishModels(models);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,9 +48,10 @@ export class CodexPanelSettingTab extends PluginSettingTab {
|
|||
|
||||
constructor(
|
||||
app: App,
|
||||
owner: Plugin,
|
||||
private readonly plugin: CodexPanelSettingTabHost,
|
||||
) {
|
||||
super(app, plugin);
|
||||
super(app, owner);
|
||||
this.models = plugin.cachedModels();
|
||||
}
|
||||
|
||||
|
|
@ -528,7 +529,7 @@ export class CodexPanelSettingTab extends PluginSettingTab {
|
|||
}
|
||||
}
|
||||
|
||||
export interface CodexPanelSettingTabHost extends Plugin {
|
||||
export interface CodexPanelSettingTabHost {
|
||||
settings: CodexPanelSettings;
|
||||
vaultPath: string;
|
||||
saveSettings(): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -1191,12 +1191,10 @@ function chatHost(overrides: Partial<CodexChatHost> = {}): CodexChatHost {
|
|||
},
|
||||
vaultPath: "/vault",
|
||||
openThreadInNewView: vi.fn(),
|
||||
openThreadInAvailableView: vi.fn().mockResolvedValue(undefined),
|
||||
focusThreadInOpenView: vi.fn().mockResolvedValue(false),
|
||||
openTurnDiff: vi.fn(),
|
||||
notifyThreadArchived: vi.fn(),
|
||||
notifyThreadRenamed: vi.fn(),
|
||||
refreshOpenViews: vi.fn(),
|
||||
refreshSharedThreadListFromOpenSurface: vi.fn(),
|
||||
refreshThreadsViewLiveState: vi.fn(),
|
||||
applyThreadListSnapshot: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -5,12 +5,28 @@ import { FileSystemAdapter } from "obsidian";
|
|||
|
||||
import { VIEW_TYPE_CODEX_PANEL } from "../src/constants";
|
||||
import { DEFAULT_SETTINGS } from "../src/settings/model";
|
||||
import type CodexPanelPlugin from "../src/main";
|
||||
import type { CodexChatView } from "../src/features/chat/view";
|
||||
import type { Thread } from "../src/generated/app-server/v2/Thread";
|
||||
import type { SharedAppServerCache } from "../src/runtime/shared-app-server-cache";
|
||||
import type { WorkspacePanelCoordinator } from "../src/workspace/panel-coordinator";
|
||||
import type { ThreadSurfaceCoordinator } from "../src/workspace/thread-surface-coordinator";
|
||||
import { installObsidianDomShims } from "./support/dom";
|
||||
|
||||
installObsidianDomShims();
|
||||
|
||||
function panels(plugin: CodexPanelPlugin): WorkspacePanelCoordinator {
|
||||
return (plugin as unknown as { panels: WorkspacePanelCoordinator }).panels;
|
||||
}
|
||||
|
||||
function threadSurfaces(plugin: CodexPanelPlugin): ThreadSurfaceCoordinator {
|
||||
return (plugin as unknown as { threadSurfaces: ThreadSurfaceCoordinator }).threadSurfaces;
|
||||
}
|
||||
|
||||
function sharedAppServerCache(plugin: CodexPanelPlugin): SharedAppServerCache {
|
||||
return (plugin as unknown as { sharedAppServerCache: SharedAppServerCache }).sharedAppServerCache;
|
||||
}
|
||||
|
||||
describe("CodexPanelPlugin boot restored panel loading", () => {
|
||||
beforeEach(() => {
|
||||
vi.useRealTimers();
|
||||
|
|
@ -56,7 +72,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
restoredLeaf.view = chatView(CodexChatView, restoredLeaf);
|
||||
});
|
||||
|
||||
await plugin.openThreadInAvailableView("thread-1");
|
||||
await panels(plugin).openThreadInAvailableView("thread-1");
|
||||
|
||||
expect(restoredLeaf.loadIfDeferred).toHaveBeenCalledTimes(1);
|
||||
expect(restoredLeaf.view).toBeInstanceOf(CodexChatView);
|
||||
|
|
@ -84,7 +100,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const openEmptyThread = vi.spyOn(emptyView, "openThread").mockResolvedValue(undefined);
|
||||
const plugin = await pluginWithLeaves([openLeaf, emptyLeaf]);
|
||||
|
||||
await plugin.openThreadInAvailableView("thread-1");
|
||||
await panels(plugin).openThreadInAvailableView("thread-1");
|
||||
|
||||
expect((plugin.app.workspace.revealLeaf as ReturnType<typeof vi.fn>).mock.calls).toContainEqual([openLeaf]);
|
||||
expect(openEmptyThread).not.toHaveBeenCalled();
|
||||
|
|
@ -121,7 +137,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const openEmptyThread = vi.spyOn(emptyView, "openThread").mockResolvedValue(undefined);
|
||||
const plugin = await pluginWithLeaves([busyLeaf, emptyLeaf]);
|
||||
|
||||
await plugin.openThreadInAvailableView("thread-1");
|
||||
await panels(plugin).openThreadInAvailableView("thread-1");
|
||||
|
||||
expect(openEmptyThread).toHaveBeenCalledWith("thread-1");
|
||||
});
|
||||
|
|
@ -139,7 +155,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const plugin = await pluginWithLeaves([olderLeaf, currentLeaf]);
|
||||
(plugin.app.workspace.getMostRecentLeaf as ReturnType<typeof vi.fn>).mockReturnValue(currentLeaf);
|
||||
|
||||
await plugin.openThreadInCurrentView("thread-1");
|
||||
await panels(plugin).openThreadInCurrentView("thread-1");
|
||||
|
||||
expect(openCurrentThread).toHaveBeenCalledWith("thread-1");
|
||||
expect(openOlderThread).not.toHaveBeenCalled();
|
||||
|
|
@ -159,7 +175,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
(plugin.app.workspace.getActiveViewOfType as ReturnType<typeof vi.fn>).mockReturnValue(activeView);
|
||||
(plugin.app.workspace.getMostRecentLeaf as ReturnType<typeof vi.fn>).mockReturnValue(fallbackLeaf);
|
||||
|
||||
await plugin.openThreadInCurrentView("thread-1");
|
||||
await panels(plugin).openThreadInCurrentView("thread-1");
|
||||
|
||||
expect(openActiveThread).toHaveBeenCalledWith("thread-1");
|
||||
expect(openFallbackThread).not.toHaveBeenCalled();
|
||||
|
|
@ -179,7 +195,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const plugin = await pluginWithLeaves([openLeaf, currentLeaf]);
|
||||
(plugin.app.workspace.getMostRecentLeaf as ReturnType<typeof vi.fn>).mockReturnValue(currentLeaf);
|
||||
|
||||
await plugin.openThreadInCurrentView("thread-1");
|
||||
await panels(plugin).openThreadInCurrentView("thread-1");
|
||||
|
||||
expect(focusOpenThread).toHaveBeenCalledWith("thread-1");
|
||||
expect(openCurrentThread).not.toHaveBeenCalled();
|
||||
|
|
@ -197,7 +213,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
restoredLeaf.view = view;
|
||||
});
|
||||
|
||||
await plugin.openThreadInCurrentView("selected-thread");
|
||||
await panels(plugin).openThreadInCurrentView("selected-thread");
|
||||
|
||||
expect(restoredLeaf.loadIfDeferred).toHaveBeenCalledOnce();
|
||||
expect(openThread).toHaveBeenCalledWith("selected-thread");
|
||||
|
|
@ -217,7 +233,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const focusComposer = vi.spyOn(view, "focusComposer").mockImplementation(() => undefined);
|
||||
const openThread = vi.spyOn(view, "openThread").mockResolvedValue(undefined);
|
||||
|
||||
await plugin.openThreadInNewView("thread-1");
|
||||
await panels(plugin).openThreadInNewView("thread-1");
|
||||
|
||||
expect(connect).not.toHaveBeenCalled();
|
||||
expect(focusComposer).toHaveBeenCalledOnce();
|
||||
|
|
@ -239,7 +255,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const plugin = await pluginWithLeaves([firstLeaf, activeLeaf]);
|
||||
(plugin.app.workspace.getActiveViewOfType as ReturnType<typeof vi.fn>).mockReturnValue(activeView);
|
||||
|
||||
await expect(plugin.activateView()).resolves.toBe(activeView);
|
||||
await expect(panels(plugin).activateView()).resolves.toBe(activeView);
|
||||
|
||||
expect((plugin.app.workspace.revealLeaf as ReturnType<typeof vi.fn>).mock.calls).toContainEqual([activeLeaf]);
|
||||
expect(connectActive).toHaveBeenCalledOnce();
|
||||
|
|
@ -267,7 +283,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
if (name === "active-leaf-change") activeLeafHandlers.push(handler);
|
||||
return {};
|
||||
});
|
||||
const refreshLiveState = vi.spyOn(plugin, "refreshThreadsViewLiveState").mockImplementation(() => undefined);
|
||||
const refreshLiveState = vi.spyOn(threadSurfaces(plugin), "refreshThreadsViewLiveState").mockImplementation(() => undefined);
|
||||
|
||||
await plugin.onload();
|
||||
const activeLeafHandler = activeLeafHandlers.at(0);
|
||||
|
|
@ -275,7 +291,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
activeLeafHandler(secondLeaf);
|
||||
|
||||
expect(refreshLiveState).toHaveBeenCalledOnce();
|
||||
expect(plugin.getOpenPanelSnapshots()).toMatchObject([
|
||||
expect(panels(plugin).getOpenPanelSnapshots()).toMatchObject([
|
||||
{ viewId: "first", lastFocused: false },
|
||||
{ viewId: "second", lastFocused: true },
|
||||
]);
|
||||
|
|
@ -295,7 +311,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const plugin = await pluginWithLeaves([firstLeaf, activeLeaf]);
|
||||
(plugin.app.workspace.getActiveViewOfType as ReturnType<typeof vi.fn>).mockReturnValue(activeView);
|
||||
|
||||
expect(plugin.getOpenPanelSnapshots()).toMatchObject([
|
||||
expect(panels(plugin).getOpenPanelSnapshots()).toMatchObject([
|
||||
{ viewId: "first", lastFocused: false },
|
||||
{ viewId: "active", lastFocused: true },
|
||||
]);
|
||||
|
|
@ -316,7 +332,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const plugin = await pluginWithLeaves([recentLeaf, otherLeaf]);
|
||||
(plugin.app.workspace.getMostRecentLeaf as ReturnType<typeof vi.fn>).mockReturnValue(recentLeaf);
|
||||
|
||||
expect(plugin.getOpenPanelSnapshots()).toMatchObject([
|
||||
expect(panels(plugin).getOpenPanelSnapshots()).toMatchObject([
|
||||
{ viewId: "recent", lastFocused: true },
|
||||
{ viewId: "other", lastFocused: false },
|
||||
]);
|
||||
|
|
@ -335,7 +351,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const focusComposer = vi.spyOn(view, "focusComposer").mockImplementation(() => undefined);
|
||||
const openThread = vi.spyOn(view, "openThread").mockResolvedValue(undefined);
|
||||
|
||||
await plugin.openNewPanel();
|
||||
await panels(plugin).openNewPanel();
|
||||
|
||||
expect(connect).toHaveBeenCalledOnce();
|
||||
expect(focusComposer).toHaveBeenCalledOnce();
|
||||
|
|
@ -344,9 +360,11 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
|
||||
it("refreshes shared thread lists after archive lifecycle notifications", async () => {
|
||||
const plugin = await pluginWithLeaves([]);
|
||||
const refreshSharedThreadList = vi.spyOn(plugin, "refreshSharedThreadListFromOpenSurface").mockImplementation(() => undefined);
|
||||
const refreshSharedThreadList = vi
|
||||
.spyOn(threadSurfaces(plugin), "refreshSharedThreadListFromOpenSurface")
|
||||
.mockImplementation(() => undefined);
|
||||
|
||||
plugin.notifyThreadArchived("thread-1");
|
||||
threadSurfaces(plugin).notifyThreadArchived("thread-1");
|
||||
|
||||
expect(refreshSharedThreadList).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
|
@ -361,15 +379,15 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
otherLeaf.view = chatView(CodexChatView, otherLeaf);
|
||||
vi.spyOn(otherLeaf.view as CodexChatView, "openPanelSnapshot").mockReturnValue(panelSnapshot({ threadId: "thread-2" }));
|
||||
const plugin = await pluginWithLeaves([restoredMatchingLeaf, matchingLeaf, otherLeaf]);
|
||||
vi.spyOn(plugin, "refreshSharedThreadListFromOpenSurface").mockImplementation(() => undefined);
|
||||
vi.spyOn(threadSurfaces(plugin), "refreshSharedThreadListFromOpenSurface").mockImplementation(() => undefined);
|
||||
|
||||
plugin.notifyThreadArchived("thread-1");
|
||||
threadSurfaces(plugin).notifyThreadArchived("thread-1");
|
||||
|
||||
expect(restoredMatchingLeaf.detach).not.toHaveBeenCalled();
|
||||
expect(matchingLeaf.detach).not.toHaveBeenCalled();
|
||||
expect(otherLeaf.detach).not.toHaveBeenCalled();
|
||||
|
||||
plugin.notifyThreadArchived("thread-1", { closeOpenPanels: true });
|
||||
threadSurfaces(plugin).notifyThreadArchived("thread-1", { closeOpenPanels: true });
|
||||
|
||||
expect(restoredMatchingLeaf.detach).toHaveBeenCalledOnce();
|
||||
expect(matchingLeaf.detach).toHaveBeenCalledOnce();
|
||||
|
|
@ -378,9 +396,11 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
|
||||
it("refreshes shared thread lists after rename lifecycle notifications", async () => {
|
||||
const plugin = await pluginWithLeaves([]);
|
||||
const refreshSharedThreadList = vi.spyOn(plugin, "refreshSharedThreadListFromOpenSurface").mockImplementation(() => undefined);
|
||||
const refreshSharedThreadList = vi
|
||||
.spyOn(threadSurfaces(plugin), "refreshSharedThreadListFromOpenSurface")
|
||||
.mockImplementation(() => undefined);
|
||||
|
||||
plugin.notifyThreadRenamed("thread-1", "Renamed thread");
|
||||
threadSurfaces(plugin).notifyThreadRenamed("thread-1", "Renamed thread");
|
||||
|
||||
expect(refreshSharedThreadList).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
|
@ -396,8 +416,8 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
);
|
||||
const secondFetch = vi.fn().mockResolvedValue([thread("second")]);
|
||||
|
||||
const first = plugin.refreshThreadList(fetchThreads);
|
||||
const second = plugin.refreshThreadList(secondFetch);
|
||||
const first = sharedAppServerCache(plugin).refreshThreadList(fetchThreads);
|
||||
const second = sharedAppServerCache(plugin).refreshThreadList(secondFetch);
|
||||
|
||||
expect(fetchThreads).toHaveBeenCalledOnce();
|
||||
expect(secondFetch).not.toHaveBeenCalled();
|
||||
|
|
@ -405,16 +425,16 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
|
||||
await expect(first).resolves.toEqual([thread("first")]);
|
||||
await expect(second).resolves.toEqual([thread("first")]);
|
||||
expect(plugin.cachedThreadList()).toEqual([thread("first")]);
|
||||
expect(sharedAppServerCache(plugin).cachedThreadList()).toEqual([thread("first")]);
|
||||
});
|
||||
|
||||
it("keeps the previous shared thread list when refresh fails", async () => {
|
||||
const plugin = await pluginWithLeaves([]);
|
||||
await plugin.refreshThreadList(() => Promise.resolve([thread("cached")]));
|
||||
await sharedAppServerCache(plugin).refreshThreadList(() => Promise.resolve([thread("cached")]));
|
||||
|
||||
await expect(plugin.refreshThreadList(() => Promise.reject(new Error("boom")))).rejects.toThrow("boom");
|
||||
await expect(sharedAppServerCache(plugin).refreshThreadList(() => Promise.reject(new Error("boom")))).rejects.toThrow("boom");
|
||||
|
||||
expect(plugin.cachedThreadList()).toEqual([thread("cached")]);
|
||||
expect(sharedAppServerCache(plugin).cachedThreadList()).toEqual([thread("cached")]);
|
||||
});
|
||||
|
||||
it("refreshes shared thread lists from a connected chat panel", async () => {
|
||||
|
|
@ -433,7 +453,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
|
||||
const plugin = await pluginWithLeaves([disconnectedLeaf, connectedLeaf]);
|
||||
|
||||
plugin.refreshSharedThreadListFromOpenSurface();
|
||||
threadSurfaces(plugin).refreshSharedThreadListFromOpenSurface();
|
||||
|
||||
expect(disconnectedRefresh).not.toHaveBeenCalled();
|
||||
expect(connectedRefresh).toHaveBeenCalledOnce();
|
||||
|
|
@ -462,7 +482,7 @@ describe("CodexPanelPlugin boot restored panel loading", () => {
|
|||
const plugin = await pluginWithLeaves(leaves);
|
||||
|
||||
sourceLeaf.detach();
|
||||
plugin.notifyThreadArchived("thread-1");
|
||||
threadSurfaces(plugin).notifyThreadArchived("thread-1");
|
||||
|
||||
expect(sourceRefresh).not.toHaveBeenCalled();
|
||||
expect(remainingRefresh).toHaveBeenCalledOnce();
|
||||
|
|
@ -535,12 +555,10 @@ function chatView(CodexChatViewCtor: typeof CodexChatView, leaf: TestLeaf) {
|
|||
settings: { ...DEFAULT_SETTINGS, codexPath: "codex", sendShortcut: "enter" },
|
||||
vaultPath: "/vault",
|
||||
openThreadInNewView: vi.fn(),
|
||||
openThreadInAvailableView: vi.fn(),
|
||||
focusThreadInOpenView: vi.fn(),
|
||||
openTurnDiff: vi.fn(),
|
||||
notifyThreadArchived: vi.fn(),
|
||||
notifyThreadRenamed: vi.fn(),
|
||||
refreshOpenViews: vi.fn(),
|
||||
refreshSharedThreadListFromOpenSurface: vi.fn(),
|
||||
refreshThreadsViewLiveState: vi.fn(),
|
||||
applyThreadListSnapshot: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -368,6 +368,7 @@ function newSettingsTab(
|
|||
} = {},
|
||||
): CodexPanelSettingTab {
|
||||
return new CodexPanelSettingTab(
|
||||
{} as never,
|
||||
{} as never,
|
||||
{
|
||||
settings: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue