Skip to content

Commit e0a0ddf

Browse files
committed
fix: replace native confirm dialog with React dialog for agent deletion
- Replace synchronous confirm() with proper React Dialog component - Add state management for delete confirmation dialog - Prevent immediate deletion before user confirmation - Add loading states and proper error handling - Improve UX with clear confirmation message and responsive design
1 parent 00cd299 commit e0a0ddf

1 file changed

Lines changed: 85 additions & 4 deletions

File tree

src/components/CCAgents.tsx

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ import {
3030
DropdownMenuItem,
3131
DropdownMenuTrigger,
3232
} from "@/components/ui/dropdown-menu";
33+
import {
34+
Dialog,
35+
DialogContent,
36+
DialogDescription,
37+
DialogFooter,
38+
DialogHeader,
39+
DialogTitle,
40+
} from "@/components/ui/dialog";
3341
import { api, type Agent, type AgentRunWithMetrics } from "@/lib/api";
3442
import { save, open } from "@tauri-apps/plugin-dialog";
3543
import { invoke } from "@tauri-apps/api/core";
@@ -87,6 +95,9 @@ export const CCAgents: React.FC<CCAgentsProps> = ({ onBack, className }) => {
8795
const [selectedAgent, setSelectedAgent] = useState<Agent | null>(null);
8896
const [selectedRunId, setSelectedRunId] = useState<number | null>(null);
8997
const [showGitHubBrowser, setShowGitHubBrowser] = useState(false);
98+
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
99+
const [agentToDelete, setAgentToDelete] = useState<Agent | null>(null);
100+
const [isDeleting, setIsDeleting] = useState(false);
90101

91102
const AGENTS_PER_PAGE = 9; // 3x3 grid
92103

@@ -122,20 +133,46 @@ export const CCAgents: React.FC<CCAgentsProps> = ({ onBack, className }) => {
122133
}
123134
};
124135

125-
const handleDeleteAgent = async (id: number) => {
126-
if (!confirm("Are you sure you want to delete this agent?")) return;
136+
/**
137+
* Initiates the delete agent process by showing the confirmation dialog
138+
* @param agent - The agent to be deleted
139+
*/
140+
const handleDeleteAgent = (agent: Agent) => {
141+
setAgentToDelete(agent);
142+
setShowDeleteDialog(true);
143+
};
144+
145+
/**
146+
* Confirms and executes the agent deletion
147+
* Only called when user explicitly confirms the deletion
148+
*/
149+
const confirmDeleteAgent = async () => {
150+
if (!agentToDelete?.id) return;
127151

128152
try {
129-
await api.deleteAgent(id);
153+
setIsDeleting(true);
154+
await api.deleteAgent(agentToDelete.id);
130155
setToast({ message: "Agent deleted successfully", type: "success" });
131156
await loadAgents();
132157
await loadRuns(); // Reload runs as they might be affected
133158
} catch (err) {
134159
console.error("Failed to delete agent:", err);
135160
setToast({ message: "Failed to delete agent", type: "error" });
161+
} finally {
162+
setIsDeleting(false);
163+
setShowDeleteDialog(false);
164+
setAgentToDelete(null);
136165
}
137166
};
138167

168+
/**
169+
* Cancels the delete operation and closes the dialog
170+
*/
171+
const cancelDeleteAgent = () => {
172+
setShowDeleteDialog(false);
173+
setAgentToDelete(null);
174+
};
175+
139176
const handleEditAgent = (agent: Agent) => {
140177
setSelectedAgent(agent);
141178
setView("edit");
@@ -473,7 +510,7 @@ export const CCAgents: React.FC<CCAgentsProps> = ({ onBack, className }) => {
473510
<Button
474511
size="sm"
475512
variant="ghost"
476-
onClick={() => handleDeleteAgent(agent.id!)}
513+
onClick={() => handleDeleteAgent(agent)}
477514
className="flex items-center gap-1 text-destructive hover:text-destructive"
478515
title="Delete agent"
479516
>
@@ -571,6 +608,50 @@ export const CCAgents: React.FC<CCAgentsProps> = ({ onBack, className }) => {
571608
setToast({ message: "Agent imported successfully from GitHub", type: "success" });
572609
}}
573610
/>
611+
612+
{/* Delete Confirmation Dialog */}
613+
<Dialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
614+
<DialogContent className="sm:max-w-md">
615+
<DialogHeader>
616+
<DialogTitle className="flex items-center gap-2">
617+
<Trash2 className="h-5 w-5 text-destructive" />
618+
Delete Agent
619+
</DialogTitle>
620+
<DialogDescription>
621+
Are you sure you want to delete the agent "{agentToDelete?.name}"?
622+
This action cannot be undone and will permanently remove the agent and all its associated data.
623+
</DialogDescription>
624+
</DialogHeader>
625+
<DialogFooter className="flex flex-col-reverse sm:flex-row sm:justify-end gap-2">
626+
<Button
627+
variant="outline"
628+
onClick={cancelDeleteAgent}
629+
disabled={isDeleting}
630+
className="w-full sm:w-auto"
631+
>
632+
Cancel
633+
</Button>
634+
<Button
635+
variant="destructive"
636+
onClick={confirmDeleteAgent}
637+
disabled={isDeleting}
638+
className="w-full sm:w-auto"
639+
>
640+
{isDeleting ? (
641+
<>
642+
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2" />
643+
Deleting...
644+
</>
645+
) : (
646+
<>
647+
<Trash2 className="h-4 w-4 mr-2" />
648+
Delete Agent
649+
</>
650+
)}
651+
</Button>
652+
</DialogFooter>
653+
</DialogContent>
654+
</Dialog>
574655
</div>
575656
);
576657
};

0 commit comments

Comments
 (0)