diff --git a/web/src/components/overview/StorageSection.test.tsx b/web/src/components/overview/StorageSection.test.tsx index f63f3d39fa..1ee9c1515e 100644 --- a/web/src/components/overview/StorageSection.test.tsx +++ b/web/src/components/overview/StorageSection.test.tsx @@ -25,6 +25,7 @@ import { screen } from "@testing-library/react"; import { plainRender } from "~/test-utils"; import { StorageSection } from "~/components/overview"; import * as ConfigModel from "~/api/storage/types/config-model"; +import { Issue } from "~/types/issues"; const sdaDrive: ConfigModel.Drive = { name: "/dev/sda", @@ -43,11 +44,22 @@ const mockDevices = [ { name: "/dev/sdb", size: 697932185600 }, ]; +const systemError: Issue = { + description: "System error", + kind: "storage", + details: "", + source: 1, + severity: 1, +}; + const mockUseConfigModelFn = jest.fn(); +const mockUseAvailableDevicesFn = jest.fn(); +const mockUseSystemErrorsFn = jest.fn(); jest.mock("~/queries/storage", () => ({ ...jest.requireActual("~/queries/storage"), useDevices: () => mockDevices, + useAvailableDevices: () => mockUseAvailableDevicesFn(), })); jest.mock("~/queries/storage/config-model", () => ({ @@ -55,6 +67,11 @@ jest.mock("~/queries/storage/config-model", () => ({ useConfigModel: () => mockUseConfigModelFn(), })); +jest.mock("~/queries/issues", () => ({ + ...jest.requireActual("~/queries/issues"), + useSystemErrors: () => mockUseSystemErrorsFn(), +})); + describe("when the configuration does not include any device", () => { beforeEach(() => { mockUseConfigModelFn.mockReturnValue({ drives: [] }); @@ -155,3 +172,65 @@ describe("when the configuration contains several drives", () => { }); }); }); + +describe("when there is no configuration model (unsupported features)", () => { + beforeEach(() => { + mockUseConfigModelFn.mockReturnValue(undefined); + }); + + describe("if the storage proposal succeeded", () => { + beforeEach(() => { + mockUseSystemErrorsFn.mockReturnValue([]); + }); + + describe("and there are no available disks", () => { + beforeEach(() => { + mockUseAvailableDevicesFn.mockReturnValue([]); + }); + + it("indicates that an unhandled configuration was used", async () => { + plainRender(); + await screen.findByText(/advanced configuration/); + }); + }); + + describe("and there are available disks", () => { + beforeEach(() => { + mockUseAvailableDevicesFn.mockReturnValue(mockDevices); + }); + + it("indicates that an unhandled configuration was used", async () => { + plainRender(); + await screen.findByText(/advanced configuration/); + }); + }); + }); + + describe("if the storage proposal was not possible", () => { + beforeEach(() => { + mockUseSystemErrorsFn.mockReturnValue([systemError]); + }); + + describe("and there are no available disks", () => { + beforeEach(() => { + mockUseAvailableDevicesFn.mockReturnValue([]); + }); + + it("indicates that there are no available disks", async () => { + plainRender(); + await screen.findByText(/no disks available/); + }); + }); + + describe("and there are available disks", () => { + beforeEach(() => { + mockUseAvailableDevicesFn.mockReturnValue(mockDevices); + }); + + it("indicates that an unhandled configuration was used", async () => { + plainRender(); + await screen.findByText(/advanced configuration/); + }); + }); + }); +}); diff --git a/web/src/components/overview/StorageSection.tsx b/web/src/components/overview/StorageSection.tsx index 5df7520496..b3c8eb5246 100644 --- a/web/src/components/overview/StorageSection.tsx +++ b/web/src/components/overview/StorageSection.tsx @@ -23,8 +23,9 @@ import React from "react"; import { Content } from "@patternfly/react-core"; import { deviceLabel } from "~/components/storage/utils"; -import { useDevices } from "~/queries/storage"; +import { useDevices, useAvailableDevices } from "~/queries/storage"; import { useConfigModel } from "~/queries/storage/config-model"; +import { useSystemErrors } from "~/queries/issues"; import { StorageDevice } from "~/types/storage"; import * as ConfigModel from "~/api/storage/types/config-model"; import { _ } from "~/i18n"; @@ -78,26 +79,40 @@ const MultipleDisksSummary = ({ drives }: { drives: ConfigModel.Drive[] }): stri return options[drives[0].spacePolicy]; }; +const ModelSummary = ({ model }: { model: ConfigModel.Config }): React.ReactNode => { + const devices = useDevices("system", { suspense: true }); + const drives = model?.drives || []; + const existDevice = (name: string) => devices.some((d) => d.name === name); + const noDrive = drives.length === 0 || drives.some((d) => !existDevice(d.name)); + + if (noDrive) return ; + if (drives.length > 1) return ; + return ; +}; + +const NoModelSummary = (): React.ReactNode => { + const availableDevices = useAvailableDevices(); + const systemErrors = useSystemErrors("storage"); + const hasDisks = !!availableDevices.length; + const hasResult = !systemErrors.length; + + if (!hasResult && !hasDisks) return _("There are no disks available for the installation."); + return _("Install using an advanced configuration."); +}; + /** * Text explaining the storage proposal - * - * TODO: The current implementation assumes there are only drives and no other kind of devices like - * LVM volume groups or MD raids. Support for more cases (like LVM installation) will be added as - * the rest of the interface is also adapted. */ export default function StorageSection() { const configModel = useConfigModel(); - const devices = useDevices("system", { suspense: true }); - const drives = configModel?.drives || []; - const existDevice = (name: string) => devices.some((d) => d.name === name); - const noDrive = drives.length === 0 || drives.some((d) => !existDevice(d.name)); return ( {_("Storage")} - {noDrive && } - {drives.length === 1 && } - {drives.length > 1 && } + + {configModel && } + {!configModel && } + ); }