mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-08 12:24:45 +00:00
fix(ui): show Registry subscription and setup prompts (#13038)
This commit is contained in:
1 parent
286ae6c7cf
commit
64c19b3db6
23 files changed
+571
-73
No files matched your search
@@ -440,6 +440,28 @@ describe("RegistryExplorer", () => {
|
||||
expect(cardFor("AWS guard")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("re-renders the page when a refresh reports a lapsed subscription", async () => {
|
||||
// Given
|
||||
const screen = await render(<RegistryExplorer initialState={readyState} />);
|
||||
refreshRegistryCollectionsMock.mockResolvedValue({
|
||||
status: "subscription_required",
|
||||
});
|
||||
// When
|
||||
await screen.getByRole("button", { name: "Refresh Registry" }).click();
|
||||
// Then
|
||||
// The mocked router never swaps the page, so the explorer may refresh again.
|
||||
await expect
|
||||
.poll(() => vi.mocked(registryRouter.refresh).mock.calls.length)
|
||||
.toBeGreaterThanOrEqual(1);
|
||||
expect(vi.mocked(registryRouter.replace)).not.toHaveBeenCalled();
|
||||
await expect
|
||||
.element(screen.getByRole("button", { name: "Refresh Registry" }))
|
||||
.toBeEnabled();
|
||||
expect(document.body.textContent).not.toContain(
|
||||
"Registry could not be refreshed.",
|
||||
);
|
||||
});
|
||||
|
||||
it.each(["access_denied", "reconnect", "onboarding"])(
|
||||
"honors %s from a collection refresh",
|
||||
async (status) => {
|
||||
|
||||
@@ -182,6 +182,9 @@ export function RegistryExplorer({
|
||||
onResult: (result) => {
|
||||
if (result.status === "access_denied") {
|
||||
router.replace("/profile");
|
||||
} else if (result.status === "subscription_required") {
|
||||
// The server page swaps the catalog for the paid-plan prompt.
|
||||
router.refresh();
|
||||
} else if (result.status === "complete") {
|
||||
setRefreshMessage(undefined);
|
||||
setState((current) =>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { afterEach, describe, expect, vi } from "vitest";
|
||||
import { page } from "vitest/browser";
|
||||
|
||||
import { it } from "@/__tests__/fixtures";
|
||||
import { render } from "@/__tests__/render-browser";
|
||||
import { CloudUpgradeModal } from "@/components/shared/cloud-upgrade-modal";
|
||||
import { useCloudUpgradeStore } from "@/store/cloud-upgrade/store";
|
||||
|
||||
import { RegistryUpgradePrompt } from "./registry-upgrade-prompt";
|
||||
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({ permissions: { manage_billing: true } }),
|
||||
}));
|
||||
|
||||
const VIEWPORTS = [
|
||||
{ name: "mobile", width: 390, height: 844 },
|
||||
{ name: "tablet", width: 768, height: 1024 },
|
||||
{ name: "desktop", width: 1280, height: 800 },
|
||||
];
|
||||
|
||||
describe("Registry paid plan prompt", () => {
|
||||
afterEach(() => {
|
||||
useCloudUpgradeStore.getState().closeCloudUpgrade();
|
||||
});
|
||||
|
||||
it.each(VIEWPORTS)(
|
||||
"opens the shared paid plan modal on $name",
|
||||
async ({ name, width, height }) => {
|
||||
// Given
|
||||
await page.viewport(width, height);
|
||||
const screen = await render(
|
||||
<main className="bg-bg-neutral-primary min-h-screen p-6">
|
||||
<RegistryUpgradePrompt />
|
||||
<CloudUpgradeModal />
|
||||
</main>,
|
||||
);
|
||||
|
||||
// When
|
||||
await screen.getByRole("button", { name: "Unlock Registry" }).click();
|
||||
|
||||
// Then
|
||||
await expect
|
||||
.element(page.getByRole("dialog", { name: "Unlock Prowler Registry" }))
|
||||
.toBeVisible();
|
||||
await expect
|
||||
.element(page.getByRole("link", { name: "Upgrade to Unlock Registry" }))
|
||||
.toHaveAttribute("href", "/billing?feature=registry");
|
||||
expect(document.documentElement.scrollWidth).toBeLessThanOrEqual(width);
|
||||
await expect
|
||||
.poll(() =>
|
||||
page
|
||||
.getByRole("dialog", { name: "Unlock Prowler Registry" })
|
||||
.element()
|
||||
.getAnimations({ subtree: true })
|
||||
.every((animation) => animation.playState !== "running"),
|
||||
)
|
||||
.toBe(true);
|
||||
await page.screenshot({
|
||||
path: `../../tests/providers/evidence/registry-paywall-${name}.png`,
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { RegistrySetupPrompt } from "./registry-upgrade-prompt";
|
||||
|
||||
const { permissions } = vi.hoisted(() => ({
|
||||
permissions: { manage_registry: false },
|
||||
}));
|
||||
|
||||
vi.mock("@/hooks/use-auth", () => ({
|
||||
useAuth: () => ({ permissions }),
|
||||
}));
|
||||
|
||||
describe("RegistrySetupPrompt", () => {
|
||||
beforeEach(() => {
|
||||
permissions.manage_registry = false;
|
||||
});
|
||||
|
||||
it("sends Registry managers to connect their key", () => {
|
||||
// Given
|
||||
permissions.manage_registry = true;
|
||||
|
||||
// When
|
||||
render(<RegistrySetupPrompt />);
|
||||
|
||||
// Then
|
||||
expect(
|
||||
screen.getByRole("link", { name: "Connect Registry" }),
|
||||
).toHaveAttribute("href", "/registry");
|
||||
});
|
||||
|
||||
it("asks everyone else for an administrator", () => {
|
||||
// When
|
||||
render(<RegistrySetupPrompt />);
|
||||
|
||||
// Then
|
||||
expect(
|
||||
screen.getByText(
|
||||
"Ask an administrator to connect Registry before adding custom providers.",
|
||||
),
|
||||
).toBeVisible();
|
||||
expect(
|
||||
screen.queryByRole("link", { name: "Connect Registry" }),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/shadcn/alert";
|
||||
import { Button } from "@/components/shadcn/button/button";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useCloudUpgradeStore } from "@/store/cloud-upgrade/store";
|
||||
import { PAID_PLAN_UPGRADE_FEATURE } from "@/types/cloud-upgrade";
|
||||
|
||||
export function RegistryUpgradePrompt() {
|
||||
const openCloudUpgrade = useCloudUpgradeStore(
|
||||
(state) => state.openCloudUpgrade,
|
||||
);
|
||||
|
||||
return (
|
||||
<Alert>
|
||||
<AlertTitle>Registry is available on paid plans</AlertTitle>
|
||||
<AlertDescription>
|
||||
Unlock custom providers, security checks, and compliance frameworks.
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => openCloudUpgrade(PAID_PLAN_UPGRADE_FEATURE.REGISTRY)}
|
||||
>
|
||||
Unlock Registry
|
||||
</Button>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export function RegistrySetupPrompt() {
|
||||
const { permissions } = useAuth();
|
||||
return (
|
||||
<Alert>
|
||||
<AlertTitle>Registry is not connected yet</AlertTitle>
|
||||
<AlertDescription>
|
||||
{permissions.manage_registry === true ? (
|
||||
<>
|
||||
Connect your Registry API key to load custom providers.
|
||||
<Button asChild variant="outline">
|
||||
<a href="/registry">Connect Registry</a>
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
"Ask an administrator to connect Registry before adding custom providers."
|
||||
)}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user