| 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 | 145 | import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings"; |
| 146 | 146 | import { type NewProjectScriptInput } from "./ProjectScriptsControl"; |
| 147 | 147 | import { |
| 148 | buildProjectScript, | |
| 148 | 149 | commandForProjectScript, |
| 149 | 150 | nextProjectScriptId, |
| 150 | 151 | projectScriptIdFromCommand, |
| ... | ... | @@ -2752,13 +2753,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 2752 | 2753 | input.name, |
| 2753 | 2754 | activeProject.scripts.map((script) => script.id), |
| 2754 | 2755 | ); |
| 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); | |
| 2762 | 2757 | const nextScripts = input.runOnWorktreeCreate |
| 2763 | 2758 | ? [ |
| 2764 | 2759 | ...activeProject.scripts.map((script) => |
| ... | ... | @@ -2792,13 +2787,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 2792 | 2787 | return AsyncResult.failure(Cause.fail(new Error("Script not found."))); |
| 2793 | 2788 | } |
| 2794 | 2789 | |
| 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); | |
| 2802 | 2791 | const nextScripts = activeProject.scripts.map((script) => |
| 2803 | 2792 | script.id === scriptId |
| 2804 | 2793 | ? updatedScript |
apps/web/src/projectScripts.test.ts+41| ... | ... | @@ -6,6 +6,7 @@ import { |
| 6 | 6 | } from "@t3tools/shared/projectScripts"; |
| 7 | 7 | |
| 8 | 8 | import { |
| 9 | buildProjectScript, | |
| 9 | 10 | commandForProjectScript, |
| 10 | 11 | nextProjectScriptId, |
| 11 | 12 | primaryProjectScript, |
| ... | ... | @@ -13,6 +14,46 @@ import { |
| 13 | 14 | } from "./projectScripts"; |
| 14 | 15 | |
| 15 | 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 | 57 | it("builds and parses script run commands", () => { |
| 17 | 58 | const command = commandForProjectScript("lint"); |
| 18 | 59 | expect(command).toBe("script.lint.run"); |
apps/web/src/projectScripts.ts+25| ... | ... | @@ -7,6 +7,31 @@ import { |
| 7 | 7 | import * as Schema from "effect/Schema"; |
| 8 | 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 | 35 | function normalizeScriptId(value: string): string { |
| 11 | 36 | const cleaned = value |
| 12 | 37 | .trim() |