Archived
feat: add delete new session action
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@jmfederico/pi-web": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Add an action-palette command for deleting browser-cached new sessions, while keeping archive and delete session actions context-specific.
|
||||||
@@ -862,6 +862,7 @@ export class PiWebApp extends LitElement {
|
|||||||
deleteWorkspace: (workspace) => this.deleteWorkspace(workspace),
|
deleteWorkspace: (workspace) => this.deleteWorkspace(workspace),
|
||||||
startSession: () => this.withChatScrollTransition(() => this.sessions.startSession()),
|
startSession: () => this.withChatScrollTransition(() => this.sessions.startSession()),
|
||||||
archiveSession: () => this.sessions.archiveSession(),
|
archiveSession: () => this.sessions.archiveSession(),
|
||||||
|
deleteCachedNewSession: () => this.sessions.deleteCachedNewSession(),
|
||||||
stopActiveWork: () => this.sessions.stopActiveWork(),
|
stopActiveWork: () => this.sessions.stopActiveWork(),
|
||||||
}, createContext);
|
}, createContext);
|
||||||
return createContext("core");
|
return createContext("core");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { isSessionActive } from "../../../../shared/activity";
|
import { isSessionActive } from "../../../../shared/activity";
|
||||||
import type { AppState } from "../../appState";
|
import type { AppState } from "../../appState";
|
||||||
|
import { isCachedNewSessionInfo } from "../../cachedNewSessions";
|
||||||
import { isWorkspaceDeletionPending } from "../../workspaceDeletion";
|
import { isWorkspaceDeletionPending } from "../../workspaceDeletion";
|
||||||
import type { PluginAction } from "../types";
|
import type { PluginAction } from "../types";
|
||||||
|
|
||||||
@@ -138,9 +139,17 @@ export function createCoreActions(): PluginAction[] {
|
|||||||
title: "Archive Session",
|
title: "Archive Session",
|
||||||
description: "Archive the selected session",
|
description: "Archive the selected session",
|
||||||
group: "Session",
|
group: "Session",
|
||||||
enabled: (context) => context.state.selectedSession !== undefined && context.state.selectedSession.archived !== true,
|
enabled: hasArchivableSession,
|
||||||
run: (context) => context.archiveSession(),
|
run: (context) => context.archiveSession(),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "session.delete",
|
||||||
|
title: "Delete New Session",
|
||||||
|
description: "Delete the selected browser-cached new session",
|
||||||
|
group: "Session",
|
||||||
|
enabled: hasCachedNewSession,
|
||||||
|
run: (context) => context.deleteCachedNewSession(),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "session.stop",
|
id: "session.stop",
|
||||||
title: "Stop Active Work",
|
title: "Stop Active Work",
|
||||||
@@ -164,3 +173,12 @@ function hasDeletableWorkspace(context: { state: AppState }): boolean {
|
|||||||
const workspace = context.state.selectedWorkspace;
|
const workspace = context.state.selectedWorkspace;
|
||||||
return workspace !== undefined && workspace.isGitWorktree && !workspace.isMain && !isWorkspaceDeletionPending(context.state, workspace);
|
return workspace !== undefined && workspace.isGitWorktree && !workspace.isMain && !isWorkspaceDeletionPending(context.state, workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasArchivableSession(context: { state: AppState }): boolean {
|
||||||
|
const session = context.state.selectedSession;
|
||||||
|
return session !== undefined && session.archived !== true && !isCachedNewSessionInfo(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasCachedNewSession(context: { state: AppState }): boolean {
|
||||||
|
return isCachedNewSessionInfo(context.state.selectedSession);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import type { Workspace } from "../api";
|
import type { SessionInfo, Workspace } from "../api";
|
||||||
import { initialAppState, type AppState } from "../appState";
|
import { initialAppState, type AppState } from "../appState";
|
||||||
|
import { markCachedNewSessionInfo } from "../cachedNewSessions";
|
||||||
import { corePlugin } from "./core";
|
import { corePlugin } from "./core";
|
||||||
import { PluginRegistry } from "./registry";
|
import { PluginRegistry } from "./registry";
|
||||||
import { themePackPlugin } from "./themes";
|
import { themePackPlugin } from "./themes";
|
||||||
@@ -34,6 +35,7 @@ function createContext(statePatch: Partial<AppState> = {}) {
|
|||||||
deleteWorkspace: vi.fn(() => { calls.push("deleteWorkspace"); }),
|
deleteWorkspace: vi.fn(() => { calls.push("deleteWorkspace"); }),
|
||||||
startSession: vi.fn(() => { calls.push("startSession"); }),
|
startSession: vi.fn(() => { calls.push("startSession"); }),
|
||||||
archiveSession: vi.fn(() => { calls.push("archiveSession"); }),
|
archiveSession: vi.fn(() => { calls.push("archiveSession"); }),
|
||||||
|
deleteCachedNewSession: vi.fn(() => { calls.push("deleteCachedNewSession"); }),
|
||||||
stopActiveWork: vi.fn(() => { calls.push("stopActiveWork"); }),
|
stopActiveWork: vi.fn(() => { calls.push("stopActiveWork"); }),
|
||||||
};
|
};
|
||||||
return { context, calls };
|
return { context, calls };
|
||||||
@@ -98,6 +100,34 @@ describe("PluginRegistry", () => {
|
|||||||
expect(calls).toEqual(["deleteWorkspace"]);
|
expect(calls).toEqual(["deleteWorkspace"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("offers archive only for persisted sessions and delete only for browser-cached new sessions", () => {
|
||||||
|
const registry = new PluginRegistry();
|
||||||
|
registry.register({ id: "core", plugin: corePlugin });
|
||||||
|
|
||||||
|
const persistedActions = registry.getActions(createContext({ selectedSession: testSession() }).context);
|
||||||
|
expect(persistedActions.find((action) => action.id === "core:session.archive")?.enabled).toBe(true);
|
||||||
|
expect(persistedActions.find((action) => action.id === "core:session.delete")?.enabled).toBe(false);
|
||||||
|
|
||||||
|
const cachedActions = registry.getActions(createContext({ selectedSession: markCachedNewSessionInfo(testSession()) }).context);
|
||||||
|
expect(cachedActions.find((action) => action.id === "core:session.archive")?.enabled).toBe(false);
|
||||||
|
expect(cachedActions.find((action) => action.id === "core:session.delete")?.enabled).toBe(true);
|
||||||
|
|
||||||
|
const archivedActions = registry.getActions(createContext({ selectedSession: { ...testSession(), archived: true, archivedAt: "2026-05-20T00:00:00.000Z" } }).context);
|
||||||
|
expect(archivedActions.find((action) => action.id === "core:session.archive")?.enabled).toBe(false);
|
||||||
|
expect(archivedActions.find((action) => action.id === "core:session.delete")?.enabled).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes browser-cached new session delete through the runtime context", () => {
|
||||||
|
const registry = new PluginRegistry();
|
||||||
|
registry.register({ id: "core", plugin: corePlugin });
|
||||||
|
const { context, calls } = createContext({ selectedSession: markCachedNewSessionInfo(testSession()) });
|
||||||
|
const action = registry.getActions(context).find((candidate) => candidate.id === "core:session.delete");
|
||||||
|
|
||||||
|
if (action !== undefined) void action.run();
|
||||||
|
|
||||||
|
expect(calls).toEqual(["deleteCachedNewSession"]);
|
||||||
|
});
|
||||||
|
|
||||||
it("routes refresh current to the active core workspace panel", () => {
|
it("routes refresh current to the active core workspace panel", () => {
|
||||||
const registry = new PluginRegistry();
|
const registry = new PluginRegistry();
|
||||||
registry.register({ id: "core", plugin: corePlugin });
|
registry.register({ id: "core", plugin: corePlugin });
|
||||||
@@ -233,6 +263,19 @@ function testWorkspace(patch: Partial<Workspace> = {}): Workspace {
|
|||||||
return { id: "w1", projectId: "p1", path: "/tmp/project", label: "main", isMain: true, isGitRepo: true, isGitWorktree: false, ...patch };
|
return { id: "w1", projectId: "p1", path: "/tmp/project", label: "main", isMain: true, isGitRepo: true, isGitWorktree: false, ...patch };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testSession(patch: Partial<SessionInfo> = {}): SessionInfo {
|
||||||
|
return {
|
||||||
|
id: "s1",
|
||||||
|
path: "/tmp/s1.jsonl",
|
||||||
|
cwd: "/tmp/project",
|
||||||
|
created: "2026-05-20T00:00:00.000Z",
|
||||||
|
modified: "2026-05-20T00:00:00.000Z",
|
||||||
|
messageCount: 1,
|
||||||
|
firstMessage: "Hello",
|
||||||
|
...patch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function testThemeTokens(): ThemeTokens {
|
function testThemeTokens(): ThemeTokens {
|
||||||
return {
|
return {
|
||||||
"--pi-bg": "#000000",
|
"--pi-bg": "#000000",
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export interface PluginRuntimeContext {
|
|||||||
deleteWorkspace: (workspace?: Workspace) => void | Promise<void>;
|
deleteWorkspace: (workspace?: Workspace) => void | Promise<void>;
|
||||||
startSession: () => void | Promise<void>;
|
startSession: () => void | Promise<void>;
|
||||||
archiveSession: () => void | Promise<void>;
|
archiveSession: () => void | Promise<void>;
|
||||||
|
deleteCachedNewSession: () => void | Promise<void>;
|
||||||
stopActiveWork: () => void | Promise<void>;
|
stopActiveWork: () => void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user