fix(clone): a CodeCommit region borrows saved key IDs; Clone runs in the background

An IAM SSH key ID logs in to every region of its AWS account, but a login
was saved per host, so a repo in a region with no key ID of its own was
refused. Clone now tries the key IDs saved for the other CodeCommit regions
(each with its own key; the first ls-remote accepts, or the only one) and
keeps that user in the clone's origin.

Files → New → Clone repository steps aside for its progress chip as soon
as the clone starts; a failure asking for a login reopens the form.
This commit is contained in:
2026-11-02 10:00:09 +07:00
parent 8d0477e0f7
commit e4ecd116a2
6 changed files with 126 additions and 20 deletions
@@ -7,10 +7,11 @@
* folder's account with that account's own SSH key / HTTPS login — and opens
* a workspace on the new folder. A 409 `ECREDENTIALS` opens a login row (sent
* once, optionally remembered), `ESSHAUTH` points to Settings → Git.
* A running clone shows `CloneProgress` and never holds the page: closing the
* dialog only hides it behind a small progress chip (click to reopen), the
* A clone runs in the background from the moment it starts: the dialog steps
* aside for a small progress chip (`CloneProgress`; click to reopen), the
* request keeps going, and its outcome arrives as a toast — a failure is kept
* for the next open so a login row is still there to fill in.
* for the next open, and one asking for a login reopens the dialog with its
* login row.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
@@ -111,6 +112,9 @@ export function CloneHereDialog({
setTarget(into);
setError(null);
setSshRefused(false);
// Runs in the background by default: the dialog steps aside for the
// progress chip, and comes back only if the clone needs a login.
onClose();
try {
const result = await api.lanes.clone({
url: u,
@@ -156,6 +160,8 @@ export function CloneHereDialog({
if (!openRef.current) {
keepRef.current = true;
toast.error(message);
// A login to type: show the form again with its login row.
if (e.code === "ECREDENTIALS") onReopen();
}
}
};
@@ -632,14 +632,16 @@ describe("FileExplorer — New → Clone repository", () => {
const dialog = await openClone(user);
await user.type(within(dialog).getByLabelText("Repository URL"), "git@host:o/repo.git");
await user.click(within(dialog).getByTestId("fx-clone-submit"));
expect(await within(dialog).findByRole("progressbar")).toHaveAttribute("aria-valuenow", "45");
await user.click(within(dialog).getByRole("button", { name: "Run in background" }));
// In the background straight away: the chip carries the progress.
expect(screen.queryByTestId("fx-clone-dialog")).toBeNull();
const chip = await screen.findByTestId("fx-clone-chip");
expect(within(chip).getByText(/repo/)).toBeInTheDocument();
expect(await within(chip).findByRole("progressbar")).toHaveAttribute("aria-valuenow", "45");
await user.click(chip);
expect(screen.getByTestId("fx-clone-dialog")).toBeInTheDocument();
await user.keyboard("{Escape}");
const back = screen.getByTestId("fx-clone-dialog");
expect(await within(back).findByRole("progressbar")).toHaveAttribute("aria-valuenow", "45");
await user.click(within(back).getByRole("button", { name: "Run in background" }));
expect(screen.queryByTestId("fx-clone-dialog")).toBeNull();
finish({
lane: { id: 9, title: "repo", cwd: "/w/one/repo" },
created: true,
@@ -649,7 +651,7 @@ describe("FileExplorer — New → Clone repository", () => {
expect(screen.queryByTestId("fx-clone-chip")).toBeNull();
});
it("toasts a failure that lands while hidden and keeps it for the next open", async () => {
it("toasts a failure that lands while hidden, and reopens the form for a login", async () => {
let fail: (e: unknown) => void = () => {};
vi.mocked(api.lanes.clone).mockReturnValue(new Promise((_, r) => (fail = r)) as never);
vi.mocked(api.lanes.cloneProgress).mockRejectedValue(new Error("404"));
@@ -659,12 +661,12 @@ describe("FileExplorer — New → Clone repository", () => {
const dialog = await openClone(user);
await user.type(within(dialog).getByLabelText("Repository URL"), "https://git.example/o/r.git");
await user.click(within(dialog).getByTestId("fx-clone-submit"));
await user.keyboard("{Escape}");
fail(
Object.assign(new Error("login"), { code: "ECREDENTIALS", auth: { host: "git.example" } })
);
await waitFor(() => expect(toast.error).toHaveBeenCalled());
const again = await openClone(user);
// A login to type reopens the form by itself, its row ready.
const again = await screen.findByTestId("fx-clone-dialog");
expect(within(again).getByTestId("fx-clone-login")).toBeInTheDocument();
expect(within(again).getByLabelText("Repository URL")).toHaveValue(
"https://git.example/o/r.git"
@@ -687,10 +689,11 @@ describe("FileExplorer — New → Clone repository", () => {
const dialog = await openClone(user);
await user.type(within(dialog).getByLabelText("Repository URL"), "https://git.example/o/r.git");
await user.click(within(dialog).getByTestId("fx-clone-submit"));
const login = await within(dialog).findByTestId("fx-clone-login");
const reopened = await screen.findByTestId("fx-clone-dialog");
const login = await within(reopened).findByTestId("fx-clone-login");
await user.type(within(login).getByLabelText("Username"), "ann");
await user.type(within(login).getByLabelText("Password or access token"), "tok");
await user.click(within(dialog).getByTestId("fx-clone-submit"));
await user.click(within(reopened).getByTestId("fx-clone-submit"));
await waitFor(() =>
expect(api.lanes.clone).toHaveBeenLastCalledWith(
expect.objectContaining({