| author | |
| committer | |
| log | 63b6b44627d605afba7ec2549f817c23c0f903ad |
| tree | 37b410113e6ce03dc2b7c2c9ee6a6a6de196fe27 |
| parent | 3795dbb01723d7474db8ddf805b1f64d5b56919c |
| signature | Signed by PGP key B5690EEEBB952194 |
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"; | ... | @@ -145,6 +145,7 @@ import { stackedThreadToast, toastManager } from "./ui/toast"; |
| 145 | import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings"; | 145 | import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings"; |
| 146 | import { type NewProjectScriptInput } from "./ProjectScriptsControl"; | 146 | import { type NewProjectScriptInput } from "./ProjectScriptsControl"; |
| 147 | import { | 147 | import { |
| 148 | buildProjectScript, | ||
| 148 | commandForProjectScript, | 149 | commandForProjectScript, |
| 149 | nextProjectScriptId, | 150 | nextProjectScriptId, |
| 150 | projectScriptIdFromCommand, | 151 | projectScriptIdFromCommand, |
| ... | @@ -2752,13 +2753,7 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -2752,13 +2753,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 2752 | input.name, | 2753 | input.name, |
| 2753 | activeProject.scripts.map((script) => script.id), | 2754 | activeProject.scripts.map((script) => script.id), |
| 2754 | ); | 2755 | ); |
| 2755 | const nextScript: ProjectScript = { | 2756 | const nextScript = buildProjectScript(nextId, input); |
| 2756 | id: nextId, | ||
| 2757 | name: input.name, | ||
| 2758 | command: input.command, | ||
| 2759 | icon: input.icon, | ||
| 2760 | runOnWorktreeCreate: input.runOnWorktreeCreate, | ||
| 2761 | }; | ||
| 2762 | const nextScripts = input.runOnWorktreeCreate | 2757 | const nextScripts = input.runOnWorktreeCreate |
| 2763 | ? [ | 2758 | ? [ |
| 2764 | ...activeProject.scripts.map((script) => | 2759 | ...activeProject.scripts.map((script) => |
| ... | @@ -2792,13 +2787,7 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -2792,13 +2787,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 2792 | return AsyncResult.failure(Cause.fail(new Error("Script not found."))); | 2787 | return AsyncResult.failure(Cause.fail(new Error("Script not found."))); |
| 2793 | } | 2788 | } |
| 2794 | 2789 | ||
| 2795 | const updatedScript: ProjectScript = { | 2790 | const updatedScript = buildProjectScript(existingScript.id, input); |
| 2796 | ...existingScript, | ||
| 2797 | name: input.name, | ||
| 2798 | command: input.command, | ||
| 2799 | icon: input.icon, | ||
| 2800 | runOnWorktreeCreate: input.runOnWorktreeCreate, | ||
| 2801 | }; | ||
| 2802 | const nextScripts = activeProject.scripts.map((script) => | 2791 | const nextScripts = activeProject.scripts.map((script) => |
| 2803 | script.id === scriptId | 2792 | script.id === scriptId |
| 2804 | ? updatedScript | 2793 | ? updatedScript |
apps/web/src/projectScripts.test.ts+41| ... | @@ -6,6 +6,7 @@ import { | ... | @@ -6,6 +6,7 @@ import { |
| 6 | } from "@t3tools/shared/projectScripts"; | 6 | } from "@t3tools/shared/projectScripts"; |
| 7 | 7 | ||
| 8 | import { | 8 | import { |
| 9 | buildProjectScript, | ||
| 9 | commandForProjectScript, | 10 | commandForProjectScript, |
| 10 | nextProjectScriptId, | 11 | nextProjectScriptId, |
| 11 | primaryProjectScript, | 12 | primaryProjectScript, |
| ... | @@ -13,6 +14,46 @@ import { | ... | @@ -13,6 +14,46 @@ import { |
| 13 | } from "./projectScripts"; | 14 | } from "./projectScripts"; |
| 14 | 15 | ||
| 15 | describe("projectScripts helpers", () => { | 16 | describe("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 | |||
| 16 | it("builds and parses script run commands", () => { | 57 | it("builds and parses script run commands", () => { |
| 17 | const command = commandForProjectScript("lint"); | 58 | const command = commandForProjectScript("lint"); |
| 18 | expect(command).toBe("script.lint.run"); | 59 | expect(command).toBe("script.lint.run"); |
apps/web/src/projectScripts.ts+25| ... | @@ -7,6 +7,31 @@ import { | ... | @@ -7,6 +7,31 @@ import { |
| 7 | import * as Schema from "effect/Schema"; | 7 | import * as Schema from "effect/Schema"; |
| 8 | const isScriptRunCommand = Schema.is(SCRIPT_RUN_COMMAND_PATTERN); | 8 | const isScriptRunCommand = Schema.is(SCRIPT_RUN_COMMAND_PATTERN); |
| 9 | 9 | ||
| 10 | export 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 | |||
| 19 | export 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 | |||
| 10 | function normalizeScriptId(value: string): string { | 35 | function normalizeScriptId(value: string): string { |
| 11 | const cleaned = value | 36 | const cleaned = value |
| 12 | .trim() | 37 | .trim() |