@openshift-assisted/ui-lib 2.55.2 → 2.55.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/@types/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/ClusterWizardContextProvider.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/ClusterWizardNavigation.d.ts +7 -0
- package/build/@types/ocm/components/clusterWizard/ClusterWizardNavigation.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/NewClusterWizard.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/StaticIp.d.ts +1 -1
- package/build/@types/ocm/components/clusterWizard/StaticIp.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/disconnected/BasicStep.d.ts +1 -1
- package/build/@types/ocm/components/clusterWizard/disconnected/BasicStep.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/disconnected/DisconnectedStaticIp.d.ts +4 -0
- package/build/@types/ocm/components/clusterWizard/disconnected/DisconnectedStaticIp.d.ts.map +1 -0
- package/build/@types/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/disconnected/ReviewStep.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterWizard/utils.d.ts +7 -0
- package/build/@types/ocm/components/clusterWizard/utils.d.ts.map +1 -0
- package/build/@types/ocm/components/clusters/AssistedInstallerHeader.d.ts.map +1 -1
- package/build/cjs/common/components/clusterWizard/ClusterWizardStep.css +9 -0
- package/build/cjs/common/validationSchemas/addressValidation.js +2 -2
- package/build/cjs/common/validationSchemas/addressValidation.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.js +3 -1
- package/build/cjs/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js +47 -47
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardNavigation.js +31 -19
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardNavigation.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/NewClusterWizard.js +5 -0
- package/build/cjs/ocm/components/clusterWizard/NewClusterWizard.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/StaticIp.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/disconnected/BasicStep.js +2 -3
- package/build/cjs/ocm/components/clusterWizard/disconnected/BasicStep.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/disconnected/DisconnectedStaticIp.js +26 -0
- package/build/cjs/ocm/components/clusterWizard/disconnected/DisconnectedStaticIp.js.map +1 -0
- package/build/cjs/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.js +52 -19
- package/build/cjs/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js +4 -5
- package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/utils.js +63 -0
- package/build/cjs/ocm/components/clusterWizard/utils.js.map +1 -0
- package/build/cjs/ocm/components/clusters/AssistedInstallerHeader.js +0 -3
- package/build/cjs/ocm/components/clusters/AssistedInstallerHeader.js.map +1 -1
- package/lib/common/components/clusterWizard/ClusterWizardStep.css +9 -0
- package/lib/common/validationSchemas/_validationSchemas.test.ts +1 -1
- package/lib/common/validationSchemas/addressValidation.tsx +2 -2
- package/lib/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.tsx +4 -1
- package/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx +48 -71
- package/lib/ocm/components/clusterWizard/ClusterWizardNavigation.tsx +39 -16
- package/lib/ocm/components/clusterWizard/NewClusterWizard.tsx +5 -0
- package/lib/ocm/components/clusterWizard/StaticIp.tsx +1 -1
- package/lib/ocm/components/clusterWizard/_wizardTransition.test.ts +60 -1
- package/lib/ocm/components/clusterWizard/disconnected/BasicStep.tsx +2 -3
- package/lib/ocm/components/clusterWizard/disconnected/DisconnectedStaticIp.tsx +29 -0
- package/lib/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.tsx +72 -12
- package/lib/ocm/components/clusterWizard/disconnected/ReviewStep.tsx +9 -11
- package/lib/ocm/components/clusterWizard/utils.ts +75 -0
- package/lib/ocm/components/clusters/AssistedInstallerHeader.tsx +1 -9
- package/package.json +3 -3
|
@@ -13,6 +13,30 @@ import { staticIpFormViewSubSteps, wizardStepNames } from './constants';
|
|
|
13
13
|
import WizardNavItem from '../../../common/components/ui/WizardNavItem';
|
|
14
14
|
import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
|
|
15
15
|
|
|
16
|
+
export type WizardNavEntry = {
|
|
17
|
+
stepId: ClusterWizardStepsType;
|
|
18
|
+
visualNumber: number;
|
|
19
|
+
isStaticIpFormGroup: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const getWizardNavEntries = (wizardStepIds: ClusterWizardStepsType[]): WizardNavEntry[] => {
|
|
23
|
+
const entries: WizardNavEntry[] = [];
|
|
24
|
+
let i = 0;
|
|
25
|
+
let visualNumber = 1;
|
|
26
|
+
while (i < wizardStepIds.length) {
|
|
27
|
+
const stepId = wizardStepIds[i];
|
|
28
|
+
if (stepId === 'static-ip-network-wide-configurations') {
|
|
29
|
+
entries.push({ stepId, visualNumber, isStaticIpFormGroup: true });
|
|
30
|
+
i += 2;
|
|
31
|
+
} else {
|
|
32
|
+
entries.push({ stepId, visualNumber, isStaticIpFormGroup: false });
|
|
33
|
+
i += 1;
|
|
34
|
+
}
|
|
35
|
+
visualNumber += 1;
|
|
36
|
+
}
|
|
37
|
+
return entries;
|
|
38
|
+
};
|
|
39
|
+
|
|
16
40
|
const isStepValid = (stepId: ClusterWizardStepsType, cluster?: Cluster): boolean => {
|
|
17
41
|
if (!cluster) {
|
|
18
42
|
return true;
|
|
@@ -48,7 +72,11 @@ const ClusterWizardNavigation = ({ cluster }: { cluster?: Cluster }) => {
|
|
|
48
72
|
return stepId === 'cluster-details' ? false : isStepIdxAfterCurrent(idx);
|
|
49
73
|
};
|
|
50
74
|
|
|
51
|
-
const getNavItem = (
|
|
75
|
+
const getNavItem = (
|
|
76
|
+
idx: number,
|
|
77
|
+
stepId: ClusterWizardStepsType,
|
|
78
|
+
visualNumber: number,
|
|
79
|
+
): ReactNode => {
|
|
52
80
|
return (
|
|
53
81
|
<WizardNavItem
|
|
54
82
|
stepIndex={idx}
|
|
@@ -60,11 +88,12 @@ const ClusterWizardNavigation = ({ cluster }: { cluster?: Cluster }) => {
|
|
|
60
88
|
isDisabled={isStepDisabled(idx, stepId)}
|
|
61
89
|
isValid={() => isStepValid(stepId, cluster)}
|
|
62
90
|
data-testid={`cluster-wizard-nav-item-${stepId}`}
|
|
91
|
+
style={{ '--cluster-wizard-step-number': `"${visualNumber}"` } as React.CSSProperties}
|
|
63
92
|
/>
|
|
64
93
|
);
|
|
65
94
|
};
|
|
66
95
|
|
|
67
|
-
const getStaticIpFormViewNavItem = (idx: number): ReactNode => {
|
|
96
|
+
const getStaticIpFormViewNavItem = (idx: number, visualNumber: number): ReactNode => {
|
|
68
97
|
return (
|
|
69
98
|
<WizardNavItem
|
|
70
99
|
stepIndex={idx}
|
|
@@ -74,13 +103,14 @@ const ClusterWizardNavigation = ({ cluster }: { cluster?: Cluster }) => {
|
|
|
74
103
|
isCurrent={isStaticIpStep(clusterWizardContext.currentStepId)}
|
|
75
104
|
isDisabled={isStepIdxAfterCurrent(idx)}
|
|
76
105
|
data-testid={`cluster-wizard-nav-item-static-network-configuration-form-view`}
|
|
106
|
+
style={{ '--cluster-wizard-step-number': `"${visualNumber}"` } as React.CSSProperties}
|
|
77
107
|
>
|
|
78
108
|
<WizardNav
|
|
79
109
|
isInnerList
|
|
80
110
|
data-testid="cluster-wizard-nav-item-static-network-configuration-form-view-inner-list"
|
|
81
111
|
>
|
|
82
112
|
{staticIpFormViewSubSteps.map((stepId, subIdx) => {
|
|
83
|
-
return getNavItem(idx + subIdx, stepId);
|
|
113
|
+
return getNavItem(idx + subIdx, stepId, visualNumber);
|
|
84
114
|
})}
|
|
85
115
|
</WizardNav>
|
|
86
116
|
</WizardNavItem>
|
|
@@ -88,20 +118,13 @@ const ClusterWizardNavigation = ({ cluster }: { cluster?: Cluster }) => {
|
|
|
88
118
|
};
|
|
89
119
|
|
|
90
120
|
const getWizardNavItems = (): ReactNode[] => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (stepId !== 'static-ip-network-wide-configurations') {
|
|
96
|
-
navItems.push(getNavItem(i, stepId));
|
|
97
|
-
i += 1;
|
|
98
|
-
} else {
|
|
99
|
-
navItems.push(getStaticIpFormViewNavItem(i));
|
|
100
|
-
//skip iteration on form view sub steps
|
|
101
|
-
i += 2;
|
|
121
|
+
return getWizardNavEntries(clusterWizardContext.wizardStepIds).map((entry) => {
|
|
122
|
+
const idx = clusterWizardContext.wizardStepIds.indexOf(entry.stepId);
|
|
123
|
+
if (entry.isStaticIpFormGroup) {
|
|
124
|
+
return getStaticIpFormViewNavItem(idx, entry.visualNumber);
|
|
102
125
|
}
|
|
103
|
-
|
|
104
|
-
|
|
126
|
+
return getNavItem(idx, entry.stepId, entry.visualNumber);
|
|
127
|
+
});
|
|
105
128
|
};
|
|
106
129
|
|
|
107
130
|
return <WizardNav data-testid="cluster-wizard-nav">{getWizardNavItems()}</WizardNav>;
|
|
@@ -5,6 +5,7 @@ import { useClusterWizardContext } from './ClusterWizardContext';
|
|
|
5
5
|
import ReviewStep from './disconnected/ReviewStep';
|
|
6
6
|
import BasicStep from './disconnected/BasicStep';
|
|
7
7
|
import OptionalConfigurationsStep from './disconnected/OptionalConfigurationsStep';
|
|
8
|
+
import DisconnectedStaticIp from './disconnected/DisconnectedStaticIp';
|
|
8
9
|
import { ClusterWizardStepsType } from './wizardTransition';
|
|
9
10
|
import { useInfraEnv } from '../../hooks';
|
|
10
11
|
import { CpuArchitecture } from '../../../common/types';
|
|
@@ -18,6 +19,10 @@ const getCurrentStep = (currentStepId: ClusterWizardStepsType, infraEnv?: InfraE
|
|
|
18
19
|
return <OptionalConfigurationsStep />;
|
|
19
20
|
case 'disconnected-basic':
|
|
20
21
|
return <BasicStep />;
|
|
22
|
+
case 'static-ip-yaml-view':
|
|
23
|
+
case 'static-ip-network-wide-configurations':
|
|
24
|
+
case 'static-ip-host-configurations':
|
|
25
|
+
return <DisconnectedStaticIp />;
|
|
21
26
|
default:
|
|
22
27
|
return <ClusterDetails infraEnv={infraEnv} />;
|
|
23
28
|
}
|
|
@@ -8,7 +8,15 @@ import {
|
|
|
8
8
|
Validation as HostValidation,
|
|
9
9
|
} from '../../../common/types/hosts';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
canNextClusterDetails,
|
|
13
|
+
canNextHostDiscovery,
|
|
14
|
+
canNextStorage,
|
|
15
|
+
disconnectedSteps,
|
|
16
|
+
} from './wizardTransition';
|
|
17
|
+
import { getWizardNavEntries } from './ClusterWizardNavigation';
|
|
18
|
+
import { getDisconnectedWizardStepIds } from './utils';
|
|
19
|
+
import { StaticIpView } from '../clusterConfiguration/staticIp/data/dataTypes';
|
|
12
20
|
import { Cluster, Host } from '@openshift-assisted/types/assisted-installer-service';
|
|
13
21
|
|
|
14
22
|
const clusterBase: Cluster = {
|
|
@@ -441,3 +449,54 @@ describe('OCM wizard transition of Storage', () => {
|
|
|
441
449
|
expect(canNextStorage({ cluster })).toBe(true);
|
|
442
450
|
});
|
|
443
451
|
});
|
|
452
|
+
|
|
453
|
+
describe('Disconnected wizard step ids', () => {
|
|
454
|
+
test('starts with the three base disconnected steps', () => {
|
|
455
|
+
expect(getDisconnectedWizardStepIds()).toEqual(disconnectedSteps);
|
|
456
|
+
expect(getDisconnectedWizardStepIds('dhcp-selected')).toEqual(disconnectedSteps);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
test('inserts static IP form steps and removes them again for DHCP', () => {
|
|
460
|
+
const withStatic = getDisconnectedWizardStepIds(StaticIpView.FORM);
|
|
461
|
+
expect(withStatic).toEqual([
|
|
462
|
+
'disconnected-basic',
|
|
463
|
+
'disconnected-optional-configurations',
|
|
464
|
+
'static-ip-network-wide-configurations',
|
|
465
|
+
'static-ip-host-configurations',
|
|
466
|
+
'disconnected-review',
|
|
467
|
+
]);
|
|
468
|
+
expect(getDisconnectedWizardStepIds('dhcp-selected')).toEqual(disconnectedSteps);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
test('inserts the YAML static IP step', () => {
|
|
472
|
+
expect(getDisconnectedWizardStepIds(StaticIpView.YAML)).toEqual([
|
|
473
|
+
'disconnected-basic',
|
|
474
|
+
'disconnected-optional-configurations',
|
|
475
|
+
'static-ip-yaml-view',
|
|
476
|
+
'disconnected-review',
|
|
477
|
+
]);
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
describe('Wizard nav visual numbers', () => {
|
|
482
|
+
test('numbers review as 3 when static IP steps are absent', () => {
|
|
483
|
+
const entries = getWizardNavEntries(disconnectedSteps);
|
|
484
|
+
expect(entries.map((entry) => [entry.stepId, entry.visualNumber])).toEqual([
|
|
485
|
+
['disconnected-basic', 1],
|
|
486
|
+
['disconnected-optional-configurations', 2],
|
|
487
|
+
['disconnected-review', 3],
|
|
488
|
+
]);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
test('keeps a single number for form-view static IP and numbers review as 4', () => {
|
|
492
|
+
const entries = getWizardNavEntries(getDisconnectedWizardStepIds(StaticIpView.FORM));
|
|
493
|
+
expect(
|
|
494
|
+
entries.map((entry) => [entry.stepId, entry.visualNumber, entry.isStaticIpFormGroup]),
|
|
495
|
+
).toEqual([
|
|
496
|
+
['disconnected-basic', 1, false],
|
|
497
|
+
['disconnected-optional-configurations', 2, false],
|
|
498
|
+
['static-ip-network-wide-configurations', 3, true],
|
|
499
|
+
['disconnected-review', 4, false],
|
|
500
|
+
]);
|
|
501
|
+
});
|
|
502
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ClusterWizardStep,
|
|
2
|
+
import { ClusterWizardStep, StaticTextField } from '../../../../common';
|
|
3
3
|
import { Flex, Grid, GridItem, Form, Content } from '@patternfly/react-core';
|
|
4
4
|
import { useClusterWizardContext } from '../ClusterWizardContext';
|
|
5
5
|
import ClusterWizardFooter from '../ClusterWizardFooter';
|
|
@@ -7,7 +7,7 @@ import ClusterWizardNavigation from '../ClusterWizardNavigation';
|
|
|
7
7
|
import { WithErrorBoundary } from '../../../../common/components/ErrorHandling/WithErrorBoundary';
|
|
8
8
|
import InstallDisconnectedSwitch from './InstallDisconnectedSwitch';
|
|
9
9
|
|
|
10
|
-
export const DISCONNECTED_OPENSHIFT_VERSION = '4.
|
|
10
|
+
export const DISCONNECTED_OPENSHIFT_VERSION = '4.22.13';
|
|
11
11
|
|
|
12
12
|
const BasicStep = () => {
|
|
13
13
|
const { moveNext } = useClusterWizardContext();
|
|
@@ -26,7 +26,6 @@ const BasicStep = () => {
|
|
|
26
26
|
<Flex alignItems={{ default: 'alignItemsCenter' }} gap={{ default: 'gapSm' }}>
|
|
27
27
|
<InstallDisconnectedSwitch />
|
|
28
28
|
<span>I'm installing on a disconnected/air-gapped/secured environment</span>
|
|
29
|
-
<TechnologyPreview />
|
|
30
29
|
</Flex>
|
|
31
30
|
</GridItem>
|
|
32
31
|
<GridItem>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { InfraEnvUpdateParams } from '@openshift-assisted/types/assisted-installer-service';
|
|
3
|
+
import { useClusterWizardContext } from '../ClusterWizardContext';
|
|
4
|
+
import { InfraEnvsAPI } from '../../../services/apis';
|
|
5
|
+
import StaticIp from '../StaticIp';
|
|
6
|
+
|
|
7
|
+
export const DisconnectedStaticIp: React.FC = () => {
|
|
8
|
+
const { disconnectedInfraEnv, setDisconnectedInfraEnv } = useClusterWizardContext();
|
|
9
|
+
|
|
10
|
+
const updateInfraEnv = React.useCallback(
|
|
11
|
+
async (params: InfraEnvUpdateParams) => {
|
|
12
|
+
if (!disconnectedInfraEnv?.id) {
|
|
13
|
+
throw new Error('No disconnected infraEnv available');
|
|
14
|
+
}
|
|
15
|
+
const { data: updatedInfraEnv } = await InfraEnvsAPI.update(disconnectedInfraEnv.id, params);
|
|
16
|
+
setDisconnectedInfraEnv(updatedInfraEnv);
|
|
17
|
+
return updatedInfraEnv;
|
|
18
|
+
},
|
|
19
|
+
[disconnectedInfraEnv, setDisconnectedInfraEnv],
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
if (!disconnectedInfraEnv) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return <StaticIp infraEnv={disconnectedInfraEnv} updateInfraEnv={updateInfraEnv} />;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default DisconnectedStaticIp;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Formik, useFormikContext } from 'formik';
|
|
3
3
|
import * as Yup from 'yup';
|
|
4
|
-
import { AlertVariant } from '@patternfly/react-core';
|
|
5
|
-
import {
|
|
4
|
+
import { AlertVariant, Form, Grid, GridItem, Content } from '@patternfly/react-core';
|
|
5
|
+
import {
|
|
6
|
+
HostStaticNetworkConfig,
|
|
7
|
+
InfraEnv,
|
|
8
|
+
InfraEnvUpdateParams,
|
|
9
|
+
ImageType,
|
|
10
|
+
} from '@openshift-assisted/types/assisted-installer-service';
|
|
6
11
|
import {
|
|
7
12
|
ClusterWizardStep,
|
|
8
13
|
PullSecret,
|
|
@@ -14,15 +19,21 @@ import {
|
|
|
14
19
|
sshPublicKeyValidationSchema,
|
|
15
20
|
useAlerts,
|
|
16
21
|
useTranslation,
|
|
22
|
+
InputField,
|
|
23
|
+
ipValidationSchema,
|
|
24
|
+
getFormikErrorFields,
|
|
17
25
|
} from '../../../../common';
|
|
18
26
|
import { WithErrorBoundary } from '../../../../common/components/ErrorHandling/WithErrorBoundary';
|
|
19
27
|
import { useClusterWizardContext } from '../ClusterWizardContext';
|
|
20
28
|
import ClusterWizardFooter from '../ClusterWizardFooter';
|
|
21
29
|
import ClusterWizardNavigation from '../ClusterWizardNavigation';
|
|
22
30
|
import { InfraEnvsAPI, ClustersAPI } from '../../../services/apis';
|
|
23
|
-
import { ImageType } from '@openshift-assisted/types/assisted-installer-service';
|
|
24
31
|
import usePullSecret from '../../../hooks/usePullSecret';
|
|
25
32
|
import { DISCONNECTED_OPENSHIFT_VERSION } from './BasicStep';
|
|
33
|
+
import { HostsNetworkConfigurationControlGroup } from '../../clusterConfiguration/HostsNetworkConfigurationControlGroup';
|
|
34
|
+
import { HostsNetworkConfigurationType } from '../../../services/types';
|
|
35
|
+
import { getDummyInfraEnvField } from '../../clusterConfiguration/staticIp/data/dummyData';
|
|
36
|
+
import { getStaticNetworkConfig } from '../../clusterConfiguration/staticIp/data/fromInfraEnv';
|
|
26
37
|
|
|
27
38
|
const DISCONNECTED_IMAGE_TYPE: ImageType = 'disconnected-iso';
|
|
28
39
|
const DISCONNECTED_CLUSTER_NAME = 'disconnected-cluster';
|
|
@@ -30,6 +41,8 @@ const DISCONNECTED_CLUSTER_NAME = 'disconnected-cluster';
|
|
|
30
41
|
type OptionalConfigurationsValues = {
|
|
31
42
|
sshPublicKey: string;
|
|
32
43
|
pullSecret: string;
|
|
44
|
+
rendezvousIp: string;
|
|
45
|
+
hostsNetworkConfigurationType: HostsNetworkConfigurationType;
|
|
33
46
|
};
|
|
34
47
|
|
|
35
48
|
type OptionalConfigurationsFormProps = {
|
|
@@ -42,7 +55,8 @@ const OptionalConfigurationsForm: React.FC<OptionalConfigurationsFormProps> = ({
|
|
|
42
55
|
isSubmitting,
|
|
43
56
|
}) => {
|
|
44
57
|
const { moveBack } = useClusterWizardContext();
|
|
45
|
-
const { isValid, submitForm } = useFormikContext<OptionalConfigurationsValues>();
|
|
58
|
+
const { isValid, submitForm, errors, touched } = useFormikContext<OptionalConfigurationsValues>();
|
|
59
|
+
const errorFields = getFormikErrorFields(errors, touched);
|
|
46
60
|
|
|
47
61
|
return (
|
|
48
62
|
<ClusterWizardStep
|
|
@@ -53,6 +67,7 @@ const OptionalConfigurationsForm: React.FC<OptionalConfigurationsFormProps> = ({
|
|
|
53
67
|
onBack={moveBack}
|
|
54
68
|
isSubmitting={isSubmitting}
|
|
55
69
|
isNextDisabled={!isValid}
|
|
70
|
+
errorFields={errorFields}
|
|
56
71
|
/>
|
|
57
72
|
}
|
|
58
73
|
>
|
|
@@ -63,8 +78,15 @@ const OptionalConfigurationsForm: React.FC<OptionalConfigurationsFormProps> = ({
|
|
|
63
78
|
</GridItem>
|
|
64
79
|
<GridItem>
|
|
65
80
|
<Form id="wizard-cluster-optional-config__form">
|
|
81
|
+
<InputField
|
|
82
|
+
label="Rendezvous IP"
|
|
83
|
+
name="rendezvousIp"
|
|
84
|
+
helperText="The IP address that hosts will use to communicate with the bootstrap node during installation."
|
|
85
|
+
maxLength={45}
|
|
86
|
+
/>
|
|
66
87
|
<UploadSSH />
|
|
67
88
|
{!isInOcm && <PullSecret isOcm={false} defaultPullSecret={defaultPullSecret} />}
|
|
89
|
+
<HostsNetworkConfigurationControlGroup clusterExists={false} isDisabled={false} />
|
|
68
90
|
</Form>
|
|
69
91
|
</GridItem>
|
|
70
92
|
</Grid>
|
|
@@ -73,6 +95,29 @@ const OptionalConfigurationsForm: React.FC<OptionalConfigurationsFormProps> = ({
|
|
|
73
95
|
);
|
|
74
96
|
};
|
|
75
97
|
|
|
98
|
+
const getStaticNetworkConfigUpdate = (
|
|
99
|
+
values: OptionalConfigurationsValues,
|
|
100
|
+
infraEnv: InfraEnv | undefined,
|
|
101
|
+
): HostStaticNetworkConfig[] => {
|
|
102
|
+
if (values.hostsNetworkConfigurationType === HostsNetworkConfigurationType.DHCP) {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
// Static IP selected — resend existing config, or seed with dummy if none exists yet.
|
|
106
|
+
if (!infraEnv?.staticNetworkConfig) {
|
|
107
|
+
return getDummyInfraEnvField();
|
|
108
|
+
}
|
|
109
|
+
return getStaticNetworkConfig(infraEnv) ?? getDummyInfraEnvField();
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const buildInfraEnvUpdateParams = (
|
|
113
|
+
values: OptionalConfigurationsValues,
|
|
114
|
+
disconnectedInfraEnv: InfraEnv | undefined,
|
|
115
|
+
): InfraEnvUpdateParams => ({
|
|
116
|
+
sshAuthorizedKey: values.sshPublicKey,
|
|
117
|
+
rendezvousIp: values.rendezvousIp,
|
|
118
|
+
staticNetworkConfig: getStaticNetworkConfigUpdate(values, disconnectedInfraEnv),
|
|
119
|
+
});
|
|
120
|
+
|
|
76
121
|
const OptionalConfigurationsStep = () => {
|
|
77
122
|
const { t } = useTranslation();
|
|
78
123
|
const {
|
|
@@ -91,6 +136,9 @@ const OptionalConfigurationsStep = () => {
|
|
|
91
136
|
Yup.object({
|
|
92
137
|
sshPublicKey: sshPublicKeyValidationSchema(t),
|
|
93
138
|
pullSecret: isInOcm ? Yup.string() : pullSecretValidationSchema(t),
|
|
139
|
+
rendezvousIp: Yup.string()
|
|
140
|
+
.max(45, 'IP address must be at most 45 characters')
|
|
141
|
+
.concat(ipValidationSchema(t)),
|
|
94
142
|
}),
|
|
95
143
|
[t],
|
|
96
144
|
);
|
|
@@ -98,6 +146,10 @@ const OptionalConfigurationsStep = () => {
|
|
|
98
146
|
const initialValues: OptionalConfigurationsValues = {
|
|
99
147
|
sshPublicKey: disconnectedInfraEnv?.sshAuthorizedKey ?? '',
|
|
100
148
|
pullSecret: defaultPullSecret ?? '',
|
|
149
|
+
rendezvousIp: disconnectedInfraEnv?.rendezvousIp ?? '',
|
|
150
|
+
hostsNetworkConfigurationType: disconnectedInfraEnv?.staticNetworkConfig
|
|
151
|
+
? HostsNetworkConfigurationType.STATIC
|
|
152
|
+
: HostsNetworkConfigurationType.DHCP,
|
|
101
153
|
};
|
|
102
154
|
|
|
103
155
|
const handleNext = React.useCallback(
|
|
@@ -107,12 +159,9 @@ const OptionalConfigurationsStep = () => {
|
|
|
107
159
|
try {
|
|
108
160
|
const pullSecretToUse = isInOcm ? defaultPullSecret ?? '' : values.pullSecret;
|
|
109
161
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
114
|
-
setDisconnectedInfraEnv(updatedInfraEnv);
|
|
115
|
-
} else {
|
|
162
|
+
let infraEnvToUse: InfraEnv | undefined = disconnectedInfraEnv;
|
|
163
|
+
|
|
164
|
+
if (!disconnectedCluster?.id || !infraEnvToUse?.id) {
|
|
116
165
|
const { data: cluster } = await ClustersAPI.registerDisconnected({
|
|
117
166
|
name: DISCONNECTED_CLUSTER_NAME,
|
|
118
167
|
openshiftVersion: DISCONNECTED_OPENSHIFT_VERSION,
|
|
@@ -126,10 +175,22 @@ const OptionalConfigurationsStep = () => {
|
|
|
126
175
|
imageType: DISCONNECTED_IMAGE_TYPE,
|
|
127
176
|
openshiftVersion: DISCONNECTED_OPENSHIFT_VERSION,
|
|
128
177
|
sshAuthorizedKey: values.sshPublicKey || undefined,
|
|
178
|
+
rendezvousIp: values.rendezvousIp || undefined,
|
|
179
|
+
staticNetworkConfig:
|
|
180
|
+
values.hostsNetworkConfigurationType === HostsNetworkConfigurationType.STATIC
|
|
181
|
+
? getDummyInfraEnvField()
|
|
182
|
+
: undefined,
|
|
129
183
|
});
|
|
130
|
-
|
|
184
|
+
infraEnvToUse = createdInfraEnv;
|
|
185
|
+
} else {
|
|
186
|
+
const { data: updatedInfraEnv } = await InfraEnvsAPI.update(
|
|
187
|
+
infraEnvToUse.id,
|
|
188
|
+
buildInfraEnvUpdateParams(values, infraEnvToUse),
|
|
189
|
+
);
|
|
190
|
+
infraEnvToUse = updatedInfraEnv;
|
|
131
191
|
}
|
|
132
192
|
|
|
193
|
+
setDisconnectedInfraEnv(infraEnvToUse);
|
|
133
194
|
moveNext();
|
|
134
195
|
} catch (error) {
|
|
135
196
|
handleApiError(error, () => {
|
|
@@ -158,7 +219,6 @@ const OptionalConfigurationsStep = () => {
|
|
|
158
219
|
return (
|
|
159
220
|
<Formik<OptionalConfigurationsValues>
|
|
160
221
|
initialValues={initialValues}
|
|
161
|
-
enableReinitialize
|
|
162
222
|
validationSchema={validationSchema}
|
|
163
223
|
onSubmit={(values) => void handleNext(values)}
|
|
164
224
|
>
|
|
@@ -2,8 +2,6 @@ import * as React from 'react';
|
|
|
2
2
|
import { saveAs } from 'file-saver';
|
|
3
3
|
import { useNavigate } from 'react-router';
|
|
4
4
|
import {
|
|
5
|
-
Split,
|
|
6
|
-
SplitItem,
|
|
7
5
|
Alert,
|
|
8
6
|
Grid,
|
|
9
7
|
DescriptionList,
|
|
@@ -18,7 +16,6 @@ import {
|
|
|
18
16
|
} from '@patternfly/react-core';
|
|
19
17
|
import {
|
|
20
18
|
ClusterWizardStep,
|
|
21
|
-
TechnologyPreview,
|
|
22
19
|
ExternalLink,
|
|
23
20
|
getDisconnectedDocsLink,
|
|
24
21
|
getMajorMinorVersion,
|
|
@@ -53,14 +50,7 @@ const ReviewStep = () => {
|
|
|
53
50
|
>
|
|
54
51
|
<WithErrorBoundary title="Failed to load Review step">
|
|
55
52
|
<Grid hasGutter>
|
|
56
|
-
<
|
|
57
|
-
<SplitItem>
|
|
58
|
-
<Content component="h2">Review and download ISO</Content>
|
|
59
|
-
</SplitItem>
|
|
60
|
-
<SplitItem>
|
|
61
|
-
<TechnologyPreview />
|
|
62
|
-
</SplitItem>
|
|
63
|
-
</Split>
|
|
53
|
+
<Content component="h2">Review and download ISO</Content>
|
|
64
54
|
<Alert isInline variant="info" title="ISO boot instructions">
|
|
65
55
|
<List component={ListComponent.ol} type={OrderType.number}>
|
|
66
56
|
<ListItem>Download the ISO.</ListItem>
|
|
@@ -98,6 +88,14 @@ const ReviewStep = () => {
|
|
|
98
88
|
{disconnectedInfraEnv?.openshiftVersion ?? DISCONNECTED_OPENSHIFT_VERSION}
|
|
99
89
|
</DescriptionListDescription>
|
|
100
90
|
</DescriptionListGroup>
|
|
91
|
+
{disconnectedInfraEnv?.rendezvousIp && (
|
|
92
|
+
<DescriptionListGroup>
|
|
93
|
+
<DescriptionListTerm>Rendezvous IP</DescriptionListTerm>
|
|
94
|
+
<DescriptionListDescription>
|
|
95
|
+
{disconnectedInfraEnv.rendezvousIp}
|
|
96
|
+
</DescriptionListDescription>
|
|
97
|
+
</DescriptionListGroup>
|
|
98
|
+
)}
|
|
101
99
|
<DescriptionListGroup>
|
|
102
100
|
<DescriptionListTerm>CPU architecture</DescriptionListTerm>
|
|
103
101
|
<DescriptionListDescription>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { defaultWizardSteps, staticIpFormViewSubSteps } from './constants';
|
|
2
|
+
import { StaticIpView } from '../clusterConfiguration/staticIp/data/dataTypes';
|
|
3
|
+
import { ClusterWizardStepsType, disconnectedSteps } from './wizardTransition';
|
|
4
|
+
|
|
5
|
+
export const addStepToClusterWizard = (
|
|
6
|
+
wizardStepIds: ClusterWizardStepsType[],
|
|
7
|
+
addAfterStep: ClusterWizardStepsType,
|
|
8
|
+
itemsToAdd: ClusterWizardStepsType[],
|
|
9
|
+
): ClusterWizardStepsType[] => {
|
|
10
|
+
const stepsIds = [...wizardStepIds];
|
|
11
|
+
const referencePosition = stepsIds.findIndex((step) => step === addAfterStep);
|
|
12
|
+
const found = wizardStepIds.filter((step) => step === itemsToAdd[0]);
|
|
13
|
+
if (referencePosition !== -1 && found.length === 0) {
|
|
14
|
+
stepsIds.splice(referencePosition + 1, 0, ...itemsToAdd);
|
|
15
|
+
}
|
|
16
|
+
return stepsIds;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const removeStepFromClusterWizard = (
|
|
20
|
+
wizardStepIds: ClusterWizardStepsType[],
|
|
21
|
+
itemToRemove: ClusterWizardStepsType,
|
|
22
|
+
numberItemsToRemove: number,
|
|
23
|
+
): ClusterWizardStepsType[] => {
|
|
24
|
+
const stepsIds = [...wizardStepIds];
|
|
25
|
+
const position = stepsIds.findIndex((step) => step === itemToRemove);
|
|
26
|
+
if (position !== -1) {
|
|
27
|
+
stepsIds.splice(position, numberItemsToRemove);
|
|
28
|
+
}
|
|
29
|
+
return stepsIds;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const getWizardStepIds = (
|
|
33
|
+
wizardStepIds: ClusterWizardStepsType[] | undefined,
|
|
34
|
+
staticIpView?: StaticIpView | 'dhcp-selected',
|
|
35
|
+
isSingleClusterFeatureEnabled?: boolean,
|
|
36
|
+
): ClusterWizardStepsType[] => {
|
|
37
|
+
let stepsCopy = wizardStepIds ? [...wizardStepIds] : [...defaultWizardSteps];
|
|
38
|
+
if (staticIpView === StaticIpView.YAML) {
|
|
39
|
+
stepsCopy = removeStepFromClusterWizard(stepsCopy, 'static-ip-network-wide-configurations', 2);
|
|
40
|
+
stepsCopy = addStepToClusterWizard(stepsCopy, 'cluster-details', ['static-ip-yaml-view']);
|
|
41
|
+
} else if (staticIpView === StaticIpView.FORM) {
|
|
42
|
+
stepsCopy = removeStepFromClusterWizard(stepsCopy, 'static-ip-yaml-view', 1);
|
|
43
|
+
stepsCopy = addStepToClusterWizard(stepsCopy, 'cluster-details', staticIpFormViewSubSteps);
|
|
44
|
+
} else if (staticIpView === 'dhcp-selected') {
|
|
45
|
+
stepsCopy = removeStepFromClusterWizard(stepsCopy, 'static-ip-network-wide-configurations', 2);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (isSingleClusterFeatureEnabled && !stepsCopy.includes('credentials-download')) {
|
|
49
|
+
stepsCopy = addStepToClusterWizard(stepsCopy, 'custom-manifests', ['credentials-download']);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return stepsCopy;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const getDisconnectedWizardStepIds = (
|
|
56
|
+
staticIpView?: StaticIpView | 'dhcp-selected',
|
|
57
|
+
): ClusterWizardStepsType[] => {
|
|
58
|
+
// Always rebuild from the base disconnected steps so toggling static IP / DHCP
|
|
59
|
+
// cannot leave leftover sub-steps in the list.
|
|
60
|
+
const copy = [...disconnectedSteps];
|
|
61
|
+
|
|
62
|
+
if (staticIpView === StaticIpView.YAML) {
|
|
63
|
+
return addStepToClusterWizard(copy, 'disconnected-optional-configurations', [
|
|
64
|
+
'static-ip-yaml-view',
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
if (staticIpView === StaticIpView.FORM) {
|
|
68
|
+
return addStepToClusterWizard(copy, 'disconnected-optional-configurations', [
|
|
69
|
+
'static-ip-network-wide-configurations',
|
|
70
|
+
'static-ip-host-configurations',
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return copy;
|
|
75
|
+
};
|
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Content, Split, SplitItem } from '@patternfly/react-core';
|
|
3
|
-
import {
|
|
4
|
-
ASSISTED_INSTALLER_DOCUMENTATION_LINK,
|
|
5
|
-
TechnologyPreview,
|
|
6
|
-
ExternalLink,
|
|
7
|
-
isInOcm,
|
|
8
|
-
} from '../../../common';
|
|
9
|
-
import { useFeature } from '../../hooks/use-feature';
|
|
3
|
+
import { ASSISTED_INSTALLER_DOCUMENTATION_LINK, ExternalLink, isInOcm } from '../../../common';
|
|
10
4
|
|
|
11
5
|
type AssistedInstallerHeaderProps = {
|
|
12
6
|
clusterName?: string;
|
|
13
7
|
};
|
|
14
8
|
|
|
15
9
|
export const AssistedInstallerHeader = ({ clusterName }: AssistedInstallerHeaderProps) => {
|
|
16
|
-
const isSingleClusterFeatureEnabled = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE');
|
|
17
10
|
return (
|
|
18
11
|
<>
|
|
19
12
|
<Content component="h1" className="pf-v6-u-display-inline">
|
|
20
13
|
{clusterName || 'Install OpenShift with the Assisted Installer'}
|
|
21
14
|
</Content>
|
|
22
|
-
{isSingleClusterFeatureEnabled && <TechnologyPreview />}
|
|
23
15
|
<Split hasGutter>
|
|
24
16
|
<SplitItem>
|
|
25
17
|
<ExternalLink href={ASSISTED_INSTALLER_DOCUMENTATION_LINK}>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@openshift-assisted/locales": "2.55.
|
|
4
|
-
"@openshift-assisted/types": "2.55.
|
|
3
|
+
"@openshift-assisted/locales": "2.55.3",
|
|
4
|
+
"@openshift-assisted/types": "2.55.3",
|
|
5
5
|
"@openshift-console/dynamic-plugin-sdk": "^4.22.0",
|
|
6
6
|
"@patternfly/patternfly": "6.4.0",
|
|
7
7
|
"@patternfly/react-code-editor": "6.4.1",
|
|
@@ -136,5 +136,5 @@
|
|
|
136
136
|
]
|
|
137
137
|
}
|
|
138
138
|
},
|
|
139
|
-
"version": "2.55.
|
|
139
|
+
"version": "2.55.3"
|
|
140
140
|
}
|