fix(vcs): keep the current branch name in New Branch even though it exists (#1305)
CI / Rust (ubuntu-22.04) (push) Failing after 1h0m11s
CI / Remote server (linux musl) (push) Failing after 33m23s
CI / Plugins (SDK, official, fixtures) (push) Successful in 3m22s
CI / Cargo deny (push) Successful in 43s
CI / Frontend (push) Successful in 28m17s
CI / E2E (push) Failing after 23m35s
CI / Rust (macos-latest) (push) Canceled after 0s
CI / Rust (windows-latest) (push) Canceled after 0s

New Branch dropped its suggestion when validateBranchName rejected it, and the current branch always exists, so a plain New Branch from HEAD always opened empty; the test never seeded the local branches. The suggestion is kept, the dialog shows that the branch exists from the start and Create stays disabled until the name changes; other prefilled prompts (Rename Branch) keep showing errors only after editing.
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-11-04 23:12:40 +08:00
1 джерело b31edc3482
коміт 092a700ddc
3 files changed
+26 -4

No files matched your search

+19 -2
Переглянути файл
@@ -1,5 +1,5 @@
import { beforeEach, expect, it, vi } from "vitest";
import type { BranchInfo } from "@/bindings";
import type { Branch, BranchInfo } from "@/bindings";
const mocks = vi.hoisted(() => ({ prompt: vi.fn() }));
vi.mock("../dialogs", async (original) => ({
...(await original<typeof import("../dialogs")>()),
@@ -17,9 +17,25 @@ const branch = (head: string | null): BranchInfo => ({
operation: null,
});
const local = (name: string, current = false): Branch => ({
name,
remote: false,
current,
upstream: null,
ahead: 0,
behind: 0,
lastCommitMs: null,
});
beforeEach(() => {
vi.clearAllMocks();
useVcs.setState({ root: "/p", repo: "/p/front", branch: branch("feature/ui") });
// The current branch is always among the local branches, so the suggestion names an existing one.
useVcs.setState({
root: "/p",
repo: "/p/front",
branch: branch("feature/ui"),
branches: [local("feature/ui", true), local("main")],
});
// Cancel: only what the dialog was offered matters here, not its outcome.
mocks.prompt.mockResolvedValue(null);
});
@@ -27,6 +43,7 @@ beforeEach(() => {
it("prefills a plain New Branch with the current branch name", async () => {
await newBranch();
expect(mocks.prompt.mock.calls[0]?.[0].initial).toBe("feature/ui");
expect(mocks.prompt.mock.calls[0]?.[0].validateInitial).toBe(true);
});
it("prefills nothing when HEAD is detached", async () => {
+4 -1
Переглянути файл
@@ -156,10 +156,12 @@ export async function newBranch(from?: string) {
const r = await promptText({
title: from ? tx`Create New Branch from ${from}` : "Create New Branch",
label: "New branch name:",
initial: suggestion && !validateBranchName(suggestion) ? suggestion : "",
// Kept even when that branch exists (the current one always does): the user edits it.
initial: suggestion,
mono: true,
okLabel: "Create",
validate: validateBranchName,
validateInitial: true,
checkbox: { label: "Checkout branch", initial: true },
});
if (!r) return;
@@ -371,6 +373,7 @@ export async function newBranchInRepos(roots: readonly string[], from?: string)
mono: true,
okLabel: "Create",
validate: validateBranchName,
validateInitial: true,
checkbox: { label: "Checkout branch", initial: true },
});
if (!r) return;
+3 -1
Переглянути файл
@@ -43,6 +43,8 @@ export interface PromptOptions {
mono?: boolean;
/** Returns an error message, or null when valid. */
validate?: (value: string) => string | null;
/** Show the prefilled value's problem (e.g. the branch exists) before it is edited. */
validateInitial?: boolean;
/** Optional checkbox below the field. */
checkbox?: { label: string; initial: boolean };
}
@@ -70,7 +72,7 @@ function PromptDialog(props: PromptOptions & { onDone: (r: PromptResult | null)
const { title, label, initial = "", placeholder, okLabel = "OK", mono, validate, checkbox, onDone } = props;
const [value, setValue] = useState(initial);
const [checked, setChecked] = useState(checkbox?.initial ?? false);
const [touched, setTouched] = useState(false);
const [touched, setTouched] = useState(!!props.validateInitial && initial !== "");
const error = validate ? validate(value) : value.trim() ? null : "Value must not be empty";
const submit = () => {
setTouched(true);