mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Represent restored panel presence in threads view
This commit is contained in:
parent
1639c37ac3
commit
2d490c6fca
5 changed files with 45 additions and 22 deletions
|
|
@ -11,7 +11,7 @@ import {
|
|||
type ThreadRenameLifecycleState as SharedThreadRenameLifecycleState,
|
||||
} from "../threads/rename-lifecycle";
|
||||
|
||||
type ThreadsLiveStatus = "pending" | "running" | "draft" | "offline" | "open";
|
||||
type ThreadsLiveStatus = "pending" | "running" | "open";
|
||||
|
||||
interface ThreadsLiveState {
|
||||
status: ThreadsLiveStatus;
|
||||
|
|
@ -33,10 +33,8 @@ export type ThreadsRenameLifecycleEvent =
|
|||
| { type: "auto-name-finished"; generatingState: ThreadsGeneratingRenameState };
|
||||
|
||||
const STATUS_PRIORITY: Record<ThreadsLiveStatus, number> = {
|
||||
pending: 4,
|
||||
running: 3,
|
||||
draft: 2,
|
||||
offline: 1,
|
||||
pending: 2,
|
||||
running: 1,
|
||||
open: 0,
|
||||
};
|
||||
|
||||
|
|
@ -127,7 +125,5 @@ function snapshotsForThreads(snapshots: OpenCodexPanelSnapshot[]): Map<string, O
|
|||
function snapshotStatus(snapshot: OpenCodexPanelSnapshot): ThreadsLiveStatus {
|
||||
if (hasPendingRequests(pendingRequestCounts(snapshot))) return "pending";
|
||||
if (snapshot.turnLifecycle.kind !== "idle") return "running";
|
||||
if (snapshot.hasComposerDraft) return "draft";
|
||||
if (!snapshot.connected) return "offline";
|
||||
return "open";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,22 +78,12 @@
|
|||
--codex-panel-threads-gutter-color: color-mix(in srgb, var(--codex-panel-color-accent) 68%, transparent);
|
||||
}
|
||||
|
||||
.codex-panel-threads__row--draft {
|
||||
--codex-panel-threads-gutter-color: color-mix(in srgb, var(--codex-panel-color-accent) 36%, transparent);
|
||||
}
|
||||
|
||||
.codex-panel-threads__row--offline {
|
||||
--codex-panel-threads-gutter-color: var(--text-muted);
|
||||
}
|
||||
|
||||
.codex-panel-threads__row--open {
|
||||
--codex-panel-threads-gutter-color: var(--codex-panel-border-muted-color);
|
||||
}
|
||||
|
||||
.codex-panel-threads__row--pending::before,
|
||||
.codex-panel-threads__row--running::before,
|
||||
.codex-panel-threads__row--draft::before,
|
||||
.codex-panel-threads__row--offline::before,
|
||||
.codex-panel-threads__row--open::before {
|
||||
background: var(--codex-panel-threads-gutter-color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,9 +129,12 @@ export class WorkspacePanelCoordinator {
|
|||
getOpenPanelSnapshots(): OpenCodexPanelSnapshot[] {
|
||||
const leaves = this.panelLeaves();
|
||||
this.ensureInitialFocusedPanel(leaves);
|
||||
return leaves.flatMap((leaf) =>
|
||||
leaf.view instanceof CodexChatView ? [this.openPanelSnapshotWithFocus(workspacePanelSurface(leaf.view).openPanelSnapshot())] : [],
|
||||
);
|
||||
return leaves.flatMap((leaf, index) => {
|
||||
if (leaf.view instanceof CodexChatView)
|
||||
return [this.openPanelSnapshotWithFocus(workspacePanelSurface(leaf.view).openPanelSnapshot())];
|
||||
const restoredSnapshot = restoredPanelSnapshot(leaf, index);
|
||||
return restoredSnapshot ? [restoredSnapshot] : [];
|
||||
});
|
||||
}
|
||||
|
||||
async focusOpenPanel(viewId: string, threadId: string | null = null): Promise<boolean> {
|
||||
|
|
@ -438,3 +441,19 @@ function restoredThreadId(leaf: WorkspaceLeaf): string | null {
|
|||
const threadId = (state as { threadId?: unknown }).threadId;
|
||||
return typeof threadId === "string" && threadId.length > 0 ? threadId : null;
|
||||
}
|
||||
|
||||
function restoredPanelSnapshot(leaf: WorkspaceLeaf, index: number): OpenCodexPanelSnapshot | null {
|
||||
const threadId = restoredThreadId(leaf);
|
||||
if (!threadId) return null;
|
||||
return {
|
||||
viewId: `restored:${String(index)}:${threadId}`,
|
||||
threadId,
|
||||
turnLifecycle: { kind: "idle" },
|
||||
pendingApprovals: 0,
|
||||
pendingUserInputs: 0,
|
||||
pendingMcpElicitations: 0,
|
||||
hasComposerDraft: false,
|
||||
connected: false,
|
||||
lastFocused: false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ describe("threads view renderer decisions", () => {
|
|||
new Map(),
|
||||
)[0]?.live,
|
||||
).toMatchObject({
|
||||
status: "draft",
|
||||
status: "open",
|
||||
});
|
||||
expect(
|
||||
threadRows(
|
||||
|
|
@ -113,7 +113,7 @@ describe("threads view renderer decisions", () => {
|
|||
new Map(),
|
||||
)[0]?.live,
|
||||
).toMatchObject({
|
||||
status: "offline",
|
||||
status: "open",
|
||||
});
|
||||
expect(
|
||||
threadRows(
|
||||
|
|
|
|||
|
|
@ -99,6 +99,24 @@ describe("CodexPanelPlugin workspace panel reconciliation", () => {
|
|||
expect(restoredLeaf.view).toBeInstanceOf(CodexChatView);
|
||||
});
|
||||
|
||||
it("includes deferred restored panels in open panel snapshots", async () => {
|
||||
const restoredLeaf = leaf({ state: { threadId: "thread-1", threadTitle: "Restored thread" } });
|
||||
const plugin = await pluginWithLeaves([restoredLeaf]);
|
||||
|
||||
expect(panels(plugin).getOpenPanelSnapshots()).toMatchObject([
|
||||
{
|
||||
threadId: "thread-1",
|
||||
turnLifecycle: { kind: "idle" },
|
||||
pendingApprovals: 0,
|
||||
pendingUserInputs: 0,
|
||||
pendingMcpElicitations: 0,
|
||||
hasComposerDraft: false,
|
||||
connected: false,
|
||||
lastFocused: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("focuses an already open thread before reusing an empty panel", async () => {
|
||||
const { CodexChatView } = await import("../src/features/chat/host/view");
|
||||
const openLeaf = leaf();
|
||||
|
|
|
|||
Loading…
Reference in a new issue