From 1dae78751b4f186dd1e9c1171a3b70bb4109f05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 10 Jan 2025 12:17:56 +0000 Subject: [PATCH 1/4] fix(web): warn the user when using the new storage settings --- web/src/api/storage/proposal.ts | 7 ++++-- .../components/overview/StorageSection.tsx | 8 ++++++- web/src/components/storage/BootSelection.tsx | 10 ++++---- .../components/storage/DeviceSelection.tsx | 14 ++++++----- web/src/components/storage/ProposalPage.tsx | 24 +++++++++++++++++-- web/src/queries/storage.ts | 2 ++ 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/web/src/api/storage/proposal.ts b/web/src/api/storage/proposal.ts index 3a5335beb6..59b2b94182 100644 --- a/web/src/api/storage/proposal.ts +++ b/web/src/api/storage/proposal.ts @@ -38,9 +38,12 @@ const fetchDefaultVolume = (mountPath: string): Promise => { return get(`/api/storage/product/volume_for?mount_path=${path}`); }; -const fetchSettings = (): Promise => get("/api/storage/proposal/settings"); +// NOTE: the settings might not exist. +const fetchSettings = (): Promise => + get("/api/storage/proposal/settings").catch(() => null); -const fetchActions = (): Promise => get("/api/storage/proposal/actions"); +// NOTE: the actions might not exist. +const fetchActions = (): Promise => get("/api/storage/proposal/actions").catch(() => []); const calculate = (settings: ProposalSettingsPatch) => put("/api/storage/proposal/settings", settings); diff --git a/web/src/components/overview/StorageSection.tsx b/web/src/components/overview/StorageSection.tsx index 3e514a03ba..5c4621604b 100644 --- a/web/src/components/overview/StorageSection.tsx +++ b/web/src/components/overview/StorageSection.tsx @@ -115,7 +115,13 @@ export default function StorageSection() { const availableDevices = useAvailableDevices(); const result = useProposalResult(); - if (result === undefined) return; + if (result === undefined) { + return ( + + {_("Install using an advanced method.")} + + ); + } const label = (deviceName) => { const device = availableDevices.find((d) => d.name === deviceName); diff --git a/web/src/components/storage/BootSelection.tsx b/web/src/components/storage/BootSelection.tsx index 27fc49fa29..9a1bcc71e8 100644 --- a/web/src/components/storage/BootSelection.tsx +++ b/web/src/components/storage/BootSelection.tsx @@ -53,16 +53,16 @@ export default function BootSelectionDialog() { }; const [state, setState] = useState({ load: false }); - const { settings } = useProposalResult(); + const proposal = useProposalResult(); const availableDevices = useAvailableDevices(); const updateProposal = useProposalMutation(); const navigate = useNavigate(); useEffect(() => { - if (state.load) return; + if (state.load || !proposal.settings) return; let selectedOption: string; - const { bootDevice, configureBoot, defaultBootDevice } = settings; + const { bootDevice, configureBoot, defaultBootDevice } = proposal.settings; if (!configureBoot) { selectedOption = BOOT_DISABLED_ID; @@ -82,7 +82,7 @@ export default function BootSelectionDialog() { availableDevices, selectedOption, }); - }, [availableDevices, settings, state.load]); + }, [availableDevices, proposal, state.load]); if (!state.load) return; @@ -97,7 +97,7 @@ export default function BootSelectionDialog() { bootDevice: state.selectedOption === BOOT_MANUAL_ID ? state.bootDevice.name : undefined, }; - await updateProposal.mutateAsync({ ...settings, ...newSettings }); + await updateProposal.mutateAsync({ ...proposal.settings, ...newSettings }); navigate(".."); }; diff --git a/web/src/components/storage/DeviceSelection.tsx b/web/src/components/storage/DeviceSelection.tsx index 434880e177..5fc87aae9e 100644 --- a/web/src/components/storage/DeviceSelection.tsx +++ b/web/src/components/storage/DeviceSelection.tsx @@ -49,7 +49,7 @@ type DeviceSelectionState = { * @component */ export default function DeviceSelection() { - const { settings } = useProposalResult(); + const proposal = useProposalResult(); const availableDevices = useAvailableDevices(); const updateProposal = useProposalMutation(); const navigate = useNavigate(); @@ -63,11 +63,13 @@ export default function DeviceSelection() { // FIXME: move to a state/reducer setState({ - target: settings.target, - targetDevice: availableDevices.find((d) => d.name === settings.targetDevice), - targetPVDevices: availableDevices.filter((d) => settings.targetPVDevices?.includes(d.name)), + target: proposal.settings.target, + targetDevice: availableDevices.find((d) => d.name === proposal.settings.targetDevice), + targetPVDevices: availableDevices.filter((d) => + proposal.settings.targetPVDevices?.includes(d.name), + ), }); - }, [settings, availableDevices, state.target]); + }, [proposal, availableDevices, state.target]); const selectTargetDisk = () => setState({ ...state, target: ProposalTarget.DISK }); const selectTargetNewLvmVG = () => setState({ ...state, target: ProposalTarget.NEW_LVM_VG }); @@ -86,7 +88,7 @@ export default function DeviceSelection() { targetPVDevices: isTargetNewLvmVg ? state.targetPVDevices.map((d) => d.name) : [], }; - updateProposal.mutateAsync({ ...settings, ...newSettings }); + updateProposal.mutateAsync({ ...proposal.settings, ...newSettings }); navigate(".."); }; diff --git a/web/src/components/storage/ProposalPage.tsx b/web/src/components/storage/ProposalPage.tsx index 0972c721e8..245e38952a 100644 --- a/web/src/components/storage/ProposalPage.tsx +++ b/web/src/components/storage/ProposalPage.tsx @@ -22,7 +22,7 @@ import React, { useRef } from "react"; import { Grid, GridItem, Stack } from "@patternfly/react-core"; -import { Page, Drawer } from "~/components/core/"; +import { Page, Drawer, EmptyState } from "~/components/core/"; import ProposalTransactionalInfo from "./ProposalTransactionalInfo"; import ProposalSettingsSection from "./ProposalSettingsSection"; import ProposalResultSection from "./ProposalResultSection"; @@ -46,6 +46,22 @@ import { import { useQueryClient } from "@tanstack/react-query"; import { refresh } from "~/api/storage"; +const StorageWarning = () => ( + + +

{_("Storage")}

+
+ + + +
+); + /** * Which UI item is being changed by user */ @@ -78,7 +94,7 @@ export default function ProposalPage() { const volumeDevices = useVolumeDevices(); const volumeTemplates = useVolumeTemplates(); const { encryptionMethods } = useProductParams({ suspense: true }); - const { actions, settings } = useProposalResult(); + const proposal = useProposalResult(); const updateProposal = useProposalMutation(); const deprecated = useDeprecated(); const queryClient = useQueryClient(); @@ -95,6 +111,10 @@ export default function ProposalPage() { .filter((s) => s.severity === IssueSeverity.Error) .map(toValidationError); + if (proposal === undefined) return ; + + const { settings, actions } = proposal; + const changeSettings = async (changing, updated: object) => { const newSettings = { ...settings, ...updated }; updateProposal.mutateAsync(newSettings).catch(console.error); diff --git a/web/src/queries/storage.ts b/web/src/queries/storage.ts index d70e6b053b..d80e3079b6 100644 --- a/web/src/queries/storage.ts +++ b/web/src/queries/storage.ts @@ -269,6 +269,8 @@ const useProposalResult = (): ProposalResult | undefined => { const systemDevices = useDevices("system", { suspense: true }); const { mountPoints: productMountPoints } = useProductParams({ suspense: true }); + if (settings === null) return undefined; + return { settings: { ...settings, From 7c4454a11da169f86e40a48021cdb89e4ff4c4d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 10 Jan 2025 12:56:37 +0000 Subject: [PATCH 2/4] fix(web): better wording in storage warning --- web/src/components/overview/StorageSection.tsx | 2 +- web/src/components/storage/ProposalPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/overview/StorageSection.tsx b/web/src/components/overview/StorageSection.tsx index 5c4621604b..a4f4526963 100644 --- a/web/src/components/overview/StorageSection.tsx +++ b/web/src/components/overview/StorageSection.tsx @@ -118,7 +118,7 @@ export default function StorageSection() { if (result === undefined) { return ( - {_("Install using an advanced method.")} + {_("Install using an advanced configuration.")} ); } diff --git a/web/src/components/storage/ProposalPage.tsx b/web/src/components/storage/ProposalPage.tsx index 245e38952a..245b16b064 100644 --- a/web/src/components/storage/ProposalPage.tsx +++ b/web/src/components/storage/ProposalPage.tsx @@ -54,7 +54,7 @@ const StorageWarning = () => ( From 4806ad087e6435d74f959e9f2f18bb8df08f6eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 10 Jan 2025 12:57:06 +0000 Subject: [PATCH 3/4] chore(web): add a unit test for the storage warning --- .../overview/StorageSection.test.tsx | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/web/src/components/overview/StorageSection.test.tsx b/web/src/components/overview/StorageSection.test.tsx index 742ed461c5..75484333c3 100644 --- a/web/src/components/overview/StorageSection.test.tsx +++ b/web/src/components/overview/StorageSection.test.tsx @@ -31,15 +31,30 @@ const mockAvailableDevices = [ ]; const mockResultSettings = { target: "disk", targetDevice: "/dev/sda", spacePolicy: "delete" }; +let mockProposalResult; jest.mock("~/queries/storage", () => ({ ...jest.requireActual("~/queries/storage"), useAvailableDevices: () => mockAvailableDevices, - useProposalResult: () => ({ + useProposalResult: () => mockProposalResult, +})); + +beforeEach(() => { + mockProposalResult = { settings: mockResultSettings, actions: [], - }), -})); + }; +}); + +describe("when using the new storage settings", () => { + beforeEach(() => (mockProposalResult = undefined)); + + it("renders a warning message", () => { + plainRender(); + + expect(screen.getByText("Install using an advanced configuration.")).toBeInTheDocument(); + }); +}); describe("when there is a proposal", () => { beforeEach(() => { From d17bae883bd4688b9e7777f9b1145e92d9d67610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Fri, 10 Jan 2025 13:22:52 +0000 Subject: [PATCH 4/4] doc(web): update the changes file --- web/package/agama-web-ui.changes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/package/agama-web-ui.changes b/web/package/agama-web-ui.changes index f330f2b9e1..cf4e2281be 100644 --- a/web/package/agama-web-ui.changes +++ b/web/package/agama-web-ui.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Jan 10 13:22:27 UTC 2025 - Imobach Gonzalez Sosa + +- Do not allow changing the storage setup when Agama is using the + new storage settings (gh#agama-project/agama#1881). + ------------------------------------------------------------------- Wed Jan 8 16:07:13 UTC 2025 - Imobach Gonzalez Sosa