diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs index 5e3f421f..a9163904 100644 --- a/src-tauri/src/types.rs +++ b/src-tauri/src/types.rs @@ -268,10 +268,21 @@ pub(crate) struct WorkspaceSettings { pub(crate) codex_args: Option, #[serde(default, rename = "launchScript")] pub(crate) launch_script: Option, + #[serde(default, rename = "launchScripts")] + pub(crate) launch_scripts: Option>, #[serde(default, rename = "worktreeSetupScript")] pub(crate) worktree_setup_script: Option, } +#[derive(Debug, Serialize, Deserialize, Clone)] +pub(crate) struct LaunchScriptEntry { + pub(crate) id: String, + pub(crate) script: String, + pub(crate) icon: String, + #[serde(default)] + pub(crate) label: Option, +} + #[derive(Debug, Serialize, Deserialize, Clone)] pub(crate) struct WorktreeSetupStatus { #[serde(rename = "shouldRun")] diff --git a/src-tauri/src/workspaces/tests.rs b/src-tauri/src/workspaces/tests.rs index c0bda742..2e7a6959 100644 --- a/src-tauri/src/workspaces/tests.rs +++ b/src-tauri/src/workspaces/tests.rs @@ -46,6 +46,7 @@ fn workspace_with_id_and_kind( codex_home: None, codex_args: None, launch_script: None, + launch_scripts: None, worktree_setup_script: None, }, } diff --git a/src/App.tsx b/src/App.tsx index 85490fbf..f19840c4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -91,6 +91,7 @@ import { useLiquidGlassEffect } from "./features/app/hooks/useLiquidGlassEffect" import { useCopyThread } from "./features/threads/hooks/useCopyThread"; import { useTerminalController } from "./features/terminal/hooks/useTerminalController"; import { useWorkspaceLaunchScript } from "./features/app/hooks/useWorkspaceLaunchScript"; +import { useWorkspaceLaunchScripts } from "./features/app/hooks/useWorkspaceLaunchScripts"; import { useWorktreeSetupScript } from "./features/app/hooks/useWorktreeSetupScript"; import { useGitCommitController } from "./features/app/hooks/useGitCommitController"; import { WorkspaceHome } from "./features/workspaces/components/WorkspaceHome"; @@ -772,6 +773,23 @@ function MainApp() { activeTerminalId, }); + const launchScriptsState = useWorkspaceLaunchScripts({ + activeWorkspace, + updateWorkspaceSettings, + openTerminal, + ensureLaunchTerminal: (workspaceId, entry, title) => { + const label = entry.label?.trim() || entry.icon; + return ensureTerminalWithTitle( + workspaceId, + `launch:${entry.id}`, + title || `Launch ${label}`, + ); + }, + restartLaunchSession: restartTerminalSession, + terminalState, + activeTerminalId, + }); + const worktreeSetupScriptState = useWorktreeSetupScript({ ensureTerminalWithTitle, restartTerminalSession, @@ -1717,6 +1735,7 @@ function MainApp() { onCloseLaunchScriptEditor: launchScriptState.onCloseEditor, onLaunchScriptDraftChange: launchScriptState.onDraftScriptChange, onSaveLaunchScript: launchScriptState.onSaveLaunchScript, + launchScriptsState, mainHeaderActionsNode: ( void; onDraftChange: (value: string) => void; onSave: () => void; + showNew?: boolean; + newEditorOpen?: boolean; + newDraftScript?: string; + newDraftIcon?: LaunchScriptIconId; + newDraftLabel?: string; + newError?: string | null; + onOpenNew?: () => void; + onCloseNew?: () => void; + onNewDraftChange?: (value: string) => void; + onNewDraftIconChange?: (value: LaunchScriptIconId) => void; + onNewDraftLabelChange?: (value: string) => void; + onCreateNew?: () => void; }; export function LaunchScriptButton({ @@ -25,6 +40,18 @@ export function LaunchScriptButton({ onCloseEditor, onDraftChange, onSave, + showNew = false, + newEditorOpen = false, + newDraftScript = "", + newDraftIcon = DEFAULT_LAUNCH_SCRIPT_ICON, + newDraftLabel = "", + newError = null, + onOpenNew, + onCloseNew, + onNewDraftChange, + onNewDraftIconChange, + onNewDraftLabelChange, + onCreateNew, }: LaunchScriptButtonProps) { const popoverRef = useRef(null); const hasLaunchScript = Boolean(launchScript?.trim()); @@ -39,12 +66,13 @@ export function LaunchScriptButton({ return; } onCloseEditor(); + onCloseNew?.(); }; window.addEventListener("mousedown", handleClick); return () => { window.removeEventListener("mousedown", handleClick); }; - }, [editorOpen, onCloseEditor]); + }, [editorOpen, onCloseEditor, onCloseNew]); return (
@@ -80,11 +108,24 @@ export function LaunchScriptButton({ + {showNew && onOpenNew && ( + + )}
+ {showNew && newEditorOpen && onNewDraftChange && onNewDraftIconChange && onCreateNew && ( +
+
New launch script
+ + onNewDraftLabelChange?.(event.target.value)} + data-tauri-drag-region="false" + /> +