diff --git a/ui/src/pages/CompanyImport.test.tsx b/ui/src/pages/CompanyImport.test.tsx index 835a712a922..f121ab77044 100644 --- a/ui/src/pages/CompanyImport.test.tsx +++ b/ui/src/pages/CompanyImport.test.tsx @@ -479,6 +479,26 @@ describe("CompanyImport", () => { expect(container.textContent).not.toContain("Import failed:"); + // File-selection edits feed the payload too and supersede a failure. + await clickButton((text) => text.startsWith("Import 3 file")); + await act(async () => { + rejectImport(new Error("third failure")); + }); + await flushReact(); + + expect(container.textContent).toContain("Import failed: third failure"); + + const fileCheckbox = Array.from( + container.querySelectorAll('input[type="checkbox"]'), + ).find((input) => !input.closest("label")?.textContent?.includes("Start imported agents")); + expect(fileCheckbox).toBeTruthy(); + await act(async () => { + fileCheckbox!.click(); + }); + await flushReact(); + + expect(container.textContent).not.toContain("Import failed:"); + // 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"); diff --git a/ui/src/pages/CompanyImport.tsx b/ui/src/pages/CompanyImport.tsx index 952da1d64a9..d0768fe78d9 100644 --- a/ui/src/pages/CompanyImport.tsx +++ b/ui/src/pages/CompanyImport.tsx @@ -941,11 +941,13 @@ export function CompanyImport() { // 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 and - // pause toggle are set against a rendered preview, so they reset only the - // panels; structural changes also discard the preview itself. Structural - // controls are locked while an import runs, so this can never unmount the - // preview section that hosts a running import's status panels. + // action buttons stay disabled) until it settles. Payload edits made + // against a rendered preview (new-company name, pause toggle, file + // selection, conflict choices, adapter overrides, dropping attachments) + // reset only the panels; structural changes also discard the preview + // itself. Structural controls are locked while an import runs, so this can + // never unmount the preview section that hosts a running import's status + // panels. function resetMutationState() { if (!previewMutation.isPending) previewMutation.reset(); if (!importMutation.isPending) importMutation.reset(); @@ -1022,6 +1024,7 @@ export function CompanyImport() { function handleToggleCheck(path: string, kind: "file" | "dir") { if (!importPreview) return; + resetMutationState(); setCheckedFiles((prev) => { const next = new Set(prev); if (kind === "file") { @@ -1054,6 +1057,7 @@ export function CompanyImport() { } function handleConflictRename(slug: string, newName: string) { + resetMutationState(); setNameOverrides((prev) => ({ ...prev, [slug]: newName })); // Editing the name un-confirms setConfirmedSlugs((prev) => { @@ -1065,6 +1069,7 @@ export function CompanyImport() { } function handleConflictToggleConfirm(slug: string) { + resetMutationState(); setConfirmedSlugs((prev) => { const next = new Set(prev); if (next.has(slug)) next.delete(slug); @@ -1074,6 +1079,7 @@ export function CompanyImport() { } function handleConflictToggleSkip(slug: string, filePath: string | null) { + resetMutationState(); setSkippedSlugs((prev) => { const next = new Set(prev); const wasSkipped = next.has(slug); @@ -1101,6 +1107,7 @@ export function CompanyImport() { } function handleAdapterChange(slug: string, adapterType: string) { + resetMutationState(); setAdapterOverrides((prev) => ({ ...prev, [slug]: adapterType })); // Reset config values when adapter type changes setAdapterConfigValues((prev) => { @@ -1120,6 +1127,7 @@ export function CompanyImport() { } function handleAdapterConfigChange(slug: string, patch: Partial) { + resetMutationState(); setAdapterConfigValues((prev) => ({ ...prev, [slug]: { ...(prev[slug] ?? { ...defaultCreateValues, adapterType: adapterOverrides[slug] ?? "claude_local" }), ...patch }, @@ -1207,6 +1215,7 @@ export function CompanyImport() { function handleContinueWithoutAttachments() { if (!localPackage) return; + resetMutationState(); setLocalPackage({ ...localPackage, files: stripBlobFiles(localPackage.files) }); setCheckedFiles((prev) => new Set([...prev].filter((filePath) => !isBlobStoreFilePath(filePath)))); }