mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Move thread title derivations to view model
This commit is contained in:
parent
76a1598f04
commit
8632c629e5
3 changed files with 59 additions and 17 deletions
|
|
@ -15,7 +15,7 @@ import { readRuntimeConfig } from "../../runtime/config";
|
|||
import { sortedAvailableModels } from "../../runtime/model";
|
||||
import { compactContextLabel } from "../../runtime/settings";
|
||||
import { contextSummary, effectiveConfigSections, rateLimitSummary } from "../../runtime/view";
|
||||
import { getThreadTitle } from "../../domain/threads/model";
|
||||
import { codexPanelDisplayTitle, explicitThreadName, getThreadTitle } from "../../domain/threads/model";
|
||||
import { connectionDiagnosticSections, diagnosticAlertLevel } from "./diagnostics";
|
||||
import type { ChatState } from "./chat-state";
|
||||
import { statusValue, usageLimitStatusLines } from "./status-lines";
|
||||
|
|
@ -52,6 +52,12 @@ export interface RuntimeToolbarChoicesInput {
|
|||
setRequestedReasoningEffort: (effort: ReasoningEffort | null) => void;
|
||||
}
|
||||
|
||||
export interface RestoredThreadTitleSnapshot {
|
||||
threadId: string;
|
||||
title: string | null;
|
||||
explicitName: string | null;
|
||||
}
|
||||
|
||||
export function runtimeSnapshotForChatState({ state }: RuntimeSnapshotInput): RuntimeSnapshot {
|
||||
return {
|
||||
effectiveConfig: state.effectiveConfig,
|
||||
|
|
@ -106,6 +112,30 @@ export function runtimeToolbarChoices(input: RuntimeToolbarChoicesInput): Pick<T
|
|||
return { modelChoices, effortChoices };
|
||||
}
|
||||
|
||||
export function chatViewDisplayTitle(state: ChatState, restoredThreadTitle: string | null): string {
|
||||
return codexPanelDisplayTitle(state.activeThreadId, state.listedThreads, restoredThreadTitle);
|
||||
}
|
||||
|
||||
export function activeThreadTitle(state: ChatState): string | null {
|
||||
const threadId = state.activeThreadId;
|
||||
if (!threadId) return null;
|
||||
const thread = state.listedThreads.find((item) => item.id === threadId);
|
||||
return thread ? getThreadTitle(thread) : null;
|
||||
}
|
||||
|
||||
export function activeComposerThreadName(state: ChatState, restoredThread: RestoredThreadTitleSnapshot | null): string | null {
|
||||
const threadId = state.activeThreadId;
|
||||
if (!threadId) return null;
|
||||
const thread = state.listedThreads.find((item) => item.id === threadId);
|
||||
const listedName = thread ? explicitThreadName(thread) : null;
|
||||
if (listedName) return listedName;
|
||||
return restoredThread?.threadId === threadId ? restoredThread.explicitName : null;
|
||||
}
|
||||
|
||||
export function composerPlaceholder(threadName: string | null): string {
|
||||
return threadName ? `Ask Codex to work on “${threadName}”...` : "Ask Codex to work on this task...";
|
||||
}
|
||||
|
||||
export function toolbarViewModel(input: ToolbarViewModelInput): ToolbarViewModel {
|
||||
const { state, snapshot } = input;
|
||||
const config = readRuntimeConfig(state.effectiveConfig);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import {
|
|||
type ChatAction,
|
||||
type ChatState,
|
||||
} from "./chat-state";
|
||||
import { codexPanelDisplayTitle, explicitThreadName, getThreadTitle } from "../../domain/threads/model";
|
||||
import {
|
||||
referencedThreadDisplay,
|
||||
referencedThreadPrompt,
|
||||
|
|
@ -50,7 +49,11 @@ import { ChatRuntimeSettingsController } from "./runtime-settings-controller";
|
|||
import { RestoredThreadController } from "./restored-thread-controller";
|
||||
import { unmountReactRoot } from "../../shared/ui/react-root";
|
||||
import {
|
||||
activeComposerThreadName as buildActiveComposerThreadName,
|
||||
activeThreadTitle as buildActiveThreadTitle,
|
||||
chatViewDisplayTitle,
|
||||
connectionDiagnosticsModel,
|
||||
composerPlaceholder as buildComposerPlaceholder,
|
||||
effortStatusLines as buildEffortStatusLines,
|
||||
modelStatusLines as buildModelStatusLines,
|
||||
runtimeToolbarChoices,
|
||||
|
|
@ -366,7 +369,7 @@ export class CodexChatView extends ItemView {
|
|||
}
|
||||
|
||||
override getDisplayText(): string {
|
||||
return codexPanelDisplayTitle(this.state.activeThreadId, this.state.listedThreads, this.restoredThreadTitle());
|
||||
return chatViewDisplayTitle(this.state, this.restoredThreadTitle());
|
||||
}
|
||||
|
||||
override getIcon(): string {
|
||||
|
|
@ -1026,10 +1029,7 @@ export class CodexChatView extends ItemView {
|
|||
}
|
||||
|
||||
private activeThreadTitle(): string | null {
|
||||
const threadId = this.state.activeThreadId;
|
||||
if (!threadId) return null;
|
||||
const thread = this.state.listedThreads.find((item) => item.id === threadId);
|
||||
return thread ? getThreadTitle(thread) : null;
|
||||
return buildActiveThreadTitle(this.state);
|
||||
}
|
||||
|
||||
private restoredThreadPlaceholder() {
|
||||
|
|
@ -1045,18 +1045,11 @@ export class CodexChatView extends ItemView {
|
|||
}
|
||||
|
||||
private composerPlaceholder(): string {
|
||||
const threadName = this.activeComposerThreadName();
|
||||
return threadName ? `Ask Codex to work on “${threadName}”...` : "Ask Codex to work on this task...";
|
||||
return buildComposerPlaceholder(this.activeComposerThreadName());
|
||||
}
|
||||
|
||||
private activeComposerThreadName(): string | null {
|
||||
const threadId = this.state.activeThreadId;
|
||||
if (!threadId) return null;
|
||||
const thread = this.state.listedThreads.find((item) => item.id === threadId);
|
||||
const listedName = thread ? explicitThreadName(thread) : null;
|
||||
if (listedName) return listedName;
|
||||
const restoredThread = this.restoredThreadPlaceholder();
|
||||
return restoredThread?.threadId === threadId ? restoredThread.explicitName : null;
|
||||
return buildActiveComposerThreadName(this.state, this.restoredThreadPlaceholder());
|
||||
}
|
||||
|
||||
private readonly renderToolbarSlot = (toolbar: HTMLElement): void => {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ import { describe, expect, it } from "vitest";
|
|||
import { createAppServerDiagnostics } from "../../../src/app-server/compatibility";
|
||||
import { createChatState } from "../../../src/features/chat/chat-state";
|
||||
import {
|
||||
activeComposerThreadName,
|
||||
activeThreadTitle,
|
||||
chatViewDisplayTitle,
|
||||
composerPlaceholder,
|
||||
effortStatusLines,
|
||||
runtimeToolbarChoices,
|
||||
modelStatusLines,
|
||||
|
|
@ -94,6 +98,21 @@ describe("chat view model", () => {
|
|||
expect(selectedModels).toEqual(["gpt-5-mini"]);
|
||||
expect(selectedEfforts).toEqual(["high"]);
|
||||
});
|
||||
|
||||
it("derives active thread titles and composer placeholders", () => {
|
||||
const state = createChatState();
|
||||
state.activeThreadId = "thread-1";
|
||||
state.listedThreads = [threadFixture("thread-1", "Active")];
|
||||
|
||||
expect(chatViewDisplayTitle(state, null)).toBe("Codex: Active");
|
||||
expect(activeThreadTitle(state)).toBe("Active");
|
||||
expect(activeComposerThreadName(state, null)).toBe("Active");
|
||||
expect(composerPlaceholder("Active")).toBe("Ask Codex to work on “Active”...");
|
||||
expect(composerPlaceholder(null)).toBe("Ask Codex to work on this task...");
|
||||
|
||||
state.listedThreads = [threadFixture("thread-1", null)];
|
||||
expect(activeComposerThreadName(state, { threadId: "thread-1", title: "Restored", explicitName: "Restored" })).toBe("Restored");
|
||||
});
|
||||
});
|
||||
|
||||
function effectiveConfigFixture(config: Record<string, unknown>): ConfigReadResponse {
|
||||
|
|
@ -104,7 +123,7 @@ function effectiveConfigFixture(config: Record<string, unknown>): ConfigReadResp
|
|||
};
|
||||
}
|
||||
|
||||
function threadFixture(id: string, name: string): Thread {
|
||||
function threadFixture(id: string, name: string | null): Thread {
|
||||
return {
|
||||
id,
|
||||
sessionId: "session",
|
||||
|
|
|
|||
Loading…
Reference in a new issue