## 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>
223 lines
16 KiB
TypeScript
223 lines
16 KiB
TypeScript
export const instanceMessages = {
|
||
"instanceTabs.new.title": "מופע חדש (Cmd/Ctrl+N)",
|
||
"instanceTabs.new.ariaLabel": "מופע חדש",
|
||
"instanceTabs.remote.title": "חיבור מרוחק",
|
||
"instanceTabs.remote.ariaLabel": "חיבור מרוחק",
|
||
|
||
"instanceInfo.title": "מידע על המופע",
|
||
"instanceInfo.labels.folder": "תיקייה",
|
||
"instanceInfo.labels.project": "פרויקט",
|
||
"instanceInfo.labels.versionControl": "בקרת גרסאות",
|
||
"instanceInfo.labels.opencodeVersion": "גרסת OpenCode",
|
||
"instanceInfo.labels.binaryPath": "נתיב קובץ בינארי",
|
||
"instanceInfo.labels.environmentVariables": "משתני סביבה ({count})",
|
||
"instanceInfo.loading": "טוען...",
|
||
"instanceInfo.server.title": "שרת",
|
||
"instanceInfo.server.port": "פורט:",
|
||
"instanceInfo.server.pid": "PID:",
|
||
"instanceInfo.server.status": "סטטוס:",
|
||
|
||
"instanceTab.status.permission": "ממתין לאישור",
|
||
"instanceTab.status.compacting": "מסכם",
|
||
"instanceTab.status.working": "עובד",
|
||
"instanceTab.status.idle": "מוכן",
|
||
"instanceTab.status.ariaLabel": "סטטוס מופע: {status}",
|
||
"instanceTab.actions.close.ariaLabel": "סגור מופע",
|
||
|
||
"instanceShell.leftPanel.sessionsTitle": "סשנים",
|
||
"instanceShell.leftPanel.instanceInfo": "מידע על המופע",
|
||
"instanceShell.leftDrawer.pin": "נעץ מגירה שמאלית",
|
||
"instanceShell.leftDrawer.unpin": "שחרר נעיצת מגירה שמאלית",
|
||
"instanceShell.leftDrawer.toggle.pinned": "המגירה השמאלית נעוצה",
|
||
"instanceShell.leftDrawer.toggle.open": "פתח מגירה שמאלית",
|
||
"instanceShell.leftDrawer.toggle.close": "סגור מגירה שמאלית",
|
||
|
||
"instanceShell.rightDrawer.pin": "נעץ מגירה ימנית",
|
||
"instanceShell.rightDrawer.unpin": "שחרר נעיצת מגירה ימנית",
|
||
"instanceShell.rightDrawer.toggle.pinned": "המגירה הימנית נעוצה",
|
||
"instanceShell.rightDrawer.toggle.open": "פתח מגירה ימנית",
|
||
"instanceShell.rightDrawer.toggle.close": "סגור מגירה ימנית",
|
||
|
||
"instanceShell.fullscreen.enter": "מסך מלא",
|
||
"instanceShell.fullscreen.exit": "יציאה ממסך מלא",
|
||
|
||
"instanceShell.metrics.usedLabel": "בשימוש",
|
||
"instanceShell.metrics.availableLabel": "זמין",
|
||
|
||
"instanceShell.commandPalette.openAriaLabel": "פתח לוח פקודות",
|
||
"instanceShell.commandPalette.button": "לוח פקודות",
|
||
|
||
"instanceShell.connection.ariaLabel": "חיבור {status}",
|
||
"instanceShell.connection.connected": "מחובר",
|
||
"instanceShell.connection.connecting": "מתחבר...",
|
||
"instanceShell.connection.disconnected": "מנותק",
|
||
"instanceShell.connection.unknown": "לא ידוע",
|
||
|
||
"instanceWelcome.shortcuts.newSession": "סשן חדש",
|
||
"instanceWelcome.empty.title": "אין סשנים קודמים",
|
||
"instanceWelcome.empty.description": "צור סשן חדש למטה כדי להתחיל",
|
||
"instanceWelcome.loading.title": "טוען סשנים",
|
||
"instanceWelcome.loading.description": "מאחזר את הסשנים הקודמים שלך...",
|
||
"instanceWelcome.resume.title": "המשך סשן",
|
||
"instanceWelcome.resume.subtitle.one": "סשן אחד זמין",
|
||
"instanceWelcome.resume.subtitle.other": "{count} סשנים זמינים",
|
||
"instanceWelcome.session.untitled": "סשן ללא שם",
|
||
"instanceWelcome.new.title": "התחל סשן חדש",
|
||
"instanceWelcome.new.subtitle": "ישתמש אוטומטית בסוכן/מודל האחרון שלך",
|
||
"instanceWelcome.new.createButton": "צור סשן",
|
||
"instanceWelcome.overlay.close": "סגור",
|
||
"instanceWelcome.actions.viewInstanceInfo": "צפה במידע על המופע",
|
||
"instanceWelcome.actions.renameTitle": "שנה שם סשן",
|
||
"instanceWelcome.actions.deleteTitle": "מחק סשן",
|
||
"instanceWelcome.hints.navigate": "ניווט",
|
||
"instanceWelcome.hints.jump": "קפיצה",
|
||
"instanceWelcome.hints.firstLast": "ראשון/אחרון",
|
||
"instanceWelcome.hints.resume": "המשך",
|
||
"instanceWelcome.hints.delete": "מחיקה",
|
||
"instanceWelcome.toasts.renameError": "לא ניתן לשנות שם הסשן",
|
||
|
||
"instanceDisconnected.title": "המופע התנתק",
|
||
"instanceDisconnected.folderFallback": "סביבת עבודה זו",
|
||
"instanceDisconnected.reasonFallback": "השרת הפסיק להגיב",
|
||
"instanceDisconnected.description": "לא ניתן עוד להגיע ל-{folder}. סגור את הלשונית כדי להמשיך לעבוד.",
|
||
"instanceDisconnected.details.title": "פרטים",
|
||
"instanceDisconnected.details.folderLabel": "תיקייה:",
|
||
"instanceDisconnected.actions.closeInstance": "סגור מופע",
|
||
|
||
"instanceShell.empty.title": "לא נבחר סשן",
|
||
"instanceShell.empty.description": "בחר סשן לצפייה בהודעות",
|
||
|
||
"instanceShell.rightPanel.title": "לוח סטטוס",
|
||
"instanceShell.rightPanel.tabs.changes": "שינויי סשן",
|
||
"instanceShell.rightPanel.tabs.gitChanges": "שינויי Git",
|
||
"instanceShell.rightPanel.tabs.files": "קבצים",
|
||
"instanceShell.rightPanel.tabs.status": "סטטוס",
|
||
"instanceShell.rightPanel.tabs.ariaLabel": "לשוניות לוח ימני",
|
||
"instanceShell.rightPanel.actions.refresh": "רענן",
|
||
"instanceShell.rightPanel.actions.save": "שמור (Ctrl+S)",
|
||
"instanceShell.rightPanel.actions.saveConfirm.message": "האם ברצונך לשמור את השינויים לפני המעבר?",
|
||
"instanceShell.rightPanel.actions.saveConfirm.confirmLabel": "שמור",
|
||
"instanceShell.rightPanel.actions.saveConfirm.cancelLabel": "בטל שינויים",
|
||
"instanceShell.rightPanel.actions.conflict.message": "הקובץ שונה על ידי הסוכן. לדרוס את שינויי הסוכן?",
|
||
"instanceShell.rightPanel.actions.conflict.confirmLabel": "דרוס",
|
||
"instanceShell.rightPanel.actions.conflict.cancelLabel": "בטל",
|
||
"instanceShell.rightPanel.actions.refreshDirty.message": "לקובץ יש שינויים שלא נשמרו. רענון יבטל את העריכות שלך. להמשיך?",
|
||
"instanceShell.rightPanel.actions.refreshDirty.confirmLabel": "רענן",
|
||
"instanceShell.rightPanel.actions.refreshDirty.cancelLabel": "בטל",
|
||
"instanceShell.rightPanel.toast.saveSuccess": "הקובץ נשמר בהצלחה",
|
||
"instanceShell.rightPanel.toast.saveError": "כשלון בשמירת הקובץ",
|
||
"instanceShell.rightPanel.sections.yoloMode": "מצב Yolo",
|
||
"instanceShell.rightPanel.sections.yoloMode.tooltip": "מאשר אוטומטית בקשות הרשאה עבור הסשן הנוכחי. השתמשו בזה רק אם אתם סומכים על הכלים שרצים.",
|
||
"instanceShell.rightPanel.sections.sessionChanges": "שינויי סשן",
|
||
"instanceShell.rightPanel.sections.sessionChanges.tooltip": "קבצים שהשתנו בסשן הנוכחי. מציג הוספות ומחיקות לכל קובץ.",
|
||
"instanceShell.rightPanel.sections.plan": "תוכנית",
|
||
"instanceShell.rightPanel.sections.plan.tooltip": "מפת הדרכים של הסוכן לסשן זה. עוקב אחר משימות, תת-משימות וסטטוס השלמתן.",
|
||
"instanceShell.rightPanel.sections.backgroundProcesses": "מעטפות רקע",
|
||
"instanceShell.rightPanel.sections.backgroundProcesses.tooltip": "תהליכים ממושכים שהופעלו על ידי הסוכן. ניתן לעקוב אחר פלטם, לעצור אותם או לסיים אותם.",
|
||
"instanceShell.rightPanel.sections.mcp": "שרתי MCP",
|
||
"instanceShell.rightPanel.sections.mcp.tooltip": "שרתי Model Context Protocol המרחיבים את יכולות הסוכן עם כלים ושירותים חיצוניים.",
|
||
"instanceShell.rightPanel.sections.lsp": "שרתי LSP",
|
||
"instanceShell.rightPanel.sections.lsp.tooltip": "שרתי Language Server Protocol המספקים בינת קוד, אבחון ותכונות ספציפיות לשפה.",
|
||
"instanceShell.rightPanel.sections.plugins": "תוספים",
|
||
"instanceShell.rightPanel.sections.plugins.tooltip": "תוספים המתאימים אישית את הממשק ואת התנהגות השרת, ומוסיפים תכונות מעבר ל-MCP ו-LSP.",
|
||
|
||
"instanceShell.sessionChanges.noSessionSelected": "בחר סשן לצפייה בשינויים.",
|
||
"instanceShell.sessionChanges.loading": "מאחזר שינויי סשן...",
|
||
"instanceShell.sessionChanges.empty": "אין שינויי סשן עדיין.",
|
||
"instanceShell.sessionChanges.filesChanged": "{count} קבצים שונו",
|
||
"instanceShell.sessionChanges.actions.show": "הצג שינויים",
|
||
|
||
"instanceShell.filesShell.fileListTitle": "רשימת קבצים",
|
||
"instanceShell.filesShell.mobileSelectorLabel": "בחר קובץ",
|
||
"instanceShell.filesShell.mobileSelectorEmpty": "בחר קובץ",
|
||
"instanceShell.filesShell.viewerTitle": "מציג שינויים",
|
||
"instanceShell.filesShell.viewerPlaceholder": "תצוגת שינויים מפורטת תתווסף בשלב הבא.",
|
||
"instanceShell.filesShell.viewerEmpty": "לא נבחר קובץ.",
|
||
"instanceShell.filesShell.hideFiles": "הסתר קבצים",
|
||
"instanceShell.filesShell.showFiles": "הצג קבצים",
|
||
"instanceShell.gitChanges.noSessionSelected": "בחר סשן לצפייה בשינויי Git.",
|
||
"instanceShell.gitChanges.loading": "טוען שינויי Git…",
|
||
"instanceShell.gitChanges.empty": "אין שינויי Git עדיין.",
|
||
"instanceShell.gitChanges.binaryViewer": "לא ניתן להציג קובץ בינארי",
|
||
"instanceShell.gitChanges.sections.staged": "שינויים שנשמרו ל-staging",
|
||
"instanceShell.gitChanges.sections.unstaged": "שינויים",
|
||
"instanceShell.gitChanges.actions.insertContext": "הוסף לפרומפט",
|
||
"instanceShell.gitChanges.actions.stage": "העבר ל-staging",
|
||
"instanceShell.gitChanges.actions.unstage": "הוצא מ-staging",
|
||
"instanceShell.gitChanges.commit.placeholder": "הזן הודעת commit",
|
||
"instanceShell.gitChanges.commit.submit": "Commit",
|
||
"instanceShell.gitChanges.commit.submitting": "מבצע commit...",
|
||
"instanceShell.gitChanges.commit.success": "ה-commit נוצר בהצלחה",
|
||
"instanceShell.gitChanges.commit.error": "יצירת ה-commit נכשלה",
|
||
"instanceShell.diff.hideUnchanged": "הסתר אזורים ללא שינוי",
|
||
"instanceShell.diff.showFull": "הצג קובץ מלא",
|
||
"instanceShell.diff.switchToSplit": "עבור לתצוגה מפוצלת",
|
||
"instanceShell.diff.switchToUnified": "עבור לתצוגה מאוחדת",
|
||
"instanceShell.diff.enableWordWrap": "הפעל גלישת מילים",
|
||
"instanceShell.diff.disableWordWrap": "כבה גלישת מילים",
|
||
"instanceShell.worktree.create": "+ צור worktree",
|
||
|
||
"instanceShell.plan.noSessionSelected": "בחר סשן לצפייה בתוכנית.",
|
||
"instanceShell.plan.empty": "עדיין לא תוכנן דבר.",
|
||
|
||
"instanceShell.yoloMode.noSessionSelected": "בחרו סשן כדי להגדיר מצב Yolo.",
|
||
"instanceShell.yoloMode.title": "מצב Yolo",
|
||
"instanceShell.yoloMode.description": "מאשר אוטומטית בקשות הרשאה עבור הסשן הזה. כבוי כברירת מחדל.",
|
||
"instanceShell.yoloMode.badge": "Yolo",
|
||
"instanceShell.yoloMode.badgeAriaLabel": "מצב Yolo פעיל",
|
||
|
||
"instanceShell.backgroundProcesses.empty": "אין תהליכי רקע.",
|
||
"instanceShell.backgroundProcesses.status": "סטטוס: {status}",
|
||
"instanceShell.backgroundProcesses.output": "פלט: {sizeKb}KB",
|
||
"instanceShell.backgroundProcesses.notify.enabled": "התראת סיום פעילה",
|
||
"instanceShell.backgroundProcesses.notify.disabled": "התראת סיום כבויה",
|
||
"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": "Git סירב למחוק את ה-worktree הזה כי יש בו קבצים ששונו או קבצים לא במעקב.",
|
||
"instanceShell.worktree.delete.error.summary.inUse": "CodeNomad לא הצליח למחוק את ה-worktree הזה כי משהו עדיין משתמש בקבצים שבתיקייה.",
|
||
"instanceShell.worktree.delete.error.summary.notFound": "CodeNomad לא הצליח למחוק את ה-worktree הזה כי התיקייה או רשומת ה-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": "ה-backend החזיר שגיאת מחיקה שלא סווגה",
|
||
"instanceShell.worktree.delete.error.nextStep.localChanges": "הפעילו מחיקה בכפייה אם אתם רוצים לזרוק את השינויים המקומיים, או נקו את ה-worktree ונסו שוב.",
|
||
"instanceShell.worktree.delete.error.nextStep.inUse": "סגרו טרמינלים, עורכים, watchers או תהליכי רקע שמשתמשים ב-worktree הזה ונסו שוב.",
|
||
"instanceShell.worktree.delete.error.nextStep.notFound": "רעננו את רשימת ה-worktrees ונסו שוב. אם זה עדיין נכשל, בדקו את נתיב ה-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": "ממשק",
|
||
"versionPill.uiWithVersion": "ממשק {version}",
|
||
"versionPill.source": " ({source})",
|
||
|
||
"opencodeBinarySelector.title": "קובץ בינארי של OpenCode",
|
||
"opencodeBinarySelector.subtitle": "בחר איזה קובץ הרצה OpenCode ישתמש",
|
||
"opencodeBinarySelector.customPath.placeholder": "הזן נתיב לקובץ בינארי של opencode…",
|
||
"opencodeBinarySelector.actions.add": "הוסף",
|
||
"opencodeBinarySelector.actions.browse": "עיין אחר קובץ בינארי…",
|
||
"opencodeBinarySelector.actions.removeTitle": "הסר קובץ בינארי",
|
||
"opencodeBinarySelector.badge.systemPath": "השתמש בקובץ בינארי מנתיב המערכת",
|
||
"opencodeBinarySelector.status.checkingVersions": "בודק גרסאות…",
|
||
"opencodeBinarySelector.status.checking": "בודק…",
|
||
"opencodeBinarySelector.dialog.title": "בחר קובץ בינארי של OpenCode",
|
||
"opencodeBinarySelector.dialog.description": "עיין בקבצים החשופים על ידי שרת ה-CLI.",
|
||
"opencodeBinarySelector.validation.invalidBinary": "קובץ בינארי לא תקין של OpenCode",
|
||
"opencodeBinarySelector.validation.alreadyValidating": "כבר מאמת",
|
||
"opencodeBinarySelector.display.systemPath": "{name} (נתיב מערכת)",
|
||
"opencodeBinarySelector.versionLabel": "v{version}",
|
||
} as const
|