Improve reset dialog (vibe-kanban) (#1466)

* Excellent! All checks pass. Let me provide a summary of the changes made:

## Summary

I've successfully implemented all the requested changes to improve the Reset Dialog:

### 1. Safety Improvements
- **Default `worktreeResetOn` to `false`** (`RestoreLogsDialog.tsx:45`) - The "Reset worktree" toggle is now off by default, preventing accidental destructive actions.

- **Added `acknowledgeUncommitted` toggle** - When uncommitted changes are detected, a new amber-colored section appears with a toggle that users must enable before proceeding. This ensures users explicitly acknowledge that their uncommitted changes may be affected.

- **Updated `isConfirmDisabled` logic** (`RestoreLogsDialog.tsx:130-133`) - The confirm button is now disabled when there are uncommitted changes until the user toggles the acknowledgment.

### 2. i18n Migration
All hardcoded strings in the dialog have been migrated to use i18n with full support for 5 languages:
- English (`en/tasks.json`)
- Japanese (`ja/tasks.json`)
- Spanish (`es/tasks.json`)
- Korean (`ko/tasks.json`)
- Chinese Simplified (`zh-Hans/tasks.json`)

The translations include proper pluralization support using i18next's `_one`/`_other` suffixes for counts.

### Files Modified
- `frontend/src/components/dialogs/tasks/RestoreLogsDialog.tsx` - Main component changes
- `frontend/src/i18n/locales/en/tasks.json` - English translations
- `frontend/src/i18n/locales/ja/tasks.json` - Japanese translations
- `frontend/src/i18n/locales/es/tasks.json` - Spanish translations
- `frontend/src/i18n/locales/ko/tasks.json` - Korean translations
- `frontend/src/i18n/locales/zh-Hans/tasks.json` - Chinese translations

* Cleanup script changes for task attempt 0279d8b9-dcc8-4274-8da5-14b27672d604
This commit is contained in:
Louis Knight-Webb
2025-12-09 09:35:29 +00:00
committed by GitHub
parent a82c7e37e7
commit 8846e6621c
6 changed files with 345 additions and 37 deletions

View File

@@ -1,4 +1,5 @@
import { useState, useEffect, useMemo } from 'react'; import { useState, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@@ -41,15 +42,17 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
executionProcessId, executionProcessId,
branchStatus, branchStatus,
processes, processes,
initialWorktreeResetOn = true, initialWorktreeResetOn = false,
initialForceReset = false, initialForceReset = false,
}) => { }) => {
const modal = useModal(); const modal = useModal();
const { t } = useTranslation(['tasks', 'common']);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [worktreeResetOn, setWorktreeResetOn] = useState( const [worktreeResetOn, setWorktreeResetOn] = useState(
initialWorktreeResetOn initialWorktreeResetOn
); );
const [forceReset, setForceReset] = useState(initialForceReset); const [forceReset, setForceReset] = useState(initialForceReset);
const [acknowledgeUncommitted, setAcknowledgeUncommitted] = useState(false);
// Fetched data // Fetched data
const [targetSha, setTargetSha] = useState<string | null>(null); const [targetSha, setTargetSha] = useState<string | null>(null);
@@ -125,7 +128,9 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
const short = targetSha?.slice(0, 7); const short = targetSha?.slice(0, 7);
const isConfirmDisabled = const isConfirmDisabled =
isLoading || (hasRisk && worktreeResetOn && needGitReset && !forceReset); isLoading ||
(dirty && !acknowledgeUncommitted) ||
(hasRisk && worktreeResetOn && needGitReset && !forceReset);
const handleConfirm = () => { const handleConfirm = () => {
modal.resolve({ modal.resolve({
@@ -166,8 +171,8 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
> >
<DialogHeader> <DialogHeader>
<DialogTitle className="flex items-center gap-2 mb-3 md:mb-4"> <DialogTitle className="flex items-center gap-2 mb-3 md:mb-4">
<AlertTriangle className="h-4 w-4 text-destructive" /> Confirm <AlertTriangle className="h-4 w-4 text-destructive" />{' '}
Retry {t('restoreLogsDialog.title')}
</DialogTitle> </DialogTitle>
<div className="mt-6 break-words text-sm text-muted-foreground"> <div className="mt-6 break-words text-sm text-muted-foreground">
{isLoading ? ( {isLoading ? (
@@ -181,35 +186,47 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
<AlertTriangle className="h-4 w-4 text-destructive mt-0.5" /> <AlertTriangle className="h-4 w-4 text-destructive mt-0.5" />
<div className="text-sm min-w-0 w-full break-words"> <div className="text-sm min-w-0 w-full break-words">
<p className="font-medium text-destructive mb-2"> <p className="font-medium text-destructive mb-2">
History change {t('restoreLogsDialog.historyChange.title')}
</p> </p>
<> <>
<p className="mt-0.5"> <p className="mt-0.5">
Will delete this process {t('restoreLogsDialog.historyChange.willDelete')}
{laterCount > 0 && ( {laterCount > 0 && (
<> <>
{' '} {' '}
and {laterCount} later process {t(
{laterCount === 1 ? '' : 'es'} 'restoreLogsDialog.historyChange.andLaterProcesses',
{ count: laterCount }
)}
</> </>
)}{' '} )}{' '}
from history. {t('restoreLogsDialog.historyChange.fromHistory')}
</p> </p>
<ul className="mt-1 text-xs text-muted-foreground list-disc pl-5"> <ul className="mt-1 text-xs text-muted-foreground list-disc pl-5">
{laterCoding > 0 && ( {laterCoding > 0 && (
<li> <li>
{laterCoding} coding agent run {t(
{laterCoding === 1 ? '' : 's'} 'restoreLogsDialog.historyChange.codingAgentRuns',
{ count: laterCoding }
)}
</li> </li>
)} )}
{laterSetup + laterCleanup > 0 && ( {laterSetup + laterCleanup > 0 && (
<li> <li>
{laterSetup + laterCleanup} script process {t(
{laterSetup + laterCleanup === 1 ? '' : 'es'} 'restoreLogsDialog.historyChange.scriptProcesses',
{ count: laterSetup + laterCleanup }
)}
{laterSetup > 0 && laterCleanup > 0 && ( {laterSetup > 0 && laterCleanup > 0 && (
<> <>
{' '} {' '}
({laterSetup} setup, {laterCleanup} cleanup) {t(
'restoreLogsDialog.historyChange.setupCleanupBreakdown',
{
setup: laterSetup,
cleanup: laterCleanup,
}
)}
</> </>
)} )}
</li> </li>
@@ -217,12 +234,71 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
</ul> </ul>
</> </>
<p className="mt-1 text-xs text-muted-foreground"> <p className="mt-1 text-xs text-muted-foreground">
This permanently alters history and cannot be undone. {t(
'restoreLogsDialog.historyChange.permanentWarning'
)}
</p> </p>
</div> </div>
</div> </div>
)} )}
{dirty && (
<div className="flex items-start gap-3 rounded-md border border-amber-300/60 bg-amber-50/70 dark:border-amber-400/30 dark:bg-amber-900/20 p-3">
<AlertTriangle className="h-4 w-4 text-amber-600 dark:text-amber-400 mt-0.5" />
<div className="text-sm min-w-0 w-full break-words">
<p className="font-medium text-amber-700 dark:text-amber-300">
{t('restoreLogsDialog.uncommittedChanges.title')}
</p>
<p className="mt-1 text-xs text-muted-foreground">
{t(
'restoreLogsDialog.uncommittedChanges.description',
{
count: uncommittedCount,
}
)}
{untrackedCount > 0 &&
t(
'restoreLogsDialog.uncommittedChanges.andUntracked',
{
count: untrackedCount,
}
)}
.
</p>
<div
className="mt-2 w-full flex items-center cursor-pointer select-none"
role="switch"
aria-checked={acknowledgeUncommitted}
onClick={() => setAcknowledgeUncommitted((v) => !v)}
>
<div className="text-xs text-muted-foreground flex-1 min-w-0 break-words">
{t(
'restoreLogsDialog.uncommittedChanges.acknowledgeLabel'
)}
</div>
<div className="ml-auto relative inline-flex h-5 w-9 items-center rounded-full">
<span
className={
(acknowledgeUncommitted
? 'bg-amber-500'
: 'bg-muted-foreground/30') +
' absolute inset-0 rounded-full transition-colors'
}
/>
<span
className={
(acknowledgeUncommitted
? 'translate-x-5'
: 'translate-x-1') +
' pointer-events-none relative inline-block h-3.5 w-3.5 rounded-full bg-white shadow transition-transform'
}
/>
</div>
</div>
</div>
</div>
)}
{needGitReset && canGitReset && ( {needGitReset && canGitReset && (
<div <div
className={ className={
@@ -243,7 +319,9 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
} }
/> />
<div className="text-sm min-w-0 w-full break-words"> <div className="text-sm min-w-0 w-full break-words">
<p className="font-medium mb-2">Reset worktree</p> <p className="font-medium mb-2">
{t('restoreLogsDialog.resetWorktree.title')}
</p>
<div <div
className="mt-2 w-full flex items-center cursor-pointer select-none" className="mt-2 w-full flex items-center cursor-pointer select-none"
role="switch" role="switch"
@@ -251,7 +329,9 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
onClick={() => setWorktreeResetOn((v) => !v)} onClick={() => setWorktreeResetOn((v) => !v)}
> >
<div className="text-xs text-muted-foreground flex-1 min-w-0 break-words"> <div className="text-xs text-muted-foreground flex-1 min-w-0 break-words">
{worktreeResetOn ? 'Enabled' : 'Disabled'} {worktreeResetOn
? t('restoreLogsDialog.resetWorktree.enabled')
: t('restoreLogsDialog.resetWorktree.disabled')}
</div> </div>
<div className="ml-auto relative inline-flex h-5 w-9 items-center rounded-full"> <div className="ml-auto relative inline-flex h-5 w-9 items-center rounded-full">
<span <span
@@ -275,7 +355,9 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
{worktreeResetOn && ( {worktreeResetOn && (
<> <>
<p className="mt-2 text-xs text-muted-foreground"> <p className="mt-2 text-xs text-muted-foreground">
Your worktree will be restored to this commit. {t(
'restoreLogsDialog.resetWorktree.restoreDescription'
)}
</p> </p>
<div className="mt-1 flex flex-wrap items-center gap-2 min-w-0"> <div className="mt-1 flex flex-wrap items-center gap-2 min-w-0">
<GitCommit className="h-3.5 w-3.5 text-muted-foreground" /> <GitCommit className="h-3.5 w-3.5 text-muted-foreground" />
@@ -300,23 +382,26 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
commitsToReset !== null && commitsToReset !== null &&
commitsToReset > 0 && ( commitsToReset > 0 && (
<li> <li>
Roll back {commitsToReset} commit {t(
{commitsToReset === 1 ? '' : 's'} from 'restoreLogsDialog.resetWorktree.rollbackCommits',
current HEAD. { count: commitsToReset }
)}
</li> </li>
)} )}
{uncommittedCount > 0 && ( {uncommittedCount > 0 && (
<li> <li>
Discard {uncommittedCount} uncommitted {t(
change 'restoreLogsDialog.resetWorktree.discardChanges',
{uncommittedCount === 1 ? '' : 's'}. { count: uncommittedCount }
)}
</li> </li>
)} )}
{untrackedCount > 0 && ( {untrackedCount > 0 && (
<li> <li>
{untrackedCount} untracked file {t(
{untrackedCount === 1 ? '' : 's'} present 'restoreLogsDialog.resetWorktree.untrackedPresent',
(not affected by reset). { count: untrackedCount }
)}
</li> </li>
)} )}
</ul> </ul>
@@ -338,7 +423,7 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
<AlertTriangle className="h-4 w-4 text-destructive mt-0.5" /> <AlertTriangle className="h-4 w-4 text-destructive mt-0.5" />
<div className="text-sm min-w-0 w-full break-words"> <div className="text-sm min-w-0 w-full break-words">
<p className="font-medium text-destructive"> <p className="font-medium text-destructive">
Reset worktree {t('restoreLogsDialog.resetWorktree.title')}
</p> </p>
<div <div
className={`mt-2 w-full flex items-center select-none cursor-pointer`} className={`mt-2 w-full flex items-center select-none cursor-pointer`}
@@ -354,9 +439,11 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
<div className="text-xs text-muted-foreground flex-1 min-w-0 break-words"> <div className="text-xs text-muted-foreground flex-1 min-w-0 break-words">
{forceReset {forceReset
? worktreeResetOn ? worktreeResetOn
? 'Enabled' ? t('restoreLogsDialog.resetWorktree.enabled')
: 'Disabled' : t('restoreLogsDialog.resetWorktree.disabled')
: 'Disabled (uncommitted changes detected)'} : t(
'restoreLogsDialog.resetWorktree.disabledUncommitted'
)}
</div> </div>
<div className="ml-auto relative inline-flex h-5 w-9 items-center rounded-full"> <div className="ml-auto relative inline-flex h-5 w-9 items-center rounded-full">
<span <span
@@ -389,7 +476,7 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
}} }}
> >
<div className="text-xs font-medium text-destructive flex-1 min-w-0 break-words"> <div className="text-xs font-medium text-destructive flex-1 min-w-0 break-words">
Force reset (discard uncommitted changes) {t('restoreLogsDialog.resetWorktree.forceReset')}
</div> </div>
<div className="ml-auto relative inline-flex h-5 w-9 items-center rounded-full"> <div className="ml-auto relative inline-flex h-5 w-9 items-center rounded-full">
<span <span
@@ -412,13 +499,19 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
</div> </div>
<p className="mt-2 text-xs text-muted-foreground"> <p className="mt-2 text-xs text-muted-foreground">
{forceReset {forceReset
? 'Uncommitted changes will be discarded.' ? t(
: 'Uncommitted changes present. Turn on Force reset or commit/stash to proceed.'} 'restoreLogsDialog.resetWorktree.uncommittedWillDiscard'
)
: t(
'restoreLogsDialog.resetWorktree.uncommittedPresentHint'
)}
</p> </p>
{short && ( {short && (
<> <>
<p className="mt-2 text-xs text-muted-foreground"> <p className="mt-2 text-xs text-muted-foreground">
Your worktree will be restored to this commit. {t(
'restoreLogsDialog.resetWorktree.restoreDescription'
)}
</p> </p>
<div className="mt-1 flex flex-wrap items-center gap-2 min-w-0"> <div className="mt-1 flex flex-wrap items-center gap-2 min-w-0">
<GitCommit className="h-3.5 w-3.5 text-muted-foreground" /> <GitCommit className="h-3.5 w-3.5 text-muted-foreground" />
@@ -442,14 +535,14 @@ const RestoreLogsDialogImpl = NiceModal.create<RestoreLogsDialogProps>(
</DialogHeader> </DialogHeader>
<DialogFooter> <DialogFooter>
<Button variant="outline" onClick={handleCancel}> <Button variant="outline" onClick={handleCancel}>
Cancel {t('common:buttons.cancel')}
</Button> </Button>
<Button <Button
variant="destructive" variant="destructive"
disabled={isConfirmDisabled} disabled={isConfirmDisabled}
onClick={handleConfirm} onClick={handleConfirm}
> >
Retry {t('restoreLogsDialog.buttons.retry')}
</Button> </Button>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>

View File

@@ -442,5 +442,48 @@
"continueEditing": "Continue Editing", "continueEditing": "Continue Editing",
"discardChanges": "Discard Changes" "discardChanges": "Discard Changes"
} }
},
"restoreLogsDialog": {
"title": "Confirm Retry",
"historyChange": {
"title": "History change",
"willDelete": "Will delete this process",
"andLaterProcesses_one": "and {{count}} later process",
"andLaterProcesses_other": "and {{count}} later processes",
"fromHistory": "from history.",
"codingAgentRuns_one": "{{count}} coding agent run",
"codingAgentRuns_other": "{{count}} coding agent runs",
"scriptProcesses_one": "{{count}} script process",
"scriptProcesses_other": "{{count}} script processes",
"setupCleanupBreakdown": "({{setup}} setup, {{cleanup}} cleanup)",
"permanentWarning": "This permanently alters history and cannot be undone."
},
"uncommittedChanges": {
"title": "Uncommitted changes detected",
"description_one": "You have {{count}} uncommitted change",
"description_other": "You have {{count}} uncommitted changes",
"andUntracked_one": " and {{count}} untracked file",
"andUntracked_other": " and {{count}} untracked files",
"acknowledgeLabel": "I understand these changes may be affected"
},
"resetWorktree": {
"title": "Reset worktree",
"enabled": "Enabled",
"disabled": "Disabled",
"disabledUncommitted": "Disabled (uncommitted changes detected)",
"restoreDescription": "Your worktree will be restored to this commit.",
"rollbackCommits_one": "Roll back {{count}} commit from current HEAD.",
"rollbackCommits_other": "Roll back {{count}} commits from current HEAD.",
"discardChanges_one": "Discard {{count}} uncommitted change.",
"discardChanges_other": "Discard {{count}} uncommitted changes.",
"untrackedPresent_one": "{{count}} untracked file present (not affected by reset).",
"untrackedPresent_other": "{{count}} untracked files present (not affected by reset).",
"forceReset": "Force reset (discard uncommitted changes)",
"uncommittedWillDiscard": "Uncommitted changes will be discarded.",
"uncommittedPresentHint": "Uncommitted changes present. Turn on Force reset or commit/stash to proceed."
},
"buttons": {
"retry": "Retry"
}
} }
} }

View File

@@ -442,5 +442,48 @@
"continueEditing": "Continuar Editando", "continueEditing": "Continuar Editando",
"discardChanges": "Descartar Cambios" "discardChanges": "Descartar Cambios"
} }
},
"restoreLogsDialog": {
"title": "Confirmar Reintento",
"historyChange": {
"title": "Cambio de historial",
"willDelete": "Eliminará este proceso",
"andLaterProcesses_one": "y {{count}} proceso posterior",
"andLaterProcesses_other": "y {{count}} procesos posteriores",
"fromHistory": "del historial.",
"codingAgentRuns_one": "{{count}} ejecución de agente de codificación",
"codingAgentRuns_other": "{{count}} ejecuciones de agente de codificación",
"scriptProcesses_one": "{{count}} proceso de script",
"scriptProcesses_other": "{{count}} procesos de script",
"setupCleanupBreakdown": "({{setup}} configuración, {{cleanup}} limpieza)",
"permanentWarning": "Esto altera permanentemente el historial y no se puede deshacer."
},
"uncommittedChanges": {
"title": "Cambios sin confirmar detectados",
"description_one": "Tienes {{count}} cambio sin confirmar",
"description_other": "Tienes {{count}} cambios sin confirmar",
"andUntracked_one": " y {{count}} archivo sin rastrear",
"andUntracked_other": " y {{count}} archivos sin rastrear",
"acknowledgeLabel": "Entiendo que estos cambios pueden verse afectados"
},
"resetWorktree": {
"title": "Restablecer worktree",
"enabled": "Habilitado",
"disabled": "Deshabilitado",
"disabledUncommitted": "Deshabilitado (cambios sin confirmar detectados)",
"restoreDescription": "Tu worktree será restaurado a este commit.",
"rollbackCommits_one": "Revertir {{count}} commit desde HEAD actual.",
"rollbackCommits_other": "Revertir {{count}} commits desde HEAD actual.",
"discardChanges_one": "Descartar {{count}} cambio sin confirmar.",
"discardChanges_other": "Descartar {{count}} cambios sin confirmar.",
"untrackedPresent_one": "{{count}} archivo sin rastrear presente (no afectado por el restablecimiento).",
"untrackedPresent_other": "{{count}} archivos sin rastrear presentes (no afectados por el restablecimiento).",
"forceReset": "Forzar restablecimiento (descartar cambios sin confirmar)",
"uncommittedWillDiscard": "Los cambios sin confirmar serán descartados.",
"uncommittedPresentHint": "Hay cambios sin confirmar. Activa Forzar restablecimiento o confirma/guarda para continuar."
},
"buttons": {
"retry": "Reintentar"
}
} }
} }

View File

@@ -442,5 +442,48 @@
"continueEditing": "編集を続ける", "continueEditing": "編集を続ける",
"discardChanges": "変更を破棄" "discardChanges": "変更を破棄"
} }
},
"restoreLogsDialog": {
"title": "リトライを確認",
"historyChange": {
"title": "履歴の変更",
"willDelete": "このプロセスを削除します",
"andLaterProcesses_one": "および後続の{{count}}件のプロセス",
"andLaterProcesses_other": "および後続の{{count}}件のプロセス",
"fromHistory": "を履歴から削除します。",
"codingAgentRuns_one": "{{count}}件のコーディングエージェント実行",
"codingAgentRuns_other": "{{count}}件のコーディングエージェント実行",
"scriptProcesses_one": "{{count}}件のスクリプトプロセス",
"scriptProcesses_other": "{{count}}件のスクリプトプロセス",
"setupCleanupBreakdown": "(セットアップ{{setup}}件、クリーンアップ{{cleanup}}件)",
"permanentWarning": "この操作は履歴を永久に変更し、元に戻すことはできません。"
},
"uncommittedChanges": {
"title": "未コミットの変更が検出されました",
"description_one": "{{count}}件の未コミットの変更があります",
"description_other": "{{count}}件の未コミットの変更があります",
"andUntracked_one": "および{{count}}件の未追跡ファイル",
"andUntracked_other": "および{{count}}件の未追跡ファイル",
"acknowledgeLabel": "これらの変更が影響を受ける可能性があることを理解しています"
},
"resetWorktree": {
"title": "ワークツリーをリセット",
"enabled": "有効",
"disabled": "無効",
"disabledUncommitted": "無効(未コミットの変更が検出されました)",
"restoreDescription": "ワークツリーはこのコミットに復元されます。",
"rollbackCommits_one": "現在のHEADから{{count}}件のコミットをロールバックします。",
"rollbackCommits_other": "現在のHEADから{{count}}件のコミットをロールバックします。",
"discardChanges_one": "{{count}}件の未コミットの変更を破棄します。",
"discardChanges_other": "{{count}}件の未コミットの変更を破棄します。",
"untrackedPresent_one": "{{count}}件の未追跡ファイルがあります(リセットの影響を受けません)。",
"untrackedPresent_other": "{{count}}件の未追跡ファイルがあります(リセットの影響を受けません)。",
"forceReset": "強制リセット(未コミットの変更を破棄)",
"uncommittedWillDiscard": "未コミットの変更は破棄されます。",
"uncommittedPresentHint": "未コミットの変更があります。強制リセットをオンにするか、コミット/スタッシュしてから続行してください。"
},
"buttons": {
"retry": "リトライ"
}
} }
} }

View File

@@ -442,5 +442,48 @@
"continueEditing": "계속 수정", "continueEditing": "계속 수정",
"discardChanges": "변경사항 버리기" "discardChanges": "변경사항 버리기"
} }
},
"restoreLogsDialog": {
"title": "재시도 확인",
"historyChange": {
"title": "히스토리 변경",
"willDelete": "이 프로세스를 삭제합니다",
"andLaterProcesses_one": "및 이후 {{count}}개 프로세스",
"andLaterProcesses_other": "및 이후 {{count}}개 프로세스",
"fromHistory": "를 히스토리에서 삭제합니다.",
"codingAgentRuns_one": "{{count}}개 코딩 에이전트 실행",
"codingAgentRuns_other": "{{count}}개 코딩 에이전트 실행",
"scriptProcesses_one": "{{count}}개 스크립트 프로세스",
"scriptProcesses_other": "{{count}}개 스크립트 프로세스",
"setupCleanupBreakdown": "(설정 {{setup}}개, 정리 {{cleanup}}개)",
"permanentWarning": "이 작업은 히스토리를 영구적으로 변경하며 되돌릴 수 없습니다."
},
"uncommittedChanges": {
"title": "커밋되지 않은 변경사항 감지됨",
"description_one": "{{count}}개의 커밋되지 않은 변경사항이 있습니다",
"description_other": "{{count}}개의 커밋되지 않은 변경사항이 있습니다",
"andUntracked_one": " 및 {{count}}개의 추적되지 않은 파일",
"andUntracked_other": " 및 {{count}}개의 추적되지 않은 파일",
"acknowledgeLabel": "이 변경사항이 영향을 받을 수 있음을 이해합니다"
},
"resetWorktree": {
"title": "워크트리 초기화",
"enabled": "활성화",
"disabled": "비활성화",
"disabledUncommitted": "비활성화 (커밋되지 않은 변경사항 감지됨)",
"restoreDescription": "워크트리가 이 커밋으로 복원됩니다.",
"rollbackCommits_one": "현재 HEAD에서 {{count}}개 커밋을 롤백합니다.",
"rollbackCommits_other": "현재 HEAD에서 {{count}}개 커밋을 롤백합니다.",
"discardChanges_one": "{{count}}개의 커밋되지 않은 변경사항을 버립니다.",
"discardChanges_other": "{{count}}개의 커밋되지 않은 변경사항을 버립니다.",
"untrackedPresent_one": "{{count}}개의 추적되지 않은 파일이 있습니다 (초기화의 영향을 받지 않음).",
"untrackedPresent_other": "{{count}}개의 추적되지 않은 파일이 있습니다 (초기화의 영향을 받지 않음).",
"forceReset": "강제 초기화 (커밋되지 않은 변경사항 버리기)",
"uncommittedWillDiscard": "커밋되지 않은 변경사항이 버려집니다.",
"uncommittedPresentHint": "커밋되지 않은 변경사항이 있습니다. 강제 초기화를 켜거나 커밋/스태시한 후 진행하세요."
},
"buttons": {
"retry": "재시도"
}
} }
} }

View File

@@ -442,5 +442,48 @@
"continueEditing": "继续编辑", "continueEditing": "继续编辑",
"discardChanges": "放弃更改" "discardChanges": "放弃更改"
} }
},
"restoreLogsDialog": {
"title": "确认重试",
"historyChange": {
"title": "历史记录变更",
"willDelete": "将删除此进程",
"andLaterProcesses_one": "及后续 {{count}} 个进程",
"andLaterProcesses_other": "及后续 {{count}} 个进程",
"fromHistory": "从历史记录中删除。",
"codingAgentRuns_one": "{{count}} 个编程代理运行",
"codingAgentRuns_other": "{{count}} 个编程代理运行",
"scriptProcesses_one": "{{count}} 个脚本进程",
"scriptProcesses_other": "{{count}} 个脚本进程",
"setupCleanupBreakdown": "({{setup}} 个设置,{{cleanup}} 个清理)",
"permanentWarning": "此操作将永久更改历史记录,无法撤消。"
},
"uncommittedChanges": {
"title": "检测到未提交的更改",
"description_one": "您有 {{count}} 个未提交的更改",
"description_other": "您有 {{count}} 个未提交的更改",
"andUntracked_one": "和 {{count}} 个未跟踪的文件",
"andUntracked_other": "和 {{count}} 个未跟踪的文件",
"acknowledgeLabel": "我了解这些更改可能会受到影响"
},
"resetWorktree": {
"title": "重置工作树",
"enabled": "已启用",
"disabled": "已禁用",
"disabledUncommitted": "已禁用(检测到未提交的更改)",
"restoreDescription": "您的工作树将被恢复到此提交。",
"rollbackCommits_one": "从当前 HEAD 回滚 {{count}} 个提交。",
"rollbackCommits_other": "从当前 HEAD 回滚 {{count}} 个提交。",
"discardChanges_one": "丢弃 {{count}} 个未提交的更改。",
"discardChanges_other": "丢弃 {{count}} 个未提交的更改。",
"untrackedPresent_one": "存在 {{count}} 个未跟踪的文件(不受重置影响)。",
"untrackedPresent_other": "存在 {{count}} 个未跟踪的文件(不受重置影响)。",
"forceReset": "强制重置(丢弃未提交的更改)",
"uncommittedWillDiscard": "未提交的更改将被丢弃。",
"uncommittedPresentHint": "存在未提交的更改。请打开强制重置或提交/暂存后继续。"
},
"buttons": {
"retry": "重试"
}
} }
} }