From 4aeca68a7e2f6b9169699b7e889aa051e40c4226 Mon Sep 17 00:00:00 2001 From: Mubin Ansari Date: Sat, 7 Mar 2026 07:07:24 +0530 Subject: [PATCH] Add delete option for project actions Adds a delete button to the action edit dialog with a confirmation alert. Fixes pingdotgg/t3code#208. --- apps/web/src/components/ChatView.tsx | 34 ++++++++++++++ .../src/components/ProjectScriptsControl.tsx | 46 ++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 46231694d2..1ef9745693 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -1580,6 +1580,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) => { @@ -3338,6 +3368,7 @@ export default function ChatView({ threadId }: ChatViewProps) { }} onAddProjectScript={saveProjectScript} onUpdateProjectScript={updateProjectScript} + onDeleteProjectScript={deleteProjectScript} onToggleDiff={onToggleDiff} /> @@ -3914,6 +3945,7 @@ interface ChatHeaderProps { onRunProjectScript: (script: ProjectScript) => void; onAddProjectScript: (input: NewProjectScriptInput) => Promise; onUpdateProjectScript: (scriptId: string, input: NewProjectScriptInput) => Promise; + onDeleteProjectScript: (scriptId: string) => Promise; onToggleDiff: () => void; } @@ -3932,6 +3964,7 @@ const ChatHeader = memo(function ChatHeader({ onRunProjectScript, onAddProjectScript, onUpdateProjectScript, + onDeleteProjectScript, onToggleDiff, }: ChatHeaderProps) { return ( @@ -3959,6 +3992,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 092f2d598a..437b3e78ef 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 && ( + + )} + + + ); }