diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index b284523c529898593a2e7b0f4dd562db6062232f..a96b17bdb76523656d2ce1ff55cdf2ee037af8d8 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -1621,6 +1621,36 @@ export default function ChatView({ threadId }: ChatViewProps) { }, [activeProject, persistProjectScripts], ); + const deleteProjectScript = useCallback( + async (scriptId: string) => { + if (!activeProject) return; + const nextScripts = activeProject.scripts.filter((script) => script.id !== scriptId); + + const deletedName = activeProject.scripts.find((s) => s.id === scriptId)?.name; + + try { + await persistProjectScripts({ + projectId: activeProject.id, + projectCwd: activeProject.cwd, + previousScripts: activeProject.scripts, + nextScripts, + keybinding: null, + keybindingCommand: commandForProjectScript(scriptId), + }); + toastManager.add({ + type: "success", + title: `Deleted action "${deletedName ?? "Unknown"}"`, + }); + } catch (error) { + toastManager.add({ + type: "error", + title: "Could not delete action", + description: error instanceof Error ? error.message : "An unexpected error occurred.", + }); + } + }, + [activeProject, persistProjectScripts], + ); const handleRuntimeModeChange = useCallback( (mode: RuntimeMode) => { @@ -3428,6 +3458,7 @@ export default function ChatView({ threadId }: ChatViewProps) { }} onAddProjectScript={saveProjectScript} onUpdateProjectScript={updateProjectScript} + onDeleteProjectScript={deleteProjectScript} onToggleDiff={onToggleDiff} /> @@ -4008,6 +4039,7 @@ interface ChatHeaderProps { onRunProjectScript: (script: ProjectScript) => void; onAddProjectScript: (input: NewProjectScriptInput) => Promise; onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise; + onDeleteProjectScript: (scriptId: string) => Promise; onToggleDiff: () => void; } @@ -4027,6 +4059,7 @@ const ChatHeader = memo(function ChatHeader({ onRunProjectScript, onAddProjectScript, onUpdateProjectScript, + onDeleteProjectScript, onToggleDiff, }: ChatHeaderProps) { return ( @@ -4059,6 +4092,7 @@ const ChatHeader = memo(function ChatHeader({ onRunScript={onRunProjectScript} onAddScript={onAddProjectScript} onUpdateScript={onUpdateProjectScript} + onDeleteScript={onDeleteProjectScript} /> )} {activeProjectName && ( diff --git a/apps/web/src/components/ProjectScriptsControl.tsx b/apps/web/src/components/ProjectScriptsControl.tsx index 092f2d598a9ccb391003eecb33f976030c297010..437b3e78ef7f8c98d8ebd30c309d9c1c66f61b6e 100644 --- a/apps/web/src/components/ProjectScriptsControl.tsx +++ b/apps/web/src/components/ProjectScriptsControl.tsx @@ -14,7 +14,7 @@ import { SettingsIcon, WrenchIcon, } from "lucide-react"; -import React, { type FormEvent, type KeyboardEvent, useMemo, useState } from "react"; +import React, { type FormEvent, type KeyboardEvent, useCallback, useMemo, useState } from "react"; import { keybindingValueForCommand, @@ -27,6 +27,15 @@ import { } from "~/projectScripts"; import { shortcutLabelForCommand } from "~/keybindings"; import { isMacPlatform } from "~/lib/utils"; +import { + AlertDialog, + AlertDialogClose, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogPopup, + AlertDialogTitle, +} from "./ui/alert-dialog"; import { Button } from "./ui/button"; import { Dialog, @@ -84,6 +93,7 @@ interface ProjectScriptsControlProps { onRunScript: (script: ProjectScript) => void; onAddScript: (input: NewProjectScriptInput) => Promise | void; onUpdateScript: (scriptId: string, input: NewProjectScriptInput) => Promise | void; + onDeleteScript: (scriptId: string) => Promise | void; } function normalizeShortcutKeyToken(key: string): string | null { @@ -144,6 +154,7 @@ export default function ProjectScriptsControl({ onRunScript, onAddScript, onUpdateScript, + onDeleteScript, }: ProjectScriptsControlProps) { const addScriptFormId = React.useId(); const [editingScriptId, setEditingScriptId] = useState(null); @@ -155,6 +166,7 @@ export default function ProjectScriptsControl({ const [runOnWorktreeCreate, setRunOnWorktreeCreate] = useState(false); const [keybinding, setKeybinding] = useState(""); const [validationError, setValidationError] = useState(null); + const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false); const primaryScript = useMemo(() => { if (preferredScriptId) { @@ -247,6 +259,13 @@ export default function ProjectScriptsControl({ setDialogOpen(true); }; + const confirmDeleteScript = useCallback(() => { + if (!editingScriptId) return; + setDeleteConfirmOpen(false); + setDialogOpen(false); + void onDeleteScript(editingScriptId); + }, [editingScriptId, onDeleteScript]); + return ( <> {primaryScript ? ( @@ -440,6 +459,16 @@ export default function ProjectScriptsControl({ + {isEditing && ( + + )} + + + ); }