From 29005810b6b61478ea338b73df1753fe9c465b28 Mon Sep 17 00:00:00 2001 From: "Pablo F.G" Date: Fri, 17 Jul 2026 09:37:30 +0200 Subject: [PATCH] fix(ui): now onboarding is gated again behind hasConnectedProviders --- ui/components/scans/scans-page-shell.test.tsx | 65 +++++++++++++++++++ ui/components/scans/scans-page-shell.tsx | 22 ++++--- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/ui/components/scans/scans-page-shell.test.tsx b/ui/components/scans/scans-page-shell.test.tsx index 689fe51846..0c402b76ed 100644 --- a/ui/components/scans/scans-page-shell.test.tsx +++ b/ui/components/scans/scans-page-shell.test.tsx @@ -17,6 +17,10 @@ const { scansFilterBarSpy } = vi.hoisted(() => ({ scansFilterBarSpy: vi.fn(), })); +const { onboardingTriggerSpy } = vi.hoisted(() => ({ + onboardingTriggerSpy: vi.fn(), +})); + const localStorageMock = (() => { let store: Record = {}; @@ -103,6 +107,14 @@ vi.mock("@/components/providers/muted-findings-config-button", () => ({ MutedFindingsConfigButton: () => Configure Mutelist, })); +vi.mock("@/components/onboarding", () => ({ + OnboardingTrigger: (props: unknown) => { + onboardingTriggerSpy(props); + return
; + }, + PageReady: () =>
, +})); + const providers: ProviderProps[] = [ { id: "provider-1", @@ -476,4 +488,57 @@ describe("ScansPageShell", () => { screen.queryByText("No Providers Configured"), ).not.toBeInTheDocument(); }); + + it("starts the view-first-scan tour when a provider is connected", () => { + vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false"); + + render( + +
Scans table
+
, + ); + + expect(screen.getByTestId("onboarding-trigger")).toBeInTheDocument(); + }); + + it("suppresses the view-first-scan tour when no provider is connected, since Launch Scan is disabled", () => { + vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false"); + + render( + +
Scans table
+
, + ); + + expect(screen.queryByTestId("onboarding-trigger")).not.toBeInTheDocument(); + // The table (and therefore imported scans) must still render even with the tour suppressed. + expect(screen.getByText("Scans table")).toBeInTheDocument(); + }); + + it("suppresses the view-first-scan tour when there are no providers", () => { + vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false"); + + render( + +
Scans table
+
, + ); + + expect(screen.queryByTestId("onboarding-trigger")).not.toBeInTheDocument(); + }); + + it("still signals page-ready without a connected provider so the navbar replay fallback works", () => { + vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false"); + + render( + +
Scans table
+
, + ); + + expect(screen.getByTestId("page-ready")).toBeInTheDocument(); + }); }); diff --git a/ui/components/scans/scans-page-shell.tsx b/ui/components/scans/scans-page-shell.tsx index cd491fbde9..634ed2d330 100644 --- a/ui/components/scans/scans-page-shell.tsx +++ b/ui/components/scans/scans-page-shell.tsx @@ -107,15 +107,21 @@ export function ScansPageShell({ return (
+ {/* Only start the scan tour when a provider is connected: its primary target + (Launch Scan) is disabled otherwise, so a `?onboarding=view-first-scan` + URL or active sequence would anchor to an unusable button. The navbar + replay falls back to the add-provider flow in this state (see page.tsx). */} {/* Suspense required: OnboardingTrigger reads useSearchParams */} - - - + {hasConnectedProviders && ( + + + + )} {/* Signals the navbar that this route's data has loaded (enables the replay icon). */} {showProvidersHint && (