diff --git a/src/actions/storage-actions.js b/src/actions/storage-actions.js index 0fe525b227..fb5f18acb2 100644 --- a/src/actions/storage-actions.js +++ b/src/actions/storage-actions.js @@ -60,7 +60,10 @@ export const getDevicesAction = () => { return dispatch({ type: "GET_DEVICES_DATA", - payload: { devices: devicesData.reduce((acc, curr) => ({ ...acc, ...curr }), {}) } + payload: { + deviceNames: devices, + devices: devicesData.reduce((acc, curr) => ({ ...acc, ...curr }), {}), + } }); } catch (error) { return dispatch(setCriticalErrorAction(error)); diff --git a/src/components/AnacondaWizard.jsx b/src/components/AnacondaWizard.jsx index d6abeec7ec..a8720c037a 100644 --- a/src/components/AnacondaWizard.jsx +++ b/src/components/AnacondaWizard.jsx @@ -42,9 +42,6 @@ import { Accounts, getPageProps as getAccountsProps, getAccountsState, applyAcco import { InstallationProgress } from "./installation/InstallationProgress.jsx"; import { ReviewConfiguration, ReviewConfigurationConfirmModal, getPageProps as getReviewConfigurationProps } from "./review/ReviewConfiguration.jsx"; import { exitGui } from "../helpers/exit.js"; -import { - getMountPointConstraints, -} from "../apis/storage_devicetree.js"; import { applyStorage, resetPartitioning, @@ -57,7 +54,6 @@ const N_ = cockpit.noop; export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtimeData, onCritFail, title, conf }) => { const [isFormDisabled, setIsFormDisabled] = useState(false); const [isFormValid, setIsFormValid] = useState(false); - const [mountPointConstraints, setMountPointConstraints] = useState(); const [reusePartitioning, setReusePartitioning] = useState(false); const [stepNotification, setStepNotification] = useState(); const [storageEncryption, setStorageEncryption] = useState(getStorageEncryptionState()); @@ -67,19 +63,12 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim const [currentStepId, setCurrentStepId] = useState(); const osRelease = useContext(OsReleaseContext); const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO"; + const selectedDisks = storageData.diskSelection.selectedDisks; const availableDevices = useMemo(() => { return Object.keys(storageData.devices); }, [storageData.devices]); - useEffect(() => { - const updateMountPointConstraints = async () => { - const mountPointConstraints = await getMountPointConstraints().catch(console.error); - setMountPointConstraints(mountPointConstraints); - }; - updateMountPointConstraints(); - }, []); - useEffect(() => { if (!currentStepId) { return; @@ -94,7 +83,7 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim * but for custom mount assignment we try to reuse the partitioning when possible. */ setReusePartitioning(false); - }, [availableDevices, storageData.diskSelection.selectedDisks]); + }, [availableDevices, selectedDisks]); const language = useMemo(() => { for (const l of Object.keys(localizationData.languages)) { @@ -115,6 +104,7 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim component: InstallationMethod, data: { deviceData: storageData.devices, + deviceNames: storageData.deviceNames, diskSelection: storageData.diskSelection, dispatch, storageScenarioId, @@ -135,7 +125,6 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim diskSelection: storageData.diskSelection, dispatch, partitioningData: storageData.partitioning, - mountPointConstraints, reusePartitioning, setReusePartitioning, }, @@ -273,14 +262,18 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim ); } - const firstVisibleStepIndex = steps.findIndex(step => !step.props.isHidden) + 1; + const startIndex = steps.findIndex(step => { + // Find the first step that is not hidden if the Wizard is opening for the first time. + // Otherwise, find the first step that was last visited. + return currentStepId ? step.props.id === currentStepId : !step.props.isHidden; + }) + 1; return ( . + */ +import { useEffect, useState } from "react"; + +import { + getDiskFreeSpace, + getDiskTotalSpace, + getMountPointConstraints, + getRequiredDeviceSize, +} from "../../apis/storage_devicetree.js"; +import { + getRequiredSpace +} from "../../apis/payloads.js"; +import { findDuplicatesInArray } from "../../helpers/utils.js"; + +export const useDiskTotalSpace = ({ selectedDisks, devices }) => { + const [diskTotalSpace, setDiskTotalSpace] = useState(); + + useEffect(() => { + const update = async () => { + const diskTotalSpace = await getDiskTotalSpace({ diskNames: selectedDisks }); + + setDiskTotalSpace(diskTotalSpace); + }; + update(); + }, [selectedDisks, devices]); + + return diskTotalSpace; +}; + +export const useDiskFreeSpace = ({ selectedDisks, devices }) => { + const [diskFreeSpace, setDiskFreeSpace] = useState(); + + useEffect(() => { + const update = async () => { + const diskFreeSpace = await getDiskFreeSpace({ diskNames: selectedDisks }); + + setDiskFreeSpace(diskFreeSpace); + }; + update(); + }, [selectedDisks, devices]); + + return diskFreeSpace; +}; + +export const useDuplicateDeviceNames = ({ deviceNames }) => { + const [duplicateDeviceNames, setDuplicateDeviceNames] = useState([]); + + useEffect(() => { + const update = async () => { + const _duplicateDeviceNames = findDuplicatesInArray(deviceNames); + + setDuplicateDeviceNames(_duplicateDeviceNames); + }; + update(); + }, [deviceNames]); + + return duplicateDeviceNames; +}; + +export const useHasFilesystems = ({ selectedDisks, devices }) => { + const [hasFilesystems, setHasFilesystems] = useState(); + + useEffect(() => { + const _hasFilesystems = ( + selectedDisks.some(device => ( + devices[device]?.children.v.some(child => ( + devices[child]?.formatData.mountable.v || devices[child]?.formatData.type.v === "luks") + ) + )) + ); + + setHasFilesystems(_hasFilesystems); + }, [selectedDisks, devices]); + + return hasFilesystems; +}; + +export const useRequiredSize = () => { + const [requiredSize, setRequiredSize] = useState(); + + useEffect(() => { + const update = async () => { + const requiredSpace = await getRequiredSpace().catch(console.error); + const requiredSize = await getRequiredDeviceSize({ requiredSpace }).catch(console.error); + + setRequiredSize(requiredSize); + }; + update(); + }, []); + + return requiredSize; +}; + +export const useMountPointConstraints = () => { + const [mountPointConstraints, setMountPointConstraints] = useState(); + + useEffect(() => { + const update = async () => { + const mountPointConstraints = await getMountPointConstraints().catch(console.error); + setMountPointConstraints(mountPointConstraints); + }; + update(); + }, []); + + return mountPointConstraints; +}; diff --git a/src/components/storage/InstallationMethod.jsx b/src/components/storage/InstallationMethod.jsx index 756f81345c..3beb992737 100644 --- a/src/components/storage/InstallationMethod.jsx +++ b/src/components/storage/InstallationMethod.jsx @@ -30,6 +30,7 @@ const _ = cockpit.gettext; export const InstallationMethod = ({ deviceData, + deviceNames, diskSelection, dispatch, idPrefix, @@ -58,6 +59,7 @@ export const InstallationMethod = ({ />