Open History to see the last commit
1import { type ProjectMutation } from "@t3tools/contracts";
2import * as Effect from "effect/Effect";
3
4import { type ProjectCloneTracker } from "./ProjectCloneTracker.ts";
5import { type ProjectService } from "./ProjectService.ts";
6
7type ProjectMutations = Pick<ProjectService["Service"], "create" | "delete" | "update">;
8
9export const projectMutationOperation = Effect.fn("projectMutationOperation")(function* (
10 projects: ProjectMutations,
11 mutation: ProjectMutation,
12) {
13 switch (mutation.type) {
14 case "project.create":
15 return yield* projects.create({
16 commandId: mutation.commandId,
17 projectId: mutation.projectId,
18 title: mutation.title,
19 workspaceRoot: mutation.workspaceRoot,
20 ...(mutation.createWorkspaceRootIfMissing === undefined
21 ? {}
22 : { createWorkspaceRootIfMissing: mutation.createWorkspaceRootIfMissing }),
23 ...(mutation.defaultModelSelection === undefined
24 ? {}
25 : { defaultModelSelection: mutation.defaultModelSelection }),
26 ...(mutation.scripts === undefined ? {} : { scripts: mutation.scripts }),
27 });
28
29 case "project.update":
30 return yield* projects.update({
31 commandId: mutation.commandId,
32 projectId: mutation.projectId,
33 ...(mutation.title === undefined ? {} : { title: mutation.title }),
34 ...(mutation.workspaceRoot === undefined ? {} : { workspaceRoot: mutation.workspaceRoot }),
35 ...(mutation.defaultModelSelection === undefined
36 ? {}
37 : { defaultModelSelection: mutation.defaultModelSelection }),
38 ...(mutation.autoPull === undefined ? {} : { autoPull: mutation.autoPull }),
39 ...(mutation.projectIcon === undefined ? {} : { projectIcon: mutation.projectIcon }),
40 ...(mutation.faviconPath === undefined ? {} : { faviconPath: mutation.faviconPath }),
41 ...(mutation.defaultThreadEnvMode === undefined
42 ? {}
43 : { defaultThreadEnvMode: mutation.defaultThreadEnvMode }),
44 ...(mutation.scripts === undefined ? {} : { scripts: mutation.scripts }),
45 ...(mutation.pinned === undefined ? {} : { pinned: mutation.pinned }),
46 ...(mutation.archived === undefined ? {} : { archived: mutation.archived }),
47 });
48
49 case "project.delete":
50 return yield* projects.delete({
51 commandId: mutation.commandId,
52 projectId: mutation.projectId,
53 ...(mutation.force === undefined ? {} : { force: mutation.force }),
54 });
55 }
56});
57
58// A disconnect after deletion commits must not leave the in-memory clone record behind.
59export const mutateProjectWithClone = Effect.fn("mutateProjectWithClone")(function* (
60 projects: ProjectMutations,
61 clones: Pick<ProjectCloneTracker["Service"], "discard">,
62 mutation: ProjectMutation,
63) {
64 if (mutation.type !== "project.delete")
65 return yield* projectMutationOperation(projects, mutation);
66 return yield* projectMutationOperation(projects, mutation).pipe(
67 Effect.tap(() => clones.discard(mutation.projectId)),
68 Effect.uninterruptible,
69 );
70});