Skip to content

Commit e8907dc

Browse files
authored
Show file change types inline in summary (#55)
1 parent 482cea0 commit e8907dc

83 files changed

Lines changed: 227 additions & 91 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎DESIGN.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,9 @@ Do not add motion for decoration. New animation must honor
416416
File/folder rows, filter, summary toggle, and review progress retain desktop
417417
control heights and spacing; do not apply the general mobile enlargement here.
418418
- Hide redundant summary/shortcut detail before removing essential actions.
419+
Keep the Files changed total and inline added/deleted/modified/renamed counts
420+
visible in the drawer. Use file icons, semantic status colors, hover labels,
421+
and accessible names; wrap the group when the sidebar is too narrow.
419422
- At mobile widths or coarse pointers, app-owned controls target 44px hit heights;
420423
icon controls also reach 44px width. Text-input sizing uses `--text-input-touch`.
421424
The compact View options and collapse/expand icons match the theme control's

‎apps/web/src/ReviewTools.tsx‎

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { ChevronDownIcon, CopyIcon } from "lucide-react";
1+
import {
2+
ChevronDownIcon,
3+
CopyIcon,
4+
FileMinus2Icon,
5+
FilePenLineIcon,
6+
FilePlus2Icon,
7+
FileSymlinkIcon,
8+
} from "lucide-react";
29
import { useEffect, useState } from "react";
310
import { Button } from "@/components/ui/button";
411
import {
@@ -145,6 +152,34 @@ export function ChangeSummary() {
145152
save("summary-collapsed", String(summaryCollapsed));
146153
}, [summaryCollapsed]);
147154
const allFiles = repository?.files ?? [];
155+
const fileChanges = [
156+
{
157+
kind: "added",
158+
Icon: FilePlus2Icon,
159+
count: allFiles.filter((file) => ["A", "?", "C"].includes(file.status))
160+
.length,
161+
description: "Files added (including untracked and copied files)",
162+
},
163+
{
164+
kind: "deleted",
165+
Icon: FileMinus2Icon,
166+
count: allFiles.filter((file) => file.status === "D").length,
167+
description: "Files deleted",
168+
},
169+
{
170+
kind: "modified",
171+
Icon: FilePenLineIcon,
172+
count: allFiles.filter((file) => ["M", "T", "U"].includes(file.status))
173+
.length,
174+
description: "Files modified (including type changes and conflicts)",
175+
},
176+
{
177+
kind: "renamed",
178+
Icon: FileSymlinkIcon,
179+
count: allFiles.filter((file) => file.status === "R").length,
180+
description: "Files renamed",
181+
},
182+
];
148183
const additions = allFiles.reduce((sum, file) => sum + file.additions, 0);
149184
const deletions = allFiles.reduce((sum, file) => sum + file.deletions, 0);
150185
const reviewedCount = allFiles.filter(isReviewed).length;
@@ -166,9 +201,30 @@ export function ChangeSummary() {
166201
</Button>
167202
<div id="summary-content" hidden={summaryCollapsed}>
168203
<div className="sidebar-bottom">
169-
<div className="summary-row">
204+
<div className="summary-row summary-files-row">
170205
<span>Files changed</span>
171-
<strong id="summary-files">{allFiles.length}</strong>
206+
<div className="summary-file-counts">
207+
<strong id="summary-files">{allFiles.length}</strong>
208+
<div
209+
className="summary-file-breakdown"
210+
role="group"
211+
aria-label="File changes by type"
212+
>
213+
{fileChanges.map(({ kind, Icon, count, description }) => (
214+
<span
215+
key={kind}
216+
className="summary-file-kind"
217+
data-kind={kind}
218+
role="img"
219+
aria-label={`${count} ${count === 1 ? "file" : "files"} ${kind}`}
220+
title={`${description}: ${count}`}
221+
>
222+
<Icon aria-hidden="true" />
223+
<span aria-hidden="true">{count.toLocaleString()}</span>
224+
</span>
225+
))}
226+
</div>
227+
</div>
172228
</div>
173229
<div className="summary-row">
174230
<span>Additions</span>

‎apps/web/src/review.css‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@
745745

746746
@media (max-width: 767px) {
747747
.sidebar-bottom .summary-label,
748-
.sidebar-bottom .summary-row,
748+
.sidebar-bottom .summary-row:not(.summary-files-row),
749749
.sidebar-bottom .change-bar {
750750
display: none;
751751
}

‎apps/web/src/style.css‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,47 @@ kbd {
329329
.summary-row strong {
330330
font: var(--text-sm) var(--font-mono);
331331
}
332+
.summary-files-row {
333+
align-items: center;
334+
flex-wrap: wrap;
335+
gap: var(--space-1) var(--space-2);
336+
}
337+
.summary-file-counts,
338+
.summary-file-breakdown,
339+
.summary-file-kind {
340+
display: flex;
341+
align-items: center;
342+
}
343+
.summary-file-counts {
344+
margin-left: auto;
345+
gap: var(--space-2);
346+
}
347+
.summary-file-breakdown {
348+
flex-wrap: wrap;
349+
gap: var(--space-2);
350+
border-left: 1px solid var(--border-muted);
351+
padding-left: var(--space-2);
352+
}
353+
.summary-file-kind {
354+
gap: var(--space-1);
355+
font: var(--text-xs) var(--font-mono);
356+
}
357+
.summary-file-kind svg {
358+
width: var(--icon-sm);
359+
height: var(--icon-sm);
360+
}
361+
.summary-file-kind[data-kind="added"] {
362+
color: var(--success);
363+
}
364+
.summary-file-kind[data-kind="deleted"] {
365+
color: var(--error);
366+
}
367+
.summary-file-kind[data-kind="modified"] {
368+
color: var(--warning);
369+
}
370+
.summary-file-kind[data-kind="renamed"] {
371+
color: var(--accent);
372+
}
332373
.change-bar {
333374
height: var(--space-1);
334375
background: var(--error);

‎apps/web/test/browser/app.spec.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,42 @@ async function resolvedRadius(
1717

1818
test.beforeEach(async ({ request }) => resetFixtureState(request));
1919

20+
test("file summary counts change types across filtering and mobile", async ({
21+
page,
22+
}) => {
23+
await page.goto("/");
24+
const summary = page.getByRole("region", { name: "Summary", exact: true });
25+
await expect(summary.locator("#summary-files")).toHaveText("12");
26+
for (const label of [
27+
"4 files added",
28+
"2 files deleted",
29+
"5 files modified",
30+
"1 file renamed",
31+
]) {
32+
await expect(summary.getByRole("img", { name: label })).toBeVisible();
33+
}
34+
await page.getByRole("searchbox", { name: "Filter files" }).fill("value.ts");
35+
await expect(page.locator("#file-tree [data-path]")).toHaveCount(1);
36+
await expect(summary.locator("#summary-files")).toHaveText("12");
37+
await expect(
38+
summary.getByRole("img", { name: "1 file renamed" }),
39+
).toBeVisible();
40+
41+
await page.setViewportSize({ width: 390, height: 844 });
42+
await page.getByRole("button", { name: "Show file sidebar" }).click();
43+
await expect(summary.locator("#summary-files")).toBeVisible();
44+
await expect(
45+
summary.getByRole("img", { name: "4 files added" }),
46+
).toBeVisible();
47+
await expect(
48+
summary.getByRole("img", { name: "1 file renamed" }),
49+
).toBeVisible();
50+
const row = summary.locator(".summary-files-row");
51+
expect(
52+
await row.evaluate((element) => element.scrollWidth <= element.clientWidth),
53+
).toBe(true);
54+
});
55+
2056
test("disabled comments issue no requests and expose no comment UI", async ({
2157
page,
2258
}) => {

internal/webui/dist/assets/angular-html-zSUgWMpk.js renamed to internal/webui/dist/assets/angular-html-CXf32AcN.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/webui/dist/assets/angular-ts-svdTVWoR.js renamed to internal/webui/dist/assets/angular-ts-DJW2Kg-P.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/webui/dist/assets/apl-BoUWP9tl.js renamed to internal/webui/dist/assets/apl-q_-s_TGZ.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/webui/dist/assets/astro-DQRzsDmW.js renamed to internal/webui/dist/assets/astro-CJVz5Clq.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/webui/dist/assets/blade-BTXKADPL.js renamed to internal/webui/dist/assets/blade-CaTnJ6RM.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)