A setState action was occuring in during render in the customStatusNavItem component of the CreateImageWizard. We just needed to wrap this setState call in a useEffect hook. I also renamed the component to CustomStatusNavItem for React component naming conventions. See: https://reactjs.org/link/setstate-in-render
718 lines
24 KiB
TypeScript
718 lines
24 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
|
|
import {
|
|
Button,
|
|
Wizard,
|
|
WizardFooterWrapper,
|
|
WizardNavItem,
|
|
WizardStep,
|
|
useWizardContext,
|
|
PageSection,
|
|
PageSectionTypes,
|
|
Flex,
|
|
} from '@patternfly/react-core';
|
|
import { WizardStepType } from '@patternfly/react-core/dist/esm/components/Wizard';
|
|
import useChrome from '@redhat-cloud-services/frontend-components/useChrome';
|
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
|
|
|
import DetailsStep from './steps/Details';
|
|
import FileSystemStep from './steps/FileSystem';
|
|
import { FileSystemContext } from './steps/FileSystem/FileSystemTable';
|
|
import FirewallStep from './steps/Firewall';
|
|
import FirstBootStep from './steps/FirstBoot';
|
|
import HostnameStep from './steps/Hostname';
|
|
import ImageOutputStep from './steps/ImageOutput';
|
|
import KernelStep from './steps/Kernel';
|
|
import LocaleStep from './steps/Locale';
|
|
import OscapStep from './steps/Oscap';
|
|
import PackagesStep from './steps/Packages';
|
|
import RegistrationStep from './steps/Registration';
|
|
import RepositoriesStep from './steps/Repositories';
|
|
import ReviewStep from './steps/Review';
|
|
import ReviewWizardFooter from './steps/Review/Footer/Footer';
|
|
import ServicesStep from './steps/Services';
|
|
import SnapshotStep from './steps/Snapshot';
|
|
import Aws from './steps/TargetEnvironment/Aws';
|
|
import Azure from './steps/TargetEnvironment/Azure';
|
|
import Gcp from './steps/TargetEnvironment/Gcp';
|
|
import TimezoneStep from './steps/Timezone';
|
|
import UsersStep from './steps/Users';
|
|
import { getHostArch, getHostDistro } from './utilities/getHostInfo';
|
|
import {
|
|
useFilesystemValidation,
|
|
useSnapshotValidation,
|
|
useFirstBootValidation,
|
|
useDetailsValidation,
|
|
useRegistrationValidation,
|
|
useHostnameValidation,
|
|
useKernelValidation,
|
|
useUsersValidation,
|
|
useTimezoneValidation,
|
|
useFirewallValidation,
|
|
useServicesValidation,
|
|
useLocaleValidation,
|
|
} from './utilities/useValidation';
|
|
import {
|
|
isAwsAccountIdValid,
|
|
isAzureTenantGUIDValid,
|
|
isAzureSubscriptionIdValid,
|
|
isAzureResourceGroupValid,
|
|
isGcpEmailValid,
|
|
} from './validators';
|
|
|
|
import {
|
|
RHEL_8,
|
|
RHEL_10_BETA,
|
|
RHEL_10,
|
|
AARCH64,
|
|
CENTOS_9,
|
|
AMPLITUDE_MODULE_NAME,
|
|
RHEL_9,
|
|
} from '../../constants';
|
|
import { useAppDispatch, useAppSelector } from '../../store/hooks';
|
|
import './CreateImageWizard.scss';
|
|
import {
|
|
changeDistribution,
|
|
changeArchitecture,
|
|
initializeWizard,
|
|
selectAwsAccountId,
|
|
selectAwsShareMethod,
|
|
selectAwsSourceId,
|
|
selectAzureResourceGroup,
|
|
selectAzureShareMethod,
|
|
selectAzureSource,
|
|
selectAzureSubscriptionId,
|
|
selectAzureTenantId,
|
|
selectDistribution,
|
|
selectGcpEmail,
|
|
selectGcpShareMethod,
|
|
selectImageTypes,
|
|
addImageType,
|
|
changeRegistrationType,
|
|
} from '../../store/wizardSlice';
|
|
import isRhel from '../../Utilities/isRhel';
|
|
import { resolveRelPath } from '../../Utilities/path';
|
|
import { useFlag, useGetEnvironment } from '../../Utilities/useGetEnvironment';
|
|
import { ImageBuilderHeader } from '../sharedComponents/ImageBuilderHeader';
|
|
|
|
type CustomWizardFooterPropType = {
|
|
disableBack?: boolean;
|
|
disableNext: boolean;
|
|
beforeNext?: () => boolean;
|
|
optional?: boolean;
|
|
};
|
|
|
|
export const CustomWizardFooter = ({
|
|
disableBack: disableBack,
|
|
disableNext: disableNext,
|
|
beforeNext,
|
|
optional: optional,
|
|
}: CustomWizardFooterPropType) => {
|
|
const { goToNextStep, goToPrevStep, goToStepById, close, activeStep } =
|
|
useWizardContext();
|
|
const { analytics } = useChrome();
|
|
const nextBtnID = 'wizard-next-btn';
|
|
const backBtnID = 'wizard-back-btn';
|
|
const reviewAndFinishBtnID = 'wizard-review-and-finish-btn';
|
|
const cancelBtnID = 'wizard-cancel-btn';
|
|
return (
|
|
<WizardFooterWrapper>
|
|
<Flex columnGap={{ default: 'columnGapSm' }}>
|
|
<Button
|
|
variant="primary"
|
|
onClick={() => {
|
|
if (!process.env.IS_ON_PREMISE) {
|
|
analytics.track(`${AMPLITUDE_MODULE_NAME} - Button Clicked`, {
|
|
module: AMPLITUDE_MODULE_NAME,
|
|
button_id: nextBtnID,
|
|
active_step_id: activeStep.id,
|
|
});
|
|
}
|
|
if (!beforeNext || beforeNext()) goToNextStep();
|
|
}}
|
|
isDisabled={disableNext}
|
|
>
|
|
Next
|
|
</Button>
|
|
<Button
|
|
variant="secondary"
|
|
onClick={() => {
|
|
if (!process.env.IS_ON_PREMISE) {
|
|
analytics.track(`${AMPLITUDE_MODULE_NAME} - Button Clicked`, {
|
|
module: AMPLITUDE_MODULE_NAME,
|
|
button_id: backBtnID,
|
|
active_step_id: activeStep.id,
|
|
});
|
|
}
|
|
goToPrevStep();
|
|
}}
|
|
isDisabled={disableBack || false}
|
|
>
|
|
Back
|
|
</Button>
|
|
{optional && (
|
|
<Button
|
|
variant="tertiary"
|
|
onClick={() => {
|
|
if (!process.env.IS_ON_PREMISE) {
|
|
analytics.track(`${AMPLITUDE_MODULE_NAME} - Button Clicked`, {
|
|
module: AMPLITUDE_MODULE_NAME,
|
|
button_id: reviewAndFinishBtnID,
|
|
active_step_id: activeStep.id,
|
|
});
|
|
}
|
|
if (!beforeNext || beforeNext()) goToStepById('step-review');
|
|
}}
|
|
isDisabled={disableNext}
|
|
>
|
|
Review and finish
|
|
</Button>
|
|
)}
|
|
<Button
|
|
variant="link"
|
|
onClick={() => {
|
|
if (!process.env.IS_ON_PREMISE) {
|
|
analytics.track(`${AMPLITUDE_MODULE_NAME} - Button Clicked`, {
|
|
module: AMPLITUDE_MODULE_NAME,
|
|
button_id: cancelBtnID,
|
|
active_step_id: activeStep.id,
|
|
});
|
|
}
|
|
close();
|
|
}}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
</Flex>
|
|
</WizardFooterWrapper>
|
|
);
|
|
};
|
|
|
|
type CreateImageWizardProps = {
|
|
isEdit?: boolean;
|
|
};
|
|
|
|
const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
|
|
const { analytics, isBeta } = useChrome();
|
|
const navigate = useNavigate();
|
|
const dispatch = useAppDispatch();
|
|
const [searchParams] = useSearchParams();
|
|
const { isFedoraEnv } = useGetEnvironment();
|
|
// Feature flags
|
|
const complianceEnabled = useFlag('image-builder.compliance.enabled');
|
|
|
|
// IMPORTANT: Ensure the wizard starts with a fresh initial state
|
|
useEffect(() => {
|
|
dispatch(initializeWizard());
|
|
if (isFedoraEnv) {
|
|
dispatch(changeDistribution(CENTOS_9));
|
|
dispatch(changeRegistrationType('register-later'));
|
|
}
|
|
if (searchParams.get('release') === 'rhel8') {
|
|
dispatch(changeDistribution(RHEL_8));
|
|
}
|
|
if (searchParams.get('release') === 'rhel9') {
|
|
dispatch(changeDistribution(RHEL_9));
|
|
}
|
|
if (searchParams.get('release') === 'rhel10beta') {
|
|
dispatch(changeDistribution(RHEL_10_BETA));
|
|
}
|
|
if (searchParams.get('release') === 'rhel10') {
|
|
dispatch(changeDistribution(RHEL_10));
|
|
}
|
|
if (searchParams.get('arch') === AARCH64) {
|
|
dispatch(changeArchitecture(AARCH64));
|
|
}
|
|
if (searchParams.get('target') === 'iso') {
|
|
dispatch(addImageType('image-installer'));
|
|
}
|
|
if (searchParams.get('target') === 'qcow2') {
|
|
dispatch(addImageType('guest-image'));
|
|
}
|
|
|
|
const initializeHostDistro = async () => {
|
|
const distro = await getHostDistro();
|
|
dispatch(changeDistribution(distro));
|
|
};
|
|
|
|
const initializeHostArch = async () => {
|
|
const arch = await getHostArch();
|
|
dispatch(changeArchitecture(arch));
|
|
};
|
|
|
|
if (process.env.IS_ON_PREMISE && !isEdit) {
|
|
if (!searchParams.get('release')) {
|
|
initializeHostDistro();
|
|
}
|
|
initializeHostArch();
|
|
}
|
|
// This useEffect hook should run *only* on mount and therefore has an empty
|
|
// dependency array. eslint's exhaustive-deps rule does not support this use.
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
/* *
|
|
* Selectors *
|
|
* */
|
|
|
|
const distribution = useAppSelector(selectDistribution);
|
|
|
|
// Image Output
|
|
const targetEnvironments = useAppSelector(selectImageTypes);
|
|
// AWS
|
|
const awsShareMethod = useAppSelector(selectAwsShareMethod);
|
|
const awsAccountId = useAppSelector(selectAwsAccountId);
|
|
const awsSourceId = useAppSelector(selectAwsSourceId);
|
|
// GCP
|
|
const gcpShareMethod = useAppSelector(selectGcpShareMethod);
|
|
const gcpEmail = useAppSelector(selectGcpEmail);
|
|
// AZURE
|
|
const azureShareMethod = useAppSelector(selectAzureShareMethod);
|
|
const azureTenantId = useAppSelector(selectAzureTenantId);
|
|
const azureSubscriptionId = useAppSelector(selectAzureSubscriptionId);
|
|
const azureResourceGroup = useAppSelector(selectAzureResourceGroup);
|
|
const azureSource = useAppSelector(selectAzureSource);
|
|
// Registration
|
|
const registrationValidation = useRegistrationValidation();
|
|
// Snapshots
|
|
const snapshotValidation = useSnapshotValidation();
|
|
// Filesystem
|
|
const [filesystemPristine, setFilesystemPristine] = useState(true);
|
|
const fileSystemValidation = useFilesystemValidation();
|
|
// Timezone
|
|
const timezoneValidation = useTimezoneValidation();
|
|
// Locale
|
|
const localeValidation = useLocaleValidation();
|
|
// Hostname
|
|
const hostnameValidation = useHostnameValidation();
|
|
// Kernel
|
|
const kernelValidation = useKernelValidation();
|
|
// Firewall
|
|
const firewallValidation = useFirewallValidation();
|
|
// Services
|
|
const servicesValidation = useServicesValidation();
|
|
// Firstboot
|
|
const firstBootValidation = useFirstBootValidation();
|
|
// Details
|
|
const detailsValidation = useDetailsValidation();
|
|
// Users
|
|
const usersValidation = useUsersValidation();
|
|
|
|
let startIndex = 1; // default index
|
|
if (isEdit) {
|
|
startIndex = 22;
|
|
}
|
|
|
|
const [wasRegisterVisited, setWasRegisterVisited] = useState(false);
|
|
|
|
// Duplicating some of the logic from the Wizard component to allow for custom nav items status
|
|
// for original code see https://github.com/patternfly/patternfly-react/blob/184c55f8d10e1d94ffd72e09212db56c15387c5e/packages/react-core/src/components/Wizard/WizardNavInternal.tsx#L128
|
|
const CustomStatusNavItem = (
|
|
step: WizardStepType,
|
|
activeStep: WizardStepType,
|
|
steps: WizardStepType[],
|
|
goToStepByIndex: (index: number) => void
|
|
) => {
|
|
const isVisitOptional =
|
|
'parentId' in step && step.parentId === 'step-optional-steps';
|
|
|
|
useEffect(() => {
|
|
if (process.env.IS_ON_PREMISE) {
|
|
if (step.id === 'step-oscap' && step.isVisited) {
|
|
setWasRegisterVisited(true);
|
|
}
|
|
} else if (step.id === 'step-register' && step.isVisited) {
|
|
setWasRegisterVisited(true);
|
|
}
|
|
}, [step.id, step.isVisited]);
|
|
|
|
const hasVisitedNextStep = steps.some(
|
|
(s) => s.index > step.index && s.isVisited
|
|
);
|
|
|
|
// Only this code is different from the original
|
|
const status = (step?.id !== activeStep?.id && step?.status) || 'default';
|
|
|
|
return (
|
|
<WizardNavItem
|
|
key={step?.id}
|
|
id={step?.id}
|
|
content={step.name}
|
|
isCurrent={activeStep?.id === step?.id}
|
|
isDisabled={
|
|
step.isDisabled ||
|
|
(!step.isVisited &&
|
|
!hasVisitedNextStep &&
|
|
!(isVisitOptional && wasRegisterVisited))
|
|
}
|
|
isVisited={step.isVisited || false}
|
|
stepIndex={step.index}
|
|
onClick={() => {
|
|
goToStepByIndex(step.index);
|
|
if (isEdit && step.id === 'wizard-additional-packages') {
|
|
analytics.track(
|
|
`${AMPLITUDE_MODULE_NAME} - Additional Packages Revisited in Edit`,
|
|
{
|
|
module: AMPLITUDE_MODULE_NAME,
|
|
isPreview: isBeta(),
|
|
}
|
|
);
|
|
}
|
|
}}
|
|
status={status}
|
|
/>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<ImageBuilderHeader inWizard />
|
|
<PageSection hasBodyWrapper={false} type={PageSectionTypes.wizard}>
|
|
<Wizard
|
|
startIndex={startIndex}
|
|
onClose={() => navigate(resolveRelPath(''))}
|
|
isVisitRequired
|
|
>
|
|
<WizardStep
|
|
name="Image output"
|
|
id="step-image-output"
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={targetEnvironments.length === 0}
|
|
disableBack={true}
|
|
/>
|
|
}
|
|
>
|
|
<ImageOutputStep />
|
|
</WizardStep>
|
|
<WizardStep
|
|
name="Target Environment"
|
|
id="step-target-environment"
|
|
isHidden={
|
|
!targetEnvironments.find(
|
|
(target) =>
|
|
target === 'aws' || target === 'gcp' || target === 'azure'
|
|
)
|
|
}
|
|
steps={[
|
|
<WizardStep
|
|
name="Amazon Web Services"
|
|
id="wizard-target-aws"
|
|
key="wizard-target-aws"
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={
|
|
awsShareMethod === 'manual'
|
|
? !isAwsAccountIdValid(awsAccountId)
|
|
: awsSourceId === undefined
|
|
}
|
|
/>
|
|
}
|
|
isHidden={!targetEnvironments.includes('aws')}
|
|
>
|
|
<Aws />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Google Cloud Platform"
|
|
id="wizard-target-gcp"
|
|
key="wizard-target-gcp"
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={
|
|
gcpShareMethod === 'withGoogle' &&
|
|
!isGcpEmailValid(gcpEmail)
|
|
}
|
|
/>
|
|
}
|
|
isHidden={!targetEnvironments.includes('gcp')}
|
|
>
|
|
<Gcp />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Azure"
|
|
id="wizard-target-azure"
|
|
key="wizard-target-azure"
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={
|
|
azureShareMethod === 'manual'
|
|
? !isAzureTenantGUIDValid(azureTenantId) ||
|
|
!isAzureSubscriptionIdValid(azureSubscriptionId) ||
|
|
!isAzureResourceGroupValid(azureResourceGroup)
|
|
: azureShareMethod === 'sources'
|
|
? !isAzureTenantGUIDValid(azureTenantId) ||
|
|
!isAzureSubscriptionIdValid(azureSubscriptionId) ||
|
|
!isAzureResourceGroupValid(azureResourceGroup)
|
|
: azureSource === undefined
|
|
}
|
|
/>
|
|
}
|
|
isHidden={!targetEnvironments.includes('azure')}
|
|
>
|
|
<Azure />
|
|
</WizardStep>,
|
|
]}
|
|
/>
|
|
<WizardStep
|
|
name="Optional steps"
|
|
id="step-optional-steps"
|
|
steps={[
|
|
<WizardStep
|
|
name="Register"
|
|
id="step-register"
|
|
key="step-register"
|
|
isHidden={!!process.env.IS_ON_PREMISE || !isRhel(distribution)}
|
|
navItem={CustomStatusNavItem}
|
|
status={
|
|
wasRegisterVisited
|
|
? registrationValidation.disabledNext
|
|
? 'error'
|
|
: 'default'
|
|
: 'default'
|
|
}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={registrationValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<RegistrationStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name={complianceEnabled ? 'Compliance' : 'OpenSCAP'}
|
|
id="step-oscap"
|
|
key="step-oscap"
|
|
isHidden={distribution === RHEL_10_BETA}
|
|
navItem={CustomStatusNavItem}
|
|
footer={
|
|
<CustomWizardFooter disableNext={false} optional={true} />
|
|
}
|
|
>
|
|
<OscapStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="File system configuration"
|
|
id="step-file-system"
|
|
key="step-file-system"
|
|
navItem={CustomStatusNavItem}
|
|
footer={
|
|
<CustomWizardFooter
|
|
beforeNext={() => {
|
|
if (fileSystemValidation.disabledNext) {
|
|
setFilesystemPristine(false);
|
|
return false;
|
|
}
|
|
return true;
|
|
}}
|
|
disableNext={
|
|
!filesystemPristine && fileSystemValidation.disabledNext
|
|
}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<FileSystemContext.Provider value={filesystemPristine}>
|
|
<FileSystemStep />
|
|
</FileSystemContext.Provider>
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Repeatable build"
|
|
id="wizard-repository-snapshot"
|
|
key="wizard-repository-snapshot"
|
|
navItem={CustomStatusNavItem}
|
|
status={snapshotValidation.disabledNext ? 'error' : 'default'}
|
|
isHidden={
|
|
distribution === RHEL_10_BETA ||
|
|
!!process.env.IS_ON_PREMISE ||
|
|
isFedoraEnv
|
|
}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={snapshotValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<SnapshotStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Custom repositories"
|
|
id="wizard-custom-repositories"
|
|
key="wizard-custom-repositories"
|
|
navItem={CustomStatusNavItem}
|
|
isHidden={
|
|
distribution === RHEL_10_BETA ||
|
|
!!process.env.IS_ON_PREMISE ||
|
|
isFedoraEnv
|
|
}
|
|
isDisabled={snapshotValidation.disabledNext}
|
|
footer={
|
|
<CustomWizardFooter disableNext={false} optional={true} />
|
|
}
|
|
>
|
|
<RepositoriesStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Additional packages"
|
|
id="wizard-additional-packages"
|
|
key="wizard-additional-packages"
|
|
navItem={CustomStatusNavItem}
|
|
isHidden={isFedoraEnv}
|
|
isDisabled={snapshotValidation.disabledNext}
|
|
footer={
|
|
<CustomWizardFooter disableNext={false} optional={true} />
|
|
}
|
|
>
|
|
<PackagesStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Users"
|
|
id="wizard-users"
|
|
key="wizard-users"
|
|
navItem={CustomStatusNavItem}
|
|
status={usersValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={usersValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<UsersStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Timezone"
|
|
id="wizard-timezone"
|
|
key="wizard-timezone"
|
|
navItem={CustomStatusNavItem}
|
|
status={timezoneValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={timezoneValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<TimezoneStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Locale"
|
|
id="wizard-locale"
|
|
key="wizard-locale"
|
|
navItem={CustomStatusNavItem}
|
|
status={localeValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={localeValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<LocaleStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Hostname"
|
|
id="wizard-hostname"
|
|
key="wizard-hostname"
|
|
navItem={CustomStatusNavItem}
|
|
status={hostnameValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={hostnameValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<HostnameStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Kernel"
|
|
id="wizard-kernel"
|
|
key="wizard-kernel"
|
|
navItem={CustomStatusNavItem}
|
|
status={kernelValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={kernelValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<KernelStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Firewall"
|
|
id="wizard-firewall"
|
|
key="wizard-firewall"
|
|
navItem={CustomStatusNavItem}
|
|
status={firewallValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={firewallValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<FirewallStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="Systemd services"
|
|
id="wizard-services"
|
|
key="wizard-services"
|
|
navItem={CustomStatusNavItem}
|
|
status={servicesValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={servicesValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<ServicesStep />
|
|
</WizardStep>,
|
|
<WizardStep
|
|
name="First boot script configuration"
|
|
id="wizard-first-boot"
|
|
key="wizard-first-boot"
|
|
navItem={CustomStatusNavItem}
|
|
status={firstBootValidation.disabledNext ? 'error' : 'default'}
|
|
isHidden={!!process.env.IS_ON_PREMISE || isFedoraEnv}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={firstBootValidation.disabledNext}
|
|
optional={true}
|
|
/>
|
|
}
|
|
>
|
|
<FirstBootStep />
|
|
</WizardStep>,
|
|
]}
|
|
/>
|
|
<WizardStep
|
|
name="Details"
|
|
id="step-details"
|
|
navItem={CustomStatusNavItem}
|
|
status={detailsValidation.disabledNext ? 'error' : 'default'}
|
|
footer={
|
|
<CustomWizardFooter
|
|
disableNext={detailsValidation.disabledNext}
|
|
/>
|
|
}
|
|
>
|
|
<DetailsStep />
|
|
</WizardStep>
|
|
<WizardStep
|
|
name="Review"
|
|
id="step-review"
|
|
footer={<ReviewWizardFooter />}
|
|
>
|
|
<ReviewStep />
|
|
</WizardStep>
|
|
</Wizard>
|
|
</PageSection>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default CreateImageWizard;
|