Skip to content

Commit

Permalink
Merge pull request #146 from KKoukiou/storage-pre-cockpit-cleanup
Browse files Browse the repository at this point in the history
Prepare for the blivet-gui / cockpit-storage migration
  • Loading branch information
KKoukiou committed Jan 30, 2024
2 parents a63ed8b + fc1fd21 commit a0aa36b
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 77 deletions.
5 changes: 4 additions & 1 deletion src/actions/storage-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
25 changes: 9 additions & 16 deletions src/components/AnacondaWizard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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());
Expand All @@ -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;
Expand All @@ -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)) {
Expand All @@ -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,
Expand All @@ -135,7 +125,6 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim
diskSelection: storageData.diskSelection,
dispatch,
partitioningData: storageData.partitioning,
mountPointConstraints,
reusePartitioning,
setReusePartitioning,
},
Expand Down Expand Up @@ -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 (
<PageSection type={PageSectionTypes.wizard} variant={PageSectionVariants.light}>
<Wizard
id="installation-wizard"
isVisitRequired
startIndex={firstVisibleStepIndex}
startIndex={startIndex}
footer={<Footer
onCritFail={onCritFail}
isFormValid={isFormValid}
Expand Down
121 changes: 121 additions & 0 deletions src/components/storage/Common.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (C) 2024 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with This program; If not, see <http://www.gnu.org/licenses/>.
*/
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;
};
2 changes: 2 additions & 0 deletions src/components/storage/InstallationMethod.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const _ = cockpit.gettext;

export const InstallationMethod = ({
deviceData,
deviceNames,
diskSelection,
dispatch,
idPrefix,
Expand Down Expand Up @@ -58,6 +59,7 @@ export const InstallationMethod = ({
/>
<InstallationScenario
deviceData={deviceData}
deviceNames={deviceNames}
diskSelection={diskSelection}
dispatch={dispatch}
idPrefix={idPrefix}
Expand Down
76 changes: 19 additions & 57 deletions src/components/storage/InstallationScenario.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,15 @@ import {

import { SystemTypeContext } from "../Common.jsx";
import { helpEraseAll, helpUseFreeSpace, helpMountPointMapping } from "./HelpAutopartOptions.jsx";
import { findDuplicatesInArray } from "../../helpers/utils.js";

import {
getDevices,
getRequiredDeviceSize,
getDiskTotalSpace,
getDiskFreeSpace,
} from "../../apis/storage_devicetree.js";
import { useDiskTotalSpace, useDiskFreeSpace, useDuplicateDeviceNames, useHasFilesystems, useRequiredSize } from "./Common.jsx";
import {
setInitializationMode,
} from "../../apis/storage_disk_initialization.js";

import {
getRequiredSpace,
} from "../../apis/payloads";

import "./InstallationScenario.scss";

const _ = cockpit.gettext;
const N_ = cockpit.noop;

function AvailabilityState (available = false, hidden = false, reason = null, hint = null) {
this.available = available;
Expand Down Expand Up @@ -162,54 +151,26 @@ export const getDefaultScenario = () => {
return scenarios.filter(s => s.default)[0];
};

const InstallationScenarioSelector = ({ deviceData, selectedDisks, idPrefix, isFormDisabled, onCritFail, storageScenarioId, setStorageScenarioId, setIsFormValid }) => {
const InstallationScenarioSelector = ({
deviceData,
deviceNames,
idPrefix,
isFormDisabled,
onCritFail,
selectedDisks,
setIsFormValid,
setStorageScenarioId,
storageScenarioId,
}) => {
const [selectedScenario, setSelectedScenario] = useState();
const [scenarioAvailability, setScenarioAvailability] = useState(Object.fromEntries(
scenarios.map((s) => [s.id, new AvailabilityState()])
));
const [requiredSize, setRequiredSize] = useState();
const [diskTotalSpace, setDiskTotalSpace] = useState();
const [diskFreeSpace, setDiskFreeSpace] = useState();
const [hasFilesystems, setHasFilesystems] = useState();
const [duplicateDeviceNames, setDuplicateDeviceNames] = useState([]);

useEffect(() => {
getDevices().then(res => {
const _duplicateDeviceNames = findDuplicatesInArray(res);
setDuplicateDeviceNames(_duplicateDeviceNames);
setIsFormValid(_duplicateDeviceNames.length === 0);
}, onCritFail({ context: N_("Failed to get device names.") }));
}, [deviceData, onCritFail, setIsFormValid]);

useEffect(() => {
const updateSizes = async () => {
const diskTotalSpace = await getDiskTotalSpace({ diskNames: selectedDisks }).catch(console.error);
const diskFreeSpace = await getDiskFreeSpace({ diskNames: selectedDisks }).catch(console.error);
const devices = await getDevices().catch(console.error);
const _duplicateDeviceNames = findDuplicatesInArray(devices);

setDuplicateDeviceNames(_duplicateDeviceNames);
setDiskTotalSpace(diskTotalSpace);
setDiskFreeSpace(diskFreeSpace);
};
updateSizes();
}, [selectedDisks]);

useEffect(() => {
const updateRequiredSize = async () => {
const requiredSpace = await getRequiredSpace().catch(console.error);
const requiredSize = await getRequiredDeviceSize({ requiredSpace }).catch(console.error);

setRequiredSize(requiredSize);
};
updateRequiredSize();
}, []);

useEffect(() => {
const hasFilesystems = selectedDisks.some(device => deviceData[device]?.children.v.some(child => deviceData[child]?.formatData.mountable.v || deviceData[child]?.formatData.type.v === "luks"));

setHasFilesystems(hasFilesystems);
}, [selectedDisks, deviceData]);
const diskTotalSpace = useDiskTotalSpace({ selectedDisks, devices: deviceData });
const diskFreeSpace = useDiskFreeSpace({ selectedDisks, devices: deviceData });
const duplicateDeviceNames = useDuplicateDeviceNames({ deviceNames });
const hasFilesystems = useHasFilesystems({ selectedDisks, devices: deviceData });
const requiredSize = useRequiredSize();

useEffect(() => {
let selectedScenarioId = "";
Expand Down Expand Up @@ -283,7 +244,7 @@ const InstallationScenarioSelector = ({ deviceData, selectedDisks, idPrefix, isF
return scenarioItems;
};

export const InstallationScenario = ({ deviceData, diskSelection, idPrefix, isFormDisabled, onCritFail, setIsFormValid, storageScenarioId, setStorageScenarioId }) => {
export const InstallationScenario = ({ deviceData, deviceNames, diskSelection, idPrefix, isFormDisabled, onCritFail, setIsFormValid, storageScenarioId, setStorageScenarioId }) => {
const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO";
const headingLevel = isBootIso ? "h2" : "h3";

Expand All @@ -293,6 +254,7 @@ export const InstallationScenario = ({ deviceData, diskSelection, idPrefix, isFo
<FormGroup isStack hasNoPaddingTop>
<InstallationScenarioSelector
deviceData={deviceData}
deviceNames={deviceNames}
selectedDisks={diskSelection.selectedDisks}
idPrefix={idPrefix}
onCritFail={onCritFail}
Expand Down
5 changes: 3 additions & 2 deletions src/components/storage/MountPointMapping.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { ListingTable } from "cockpit-components-table.jsx";
import { EmptyStatePanel } from "cockpit-components-empty-state.jsx";

import { EncryptedDevices } from "./EncryptedDevices.jsx";
import { useMountPointConstraints } from "./Common.jsx";

import {
setBootloaderDrive,
Expand Down Expand Up @@ -611,13 +612,13 @@ export const MountPointMapping = ({
dispatch,
idPrefix,
partitioningData,
mountPointConstraints,
reusePartitioning,
setIsFormValid,
setReusePartitioning,
setStepNotification,
}) => {
const [usedPartitioning, setUsedPartitioning] = useState(partitioningData?.path);
const mountPointConstraints = useMountPointConstraints();
const [skipUnlock, setSkipUnlock] = useState(false);
const lockedLUKSDevices = useMemo(
() => getLockedLUKSDevices(partitioningData?.requests, deviceData),
Expand Down Expand Up @@ -657,7 +658,7 @@ export const MountPointMapping = ({
/>
)}
{!showLuksUnlock && (
(isLoadingNewPartitioning || mountPointConstraints === null || !partitioningData?.requests)
(isLoadingNewPartitioning || mountPointConstraints === undefined || !partitioningData?.requests)
? (
<EmptyStatePanel loading />
)
Expand Down
3 changes: 2 additions & 1 deletion src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { useReducer, useCallback } from "react";
/* Initial state for the storeage store substate */
export const storageInitialState = {
devices: {},
deviceNames: [],
diskSelection: {
usableDisks: [],
selectedDisks: [],
Expand Down Expand Up @@ -90,7 +91,7 @@ export const reducer = (state, action) => {

export const storageReducer = (state = storageInitialState, action) => {
if (action.type === "GET_DEVICES_DATA") {
return { ...state, devices: action.payload.devices };
return { ...state, devices: action.payload.devices, deviceNames: action.payload.deviceNames };
} else if (action.type === "GET_DISK_SELECTION") {
return { ...state, diskSelection: action.payload.diskSelection };
} else if (action.type === "GET_PARTITIONING_DATA") {
Expand Down

0 comments on commit a0aa36b

Please sign in to comment.