Merge branch 'main' into cv-main-xx1jlt

This commit is contained in:
xintaofei
2026-03-15 22:46:27 +08:00
14 changed files with 293 additions and 50 deletions

View File

@@ -489,7 +489,7 @@ function RenderNode({
return ( return (
<ContextMenu> <ContextMenu>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFile <FileTreeFile
path={node.path} path={node.path}
name={node.name} name={node.name}
@@ -614,7 +614,7 @@ function RenderNode({
return ( return (
<ContextMenu> <ContextMenu>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFolder <FileTreeFolder
path={node.path} path={node.path}
name={node.name} name={node.name}
@@ -2128,7 +2128,7 @@ export function FileTreeTab() {
> >
{folder?.path && ( {folder?.path && (
<ContextMenu> <ContextMenu>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFolder <FileTreeFolder
path={FILE_TREE_ROOT_PATH} path={FILE_TREE_ROOT_PATH}
name={rootNodeName} name={rootNodeName}

View File

@@ -900,7 +900,7 @@ export function GitChangesTab() {
return ( return (
<ContextMenu key={`tracked:${node.path}`}> <ContextMenu key={`tracked:${node.path}`}>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFolder <FileTreeFolder
path={node.path} path={node.path}
name={node.name} name={node.name}
@@ -956,7 +956,7 @@ export function GitChangesTab() {
return ( return (
<ContextMenu key={`tracked:${file.path}`}> <ContextMenu key={`tracked:${file.path}`}>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFile <FileTreeFile
className="w-full min-w-0 cursor-pointer" className="w-full min-w-0 cursor-pointer"
name={node.name} name={node.name}
@@ -1047,7 +1047,7 @@ export function GitChangesTab() {
return ( return (
<ContextMenu key={`untracked:${node.path}`}> <ContextMenu key={`untracked:${node.path}`}>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFolder <FileTreeFolder
path={node.path} path={node.path}
name={node.name} name={node.name}
@@ -1102,7 +1102,7 @@ export function GitChangesTab() {
return ( return (
<ContextMenu key={`untracked:${file.path}`}> <ContextMenu key={`untracked:${file.path}`}>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFile <FileTreeFile
className="w-full min-w-0 cursor-pointer" className="w-full min-w-0 cursor-pointer"
name={node.name} name={node.name}
@@ -1239,7 +1239,7 @@ export function GitChangesTab() {
onExpandedChange={setExpandedTrackedPaths} onExpandedChange={setExpandedTrackedPaths}
> >
<ContextMenu> <ContextMenu>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFolder <FileTreeFolder
path={TRACKED_ROOT_PATH} path={TRACKED_ROOT_PATH}
name={folderName} name={folderName}
@@ -1332,7 +1332,7 @@ export function GitChangesTab() {
onExpandedChange={setExpandedUntrackedPaths} onExpandedChange={setExpandedUntrackedPaths}
> >
<ContextMenu> <ContextMenu>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFolder <FileTreeFolder
path={UNTRACKED_ROOT_PATH} path={UNTRACKED_ROOT_PATH}
name={folderName} name={folderName}

View File

@@ -422,7 +422,7 @@ function CommitFilesTree({
const file = node.change const file = node.change
return ( return (
<ContextMenu key={`${commitHash}:${file.path}`}> <ContextMenu key={`${commitHash}:${file.path}`}>
<ContextMenuTrigger asChild> <ContextMenuTrigger>
<FileTreeFile <FileTreeFile
className="w-full min-w-0 cursor-pointer" className="w-full min-w-0 cursor-pointer"
name={node.name} name={node.name}

View File

@@ -157,6 +157,12 @@ function buildFileTree(entries: GitStatusEntry[]): TreeNode[] {
return toNodes(root) return toNodes(root)
} }
/** Collect all file paths under a tree node (recursive). */
function collectFilePaths(node: TreeNode): string[] {
if (node.kind === "file") return [node.path]
return node.children.flatMap(collectFilePaths)
}
/** Depth-first traversal to find the first file node (matches visual order). */ /** Depth-first traversal to find the first file node (matches visual order). */
function findFirstFile(nodes: TreeNode[]): string | undefined { function findFirstFile(nodes: TreeNode[]): string | undefined {
for (const node of nodes) { for (const node of nodes) {
@@ -523,6 +529,99 @@ export function CommitWorkspace({
[folderPath, loadStatus, t] [folderPath, loadStatus, t]
) )
const handleRollbackDir = useCallback(
(dirPath: string, files: string[], displayName?: string) => {
const label = displayName ?? dirPath
setConfirm({
open: true,
title: t("confirm.rollbackTitle"),
description: t("confirm.rollbackDirDescription", { dir: label }),
variant: "destructive",
action: () => {
void (async () => {
if (!folderPath) return
try {
await gitRollbackFile(folderPath, dirPath)
toast.success(t("toasts.dirRolledBack"), {
description: label,
})
if (diffFileRef.current && files.includes(diffFileRef.current)) {
setDiffFile(null)
setDiffOriginal("")
setDiffModified("")
}
setSelected((prev) => {
const next = new Set(prev)
files.forEach((f) => next.delete(f))
return next
})
void loadStatus()
} catch (err) {
toast.error(t("toasts.rollbackFailed"), {
description: String(err),
})
}
})()
},
})
},
[folderPath, loadStatus, t]
)
const handleDeleteDir = useCallback(
(dirPath: string, files: string[], displayName?: string) => {
const label = displayName ?? dirPath
setConfirm({
open: true,
title: t("confirm.deleteTitle"),
description: t("confirm.deleteDirDescription", { dir: label }),
variant: "destructive",
action: () => {
void (async () => {
if (!folderPath) return
try {
await deleteFileTreeEntry(folderPath, dirPath)
toast.success(t("toasts.dirDeleted"), {
description: label,
})
if (diffFileRef.current && files.includes(diffFileRef.current)) {
setDiffFile(null)
setDiffOriginal("")
setDiffModified("")
}
setSelected((prev) => {
const next = new Set(prev)
files.forEach((f) => next.delete(f))
return next
})
void loadStatus()
} catch (err) {
toast.error(t("toasts.deleteFailed"), {
description: String(err),
})
}
})()
},
})
},
[folderPath, loadStatus, t]
)
const handleAddDirToVcs = useCallback(
async (dirPath: string, files: string[], displayName?: string) => {
if (!folderPath) return
const label = displayName ?? dirPath
try {
await gitAddFiles(folderPath, files)
toast.success(t("toasts.addedToVcs"), { description: label })
void loadStatus()
} catch (err) {
toast.error(t("toasts.addToVcsFailed"), { description: String(err) })
}
},
[folderPath, loadStatus, t]
)
const closeConfirm = useCallback(() => { const closeConfirm = useCallback(() => {
setConfirm(CONFIRM_INITIAL) setConfirm(CONFIRM_INITIAL)
}, []) }, [])
@@ -607,14 +706,36 @@ export function CommitWorkspace({
const renderTrackedNode = useCallback( const renderTrackedNode = useCallback(
function renderNode(node: TreeNode): React.ReactNode { function renderNode(node: TreeNode): React.ReactNode {
if (node.kind === "dir") { if (node.kind === "dir") {
const dirFiles = collectFilePaths(node)
const hasNonDeleted = node.children.some(
(child) =>
child.kind === "file" &&
child.entry.status !== " D" &&
child.entry.status !== "D"
)
return ( return (
<FileTreeFolder <ContextMenu key={`tracked:${node.path}`}>
key={`tracked:${node.path}`} <ContextMenuTrigger>
name={node.name} <FileTreeFolder name={node.name} path={node.path}>
path={node.path} {node.children.map(renderNode)}
> </FileTreeFolder>
{node.children.map(renderNode)} </ContextMenuTrigger>
</FileTreeFolder> <ContextMenuContent>
{hasNonDeleted && (
<ContextMenuItem
onClick={() => handleRollbackDir(node.path, dirFiles)}
>
{t("actions.rollback")}
</ContextMenuItem>
)}
<ContextMenuItem
variant="destructive"
onClick={() => handleDeleteDir(node.path, dirFiles)}
>
{tCommon("delete")}
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
) )
} }
@@ -686,7 +807,9 @@ export function CommitWorkspace({
toggleFile, toggleFile,
handleViewDiff, handleViewDiff,
handleRollbackFile, handleRollbackFile,
handleRollbackDir,
handleDeleteFile, handleDeleteFile,
handleDeleteDir,
t, t,
tCommon, tCommon,
] ]
@@ -695,14 +818,31 @@ export function CommitWorkspace({
const renderUntrackedNode = useCallback( const renderUntrackedNode = useCallback(
function renderNode(node: TreeNode): React.ReactNode { function renderNode(node: TreeNode): React.ReactNode {
if (node.kind === "dir") { if (node.kind === "dir") {
const dirFiles = collectFilePaths(node)
return ( return (
<FileTreeFolder <ContextMenu key={`untracked:${node.path}`}>
key={`untracked:${node.path}`} <ContextMenuTrigger>
name={node.name} <FileTreeFolder name={node.name} path={node.path}>
path={node.path} {node.children.map(renderNode)}
> </FileTreeFolder>
{node.children.map(renderNode)} </ContextMenuTrigger>
</FileTreeFolder> <ContextMenuContent>
<ContextMenuItem
onClick={() => {
void handleAddDirToVcs(node.path, dirFiles)
}}
>
{t("actions.addToVcs")}
</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem
variant="destructive"
onClick={() => handleDeleteDir(node.path, dirFiles)}
>
{tCommon("delete")}
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
) )
} }
@@ -768,7 +908,9 @@ export function CommitWorkspace({
toggleFile, toggleFile,
handleViewDiff, handleViewDiff,
handleAddToVcs, handleAddToVcs,
handleAddDirToVcs,
handleDeleteFile, handleDeleteFile,
handleDeleteDir,
t, t,
tCommon, tCommon,
] ]
@@ -879,9 +1021,37 @@ export function CommitWorkspace({
selectedPath={diffFile ?? undefined} selectedPath={diffFile ?? undefined}
onSelect={handleSelectPath} onSelect={handleSelectPath}
> >
<FileTreeFolder name={folderName} path={folderName}> <ContextMenu>
{trackedTree.map(renderTrackedNode)} <ContextMenuTrigger>
</FileTreeFolder> <FileTreeFolder
name={folderName}
path={folderName}
>
{trackedTree.map(renderTrackedNode)}
</FileTreeFolder>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
onClick={() =>
handleRollbackDir(
".",
trackedFiles,
folderName
)
}
>
{t("actions.rollback")}
</ContextMenuItem>
<ContextMenuItem
variant="destructive"
onClick={() =>
handleDeleteDir(".", trackedFiles, folderName)
}
>
{tCommon("delete")}
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
</FileTree> </FileTree>
</section> </section>
)} )}
@@ -933,9 +1103,42 @@ export function CommitWorkspace({
selectedPath={diffFile ?? undefined} selectedPath={diffFile ?? undefined}
onSelect={handleSelectPath} onSelect={handleSelectPath}
> >
<FileTreeFolder name={folderName} path={folderName}> <ContextMenu>
{untrackedTree.map(renderUntrackedNode)} <ContextMenuTrigger>
</FileTreeFolder> <FileTreeFolder
name={folderName}
path={folderName}
>
{untrackedTree.map(renderUntrackedNode)}
</FileTreeFolder>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
onClick={() => {
void handleAddDirToVcs(
".",
untrackedFiles,
folderName
)
}}
>
{t("actions.addToVcs")}
</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem
variant="destructive"
onClick={() =>
handleDeleteDir(
".",
untrackedFiles,
folderName
)
}
>
{tCommon("delete")}
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
</FileTree> </FileTree>
)} )}
</section> </section>

View File

@@ -895,13 +895,17 @@
"fileDeleted": "تم حذف الملف", "fileDeleted": "تم حذف الملف",
"deleteFailed": "فشل الحذف", "deleteFailed": "فشل الحذف",
"fileRolledBack": "تم التراجع عن الملف", "fileRolledBack": "تم التراجع عن الملف",
"rollbackFailed": "فشل التراجع" "rollbackFailed": "فشل التراجع",
"dirRolledBack": "تم استعادة المجلد",
"dirDeleted": "تم حذف المجلد"
}, },
"confirm": { "confirm": {
"deleteTitle": "تأكيد الحذف", "deleteTitle": "تأكيد الحذف",
"deleteDescription": "حذف الملف \"{file}\"؟ لا يمكن التراجع عن هذا الإجراء.", "deleteDescription": "حذف الملف \"{file}\"؟ لا يمكن التراجع عن هذا الإجراء.",
"rollbackTitle": "تأكيد التراجع", "rollbackTitle": "تأكيد التراجع",
"rollbackDescription": "التراجع عن الملف \"{file}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة." "rollbackDescription": "التراجع عن الملف \"{file}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.",
"rollbackDirDescription": "هل تريد استعادة المجلد \"{dir}\" إلى HEAD؟ ستفقد التغييرات غير المحفوظة.",
"deleteDirDescription": "هل تريد حذف المجلد \"{dir}\"؟ لا يمكن التراجع عن هذا الإجراء."
}, },
"actions": { "actions": {
"select": "تحديد", "select": "تحديد",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "Datei gelöscht", "fileDeleted": "Datei gelöscht",
"deleteFailed": "Löschen fehlgeschlagen", "deleteFailed": "Löschen fehlgeschlagen",
"fileRolledBack": "Datei zurückgesetzt", "fileRolledBack": "Datei zurückgesetzt",
"rollbackFailed": "Rollback fehlgeschlagen" "rollbackFailed": "Rollback fehlgeschlagen",
"dirRolledBack": "Verzeichnis zurückgesetzt",
"dirDeleted": "Verzeichnis gelöscht"
}, },
"confirm": { "confirm": {
"deleteTitle": "Löschen bestätigen", "deleteTitle": "Löschen bestätigen",
"deleteDescription": "Datei \"{file}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.", "deleteDescription": "Datei \"{file}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden.",
"rollbackTitle": "Rollback bestätigen", "rollbackTitle": "Rollback bestätigen",
"rollbackDescription": "Datei \"{file}\" auf HEAD zurücksetzen? Ungespeicherte Änderungen gehen verloren." "rollbackDescription": "Datei \"{file}\" auf HEAD zurücksetzen? Ungespeicherte Änderungen gehen verloren.",
"rollbackDirDescription": "Verzeichnis \"{dir}\" auf HEAD zurücksetzen? Nicht gespeicherte Änderungen gehen verloren.",
"deleteDirDescription": "Verzeichnis \"{dir}\" löschen? Diese Aktion kann nicht rückgängig gemacht werden."
}, },
"actions": { "actions": {
"select": "Auswählen", "select": "Auswählen",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "File deleted", "fileDeleted": "File deleted",
"deleteFailed": "Delete failed", "deleteFailed": "Delete failed",
"fileRolledBack": "File rolled back", "fileRolledBack": "File rolled back",
"rollbackFailed": "Rollback failed" "rollbackFailed": "Rollback failed",
"dirRolledBack": "Directory rolled back",
"dirDeleted": "Directory deleted"
}, },
"confirm": { "confirm": {
"deleteTitle": "Confirm deletion", "deleteTitle": "Confirm deletion",
"deleteDescription": "Delete file \"{file}\"? This action cannot be undone.", "deleteDescription": "Delete file \"{file}\"? This action cannot be undone.",
"rollbackTitle": "Confirm rollback", "rollbackTitle": "Confirm rollback",
"rollbackDescription": "Rollback file \"{file}\" to HEAD? Unsaved changes will be lost." "rollbackDescription": "Rollback file \"{file}\" to HEAD? Unsaved changes will be lost.",
"rollbackDirDescription": "Rollback directory \"{dir}\" to HEAD? Unsaved changes will be lost.",
"deleteDirDescription": "Delete directory \"{dir}\"? This action cannot be undone."
}, },
"actions": { "actions": {
"select": "Select", "select": "Select",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "Archivo eliminado", "fileDeleted": "Archivo eliminado",
"deleteFailed": "Error al eliminar", "deleteFailed": "Error al eliminar",
"fileRolledBack": "Archivo revertido", "fileRolledBack": "Archivo revertido",
"rollbackFailed": "Error al revertir" "rollbackFailed": "Error al revertir",
"dirRolledBack": "Directorio revertido",
"dirDeleted": "Directorio eliminado"
}, },
"confirm": { "confirm": {
"deleteTitle": "Confirmar eliminación", "deleteTitle": "Confirmar eliminación",
"deleteDescription": "¿Eliminar el archivo \"{file}\"? Esta acción no se puede deshacer.", "deleteDescription": "¿Eliminar el archivo \"{file}\"? Esta acción no se puede deshacer.",
"rollbackTitle": "Confirmar reversión", "rollbackTitle": "Confirmar reversión",
"rollbackDescription": "¿Revertir el archivo \"{file}\" a HEAD? Se perderán los cambios sin guardar." "rollbackDescription": "¿Revertir el archivo \"{file}\" a HEAD? Se perderán los cambios sin guardar.",
"rollbackDirDescription": "¿Revertir el directorio \"{dir}\" a HEAD? Los cambios no guardados se perderán.",
"deleteDirDescription": "¿Eliminar el directorio \"{dir}\"? Esta acción no se puede deshacer."
}, },
"actions": { "actions": {
"select": "Seleccionar", "select": "Seleccionar",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "Fichier supprimé", "fileDeleted": "Fichier supprimé",
"deleteFailed": "Échec de la suppression", "deleteFailed": "Échec de la suppression",
"fileRolledBack": "Fichier restauré", "fileRolledBack": "Fichier restauré",
"rollbackFailed": "Échec du rollback" "rollbackFailed": "Échec du rollback",
"dirRolledBack": "Répertoire restauré",
"dirDeleted": "Répertoire supprimé"
}, },
"confirm": { "confirm": {
"deleteTitle": "Confirmer la suppression", "deleteTitle": "Confirmer la suppression",
"deleteDescription": "Supprimer le fichier \"{file}\" ? Cette action est irréversible.", "deleteDescription": "Supprimer le fichier \"{file}\" ? Cette action est irréversible.",
"rollbackTitle": "Confirmer le rollback", "rollbackTitle": "Confirmer le rollback",
"rollbackDescription": "Restaurer le fichier \"{file}\" vers HEAD ? Les modifications non enregistrées seront perdues." "rollbackDescription": "Restaurer le fichier \"{file}\" vers HEAD ? Les modifications non enregistrées seront perdues.",
"rollbackDirDescription": "Restaurer le répertoire \"{dir}\" vers HEAD ? Les modifications non enregistrées seront perdues.",
"deleteDirDescription": "Supprimer le répertoire \"{dir}\" ? Cette action est irréversible."
}, },
"actions": { "actions": {
"select": "Sélectionner", "select": "Sélectionner",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "ファイルを削除しました", "fileDeleted": "ファイルを削除しました",
"deleteFailed": "削除に失敗しました", "deleteFailed": "削除に失敗しました",
"fileRolledBack": "ファイルをロールバックしました", "fileRolledBack": "ファイルをロールバックしました",
"rollbackFailed": "ロールバックに失敗しました" "rollbackFailed": "ロールバックに失敗しました",
"dirRolledBack": "ディレクトリをロールバックしました",
"dirDeleted": "ディレクトリを削除しました"
}, },
"confirm": { "confirm": {
"deleteTitle": "削除の確認", "deleteTitle": "削除の確認",
"deleteDescription": "ファイル \"{file}\" を削除しますか?この操作は元に戻せません。", "deleteDescription": "ファイル \"{file}\" を削除しますか?この操作は元に戻せません。",
"rollbackTitle": "ロールバックの確認", "rollbackTitle": "ロールバックの確認",
"rollbackDescription": "ファイル \"{file}\" を HEAD にロールバックしますか?未保存の変更は失われます。" "rollbackDescription": "ファイル \"{file}\" を HEAD にロールバックしますか?未保存の変更は失われます。",
"rollbackDirDescription": "ディレクトリ「{dir}」をHEADにロールバックしますか未保存の変更は失われます。",
"deleteDirDescription": "ディレクトリ「{dir}」を削除しますか?この操作は元に戻せません。"
}, },
"actions": { "actions": {
"select": "選択", "select": "選択",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "파일이 삭제되었습니다", "fileDeleted": "파일이 삭제되었습니다",
"deleteFailed": "삭제에 실패했습니다", "deleteFailed": "삭제에 실패했습니다",
"fileRolledBack": "파일이 롤백되었습니다", "fileRolledBack": "파일이 롤백되었습니다",
"rollbackFailed": "롤백에 실패했습니다" "rollbackFailed": "롤백에 실패했습니다",
"dirRolledBack": "디렉토리가 롤백되었습니다",
"dirDeleted": "디렉토리가 삭제되었습니다"
}, },
"confirm": { "confirm": {
"deleteTitle": "삭제 확인", "deleteTitle": "삭제 확인",
"deleteDescription": "파일 \"{file}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.", "deleteDescription": "파일 \"{file}\"을(를) 삭제할까요? 이 작업은 되돌릴 수 없습니다.",
"rollbackTitle": "롤백 확인", "rollbackTitle": "롤백 확인",
"rollbackDescription": "파일 \"{file}\"을(를) HEAD로 롤백할까요? 저장되지 않은 변경 사항은 사라집니다." "rollbackDescription": "파일 \"{file}\"을(를) HEAD로 롤백할까요? 저장되지 않은 변경 사항은 사라집니다.",
"rollbackDirDescription": "디렉토리 \"{dir}\"를 HEAD로 롤백하시겠습니까? 저장되지 않은 변경 사항이 손실됩니다.",
"deleteDirDescription": "디렉토리 \"{dir}\"를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
}, },
"actions": { "actions": {
"select": "선택", "select": "선택",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "Arquivo excluído", "fileDeleted": "Arquivo excluído",
"deleteFailed": "Falha ao excluir", "deleteFailed": "Falha ao excluir",
"fileRolledBack": "Arquivo revertido", "fileRolledBack": "Arquivo revertido",
"rollbackFailed": "Falha no rollback" "rollbackFailed": "Falha no rollback",
"dirRolledBack": "Diretório revertido",
"dirDeleted": "Diretório excluído"
}, },
"confirm": { "confirm": {
"deleteTitle": "Confirmar exclusão", "deleteTitle": "Confirmar exclusão",
"deleteDescription": "Excluir o arquivo \"{file}\"? Esta ação não pode ser desfeita.", "deleteDescription": "Excluir o arquivo \"{file}\"? Esta ação não pode ser desfeita.",
"rollbackTitle": "Confirmar rollback", "rollbackTitle": "Confirmar rollback",
"rollbackDescription": "Reverter o arquivo \"{file}\" para o HEAD? Alterações não salvas serão perdidas." "rollbackDescription": "Reverter o arquivo \"{file}\" para o HEAD? Alterações não salvas serão perdidas.",
"rollbackDirDescription": "Reverter o diretório \"{dir}\" para HEAD? Alterações não salvas serão perdidas.",
"deleteDirDescription": "Excluir o diretório \"{dir}\"? Esta ação não pode ser desfeita."
}, },
"actions": { "actions": {
"select": "Selecionar", "select": "Selecionar",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "文件已删除", "fileDeleted": "文件已删除",
"deleteFailed": "删除失败", "deleteFailed": "删除失败",
"fileRolledBack": "文件已回滚", "fileRolledBack": "文件已回滚",
"rollbackFailed": "回滚失败" "rollbackFailed": "回滚失败",
"dirRolledBack": "目录已回滚",
"dirDeleted": "目录已删除"
}, },
"confirm": { "confirm": {
"deleteTitle": "确认删除", "deleteTitle": "确认删除",
"deleteDescription": "确定要删除文件「{file}」吗?此操作不可恢复。", "deleteDescription": "确定要删除文件「{file}」吗?此操作不可恢复。",
"rollbackTitle": "确认回滚", "rollbackTitle": "确认回滚",
"rollbackDescription": "确定要回滚文件「{file}」到 HEAD 版本吗?未保存的修改将丢失。" "rollbackDescription": "确定要回滚文件「{file}」到 HEAD 版本吗?未保存的修改将丢失。",
"rollbackDirDescription": "确定要回滚目录「{dir}」到 HEAD 版本吗?未保存的修改将丢失。",
"deleteDirDescription": "确定要删除目录「{dir}」吗?此操作不可恢复。"
}, },
"actions": { "actions": {
"select": "选择", "select": "选择",

View File

@@ -895,13 +895,17 @@
"fileDeleted": "檔案已刪除", "fileDeleted": "檔案已刪除",
"deleteFailed": "刪除失敗", "deleteFailed": "刪除失敗",
"fileRolledBack": "檔案已回滾", "fileRolledBack": "檔案已回滾",
"rollbackFailed": "回滾失敗" "rollbackFailed": "回滾失敗",
"dirRolledBack": "目錄已回滾",
"dirDeleted": "目錄已刪除"
}, },
"confirm": { "confirm": {
"deleteTitle": "確認刪除", "deleteTitle": "確認刪除",
"deleteDescription": "確定要刪除檔案「{file}」嗎?此操作無法復原。", "deleteDescription": "確定要刪除檔案「{file}」嗎?此操作無法復原。",
"rollbackTitle": "確認回滾", "rollbackTitle": "確認回滾",
"rollbackDescription": "確定要回滾檔案「{file}」到 HEAD 版本嗎?未儲存修改將遺失。" "rollbackDescription": "確定要回滾檔案「{file}」到 HEAD 版本嗎?未儲存修改將遺失。",
"rollbackDirDescription": "確定要回滾目錄「{dir}」到 HEAD 版本嗎?未儲存的修改將遺失。",
"deleteDirDescription": "確定要刪除目錄「{dir}」嗎?此操作不可恢復。"
}, },
"actions": { "actions": {
"select": "選擇", "select": "選擇",