From c7f6694d0acebfe3550ef9a35850197abe661134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 14 Jan 2026 16:42:59 +0000 Subject: [PATCH 1/7] web: drop leftover semicolon --- web/src/components/core/InstallationProgress.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/core/InstallationProgress.tsx b/web/src/components/core/InstallationProgress.tsx index 2d3fea18c7..e1c37d315a 100644 --- a/web/src/components/core/InstallationProgress.tsx +++ b/web/src/components/core/InstallationProgress.tsx @@ -28,7 +28,7 @@ import Page from "./Page"; function InstallationProgress() { return ( - ; + ); } From 30984012d0cdc017704be4eeee4902ac62185c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 14 Jan 2026 18:33:55 +0000 Subject: [PATCH 2/7] web: revamp installation progress page Which also means revamping ProgressReport core component, which most probably will be unified with InstallationProgress now that there are no more progress to show in that way in Agama. --- .../components/core/InstallationProgress.tsx | 59 ++++++++++++++-- .../components/core/ProgressReport.test.tsx | 10 +-- web/src/components/core/ProgressReport.tsx | 67 ++++--------------- web/src/components/layout/Icon.tsx | 2 + 4 files changed, 72 insertions(+), 66 deletions(-) diff --git a/web/src/components/core/InstallationProgress.tsx b/web/src/components/core/InstallationProgress.tsx index e1c37d315a..0c3c103fb4 100644 --- a/web/src/components/core/InstallationProgress.tsx +++ b/web/src/components/core/InstallationProgress.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2026] SUSE LLC * * All Rights Reserved. * @@ -21,16 +21,61 @@ */ import React from "react"; +import { Flex, Grid, GridItem, HelperText, HelperTextItem, Title } from "@patternfly/react-core"; +import Page from "~/components/core/Page"; +import ProgressReport from "~/components/core/ProgressReport"; +import Icon from "~/components/layout/Icon"; +import ProductLogo from "../product/ProductLogo"; +import { useProductInfo } from "~/hooks/model/config/product"; import { _ } from "~/i18n"; -import ProgressReport from "./ProgressReport"; -import Page from "./Page"; -function InstallationProgress() { +import textStyles from "@patternfly/react-styles/css/utilities/Text/text"; +import alignmentStyles from "@patternfly/react-styles/css/utilities/Alignment/alignment"; + +export default function InstallationProgress() { + const product = useProductInfo(); + return ( - + + + + + + + <ProductLogo product={product} width="1.25em" /> {product.name} + + + + {_("Installation in progress")} + + + + + + + + + + ); } - -export default InstallationProgress; diff --git a/web/src/components/core/ProgressReport.test.tsx b/web/src/components/core/ProgressReport.test.tsx index 31f12070e3..77227bd7d1 100644 --- a/web/src/components/core/ProgressReport.test.tsx +++ b/web/src/components/core/ProgressReport.test.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2026] SUSE LLC * * All Rights Reserved. * @@ -48,14 +48,14 @@ describe("ProgressReport", () => { }); it("shows the progress including the details", () => { - plainRender(); + plainRender(); expect(screen.getByText(/Partition disks/)).toBeInTheDocument(); expect(screen.getByText(/Install software/)).toBeInTheDocument(); // NOTE: not finding the whole text because it is now split in two because of PF/Truncate expect(screen.getByText(/Doing some/)).toBeInTheDocument(); - expect(screen.getByText(/\(1\/1\)/)).toBeInTheDocument(); + expect(screen.getByText(/Step 1 of 1/)).toBeInTheDocument(); }); }); @@ -80,14 +80,14 @@ describe("ProgressReport", () => { }); it("shows the progress including the details", () => { - plainRender(); + plainRender(); expect(screen.getByText(/Partition disks/)).toBeInTheDocument(); expect(screen.getByText(/Install software/)).toBeInTheDocument(); // NOTE: not finding the whole text because it is now split in two because of PF/Truncate expect(screen.getByText(/Installing vim/)).toBeInTheDocument(); - expect(screen.getByText(/\(5\/200\)/)).toBeInTheDocument(); + expect(screen.getByText(/Step 5 of 200/)).toBeInTheDocument(); }); }); }); diff --git a/web/src/components/core/ProgressReport.tsx b/web/src/components/core/ProgressReport.tsx index 6eef62f4b7..fd7ee35a01 100644 --- a/web/src/components/core/ProgressReport.tsx +++ b/web/src/components/core/ProgressReport.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2025] SUSE LLC + * Copyright (c) [2022-2026] SUSE LLC * * All Rights Reserved. * @@ -21,8 +21,8 @@ */ import React from "react"; +import { sprintf } from "sprintf-js"; import { - Content, Flex, ProgressStep, ProgressStepper, @@ -30,32 +30,22 @@ import { Spinner, Truncate, } from "@patternfly/react-core"; -import sizingStyles from "@patternfly/react-styles/css/utilities/Sizing/sizing"; +import Text from "~/components/core/Text"; import { _ } from "~/i18n"; import { useStatus } from "~/hooks/model/status"; import type { Progress as ProgressType } from "~/model/status"; -type StepProps = { - id: string; - titleId: string; - isCurrent: boolean; - variant?: ProgressStepProps["variant"]; - description?: ProgressStepProps["description"]; -}; - const Progress = ({ steps, step, - firstStep, detail, }: { steps: string[]; step: ProgressType; - firstStep: React.ReactNode; detail: ProgressType | undefined; }) => { - const stepProperties = (stepNumber: number): StepProps => { - const properties: StepProps = { + const stepProperties = (stepNumber: number) => { + const properties: ProgressStepProps = { isCurrent: stepNumber === step.index, id: `step-${stepNumber}-id`, titleId: `step-${stepNumber}-title`, @@ -63,20 +53,17 @@ const Progress = ({ if (stepNumber > step.index) { properties.variant = "pending"; - properties.description =
{_("Pending")}
; } if (properties.isCurrent) { properties.variant = "info"; + properties.icon = ; if (detail && detail.step !== "") { const { step: message, index, size } = detail; properties.description = ( -
{_("In progress")}
-
- -
-
{`(${index}/${size})`}
+ + {sprintf(_("Step %1$d of %2$d"), index, size)}
); } @@ -84,23 +71,14 @@ const Progress = ({ if (stepNumber < step.index) { properties.variant = "success"; - properties.description =
{_("Finished")}
; } return properties; }; return ( - - {firstStep && ( - - {firstStep} - - )} - {steps.map((description: StepProps["description"], idx: number) => { + + {steps.map((description, idx: number) => { return ( {description} @@ -112,9 +90,9 @@ const Progress = ({ }; /** - * Shows progress steps when a product is selected. + * Renders progress with a PF/ProgresStepper */ -function ProgressReport({ title, firstStep }: { title: string; firstStep?: React.ReactNode }) { +export default function ProgressReport() { const { progresses } = useStatus(); const managerProgress = progresses.find((t) => t.scope === "manager"); @@ -125,24 +103,5 @@ function ProgressReport({ title, firstStep }: { title: string; firstStep?: React const detail = softwareProgress || storageProgress; - return ( - - - {title} - - - ); + return ; } - -export default ProgressReport; diff --git a/web/src/components/layout/Icon.tsx b/web/src/components/layout/Icon.tsx index fd5d316e07..bbafcbdb97 100644 --- a/web/src/components/layout/Icon.tsx +++ b/web/src/components/layout/Icon.tsx @@ -35,6 +35,7 @@ import CheckCircle from "@icons/check_circle.svg?component"; import ChevronLeft from "@icons/chevron_left.svg?component"; import ChevronRight from "@icons/chevron_right.svg?component"; import Delete from "@icons/delete.svg?component"; +import DeployedCodeUpdate from "@icons/deployed_code_update.svg?component"; import EditSquare from "@icons/edit_square.svg?component"; import Emergency from "@icons/emergency.svg?component"; import Error from "@icons/error.svg?component"; @@ -78,6 +79,7 @@ const icons = { chevron_left: ChevronLeft, chevron_right: ChevronRight, delete: Delete, + deployed_code_update: DeployedCodeUpdate, edit_square: EditSquare, emergency: Emergency, error: Error, From ddf3f14c4e1f46ae9d3b6c562a4803f21b85c47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 14 Jan 2026 18:45:23 +0000 Subject: [PATCH 3/7] web: drop no longer needed component And its related path and references to it. --- web/src/App.test.tsx | 1 - .../components/core/InstallButton.test.tsx | 1 - .../components/core/InstallerOptions.test.tsx | 3 +- web/src/components/core/InstallerOptions.tsx | 8 +-- .../product/ProductSelectionProgress.test.tsx | 63 ------------------- .../product/ProductSelectionProgress.tsx | 50 --------------- web/src/components/product/index.ts | 1 - web/src/routes/paths.ts | 2 - web/src/routes/products.tsx | 8 +-- 9 files changed, 6 insertions(+), 131 deletions(-) delete mode 100644 web/src/components/product/ProductSelectionProgress.test.tsx delete mode 100644 web/src/components/product/ProductSelectionProgress.tsx diff --git a/web/src/App.test.tsx b/web/src/App.test.tsx index abe128ca4d..7918ca18d5 100644 --- a/web/src/App.test.tsx +++ b/web/src/App.test.tsx @@ -41,7 +41,6 @@ jest.mock("~/client"); // Mock some components, // See https://www.chakshunyu.com/blog/how-to-mock-a-react-component-in-jest/#default-export jest.mock("~/components/layout/Loading", () => () =>
Loading Mock
); -jest.mock("~/components/product/ProductSelectionProgress", () => () =>
Product progress
); it.todo("adapt to new api/hooks, adding needed mocking"); describe.skip("App", () => { diff --git a/web/src/components/core/InstallButton.test.tsx b/web/src/components/core/InstallButton.test.tsx index 2b44065363..b087f10c85 100644 --- a/web/src/components/core/InstallButton.test.tsx +++ b/web/src/components/core/InstallButton.test.tsx @@ -43,7 +43,6 @@ describe("InstallButton", () => { ["overview (full route)", ROOT.overview], ["login", ROOT.login], ["product selection", PRODUCT.changeProduct], - ["product selection progress", PRODUCT.progress], ["installation progress", ROOT.installationProgress], ["installation finished", ROOT.installationFinished], ["installation exit", ROOT.installationExit], diff --git a/web/src/components/core/InstallerOptions.test.tsx b/web/src/components/core/InstallerOptions.test.tsx index fffa6abcb2..f0502df03a 100644 --- a/web/src/components/core/InstallerOptions.test.tsx +++ b/web/src/components/core/InstallerOptions.test.tsx @@ -29,7 +29,7 @@ import { Keymap, Locale } from "~/model/system/l10n"; import { Progress, Stage } from "~/model/status"; import { System } from "~/model/system/network"; import * as utils from "~/utils"; -import { PRODUCT, ROOT } from "~/routes/paths"; +import { ROOT } from "~/routes/paths"; import InstallerOptions, { InstallerOptionsProps } from "./InstallerOptions"; import { useStatus } from "~/hooks/model/status"; @@ -135,7 +135,6 @@ describe("InstallerOptions", () => { describe.each([ ["login", ROOT.login], - ["product selection progress", PRODUCT.progress], ["installation progress", ROOT.installationProgress], ["installation finished", ROOT.installationFinished], ])(`when the installer is rendering the %s screen`, (_, path) => { diff --git a/web/src/components/core/InstallerOptions.tsx b/web/src/components/core/InstallerOptions.tsx index 0b72b219a2..43f35b7c40 100644 --- a/web/src/components/core/InstallerOptions.tsx +++ b/web/src/components/core/InstallerOptions.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2025] SUSE LLC + * Copyright (c) [2022-2026] SUSE LLC * * All Rights Reserved. * @@ -51,7 +51,7 @@ import { useInstallerL10n } from "~/context/installerL10n"; import { localConnection } from "~/utils"; import { _ } from "~/i18n"; import supportedLanguages from "~/languages.json"; -import { PRODUCT, ROOT, L10N } from "~/routes/paths"; +import { ROOT, L10N } from "~/routes/paths"; import { useProductInfo } from "~/hooks/model/config/product"; import { useSystem } from "~/hooks/model/system"; import { useStatus } from "~/hooks/model/status"; @@ -575,9 +575,7 @@ export default function InstallerOptions({ stage === "installing" || // FIXME: below condition could be a problem for a question appearing while // product progress - [ROOT.login, ROOT.installationProgress, ROOT.installationFinished, PRODUCT.progress].includes( - location.pathname, - ); + [ROOT.login, ROOT.installationProgress, ROOT.installationFinished].includes(location.pathname); if (skip) return; diff --git a/web/src/components/product/ProductSelectionProgress.test.tsx b/web/src/components/product/ProductSelectionProgress.test.tsx deleted file mode 100644 index 2101bbf43f..0000000000 --- a/web/src/components/product/ProductSelectionProgress.test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) [2025] SUSE LLC - * - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, contact SUSE LLC. - * - * To contact SUSE LLC about this file by physical or electronic mail, you may - * find current contact information at www.suse.com. - */ - -import React from "react"; -import { screen } from "@testing-library/react"; -import { installerRender } from "~/test-utils"; -import ProductSelectionProgress from "./ProductSelectionProgress"; -import { ROOT } from "~/routes/paths"; -import { Product } from "~/types/software"; - -jest.mock("~/components/core/ProgressReport", () => () =>
ProgressReport Mock
); - -let isBusy = false; -const tumbleweed: Product = { id: "openSUSE", name: "openSUSE Tumbleweed", registration: false }; - -jest.mock("~/queries/status", () => ({ - ...jest.requireActual("~/queries/status"), - useInstallerStatus: () => ({ isBusy }), -})); - -jest.mock("~/queries/software", () => ({ - ...jest.requireActual("~/queries/software"), - useProduct: () => ({ selectedProduct: tumbleweed }), -})); - -describe("ProductSelectionProgress", () => { - describe("when installer is not busy", () => { - it("redirects to the root path", async () => { - installerRender(); - await screen.findByText(`Navigating to ${ROOT.root}`); - }); - }); - - describe("when installer in busy", () => { - beforeEach(() => { - isBusy = true; - }); - - it("renders progress report", () => { - installerRender(); - screen.getByText("ProgressReport Mock"); - }); - }); -}); diff --git a/web/src/components/product/ProductSelectionProgress.tsx b/web/src/components/product/ProductSelectionProgress.tsx deleted file mode 100644 index b971b337ce..0000000000 --- a/web/src/components/product/ProductSelectionProgress.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) [2024-2025] SUSE LLC - * - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, contact SUSE LLC. - * - * To contact SUSE LLC about this file by physical or electronic mail, you may - * find current contact information at www.suse.com. - */ - -import React from "react"; -import { Navigate } from "react-router"; -import { Page, ProgressReport } from "~/components/core"; -import { useProduct } from "~/queries/software"; -import { useInstallerStatus } from "~/queries/status"; -import { ROOT as PATHS } from "~/routes/paths"; -import { _ } from "~/i18n"; - -/** - * Shows progress steps when a product is selected. - */ -function ProductSelectionProgress() { - const { selectedProduct } = useProduct({ suspense: true }); - const { isBusy } = useInstallerStatus({ suspense: true }); - - if (!isBusy) return ; - - return ( - - - - ); -} - -export default ProductSelectionProgress; diff --git a/web/src/components/product/index.ts b/web/src/components/product/index.ts index 5ddad57168..ef49972a04 100644 --- a/web/src/components/product/index.ts +++ b/web/src/components/product/index.ts @@ -21,6 +21,5 @@ */ export { default as ProductSelectionPage } from "./ProductSelectionPage"; -export { default as ProductSelectionProgress } from "./ProductSelectionProgress"; export { default as ProductRegistrationPage } from "./ProductRegistrationPage"; export { default as LicenseDialog } from "./LicenseDialog"; diff --git a/web/src/routes/paths.ts b/web/src/routes/paths.ts index 3657dfce9e..251bca6d5d 100644 --- a/web/src/routes/paths.ts +++ b/web/src/routes/paths.ts @@ -38,7 +38,6 @@ const NETWORK = { const PRODUCT = { root: "/products", changeProduct: "/products", - progress: "/products/progress", }; const REGISTRATION = { @@ -116,7 +115,6 @@ const HOSTNAME = { const SIDE_PATHS = [ ROOT.login, PRODUCT.changeProduct, - PRODUCT.progress, ROOT.installationProgress, ROOT.installationFinished, ROOT.installationExit, diff --git a/web/src/routes/products.tsx b/web/src/routes/products.tsx index 7185b5e9cd..70f68d3954 100644 --- a/web/src/routes/products.tsx +++ b/web/src/routes/products.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2024] SUSE LLC + * Copyright (c) [2024-2026] SUSE LLC * * All Rights Reserved. * @@ -21,7 +21,7 @@ */ import React from "react"; -import { ProductSelectionPage, ProductSelectionProgress } from "~/components/product"; +import { ProductSelectionPage } from "~/components/product"; import { Route } from "~/types/routes"; import { PRODUCT as PATHS } from "~/routes/paths"; @@ -32,10 +32,6 @@ const routes = (): Route => ({ index: true, element: , }, - { - path: PATHS.progress, - element: , - }, ], }); From f2421c540b301a0d5754ff40dec1247e76e093da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 14 Jan 2026 19:34:57 +0000 Subject: [PATCH 4/7] web: protect ProductLogo from nullish product prop --- .../components/product/ProductLogo.test.tsx | 79 +++++++++++++++++++ web/src/components/product/ProductLogo.tsx | 2 + 2 files changed, 81 insertions(+) create mode 100644 web/src/components/product/ProductLogo.test.tsx diff --git a/web/src/components/product/ProductLogo.test.tsx b/web/src/components/product/ProductLogo.test.tsx new file mode 100644 index 0000000000..093b098e06 --- /dev/null +++ b/web/src/components/product/ProductLogo.test.tsx @@ -0,0 +1,79 @@ +/* + * Copyright (c) [2026] SUSE LLC + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, contact SUSE LLC. + * + * To contact SUSE LLC about this file by physical or electronic mail, you may + * find current contact information at www.suse.com. + */ + +import React from "react"; +import { screen } from "@testing-library/react"; +import { plainRender } from "~/test-utils"; +import ProductLogo from "./ProductLogo"; + +const product = { + id: "Tumbleweed", + name: "openSUSE Tumbleweed", + icon: "tumbleweed.svg", + description: "Tumbleweed description...", + registration: false, +}; + +describe("ProductLogo", () => { + it("renders nothing when product is null", () => { + const { container } = plainRender(); + + expect(container).toBeEmptyDOMElement(); + }); + + it("renders nothing when product is undefined", () => { + const { container } = plainRender(); + + expect(container).toBeEmptyDOMElement(); + }); + + it("renders the logo image with correct src and alt text", () => { + plainRender(); + + const img = screen.getByRole("img", { hidden: true }); + expect(img).toHaveAttribute("src", "assets/logos/tumbleweed.svg"); + expect(img).toHaveAttribute("alt", "openSUSE Tumbleweed logo"); + }); + + it("applies default width of 80px", () => { + plainRender(); + + const img = screen.getByRole("img", { hidden: true }); + expect(img).toHaveAttribute("width", "80px"); + expect(img).toHaveStyle({ width: "80px" }); + }); + + it("applies custom width when provided", () => { + plainRender(); + + const img = screen.getByRole("img", { hidden: true }); + expect(img).toHaveAttribute("width", "120px"); + expect(img).toHaveStyle({ width: "120px" }); + }); + + it("applies vertical align middle style", () => { + plainRender(); + + const img = screen.getByRole("img", { hidden: true }); + expect(img).toHaveStyle({ verticalAlign: "middle" }); + }); +}); diff --git a/web/src/components/product/ProductLogo.tsx b/web/src/components/product/ProductLogo.tsx index 278199cda8..25840c0d97 100644 --- a/web/src/components/product/ProductLogo.tsx +++ b/web/src/components/product/ProductLogo.tsx @@ -25,6 +25,8 @@ import { sprintf } from "sprintf-js"; import { _ } from "~/i18n"; export default function ProductLogo({ product, width = "80px" }) { + if (!product) return; + const logoSrc = `assets/logos/${product.icon}`; // TRANSLATORS: %s will be replaced by a product name. E.g., "openSUSE Tumbleweed" const logoAltText = sprintf(_("%s logo"), product.name); From 9ac26bc7a9f65c018f84c096f75d423105a5d7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 14 Jan 2026 19:35:27 +0000 Subject: [PATCH 5/7] web: protect installation progress from nullish product --- web/src/components/core/InstallationProgress.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/core/InstallationProgress.tsx b/web/src/components/core/InstallationProgress.tsx index 0c3c103fb4..57c359f5c2 100644 --- a/web/src/components/core/InstallationProgress.tsx +++ b/web/src/components/core/InstallationProgress.tsx @@ -52,7 +52,7 @@ export default function InstallationProgress() { style={{ textWrap: "balance" }} className={[textStyles.fontSize_3xl, alignmentStyles.textAlignEndOnMd].join(" ")} > - {product.name} + {product?.name} From 870b67edb308e346f441988640d55bcb37defb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 14 Jan 2026 19:50:06 +0000 Subject: [PATCH 6/7] web: allow hide the progress monitor in header Useful for not displaying it in the installation progress screen, since it alreadys renders the progress in a more opinionated, visible way. --- web/src/components/core/Page.tsx | 10 ++++++++++ web/src/components/layout/Header.tsx | 13 +++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/web/src/components/core/Page.tsx b/web/src/components/core/Page.tsx index 66c18e193f..72aa018ab7 100644 --- a/web/src/components/core/Page.tsx +++ b/web/src/components/core/Page.tsx @@ -335,6 +335,8 @@ interface StandardLayoutProps { showQuestions?: boolean; /** Whether to show installer options in the header */ showInstallerOptions?: boolean; + /** Whether the progress monitor must not be mounted */ + hideProgressMonitor?: boolean; /** Page content */ children?: React.ReactNode; } @@ -349,6 +351,7 @@ const StandardLayout = ({ title, showQuestions = true, showInstallerOptions = false, + hideProgressMonitor = false, }: StandardLayoutProps) => { return ( } > @@ -380,6 +384,8 @@ interface BasePageProps { progress?: ProgressBackdropProps; /** Whether to show the Questions component at the bottom of the page */ showQuestions?: boolean; + /** Whether the progress monitor must not be mounted */ + hideProgressMonitor?: boolean; /** Page content */ children?: React.ReactNode; } @@ -410,6 +416,8 @@ interface MinimalPageProps extends BasePageProps { breadcrumbs?: never; /** Installer options not available in minimal variant */ showInstallerOptions?: never; + /** Whether the progress monitor must not be mounted */ + hideProgressMonitor?: never; } /** @@ -477,6 +485,7 @@ const Page = ({ variant = "standard", showQuestions = true, showInstallerOptions = false, + hideProgressMonitor = false, children, }: PageProps): React.ReactNode => { if (variant === "minimal") { @@ -490,6 +499,7 @@ const Page = ({ title={title} showQuestions={showQuestions} showInstallerOptions={showInstallerOptions} + hideProgressMonitor={hideProgressMonitor} > {children || } diff --git a/web/src/components/layout/Header.tsx b/web/src/components/layout/Header.tsx index 619b880001..41f5b6638d 100644 --- a/web/src/components/layout/Header.tsx +++ b/web/src/components/layout/Header.tsx @@ -38,7 +38,7 @@ import { } from "@patternfly/react-core"; import { Icon } from "~/components/layout"; import { ChangeProductOption, InstallerOptions, InstallButton, SkipTo } from "~/components/core"; -import ProgressStatusMonitor from "../core/ProgressStatusMonitor"; +import ProgressStatusMonitor from "~/components/core/ProgressStatusMonitor"; import Breadcrumbs from "~/components/core/Breadcrumbs"; import { useProductInfo } from "~/hooks/model/config/product"; import { ROOT } from "~/routes/paths"; @@ -63,6 +63,8 @@ export type HeaderProps = { showInstallerOptions?: boolean; /** Breadcrumb navigation items */ breadcrumbs?: BreadcrumbProps[]; + /** Whether the progress monitor must not be mounted */ + hideProgressMonitor?: boolean; }; const OptionsDropdown = () => { @@ -109,6 +111,7 @@ export default function Header({ breadcrumbs, showSkipToContent = true, showInstallerOptions = true, + hideProgressMonitor = false, }: HeaderProps): React.ReactNode { const product = useProductInfo(); @@ -152,9 +155,11 @@ export default function Header({ - - - + {!hideProgressMonitor && ( + + + + )} {showInstallerOptions && ( From 46d05cc83511b164da6e170f847a5651e0d8dda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Wed, 14 Jan 2026 19:53:32 +0000 Subject: [PATCH 7/7] web: hide progress monitor during installation progress --- web/src/components/core/InstallationProgress.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/core/InstallationProgress.tsx b/web/src/components/core/InstallationProgress.tsx index 57c359f5c2..ce04ff44b6 100644 --- a/web/src/components/core/InstallationProgress.tsx +++ b/web/src/components/core/InstallationProgress.tsx @@ -36,7 +36,7 @@ export default function InstallationProgress() { const product = useProductInfo(); return ( - +