From 8efa7f8ece032d1739dd4424b929df01a170cf86 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 4 Nov 2026 02:07:42 +0800 Subject: [PATCH] feat(vcs): Manage Remotes from the Remote node of the Git Log branches pane (#1081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manage Remotes… was only in the Git menu. The Remote node of the Git Log branches pane and each remote under it now offer it in their context menu. Refs #800 --- src/features/vcs/GitLog.tsx | 8 +++++- .../vcs/__tests__/logBranches.test.tsx | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/features/vcs/GitLog.tsx b/src/features/vcs/GitLog.tsx index 440a9b03..6d87bee3 100644 --- a/src/features/vcs/GitLog.tsx +++ b/src/features/vcs/GitLog.tsx @@ -18,6 +18,7 @@ import clsx from "clsx"; import { useVirtualizer } from "@tanstack/react-virtual"; import type { Branch, ChangedFile, Commit, RevisionChange } from "@/bindings"; import { call, commands } from "@/platform/ipc"; +import { executeAction } from "@/platform/actions"; import { maybeEditorService, type EditorInput } from "@/workbench/contributions"; import { EmptyState, @@ -464,7 +465,9 @@ export function BranchesPanel() { ? branchMenu(n.branch, n.repo ? (useVcs.getState().heads[n.repo]?.head ?? null) : current) : n?.kind === "tag" ? tagMenu(n.ref!) - : []; + : n?.kind === "remote" || (n?.kind === "group" && n.key.endsWith("g:remote")) + ? REMOTES_MENU + : []; const items = n?.repo ? inRepo(n.repo, menu) : menu; if (!items.length) return; e.preventDefault(); @@ -485,6 +488,9 @@ export function BranchesPanel() { ); } +/** IDEA: the Remote node and each remote of the Branches pane offer Manage Remotes…. */ +const REMOTES_MENU: MenuItem[] = [{ label: "Manage Remotes…", run: () => void executeAction("vcs.manageRemotes") }]; + // --- filters ---------------------------------------------------------------- const DAY = 86_400_000; diff --git a/src/features/vcs/__tests__/logBranches.test.tsx b/src/features/vcs/__tests__/logBranches.test.tsx index 95ea1ac0..1136d809 100644 --- a/src/features/vcs/__tests__/logBranches.test.tsx +++ b/src/features/vcs/__tests__/logBranches.test.tsx @@ -15,6 +15,13 @@ vi.mock("@/platform/ipc", async (importOriginal) => { }; }); +const execute = vi.hoisted(() => vi.fn()); +vi.mock("@/platform/actions", async (importOriginal) => ({ + ...(await importOriginal()), + executeAction: execute, +})); + +import { ContextMenuHost } from "@/ui"; import { BranchesPanel } from "../GitLog"; import { emptyFilters, useGitLog } from "../logStore"; import { useVcs } from "../store"; @@ -54,6 +61,26 @@ beforeEach(() => { }); describe("Git Log branches pane", () => { + it("offers Manage Remotes… on the Remote node and on each remote, like IDEA", async () => { + useVcs.setState({ branches: [...branches, b("origin/main", { remote: true, commit: "1" })] }); + render( + <> + + + , + ); + fireEvent.contextMenu(screen.getByText("Remote")); + fireEvent.click(await screen.findByRole("menuitem", { name: "Manage Remotes…" })); + await waitFor(() => expect(execute).toHaveBeenCalledWith("vcs.manageRemotes")); + execute.mockClear(); + // Expand Remote, then the remote itself. + fireEvent.mouseDown(screen.getByText("Remote")); + fireEvent.keyDown(screen.getByRole("tree", { name: "Branches" }), { key: "ArrowRight" }); + fireEvent.contextMenu(await screen.findByText("origin")); + fireEvent.click(await screen.findByRole("menuitem", { name: "Manage Remotes…" })); + await waitFor(() => expect(execute).toHaveBeenCalledWith("vcs.manageRemotes")); + }); + it("one click only selects the branch", () => { render(); fireEvent.mouseDown(screen.getByText("feature"));