improve delete worktree failure diagnostics (#302)
## Summary - move delete-worktree failures out of transient toast-only UX and keep them inline in the delete modal - add parsed diagnostics for common failure modes, including a short summary, likely cause, and suggested next step - make the raw error easier to review and share with raw and sanitized copy actions Closes #301. ## BEFORE: <img width="1127" height="860" alt="image" src="https://github.com/user-attachments/assets/dd09ba1e-be8c-450c-a1dd-f1cde2a48802" /> ## AFTER: <img width="1384" height="835" alt="image" src="https://github.com/user-attachments/assets/6b0d1459-21fa-4264-9e54-45540f584538" /> ## Problem Before this change, delete-worktree failures were difficult to work with: 1. The failure message was effectively raw backend or git output. 2. Users had to infer the meaning of the error themselves. 3. The UI did not explain what likely went wrong or what to do next. 4. Sharing the error for debugging was awkward when it included machine-local absolute paths. 5. The confirmation modal was not being used as the primary diagnostic surface for a destructive action that frequently fails for understandable reasons. This was especially frustrating for common cases such as: - modified or untracked files in the worktree - a process still using the worktree directory - permission errors on Windows - missing worktree directories or stale worktree records ## What changed ### Modal failure UX - keep delete failures inline inside `packages/ui/src/components/worktree-selector.tsx` - clear modal-local error state when opening or closing the dialog - keep the success toast on successful deletion, but use the modal itself for failure presentation ### Human-readable diagnostics - parse JSON-shaped backend error payloads such as `{"error":"..."}` before classification - classify common delete failure patterns into: - `localChanges` - `inUse` - `notFound` - `permissionDenied` - `unknown` - render three user-facing lines above the raw error: - summary - likely cause - suggested next step ### Copy flows - add `Copy error` for the original failure text - add `Copy sanitized` to redact common absolute path and username patterns before copying ### Modal content and sizing - present the target worktree in a simpler two-line summary block - update the delete description text to plain English: `Deletes this branch worktree and its local folder.` - size the delete modal deliberately for desktop use while allowing vertical expansion to the viewport limit before scrolling ### i18n coverage - add the new delete diagnostic strings across all currently supported locales touched by this area: - `en` - `es` - `fr` - `he` - `ja` - `ru` - `zh-Hans` ## Why this approach - It keeps the backend contract unchanged and solves the UX problem where it occurs. - It preserves access to the raw failure text instead of hiding implementation detail entirely. - It gives users immediate guidance without forcing them to translate git errors into next actions. - It improves bug reporting without requiring a separate logging or export workflow. ## Not included - server-side preflight guards that block delete when the worktree is still assigned or in use - process-aware worktree locking detection - automatic retry or force-delete-and-retry flows Those are useful follow-ups, but this PR is intentionally scoped to failure presentation and debuggability. ## Files changed - `packages/ui/src/components/worktree-selector.tsx` - `packages/ui/src/lib/i18n/messages/en/instance.ts` - `packages/ui/src/lib/i18n/messages/es/instance.ts` - `packages/ui/src/lib/i18n/messages/fr/instance.ts` - `packages/ui/src/lib/i18n/messages/he/instance.ts` - `packages/ui/src/lib/i18n/messages/ja/instance.ts` - `packages/ui/src/lib/i18n/messages/ru/instance.ts` - `packages/ui/src/lib/i18n/messages/zh-Hans/instance.ts` ## Validation - `npm run typecheck --workspace @codenomad/ui` - `npm run build --workspace @codenomad/ui` - `npm run typecheck --workspace @neuralnomads/codenomad-electron-app` ## Notes for reviewers - The error classifier is intentionally heuristic and string-based. It is meant to improve the common cases without increasing backend coupling. - The sanitized copy flow is conservative and focused on path and username redaction, not full structured log scrubbing. --------- Co-authored-by: Shantur Rathore <i@shantur.com>
This commit is contained in:
@@ -166,6 +166,30 @@ export const instanceMessages = {
|
||||
"instanceShell.backgroundProcesses.actions.output": "出力",
|
||||
"instanceShell.backgroundProcesses.actions.stop": "停止",
|
||||
"instanceShell.backgroundProcesses.actions.terminate": "終了",
|
||||
"instanceShell.worktree.delete.error.title": "削除に失敗しました",
|
||||
"instanceShell.worktree.delete.error.fallback": "worktree の削除に失敗しました",
|
||||
"instanceShell.worktree.delete.error.causeLabel": "考えられる原因:",
|
||||
"instanceShell.worktree.delete.error.nextStepLabel": "推奨される次の手順:",
|
||||
"instanceShell.worktree.delete.error.summary.localChanges": "この worktree に変更済みまたは未追跡のファイルがあるため、Git が削除を拒否しました。",
|
||||
"instanceShell.worktree.delete.error.summary.inUse": "このディレクトリ内のファイルがまだ使用中のため、CodeNomad はこの worktree を削除できませんでした。",
|
||||
"instanceShell.worktree.delete.error.summary.notFound": "ディレクトリまたは worktree レコードが見つからなかったため、CodeNomad はこの worktree を削除できませんでした。",
|
||||
"instanceShell.worktree.delete.error.summary.permissionDenied": "ディレクトリへのアクセスが拒否されたため、CodeNomad はこの worktree を削除できませんでした。",
|
||||
"instanceShell.worktree.delete.error.summary.unknown": "CodeNomad はこの worktree を削除できませんでした。",
|
||||
"instanceShell.worktree.delete.error.cause.localChanges": "ローカル変更",
|
||||
"instanceShell.worktree.delete.error.cause.inUse": "別のプロセスがこの worktree を使用中です",
|
||||
"instanceShell.worktree.delete.error.cause.notFound": "worktree のディレクトリまたは記録が見つかりません",
|
||||
"instanceShell.worktree.delete.error.cause.permissionDenied": "ファイルシステム権限が不足しています",
|
||||
"instanceShell.worktree.delete.error.cause.unknown": "バックエンドが分類できない削除エラーを返しました",
|
||||
"instanceShell.worktree.delete.error.nextStep.localChanges": "ローカル変更を破棄したい場合は Force delete を有効にするか、worktree を整理してから再試行してください。",
|
||||
"instanceShell.worktree.delete.error.nextStep.inUse": "この worktree を使用している端末、エディタ、watcher、バックグラウンドプロセスを閉じてから再試行してください。",
|
||||
"instanceShell.worktree.delete.error.nextStep.notFound": "worktree 一覧を更新して再試行してください。まだ失敗する場合は、ディスク上の worktree パスを確認してください。",
|
||||
"instanceShell.worktree.delete.error.nextStep.permissionDenied": "ファイルシステム権限を確認し、このディレクトリをロックしている可能性のあるアプリを閉じてから再試行してください。",
|
||||
"instanceShell.worktree.delete.error.nextStep.unknown": "下の生エラーで詳細を確認し、報告された問題に対処してから再試行してください。",
|
||||
"instanceShell.worktree.delete.error.copyRaw": "エラーをコピー",
|
||||
"instanceShell.worktree.delete.error.copySanitized": "サニタイズ済みをコピー",
|
||||
"instanceShell.worktree.delete.error.copySuccess": "削除エラーをコピーしました",
|
||||
"instanceShell.worktree.delete.error.copySanitizedSuccess": "サニタイズ済みの削除エラーをコピーしました",
|
||||
"instanceShell.worktree.delete.error.copyFailure": "削除エラーをコピーできませんでした",
|
||||
|
||||
"versionPill.appWithVersion": "アプリ {version}",
|
||||
"versionPill.ui": "UI",
|
||||
|
||||
Reference in New Issue
Block a user