diff --git a/ui/app/(prowler)/scans/page.test.tsx b/ui/app/(prowler)/scans/page.test.tsx
index 5134caef6b..4a8032e492 100644
--- a/ui/app/(prowler)/scans/page.test.tsx
+++ b/ui/app/(prowler)/scans/page.test.tsx
@@ -63,11 +63,11 @@ vi.mock("@/components/shadcn/content-layout", () => ({
}));
vi.mock("@/components/scans/scans-page-shell", () => ({
ScansPageShell: (props: {
- children: unknown;
+ children: ReactNode;
providers: ProviderProps[];
}) => {
scansPageShellSpy(props);
- return
;
+ return {props.children}
;
},
}));
@@ -123,8 +123,8 @@ describe("scans page rendering", () => {
const shellProps = scansPageShellSpy.mock.calls.at(-1)?.[0];
expect(shellProps?.providers).toEqual(providers);
- // The table subtree is always wired, regardless of provider connection state.
- expect(shellProps?.children).toBeTruthy();
+ // The scans table subtree actually renders, regardless of provider state.
+ expect(await screen.findByRole("table")).toBeInTheDocument();
},
);
diff --git a/ui/components/scans/scans-page-shell.test.tsx b/ui/components/scans/scans-page-shell.test.tsx
index 6906207516..3f5db065ea 100644
--- a/ui/components/scans/scans-page-shell.test.tsx
+++ b/ui/components/scans/scans-page-shell.test.tsx
@@ -575,6 +575,21 @@ describe("ScansPageShell", () => {
expect(screen.queryByTestId("onboarding-trigger")).not.toBeInTheDocument();
});
+ it("suppresses the view-first-scan tour when a provider is connected but manage scans is missing", () => {
+ vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
+
+ render(
+
+ Scans table
+ ,
+ );
+
+ // Launch Scan is disabled without manage_scans, so the tour must not anchor to it.
+ expect(screen.queryByTestId("onboarding-trigger")).not.toBeInTheDocument();
+ // The table (and therefore imported scans) must still render.
+ expect(screen.getByText("Scans table")).toBeInTheDocument();
+ });
+
it("still signals page-ready without a connected provider so the navbar replay fallback works", () => {
vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
diff --git a/ui/components/scans/scans-page-shell.tsx b/ui/components/scans/scans-page-shell.tsx
index 56cf315077..8209957879 100644
--- a/ui/components/scans/scans-page-shell.tsx
+++ b/ui/components/scans/scans-page-shell.tsx
@@ -108,12 +108,13 @@ 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). */}
+ {/* Gate on the full launch condition: the tour anchors on Launch Scan, which is
+ disabled without a connected provider AND manage_scans — starting it would
+ point at an unusable button. Every start path (?onboarding= URL, active
+ sequence, navbar replay) funnels through this trigger, so gating here covers
+ them all. */}
{/* Suspense required: OnboardingTrigger reads useSearchParams */}
- {hasConnectedProviders && (
+ {!launchDisabled && (