From 57e802e2c9a7b5edcee91a640f722326f1c58749 Mon Sep 17 00:00:00 2001 From: Gabriel Gordon-Hall Date: Tue, 13 Jan 2026 09:32:16 +0000 Subject: [PATCH] per-repo diff stats (#1961) --- crates/services/src/services/diff_stream.rs | 5 +++++ crates/services/src/services/git.rs | 2 ++ crates/utils/src/diff.rs | 2 ++ .../ui-new/containers/WorkspacesLayout.tsx | 22 ++++++++++++++----- shared/types.ts | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/services/src/services/diff_stream.rs b/crates/services/src/services/diff_stream.rs index 1f2400f6..d47a56d0 100644 --- a/crates/services/src/services/diff_stream.rs +++ b/crates/services/src/services/diff_stream.rs @@ -277,6 +277,7 @@ impl DiffStreamManager { if let Some(new) = diff.new_path { diff.new_path = Some(prefix_path(new, self.args.path_prefix.as_deref())); } + diff.repo_id = Some(self.args.repo_id); let patch = ConversationPatch::add_diff(escape_json_pointer_segment(&prefixed_entry), diff); @@ -307,6 +308,7 @@ impl DiffStreamManager { let known_paths = self.known_paths.clone(); let stats_only = self.args.stats_only; let prefix = self.args.path_prefix.clone(); + let repo_id = self.args.repo_id; let messages = tokio::task::spawn_blocking(move || { process_file_changes( @@ -319,6 +321,7 @@ impl DiffStreamManager { &known_paths, stats_only, prefix.as_deref(), + repo_id, ) }) .await??; @@ -459,6 +462,7 @@ fn process_file_changes( known_paths: &Arc>>, stats_only: bool, path_prefix: Option<&str>, + repo_id: Uuid, ) -> Result, DiffStreamError> { let path_filter: Vec<&str> = changed_paths.iter().map(|s| s.as_str()).collect(); @@ -499,6 +503,7 @@ fn process_file_changes( if let Some(new) = diff.new_path { diff.new_path = Some(prefix_path(new, path_prefix)); } + diff.repo_id = Some(repo_id); let patch = ConversationPatch::add_diff(escape_json_pointer_segment(&prefixed_entry_index), diff); diff --git a/crates/services/src/services/git.rs b/crates/services/src/services/git.rs index 1b129126..e88a644d 100644 --- a/crates/services/src/services/git.rs +++ b/crates/services/src/services/git.rs @@ -535,6 +535,7 @@ impl GitService { content_omitted, additions, deletions, + repo_id: None, }); delta_index += 1; @@ -756,6 +757,7 @@ impl GitService { content_omitted, additions, deletions, + repo_id: None, } } diff --git a/crates/utils/src/diff.rs b/crates/utils/src/diff.rs index 66947007..98f11c1d 100644 --- a/crates/utils/src/diff.rs +++ b/crates/utils/src/diff.rs @@ -4,6 +4,7 @@ use git2::{DiffOptions, Patch}; use serde::{Deserialize, Serialize}; use similar::TextDiff; use ts_rs::TS; +use uuid::Uuid; // Structs compatable with props: https://github.com/MrWangJustToDo/git-diff-view @@ -28,6 +29,7 @@ pub struct Diff { /// Optional precomputed stats for omitted content pub additions: Option, pub deletions: Option, + pub repo_id: Option, } #[derive(Debug, Clone, Serialize, Deserialize, TS)] diff --git a/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx b/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx index b0bb3a6a..54ea0635 100644 --- a/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx +++ b/frontend/src/components/ui-new/containers/WorkspacesLayout.tsx @@ -342,7 +342,7 @@ export function WorkspacesLayout() { [renameBranch] ); - // Compute diff stats from real diffs + // Compute aggregate diff stats from real diffs (for WorkspacesMainContainer) const diffStats = useMemo( () => ({ filesChanged: realDiffs.length, @@ -380,21 +380,33 @@ export function WorkspacesLayout() { } } + // Compute per-repo diff stats + const repoDiffs = realDiffs.filter((d) => d.repoId === repo.id); + const filesChanged = repoDiffs.length; + const linesAdded = repoDiffs.reduce( + (sum, d) => sum + (d.additions ?? 0), + 0 + ); + const linesRemoved = repoDiffs.reduce( + (sum, d) => sum + (d.deletions ?? 0), + 0 + ); + return { id: repo.id, name: repo.display_name || repo.name, targetBranch: repo.target_branch || 'main', commitsAhead: repoStatus?.commits_ahead ?? 0, remoteCommitsAhead: repoStatus?.remote_commits_ahead ?? 0, - filesChanged: diffStats.filesChanged, - linesAdded: diffStats.linesAdded, - linesRemoved: diffStats.linesRemoved, + filesChanged, + linesAdded, + linesRemoved, prNumber, prUrl, prStatus, }; }), - [repos, diffStats, branchStatus] + [repos, realDiffs, branchStatus] ); // Content for logs panel (either process logs or tool content) diff --git a/shared/types.ts b/shared/types.ts index b254a9ef..4dbbf8c4 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -124,7 +124,7 @@ contentOmitted: boolean, /** * Optional precomputed stats for omitted content */ -additions: number | null, deletions: number | null, }; +additions: number | null, deletions: number | null, repoId: string | null, }; export type DiffChangeKind = "added" | "deleted" | "modified" | "renamed" | "copied" | "permissionChange";