diff --git a/.lane/memory/apps/app/src/channel.tsx/01M4YQY84K8XSFAWY9R9YCMF5C-sidebar-totals-stay-per-grou.md b/.lane/memory/apps/app/src/channel.tsx/01M4YQY84K8XSFAWY9R9YCMF5C-sidebar-totals-stay-per-grou.md index 18848dfd..ed2ec57c 100644 --- a/.lane/memory/apps/app/src/channel.tsx/01M4YQY84K8XSFAWY9R9YCMF5C-sidebar-totals-stay-per-grou.md +++ b/.lane/memory/apps/app/src/channel.tsx/01M4YQY84K8XSFAWY9R9YCMF5C-sidebar-totals-stay-per-grou.md @@ -4,9 +4,9 @@ anchor: function ChannelDetails created: 2026-10-15T02:58:24Z norm: '1' sig: b49433e7f0d6d4f3 -body_hash: 0ad294e254dbf4a9 -raw_hash: 12a00ec745e4b2fa -vouched: 2026-10-16T22:31:01Z +body_hash: c78ae37103f4096d +raw_hash: 7d353ff7240b0bf1 +vouched: 2026-10-22T16:29:20Z lines: 161-209 --- diff --git a/apps/app/src/channel.tsx b/apps/app/src/channel.tsx index a4a0766a..c8e27b18 100644 --- a/apps/app/src/channel.tsx +++ b/apps/app/src/channel.tsx @@ -9,7 +9,7 @@ import { useSyncExternalStore, } from "react"; -import type { Changes, GithubPull } from "@ace/channel/protocol"; +import type { Change, Changes, GithubPull } from "@ace/channel/protocol"; import type { ChannelInfo, Listing } from "@ace/host/protocol"; import { Badge, @@ -233,20 +233,27 @@ export function ChannelDetails({ channel, user }: { channel: Listing; user: stri // Totaled per group as the Diff does, so uncommitted and untracked files never inflate the // committed work a pull request would show. const groups = new Map(); - const add = (group: string | undefined, adds: number, dels: number, files: number) => { + const add = (group: string | undefined, files: number, file?: Change) => { let sum = groups.get(group); if (!sum) { - groups.set(group, sum = { ...(group ? { group } : {}), adds: 0, dels: 0, files: 0 }); + groups.set( + group, + sum = { ...(group ? { group } : {}), adds: 0, dels: 0, files: 0, lines: false }, + ); } - sum.adds += adds; - sum.dels += dels; sum.files += files; + // Large untracked directories are only counted, so their group's line totals are unknown. + if (!file) sum.lines = false; + else if (!file.binary) { + sum.adds += file.adds; + sum.dels += file.dels; + sum.lines = true; + } }; - for (const file of changes.files) { - add(file.state && GROUPS[file.state], file.adds, file.dels, 1); - } - for (const { files } of changes.dirs || []) add(GROUPS.untracked, 0, 0, files); - return groups.size ? [...groups.values()] : [{ adds: 0, dels: 0, files: 0 }]; + for (const file of changes.files) add(file.state && GROUPS[file.state], 1, file); + // After every file, so no file's lines mark a directory's group known again. + for (const { files } of changes.dirs || []) add(GROUPS.untracked, files); + return groups.size ? [...groups.values()] : [{ adds: 0, dels: 0, files: 0, lines: true }]; }, [changes]); const mentioned = useMemo(() => items && links(items, channel.repo), [items, channel.repo]); const agents = useMemo(() => items && subagents(items, busy), [items, busy]); diff --git a/packages/ui/src/components/session-details/session-details.tsx b/packages/ui/src/components/session-details/session-details.tsx index 6b961588..b110ee5a 100644 --- a/packages/ui/src/components/session-details/session-details.tsx +++ b/packages/ui/src/components/session-details/session-details.tsx @@ -43,7 +43,14 @@ export type DetailsLink = { url: string; label: string; kind: "issue" | "pull" | export type DetailsFact = { label: string; value: string; title?: string }; type Icon = ComponentType<{ className?: string }>; /** One group's totals, such as committed or untracked files; ungrouped totals omit `group`. */ -export type DetailsChanges = { group?: string; adds: number; dels: number; files: number }; +export type DetailsChanges = { + group?: string; + adds: number; + dels: number; + files: number; + /** Whether `adds` and `dels` are known; untracked directories and binary files have none. */ + lines: boolean; +}; export type SessionDetailsViewProps = { summary?: string; @@ -129,15 +136,19 @@ function Changes({ changes, onDiff }: { changes: DetailsChanges; onDiff?: () => const files = `${changes.files.toLocaleString()} ${changes.files === 1 ? "file" : "files"}`; const adds = `${changes.adds} ${changes.adds === 1 ? "addition" : "additions"}`; const dels = `${changes.dels} ${changes.dels === 1 ? "deletion" : "deletions"}`; - const label = `${name}: ${files}, ${adds}, ${dels}`; + const label = changes.lines ? `${name}: ${files}, ${adds}, ${dels}` : `${name}: ${files}`; const content = ( <> {name} {changes.group && {files}} - +{changes.adds.toLocaleString()} - -{changes.dels.toLocaleString()} + {changes.lines && ( + <> + +{changes.adds.toLocaleString()} + -{changes.dels.toLocaleString()} + + )} );