feat: Redesign git changes to split stage/unstaged files. (#1359)
* feat: Redesign git changes to split stage/unstaged files. Signed-off-by: Paolo Insogna <paolo@cowtech.it> * fixup Signed-off-by: Paolo Insogna <paolo@cowtech.it> * fixup Signed-off-by: Paolo Insogna <paolo@cowtech.it> * refactor: streamline git changes panel * fix: label staged and working diff tabs * fix: isolate staged and working diff files * fix: scope staged and working diff updates * fix: scope git row revert to working changes --------- Signed-off-by: Paolo Insogna <paolo@cowtech.it> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Bohdan Triapitsyn
parent
9af0de0056
commit
e16097b05d
@@ -388,6 +388,7 @@ export interface GitRemoveRemotePayload {
|
||||
export interface CreateGitCommitOptions {
|
||||
addAll?: boolean;
|
||||
files?: string[];
|
||||
stageFiles?: string[];
|
||||
}
|
||||
|
||||
export interface GitLogOptions {
|
||||
@@ -421,7 +422,11 @@ export interface GitAPI {
|
||||
getGitStatus(directory: string, options?: { mode?: 'light' }): Promise<GitStatus>;
|
||||
getGitDiff(directory: string, options: GetGitDiffOptions): Promise<GitDiffResponse>;
|
||||
getGitFileDiff(directory: string, options: GetGitFileDiffOptions): Promise<GitFileDiffResponse>;
|
||||
revertGitFile(directory: string, filePath: string): Promise<void>;
|
||||
revertGitFile(directory: string, filePath: string, options?: { scope?: 'all' | 'working' }): Promise<void>;
|
||||
stageGitFile(directory: string, filePath: string): Promise<void>;
|
||||
stageGitFiles?(directory: string, filePaths: string[]): Promise<void>;
|
||||
unstageGitFile(directory: string, filePath: string): Promise<void>;
|
||||
unstageGitFiles?(directory: string, filePaths: string[]): Promise<void>;
|
||||
isLinkedWorktree(directory: string): Promise<boolean>;
|
||||
getGitBranches(directory: string): Promise<GitBranch>;
|
||||
deleteGitBranch(directory: string, payload: GitDeleteBranchPayload): Promise<{ success: boolean }>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import type { GitAPI, GitStatus } from "./api/types"
|
||||
import { getGitStatus } from "./gitApi"
|
||||
import { getGitStatus, stageGitFile, stageGitFiles, unstageGitFile, unstageGitFiles } from "./gitApi"
|
||||
|
||||
const status: GitStatus = {
|
||||
current: "main",
|
||||
@@ -48,3 +48,65 @@ describe("getGitStatus", () => {
|
||||
expect(received).toEqual({ directory: "/repo", options: { mode: "light" } })
|
||||
})
|
||||
})
|
||||
|
||||
describe("git index mutations", () => {
|
||||
test("forwards bulk stage requests to runtime git APIs", async () => {
|
||||
let received: { directory: string; paths: string[] } | null = null
|
||||
const runtimeGit = {
|
||||
stageGitFiles: async (directory: string, paths: string[]) => {
|
||||
received = { directory, paths }
|
||||
},
|
||||
} as Partial<GitAPI> as GitAPI
|
||||
|
||||
await withRuntimeGit(runtimeGit, async () => {
|
||||
await stageGitFiles("/repo", ["a.ts", "b.ts"])
|
||||
})
|
||||
|
||||
expect(received).toEqual({ directory: "/repo", paths: ["a.ts", "b.ts"] })
|
||||
})
|
||||
|
||||
test("forwards bulk unstage requests to runtime git APIs", async () => {
|
||||
let received: { directory: string; paths: string[] } | null = null
|
||||
const runtimeGit = {
|
||||
unstageGitFiles: async (directory: string, paths: string[]) => {
|
||||
received = { directory, paths }
|
||||
},
|
||||
} as Partial<GitAPI> as GitAPI
|
||||
|
||||
await withRuntimeGit(runtimeGit, async () => {
|
||||
await unstageGitFiles("/repo", ["a.ts", "b.ts"])
|
||||
})
|
||||
|
||||
expect(received).toEqual({ directory: "/repo", paths: ["a.ts", "b.ts"] })
|
||||
})
|
||||
|
||||
test("keeps single-file stage wrapper routed to runtime single-file API", async () => {
|
||||
let received: { directory: string; path: string } | null = null
|
||||
const runtimeGit = {
|
||||
stageGitFile: async (directory: string, path: string) => {
|
||||
received = { directory, path }
|
||||
},
|
||||
} as Partial<GitAPI> as GitAPI
|
||||
|
||||
await withRuntimeGit(runtimeGit, async () => {
|
||||
await stageGitFile("/repo", "a.ts")
|
||||
})
|
||||
|
||||
expect(received).toEqual({ directory: "/repo", path: "a.ts" })
|
||||
})
|
||||
|
||||
test("keeps single-file unstage wrapper routed to runtime single-file API", async () => {
|
||||
let received: { directory: string; path: string } | null = null
|
||||
const runtimeGit = {
|
||||
unstageGitFile: async (directory: string, path: string) => {
|
||||
received = { directory, path }
|
||||
},
|
||||
} as Partial<GitAPI> as GitAPI
|
||||
|
||||
await withRuntimeGit(runtimeGit, async () => {
|
||||
await unstageGitFile("/repo", "a.ts")
|
||||
})
|
||||
|
||||
expect(received).toEqual({ directory: "/repo", path: "a.ts" })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -126,10 +126,38 @@ export async function getGitFileDiff(
|
||||
return gitHttp.getGitFileDiff(directory, options);
|
||||
}
|
||||
|
||||
export async function revertGitFile(directory: string, filePath: string): Promise<void> {
|
||||
export async function revertGitFile(
|
||||
directory: string,
|
||||
filePath: string,
|
||||
options?: { scope?: 'all' | 'working' }
|
||||
): Promise<void> {
|
||||
const runtime = getRuntimeGit();
|
||||
if (runtime) return runtime.revertGitFile(directory, filePath);
|
||||
return gitHttp.revertGitFile(directory, filePath);
|
||||
if (runtime) return runtime.revertGitFile(directory, filePath, options);
|
||||
return gitHttp.revertGitFile(directory, filePath, options);
|
||||
}
|
||||
|
||||
export async function stageGitFile(directory: string, filePath: string): Promise<void> {
|
||||
const runtime = getRuntimeGit();
|
||||
if (runtime?.stageGitFile) return runtime.stageGitFile(directory, filePath);
|
||||
return gitHttp.stageGitFile(directory, filePath);
|
||||
}
|
||||
|
||||
export async function stageGitFiles(directory: string, filePaths: string[]): Promise<void> {
|
||||
const runtime = getRuntimeGit();
|
||||
if (runtime?.stageGitFiles) return runtime.stageGitFiles(directory, filePaths);
|
||||
return gitHttp.stageGitFiles(directory, filePaths);
|
||||
}
|
||||
|
||||
export async function unstageGitFile(directory: string, filePath: string): Promise<void> {
|
||||
const runtime = getRuntimeGit();
|
||||
if (runtime?.unstageGitFile) return runtime.unstageGitFile(directory, filePath);
|
||||
return gitHttp.unstageGitFile(directory, filePath);
|
||||
}
|
||||
|
||||
export async function unstageGitFiles(directory: string, filePaths: string[]): Promise<void> {
|
||||
const runtime = getRuntimeGit();
|
||||
if (runtime?.unstageGitFiles) return runtime.unstageGitFiles(directory, filePaths);
|
||||
return gitHttp.unstageGitFiles(directory, filePaths);
|
||||
}
|
||||
|
||||
export async function isLinkedWorktree(directory: string): Promise<boolean> {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { stageGitFile, stageGitFiles, unstageGitFile, unstageGitFiles } from './gitApiHttp';
|
||||
|
||||
type FetchCall = {
|
||||
input: RequestInfo | URL;
|
||||
init?: RequestInit;
|
||||
};
|
||||
|
||||
const previousFetch = globalThis.fetch;
|
||||
const previousWindowDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'window');
|
||||
|
||||
const installFetchMock = () => {
|
||||
const calls: FetchCall[] = [];
|
||||
globalThis.fetch = (async (input, init) => {
|
||||
calls.push({ input, init });
|
||||
return new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}) as typeof fetch;
|
||||
return calls;
|
||||
};
|
||||
|
||||
const installWindowMock = () => {
|
||||
Object.defineProperty(globalThis, 'window', {
|
||||
configurable: true,
|
||||
value: {
|
||||
location: { origin: 'http://localhost:3000' },
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const restoreMocks = () => {
|
||||
globalThis.fetch = previousFetch;
|
||||
if (previousWindowDescriptor) {
|
||||
Object.defineProperty(globalThis, 'window', previousWindowDescriptor);
|
||||
} else {
|
||||
delete (globalThis as { window?: Window }).window;
|
||||
}
|
||||
};
|
||||
|
||||
const captureError = async (callback: () => Promise<void>): Promise<unknown> => {
|
||||
try {
|
||||
await callback();
|
||||
return null;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
describe('gitApiHttp index mutations', () => {
|
||||
test('sends bulk stage payloads as paths', async () => {
|
||||
installWindowMock();
|
||||
const calls = installFetchMock();
|
||||
try {
|
||||
await stageGitFiles('/repo', ['a.ts', 'b.ts']);
|
||||
|
||||
expect(calls).toHaveLength(1);
|
||||
expect(String(calls[0].input)).toBe('http://localhost:3000/api/git/stage?directory=%2Frepo');
|
||||
expect(calls[0].init?.method).toBe('POST');
|
||||
expect(JSON.parse(String(calls[0].init?.body))).toEqual({ paths: ['a.ts', 'b.ts'] });
|
||||
} finally {
|
||||
restoreMocks();
|
||||
}
|
||||
});
|
||||
|
||||
test('sends bulk unstage payloads as paths', async () => {
|
||||
installWindowMock();
|
||||
const calls = installFetchMock();
|
||||
try {
|
||||
await unstageGitFiles('/repo', ['a.ts', 'b.ts']);
|
||||
|
||||
expect(calls).toHaveLength(1);
|
||||
expect(String(calls[0].input)).toBe('http://localhost:3000/api/git/unstage?directory=%2Frepo');
|
||||
expect(calls[0].init?.method).toBe('POST');
|
||||
expect(JSON.parse(String(calls[0].init?.body))).toEqual({ paths: ['a.ts', 'b.ts'] });
|
||||
} finally {
|
||||
restoreMocks();
|
||||
}
|
||||
});
|
||||
|
||||
test('single-file helpers use the bulk paths payload shape', async () => {
|
||||
installWindowMock();
|
||||
const calls = installFetchMock();
|
||||
try {
|
||||
await stageGitFile('/repo', 'a.ts');
|
||||
await unstageGitFile('/repo', 'b.ts');
|
||||
|
||||
expect(JSON.parse(String(calls[0].init?.body))).toEqual({ paths: ['a.ts'] });
|
||||
expect(JSON.parse(String(calls[1].init?.body))).toEqual({ paths: ['b.ts'] });
|
||||
} finally {
|
||||
restoreMocks();
|
||||
}
|
||||
});
|
||||
|
||||
test('rejects empty bulk path lists before fetching', async () => {
|
||||
installWindowMock();
|
||||
const calls = installFetchMock();
|
||||
try {
|
||||
const stageError = await captureError(() => stageGitFiles('/repo', [' ', '']));
|
||||
const unstageError = await captureError(() => unstageGitFiles('/repo', []));
|
||||
|
||||
expect(stageError).toBeInstanceOf(Error);
|
||||
expect((stageError as Error).message).toBe('path is required to stage git changes');
|
||||
expect(unstageError).toBeInstanceOf(Error);
|
||||
expect((unstageError as Error).message).toBe('path is required to unstage git changes');
|
||||
expect(calls).toHaveLength(0);
|
||||
} finally {
|
||||
restoreMocks();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -200,7 +200,11 @@ export async function getGitFileDiff(directory: string, options: GetGitFileDiffO
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function revertGitFile(directory: string, filePath: string): Promise<void> {
|
||||
export async function revertGitFile(
|
||||
directory: string,
|
||||
filePath: string,
|
||||
options?: { scope?: 'all' | 'working' }
|
||||
): Promise<void> {
|
||||
if (!filePath) {
|
||||
throw new Error('path is required to revert git changes');
|
||||
}
|
||||
@@ -208,7 +212,7 @@ export async function revertGitFile(directory: string, filePath: string): Promis
|
||||
const response = await fetch(buildUrl(`${API_BASE}/revert`, directory), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ path: filePath }),
|
||||
body: JSON.stringify({ path: filePath, scope: options?.scope }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -219,6 +223,52 @@ export async function revertGitFile(directory: string, filePath: string): Promis
|
||||
}
|
||||
}
|
||||
|
||||
export async function stageGitFile(directory: string, filePath: string): Promise<void> {
|
||||
await stageGitFiles(directory, [filePath]);
|
||||
}
|
||||
|
||||
export async function stageGitFiles(directory: string, filePaths: string[]): Promise<void> {
|
||||
const paths = filePaths.map((path) => path.trim()).filter(Boolean);
|
||||
|
||||
if (paths.length === 0) {
|
||||
throw new Error('path is required to stage git changes');
|
||||
}
|
||||
|
||||
const response = await fetch(buildUrl(`${API_BASE}/stage`, directory), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ paths }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const message = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(message.error || 'Failed to stage git changes');
|
||||
}
|
||||
}
|
||||
|
||||
export async function unstageGitFile(directory: string, filePath: string): Promise<void> {
|
||||
await unstageGitFiles(directory, [filePath]);
|
||||
}
|
||||
|
||||
export async function unstageGitFiles(directory: string, filePaths: string[]): Promise<void> {
|
||||
const paths = filePaths.map((path) => path.trim()).filter(Boolean);
|
||||
|
||||
if (paths.length === 0) {
|
||||
throw new Error('path is required to unstage git changes');
|
||||
}
|
||||
|
||||
const response = await fetch(buildUrl(`${API_BASE}/unstage`, directory), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ paths }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const message = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(message.error || 'Failed to unstage git changes');
|
||||
}
|
||||
}
|
||||
|
||||
export async function isLinkedWorktree(directory: string): Promise<boolean> {
|
||||
if (!directory) {
|
||||
return false;
|
||||
@@ -494,6 +544,7 @@ export async function createGitCommit(
|
||||
message,
|
||||
addAll: options.addAll ?? false,
|
||||
files: options.files,
|
||||
stageFiles: options.stageFiles,
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
|
||||
@@ -451,8 +451,16 @@ export const dict = {
|
||||
'gitView.changes.reverting': 'Reverting...',
|
||||
'gitView.changes.selectAllAria': 'Select all files',
|
||||
'gitView.changes.selectFileAria': 'Select File aria label',
|
||||
'gitView.changes.stagedTitle': 'Staged',
|
||||
'gitView.changes.resizeSplitAria': 'Resize staged and unstaged changes',
|
||||
'gitView.changes.stageAllAria': 'Stage all changes',
|
||||
'gitView.changes.stageDirectoryAria': 'Stage all changes in {path}',
|
||||
'gitView.changes.stageFileAria': 'Stage {path}',
|
||||
'gitView.changes.title': 'Changes',
|
||||
'gitView.changes.toggleDirectorySelectionAria': 'Toggle Directory Selection aria label',
|
||||
'gitView.changes.unstageAllAria': 'Unstage all changes',
|
||||
'gitView.changes.unstageDirectoryAria': 'Unstage all changes in {path}',
|
||||
'gitView.changes.unstageFileAria': 'Unstage {path}',
|
||||
'gitView.commit.addGitmoji': 'Add gitmoji',
|
||||
'gitView.commit.aiHighlights.insertAria': 'Insert aria label',
|
||||
'gitView.commit.aiHighlights.insertTooltip': 'Insert tooltip',
|
||||
@@ -467,6 +475,7 @@ export const dict = {
|
||||
'gitView.commit.pushAria': 'Commit and sync',
|
||||
'gitView.commit.pushing': 'Syncing...',
|
||||
'gitView.commit.selectFilesHint': 'Select files in Changes to enable commit.',
|
||||
'gitView.commit.stageFilesHint': 'Stage files to enable commit.',
|
||||
'gitView.commit.title': 'Commit',
|
||||
'gitView.common.cancel': 'Cancel',
|
||||
'gitView.common.close': 'Close',
|
||||
@@ -775,15 +784,21 @@ export const dict = {
|
||||
'gitView.toast.revertedFilesSingle': 'Reverted {count} file',
|
||||
'gitView.toast.revertedSomePlural': 'Reverted {success} files, {failed} failed',
|
||||
'gitView.toast.revertedSomeSingle': 'Reverted {success} file, {failed} failed',
|
||||
'gitView.toast.stageFileFailed': 'Failed to stage changes',
|
||||
'gitView.toast.stageFileToCommit': 'Stage at least one file to commit',
|
||||
'gitView.toast.stageFileToDescribe': 'Stage at least one file to describe',
|
||||
'gitView.toast.selectFileToCommit': 'Select at least one file to commit',
|
||||
'gitView.toast.selectFileToDescribe': 'Select at least one file to describe',
|
||||
'gitView.toast.stashedRestored': 'Stashed changes restored',
|
||||
'gitView.toast.syncActionFailed': '{action} failed',
|
||||
'gitView.toast.unstageFileFailed': 'Failed to unstage changes',
|
||||
'gitView.toast.upstreamSet': 'Set upstream for {branch} to {remote}',
|
||||
'gitView.worktree.availableInWorktreeMode': 'Available only in worktree mode',
|
||||
'contextPanel.mode.chat': 'Chat',
|
||||
'contextPanel.mode.files': 'Files',
|
||||
'contextPanel.mode.diff': 'Diff',
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.plan': 'Plan',
|
||||
'contextPanel.mode.context': 'Context',
|
||||
'contextPanel.mode.preview': 'Preview',
|
||||
|
||||
@@ -452,8 +452,16 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.changes.reverting": "Revertiendo...",
|
||||
"gitView.changes.selectAllAria": "Seleccionar todos los archivos",
|
||||
"gitView.changes.selectFileAria": "Seleccionar archivo",
|
||||
"gitView.changes.stagedTitle": "Preparados",
|
||||
"gitView.changes.resizeSplitAria": "Ajustar tamaño de cambios preparados y sin preparar",
|
||||
"gitView.changes.stageAllAria": "Preparar todos los cambios",
|
||||
"gitView.changes.stageDirectoryAria": "Preparar todos los cambios en {path}",
|
||||
"gitView.changes.stageFileAria": "Preparar {path}",
|
||||
"gitView.changes.title": "Cambios",
|
||||
"gitView.changes.toggleDirectorySelectionAria": "Alternar selección de directorio",
|
||||
"gitView.changes.unstageAllAria": "Quitar todos los cambios del área preparada",
|
||||
"gitView.changes.unstageDirectoryAria": "Quitar del área preparada todos los cambios en {path}",
|
||||
"gitView.changes.unstageFileAria": "Quitar {path} del área preparada",
|
||||
"gitView.commit.addGitmoji": "Añadir gitmoji",
|
||||
"gitView.commit.aiHighlights.insertAria": "Insertar",
|
||||
"gitView.commit.aiHighlights.insertTooltip": "Insertar",
|
||||
@@ -468,6 +476,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.commit.pushAria": "Commit and sync",
|
||||
"gitView.commit.pushing": "Sincronizando...",
|
||||
"gitView.commit.selectFilesHint": "Selecciona archivos en Cambios para habilitar el commit.",
|
||||
"gitView.commit.stageFilesHint": "Prepara archivos para habilitar el commit.",
|
||||
"gitView.commit.title": "Commit",
|
||||
"gitView.common.cancel": "Cancelar",
|
||||
"gitView.common.close": "Cerrar",
|
||||
@@ -776,15 +785,21 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.toast.revertedFilesSingle": "{count} archivo revertido",
|
||||
"gitView.toast.revertedSomePlural": "{success} archivos revertidos, {failed} fallidos",
|
||||
"gitView.toast.revertedSomeSingle": "{success} archivo revertido, {failed} fallido",
|
||||
"gitView.toast.stageFileFailed": "No se pudieron preparar los cambios",
|
||||
"gitView.toast.stageFileToCommit": "Prepara al menos un archivo para el commit",
|
||||
"gitView.toast.stageFileToDescribe": "Prepara al menos un archivo para describir",
|
||||
"gitView.toast.selectFileToCommit": "Selecciona al menos un archivo para el commit",
|
||||
"gitView.toast.selectFileToDescribe": "Selecciona al menos un archivo para describir",
|
||||
"gitView.toast.stashedRestored": "Cambios del stash restaurados",
|
||||
"gitView.toast.syncActionFailed": "{action} falló",
|
||||
"gitView.toast.unstageFileFailed": "No se pudieron quitar los cambios del área preparada",
|
||||
"gitView.toast.upstreamSet": "Upstream de {branch} configurado como {remote}",
|
||||
"gitView.worktree.availableInWorktreeMode": "Disponible solo en modo worktree",
|
||||
"contextPanel.mode.chat": "Chat",
|
||||
"contextPanel.mode.files": "Archivos",
|
||||
"contextPanel.mode.diff": "Diff",
|
||||
"contextPanel.mode.stagedDiff": "Staged Diff",
|
||||
"contextPanel.mode.workingDiff": "Working Diff",
|
||||
"contextPanel.mode.plan": "Plan",
|
||||
"contextPanel.mode.context": "Contexto",
|
||||
"contextPanel.mode.preview": "Vista previa",
|
||||
|
||||
@@ -452,8 +452,16 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.changes.reverting': '되돌리는 중…',
|
||||
'gitView.changes.selectAllAria': '모든 파일 선택',
|
||||
'gitView.changes.selectFileAria': '파일 선택',
|
||||
'gitView.changes.stagedTitle': '스테이징됨',
|
||||
'gitView.changes.resizeSplitAria': '스테이징 및 미스테이징 변경사항 크기 조정',
|
||||
'gitView.changes.stageAllAria': '모든 변경사항 스테이징',
|
||||
'gitView.changes.stageDirectoryAria': '{path}의 모든 변경사항 스테이징',
|
||||
'gitView.changes.stageFileAria': '{path} 스테이징',
|
||||
'gitView.changes.title': '변경사항',
|
||||
'gitView.changes.toggleDirectorySelectionAria': '디렉터리 선택 전환',
|
||||
'gitView.changes.unstageAllAria': '모든 변경사항 스테이징 해제',
|
||||
'gitView.changes.unstageDirectoryAria': '{path}의 모든 변경사항 스테이징 해제',
|
||||
'gitView.changes.unstageFileAria': '{path} 스테이징 해제',
|
||||
'gitView.commit.addGitmoji': 'gitmoji 추가',
|
||||
'gitView.commit.aiHighlights.insertAria': '커밋 메시지에 삽입',
|
||||
'gitView.commit.aiHighlights.insertTooltip': '커밋 메시지에 삽입',
|
||||
@@ -468,6 +476,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.commit.pushAria': 'Commit and sync',
|
||||
'gitView.commit.pushing': 'sync 중…',
|
||||
'gitView.commit.selectFilesHint': '커밋하려면 변경 사항에서 파일을 선택하세요.',
|
||||
'gitView.commit.stageFilesHint': '커밋하려면 파일을 스테이징하세요.',
|
||||
'gitView.commit.title': '커밋',
|
||||
'gitView.common.cancel': '취소',
|
||||
'gitView.common.close': '닫기',
|
||||
@@ -776,15 +785,21 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.toast.revertedFilesSingle': '파일 {count}개 되돌림',
|
||||
'gitView.toast.revertedSomePlural': '파일 {success}개 되돌림, {failed}개 실패',
|
||||
'gitView.toast.revertedSomeSingle': '파일 {success}개 되돌림, {failed}개 실패',
|
||||
'gitView.toast.stageFileFailed': '변경사항 스테이징 실패',
|
||||
'gitView.toast.stageFileToCommit': '커밋하려면 파일을 하나 이상 스테이징하세요',
|
||||
'gitView.toast.stageFileToDescribe': '설명하려면 파일을 하나 이상 스테이징하세요',
|
||||
'gitView.toast.selectFileToCommit': '커밋할 파일을 하나 이상 선택하세요',
|
||||
'gitView.toast.selectFileToDescribe': '설명할 파일을 하나 이상 선택하세요',
|
||||
'gitView.toast.stashedRestored': 'stash한 변경 사항이 복원되었습니다',
|
||||
'gitView.toast.syncActionFailed': '{action} 실패',
|
||||
'gitView.toast.unstageFileFailed': '변경사항 스테이징 해제 실패',
|
||||
'gitView.toast.upstreamSet': '{branch}의 업스트림을 {remote}(으)로 설정했습니다',
|
||||
'gitView.worktree.availableInWorktreeMode': '워크트리 모드에서만 사용할 수 있습니다',
|
||||
'contextPanel.mode.chat': '채팅',
|
||||
'contextPanel.mode.files': '파일',
|
||||
'contextPanel.mode.diff': '변경사항',
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.plan': '계획',
|
||||
'contextPanel.mode.context': '컨텍스트',
|
||||
'contextPanel.mode.preview': '미리보기',
|
||||
|
||||
@@ -1073,6 +1073,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
'contextPanel.mode.chat': 'Chat',
|
||||
'contextPanel.mode.context': 'Context',
|
||||
'contextPanel.mode.diff': 'Różnice',
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.files': 'Pliki',
|
||||
'contextPanel.mode.plan': 'Plan',
|
||||
'contextPanel.mode.preview': 'Podgląd',
|
||||
@@ -1421,8 +1423,16 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.changes.reverting': 'Cofanie...',
|
||||
'gitView.changes.selectAllAria': 'Zaznacz wszystkie pliki',
|
||||
'gitView.changes.selectFileAria': 'Zaznacz plik',
|
||||
'gitView.changes.stagedTitle': 'W indeksie',
|
||||
'gitView.changes.resizeSplitAria': 'Zmień rozmiar zmian w indeksie i poza indeksem',
|
||||
'gitView.changes.stageAllAria': 'Dodaj wszystkie zmiany do indeksu',
|
||||
'gitView.changes.stageDirectoryAria': 'Dodaj do indeksu wszystkie zmiany w {path}',
|
||||
'gitView.changes.stageFileAria': 'Dodaj {path} do indeksu',
|
||||
'gitView.changes.title': 'Zmiany',
|
||||
'gitView.changes.toggleDirectorySelectionAria': 'Przełącz zaznaczenie katalogu',
|
||||
'gitView.changes.unstageAllAria': 'Usuń wszystkie zmiany z indeksu',
|
||||
'gitView.changes.unstageDirectoryAria': 'Usuń z indeksu wszystkie zmiany w {path}',
|
||||
'gitView.changes.unstageFileAria': 'Usuń {path} z indeksu',
|
||||
'gitView.commit.addGitmoji': 'Dodaj gitmoji',
|
||||
'gitView.commit.aiHighlights.insertAria': 'Wstaw',
|
||||
'gitView.commit.aiHighlights.insertTooltip': 'Wstaw',
|
||||
@@ -1437,6 +1447,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.commit.pushAria': 'Wypchnij',
|
||||
'gitView.commit.pushing': 'Wypychanie...',
|
||||
'gitView.commit.selectFilesHint': 'Zaznacz pliki w sekcji Zmiany, aby włączyć commit.',
|
||||
'gitView.commit.stageFilesHint': 'Dodaj pliki do indeksu, aby włączyć commit.',
|
||||
'gitView.commit.title': 'Commit',
|
||||
'gitView.common.cancel': 'Anuluj',
|
||||
'gitView.common.close': 'Zamknij',
|
||||
@@ -1700,10 +1711,14 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.toast.revertedFilesSingle': 'Cofnięto {count} plik',
|
||||
'gitView.toast.revertedSomePlural': 'Cofnięto {success} plików, {failed} nieudanych',
|
||||
'gitView.toast.revertedSomeSingle': 'Cofnięto {success} plik, {failed} nieudanych',
|
||||
'gitView.toast.stageFileFailed': 'Nie udało się dodać zmian do indeksu',
|
||||
'gitView.toast.stageFileToCommit': 'Dodaj do indeksu co najmniej jeden plik do commita',
|
||||
'gitView.toast.stageFileToDescribe': 'Dodaj do indeksu co najmniej jeden plik do opisu',
|
||||
'gitView.toast.selectFileToCommit': 'Zaznacz co najmniej jeden plik do commita',
|
||||
'gitView.toast.selectFileToDescribe': 'Zaznacz co najmniej jeden plik do opisu',
|
||||
'gitView.toast.stashedRestored': 'Przywrócono odłożone zmiany',
|
||||
'gitView.toast.syncActionFailed': 'Operacja {action} nie powiodła się',
|
||||
'gitView.toast.unstageFileFailed': 'Nie udało się usunąć zmian z indeksu',
|
||||
'gitView.toast.upstreamSet': 'Ustawiono upstream dla {branch} na {remote}',
|
||||
'gitView.worktree.availableInWorktreeMode': 'Dostępne tylko w trybie drzewa pracy',
|
||||
'header.actions.backAria': 'Wstecz',
|
||||
|
||||
@@ -452,8 +452,16 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.changes.reverting": "Revertiendo...",
|
||||
"gitView.changes.selectAllAria": "Selecionar todos os arquivos",
|
||||
"gitView.changes.selectFileAria": "Selecionar arquivo",
|
||||
"gitView.changes.stagedTitle": "Staged",
|
||||
"gitView.changes.resizeSplitAria": "Ajustar tamanho das alterações staged e unstaged",
|
||||
"gitView.changes.stageAllAria": "Adicionar todas as alterações ao stage",
|
||||
"gitView.changes.stageDirectoryAria": "Adicionar todas as alterações em {path} ao stage",
|
||||
"gitView.changes.stageFileAria": "Adicionar {path} ao stage",
|
||||
"gitView.changes.title": "Alterações",
|
||||
"gitView.changes.toggleDirectorySelectionAria": "Alternar selección de diretório",
|
||||
"gitView.changes.unstageAllAria": "Remover todas as alterações do stage",
|
||||
"gitView.changes.unstageDirectoryAria": "Remover todas as alterações em {path} do stage",
|
||||
"gitView.changes.unstageFileAria": "Remover {path} do stage",
|
||||
"gitView.commit.addGitmoji": "Adicionar gitmoji",
|
||||
"gitView.commit.aiHighlights.insertAria": "Insertar",
|
||||
"gitView.commit.aiHighlights.insertTooltip": "Insertar",
|
||||
@@ -468,6 +476,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.commit.pushAria": "Commit and sync",
|
||||
"gitView.commit.pushing": "Sincronizando...",
|
||||
"gitView.commit.selectFilesHint": "Selecione arquivos em Alterações para habilitar o commit.",
|
||||
"gitView.commit.stageFilesHint": "Adicione arquivos ao stage para habilitar o commit.",
|
||||
"gitView.commit.title": "Commit",
|
||||
"gitView.common.cancel": "Cancelar",
|
||||
"gitView.common.close": "Fechar",
|
||||
@@ -776,15 +785,21 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.toast.revertedFilesSingle": "{count} arquivo revertido",
|
||||
"gitView.toast.revertedSomePlural": "{success} arquivos revertidos, {failed} com falha",
|
||||
"gitView.toast.revertedSomeSingle": "{success} arquivo revertido, {failed} falhou",
|
||||
"gitView.toast.stageFileFailed": "Não foi possível adicionar as alterações ao stage",
|
||||
"gitView.toast.stageFileToCommit": "Adicione ao menos um arquivo ao stage para o commit",
|
||||
"gitView.toast.stageFileToDescribe": "Adicione ao menos um arquivo ao stage para descrever",
|
||||
"gitView.toast.selectFileToCommit": "Selecione ao menos um arquivo para o commit",
|
||||
"gitView.toast.selectFileToDescribe": "Selecione ao menos um arquivo para descrever",
|
||||
"gitView.toast.stashedRestored": "Alterações do stash restaurados",
|
||||
"gitView.toast.syncActionFailed": "{action} falhou",
|
||||
"gitView.toast.unstageFileFailed": "Não foi possível remover as alterações do stage",
|
||||
"gitView.toast.upstreamSet": "Upstream de {branch} configurado como {remote}",
|
||||
"gitView.worktree.availableInWorktreeMode": "Disponível apenas em modo worktree",
|
||||
"contextPanel.mode.chat": "Chat",
|
||||
"contextPanel.mode.files": "Arquivos",
|
||||
"contextPanel.mode.diff": "Diff",
|
||||
"contextPanel.mode.stagedDiff": "Staged Diff",
|
||||
"contextPanel.mode.workingDiff": "Working Diff",
|
||||
"contextPanel.mode.plan": "Plano",
|
||||
"contextPanel.mode.context": "Contexto",
|
||||
"contextPanel.mode.preview": "Prévia",
|
||||
|
||||
@@ -452,8 +452,16 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.changes.reverting": "Скасування...",
|
||||
"gitView.changes.selectAllAria": "Вибрати всі файли",
|
||||
"gitView.changes.selectFileAria": "Вибрати файл",
|
||||
"gitView.changes.stagedTitle": "Індексовані",
|
||||
"gitView.changes.resizeSplitAria": "Змінити розмір індексованих і неіндексованих змін",
|
||||
"gitView.changes.stageAllAria": "Додати всі зміни до індексу",
|
||||
"gitView.changes.stageDirectoryAria": "Додати до індексу всі зміни в {path}",
|
||||
"gitView.changes.stageFileAria": "Додати {path} до індексу",
|
||||
"gitView.changes.title": "Зміни",
|
||||
"gitView.changes.toggleDirectorySelectionAria": "Перемкнути вибір каталогу",
|
||||
"gitView.changes.unstageAllAria": "Прибрати всі зміни з індексу",
|
||||
"gitView.changes.unstageDirectoryAria": "Прибрати з індексу всі зміни в {path}",
|
||||
"gitView.changes.unstageFileAria": "Прибрати {path} з індексу",
|
||||
"gitView.commit.addGitmoji": "Додати gitmoji",
|
||||
"gitView.commit.aiHighlights.insertAria": "Вставити підказку",
|
||||
"gitView.commit.aiHighlights.insertTooltip": "Вставити підказку",
|
||||
@@ -468,6 +476,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.commit.pushAria": "Commit and sync",
|
||||
"gitView.commit.pushing": "Sync...",
|
||||
"gitView.commit.selectFilesHint": "Виберіть файли в розділі «Зміни», щоб увімкнути коміт.",
|
||||
"gitView.commit.stageFilesHint": "Додайте файли до індексу, щоб увімкнути коміт.",
|
||||
"gitView.commit.title": "Коміт",
|
||||
"gitView.common.cancel": "Скасувати",
|
||||
"gitView.common.close": "Закрити",
|
||||
@@ -776,15 +785,21 @@ export const dict: Record<I18nKey, string> = {
|
||||
"gitView.toast.revertedFilesSingle": "Скасовано зміни у файлі: {count}",
|
||||
"gitView.toast.revertedSomePlural": "Скасовано змін у файлах: {success}, не вдалося: {failed}",
|
||||
"gitView.toast.revertedSomeSingle": "Скасовано змін у файлах: {success}, не вдалося: {failed}",
|
||||
"gitView.toast.stageFileFailed": "Не вдалося додати зміни до індексу",
|
||||
"gitView.toast.stageFileToCommit": "Додайте до індексу принаймні один файл для коміту",
|
||||
"gitView.toast.stageFileToDescribe": "Додайте до індексу принаймні один файл для опису",
|
||||
"gitView.toast.selectFileToCommit": "Виберіть принаймні один файл для коміту",
|
||||
"gitView.toast.selectFileToDescribe": "Виберіть хоча б один файл для опису",
|
||||
"gitView.toast.stashedRestored": "Зміни зі stash відновлено",
|
||||
"gitView.toast.syncActionFailed": "{action} не вдалося",
|
||||
"gitView.toast.unstageFileFailed": "Не вдалося прибрати зміни з індексу",
|
||||
"gitView.toast.upstreamSet": "Upstream для {branch} встановлено на {remote}",
|
||||
"gitView.worktree.availableInWorktreeMode": "Доступно лише в режимі worktree",
|
||||
"contextPanel.mode.chat": "Чат",
|
||||
"contextPanel.mode.files": "Файли",
|
||||
"contextPanel.mode.diff": "Diff",
|
||||
"contextPanel.mode.stagedDiff": "Staged Diff",
|
||||
"contextPanel.mode.workingDiff": "Working Diff",
|
||||
"contextPanel.mode.plan": "План",
|
||||
"contextPanel.mode.context": "Контекст",
|
||||
"contextPanel.mode.preview": "Перегляд",
|
||||
|
||||
@@ -452,8 +452,16 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.changes.reverting': '正在还原...',
|
||||
'gitView.changes.selectAllAria': '全选文件',
|
||||
'gitView.changes.selectFileAria': '选择 {path}',
|
||||
'gitView.changes.stagedTitle': '已暂存',
|
||||
'gitView.changes.resizeSplitAria': '调整已暂存和未暂存更改区域大小',
|
||||
'gitView.changes.stageAllAria': '暂存所有更改',
|
||||
'gitView.changes.stageDirectoryAria': '暂存 {path} 中的所有更改',
|
||||
'gitView.changes.stageFileAria': '暂存 {path}',
|
||||
'gitView.changes.title': '更改',
|
||||
'gitView.changes.toggleDirectorySelectionAria': '切换目录 {path} 的选择',
|
||||
'gitView.changes.unstageAllAria': '取消暂存所有更改',
|
||||
'gitView.changes.unstageDirectoryAria': '取消暂存 {path} 中的所有更改',
|
||||
'gitView.changes.unstageFileAria': '取消暂存 {path}',
|
||||
'gitView.commit.addGitmoji': '添加 gitmoji',
|
||||
'gitView.commit.aiHighlights.insertAria': '将高亮插入提交信息',
|
||||
'gitView.commit.aiHighlights.insertTooltip': '将高亮追加到提交信息',
|
||||
@@ -468,6 +476,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.commit.pushAria': '提交并同步',
|
||||
'gitView.commit.pushing': '同步中...',
|
||||
'gitView.commit.selectFilesHint': '在“更改”中选择文件以启用提交。',
|
||||
'gitView.commit.stageFilesHint': '暂存文件以启用提交。',
|
||||
'gitView.commit.title': '提交',
|
||||
'gitView.common.cancel': '取消',
|
||||
'gitView.common.close': '关闭',
|
||||
@@ -776,15 +785,21 @@ export const dict: Record<I18nKey, string> = {
|
||||
'gitView.toast.revertedFilesSingle': '已回退 {count} 个文件',
|
||||
'gitView.toast.revertedSomePlural': '已回退 {success} 个文件,{failed} 个失败',
|
||||
'gitView.toast.revertedSomeSingle': '已回退 {success} 个文件,{failed} 个失败',
|
||||
'gitView.toast.stageFileFailed': '暂存更改失败',
|
||||
'gitView.toast.stageFileToCommit': '请至少暂存一个文件再提交',
|
||||
'gitView.toast.stageFileToDescribe': '请至少暂存一个文件再生成描述',
|
||||
'gitView.toast.selectFileToCommit': '请至少选择一个文件再提交',
|
||||
'gitView.toast.selectFileToDescribe': '请至少选择一个文件再生成描述',
|
||||
'gitView.toast.stashedRestored': '已恢复储藏的更改',
|
||||
'gitView.toast.syncActionFailed': '{action} 失败',
|
||||
'gitView.toast.unstageFileFailed': '取消暂存更改失败',
|
||||
'gitView.toast.upstreamSet': '已将 {branch} 的上游设置为 {remote}',
|
||||
'gitView.worktree.availableInWorktreeMode': '仅在工作树模式下可用',
|
||||
'contextPanel.mode.chat': '聊天',
|
||||
'contextPanel.mode.files': '文件',
|
||||
'contextPanel.mode.diff': '差异',
|
||||
'contextPanel.mode.stagedDiff': 'Staged Diff',
|
||||
'contextPanel.mode.workingDiff': 'Working Diff',
|
||||
'contextPanel.mode.plan': '计划',
|
||||
'contextPanel.mode.context': '上下文',
|
||||
'contextPanel.mode.preview': '预览',
|
||||
|
||||
Reference in New Issue
Block a user