diff --git a/ui/src/pages/CompanyImport.test.tsx b/ui/src/pages/CompanyImport.test.tsx index 7843b14fe15..9e282bbdf55 100644 --- a/ui/src/pages/CompanyImport.test.tsx +++ b/ui/src/pages/CompanyImport.test.tsx @@ -346,6 +346,12 @@ describe("CompanyImport", () => { expect(container.textContent).toContain("Uploading and analyzing your package"); expect(container.textContent).toContain("Keep this page open."); + // Config edits while the request is in flight must not detach it from + // the UI: the progress panel keeps reporting it until it settles. + await enterGithubUrl("https://github.com/acme/starter-b/tree/main/company"); + + expect(container.textContent).toContain("Uploading and analyzing your package"); + await act(async () => { rejectPreview(new Error("stream disconnected")); }); @@ -379,6 +385,21 @@ describe("CompanyImport", () => { expect(container.textContent).toContain("Uploading and importing"); expect(container.textContent).toContain("Keep this page open."); + // Config edits while the import is in flight must not detach it from + // the UI: the progress panel keeps reporting it until it settles. + const midFlightNameInput = container.querySelector( + 'input[placeholder="Imported Company"]', + ); + expect(midFlightNameInput).toBeTruthy(); + await act(async () => { + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")!.set!; + setter.call(midFlightNameInput!, "Mid Flight"); + midFlightNameInput!.dispatchEvent(new Event("input", { bubbles: true })); + }); + await flushReact(); + + expect(container.textContent).toContain("Uploading and importing"); + await act(async () => { rejectImport(new Error("connection reset")); }); diff --git a/ui/src/pages/CompanyImport.tsx b/ui/src/pages/CompanyImport.tsx index 133c05c3ab5..9556b472ea3 100644 --- a/ui/src/pages/CompanyImport.tsx +++ b/ui/src/pages/CompanyImport.tsx @@ -927,13 +927,15 @@ export function CompanyImport() { }, }); - // Any change to the import configuration supersedes the request the last - // progress/error panel describes, so it resets both mutations. The - // new-company name is typed against a rendered preview, so it resets only - // the panels; structural changes also discard the preview itself. + // Any change to the import configuration supersedes the request a settled + // progress/error panel describes, so it clears settled mutation state. A + // pending request is never detached: its panel keeps reporting it (and the + // action buttons stay disabled) until it settles. The new-company name is + // typed against a rendered preview, so it resets only the panels; + // structural changes also discard the preview itself. function resetMutationState() { - previewMutation.reset(); - importMutation.reset(); + if (!previewMutation.isPending) previewMutation.reset(); + if (!importMutation.isPending) importMutation.reset(); } function resetImportFlowState() {