From 35b78c43c093cd2f1609cbd6e88e8be6c4c40212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Thu, 21 Nov 2024 10:28:08 +0000 Subject: [PATCH 01/12] feature(web): Add IssuesDrawer components --- web/src/assets/styles/app.scss | 14 ++ web/src/components/core/IssuesDrawer.test.tsx | 130 ++++++++++++++++++ web/src/components/core/IssuesDrawer.tsx | 104 ++++++++++++++ .../core/IssuesDrawerToggle.test.tsx | 115 ++++++++++++++++ .../components/core/IssuesDrawerToggle.tsx | 66 +++++++++ web/src/components/core/index.js | 2 + 6 files changed, 431 insertions(+) create mode 100644 web/src/components/core/IssuesDrawer.test.tsx create mode 100644 web/src/components/core/IssuesDrawer.tsx create mode 100644 web/src/components/core/IssuesDrawerToggle.test.tsx create mode 100644 web/src/components/core/IssuesDrawerToggle.tsx diff --git a/web/src/assets/styles/app.scss b/web/src/assets/styles/app.scss index 04d35448a9..5b8625edef 100644 --- a/web/src/assets/styles/app.scss +++ b/web/src/assets/styles/app.scss @@ -66,3 +66,17 @@ button.remove-link:hover { } } } + +.agama-issues-drawer-body { + padding: var(--pf-v5-global--spacer--lg); + + h4 a { + text-decoration: underline; + font-weight: var(--fw-bold); + } + + ul li.pf-m-info, + ul li.pf-m-warning { + --pf-v5-c-notification-drawer__list-item--before--BackgroundColor: none; + } +} diff --git a/web/src/components/core/IssuesDrawer.test.tsx b/web/src/components/core/IssuesDrawer.test.tsx new file mode 100644 index 0000000000..ea720364cf --- /dev/null +++ b/web/src/components/core/IssuesDrawer.test.tsx @@ -0,0 +1,130 @@ +/* + * Copyright (c) [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"; +import { screen, within } from "@testing-library/react"; +import { installerRender } from "~/test-utils"; +import { InstallationPhase } from "~/types/status"; +import { IssuesList } from "~/types/issues"; +import IssuesDrawer from "./IssuesDrawer"; + +let phase = InstallationPhase.Config; +let mockIssuesList: IssuesList; +const onCloseFn = jest.fn(); + +jest.mock("~/queries/issues", () => ({ + ...jest.requireActual("~/queries/issues"), + useAllIssues: () => mockIssuesList, +})); + +jest.mock("~/queries/status", () => ({ + useInstallerStatus: () => ({ + phase, + }), +})); + +const itRendersNothing = () => + it("renders nothing", () => { + const { container } = installerRender(); + expect(container).toBeEmptyDOMElement(); + }); + +describe("IssuesDrawer", () => { + describe("when there are no installation issues", () => { + beforeEach(() => { + mockIssuesList = new IssuesList([], [], [], []); + }); + + itRendersNothing(); + }); + + describe("when there are installation issues", () => { + beforeEach(() => { + mockIssuesList = new IssuesList( + [], + [ + { + description: "Software Fake Issue", + source: 0, + severity: 0, + details: "Software Fake Issue details", + }, + ], + [ + { + description: "Storage Fake Issue 1", + source: 0, + severity: 0, + details: "Storage Fake Issue 1 details", + }, + { + description: "Storage Fake Issue 2", + source: 0, + severity: 0, + details: "Storage Fake Issue 2 details", + }, + ], + [ + { + description: "Users Fake Issue", + source: 0, + severity: 0, + details: "Users Fake Issue details", + }, + ], + ); + }); + + it("renders the drawer with categorized issues linking to their scope", async () => { + const { user } = installerRender(); + + const softwareIssues = screen.getByRole("region", { name: "Software" }); + const storageIssues = screen.getByRole("region", { name: "Storage" }); + const usersIssues = screen.getByRole("region", { name: "Users" }); + + const softwareLink = within(softwareIssues).getByRole("link", { name: "Software" }); + expect(softwareLink).toHaveAttribute("href", "/software"); + within(softwareIssues).getByText("Software Fake Issue"); + + const storageLink = within(storageIssues).getByRole("link", { name: "Storage" }); + expect(storageLink).toHaveAttribute("href", "/storage"); + within(storageIssues).getByText("Storage Fake Issue 1"); + within(storageIssues).getByText("Storage Fake Issue 2"); + + const usersLink = within(usersIssues).getByRole("link", { name: "Users" }); + expect(usersLink).toHaveAttribute("href", "/users"); + within(usersIssues).getByText("Users Fake Issue"); + + const closeButton = screen.getByRole("button", { name: "Close" }); + await user.click(closeButton); + expect(onCloseFn).toHaveBeenCalled(); + }); + + describe("at install phase", () => { + beforeEach(() => { + phase = InstallationPhase.Install; + }); + + itRendersNothing(); + }); + }); +}); diff --git a/web/src/components/core/IssuesDrawer.tsx b/web/src/components/core/IssuesDrawer.tsx new file mode 100644 index 0000000000..5a751b101e --- /dev/null +++ b/web/src/components/core/IssuesDrawer.tsx @@ -0,0 +1,104 @@ +/* + * Copyright (c) [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, { forwardRef } from "react"; +import { + HelperText, + HelperTextItem, + NotificationDrawer, + NotificationDrawerBody, + NotificationDrawerHeader, + Stack, +} from "@patternfly/react-core"; +import Link from "~/components/core/Link"; +import { useAllIssues } from "~/queries/issues"; +import { useInstallerStatus } from "~/queries/status"; +import { IssueSeverity } from "~/types/issues"; +import { InstallationPhase } from "~/types/status"; +import { _ } from "~/i18n"; + +/** + * Drawer for displaying installation issues + */ +const IssuesDrawer = forwardRef(({ onClose }: { onClose: () => void }, ref) => { + const issues = useAllIssues(); + const { phase } = useInstallerStatus({ suspense: true }); + const { issues: issuesByScope } = issues; + + // FIXME: share below headers with navigation menu + const scopeHeaders = { + users: _("Users"), + storage: _("Storage"), + software: _("Software"), + }; + + if (issues.isEmpty || phase === InstallationPhase.Install) return; + + return ( + + + + +

+ {_( + "Current installation settings does not meet the necessary requirements for installing the selected product. Click on each section name to access the relevant page and adjust the settings as needed.", + )} +

+ {Object.entries(issuesByScope).map(([scope, issues], idx) => { + if (issues.length === 0) return null; + const ariaLabelId = `${scope}-issues-section`; + + return ( +
+ +

+ + {scopeHeaders[scope]} + +

+
    + {issues.map((issue, subIdx) => { + const variant = issue.severity === IssueSeverity.Error ? "warning" : "info"; + + return ( +
  • + + {/** @ts-expect-error TS complain about variant, let's fix it after PF6 migration */} + + {issue.description} + + +
  • + ); + })} +
+
+
+ ); + })} +
+
+
+ ); +}); + +export default IssuesDrawer; diff --git a/web/src/components/core/IssuesDrawerToggle.test.tsx b/web/src/components/core/IssuesDrawerToggle.test.tsx new file mode 100644 index 0000000000..c89eb774f2 --- /dev/null +++ b/web/src/components/core/IssuesDrawerToggle.test.tsx @@ -0,0 +1,115 @@ +/* + * Copyright (c) [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"; +import { screen } from "@testing-library/react"; +import { installerRender, mockRoutes } from "~/test-utils"; +import IssuesDrawerToggle from "./IssuesDrawerToggle"; +import { InstallationPhase } from "~/types/status"; +import { IssuesList } from "~/types/issues"; + +let phase = InstallationPhase.Config; +let mockIssuesList: IssuesList; +const onClickFn = jest.fn(); + +jest.mock("~/queries/issues", () => ({ + ...jest.requireActual("~/queries/issues"), + useAllIssues: () => mockIssuesList, +})); + +jest.mock("~/queries/status", () => ({ + useInstallerStatus: () => ({ + phase, + }), +})); + +const itRendersNothing = () => + it("renders nothing", () => { + const { container } = installerRender( + , + ); + expect(container).toBeEmptyDOMElement(); + }); + +describe("IssuesDrawerToggle", () => { + describe("when there are no installation issues", () => { + beforeEach(() => { + mockIssuesList = new IssuesList([], [], [], []); + }); + + itRendersNothing(); + }); + + describe("when there are installation issues", () => { + beforeEach(() => { + mockIssuesList = new IssuesList( + [ + { + description: "Fake Issue", + source: 0, + severity: 0, + details: "Fake Issue details", + }, + ], + [], + [], + [], + ); + }); + + it("renders the toggle using given props", async () => { + const { user } = installerRender( + , + ); + const toggle = screen.getByRole("button", { name: "The issues drawer toggle" }); + expect(toggle).toHaveAttribute("aria-expanded", "true"); + await user.click(toggle); + expect(onClickFn).toHaveBeenCalled(); + }); + + describe("at install phase", () => { + beforeEach(() => { + phase = InstallationPhase.Install; + }); + + itRendersNothing(); + }); + + describe("at config phase and /products/progress path", () => { + beforeEach(() => { + phase = InstallationPhase.Config; + mockRoutes("/products/progress"); + }); + + itRendersNothing(); + }); + + describe("at config phase and /login path", () => { + beforeEach(() => { + phase = InstallationPhase.Config; + mockRoutes("/login"); + }); + + itRendersNothing(); + }); + }); +}); diff --git a/web/src/components/core/IssuesDrawerToggle.tsx b/web/src/components/core/IssuesDrawerToggle.tsx new file mode 100644 index 0000000000..c696e00def --- /dev/null +++ b/web/src/components/core/IssuesDrawerToggle.tsx @@ -0,0 +1,66 @@ +/* + * Copyright (c) [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"; +import { NotificationBadge, NotificationBadgeProps } from "@patternfly/react-core"; +import { useLocation } from "react-router-dom"; +import { Icon } from "~/components/layout"; +import { useAllIssues } from "~/queries/issues"; +import { useInstallerStatus } from "~/queries/status"; +import { PRODUCT, ROOT } from "~/routes/paths"; +import { InstallationPhase } from "~/types/status"; +import { _ } from "~/i18n"; + +export type IssuesDrawerToggleProps = { + label?: string; + onClick: () => void; + isExpanded: NotificationBadgeProps["isExpanded"]; +}; + +/** + * Returns a toggle intended for changing the visibility of IssuesDrawer + */ +const IssuesDrawerToggle = ({ + label = _("Show preflight checks"), + isExpanded, + onClick, +}: IssuesDrawerToggleProps) => { + const location = useLocation(); + const issues = useAllIssues(); + const { phase } = useInstallerStatus({ suspense: true }); + + if (issues.isEmpty) return; + if (phase === InstallationPhase.Install) return; + if ([PRODUCT.changeProduct, PRODUCT.progress, ROOT.login].includes(location.pathname)) return; + + return ( + } + variant="attention" + isExpanded={isExpanded} + onClick={onClick} + /> + ); +}; + +export default IssuesDrawerToggle; diff --git a/web/src/components/core/index.js b/web/src/components/core/index.js index 781be69513..6d84390349 100644 --- a/web/src/components/core/index.js +++ b/web/src/components/core/index.js @@ -52,4 +52,6 @@ export { default as TreeTable } from "./TreeTable"; export { default as Link } from "./Link"; export { default as EmptyState } from "./EmptyState"; export { default as InstallerOptions } from "./InstallerOptions"; +export { default as IssuesDrawer } from "./IssuesDrawer"; +export { default as IssuesDrawerToggle } from "./IssuesDrawerToggle"; export { default as Drawer } from "./Drawer"; From 37088aff2be2720a26d021388d6b9b838f49d5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Thu, 21 Nov 2024 11:42:40 +0000 Subject: [PATCH 02/12] feature(web) Allow Install button be always visible But disabled when the installation is not possible because of settings issues. --- .../components/core/InstallButton.test.tsx | 9 ++--- web/src/components/core/InstallButton.tsx | 36 +++++++++++++------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/web/src/components/core/InstallButton.test.tsx b/web/src/components/core/InstallButton.test.tsx index 965660de11..6b10f4cabb 100644 --- a/web/src/components/core/InstallButton.test.tsx +++ b/web/src/components/core/InstallButton.test.tsx @@ -67,9 +67,10 @@ describe("InstallButton", () => { ); }); - it("renders nothing", () => { - const { container } = installerRender(); - expect(container).toBeEmptyDOMElement(); + it("renders a disabled Install button", () => { + installerRender(); + const button = screen.getByRole("button", { name: "Install" }); + expect(button).toHaveAttribute("aria-disabled", "true"); }); }); @@ -78,7 +79,7 @@ describe("InstallButton", () => { mockIssuesList = new IssuesList([], [], [], []); }); - it("renders an Install button", () => { + it("renders an enabled Install button", () => { installerRender(); screen.getByRole("button", { name: "Install" }); }); diff --git a/web/src/components/core/InstallButton.tsx b/web/src/components/core/InstallButton.tsx index 5d483d0360..46a5f561b0 100644 --- a/web/src/components/core/InstallButton.tsx +++ b/web/src/components/core/InstallButton.tsx @@ -21,15 +21,13 @@ */ import React, { useState } from "react"; - -import { Button, ButtonProps, Stack } from "@patternfly/react-core"; - +import { Button, ButtonProps, Stack, Tooltip } from "@patternfly/react-core"; import { Popup } from "~/components/core"; -import { _ } from "~/i18n"; import { startInstallation } from "~/api/manager"; import { useAllIssues } from "~/queries/issues"; import { useLocation } from "react-router-dom"; import { PRODUCT, ROOT } from "~/routes/paths"; +import { _ } from "~/i18n"; /** * List of paths where the InstallButton must not be shown. @@ -72,6 +70,18 @@ according to the provided installation settings.", ); }; +/** Internal component for rendering the disabled Install button */ +const DisabledButton = (props: ButtonProps) => ( + + - + {isEnabled ? + {isOpen && } ); diff --git a/web/src/components/core/IssuesDrawerToggle.test.tsx b/web/src/components/core/IssuesDrawerToggle.test.tsx deleted file mode 100644 index c89eb774f2..0000000000 --- a/web/src/components/core/IssuesDrawerToggle.test.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) [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"; -import { screen } from "@testing-library/react"; -import { installerRender, mockRoutes } from "~/test-utils"; -import IssuesDrawerToggle from "./IssuesDrawerToggle"; -import { InstallationPhase } from "~/types/status"; -import { IssuesList } from "~/types/issues"; - -let phase = InstallationPhase.Config; -let mockIssuesList: IssuesList; -const onClickFn = jest.fn(); - -jest.mock("~/queries/issues", () => ({ - ...jest.requireActual("~/queries/issues"), - useAllIssues: () => mockIssuesList, -})); - -jest.mock("~/queries/status", () => ({ - useInstallerStatus: () => ({ - phase, - }), -})); - -const itRendersNothing = () => - it("renders nothing", () => { - const { container } = installerRender( - , - ); - expect(container).toBeEmptyDOMElement(); - }); - -describe("IssuesDrawerToggle", () => { - describe("when there are no installation issues", () => { - beforeEach(() => { - mockIssuesList = new IssuesList([], [], [], []); - }); - - itRendersNothing(); - }); - - describe("when there are installation issues", () => { - beforeEach(() => { - mockIssuesList = new IssuesList( - [ - { - description: "Fake Issue", - source: 0, - severity: 0, - details: "Fake Issue details", - }, - ], - [], - [], - [], - ); - }); - - it("renders the toggle using given props", async () => { - const { user } = installerRender( - , - ); - const toggle = screen.getByRole("button", { name: "The issues drawer toggle" }); - expect(toggle).toHaveAttribute("aria-expanded", "true"); - await user.click(toggle); - expect(onClickFn).toHaveBeenCalled(); - }); - - describe("at install phase", () => { - beforeEach(() => { - phase = InstallationPhase.Install; - }); - - itRendersNothing(); - }); - - describe("at config phase and /products/progress path", () => { - beforeEach(() => { - phase = InstallationPhase.Config; - mockRoutes("/products/progress"); - }); - - itRendersNothing(); - }); - - describe("at config phase and /login path", () => { - beforeEach(() => { - phase = InstallationPhase.Config; - mockRoutes("/login"); - }); - - itRendersNothing(); - }); - }); -}); diff --git a/web/src/components/core/IssuesDrawerToggle.tsx b/web/src/components/core/IssuesDrawerToggle.tsx deleted file mode 100644 index c696e00def..0000000000 --- a/web/src/components/core/IssuesDrawerToggle.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) [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"; -import { NotificationBadge, NotificationBadgeProps } from "@patternfly/react-core"; -import { useLocation } from "react-router-dom"; -import { Icon } from "~/components/layout"; -import { useAllIssues } from "~/queries/issues"; -import { useInstallerStatus } from "~/queries/status"; -import { PRODUCT, ROOT } from "~/routes/paths"; -import { InstallationPhase } from "~/types/status"; -import { _ } from "~/i18n"; - -export type IssuesDrawerToggleProps = { - label?: string; - onClick: () => void; - isExpanded: NotificationBadgeProps["isExpanded"]; -}; - -/** - * Returns a toggle intended for changing the visibility of IssuesDrawer - */ -const IssuesDrawerToggle = ({ - label = _("Show preflight checks"), - isExpanded, - onClick, -}: IssuesDrawerToggleProps) => { - const location = useLocation(); - const issues = useAllIssues(); - const { phase } = useInstallerStatus({ suspense: true }); - - if (issues.isEmpty) return; - if (phase === InstallationPhase.Install) return; - if ([PRODUCT.changeProduct, PRODUCT.progress, ROOT.login].includes(location.pathname)) return; - - return ( - } - variant="attention" - isExpanded={isExpanded} - onClick={onClick} - /> - ); -}; - -export default IssuesDrawerToggle; diff --git a/web/src/components/core/index.js b/web/src/components/core/index.js index 73954ecda2..7ce2bff886 100644 --- a/web/src/components/core/index.js +++ b/web/src/components/core/index.js @@ -52,5 +52,4 @@ export { default as Link } from "./Link"; export { default as EmptyState } from "./EmptyState"; export { default as InstallerOptions } from "./InstallerOptions"; export { default as IssuesDrawer } from "./IssuesDrawer"; -export { default as IssuesDrawerToggle } from "./IssuesDrawerToggle"; export { default as Drawer } from "./Drawer"; diff --git a/web/src/components/layout/Header.test.tsx b/web/src/components/layout/Header.test.tsx index 986d3f7a2d..1ae19803fc 100644 --- a/web/src/components/layout/Header.test.tsx +++ b/web/src/components/layout/Header.test.tsx @@ -42,7 +42,6 @@ let phase: InstallationPhase; let isBusy: boolean; jest.mock("~/components/core/InstallerOptions", () => () =>
Installer Options Mock
); -jest.mock("~/components/core/IssuesDrawerToggle", () => () =>
Issues Drawer Mock
); jest.mock("~/components/core/InstallButton", () => () =>
Install Button Mock
); jest.mock("~/queries/software", () => ({ @@ -83,11 +82,6 @@ describe("Header", () => { expect(screen.queryByRole("heading", { name: tumbleweed.name, level: 1 })).toBeNull(); }); - it("mounts the IssuesDrawerToggle", () => { - installerRender(
); - screen.getByText("Issues Drawer Mock"); - }); - it("mounts the Install button", () => { installerRender(
); screen.getByText("Install Button Mock"); diff --git a/web/src/components/layout/Header.tsx b/web/src/components/layout/Header.tsx index 6835cc4a2a..a4cbfa9b02 100644 --- a/web/src/components/layout/Header.tsx +++ b/web/src/components/layout/Header.tsx @@ -45,8 +45,7 @@ import { useProduct } from "~/queries/software"; import { _ } from "~/i18n"; import { InstallationPhase } from "~/types/status"; import { useInstallerStatus } from "~/queries/status"; -import { InstallButton, InstallerOptions, IssuesDrawerToggle } from "~/components/core"; -import { IssuesDrawerToggleProps } from "~/components/core/IssuesDrawerToggle"; +import { InstallButton, InstallerOptions } from "~/components/core"; import { useLocation } from "react-router-dom"; import { ROOT } from "~/routes/paths"; @@ -59,10 +58,8 @@ export type HeaderProps = { showInstallerOptions?: boolean; /** The background color for the top bar */ background?: MastheadProps["backgroundColor"]; - /** Whether the issues drawer should be visible or not */ - issuesDrawerVisible?: IssuesDrawerToggleProps["isExpanded"]; - /** Callback to be triggered when the badge for issues drawer is clicked */ - onIssuesDrawerToggle?: IssuesDrawerToggleProps["onClick"]; + /** Callback to be triggered for toggling the IssuesDrawer visibility */ + toggleIssuesDrawer?: () => void; }; const OptionsDropdown = ({ showInstallerOptions }) => { @@ -125,8 +122,7 @@ export default function Header({ showSidebarToggle = true, showProductName = true, background = "dark", - issuesDrawerVisible, - onIssuesDrawerToggle, + toggleIssuesDrawer, }: HeaderProps): React.ReactNode { const location = useLocation(); const { selectedProduct } = useProduct(); @@ -157,14 +153,8 @@ export default function Header({ - - - - - + + diff --git a/web/src/components/layout/Icon.tsx b/web/src/components/layout/Icon.tsx index 6612381b44..cbdc3ce110 100644 --- a/web/src/components/layout/Icon.tsx +++ b/web/src/components/layout/Icon.tsx @@ -38,6 +38,7 @@ import Downloading from "@icons/downloading.svg?component"; import Edit from "@icons/edit.svg?component"; import EditSquare from "@icons/edit_square.svg?component"; import Error from "@icons/error.svg?component"; +import Exclamation from "@icons/exclamation.svg?component"; import ExpandAll from "@icons/expand_all.svg?component"; import ExpandCircleDown from "@icons/expand_circle_down.svg?component"; import Feedback from "@icons/feedback.svg?component"; @@ -102,6 +103,7 @@ const icons = { edit: Edit, edit_square: EditSquare, error: Error, + exclamation: Exclamation, expand_all: ExpandAll, expand_circle_down: ExpandCircleDown, feedback: Feedback, diff --git a/web/src/components/layout/Layout.tsx b/web/src/components/layout/Layout.tsx index 9991206c70..a90f83cb1c 100644 --- a/web/src/components/layout/Layout.tsx +++ b/web/src/components/layout/Layout.tsx @@ -56,8 +56,7 @@ const Layout = ({ mountHeader && (
) From fdb90d3612995ef6758d46117be712c72f6963a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Mon, 25 Nov 2024 12:00:26 +0000 Subject: [PATCH 11/12] doc(web): update changelog --- web/package/agama-web-ui.changes | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/package/agama-web-ui.changes b/web/package/agama-web-ui.changes index edcc822ca3..1e57305925 100644 --- a/web/package/agama-web-ui.changes +++ b/web/package/agama-web-ui.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Mon Nov 25 11:12:36 UTC 2024 - David Diaz + +- Unify Install and "warning" header buttons. +- Move installation issues to a drawer shown when Install button + is clicked (gh#agama-project#agama#1778). + ------------------------------------------------------------------- Fri Nov 15 08:26:29 UTC 2024 - David Diaz From 0b1e0db41905c9954e30b1ad3c9e431219529a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz?= <1691872+dgdavid@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:08:46 +0000 Subject: [PATCH 12/12] Apply wording suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Imobach González Sosa --- web/src/assets/styles/patternfly-overrides.scss | 2 +- web/src/components/core/InstallButton.test.tsx | 4 ++-- web/src/components/core/InstallButton.tsx | 2 +- web/src/components/core/IssuesDrawer.tsx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/src/assets/styles/patternfly-overrides.scss b/web/src/assets/styles/patternfly-overrides.scss index c68798010d..6cafb3e554 100644 --- a/web/src/assets/styles/patternfly-overrides.scss +++ b/web/src/assets/styles/patternfly-overrides.scss @@ -349,7 +349,7 @@ } // A temporary workaround to fix "stacking contexts" problems with scroll and -// sticky page sections in Agama layout. It will not needed when migrating to +// sticky page sections in Agama layout. It will not be needed when migrating to // latest PF6 release, since the root of the problem has been addressed there by // removing the DrawerContentBody from the Page component. See // https://github.com/patternfly/patternfly/pull/7130 and related links diff --git a/web/src/components/core/InstallButton.test.tsx b/web/src/components/core/InstallButton.test.tsx index 05258cbe5f..452b58f5e9 100644 --- a/web/src/components/core/InstallButton.test.tsx +++ b/web/src/components/core/InstallButton.test.tsx @@ -74,7 +74,7 @@ describe("InstallButton", () => { const icon = container.querySelector("svg"); expect(icon).toHaveAttribute("data-icon-name", "exclamation"); // An aria-label for users using an screen reader - within(button).getByLabelText(/Not possible with current setup/); + within(button).getByLabelText(/Not possible with the current setup/); }); it("triggers the onClickWithIssues callback without rendering the confirmation dialog", async () => { @@ -98,7 +98,7 @@ describe("InstallButton", () => { // Renders nothing else const icon = container.querySelector("svg"); expect(icon).toBeNull(); - expect(within(button).queryByLabelText(/Not possible with current setup/)).toBeNull(); + expect(within(button).queryByLabelText(/Not possible with the current setup/)).toBeNull(); }); it("renders a confirmation dialog when clicked without triggering the onClickWithIssues callback", async () => { diff --git a/web/src/components/core/InstallButton.tsx b/web/src/components/core/InstallButton.tsx index 9271a4cb28..7978a63c13 100644 --- a/web/src/components/core/InstallButton.tsx +++ b/web/src/components/core/InstallButton.tsx @@ -101,7 +101,7 @@ const InstallButton = ( // TRANSLATORS: The install button label const buttonText = _("Install"); // TRANSLATORS: Accessible text included with the install button when there are issues - const withIssuesAriaLabel = _("Not possible with current setup. Click to know more."); + const withIssuesAriaLabel = _("Not possible with the current setup. Click to know more."); return ( <> diff --git a/web/src/components/core/IssuesDrawer.tsx b/web/src/components/core/IssuesDrawer.tsx index 5a751b101e..94e94c923b 100644 --- a/web/src/components/core/IssuesDrawer.tsx +++ b/web/src/components/core/IssuesDrawer.tsx @@ -60,7 +60,7 @@ const IssuesDrawer = forwardRef(({ onClose }: { onClose: () => void }, ref) => {

{_( - "Current installation settings does not meet the necessary requirements for installing the selected product. Click on each section name to access the relevant page and adjust the settings as needed.", + "Current settings do not meet the requirements for installing the product. You can click on each section's name to access the relevant page and adjust the settings as needed.", )}

{Object.entries(issuesByScope).map(([scope, issues], idx) => {