Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { Stack, StackItem } from '@patternfly/react-core';
import {
ClusterCpuArchitecture,
getOpenshiftVersionText,
Expand All @@ -7,9 +8,9 @@ import {
} from '../../../common';

type OcmOpenShiftVersionProps = {
versions: OpenshiftVersionOptionType[];
versions?: OpenshiftVersionOptionType[];
openshiftVersion: string;
clusterCpuArchitecture: string | undefined;
clusterCpuArchitecture?: string;
withPreviewText?: boolean;
withMultiText?: boolean;
};
Expand All @@ -20,17 +21,23 @@ const OcmOpenShiftVersion = ({
versions,
withPreviewText,
withMultiText,
}: OcmOpenShiftVersionProps) => {
children,
}: React.PropsWithChildren<OcmOpenShiftVersionProps>) => {
return (
<StaticTextField name="openshiftVersion" label="OpenShift version" isRequired>
OpenShift{' '}
{getOpenshiftVersionText({
openshiftVersion,
cpuArchitecture: clusterCpuArchitecture as ClusterCpuArchitecture,
versions,
withPreviewText,
withMultiText,
})}
<Stack>
<StackItem>
OpenShift{' '}
{getOpenshiftVersionText({
openshiftVersion,
cpuArchitecture: clusterCpuArchitecture as ClusterCpuArchitecture,
versions,
withPreviewText,
withMultiText,
})}
</StackItem>
{children && <StackItem>{children}</StackItem>}
</Stack>
</StaticTextField>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ const getMachineNetworkValidationSchema = (protocolVersion: ProtocolVersion) =>
MAX_PREFIX_LENGTH[protocolVersion],
`Prefix length must be less than or equal to ${MAX_PREFIX_LENGTH[protocolVersion]}`,
)
.nullable()
.transform(transformNumber) as Yup.NumberSchema, //add casting to not get typescript error caused by nullable
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ const ClusterDetails = ({ cluster, infraEnv }: ClusterDetailsProps) => {
managedDomains={managedDomains}
ocpVersions={versions}
usedClusterNames={usedClusterNames}
moveNext={() => clusterWizardContext.moveNext()}
handleClusterUpdate={handleClusterUpdate}
handleClusterCreate={handleClusterCreate}
navigation={navigation}
Expand Down
30 changes: 16 additions & 14 deletions libs/ui-lib/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom-v5-compat';
import { Grid, GridItem } from '@patternfly/react-core';
import { Grid, GridItem, Switch } from '@patternfly/react-core';
import isUndefined from 'lodash-es/isUndefined.js';
import { Formik, FormikHelpers } from 'formik';
import {
Expand Down Expand Up @@ -41,7 +41,6 @@ type ClusterDetailsFormProps = {
ocpVersions: OpenshiftVersionOptionType[];
usedClusterNames: string[];
navigation: React.ReactNode;
moveNext: () => void;
handleClusterCreate: (params: ClusterCreateParams, addCustomManifests: boolean) => Promise<void>;
handleClusterUpdate: (
clusterId: Cluster['id'],
Expand All @@ -58,13 +57,13 @@ const ClusterDetailsForm = (props: ClusterDetailsFormProps) => {
managedDomains,
ocpVersions,
usedClusterNames = [],
moveNext,
handleClusterUpdate,
handleClusterCreate,
navigation,
} = props;

const clusterWizardContext = useClusterWizardContext();
const { installDisconnected, setInstallDisconnected, customManifestsStep, moveNext } =
useClusterWizardContext();
const { search } = useLocation();
const { isViewerMode } = useSelector(selectCurrentClusterPermissionsState);
const { clearAlerts } = useAlerts();
Expand Down Expand Up @@ -119,17 +118,9 @@ const ClusterDetailsForm = (props: ClusterDetailsFormProps) => {
managedDomains,
ocpVersions,
urlSearchParams: search,
addCustomManifests: clusterWizardContext.customManifestsStep,
addCustomManifests: customManifestsStep,
}),
[
infraEnv,
cluster,
pullSecret,
managedDomains,
ocpVersions,
search,
clusterWizardContext.customManifestsStep,
],
[infraEnv, cluster, pullSecret, managedDomains, ocpVersions, search, customManifestsStep],
);

const { t } = useTranslation();
Expand Down Expand Up @@ -173,6 +164,17 @@ const ClusterDetailsForm = (props: ClusterDetailsFormProps) => {
<GridItem>
<ClusterWizardStepHeader>Cluster details</ClusterWizardStepHeader>
</GridItem>
{!isSingleClusterFeatureEnabled && (
<GridItem>
<Switch
id="disconnected-install-switch"
label="I'm installing on a disconnected/air-gapped/secured environment"
isChecked={installDisconnected}
onChange={(_, checked) => setInstallDisconnected(checked)}
ouiaId="DisconnectedInstall"
/>
</GridItem>
)}
<GridItem span={12} lg={10} xl={9} xl2={7}>
<OcmClusterDetailsFormFields
versions={ocpVersions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { UISettingsValues } from '../../../common';
export type ClusterWizardContextType = {
currentStepId: ClusterWizardStepsType;
setCurrentStepId(stepId: ClusterWizardStepsType): void;
moveBack(): void;
moveNext(): void;
moveBack: () => void;
moveNext: () => void;
wizardStepIds: ClusterWizardStepsType[];
onUpdateStaticIpView(view: StaticIpView): void;
onUpdateHostNetworkConfigType(type: HostsNetworkConfigurationType): void;
Expand All @@ -18,6 +18,8 @@ export type ClusterWizardContextType = {
setWizardPerPage: (perPage: number) => void;
updateUISettings: (data: UISettingsValues) => Promise<void>;
uiSettings?: UISettingsValues;
installDisconnected: boolean;
setInstallDisconnected: (enabled: boolean) => void;
};

export const ClusterWizardContext = React.createContext<ClusterWizardContextType | null>(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ClusterWizardContextType, ClusterWizardContext } from './ClusterWizardC
import {
ClusterWizardFlowStateType,
ClusterWizardStepsType,
disconnectedSteps,
getClusterWizardFirstStep,
isStaticIpStep,
isStepAfter,
Expand Down Expand Up @@ -87,9 +88,10 @@ const ClusterWizardContextProvider = ({
}>) => {
const isSingleClusterFeatureEnabled = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE');
const [currentStepId, setCurrentStepId] = React.useState<ClusterWizardStepsType>();
const [wizardStepIds, setWizardStepIds] = React.useState<ClusterWizardStepsType[]>();
const [connectedWizardStepIds, setWizardStepIds] = React.useState<ClusterWizardStepsType[]>();
const [wizardPerPage, setWizardPerPage] = React.useState(10);
const [customManifestsStep, setCustomManifestsStep] = React.useState<boolean>(false);
const [installDisconnected, setInstallDisconnected] = React.useState(false);
const location = useLocation();
const locationState = location.state as ClusterWizardFlowStateType | undefined;
const {
Expand All @@ -101,6 +103,8 @@ const ClusterWizardContextProvider = ({
const { clearAlerts, addAlert, alerts } = useAlerts();
const setClusterPermissions = useSetClusterPermissions();

const wizardStepIds = installDisconnected ? disconnectedSteps : connectedWizardStepIds;

React.useEffect(() => {
if (!UISettingsLoading) {
const staticIpInfo = infraEnv ? getStaticIpInfo(infraEnv) : undefined;
Expand Down Expand Up @@ -237,7 +241,7 @@ const ClusterWizardContextProvider = ({
);
}
},
wizardStepIds,
wizardStepIds: wizardStepIds,
currentStepId,
setCurrentStepId: onSetCurrentStepId,
customManifestsStep,
Expand All @@ -246,6 +250,15 @@ const ClusterWizardContextProvider = ({
setWizardPerPage,
uiSettings,
updateUISettings,
installDisconnected,
setInstallDisconnected: (enabled: boolean) => {
setInstallDisconnected(enabled);
if (enabled) {
onSetCurrentStepId(disconnectedSteps[0]);
} else {
connectedWizardStepIds?.length && onSetCurrentStepId(connectedWizardStepIds[0]);
}
},
Comment on lines +254 to +261
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Toggling to connected flow when IDs are not ready can leave currentStepId invalid

When disabling disconnected mode, connectedWizardStepIds may still be undefined. In that case, currentStepId remains a disconnected step and navigation functions will fail (indexOf returns -1).

Compute the connected steps (and set them) before switching, and always set a valid current step.

Apply this diff:

       setInstallDisconnected: (enabled: boolean) => {
         setInstallDisconnected(enabled);
         if (enabled) {
           onSetCurrentStepId(disconnectedSteps[0]);
         } else {
-          connectedWizardStepIds?.length && onSetCurrentStepId(connectedWizardStepIds[0]);
+          // Build the connected step list deterministically and move to its first step
+          const staticIpInfo = infraEnv ? getStaticIpInfo(infraEnv) : undefined;
+          const nextSteps = getWizardStepIds(
+            connectedWizardStepIds,
+            staticIpInfo?.view,
+            customManifestsStep,
+            isSingleClusterFeatureEnabled,
+          );
+          setWizardStepIds(nextSteps);
+          onSetCurrentStepId(nextSteps[0]);
         }
       },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setInstallDisconnected: (enabled: boolean) => {
setInstallDisconnected(enabled);
if (enabled) {
onSetCurrentStepId(disconnectedSteps[0]);
} else {
connectedWizardStepIds?.length && onSetCurrentStepId(connectedWizardStepIds[0]);
}
},
setInstallDisconnected: (enabled: boolean) => {
setInstallDisconnected(enabled);
if (enabled) {
onSetCurrentStepId(disconnectedSteps[0]);
} else {
// Build the connected step list deterministically and move to its first step
const staticIpInfo = infraEnv ? getStaticIpInfo(infraEnv) : undefined;
const nextSteps = getWizardStepIds(
connectedWizardStepIds,
staticIpInfo?.view,
customManifestsStep,
isSingleClusterFeatureEnabled,
);
setWizardStepIds(nextSteps);
onSetCurrentStepId(nextSteps[0]);
}
},

};
}, [
wizardStepIds,
Expand All @@ -257,6 +270,9 @@ const ClusterWizardContextProvider = ({
clearAlerts,
uiSettings,
updateUISettings,
installDisconnected,
setInstallDisconnected,
connectedWizardStepIds,
]);

if (!contextValue) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import classNames from 'classnames';
import React from 'react';
import ClusterDetails from './ClusterDetails';
import { useClusterWizardContext } from './ClusterWizardContext';
import ReviewStep from './disconnected/ReviewStep';
import BasicStep from './disconnected/BasicStep';
import { ClusterWizardStepsType } from './wizardTransition';

const getCurrentStep = (currentStepId: ClusterWizardStepsType) => {
switch (currentStepId) {
case 'disconnected-review':
return <ReviewStep />;
case 'disconnected-basic':
return <BasicStep />;
default:
return <ClusterDetails />;
}
};

const NewClusterWizard: React.FC = () => {
const { currentStepId } = useClusterWizardContext();
return (
<div className={classNames('pf-v5-c-wizard', 'cluster-wizard')}>
<ClusterDetails />
{getCurrentStep(currentStepId)}
</div>
);
};
Expand Down
2 changes: 2 additions & 0 deletions libs/ui-lib/lib/ocm/components/clusterWizard/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const wizardStepNames: { [key in ClusterWizardStepsType]: string } = {
'custom-manifests': 'Custom manifests',
review: 'Review and create',
'credentials-download': 'Download credentials',
'disconnected-review': 'Review and download ISO',
'disconnected-basic': 'Basic information',
};

export const defaultWizardSteps: ClusterWizardStepsType[] = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from 'react';
import {
ClusterWizardStep,
DeveloperPreview,
ExternalLink,
OCP_RELEASES_PAGE,
StaticTextField,
useTranslation,
} from '../../../../common';
import {
Switch,
Split,
SplitItem,
TextContent,
Text,
TextVariants,
Grid,
GridItem,
Form,
} from '@patternfly/react-core';
import { Formik } from 'formik';
import OcmOpenShiftVersion from '../../clusterConfiguration/OcmOpenShiftVersion';
import { useClusterWizardContext } from '../ClusterWizardContext';
import ClusterWizardFooter from '../ClusterWizardFooter';
import ClusterWizardNavigation from '../ClusterWizardNavigation';
import { WithErrorBoundary } from '../../../../common/components/ErrorHandling/WithErrorBoundary';

const BasicStep = () => {
const { t } = useTranslation();
const { installDisconnected, setInstallDisconnected, moveNext } = useClusterWizardContext();

return (
<Formik
initialValues={{}}
onSubmit={() => {
// nothing to do
}}
>
<ClusterWizardStep
navigation={<ClusterWizardNavigation />}
footer={<ClusterWizardFooter onNext={moveNext} />}
>
<WithErrorBoundary title="Failed to load Basic step">
<Grid hasGutter>
<GridItem>
<Split>
<SplitItem>
<TextContent>
<Text component={TextVariants.h2}>Basic information</Text>
</TextContent>
</SplitItem>
<SplitItem>
<DeveloperPreview />
</SplitItem>
</Split>
</GridItem>
<GridItem>
<Switch
id="disconnected-install-switch"
label="I'm installing on a disconnected/air-gapped/secured environment"
isChecked={installDisconnected}
onChange={(_, checked) => setInstallDisconnected(checked)}
ouiaId="DisconnectedInstall"
/>
</GridItem>
<GridItem>
<Form id="wizard-cluster-basic-info__form">
<OcmOpenShiftVersion openshiftVersion="4.19" withPreviewText withMultiText>
<ExternalLink href={`${window.location.origin}/${OCP_RELEASES_PAGE}`}>
<span data-ouia-id="openshift-releases-link">
{t('ai:Learn more about OpenShift releases')}
</span>
</ExternalLink>
</OcmOpenShiftVersion>
<StaticTextField name="cpuArchitecture" label="CPU architecture" isRequired>
x86_64
</StaticTextField>
</Form>
</GridItem>
</Grid>
</WithErrorBoundary>
</ClusterWizardStep>
</Formik>
);
};

export default BasicStep;
Loading