diff --git a/products/catalyst/bootstrap/ui/src/pages/wizard/WizardPage.tsx b/products/catalyst/bootstrap/ui/src/pages/wizard/WizardPage.tsx index b4febeaa..86871793 100644 --- a/products/catalyst/bootstrap/ui/src/pages/wizard/WizardPage.tsx +++ b/products/catalyst/bootstrap/ui/src/pages/wizard/WizardPage.tsx @@ -4,6 +4,7 @@ import { Link, useNavigate } from '@tanstack/react-router' import { useWizardStore } from '@/entities/deployment/store' import { useSession } from '@/shared/lib/useSession' import { useInflightDeployment } from '@/shared/lib/useInflightDeployment' +import { DETECTED_MODE } from '@/shared/lib/detectMode' import { StepOrg } from './steps/StepOrg' import { StepDomain } from './steps/StepDomain' import { StepTopology } from './steps/StepTopology' @@ -92,11 +93,32 @@ export function WizardPage() { // replace:true so the wizard URL doesn't sit in history — a // back-button press from /provision/ should land on the // referrer, not on a doomed wizard step. - navigate({ - to: '/dashboard', - params: { deploymentId: inflight.id }, - replace: true, - }) + // + // Target depends on mode: + // • mothership (catalyst-zero): /provision/$deploymentId/dashboard + // — the parameterised mothership URL where deploymentId scopes + // the surface. + // • Sovereign self-mode: /dashboard (clean root, sovereign is + // implicit from hostname). + // + // Bug history: pre-fix this called navigate({to:'/dashboard', + // params:{deploymentId}}) unconditionally. On the mothership the + // bare /dashboard matched the Sovereign-Console clean-root route + // which renders SovereignConsoleLayout — that layout's mothership + // guard then redirected back to /sovereign/, indexRoute redirected + // to /wizard, WizardPage saw inflight again and looped. + if (DETECTED_MODE.mode === 'sovereign') { + navigate({ + to: '/dashboard', + replace: true, + }) + } else { + navigate({ + to: '/provision/$deploymentId/dashboard' as never, + params: { deploymentId: inflight.id } as never, + replace: true, + }) + } }, [session.loading, session.signedIn, inflight, navigate]) useEffect(() => { diff --git a/products/catalyst/bootstrap/ui/src/pages/wizard/steps/StepReview.tsx b/products/catalyst/bootstrap/ui/src/pages/wizard/steps/StepReview.tsx index c1e44152..fc9d3656 100644 --- a/products/catalyst/bootstrap/ui/src/pages/wizard/steps/StepReview.tsx +++ b/products/catalyst/bootstrap/ui/src/pages/wizard/steps/StepReview.tsx @@ -55,6 +55,7 @@ import { findNodeSize } from '@/shared/constants/providerSizes' import { API_BASE } from '@/shared/config/urls' import { useRouter } from '@tanstack/react-router' import { useSession } from '@/shared/lib/useSession' +import { DETECTED_MODE } from '@/shared/lib/detectMode' import { PinSignInModal } from '@/widgets/auth/PinSignInModal' import { StepShell, useStepNav } from './_shared' import { @@ -788,10 +789,20 @@ export function StepReview() { return } store.setDeploymentId(data.id) - router.navigate({ - to: '/dashboard', - params: { deploymentId: data.id }, - }) + // Mode-aware target: Sovereign self-mode uses the clean root + // /dashboard, mothership uses /provision/$deploymentId/dashboard. + // Sending all callers to bare /dashboard with a params payload + // matches the Sovereign-Console clean-root route on the + // mothership and triggers an infinite redirect loop with + // SovereignConsoleLayout's mothership-fall-through guard. + if (DETECTED_MODE.mode === 'sovereign') { + router.navigate({ to: '/dashboard' }) + } else { + router.navigate({ + to: '/provision/$deploymentId/dashboard' as never, + params: { deploymentId: data.id } as never, + }) + } } catch (err) { alert(`Failed to start provisioning: ${err}`) setLoading(false)