Skip to content

Commit

Permalink
Port deprecated Wizard component to new PF5 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkankovsky committed Dec 12, 2023
1 parent ce590d8 commit 9af1c46
Showing 1 changed file with 113 additions and 113 deletions.
226 changes: 113 additions & 113 deletions src/components/AnacondaWizard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ import {
PageSection,
PageSectionTypes,
PageSectionVariants,
Stack
} from "@patternfly/react-core";
import {
Stack,
useWizardContext,
Wizard,
WizardFooter,
WizardContextConsumer
} from "@patternfly/react-core/deprecated";
WizardFooterWrapper,
WizardStep
} from "@patternfly/react-core";

import { AnacondaPage } from "./AnacondaPage.jsx";
import { InstallationMethod, getPageProps as getInstallationMethodProps } from "./storage/InstallationMethod.jsx";
Expand All @@ -43,7 +42,6 @@ import { Accounts, getPageProps as getAccountsProps, getAccountsState, accountsT
import { InstallationProgress } from "./installation/InstallationProgress.jsx";
import { ReviewConfiguration, ReviewConfigurationConfirmModal, getPageProps as getReviewConfigurationProps } from "./review/ReviewConfiguration.jsx";
import { exitGui } from "../helpers/exit.js";
import { usePageLocation } from "hooks";
import {
getRequiredMountPoints,
} from "../apis/storage_devicetree.js";
Expand All @@ -69,6 +67,7 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim
const [storageScenarioId, setStorageScenarioId] = useState(window.sessionStorage.getItem("storage-scenario-id") || getDefaultScenario().id);
const [accounts, setAccounts] = useState(getAccountsState());
const [showWizard, setShowWizard] = useState(true);
const [currentStepId, setCurrentStepId] = useState();
const osRelease = useContext(OsReleaseContext);
const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO";

Expand All @@ -85,6 +84,13 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim
updateRequiredMountPoints();
}, []);

useEffect(() => {
if (!currentStepId) {
return;
}
cockpit.location.go([currentStepId]);
}, [currentStepId]);

useEffect(() => {
/*
* When disk selection changes or the user re-scans the devices we need to re-create the partitioning.
Expand Down Expand Up @@ -172,90 +178,94 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim
},
];

const componentProps = {
isFormDisabled,
onCritFail,
setIsFormDisabled,
setIsFormValid,
};

const getFlattenedStepsIds = (steps) => {
const stepIds = [];
for (const step of steps) {
stepIds.push(step.id);
if (step.steps) {
for (const childStep of step.steps) {
if (childStep?.isHidden !== true) {
stepIds.push(childStep.id);
}
}
} else {
stepIds.push(step.id);
}
}
return stepIds;
};
const flattenedStepsIds = getFlattenedStepsIds(stepsOrder);

const { path } = usePageLocation();
const firstStepId = stepsOrder.filter(step => !step.isHidden)[0].id;
const currentStepId = path[0] || firstStepId;

const isStepFollowedBy = (earlierStepId, laterStepId) => {
const earlierStepIdx = flattenedStepsIds.findIndex(s => s === earlierStepId);
const laterStepIdx = flattenedStepsIds.findIndex(s => s === laterStepId);
return earlierStepIdx < laterStepIdx;
};

const canJumpToStep = (stepId, currentStepId) => {
return stepId === currentStepId || isStepFollowedBy(stepId, currentStepId);
};

const createSteps = (stepsOrder) => {
const steps = stepsOrder.filter(s => !s.isHidden).map(s => {
let step = ({
const createSteps = (stepsOrder, componentProps) => {
return stepsOrder.map(s => {
const isVisited = firstStepId === s.id || currentStepId === s.id;
let stepProps = {
id: s.id,
isHidden: s.isHidden,
isVisited,
name: s.label,
stepNavItemProps: { id: s.id },
canJumpTo: canJumpToStep(s.id, currentStepId),
});
...(s.steps?.length && { isExpandable: true }),
};
if (s.component) {
step = ({
...step,
component: (
stepProps = {
children: (
<AnacondaPage step={s.id} title={s.title} stepNotification={stepNotification}>
<s.component
idPrefix={s.id}
setIsFormValid={setIsFormValid}
onCritFail={onCritFail}
setStepNotification={ex => setStepNotification({ step: s.id, ...ex })}
isFormDisabled={isFormDisabled}
setIsFormDisabled={setIsFormDisabled}
{...componentProps}
{...s.data}
/>
</AnacondaPage>
),
});
...stepProps
};
} else if (s.steps) {
step.steps = createSteps(s.steps);
const subSteps = createSteps(s.steps, componentProps);
stepProps = {
...stepProps,
steps: [...subSteps]
};
}
return step;
return (
<WizardStep key={s.id + s.isVisited} {...stepProps} />
);
});
return steps;
};
const steps = createSteps(stepsOrder);
const steps = createSteps(stepsOrder, componentProps);

const goToStep = (newStep, prevStep) => {
if (prevStep.prevId !== newStep.id) {
if (prevStep.id !== newStep.id) {
// first reset validation state to default
setIsFormValid(false);
}

// Reset the applied partitioning when going back from a step after creating partitioning to a step
// before creating partitioning.
if ((prevStep.prevId === "accounts" || isStepFollowedBy("accounts", prevStep.prevId)) &&
if ((prevStep.id === "accounts" || isStepFollowedBy("accounts", prevStep.id)) &&
isStepFollowedBy(newStep.id, "accounts")) {
setIsFormDisabled(true);
resetPartitioning()
.then(
() => cockpit.location.go([newStep.id]),
() => setCurrentStepId(newStep.id),
() => onCritFail({ context: cockpit.format(N_("Error was hit when going back from $0."), prevStep.prevName) })
)
.always(() => setIsFormDisabled(false));
} else {
cockpit.location.go([newStep.id]);
setCurrentStepId(newStep.id);
}
};

Expand All @@ -267,10 +277,14 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim
);
}

const firstVisibleStepIndex = steps.findIndex(step => !step.props.isHidden) + 1;

return (
<PageSection type={PageSectionTypes.wizard} variant={PageSectionVariants.light}>
<Wizard
id="installation-wizard"
isVisitRequired
startIndex={firstVisibleStepIndex}
footer={<Footer
onCritFail={onCritFail}
isFormValid={isFormValid}
Expand All @@ -285,15 +299,10 @@ export const AnacondaWizard = ({ dispatch, storageData, localizationData, runtim
storageScenarioId={storageScenarioId}
accounts={accounts}
/>}
hideClose
mainAriaLabel={`${title} content`}
navAriaLabel={`${title} steps`}
onBack={goToStep}
onGoToStep={goToStep}
onNext={goToStep}
steps={steps}
isNavExpandable
/>
onStepChange={((event, currentStep, prevStep) => goToStep(currentStep, prevStep))}
>
{steps}
</Wizard>
</PageSection>
);
};
Expand All @@ -314,6 +323,7 @@ const Footer = ({
}) => {
const [nextWaitsConfirmation, setNextWaitsConfirmation] = useState(false);
const [quitWaitsConfirmation, setQuitWaitsConfirmation] = useState(false);
const { activeStep, goToNextStep: onNext, goToPrevStep: onBack } = useWizardContext();

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable onNext.
const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO";

const goToNextStep = (activeStep, onNext) => {
Expand Down Expand Up @@ -373,78 +383,68 @@ const Footer = ({
}
};

const goToPreviousStep = (activeStep, onBack, errorHandler) => {
const goToPreviousStep = () => {
// first reset validation state to default
setIsFormValid(true);
setIsFormValid(false);
onBack();
};

const currentStep = stepsOrder.find(s => s.id === activeStep.id);
const footerHelperText = currentStep?.footerHelperText;
const isFirstScreen = stepsOrder.filter(step => !step.isHidden)[0].id === activeStep.id;
const nextButtonText = currentStep?.nextButtonText || _("Next");
const nextButtonVariant = currentStep?.nextButtonVariant || "primary";

return (
<WizardFooter>
<WizardContextConsumer>
{({ activeStep, onNext, onBack }) => {
const currentStep = stepsOrder.find(s => s.id === activeStep.id);
const footerHelperText = currentStep?.footerHelperText;
const isFirstScreen = stepsOrder.filter(step => !step.isHidden)[0].id === activeStep.id;
const nextButtonText = currentStep?.nextButtonText || _("Next");
const nextButtonVariant = currentStep?.nextButtonVariant || "primary";

return (
<Stack hasGutter>
{activeStep.id === "installation-review" &&
nextWaitsConfirmation &&
<ReviewConfigurationConfirmModal
idPrefix={activeStep.id}
onNext={() => { setShowWizard(false); cockpit.location.go(["installation-progress"]) }}
setNextWaitsConfirmation={setNextWaitsConfirmation}
storageScenarioId={storageScenarioId}
/>}
{quitWaitsConfirmation &&
<QuitInstallationConfirmModal
exitGui={exitGui}
setQuitWaitsConfirmation={setQuitWaitsConfirmation}
/>}
{footerHelperText}
<ActionList>
<Button
id="installation-back-btn"
variant="secondary"
isDisabled={isFirstScreen || isFormDisabled}
onClick={() => goToPreviousStep(
activeStep,
onBack,
onCritFail({ context: cockpit.format(N_("Error was hit when going back from $0."), activeStep.name) })
)}>
{_("Back")}
</Button>
<Button
id="installation-next-btn"
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={() => {
setQuitWaitsConfirmation(true);
}}
>
{isBootIso ? _("Reboot") : _("Quit")}
</Button>
</ActionList>
</Stack>
);
}}
</WizardContextConsumer>
</WizardFooter>
<WizardFooterWrapper>
<Stack hasGutter>
{activeStep.id === "installation-review" &&
nextWaitsConfirmation &&
<ReviewConfigurationConfirmModal
idPrefix={activeStep.id}
onNext={() => { setShowWizard(false); cockpit.location.go(["installation-progress"]) }}
setNextWaitsConfirmation={setNextWaitsConfirmation}
storageScenarioId={storageScenarioId}
/>}
{quitWaitsConfirmation &&
<QuitInstallationConfirmModal
exitGui={exitGui}
setQuitWaitsConfirmation={setQuitWaitsConfirmation}
/>}
{footerHelperText}
<ActionList>
<Button
id="installation-back-btn"
variant="secondary"
isDisabled={isFirstScreen || isFormDisabled}
onClick={() => goToPreviousStep()}>
{_("Back")}
</Button>
<Button
id="installation-next-btn"
variant={nextButtonVariant}
isDisabled={
!isFormValid ||
isFormDisabled ||
nextWaitsConfirmation
}
onClick={() => goToNextStep(activeStep, goToNextStep)}>
{nextButtonText}
</Button>
<Button
id="installation-quit-btn"
isDisabled={isFormDisabled}
style={{ marginLeft: "var(--pf-v5-c-wizard__footer-cancel--MarginLeft)" }}
variant="link"
onClick={() => {
setQuitWaitsConfirmation(true);
}}
>
{isBootIso ? _("Reboot") : _("Quit")}
</Button>
</ActionList>
</Stack>
</WizardFooterWrapper>
);
};

Expand Down

0 comments on commit 9af1c46

Please sign in to comment.