Skip to content

Commit

Permalink
Merge pull request #5240 from KKoukiou/webui-storage-improvements-tes…
Browse files Browse the repository at this point in the history
…ts-stability

webui: storage step improvements
  • Loading branch information
KKoukiou authored Oct 10, 2023
2 parents 553cdb1 + 24ee190 commit 4c1daa8
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 68 deletions.
46 changes: 19 additions & 27 deletions ui/webui/src/actions/storage-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,36 +32,28 @@ import {
export const getDevicesAction = () => {
return async (dispatch) => {
const devices = await getDevices();
return Promise.all(devices[0].map(device => dispatch(getDeviceDataAction({ device }))));
};
};
const devicesData = await Promise.all(devices[0].map(async (device) => {
let devData = await getDeviceData({ disk: device });
devData = devData[0];

export const getDeviceDataAction = ({ device }) => {
return async (dispatch) => {
let devData = {};
const deviceData = await getDeviceData({ disk: device })
.then(res => {
devData = res[0];
return getDiskFreeSpace({ diskNames: [device] });
})
.then(free => {
// Since the getDeviceData returns an object with variants as values,
// extend it with variants to keep the format consistent
devData.free = cockpit.variant(String, free);
return getDiskTotalSpace({ diskNames: [device] });
})
.then(total => {
devData.total = cockpit.variant(String, total);
return getFormatData({ diskName: device });
})
.then(formatData => {
devData.formatData = formatData;
return ({ [device]: devData });
});
const free = await getDiskFreeSpace({ diskNames: [device] });
// extend it with variants to keep the format consistent
devData.free = cockpit.variant(String, free);

const total = await getDiskTotalSpace({ diskNames: [device] });
devData.total = cockpit.variant(String, total);

const formatData = await getFormatData({ diskName: device });
devData.formatData = formatData;

const deviceData = { [device]: devData };

return deviceData;
}));

return dispatch({
type: "GET_DEVICE_DATA",
payload: { deviceData }
type: "GET_DEVICES_DATA",
payload: { devices: devicesData.reduce((acc, curr) => ({ ...acc, ...curr }), {}) }
});
};
};
Expand Down
37 changes: 18 additions & 19 deletions ui/webui/src/components/AnacondaWizard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const N_ = cockpit.noop;
export const AnacondaWizard = ({ dispatch, isBootIso, osRelease, storageData, localizationData, onCritFail, onAddErrorNotification, title, conf }) => {
const [isFormValid, setIsFormValid] = useState(false);
const [stepNotification, setStepNotification] = useState();
const [isInProgress, setIsInProgress] = useState(false);
const [isFormDisabled, setIsFormDisabled] = useState(false);
const [storageEncryption, setStorageEncryption] = useState(getStorageEncryptionState());
const [storageScenarioId, setStorageScenarioId] = useState(window.sessionStorage.getItem("storage-scenario-id") || getDefaultScenario().id);
const [reusePartitioning, setReusePartitioning] = useState(false);
Expand Down Expand Up @@ -196,7 +196,8 @@ export const AnacondaWizard = ({ dispatch, isBootIso, osRelease, storageData, lo
onCritFail={onCritFail}
onAddErrorNotification={onAddErrorNotification}
stepNotification={stepNotification}
isInProgress={isInProgress}
isFormDisabled={isFormDisabled}
setIsFormDisabled={setIsFormDisabled}
storageEncryption={storageEncryption}
setStorageEncryption={setStorageEncryption}
storageScenarioId={storageScenarioId}
Expand Down Expand Up @@ -227,13 +228,13 @@ export const AnacondaWizard = ({ dispatch, isBootIso, osRelease, storageData, lo

// Reset the applied partitioning when going back from review page
if (prevStep.prevId === "installation-review" && newStep.id !== "installation-progress") {
setIsInProgress(true);
setIsFormDisabled(true);
resetPartitioning()
.then(
() => cockpit.location.go([newStep.id]),
() => onCritFail({ context: cockpit.format(N_("Error was hit when going back from $0."), prevStep.prevName) })
)
.always(() => setIsInProgress(false));
.always(() => setIsFormDisabled(false));
} else {
cockpit.location.go([newStep.id]);
}
Expand All @@ -249,8 +250,8 @@ export const AnacondaWizard = ({ dispatch, isBootIso, osRelease, storageData, lo
partitioning={storageData.partitioning?.path}
setIsFormValid={setIsFormValid}
setStepNotification={setStepNotification}
isInProgress={isInProgress}
setIsInProgress={setIsInProgress}
isFormDisabled={isFormDisabled}
setIsFormDisabled={setIsFormDisabled}
storageEncryption={storageEncryption}
storageScenarioId={storageScenarioId}
isBootIso={isBootIso}
Expand All @@ -273,9 +274,9 @@ const Footer = ({
isFormValid,
setIsFormValid,
setStepNotification,
isInProgress,
isFormDisabled,
partitioning,
setIsInProgress,
setIsFormDisabled,
storageEncryption,
storageScenarioId,
isBootIso
Expand All @@ -288,20 +289,20 @@ const Footer = ({
setIsFormValid(true);

if (activeStep.id === "disk-encryption") {
setIsInProgress(true);
setIsFormDisabled(true);

applyStorage({
onFail: ex => {
console.error(ex);
setIsInProgress(false);
setIsFormDisabled(false);
setStepNotification({ step: activeStep.id, ...ex });
},
onSuccess: () => {
onNext();

// Reset the state after the onNext call. Otherwise,
// React will try to render the current step again.
setIsInProgress(false);
setIsFormDisabled(false);
setStepNotification();
},
encrypt: storageEncryption.encrypt,
Expand All @@ -310,21 +311,21 @@ const Footer = ({
} else if (activeStep.id === "installation-review") {
setNextWaitsConfirmation(true);
} else if (activeStep.id === "mount-point-mapping") {
setIsInProgress(true);
setIsFormDisabled(true);

applyStorage({
partitioning,
onFail: ex => {
console.error(ex);
setIsInProgress(false);
setIsFormDisabled(false);
setStepNotification({ step: activeStep.id, ...ex });
},
onSuccess: () => {
onNext();

// Reset the state after the onNext call. Otherwise,
// React will try to render the current step again.
setIsInProgress(false);
setIsFormDisabled(false);
setStepNotification();
},
});
Expand All @@ -339,10 +340,6 @@ const Footer = ({
onBack();
};

if (isInProgress) {
return null;
}

return (
<WizardFooter>
<WizardContextConsumer>
Expand Down Expand Up @@ -398,7 +395,7 @@ const Footer = ({
<Button
id="installation-back-btn"
variant="secondary"
isDisabled={isFirstScreen}
isDisabled={isFirstScreen || isFormDisabled}
onClick={() => goToPreviousStep(
activeStep,
onBack,
Expand All @@ -411,13 +408,15 @@ const Footer = ({
variant={nextButtonVariant}
isDisabled={
!isFormValid ||
isFormDisabled ||
nextWaitsConfirmation
}
onClick={() => goToNextStep(activeStep, onNext)}>
{nextButtonText}
</Button>
<Button
id="installation-quit-btn"
isDisabled={isFormDisabled}
style={{ marginLeft: "var(--pf-v5-c-wizard__footer-cancel--MarginLeft)" }}
variant="link"
onClick={() => {
Expand Down
44 changes: 27 additions & 17 deletions ui/webui/src/components/storage/InstallationMethod.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { SyncAltIcon, TimesIcon } from "@patternfly/react-icons";

import { InstallationScenario } from "./InstallationScenario.jsx";
import { ModifyStorage } from "./ModifyStorage.jsx";
import { EmptyStatePanel } from "cockpit-components-empty-state";

import {
resetPartitioning,
Expand Down Expand Up @@ -86,7 +85,7 @@ const selectDefaultDisks = ({ ignoredDisks, selectedDisks, usableDisks }) => {
}
};

const LocalDisksSelect = ({ deviceData, diskSelection, idPrefix, isRescanningDisks, setSelectedDisks }) => {
const LocalDisksSelect = ({ deviceData, diskSelection, idPrefix, isDisabled, setSelectedDisks }) => {
const [isOpen, setIsOpen] = useState(false);
const [inputValue, setInputValue] = useState("");
const [focusedItemIndex, setFocusedItemIndex] = useState(null);
Expand Down Expand Up @@ -202,7 +201,7 @@ const LocalDisksSelect = ({ deviceData, diskSelection, idPrefix, isRescanningDis
onClick={onToggleClick}
innerRef={toggleRef}
isExpanded={isOpen}
isDisabled={diskSelectionInProgress || isRescanningDisks}
isDisabled={diskSelectionInProgress || isDisabled}
className={idPrefix}
>
<TextInputGroup isPlain>
Expand Down Expand Up @@ -283,8 +282,9 @@ const LocalDisksSelect = ({ deviceData, diskSelection, idPrefix, isRescanningDis
);
};

const rescanDisks = (setIsRescanningDisks, refUsableDisks, dispatch, errorHandler) => {
const rescanDisks = (setIsRescanningDisks, refUsableDisks, dispatch, errorHandler, setIsFormDisabled) => {
setIsRescanningDisks(true);
setIsFormDisabled(true);
refUsableDisks.current = undefined;
scanDevicesWithTask()
.then(res => {
Expand All @@ -295,11 +295,18 @@ const rescanDisks = (setIsRescanningDisks, refUsableDisks, dispatch, errorHandle
dispatch(getDevicesAction()),
dispatch(getDiskSelectionAction())
]))
.finally(() => {
setIsFormDisabled(false);
setIsRescanningDisks(false);
})
.catch(errorHandler),
onFail: errorHandler
onFail: exc => {
setIsFormDisabled(false);
setIsRescanningDisks(false);
errorHandler(exc);
}
});
})
.finally(() => setIsRescanningDisks(false));
});
};

const InstallationDestination = ({
Expand All @@ -308,7 +315,9 @@ const InstallationDestination = ({
dispatch,
idPrefix,
isBootIso,
isFormDisabled,
setIsFormValid,
setIsFormDisabled,
onRescanDisks,
onCritFail
}) => {
Expand All @@ -319,7 +328,7 @@ const InstallationDestination = ({
debug("DiskSelector: deviceData: ", JSON.stringify(Object.keys(deviceData)), ", diskSelection: ", JSON.stringify(diskSelection));

useEffect(() => {
if (isRescanningDisks) {
if (isRescanningDisks && refUsableDisks.current === undefined) {
refUsableDisks.current = diskSelection.usableDisks;
setEqualDisksNotify(true);
}
Expand Down Expand Up @@ -357,13 +366,14 @@ const InstallationDestination = ({
setIsRescanningDisks,
refUsableDisks,
dispatch,
rescanErrorHandler
rescanErrorHandler,
setIsFormDisabled,
);

const rescanDisksButton = (
<Button
aria-label={_("Re-scan")}
isDisabled={isRescanningDisks || loading}
isDisabled={isRescanningDisks || loading || isFormDisabled}
isInline
id={idPrefix + "-rescan-disks"}
variant="link"
Expand All @@ -381,11 +391,11 @@ const InstallationDestination = ({
deviceData={deviceData}
diskSelection={diskSelection}
setSelectedDisks={setSelectedDisks}
isRescanningDisks={isRescanningDisks}
isDisabled={isRescanningDisks || loading || isFormDisabled}
/>
);

const equalDisks = !refUsableDisks.current || checkIfArraysAreEqual(refUsableDisks.current, diskSelection.usableDisks);
const equalDisks = refUsableDisks.current && checkIfArraysAreEqual(refUsableDisks.current, diskSelection.usableDisks);
const headingLevel = isBootIso ? "h2" : "h3";

return (
Expand Down Expand Up @@ -435,18 +445,15 @@ export const InstallationMethod = ({
dispatch,
idPrefix,
isBootIso,
isInProgress,
isFormDisabled,
onCritFail,
osRelease,
setIsFormValid,
setIsFormDisabled,
setStorageScenarioId,
stepNotification,
storageScenarioId,
}) => {
if (isInProgress) {
return <EmptyStatePanel loading />;
}

return (
<AnacondaPage title={!isBootIso ? cockpit.format(_("Welcome. Let's install $0 now."), osRelease.REDHAT_SUPPORT_PRODUCT) : null}>
<Form
Expand All @@ -466,7 +473,9 @@ export const InstallationMethod = ({
dispatch={dispatch}
idPrefix={idPrefix}
isBootIso={isBootIso}
isFormDisabled={isFormDisabled}
setIsFormValid={setIsFormValid}
setIsFormDisabled={setIsFormDisabled}
onCritFail={onCritFail}
/>
<InstallationScenario
Expand All @@ -476,6 +485,7 @@ export const InstallationMethod = ({
idPrefix={idPrefix}
isBootIso={isBootIso}
onCritFail={onCritFail}
isFormDisabled={isFormDisabled}
setIsFormValid={setIsFormValid}
setStorageScenarioId={setStorageScenarioId}
storageScenarioId={storageScenarioId}
Expand Down
7 changes: 4 additions & 3 deletions ui/webui/src/components/storage/InstallationScenario.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export const getDefaultScenario = () => {
return scenarios.filter(s => s.default)[0];
};

const InstallationScenarioSelector = ({ deviceData, selectedDisks, idPrefix, onCritFail, storageScenarioId, setStorageScenarioId, setIsFormValid }) => {
const InstallationScenarioSelector = ({ deviceData, selectedDisks, idPrefix, isFormDisabled, onCritFail, storageScenarioId, setStorageScenarioId, setIsFormValid }) => {
const [selectedScenario, setSelectedScenario] = useState();
const [scenarioAvailability, setScenarioAvailability] = useState(Object.fromEntries(
scenarios.map((s) => [s.id, new AvailabilityState()])
Expand Down Expand Up @@ -260,7 +260,7 @@ const InstallationScenarioSelector = ({ deviceData, selectedDisks, idPrefix, onC
value={scenario.id}
name={idPrefix + "-scenario"}
label={scenario.label}
isDisabled={!scenarioAvailability[scenario.id].available}
isDisabled={!scenarioAvailability[scenario.id].available || isFormDisabled}
isChecked={storageScenarioId === scenario.id}
onChange={() => onScenarioToggled(scenario.id)}
description={scenario.detail}
Expand All @@ -278,7 +278,7 @@ const InstallationScenarioSelector = ({ deviceData, selectedDisks, idPrefix, onC
return scenarioItems;
};

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

return (
Expand All @@ -291,6 +291,7 @@ export const InstallationScenario = ({ deviceData, diskSelection, idPrefix, onCr
idPrefix={idPrefix}
onCritFail={onCritFail}
setIsFormValid={setIsFormValid}
isFormDisabled={isFormDisabled}
storageScenarioId={storageScenarioId}
setStorageScenarioId={setStorageScenarioId}
/>
Expand Down
4 changes: 2 additions & 2 deletions ui/webui/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ export const reducer = (state, action) => {
};

export const storageReducer = (state = storageInitialState, action) => {
if (action.type === "GET_DEVICE_DATA") {
return { ...state, devices: { ...state.devices, ...action.payload.deviceData } };
if (action.type === "GET_DEVICES_DATA") {
return { ...state, devices: action.payload.devices };
} 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 4c1daa8

Please sign in to comment.