diff --git a/web/package/agama-web-ui.changes b/web/package/agama-web-ui.changes index 3ff05e228d..b856e7cb7c 100644 --- a/web/package/agama-web-ui.changes +++ b/web/package/agama-web-ui.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Mon Jan 13 11:11:49 UTC 2025 - David Diaz + +- Do not allow changing selected product after registering one + (related to gh#agama-project/agama#1891). + ------------------------------------------------------------------- Fri Jan 10 21:22:02 UTC 2025 - Imobach Gonzalez Sosa diff --git a/web/src/components/core/ChangeProductLink.test.tsx b/web/src/components/core/ChangeProductLink.test.tsx index e6fe63daee..da97510ccd 100644 --- a/web/src/components/core/ChangeProductLink.test.tsx +++ b/web/src/components/core/ChangeProductLink.test.tsx @@ -24,8 +24,9 @@ import React from "react"; import { screen } from "@testing-library/react"; import { installerRender } from "~/test-utils"; import { PRODUCT as PATHS } from "~/routes/paths"; -import { Product } from "~/types/software"; +import { Product, RegistrationInfo } from "~/types/software"; import ChangeProductLink from "./ChangeProductLink"; +import { useRegistration } from "~/queries/software"; const tumbleweed: Product = { id: "Tumbleweed", @@ -43,9 +44,11 @@ const microos: Product = { }; let mockUseProduct: { products: Product[]; selectedProduct?: Product }; +let registrationInfoMock: RegistrationInfo; jest.mock("~/queries/software", () => ({ useProduct: () => mockUseProduct, + useRegistration: (): ReturnType => registrationInfoMock, })); describe("ChangeProductLink", () => { @@ -59,6 +62,17 @@ describe("ChangeProductLink", () => { const link = screen.getByRole("link", { name: "Change product" }); expect(link).toHaveAttribute("href", PATHS.changeProduct); }); + + describe("but a product is registered", () => { + beforeEach(() => { + registrationInfoMock = { key: "INTERNAL-USE-ONLY-1234-5678", email: "" }; + }); + + it("renders nothing", () => { + const { container } = installerRender(); + expect(container).toBeEmptyDOMElement(); + }); + }); }); describe("when there is only one product available", () => { diff --git a/web/src/components/core/ChangeProductLink.tsx b/web/src/components/core/ChangeProductLink.tsx index d5fd67b8fb..40f7b9d4cb 100644 --- a/web/src/components/core/ChangeProductLink.tsx +++ b/web/src/components/core/ChangeProductLink.tsx @@ -22,17 +22,20 @@ import React from "react"; import { Link, LinkProps } from "react-router-dom"; -import { useProduct } from "~/queries/software"; +import { useProduct, useRegistration } from "~/queries/software"; import { PRODUCT as PATHS } from "~/routes/paths"; import { _ } from "~/i18n"; +import { isEmpty } from "~/utils"; /** * Link for navigating to the selection product. */ export default function ChangeProductLink({ children, ...props }: Omit) { const { products } = useProduct(); + const registration = useRegistration(); if (products.length <= 1) return null; + if (!isEmpty(registration?.key)) return null; return ( diff --git a/web/src/components/product/ProductSelectionPage.test.tsx b/web/src/components/product/ProductSelectionPage.test.tsx index 0c54144f16..da2b4d9d67 100644 --- a/web/src/components/product/ProductSelectionPage.test.tsx +++ b/web/src/components/product/ProductSelectionPage.test.tsx @@ -24,8 +24,8 @@ import React from "react"; import { screen } from "@testing-library/react"; import { installerRender, mockNavigateFn } from "~/test-utils"; import { ProductSelectionPage } from "~/components/product"; -import { Product } from "~/types/software"; -import { useProduct } from "~/queries/software"; +import { Product, RegistrationInfo } from "~/types/software"; +import { useProduct, useRegistration } from "~/queries/software"; jest.mock("~/components/product/ProductRegistrationAlert", () => () => (
ProductRegistrationAlert Mock
@@ -50,6 +50,7 @@ const microOs: Product = { }; let mockSelectedProduct: Product; +let registrationInfoMock: RegistrationInfo; jest.mock("~/queries/software", () => ({ ...jest.requireActual("~/queries/software"), @@ -61,11 +62,24 @@ jest.mock("~/queries/software", () => ({ }, useProductChanges: () => jest.fn(), useConfigMutation: () => ({ mutate: mockConfigMutation }), + useRegistration: (): ReturnType => registrationInfoMock, })); describe("ProductSelectionPage", () => { beforeEach(() => { mockSelectedProduct = tumbleweed; + registrationInfoMock = { key: "", email: "" }; + }); + + describe("when there is a registration code set", () => { + beforeEach(() => { + registrationInfoMock = { key: "INTERNAL-USE-ONLY-1234-5678", email: "" }; + }); + + it("navigates to root path", async () => { + installerRender(); + await screen.findByText("Navigating to /"); + }); }); describe("when there is a product already selected", () => { diff --git a/web/src/components/product/ProductSelectionPage.tsx b/web/src/components/product/ProductSelectionPage.tsx index a4ac2009dd..994f4ac269 100644 --- a/web/src/components/product/ProductSelectionPage.tsx +++ b/web/src/components/product/ProductSelectionPage.tsx @@ -34,14 +34,16 @@ import { FormGroup, Button, } from "@patternfly/react-core"; +import { Navigate, useNavigate } from "react-router-dom"; import { Page } from "~/components/core"; import { Center } from "~/components/layout"; -import { useConfigMutation, useProduct } from "~/queries/software"; +import { useConfigMutation, useProduct, useRegistration } from "~/queries/software"; import pfTextStyles from "@patternfly/react-styles/css/utilities/Text/text"; import pfRadioStyles from "@patternfly/react-styles/css/components/Radio/radio"; import { sprintf } from "sprintf-js"; import { _ } from "~/i18n"; -import { useNavigate } from "react-router-dom"; +import { PATHS } from "~/router"; +import { isEmpty } from "~/utils"; const ResponsiveGridItem = ({ children }) => ( @@ -97,10 +99,13 @@ const BackLink = () => { function ProductSelectionPage() { const setConfig = useConfigMutation(); + const registration = useRegistration(); const { products, selectedProduct } = useProduct({ suspense: true }); const [nextProduct, setNextProduct] = useState(selectedProduct); const [isLoading, setIsLoading] = useState(false); + if (!isEmpty(registration?.key)) return ; + const onSubmit = async (e: React.FormEvent) => { e.preventDefault();