From f4b0f8fa22fd3e6d45ddf847d3ecfdc3454d55b6 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:45:16 +0200 Subject: [PATCH] fix(ui): prevent rescheduling scans during credential update (#10851) --- ui/CHANGELOG.md | 4 ++++ .../use-provider-wizard-controller.test.tsx | 9 ++++---- .../hooks/use-provider-wizard-controller.ts | 7 ++++++ .../wizard/provider-wizard-modal.tsx | 22 ++++++++++++++++--- .../providers/wizard/wizard-stepper.tsx | 20 ++++++++++------- 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index bedc6d819e..dad0b20922 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -8,6 +8,10 @@ All notable changes to the **Prowler UI** are documented in this file. - Allows tenant owners to expel users from their organizations [(#10787)](https://github.com/prowler-cloud/prowler/pull/10787) +### 🐞 Fixed + +- Provider wizard no longer advances to the Launch Scan step when rotating credentials: the modal closes after a successful connection test, preventing inadvertent scan rescheduling during credential updates [(#10851)](https://github.com/prowler-cloud/prowler/pull/10851) + ### ❌ Removed - Redesign compliance page with a horizontal ThreatScore card (always-visible pillar breakdown + ActionDropdown), client-side search for compliance frameworks, compact scan selector trigger, responsive mobile filters, download-started toasts for CSV/PDF exports, enhanced compliance cards with truncated titles, and Alert-based empty/error states; migrate Progress component from HeroUI to shadcn [(#10767)](https://github.com/prowler-cloud/prowler/pull/10767) diff --git a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx index 187c1e0251..9688c3d684 100644 --- a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx +++ b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx @@ -153,7 +153,7 @@ describe("useProviderWizardController", () => { expect(onOpenChange).not.toHaveBeenCalled(); }); - it("moves to launch step after a successful connection test in update mode", async () => { + it("closes the wizard after a successful connection test in update mode", async () => { // Given const onOpenChange = vi.fn(); const { result } = renderHook(() => @@ -181,9 +181,10 @@ describe("useProviderWizardController", () => { result.current.handleTestSuccess(); }); - // Then - expect(result.current.currentStep).toBe(PROVIDER_WIZARD_STEP.LAUNCH); - expect(onOpenChange).not.toHaveBeenCalled(); + // Then: credential rotation never surfaces the launch/schedule step + expect(onOpenChange).toHaveBeenCalledWith(false); + expect(refreshMock).toHaveBeenCalledTimes(1); + expect(result.current.currentStep).not.toBe(PROVIDER_WIZARD_STEP.LAUNCH); }); it("does not override launch footer config in the controller", () => { diff --git a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts index 21fce019aa..40644450c2 100644 --- a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts +++ b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts @@ -197,6 +197,12 @@ export function useProviderWizardController({ }; const handleTestSuccess = () => { + if ( + useProviderWizardStore.getState().mode === PROVIDER_WIZARD_MODE.UPDATE + ) { + handleClose(); + return; + } setCurrentStep(PROVIDER_WIZARD_STEP.LAUNCH); }; @@ -234,6 +240,7 @@ export function useProviderWizardController({ handleTestSuccess, isOrgDirectEntry, isProviderFlow, + mode, modalTitle, openOrganizationsFlow, orgCurrentStep, diff --git a/ui/components/providers/wizard/provider-wizard-modal.tsx b/ui/components/providers/wizard/provider-wizard-modal.tsx index 9157ca74ce..706045a829 100644 --- a/ui/components/providers/wizard/provider-wizard-modal.tsx +++ b/ui/components/providers/wizard/provider-wizard-modal.tsx @@ -10,7 +10,10 @@ import { DialogHeader, DialogTitle } from "@/components/shadcn/dialog"; import { Modal } from "@/components/shadcn/modal"; import { useScrollHint } from "@/hooks/use-scroll-hint"; import { ORG_SETUP_PHASE, ORG_WIZARD_STEP } from "@/types/organizations"; -import { PROVIDER_WIZARD_STEP } from "@/types/provider-wizard"; +import { + PROVIDER_WIZARD_MODE, + PROVIDER_WIZARD_STEP, +} from "@/types/provider-wizard"; import { useProviderWizardController } from "./hooks/use-provider-wizard-controller"; import { @@ -23,7 +26,12 @@ import { WIZARD_FOOTER_ACTION_TYPE } from "./steps/footer-controls"; import { LaunchStep } from "./steps/launch-step"; import { TestConnectionStep } from "./steps/test-connection-step"; import type { OrgWizardInitialData, ProviderWizardInitialData } from "./types"; -import { WizardStepper } from "./wizard-stepper"; +import { PROVIDER_WIZARD_STEPS, WizardStepper } from "./wizard-stepper"; + +const UPDATE_MODE_WIZARD_STEPS = PROVIDER_WIZARD_STEPS.slice( + 0, + PROVIDER_WIZARD_STEP.LAUNCH, +); interface ProviderWizardModalProps { open: boolean; @@ -47,6 +55,7 @@ export function ProviderWizardModal({ handleTestSuccess, isOrgDirectEntry, isProviderFlow, + mode, modalTitle, openOrganizationsFlow, orgCurrentStep, @@ -97,7 +106,14 @@ export function ProviderWizardModal({
{isProviderFlow ? ( - + ) : ( - {STEPS.map((step, index) => { + {steps.map((step, index) => { const isComplete = index < activeVisualStep; const isActive = index === activeVisualStep; const isInactive = index > activeVisualStep; @@ -67,7 +71,7 @@ export function WizardStepper({ isActive={isActive} icon={step.icon} /> - {index < STEPS.length - 1 && ( + {index < steps.length - 1 && ( )}