authorgravatar for 6238600+keeperxy@users.noreply.github.comcoach007 <6238600+keeperxy@users.noreply.github.com> 2026-07-20 10:32:14+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-20 08:32:14+00:00
log63b6b44627d605afba7ec2549f817c23c0f903ad
tree37b410113e6ce03dc2b7c2c9ee6a6a6de196fe27
parent3795dbb01723d7474db8ddf805b1f64d5b56919c
signature Signed by PGP key B5690EEEBB952194

Fix project action preview settings persistence (#3842)


3 files changed, 69 insertions(+), 14 deletions(-)

apps/web/src/components/ChatView.tsx+3-14
......@@ -145,6 +145,7 @@ import { stackedThreadToast, toastManager } from "./ui/toast";
145145import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings";
146146import { type NewProjectScriptInput } from "./ProjectScriptsControl";
147147import {
148 buildProjectScript,
148149 commandForProjectScript,
149150 nextProjectScriptId,
150151 projectScriptIdFromCommand,
......@@ -2752,13 +2753,7 @@ function ChatViewContent(props: ChatViewProps) {
27522753 input.name,
27532754 activeProject.scripts.map((script) => script.id),
27542755 );
2755 const nextScript: ProjectScript = {
2756 id: nextId,
2757 name: input.name,
2758 command: input.command,
2759 icon: input.icon,
2760 runOnWorktreeCreate: input.runOnWorktreeCreate,
2761 };
2756 const nextScript = buildProjectScript(nextId, input);
27622757 const nextScripts = input.runOnWorktreeCreate
27632758 ? [
27642759 ...activeProject.scripts.map((script) =>
......@@ -2792,13 +2787,7 @@ function ChatViewContent(props: ChatViewProps) {
27922787 return AsyncResult.failure(Cause.fail(new Error("Script not found.")));
27932788 }
27942789
2795 const updatedScript: ProjectScript = {
2796 ...existingScript,
2797 name: input.name,
2798 command: input.command,
2799 icon: input.icon,
2800 runOnWorktreeCreate: input.runOnWorktreeCreate,
2801 };
2790 const updatedScript = buildProjectScript(existingScript.id, input);
28022791 const nextScripts = activeProject.scripts.map((script) =>
28032792 script.id === scriptId
28042793 ? updatedScript
apps/web/src/projectScripts.test.ts+41
......@@ -6,6 +6,7 @@ import {
66} from "@t3tools/shared/projectScripts";
77
88import {
9 buildProjectScript,
910 commandForProjectScript,
1011 nextProjectScriptId,
1112 primaryProjectScript,
......@@ -13,6 +14,46 @@ import {
1314} from "./projectScripts";
1415
1516describe("projectScripts helpers", () => {
17 it("builds scripts with preview settings", () => {
18 expect(
19 buildProjectScript("dev", {
20 name: "Dev server",
21 command: "pnpm dev",
22 icon: "debug",
23 runOnWorktreeCreate: false,
24 previewUrl: "http://localhost:5733",
25 autoOpenPreview: true,
26 }),
27 ).toEqual({
28 id: "dev",
29 name: "Dev server",
30 command: "pnpm dev",
31 icon: "debug",
32 runOnWorktreeCreate: false,
33 previewUrl: "http://localhost:5733",
34 autoOpenPreview: true,
35 });
36 });
37
38 it("omits preview settings when no preview URL is configured", () => {
39 expect(
40 buildProjectScript("test", {
41 name: "Test",
42 command: "pnpm test",
43 icon: "test",
44 runOnWorktreeCreate: false,
45 previewUrl: null,
46 autoOpenPreview: false,
47 }),
48 ).toEqual({
49 id: "test",
50 name: "Test",
51 command: "pnpm test",
52 icon: "test",
53 runOnWorktreeCreate: false,
54 });
55 });
56
1657 it("builds and parses script run commands", () => {
1758 const command = commandForProjectScript("lint");
1859 expect(command).toBe("script.lint.run");
apps/web/src/projectScripts.ts+25
......@@ -7,6 +7,31 @@ import {
77import * as Schema from "effect/Schema";
88const isScriptRunCommand = Schema.is(SCRIPT_RUN_COMMAND_PATTERN);
99
10export interface ProjectScriptInput {
11 readonly name: ProjectScript["name"];
12 readonly command: ProjectScript["command"];
13 readonly icon: ProjectScript["icon"];
14 readonly runOnWorktreeCreate: ProjectScript["runOnWorktreeCreate"];
15 readonly previewUrl: Exclude<ProjectScript["previewUrl"], undefined> | null;
16 readonly autoOpenPreview: boolean;
17}
18
19export function buildProjectScript(id: string, input: ProjectScriptInput): ProjectScript {
20 return {
21 id,
22 name: input.name,
23 command: input.command,
24 icon: input.icon,
25 runOnWorktreeCreate: input.runOnWorktreeCreate,
26 ...(input.previewUrl === null
27 ? {}
28 : {
29 previewUrl: input.previewUrl,
30 autoOpenPreview: input.autoOpenPreview,
31 }),
32 };
33}
34
1035function normalizeScriptId(value: string): string {
1136 const cleaned = value
1237 .trim()