mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix: improve delete worktree failure toast messages (#319)
- Show user-friendly guidance instead of raw git stderr when worktree deletion fails due to changed files, directing users to Force Delete. - Extract toast message logic to reusable getDeleteWorktreeToastCopy function with comprehensive test coverage.
This commit is contained in:
@@ -11,6 +11,7 @@ import { Button } from '@/components/ui/button'
|
||||
import { AlertTriangle, LoaderCircle, Trash2 } from 'lucide-react'
|
||||
import { useAppStore } from '@/store'
|
||||
import { toast } from 'sonner'
|
||||
import { getDeleteWorktreeToastCopy } from './delete-worktree-toast'
|
||||
|
||||
const DeleteWorktreeDialog = React.memo(function DeleteWorktreeDialog() {
|
||||
const activeModal = useAppStore((s) => s.activeModal)
|
||||
@@ -32,6 +33,7 @@ const DeleteWorktreeDialog = React.memo(function DeleteWorktreeDialog() {
|
||||
const isDeleting = deleteState?.isDeleting ?? false
|
||||
const deleteError = deleteState?.error ?? null
|
||||
const canForceDelete = deleteState?.canForceDelete ?? false
|
||||
const worktreeName = worktree?.displayName ?? 'unknown'
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && worktreeId && !worktree && !isDeleting) {
|
||||
@@ -66,8 +68,14 @@ const DeleteWorktreeDialog = React.memo(function DeleteWorktreeDialog() {
|
||||
.then((result) => {
|
||||
if (!result.ok) {
|
||||
const state = useAppStore.getState().deleteStateByWorktreeId[targetWorktreeId]
|
||||
toast.error('Failed to delete worktree', {
|
||||
description: result.error,
|
||||
const toastCopy = getDeleteWorktreeToastCopy(
|
||||
worktreeName,
|
||||
state?.canForceDelete ?? false,
|
||||
result.error
|
||||
)
|
||||
const showToast = toastCopy.isDestructive ? toast.error : toast.info
|
||||
showToast(toastCopy.title, {
|
||||
description: toastCopy.description,
|
||||
duration: 10000,
|
||||
action: state?.canForceDelete
|
||||
? {
|
||||
@@ -97,7 +105,7 @@ const DeleteWorktreeDialog = React.memo(function DeleteWorktreeDialog() {
|
||||
})
|
||||
closeModal()
|
||||
},
|
||||
[closeModal, removeWorktree, worktreeId]
|
||||
[closeModal, removeWorktree, worktreeId, worktreeName]
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { getDeleteWorktreeToastCopy } from './delete-worktree-toast'
|
||||
|
||||
describe('getDeleteWorktreeToastCopy', () => {
|
||||
it('uses direct guidance when force delete is available', () => {
|
||||
expect(getDeleteWorktreeToastCopy('feature/foo', true, 'branch has changes')).toEqual({
|
||||
title: 'Failed to delete worktree feature/foo',
|
||||
description: 'It has changed files. Use Force Delete to delete it anyway.',
|
||||
isDestructive: false
|
||||
})
|
||||
})
|
||||
|
||||
it('preserves the raw error when force delete is unavailable', () => {
|
||||
expect(getDeleteWorktreeToastCopy('feature/foo', false, 'permission denied')).toEqual({
|
||||
title: 'Failed to delete worktree feature/foo',
|
||||
description: 'permission denied',
|
||||
isDestructive: true
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
export type DeleteWorktreeToastCopy = {
|
||||
title: string
|
||||
description?: string
|
||||
isDestructive: boolean
|
||||
}
|
||||
|
||||
export function getDeleteWorktreeToastCopy(
|
||||
worktreeName: string,
|
||||
canForceDelete: boolean,
|
||||
error: string
|
||||
): DeleteWorktreeToastCopy {
|
||||
if (canForceDelete) {
|
||||
return {
|
||||
title: `Failed to delete worktree ${worktreeName}`,
|
||||
description: 'It has changed files. Use Force Delete to delete it anyway.',
|
||||
// Why: git commonly refuses the first delete when the worktree still has
|
||||
// modified or untracked files. Showing raw stderr in a destructive toast
|
||||
// made a normal cleanup step look like an Orca bug, so this common case
|
||||
// gets a concise explanation plus the force-delete path instead.
|
||||
isDestructive: false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title: `Failed to delete worktree ${worktreeName}`,
|
||||
description: error,
|
||||
isDestructive: true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user