diff --git a/apps/web/components/task/changes-panel-file-row.test.tsx b/apps/web/components/task/changes-panel-file-row.test.tsx
index 4001594461..2a08eb137f 100644
--- a/apps/web/components/task/changes-panel-file-row.test.tsx
+++ b/apps/web/components/task/changes-panel-file-row.test.tsx
@@ -155,6 +155,74 @@ describe("FileRow hover swap (stats <-> actions occupy same cell)", () => {
});
});
+describe("FileRow tree-mode hover stage action", () => {
+ it("keeps the stage button in the icon slot instead of the right hover actions", () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ const row = container.querySelector("[data-changes-file='src/file.go']") as HTMLElement | null;
+ expect(row).not.toBeNull();
+
+ const iconSlot = row!.querySelector("[data-testid='file-row-icon-action-slot']");
+ expect(iconSlot).not.toBeNull();
+ expect(iconSlot!.classList.contains("size-4")).toBe(true);
+ expect(iconSlot!.querySelector("button[title='Stage file']")).not.toBeNull();
+
+ const rightActions = row!.querySelector("[data-testid='file-row-hover-actions']");
+ expect(rightActions).not.toBeNull();
+ expect(rightActions!.querySelector("button[title='Stage file']")).toBeNull();
+ });
+
+ it("keeps the unstage button in the same icon slot for staged files", () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ const row = container.querySelector(
+ "[data-changes-file='src/staged.go']",
+ ) as HTMLElement | null;
+ expect(row).not.toBeNull();
+
+ const iconSlot = row!.querySelector("[data-testid='file-row-icon-action-slot']");
+ expect(iconSlot).not.toBeNull();
+ expect(iconSlot!.classList.contains("size-4")).toBe(true);
+ expect(iconSlot!.querySelector("button[title='Unstage file']")).not.toBeNull();
+
+ const rightActions = row!.querySelector("[data-testid='file-row-hover-actions']");
+ expect(rightActions).not.toBeNull();
+ expect(rightActions!.querySelector("button[title='Unstage file']")).toBeNull();
+ });
+});
+
describe("FileRow active-tab highlight", () => {
it("renders data-active='true' and bg-accent/60 when isActive", () => {
const { container } = render(
diff --git a/apps/web/components/task/changes-panel-file-row.tsx b/apps/web/components/task/changes-panel-file-row.tsx
index 7a3457519a..c8650b45a1 100644
--- a/apps/web/components/task/changes-panel-file-row.tsx
+++ b/apps/web/components/task/changes-panel-file-row.tsx
@@ -101,7 +101,15 @@ export function FileRow({
style={indentPx ? { paddingLeft: indentPx } : undefined}
>
{treeMode ? (
-
+
) : (
- ) : null
- }
/>
);
}
+function TreeModeFileActionSlot({
+ name,
+ isPending,
+ staged,
+ path,
+ repo,
+ onStage,
+ onUnstage,
+}: {
+ name: string;
+ isPending: boolean;
+ staged: boolean;
+ path: string;
+ repo?: string;
+ onStage: (path: string, repo?: string) => void;
+ onUnstage: (path: string, repo?: string) => void;
+}) {
+ return (
+
+ );
+}
+
function StageButton({
isPending,
staged,
@@ -209,17 +245,17 @@ function FileRowActions({
repo,
onDiscard,
onEditFile,
- stageButton,
}: {
path: string;
repo?: string;
onDiscard: (path: string, repo?: string) => void;
onEditFile: (path: string) => void;
- /** Tree mode: stage/unstage control rendered alongside the other hover actions. */
- stageButton?: React.ReactNode;
}) {
return (
-
+
- {stageButton}
);
}