Add archive session app action

This commit is contained in:
Federico Jaramillo Martinez
2026-05-08 15:19:31 +02:00
parent 6dc8dc6029
commit b0eac4157e
3 changed files with 33 additions and 1 deletions
+22 -1
View File
@@ -1,6 +1,7 @@
import { describe, expect, it, vi } from "vitest"; import { describe, expect, it, vi } from "vitest";
import { createAppActions } from "./appActions"; import { createAppActions } from "./appActions";
import { initialAppState, type AppState } from "./appState"; import { initialAppState, type AppState } from "./appState";
import type { SessionInfo } from "./api";
function createContext(statePatch: Partial<AppState> = {}) { function createContext(statePatch: Partial<AppState> = {}) {
const calls: string[] = []; const calls: string[] = [];
@@ -13,6 +14,7 @@ function createContext(statePatch: Partial<AppState> = {}) {
refreshFiles: vi.fn(() => { calls.push("refreshFiles"); }), refreshFiles: vi.fn(() => { calls.push("refreshFiles"); }),
refreshGit: vi.fn(() => { calls.push("refreshGit"); }), refreshGit: vi.fn(() => { calls.push("refreshGit"); }),
startSession: vi.fn(() => { calls.push("startSession"); }), startSession: vi.fn(() => { calls.push("startSession"); }),
archiveSession: vi.fn(() => { calls.push("archiveSession"); }),
stopActiveWork: vi.fn(() => { calls.push("stopActiveWork"); }), stopActiveWork: vi.fn(() => { calls.push("stopActiveWork"); }),
}; };
return { context, calls }; return { context, calls };
@@ -25,6 +27,7 @@ describe("createAppActions", () => {
expect(actions.find((action) => action.id === "view.files")?.enabled).toBe(false); expect(actions.find((action) => action.id === "view.files")?.enabled).toBe(false);
expect(actions.find((action) => action.id === "session.start")?.enabled).toBe(false); expect(actions.find((action) => action.id === "session.start")?.enabled).toBe(false);
expect(actions.find((action) => action.id === "session.archive")?.enabled).toBe(false);
expect(actions.find((action) => action.id === "session.stop")?.enabled).toBe(false); expect(actions.find((action) => action.id === "session.stop")?.enabled).toBe(false);
expect(actions.find((action) => action.id === "actions.show")?.enabled).toBeUndefined(); expect(actions.find((action) => action.id === "actions.show")?.enabled).toBeUndefined();
}); });
@@ -49,6 +52,24 @@ describe("createAppActions", () => {
expect(calls).toEqual(["refreshGit"]); expect(calls).toEqual(["refreshGit"]);
}); });
it("enables archive for the selected active session", () => {
const selectedSession = testSession();
const active = createAppActions(createContext({ selectedSession }).context);
const archived = createAppActions(createContext({ selectedSession: { ...selectedSession, archived: true } }).context);
expect(active.find((action) => action.id === "session.archive")?.enabled).toBe(true);
expect(archived.find((action) => action.id === "session.archive")?.enabled).toBe(false);
});
it("runs archive on the selected session", () => {
const { context, calls } = createContext({ selectedSession: testSession() });
const action = createAppActions(context).find((candidate) => candidate.id === "session.archive");
if (action !== undefined) void action.run();
expect(calls).toEqual(["archiveSession"]);
});
it("only enables stop while a session is actively working", () => { it("only enables stop while a session is actively working", () => {
const selectedSession = testSession(); const selectedSession = testSession();
const inactive = createAppActions(createContext({ selectedSession }).context); const inactive = createAppActions(createContext({ selectedSession }).context);
@@ -63,7 +84,7 @@ function testWorkspace(): AppState["selectedWorkspace"] {
return { id: "w1", projectId: "p1", path: "/tmp/project", label: "main", isMain: true, isGitWorktree: false }; return { id: "w1", projectId: "p1", path: "/tmp/project", label: "main", isMain: true, isGitWorktree: false };
} }
function testSession(): AppState["selectedSession"] { function testSession(): SessionInfo {
return { id: "s1", path: "/tmp/project/.pi/sessions/s1", cwd: "/tmp/project", created: "now", modified: "now", messageCount: 0, firstMessage: "" }; return { id: "s1", path: "/tmp/project/.pi/sessions/s1", cwd: "/tmp/project", created: "now", modified: "now", messageCount: 0, firstMessage: "" };
} }
+10
View File
@@ -10,12 +10,14 @@ export interface AppActionContext {
refreshFiles: () => void | Promise<void>; refreshFiles: () => void | Promise<void>;
refreshGit: () => void | Promise<void>; refreshGit: () => void | Promise<void>;
startSession: () => void | Promise<void>; startSession: () => void | Promise<void>;
archiveSession: () => void | Promise<void>;
stopActiveWork: () => void | Promise<void>; stopActiveWork: () => void | Promise<void>;
} }
export function createAppActions(context: AppActionContext): AppAction[] { export function createAppActions(context: AppActionContext): AppAction[] {
const hasWorkspace = context.state.selectedWorkspace !== undefined; const hasWorkspace = context.state.selectedWorkspace !== undefined;
const hasSession = context.state.selectedSession !== undefined; const hasSession = context.state.selectedSession !== undefined;
const canArchiveSession = hasSession && context.state.selectedSession?.archived !== true;
const isBusy = isActive(context.state.status); const isBusy = isActive(context.state.status);
return [ return [
{ {
@@ -95,6 +97,14 @@ export function createAppActions(context: AppActionContext): AppAction[] {
enabled: hasWorkspace, enabled: hasWorkspace,
run: context.startSession, run: context.startSession,
}, },
{
id: "session.archive",
title: "Archive Session",
description: "Archive the selected session",
group: "Session",
enabled: canArchiveSession,
run: context.archiveSession,
},
{ {
id: "session.stop", id: "session.stop",
title: "Stop Active Work", title: "Stop Active Work",
+1
View File
@@ -187,6 +187,7 @@ export class PiWebApp extends LitElement {
refreshFiles: () => this.files.refreshFiles(), refreshFiles: () => this.files.refreshFiles(),
refreshGit: () => this.git.refreshGit(), refreshGit: () => this.git.refreshGit(),
startSession: () => this.withChatScrollTransition(() => this.sessions.startSession()), startSession: () => this.withChatScrollTransition(() => this.sessions.startSession()),
archiveSession: () => this.sessions.archiveSession(),
stopActiveWork: () => this.sessions.stopActiveWork(), stopActiveWork: () => this.sessions.stopActiveWork(),
}); });
} }