mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-27 14:15:26 +08:00
feat: git panel redesign (#535)
* feat(git-panel): add Branches tab, Fetch always visible, inline error banners - Add dedicated Branches tab (local/remote sections, switch with confirmation, delete branch, create branch) - Rename History tab to Commits; add change-count badge on Changes tab - Fetch button always visible when remote exists (not only when both ahead & behind) - Inline error banner below header for failed push/pull/fetch, with dismiss button - Server: /api/git/branches now returns localBranches + remoteBranches separately - Server: add /api/git/delete-branch endpoint (prevents deleting current branch) - Controller: expose operationError, clearOperationError, deleteBranch, localBranches, remoteBranches - Constants: add deleteBranch to all ConfirmActionType record maps Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: git log datetime * feat(git-panel): add staged/unstaged sections and enhanced commit details --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Haile <118998054+blackmammoth@users.noreply.github.com>
This commit is contained in:
@@ -24,3 +24,70 @@ export function getStatusLabel(status: FileStatusCode): string {
|
||||
export function getStatusBadgeClass(status: FileStatusCode): string {
|
||||
return FILE_STATUS_BADGE_CLASSES[status] || FILE_STATUS_BADGE_CLASSES.U;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Parse `git show` output to extract per-file change info
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type CommitFileChange = {
|
||||
path: string;
|
||||
directory: string;
|
||||
filename: string;
|
||||
status: FileStatusCode;
|
||||
insertions: number;
|
||||
deletions: number;
|
||||
};
|
||||
|
||||
export type CommitFileSummary = {
|
||||
files: CommitFileChange[];
|
||||
totalFiles: number;
|
||||
totalInsertions: number;
|
||||
totalDeletions: number;
|
||||
};
|
||||
|
||||
export function parseCommitFiles(showOutput: string): CommitFileSummary {
|
||||
const files: CommitFileChange[] = [];
|
||||
// Split on file diff boundaries
|
||||
const fileDiffs = showOutput.split(/^diff --git /m).slice(1);
|
||||
|
||||
for (const section of fileDiffs) {
|
||||
const lines = section.split('\n');
|
||||
// Extract path from "a/path b/path"
|
||||
const header = lines[0] ?? '';
|
||||
const match = header.match(/^a\/(.+?) b\/(.+)/);
|
||||
if (!match) continue;
|
||||
|
||||
const pathA = match[1];
|
||||
const pathB = match[2];
|
||||
|
||||
// Determine status
|
||||
let status: FileStatusCode = 'M';
|
||||
const joined = lines.slice(0, 6).join('\n');
|
||||
if (joined.includes('new file mode')) status = 'A';
|
||||
else if (joined.includes('deleted file mode')) status = 'D';
|
||||
|
||||
const filePath = status === 'D' ? pathA : pathB;
|
||||
|
||||
// Count insertions/deletions (lines starting with +/- but not +++/---)
|
||||
let insertions = 0;
|
||||
let deletions = 0;
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('+++') || line.startsWith('---')) continue;
|
||||
if (line.startsWith('+')) insertions++;
|
||||
else if (line.startsWith('-')) deletions++;
|
||||
}
|
||||
|
||||
const lastSlash = filePath.lastIndexOf('/');
|
||||
const directory = lastSlash >= 0 ? filePath.substring(0, lastSlash + 1) : '';
|
||||
const filename = lastSlash >= 0 ? filePath.substring(lastSlash + 1) : filePath;
|
||||
|
||||
files.push({ path: filePath, directory, filename, status, insertions, deletions });
|
||||
}
|
||||
|
||||
return {
|
||||
files,
|
||||
totalFiles: files.length,
|
||||
totalInsertions: files.reduce((sum, f) => sum + f.insertions, 0),
|
||||
totalDeletions: files.reduce((sum, f) => sum + f.deletions, 0),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user