This repository was archived by the owner on May 15, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Expand file tree
/
Copy pathDeleteWorktreeModal.tsx
More file actions
140 lines (122 loc) · 4.67 KB
/
Copy pathDeleteWorktreeModal.tsx
File metadata and controls
140 lines (122 loc) · 4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import { useState, useEffect, useCallback } from "react"
import type { Worktree } from "@roo-code/types"
import { vscode } from "@/utils/vscode"
import { useAppTranslation } from "@/i18n/TranslationContext"
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Button, Checkbox } from "@/components/ui"
import { Folder, GitBranch, TriangleAlert } from "lucide-react"
interface DeleteWorktreeModalProps {
open: boolean
onClose: () => void
worktree: Worktree
onSuccess?: () => void
}
export const DeleteWorktreeModal = ({ open, onClose, worktree, onSuccess }: DeleteWorktreeModalProps) => {
const { t } = useAppTranslation()
const [isDeleting, setIsDeleting] = useState(false)
const [forceDeleteLocked, setForceDeleteLocked] = useState(false)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
const message = event.data
if (message.type === "worktreeResult") {
setIsDeleting(false)
if (message.success) {
onSuccess?.()
onClose()
} else {
setError(message.text || "Unknown error")
}
}
}
window.addEventListener("message", handleMessage)
return () => window.removeEventListener("message", handleMessage)
}, [onSuccess, onClose])
const handleDelete = useCallback(() => {
setError(null)
setIsDeleting(true)
// Always force delete unless worktree is locked and user hasn't opted in
const shouldForce = worktree.isLocked ? forceDeleteLocked : true
vscode.postMessage({
type: "deleteWorktree",
worktreePath: worktree.path,
worktreeForce: shouldForce,
})
}, [worktree.path, worktree.isLocked, forceDeleteLocked])
return (
<Dialog open={open} onOpenChange={(isOpen: boolean) => !isOpen && onClose()}>
<DialogContent>
<DialogHeader>
<DialogTitle>{t("worktrees:deleteWorktree")}</DialogTitle>
</DialogHeader>
<div className="flex flex-col gap-3 overflow-hidden">
{/* Worktree info */}
<div className="flex flex-col p-5 gap-2 cursor-default rounded-xl text-vscode-foreground bg-vscode-input-background">
<p className="flex items-center gap-2 m-0">
<GitBranch className="size-4 shrink-0" />
<span className="font-medium truncate">
{worktree.branch ||
(worktree.isDetached ? t("worktrees:detachedHead") : t("worktrees:noBranch"))}
</span>
</p>
<p className="flex items-start gap-2 m-0">
<Folder className="size-4 shrink-0" />
<span className="m-0 text-sm font-mono font-medium text-vscode-descriptionForeground">
{worktree.path}
</span>
</p>
</div>
{/* Warning message */}
<div className="flex items-start gap-2 px-5 py-2">
<TriangleAlert className="size-4 text-vscode-charts-yellow flex-shrink-0" />
<div className="flex flex-col min-w-0 gap-2">
<p className="m-0 text-vscode-foreground">{t("worktrees:deleteWarning")}</p>
<ul className="m-0 pl-0 list-none space-y-1 text-vscode-descriptionForeground">
<li>• {t("worktrees:deleteWarningBranch")}</li>
<li>• {t("worktrees:deleteWarningFiles")}</li>
</ul>
<p className="m-0 text-vscode-descriptionForeground">{t("worktrees:deleteNoticeLarge")}</p>
</div>
</div>
{/* Force delete option (only shown if worktree is locked) */}
{worktree.isLocked && (
<div className="flex items-center gap-2">
<Checkbox
id="force-delete"
checked={forceDeleteLocked}
onCheckedChange={(checked) => setForceDeleteLocked(checked === true)}
/>
<label htmlFor="force-delete" className="text-sm text-vscode-foreground cursor-pointer">
{t("worktrees:forceDelete")}
<span className="text-vscode-descriptionForeground ml-1">
({t("worktrees:worktreeIsLocked")})
</span>
</label>
</div>
)}
{/* Error message */}
{error && (
<div className="flex items-center gap-2 px-2 py-1.5 rounded bg-vscode-inputValidation-errorBackground border border-vscode-inputValidation-errorBorder text-sm">
<span className="codicon codicon-error text-vscode-errorForeground flex-shrink-0" />
<p className="text-vscode-errorForeground">{error}</p>
</div>
)}
</div>
<DialogFooter>
<Button variant="secondary" onClick={onClose}>
{t("worktrees:cancel")}
</Button>
<Button variant="destructive" onClick={handleDelete} disabled={isDeleting}>
{isDeleting ? (
<>
<span className="codicon codicon-loading codicon-modifier-spin mr-2" />
{t("worktrees:deleting")}
</>
) : (
t("worktrees:delete")
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}