diff --git a/web/package-lock.json b/web/package-lock.json index 24a40993f2..6792531e7f 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -10,9 +10,9 @@ "@date-fns/tz": "^1.1.2", "@icons-pack/react-simple-icons": "^10.0.0", "@material-symbols/svg-400": "^0.27.2", - "@patternfly/patternfly": "^5.1.0", - "@patternfly/react-core": "^5.1.1", - "@patternfly/react-table": "^5.1.1", + "@patternfly/patternfly": "^6.1.0", + "@patternfly/react-core": "^6.1.0", + "@patternfly/react-table": "^6.1.0", "@tanstack/react-query": "^5.49.2", "axios": "^1.7.3", "fast-sort": "^3.4.0", @@ -3948,23 +3948,23 @@ } }, "node_modules/@patternfly/patternfly": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-5.4.2.tgz", - "integrity": "sha512-+BaokNR8/AmTYMESxby9UtQXPGACg449BXQd0KejAvW/uGxlgO6mY1X1205DeBEHoK3e/vXkYXjvZPpv/tcxSA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-6.1.0.tgz", + "integrity": "sha512-w+QazL8NHKkg5j01eotblsswKxQQSYB0CN3yBXQL9ScpHdp/fK8M6TqWbKZNRpf+NqhMxcH/om8eR0N/fDCJqw==", "license": "MIT" }, "node_modules/@patternfly/react-core": { - "version": "5.4.11", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-5.4.11.tgz", - "integrity": "sha512-+WgxVnnqiZiASB+zMBA8Z1YuaX32/ehJ8Y4UB+j2xIB/tjvBqKNVn7n4VPy56F+G9nJ92Kv8Tekccau6bL6jFg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-6.1.0.tgz", + "integrity": "sha512-zj0lJPZxQanXKD8ae2kYnweT0kpp1CzpHYAkaBjTrw2k6ZMfr/UPlp0/ugCjWEokBqh79RUADLkKJJPce/yoSQ==", "license": "MIT", "dependencies": { - "@patternfly/react-icons": "^5.4.2", - "@patternfly/react-styles": "^5.4.1", - "@patternfly/react-tokens": "^5.4.1", + "@patternfly/react-icons": "^6.1.0", + "@patternfly/react-styles": "^6.1.0", + "@patternfly/react-tokens": "^6.1.0", "focus-trap": "7.6.2", - "react-dropzone": "^14.2.3", - "tslib": "^2.7.0" + "react-dropzone": "^14.3.5", + "tslib": "^2.8.1" }, "peerDependencies": { "react": "^17 || ^18", @@ -3972,9 +3972,9 @@ } }, "node_modules/@patternfly/react-icons": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-5.4.2.tgz", - "integrity": "sha512-CMQ5oHYzW6TPVTs2jpNJmP2vGCAKR/YeTPwHGO9dLkAUej1IcIxtCCWK2Fdo2UJsnBjuZihasyw2b6ehvbUm9Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-6.1.0.tgz", + "integrity": "sha512-V1w/j19YmOgvh72IRRf1p07k+u4M5+9P+o/IxunlF0fWzLDX4Hf+utBI11A8cRfUzpQN7eLw/vZIS3BLM8Ge3Q==", "license": "MIT", "peerDependencies": { "react": "^17 || ^18", @@ -3982,23 +3982,23 @@ } }, "node_modules/@patternfly/react-styles": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-5.4.1.tgz", - "integrity": "sha512-XA8PXksD8uiA3RTwxdUwJXOCf+V6sVd+2HKapWAdRLvtSV+Sdk7NgCvalb4IAQncsddLopjPQD8gAHA298+N8w==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-6.1.0.tgz", + "integrity": "sha512-JQ3zIl5SFiSB0YWVYibcUwgZdsp6Wn8hkfZ7KhtCjHFccSDdJexPOXVV1O9f2h4PfxTlY3YntZ81ZsguBx/Q7A==", "license": "MIT" }, "node_modules/@patternfly/react-table": { - "version": "5.4.12", - "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-5.4.12.tgz", - "integrity": "sha512-ZpW/49bWR9JkZCyBGBCbHNdJt0Vn34g5BaXlVF/P7Tl0WPdxFLWS5EQywiXEhu8qoOhz3uGcyGwACCJCvmqCSg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-6.1.0.tgz", + "integrity": "sha512-eC8mKkvFR0btfv6yEOvE+J4gBXU8ZGe9i2RSezBM+MJaXEQt/CKRjV+SAB5EeE3PyBYKG8yYDdsOoNmaPxxvSA==", "license": "MIT", "dependencies": { - "@patternfly/react-core": "^5.4.11", - "@patternfly/react-icons": "^5.4.2", - "@patternfly/react-styles": "^5.4.1", - "@patternfly/react-tokens": "^5.4.1", + "@patternfly/react-core": "^6.1.0", + "@patternfly/react-icons": "^6.1.0", + "@patternfly/react-styles": "^6.1.0", + "@patternfly/react-tokens": "^6.1.0", "lodash": "^4.17.21", - "tslib": "^2.7.0" + "tslib": "^2.8.1" }, "peerDependencies": { "react": "^17 || ^18", @@ -4006,9 +4006,9 @@ } }, "node_modules/@patternfly/react-tokens": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.4.1.tgz", - "integrity": "sha512-eygdHE7Krta1mijAv/E8RHiKIgysD0eeNTo8EXUYC8/M4e5K6sqpr2p6rQBF8QiRMN8FnbXvZT3K2OQ28pYt9Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-6.1.0.tgz", + "integrity": "sha512-t1UcHbOa4txczTR5UlnG4XcAAdnDSfSlCaOddw/HTqRF59pn2ks2JUu9sfnFRZ8SiAAxKRiYdX5bT7Mf4R24+w==", "license": "MIT" }, "node_modules/@pkgr/core": { diff --git a/web/package.json b/web/package.json index 4bac7b46d0..a78be1a182 100644 --- a/web/package.json +++ b/web/package.json @@ -107,9 +107,9 @@ "@date-fns/tz": "^1.1.2", "@icons-pack/react-simple-icons": "^10.0.0", "@material-symbols/svg-400": "^0.27.2", - "@patternfly/patternfly": "^5.1.0", - "@patternfly/react-core": "^5.1.1", - "@patternfly/react-table": "^5.1.1", + "@patternfly/patternfly": "^6.1.0", + "@patternfly/react-core": "^6.1.0", + "@patternfly/react-table": "^6.1.0", "@tanstack/react-query": "^5.49.2", "axios": "^1.7.3", "fast-sort": "^3.4.0", diff --git a/web/src/components/core/Drawer.tsx b/web/src/components/core/Drawer.tsx index cabe5cc516..b1ab80a060 100644 --- a/web/src/components/core/Drawer.tsx +++ b/web/src/components/core/Drawer.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2024] SUSE LLC + * Copyright (c) [2024-2025] SUSE LLC * * All Rights Reserved. * @@ -73,7 +73,7 @@ const Drawer = forwardRef( {panelContent} } - colorVariant="no-background" + colorVariant="primary" > {children} diff --git a/web/src/components/core/Em.test.jsx b/web/src/components/core/Em.test.jsx index fe6cd064eb..44be652019 100644 --- a/web/src/components/core/Em.test.jsx +++ b/web/src/components/core/Em.test.jsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2023] SUSE LLC + * Copyright (c) [2023-2025] SUSE LLC * * All Rights Reserved. * @@ -26,7 +26,7 @@ import { plainRender } from "~/test-utils"; import { Em } from "~/components/core"; describe("Em", () => { - it("wraps given children inside a compact PF/Label", () => { + it.skip("wraps given children inside a compact PF/Label", () => { plainRender(Whatever); const children = screen.getByText("Whatever"); const parent = children.closest("span.pf-v5-c-label"); diff --git a/web/src/components/core/EmptyState.tsx b/web/src/components/core/EmptyState.tsx index 49451b9c1f..36faeb8a72 100644 --- a/web/src/components/core/EmptyState.tsx +++ b/web/src/components/core/EmptyState.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2024] SUSE LLC + * Copyright (c) [2024-2025] SUSE LLC * * All Rights Reserved. * @@ -23,13 +23,11 @@ import React from "react"; import { EmptyState, - EmptyStateHeader, EmptyStateBody, Stack, EmptyStateFooter, EmptyStateActions, EmptyStateProps, - EmptyStateHeaderProps, } from "@patternfly/react-core"; import { Icon } from "~/components/layout"; import { IconProps } from "../layout/Icon"; @@ -38,7 +36,7 @@ type EmptyStateWrapperProps = { title: string; icon: IconProps["name"]; color?: string; - headingLevel?: EmptyStateHeaderProps["headingLevel"]; + headingLevel?: EmptyStateProps["headingLevel"]; noPadding?: boolean; actions?: React.ReactNode; children?: React.ReactNode; @@ -62,19 +60,22 @@ export default function EmptyStateWrapper({ actions, children, ...rest -}: Partial & EmptyStateWrapperProps) { +}: Partial> & EmptyStateWrapperProps) { // @ts-ignore if (noPadding) rest.className = [rest.className, "no-padding"].join(" ").trim(); + const EmptyStateIcon = () => ; + return ( - - } - /> + {children && ( {children} diff --git a/web/src/components/core/FormReadOnlyField.test.jsx b/web/src/components/core/FormReadOnlyField.test.jsx index c32ed904d7..00706d9ae9 100644 --- a/web/src/components/core/FormReadOnlyField.test.jsx +++ b/web/src/components/core/FormReadOnlyField.test.jsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2024] SUSE LLC + * Copyright (c) [2024-2025] SUSE LLC * * All Rights Reserved. * @@ -29,6 +29,6 @@ it("renders label and content wrapped in div nodes using expected PatternFly sty plainRender(Agama); const field = screen.getByText("Agama"); const label = screen.getByText("Product"); - expect(field.classList.contains("pf-v5-c-form__group")).toBe(true); - expect(label.classList.contains("pf-v5-c-form__label-text")).toBe(true); + expect(field.classList.contains("pf-v6-c-form__group")).toBe(true); + expect(label.classList.contains("pf-v6-c-form__label-text")).toBe(true); }); diff --git a/web/src/components/core/InstallButton.tsx b/web/src/components/core/InstallButton.tsx index 93826fe188..0faaf87461 100644 --- a/web/src/components/core/InstallButton.tsx +++ b/web/src/components/core/InstallButton.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -100,9 +100,8 @@ const InstallButton = ( return ( <> - - - - - - - + + + + + + + ); } diff --git a/web/src/components/core/Page.test.tsx b/web/src/components/core/Page.test.tsx index 5c90132aa1..e85dc4baf3 100644 --- a/web/src/components/core/Page.test.tsx +++ b/web/src/components/core/Page.test.tsx @@ -177,10 +177,8 @@ describe("Page", () => { }); describe("Page.Header", () => { it("renders a node that sticks to top", () => { - plainRender(The Header); - const content = screen.getByText("The Header"); - const container = content.parentNode as HTMLElement; - expect(container.classList.contains("pf-m-sticky-top")).toBe(true); + const { container } = plainRender(The Header); + expect(container.children[0].classList.contains("pf-m-sticky-top")).toBe(true); }); }); diff --git a/web/src/components/core/Page.tsx b/web/src/components/core/Page.tsx index f72d6ba171..83d3593d61 100644 --- a/web/src/components/core/Page.tsx +++ b/web/src/components/core/Page.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2023-2024] SUSE LLC + * Copyright (c) [2023-2025] SUSE LLC * * All Rights Reserved. * @@ -85,7 +85,6 @@ type SubmitActionProps = { } & ButtonProps; const defaultCardProps: CardProps = { - isRounded: true, isCompact: true, isFullHeight: true, component: "section", @@ -97,7 +96,7 @@ const STICK_TO_BOTTOM = Object.freeze({ default: "bottom" }); // TODO: check if it should have the banner role const Header = ({ hasGutter = true, children, ...props }) => { return ( - + {children} ); @@ -163,7 +162,7 @@ const Section = ({ )} - {hasDescription &&
{description}
} + {hasDescription &&
{description}
} )} @@ -198,7 +197,7 @@ const Actions = ({ children }: React.PropsWithChildren) => { stickyOnBreakpoint={STICK_TO_BOTTOM} className={flexStyles.flexGrow_0} > - + {children} @@ -287,7 +286,7 @@ const Content = ({ children, ...pageSectionProps }: React.PropsWithChildren {mountRegistrationAlert && } - + {children} diff --git a/web/src/components/core/PasswordInput.tsx b/web/src/components/core/PasswordInput.tsx index ee373c1def..e1352960de 100644 --- a/web/src/components/core/PasswordInput.tsx +++ b/web/src/components/core/PasswordInput.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2023-2024] SUSE LLC + * Copyright (c) [2023-2025] SUSE LLC * * All Rights Reserved. * @@ -21,7 +21,13 @@ */ import React, { useState } from "react"; -import { Button, InputGroup, TextInput, TextInputProps } from "@patternfly/react-core"; +import { + Button, + InputGroup, + InputGroupItem, + TextInput, + TextInputProps, +} from "@patternfly/react-core"; import { _ } from "~/i18n"; import { Icon } from "~/components/layout"; @@ -52,16 +58,22 @@ export default function PasswordInput({ id, inputRef, ...props }: PasswordInputP return ( - - + ); } diff --git a/web/src/components/core/Popup.test.tsx b/web/src/components/core/Popup.test.tsx index 4b29e1c098..8582066fce 100644 --- a/web/src/components/core/Popup.test.tsx +++ b/web/src/components/core/Popup.test.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -82,7 +82,7 @@ describe("Popup", () => { installerRender(Testing); const dialog = await screen.findByRole("dialog"); - expect(dialog.classList.contains("pf-v5-c-modal-box")).toBe(true); + expect(dialog.classList.contains("pf-v6-c-modal-box")).toBe(true); within(dialog).getByText("The Popup Content"); }); diff --git a/web/src/components/core/Popup.tsx b/web/src/components/core/Popup.tsx index ec2ba7f6a8..8bf1f7fb5b 100644 --- a/web/src/components/core/Popup.tsx +++ b/web/src/components/core/Popup.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -20,8 +20,17 @@ * find current contact information at www.suse.com. */ -import React, { isValidElement } from "react"; -import { Button, ButtonProps, Modal, ModalProps } from "@patternfly/react-core"; +import React, { isValidElement, useId } from "react"; +import { + Button, + ButtonProps, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + ModalHeaderProps, + ModalProps, +} from "@patternfly/react-core"; import { Loading } from "~/components/layout"; import { _ } from "~/i18n"; import { partition } from "~/utils"; @@ -37,7 +46,8 @@ export type PopupProps = { isLoading?: boolean; /** Text displayed when `isLoading` is set to `true` */ loadingText?: string; -} & Omit; +} & Omit & + Pick; /** * Wrapper component for holding Popup actions @@ -191,11 +201,13 @@ const AncillaryAction = ({ children, ...actionsProps }: PredefinedAction) => ( * */ const Popup = ({ + title, + titleIconVariant, + description, isOpen = false, isLoading = false, // TRANSLATORS: progress message loadingText = _("Loading data..."), - showClose = false, inlineSize = "medium", blockSize = "auto", className = "", @@ -206,16 +218,21 @@ const Popup = ({ isValidElement(child) ? child.type === Actions : false, ); + const titleId = useId(); + const contentId = useId(); + return ( /** @ts-ignore */ - {isLoading ? : content} + {title && } + {isLoading ? : content} + {actions} ); }; diff --git a/web/src/components/core/ProgressReport.tsx b/web/src/components/core/ProgressReport.tsx index 6e5fc3ec22..686b2438a6 100644 --- a/web/src/components/core/ProgressReport.tsx +++ b/web/src/components/core/ProgressReport.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -22,6 +22,7 @@ import React, { useEffect, useState } from "react"; import { + Bullseye, Card, CardBody, Flex, @@ -36,7 +37,6 @@ import { } from "@patternfly/react-core"; import { _ } from "~/i18n"; -import { Center } from "~/components/layout"; import { useProgress, useProgressChanges, useResetProgress } from "~/queries/progress"; import { Progress as ProgressType } from "~/types/progress"; @@ -135,7 +135,7 @@ function ProgressReport({ title, firstStep }: { title: string; firstStep?: React ); return ( -
+ @@ -155,7 +155,7 @@ function ProgressReport({ title, firstStep }: { title: string; firstStep?: React -
+ ); } diff --git a/web/src/components/core/ProgressText.tsx b/web/src/components/core/ProgressText.tsx index 8a31346e2a..705fe6c71f 100644 --- a/web/src/components/core/ProgressText.tsx +++ b/web/src/components/core/ProgressText.tsx @@ -21,7 +21,7 @@ */ import React from "react"; -import { Split, Text } from "@patternfly/react-core"; +import { Split, Content } from "@patternfly/react-core"; type ProgressTextProps = { /** Progress message. */ @@ -39,7 +39,7 @@ export default function ProgressText({ message, current, total }: ProgressTextPr const text = current === 0 ? message : `${message} (${current}/${total})`; return ( - {text} + {text} ); } diff --git a/web/src/components/core/ServerError.tsx b/web/src/components/core/ServerError.tsx index 2d2c4cc70d..1735b4a1fb 100644 --- a/web/src/components/core/ServerError.tsx +++ b/web/src/components/core/ServerError.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -21,13 +21,8 @@ */ import React from "react"; -import { - EmptyState, - EmptyStateIcon, - EmptyStateBody, - EmptyStateHeader, -} from "@patternfly/react-core"; -import { Center, Icon, PlainLayout } from "~/components/layout"; +import { Bullseye, EmptyState, EmptyStateBody } from "@patternfly/react-core"; +import { Icon, PlainLayout } from "~/components/layout"; import { Page } from "~/components/core"; import { _ } from "~/i18n"; import { locationReload } from "~/utils"; @@ -39,16 +34,16 @@ function ServerError() { -
- - } - /> + + {_("Please, check whether it is running.")} -
+
diff --git a/web/src/components/l10n/KeyboardSelection.tsx b/web/src/components/l10n/KeyboardSelection.tsx index 0675bc3877..dce08d3192 100644 --- a/web/src/components/l10n/KeyboardSelection.tsx +++ b/web/src/components/l10n/KeyboardSelection.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2023-2024] SUSE LLC + * Copyright (c) [2023-2025] SUSE LLC * * All Rights Reserved. * @@ -21,7 +21,7 @@ */ import React, { useState } from "react"; -import { Form, FormGroup, Radio, Text } from "@patternfly/react-core"; +import { Content, Form, FormGroup, Radio } from "@patternfly/react-core"; import { useNavigate } from "react-router-dom"; import { ListSearch, Page } from "~/components/core"; import { _ } from "~/i18n"; @@ -59,7 +59,7 @@ export default function KeyboardSelection() { {name} {" "} - {id} + {id} } value={id} diff --git a/web/src/components/l10n/LocaleSelection.tsx b/web/src/components/l10n/LocaleSelection.tsx index ccc50b8e41..2446a52e09 100644 --- a/web/src/components/l10n/LocaleSelection.tsx +++ b/web/src/components/l10n/LocaleSelection.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2023-2024] SUSE LLC + * Copyright (c) [2023-2025] SUSE LLC * * All Rights Reserved. * @@ -57,10 +57,12 @@ export default function LocaleSelection() { {name} - + {territory} - {id} + + {id} + } value={id} diff --git a/web/src/components/l10n/TimezoneSelection.tsx b/web/src/components/l10n/TimezoneSelection.tsx index 614ba8dc5a..30136056fe 100644 --- a/web/src/components/l10n/TimezoneSelection.tsx +++ b/web/src/components/l10n/TimezoneSelection.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2023-2024] SUSE LLC + * Copyright (c) [2023-2025] SUSE LLC * * All Rights Reserved. * @@ -21,7 +21,7 @@ */ import React, { useState } from "react"; -import { Divider, Flex, Form, FormGroup, Radio, Text } from "@patternfly/react-core"; +import { Content, Divider, Flex, Form, FormGroup, Radio } from "@patternfly/react-core"; import { useNavigate } from "react-router-dom"; import { ListSearch, Page } from "~/components/core"; import { timezoneTime } from "~/utils"; @@ -93,12 +93,12 @@ export default function TimezoneSelection() { {parts.join("-")} {" "} - {country} + {country} } description={ - {timezoneTime(id, date) || ""} + {timezoneTime(id, date) || ""}
{details}
diff --git a/web/src/components/layout/Center.tsx b/web/src/components/layout/Center.tsx deleted file mode 100644 index 48c4a53512..0000000000 --- a/web/src/components/layout/Center.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) [2022-2024] 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"; - -/** - * Wrapper component for centering vertically its children - * - * @note It could be replaced by the 'vertically-centered' CSS utility class once Firefox add support - * by default for the :has selector, which allows having something like - * - * .parent:has(.vertically-centered) { - * display: grid; - * place-items: center; - * block-size: 100%; - * } - * - * .vertically-centered { inline-size: 100%; } - * - * We can use \@support CSS at rule and use a workaround when :has not available, but somehow - * prefer waiting until Firefox gets support. - * - * To know more, read - * - https://www.w3.org/TR/selectors-4/#relational - * - https://ishadeed.com/article/css-has-parent-selector/ - */ -const Center = ({ children }: React.PropsWithChildren) => ( -
-
{children}
-
-); - -export default Center; diff --git a/web/src/components/layout/Header.tsx b/web/src/components/layout/Header.tsx index e14500b450..1b65057d0f 100644 --- a/web/src/components/layout/Header.tsx +++ b/web/src/components/layout/Header.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2024] SUSE LLC + * Copyright (c) [2024-2025] SUSE LLC * * All Rights Reserved. * @@ -23,11 +23,10 @@ import React, { useState } from "react"; import { Masthead, - MastheadProps, MastheadContent, MastheadToggle, MastheadMain, - MastheadBrand, + MastheadLogo, PageToggleButton, Toolbar, ToolbarContent, @@ -39,6 +38,7 @@ import { DropdownList, DropdownItem, Divider, + Content, } from "@patternfly/react-core"; import { Icon } from "~/components/layout"; import { useProduct } from "~/queries/software"; @@ -57,8 +57,6 @@ export type HeaderProps = { showProductName?: boolean; /** Whether the installer options link should be mounted */ showInstallerOptions?: boolean; - /** The background color for the top bar */ - background?: MastheadProps["backgroundColor"]; /** Callback to be triggered for toggling the IssuesDrawer visibility */ toggleIssuesDrawer?: () => void; }; @@ -124,7 +122,6 @@ const OptionsDropdown = ({ showInstallerOptions }) => { export default function Header({ showSidebarToggle = true, showProductName = true, - background = "dark", toggleIssuesDrawer, }: HeaderProps): React.ReactNode { const location = useLocation(); @@ -141,24 +138,30 @@ export default function Header({ !["/login", "/products/progress"].includes(location.pathname); return ( - - {showSidebarToggle && ( - - - - - - )} - {title && {title}} + + + {showSidebarToggle && ( + + + + + + )} + {title && ( + + {title} + + )} + - - + + diff --git a/web/src/components/layout/Layout.tsx b/web/src/components/layout/Layout.tsx index b80f62a316..9f1aa3a4f8 100644 --- a/web/src/components/layout/Layout.tsx +++ b/web/src/components/layout/Layout.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2024] SUSE LLC + * Copyright (c) [2024-2025] SUSE LLC * * All Rights Reserved. * @@ -22,7 +22,7 @@ import React, { Suspense, useState } from "react"; import { Outlet, useLocation } from "react-router-dom"; -import { Page, PageProps } from "@patternfly/react-core"; +import { Masthead, Page, PageProps } from "@patternfly/react-core"; import { Questions } from "~/components/questions"; import Header, { HeaderProps } from "~/components/layout/Header"; import { Loading, Sidebar } from "~/components/layout"; @@ -58,7 +58,7 @@ const Layout = ({ if (mountSidebar) pageProps.sidebar = ; if (mountHeader) { - pageProps.header = ( + pageProps.masthead = (
; pageProps.isNotificationDrawerExpanded = issuesDrawerVisible; + } else { + // FIXME: render an empty Masthead instead of nothing, in order to have + // everything working as designed by PatternfFly (there are some CSS rules + // that expect the masthead to be there :shrug:) + pageProps.masthead = ; } return ( <> - + }>{children || } {location.pathname !== ROOT.login && } @@ -88,7 +93,6 @@ const fullProps: LayoutProps = { headerOptions: { showProductName: true, showInstallerOptions: true, - background: "dark", }, }; @@ -105,7 +109,6 @@ const plainProps: LayoutProps = { headerOptions: { showProductName: false, showInstallerOptions: true, - background: "light200", }, }; diff --git a/web/src/components/layout/Loading.tsx b/web/src/components/layout/Loading.tsx index 7147518404..1577b8f012 100644 --- a/web/src/components/layout/Loading.tsx +++ b/web/src/components/layout/Loading.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -21,8 +21,8 @@ */ import React from "react"; -import { EmptyState, EmptyStateIcon, EmptyStateHeader, Spinner } from "@patternfly/react-core"; -import { Center, PlainLayout } from "~/components/layout"; +import { Bullseye, EmptyState, Spinner } from "@patternfly/react-core"; +import { PlainLayout } from "~/components/layout"; import { LayoutProps } from "~/components/layout/Layout"; import { _ } from "~/i18n"; @@ -38,15 +38,9 @@ function Loading({ const Wrapper = useLayout ? Layout : React.Fragment; return ( -
- - } - /> - -
+ + +
); } diff --git a/web/src/components/layout/index.ts b/web/src/components/layout/index.ts index 0bea58236e..ddb595427c 100644 --- a/web/src/components/layout/index.ts +++ b/web/src/components/layout/index.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -21,7 +21,6 @@ */ export { default as Icon } from "./Icon"; -export { default as Center } from "./Center"; export { default as Loading } from "./Loading"; export { default as Sidebar } from "./Sidebar"; export { default as Header } from "./Header"; diff --git a/web/src/components/network/ConnectionsTable.test.tsx b/web/src/components/network/ConnectionsTable.test.tsx index 779e76932f..025405ead6 100644 --- a/web/src/components/network/ConnectionsTable.test.tsx +++ b/web/src/components/network/ConnectionsTable.test.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2023-2024] SUSE LLC + * Copyright (c) [2023-2025] SUSE LLC * * All Rights Reserved. * @@ -102,9 +102,8 @@ describe("ConnectionsTable", () => { const connectionActions = screen.getByRole("button", { name: "Actions for connection enp1s0", }); - const actionsColumn = connectionActions.parentNode as HTMLElement; await user.click(connectionActions); - const menu = await within(actionsColumn).findByRole("menu"); + const menu = screen.getByRole("menu"); const editAction = within(menu).getByRole("menuitem", { name: "Edit connection enp1s0" }); await user.click(editAction); expect(mockNavigateFn).toHaveBeenCalled(); @@ -122,9 +121,8 @@ describe("ConnectionsTable", () => { const connectionActions = screen.getByRole("button", { name: "Actions for connection enp1s0", }); - const actionsColumn = connectionActions.parentNode as HTMLElement; await user.click(connectionActions); - const menu = await within(actionsColumn).findByRole("menu"); + const menu = screen.getByRole("menu"); const forgetAction = within(menu).getByRole("menuitem", { name: "Forget connection enp1s0", }); diff --git a/web/src/components/network/WifiConnectionForm.test.tsx b/web/src/components/network/WifiConnectionForm.test.tsx index 2656796f35..c7ce53ff98 100644 --- a/web/src/components/network/WifiConnectionForm.test.tsx +++ b/web/src/components/network/WifiConnectionForm.test.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2022-2024] SUSE LLC + * Copyright (c) [2022-2025] SUSE LLC * * All Rights Reserved. * @@ -126,16 +126,16 @@ describe("WifiConnectionForm", () => { it("disables cancel and submission actions", async () => { const { user } = renderForm(networkMock); - const connectButton = screen.getByText("Connect"); - const cancelLink = screen.getByText("Cancel"); + const connectButton = screen.getByRole("button", { name: "Connect" }); + const cancelButton = screen.getByRole("button", { name: "Cancel" }); expect(connectButton).not.toBeDisabled(); - expect(cancelLink).not.toBeDisabled(); + expect(cancelButton).not.toBeDisabled(); await waitFor(() => { user.click(connectButton); expect(connectButton).toBeDisabled(); - expect(cancelLink).toBeDisabled(); + expect(cancelButton).toBeDisabled(); }); }); diff --git a/web/src/components/network/WifiNetworksListPage.tsx b/web/src/components/network/WifiNetworksListPage.tsx index 36c230355c..b816384f32 100644 --- a/web/src/components/network/WifiNetworksListPage.tsx +++ b/web/src/components/network/WifiNetworksListPage.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) [2024] SUSE LLC + * Copyright (c) [2024-2025] SUSE LLC * * All Rights Reserved. * @@ -176,7 +176,7 @@ const NetworkListName = ({ network, ...props }) => { {network.ssid} {network.settings && ( -