diff --git a/ui/src/pages/CompanyImport.test.tsx b/ui/src/pages/CompanyImport.test.tsx index 08d01b5c10c..b1baabe5296 100644 --- a/ui/src/pages/CompanyImport.test.tsx +++ b/ui/src/pages/CompanyImport.test.tsx @@ -206,14 +206,14 @@ describe("CompanyImport", () => { await flushReact(); } - async function enterGithubUrl() { + async function enterGithubUrl(url = "https://github.com/acme/starter/tree/main/company") { const urlInput = container.querySelector( 'input[placeholder="https://github.com/owner/repo/tree/main/company"]', ); expect(urlInput).toBeTruthy(); await act(async () => { const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")!.set!; - setter.call(urlInput!, "https://github.com/acme/starter/tree/main/company"); + setter.call(urlInput!, url); urlInput!.dispatchEvent(new Event("input", { bubbles: true })); }); await flushReact(); @@ -355,6 +355,11 @@ describe("CompanyImport", () => { expect(container.textContent).toContain("Preview failed: stream disconnected"); expect(container.textContent).toContain("Retry, or use the CLI folder import"); expect(mockPushToast).toHaveBeenCalledWith(expect.objectContaining({ tone: "error" })); + + // Changing the package supersedes the failed request: the error panel resets. + await enterGithubUrl("https://github.com/acme/other-starter/tree/main/company"); + + expect(container.textContent).not.toContain("Preview failed:"); }); it("shows a progress panel while the import runs and a durable error panel when it fails", async () => { @@ -383,5 +388,13 @@ describe("CompanyImport", () => { expect(container.textContent).toContain("Import failed: connection reset"); expect(container.textContent).toContain("check the target company before retrying."); expect(mockPushToast).toHaveBeenCalledWith(expect.objectContaining({ tone: "error" })); + + // Changing the package supersedes the failed import: previewing a fresh + // package must not resurface the stale import error panel. + await enterGithubUrl("https://github.com/acme/other-starter/tree/main/company"); + await clickButton((text) => text === "Preview import"); + + expect(findButton((text) => text.startsWith("Import 3 file"))).toBeTruthy(); + expect(container.textContent).not.toContain("Import failed:"); }); }); diff --git a/ui/src/pages/CompanyImport.tsx b/ui/src/pages/CompanyImport.tsx index 352fa6d46b2..bb2f9d9c5d3 100644 --- a/ui/src/pages/CompanyImport.tsx +++ b/ui/src/pages/CompanyImport.tsx @@ -927,13 +927,22 @@ export function CompanyImport() { }, }); + // Any change to the package or import configuration supersedes the last + // preview and any settled mutation state, so the persistent progress/error + // panels never keep describing a request that no longer applies. + function resetImportFlowState() { + setImportPreview(null); + previewMutation.reset(); + importMutation.reset(); + } + async function handleChooseLocalPackage(e: ChangeEvent) { const fileList = e.target.files; if (!fileList || fileList.length === 0) return; try { const pkg = await readLocalPackageZip(fileList[0]!); setLocalPackage(pkg); - setImportPreview(null); + resetImportFlowState(); } catch (err) { pushToast({ tone: "error", @@ -1311,7 +1320,7 @@ export function CompanyImport() { )} onClick={() => { setSourceMode(key); - setImportPreview(null); + resetImportFlowState(); }} >
@@ -1379,7 +1388,7 @@ export function CompanyImport() { placeholder="https://github.com/owner/repo/tree/main/company" onChange={(e) => { setImportUrl(e.target.value); - setImportPreview(null); + resetImportFlowState(); }} /> @@ -1391,7 +1400,7 @@ export function CompanyImport() { value={targetMode} onChange={(e) => { setTargetMode(e.target.value as "existing" | "new"); - setImportPreview(null); + resetImportFlowState(); }} > @@ -1425,7 +1434,7 @@ export function CompanyImport() { value={collisionStrategy} onChange={(e) => { setCollisionStrategy(e.target.value as CompanyPortabilityCollisionStrategy); - setImportPreview(null); + resetImportFlowState(); }} >