@openshift-assisted/ui-lib 2.54.2 → 2.55.1

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.
Files changed (197) hide show
  1. package/build/@types/cim/components/modals/CimConfiguration/CimStorageMissingAlert.d.ts.map +1 -1
  2. package/build/@types/cim/components/modals/CimConfiguration/constants.d.ts +1 -1
  3. package/build/@types/common/api/assisted-service/ClustersAPI.d.ts +2 -1
  4. package/build/@types/common/api/assisted-service/ClustersAPI.d.ts.map +1 -1
  5. package/build/@types/common/components/clusterConfiguration/utils.d.ts +9 -1
  6. package/build/@types/common/components/clusterConfiguration/utils.d.ts.map +1 -1
  7. package/build/@types/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.d.ts.map +1 -1
  8. package/build/@types/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.d.ts.map +1 -1
  9. package/build/@types/common/components/operators/operatorSpecs.d.ts.map +1 -1
  10. package/build/@types/common/components/ui/formik/PullSecretField.d.ts +1 -0
  11. package/build/@types/common/components/ui/formik/PullSecretField.d.ts.map +1 -1
  12. package/build/@types/common/config/docs_links.d.ts.map +1 -1
  13. package/build/@types/common/types/clusters.d.ts +1 -1
  14. package/build/@types/common/types/clusters.d.ts.map +1 -1
  15. package/build/@types/ocm/components/Routes.d.ts +1 -1
  16. package/build/@types/ocm/components/Routes.d.ts.map +1 -1
  17. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.d.ts +10 -2
  18. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.d.ts.map +1 -1
  19. package/build/@types/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.d.ts.map +1 -1
  20. package/build/@types/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.d.ts.map +1 -1
  21. package/build/@types/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.d.ts.map +1 -1
  22. package/build/@types/ocm/components/clusterConfiguration/review/utils.d.ts +1 -1
  23. package/build/@types/ocm/components/clusterConfiguration/review/utils.d.ts.map +1 -1
  24. package/build/@types/ocm/components/clusterDetail/AssistedInstallerDetailCard.d.ts +1 -1
  25. package/build/@types/ocm/components/clusterDetail/AssistedInstallerDetailCard.d.ts.map +1 -1
  26. package/build/@types/ocm/components/clusterWizard/ClusterWizardContext.d.ts +5 -0
  27. package/build/@types/ocm/components/clusterWizard/ClusterWizardContext.d.ts.map +1 -1
  28. package/build/@types/ocm/components/clusterWizard/ClusterWizardContextProvider.d.ts.map +1 -1
  29. package/build/@types/ocm/components/clusterWizard/NewClusterWizard.d.ts.map +1 -1
  30. package/build/@types/ocm/components/clusterWizard/constants.d.ts.map +1 -1
  31. package/build/@types/ocm/components/clusterWizard/disconnected/BasicStep.d.ts +1 -0
  32. package/build/@types/ocm/components/clusterWizard/disconnected/BasicStep.d.ts.map +1 -1
  33. package/build/@types/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.d.ts +4 -0
  34. package/build/@types/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.d.ts.map +1 -0
  35. package/build/@types/ocm/components/clusterWizard/disconnected/ReviewStep.d.ts.map +1 -1
  36. package/build/@types/ocm/components/clusterWizard/wizardTransition.d.ts +1 -1
  37. package/build/@types/ocm/components/clusterWizard/wizardTransition.d.ts.map +1 -1
  38. package/build/@types/ocm/components/ui/Buttons/BackButton.d.ts +1 -1
  39. package/build/@types/ocm/components/ui/Buttons/BackButton.d.ts.map +1 -1
  40. package/build/@types/ocm/services/ClustersService.d.ts +2 -1
  41. package/build/@types/ocm/services/ClustersService.d.ts.map +1 -1
  42. package/build/@types/ocm/store/hooks.d.ts +1 -1
  43. package/build/@types/ocm/store/slices/clusters/selectors.d.ts +5 -61
  44. package/build/@types/ocm/store/slices/clusters/selectors.d.ts.map +1 -1
  45. package/build/@types/ocm/store/slices/feature-flags/selectors.d.ts +2 -20
  46. package/build/@types/ocm/store/slices/feature-flags/selectors.d.ts.map +1 -1
  47. package/build/@types/ocm/store/slices/infra-envs/selectors.d.ts +4 -21
  48. package/build/@types/ocm/store/slices/infra-envs/selectors.d.ts.map +1 -1
  49. package/build/cjs/cim/components/Agent/NoAgentsAlert.js +2 -2
  50. package/build/cjs/cim/components/Agent/NoAgentsAlert.js.map +1 -1
  51. package/build/cjs/cim/components/Agent/tableColumns.js +3 -3
  52. package/build/cjs/cim/components/Agent/tableColumns.js.map +1 -1
  53. package/build/cjs/cim/components/Hypershift/DetailsPage/NodePoolsTable.js +2 -2
  54. package/build/cjs/cim/components/Hypershift/DetailsPage/NodePoolsTable.js.map +1 -1
  55. package/build/cjs/cim/components/InfraEnv/AddHostDropdown.js +2 -2
  56. package/build/cjs/cim/components/InfraEnv/AddHostDropdown.js.map +1 -1
  57. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigProgressAlert.js +3 -3
  58. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigProgressAlert.js.map +1 -1
  59. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationFormFields.js +1 -1
  60. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationFormFields.js.map +1 -1
  61. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationModal.js +2 -2
  62. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationModal.js.map +1 -1
  63. package/build/cjs/cim/components/modals/CimConfiguration/CimStorageMissingAlert.js +3 -3
  64. package/build/cjs/cim/components/modals/CimConfiguration/CimStorageMissingAlert.js.map +1 -1
  65. package/build/cjs/cim/components/modals/CimConfiguration/constants.js +1 -1
  66. package/build/cjs/cim/components/modals/MassDeleteAgentModal.js +2 -2
  67. package/build/cjs/cim/components/modals/MassDeleteAgentModal.js.map +1 -1
  68. package/build/cjs/common/api/assisted-service/ClustersAPI.js +3 -0
  69. package/build/cjs/common/api/assisted-service/ClustersAPI.js.map +1 -1
  70. package/build/cjs/common/components/clusterConfiguration/utils.js +13 -1
  71. package/build/cjs/common/components/clusterConfiguration/utils.js.map +1 -1
  72. package/build/cjs/common/components/clusterConfiguration/utils.test.js +36 -0
  73. package/build/cjs/common/components/clusterConfiguration/utils.test.js.map +1 -1
  74. package/build/cjs/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.js +29 -31
  75. package/build/cjs/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.js.map +1 -1
  76. package/build/cjs/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.js +19 -30
  77. package/build/cjs/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.js.map +1 -1
  78. package/build/cjs/common/components/operators/operatorSpecs.js +0 -3
  79. package/build/cjs/common/components/operators/operatorSpecs.js.map +1 -1
  80. package/build/cjs/common/components/ui/formik/PullSecretField.js +2 -2
  81. package/build/cjs/common/components/ui/formik/PullSecretField.js.map +1 -1
  82. package/build/cjs/common/config/docs_links.js +2 -2
  83. package/build/cjs/common/config/docs_links.js.map +1 -1
  84. package/build/cjs/common/validationSchemas/addressValidation.js +1 -1
  85. package/build/cjs/common/validationSchemas/addressValidation.js.map +1 -1
  86. package/build/cjs/ocm/components/Routes.js +8 -8
  87. package/build/cjs/ocm/components/Routes.js.map +1 -1
  88. package/build/cjs/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.js.map +1 -1
  89. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.js.map +1 -1
  90. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.js +68 -17
  91. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.js.map +1 -1
  92. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.js +1 -1
  93. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.js.map +1 -1
  94. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.js +50 -13
  95. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.js.map +1 -1
  96. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.js +4 -2
  97. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.js.map +1 -1
  98. package/build/cjs/ocm/components/clusterConfiguration/review/utils.js +7 -1
  99. package/build/cjs/ocm/components/clusterConfiguration/review/utils.js.map +1 -1
  100. package/build/cjs/ocm/components/clusterConfiguration/review/utils.test.js +35 -0
  101. package/build/cjs/ocm/components/clusterConfiguration/review/utils.test.js.map +1 -1
  102. package/build/cjs/ocm/components/clusterDetail/AssistedInstallerDetailCard.js +4 -4
  103. package/build/cjs/ocm/components/clusterDetail/AssistedInstallerDetailCard.js.map +1 -1
  104. package/build/cjs/ocm/components/clusterDetail/ClusterDetail.js +4 -4
  105. package/build/cjs/ocm/components/clusterDetail/ClusterDetail.js.map +1 -1
  106. package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js +4 -4
  107. package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js.map +1 -1
  108. package/build/cjs/ocm/components/clusterWizard/ClusterDetailsForm.js +2 -2
  109. package/build/cjs/ocm/components/clusterWizard/ClusterDetailsForm.js.map +1 -1
  110. package/build/cjs/ocm/components/clusterWizard/ClusterWizardContext.js.map +1 -1
  111. package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js +11 -2
  112. package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js.map +1 -1
  113. package/build/cjs/ocm/components/clusterWizard/ClusterWizardFooter.js +2 -2
  114. package/build/cjs/ocm/components/clusterWizard/ClusterWizardFooter.js.map +1 -1
  115. package/build/cjs/ocm/components/clusterWizard/NewClusterWizard.js +3 -0
  116. package/build/cjs/ocm/components/clusterWizard/NewClusterWizard.js.map +1 -1
  117. package/build/cjs/ocm/components/clusterWizard/Operators.js +4 -4
  118. package/build/cjs/ocm/components/clusterWizard/Operators.js.map +1 -1
  119. package/build/cjs/ocm/components/clusterWizard/constants.js +1 -0
  120. package/build/cjs/ocm/components/clusterWizard/constants.js.map +1 -1
  121. package/build/cjs/ocm/components/clusterWizard/disconnected/BasicStep.js +16 -22
  122. package/build/cjs/ocm/components/clusterWizard/disconnected/BasicStep.js.map +1 -1
  123. package/build/cjs/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.js +102 -0
  124. package/build/cjs/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.js.map +1 -0
  125. package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js +10 -8
  126. package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js.map +1 -1
  127. package/build/cjs/ocm/components/clusterWizard/wizardTransition.js +3 -0
  128. package/build/cjs/ocm/components/clusterWizard/wizardTransition.js.map +1 -1
  129. package/build/cjs/ocm/components/clusters/ClusterBreadcrumbs.js +2 -2
  130. package/build/cjs/ocm/components/clusters/ClusterBreadcrumbs.js.map +1 -1
  131. package/build/cjs/ocm/components/clusters/ClusterPage.js +4 -4
  132. package/build/cjs/ocm/components/clusters/ClusterPage.js.map +1 -1
  133. package/build/cjs/ocm/components/clusters/Clusters.js +3 -3
  134. package/build/cjs/ocm/components/clusters/Clusters.js.map +1 -1
  135. package/build/cjs/ocm/components/clusters/ClustersListToolbar.js +3 -3
  136. package/build/cjs/ocm/components/clusters/ClustersListToolbar.js.map +1 -1
  137. package/build/cjs/ocm/components/ui/Buttons/BackButton.js +2 -2
  138. package/build/cjs/ocm/components/ui/Buttons/BackButton.js.map +1 -1
  139. package/build/cjs/ocm/services/ClustersService.js +3 -0
  140. package/build/cjs/ocm/services/ClustersService.js.map +1 -1
  141. package/build/cjs/ocm/store/slices/clusters/selectors.js +2 -2
  142. package/build/cjs/ocm/store/slices/clusters/selectors.js.map +1 -1
  143. package/build/cjs/ocm/store/slices/feature-flags/selectors.js.map +1 -1
  144. package/build/cjs/ocm/store/slices/infra-envs/selectors.js.map +1 -1
  145. package/lib/cim/components/Agent/NoAgentsAlert.tsx +1 -1
  146. package/lib/cim/components/Agent/tableColumns.tsx +1 -1
  147. package/lib/cim/components/Hypershift/DetailsPage/NodePoolsTable.tsx +1 -1
  148. package/lib/cim/components/InfraEnv/AddHostDropdown.tsx +1 -1
  149. package/lib/cim/components/modals/CimConfiguration/CimConfigProgressAlert.tsx +2 -2
  150. package/lib/cim/components/modals/CimConfiguration/CimConfigurationFormFields.tsx +1 -1
  151. package/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.tsx +2 -2
  152. package/lib/cim/components/modals/CimConfiguration/CimStorageMissingAlert.tsx +5 -2
  153. package/lib/cim/components/modals/CimConfiguration/constants.ts +1 -1
  154. package/lib/cim/components/modals/MassDeleteAgentModal.tsx +1 -1
  155. package/lib/common/api/assisted-service/ClustersAPI.ts +8 -0
  156. package/lib/common/components/clusterConfiguration/utils.test.ts +43 -1
  157. package/lib/common/components/clusterConfiguration/utils.ts +13 -0
  158. package/lib/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.tsx +31 -57
  159. package/lib/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.tsx +33 -38
  160. package/lib/common/components/operators/operatorSpecs.tsx +0 -16
  161. package/lib/common/components/ui/formik/PullSecretField.tsx +5 -2
  162. package/lib/common/config/docs_links.ts +2 -2
  163. package/lib/common/types/clusters.ts +1 -1
  164. package/lib/common/validationSchemas/addressValidation.tsx +2 -2
  165. package/lib/ocm/components/Routes.tsx +2 -2
  166. package/lib/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.tsx +2 -2
  167. package/lib/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.tsx +2 -2
  168. package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx +86 -22
  169. package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.tsx +2 -2
  170. package/lib/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.ts +57 -20
  171. package/lib/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.tsx +4 -2
  172. package/lib/ocm/components/clusterConfiguration/review/utils.test.ts +41 -0
  173. package/lib/ocm/components/clusterConfiguration/review/utils.tsx +5 -2
  174. package/lib/ocm/components/clusterDetail/AssistedInstallerDetailCard.tsx +1 -1
  175. package/lib/ocm/components/clusterDetail/ClusterDetail.tsx +3 -3
  176. package/lib/ocm/components/clusterWizard/ClusterDetails.tsx +2 -2
  177. package/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx +1 -1
  178. package/lib/ocm/components/clusterWizard/ClusterWizardContext.tsx +5 -0
  179. package/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx +10 -1
  180. package/lib/ocm/components/clusterWizard/ClusterWizardFooter.tsx +1 -1
  181. package/lib/ocm/components/clusterWizard/NewClusterWizard.tsx +3 -0
  182. package/lib/ocm/components/clusterWizard/Operators.tsx +2 -2
  183. package/lib/ocm/components/clusterWizard/constants.ts +1 -0
  184. package/lib/ocm/components/clusterWizard/disconnected/BasicStep.tsx +31 -52
  185. package/lib/ocm/components/clusterWizard/disconnected/OptionalConfigurationsStep.tsx +173 -0
  186. package/lib/ocm/components/clusterWizard/disconnected/ReviewStep.tsx +11 -9
  187. package/lib/ocm/components/clusterWizard/wizardTransition.ts +4 -0
  188. package/lib/ocm/components/clusters/ClusterBreadcrumbs.tsx +1 -1
  189. package/lib/ocm/components/clusters/ClusterPage.tsx +1 -1
  190. package/lib/ocm/components/clusters/Clusters.tsx +2 -2
  191. package/lib/ocm/components/clusters/ClustersListToolbar.tsx +2 -2
  192. package/lib/ocm/components/ui/Buttons/BackButton.tsx +1 -1
  193. package/lib/ocm/services/ClustersService.ts +5 -0
  194. package/lib/ocm/store/slices/clusters/selectors.tsx +7 -5
  195. package/lib/ocm/store/slices/feature-flags/selectors.ts +5 -2
  196. package/lib/ocm/store/slices/infra-envs/selectors.ts +4 -2
  197. package/package.json +8 -8
@@ -1,6 +1,6 @@
1
1
  import * as Yup from 'yup';
2
2
  import { TFunction } from 'i18next';
3
- import { CustomManifestValues, ManifestFormData } from '../data/dataTypes';
3
+ import { CustomManifestValues } from '../data/dataTypes';
4
4
  import {
5
5
  getMaxFileSizeMessage,
6
6
  validateFileSize,
@@ -62,7 +62,7 @@ const INCORRECT_FILENAME =
62
62
  const UNIQUE_FOLDER_FILENAME = 'Ensure unique file names to avoid conflicts and errors.';
63
63
 
64
64
  export const getFormViewManifestsValidationSchema = (t: TFunction) =>
65
- Yup.object<ManifestFormData>({
65
+ Yup.object({
66
66
  manifests: Yup.array<CustomManifestValues>()
67
67
  .of(
68
68
  Yup.object({
@@ -6,13 +6,16 @@ import {
6
6
  canBeDualStack,
7
7
  CpuArchitecture,
8
8
  DUAL_STACK,
9
+ getIPv6FromDualstack,
9
10
  HostSubnets,
10
11
  isAdvNetworkConf,
11
12
  isSNO,
12
13
  NetworkConfigurationValues,
14
+ NO_SUBNET_SET,
13
15
  selectApiVip,
14
16
  selectIngressVip,
15
17
  } from '../../../../common';
18
+ import { Address6 } from 'ip-address';
16
19
  import {
17
20
  ManagedNetworkingControlGroup,
18
21
  UserManagedNetworkingTextContent,
@@ -36,6 +39,7 @@ import {
36
39
  } from '@openshift-assisted/types/assisted-installer-service';
37
40
  import useSupportLevelsAPI from '../../../hooks/useSupportLevelsAPI';
38
41
  import { isOciPlatformType } from '../../utils';
42
+ import { useFeature } from '../../../hooks/use-feature';
39
43
 
40
44
  export type NetworkConfigurationProps = VirtualIPControlGroupProps & {
41
45
  hostSubnets: HostSubnets;
@@ -122,6 +126,33 @@ const getManagedNetworkingState = (
122
126
  };
123
127
  };
124
128
 
129
+ type DefaultNetworkSettings = NetworkConfigurationProps['defaultNetworkSettings'];
130
+
131
+ const getNetworkDefaultsByFamily = (
132
+ settings: DefaultNetworkSettings,
133
+ isDualStack: boolean,
134
+ isIPv6: boolean,
135
+ ) => {
136
+ if (isDualStack) {
137
+ return {
138
+ clusterNetworkDefaults: settings.clusterNetworksDualstack,
139
+ serviceNetworkDefaults: settings.serviceNetworksDualstack,
140
+ };
141
+ }
142
+ if (isIPv6) {
143
+ const ipv6Cluster = getIPv6FromDualstack(settings.clusterNetworksDualstack);
144
+ const ipv6Service = getIPv6FromDualstack(settings.serviceNetworksDualstack);
145
+ return {
146
+ clusterNetworkDefaults: ipv6Cluster ? [ipv6Cluster] : settings.clusterNetworksIpv4,
147
+ serviceNetworkDefaults: ipv6Service ? [ipv6Service] : settings.serviceNetworksIpv4,
148
+ };
149
+ }
150
+ return {
151
+ clusterNetworkDefaults: settings.clusterNetworksIpv4,
152
+ serviceNetworkDefaults: settings.serviceNetworksIpv4,
153
+ };
154
+ };
155
+
125
156
  const NetworkConfiguration = ({
126
157
  cluster,
127
158
  hostSubnets,
@@ -136,8 +167,10 @@ const NetworkConfiguration = ({
136
167
  cluster.platform?.type,
137
168
  );
138
169
  const { isViewerMode } = useSelector(selectCurrentClusterPermissionsState);
139
- const { setFieldValue, values, validateField } = useFormikContext<NetworkConfigurationValues>();
170
+ const { setFieldValue, values, validateField, validateForm } =
171
+ useFormikContext<NetworkConfigurationValues>();
140
172
 
173
+ const isSingleClusterFeature = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE');
141
174
  const isSNOCluster = isSNO(cluster);
142
175
  const isUserManagedNetworking = values.managedNetworkingType === 'userManaged';
143
176
  const isDualStack = values.stackType === DUAL_STACK;
@@ -177,30 +210,18 @@ const NetworkConfiguration = ({
177
210
  setAdvanced(checked);
178
211
 
179
212
  if (!checked) {
180
- setFieldValue(
181
- 'clusterNetworks',
182
- isDualStack
183
- ? defaultNetworkSettings.clusterNetworksDualstack
184
- : defaultNetworkSettings.clusterNetworksIpv4,
185
- true,
186
- );
187
- setFieldValue(
188
- 'serviceNetworks',
189
- isDualStack
190
- ? defaultNetworkSettings.serviceNetworksDualstack
191
- : defaultNetworkSettings.serviceNetworksIpv4,
192
- true,
213
+ const primaryCidr = values.machineNetworks?.[0]?.cidr;
214
+ const isIPv6Stack = !!primaryCidr && Address6.isValid(primaryCidr);
215
+ const { clusterNetworkDefaults, serviceNetworkDefaults } = getNetworkDefaultsByFamily(
216
+ defaultNetworkSettings,
217
+ isDualStack,
218
+ isIPv6Stack,
193
219
  );
220
+ setFieldValue('clusterNetworks', clusterNetworkDefaults, true);
221
+ setFieldValue('serviceNetworks', serviceNetworkDefaults, true);
194
222
  }
195
223
  },
196
- [
197
- setFieldValue,
198
- isDualStack,
199
- defaultNetworkSettings.clusterNetworksDualstack,
200
- defaultNetworkSettings.clusterNetworksIpv4,
201
- defaultNetworkSettings.serviceNetworksDualstack,
202
- defaultNetworkSettings.serviceNetworksIpv4,
203
- ],
224
+ [setFieldValue, isDualStack, values.machineNetworks, defaultNetworkSettings],
204
225
  );
205
226
 
206
227
  React.useEffect(() => {
@@ -209,6 +230,47 @@ const NetworkConfiguration = ({
209
230
  }
210
231
  }, [isDualStack, isViewerMode, toggleAdvConfiguration]);
211
232
 
233
+ React.useEffect(() => {
234
+ if (!isSingleClusterFeature || isViewerMode || isDualStack || isAdvanced) {
235
+ return;
236
+ }
237
+ const primaryCidr = values.machineNetworks?.[0]?.cidr;
238
+ if (!primaryCidr || primaryCidr === NO_SUBNET_SET) {
239
+ return;
240
+ }
241
+ const isIPv6 = Address6.isValid(primaryCidr);
242
+ const currentClusterCidr = values.clusterNetworks?.[0]?.cidr;
243
+ const clusterIsIPv6 = currentClusterCidr ? Address6.isValid(currentClusterCidr) : null;
244
+
245
+ if (clusterIsIPv6 === isIPv6) {
246
+ return;
247
+ }
248
+
249
+ const { clusterNetworkDefaults, serviceNetworkDefaults } = getNetworkDefaultsByFamily(
250
+ defaultNetworkSettings,
251
+ false,
252
+ isIPv6,
253
+ );
254
+ if (clusterNetworkDefaults) {
255
+ setFieldValue('clusterNetworks', clusterNetworkDefaults);
256
+ }
257
+ if (serviceNetworkDefaults) {
258
+ setFieldValue('serviceNetworks', serviceNetworkDefaults);
259
+ }
260
+ void validateForm();
261
+ }, [
262
+ isSingleClusterFeature,
263
+ isViewerMode,
264
+ isDualStack,
265
+ isAdvanced,
266
+ values.machineNetworks,
267
+ values.clusterNetworks,
268
+ defaultNetworkSettings,
269
+ setFieldValue,
270
+ validateForm,
271
+ cluster.id,
272
+ ]);
273
+
212
274
  const managedNetworkingState = React.useMemo(
213
275
  () =>
214
276
  getManagedNetworkingState(
@@ -252,6 +314,7 @@ const NetworkConfiguration = ({
252
314
  hostSubnets={hostSubnets}
253
315
  defaultNetworkValues={defaultNetworkSettings}
254
316
  isViewerMode={isViewerMode}
317
+ allowSingleStackIPv6={isSingleClusterFeature}
255
318
  />
256
319
  </StackItem>
257
320
  )}
@@ -277,6 +340,7 @@ const NetworkConfiguration = ({
277
340
  }
278
341
  openshiftVersion={cluster.openshiftVersion}
279
342
  isViewerMode={isViewerMode}
343
+ allowSingleStackIPv6={isSingleClusterFeature}
280
344
  />
281
345
  </StackItem>
282
346
  )}
@@ -9,7 +9,7 @@ import {
9
9
  getFormikErrorFields,
10
10
  getHostSubnets,
11
11
  HostSubnets,
12
- SINGLE_STACK,
12
+ DUAL_STACK,
13
13
  isSNO,
14
14
  LoadingState,
15
15
  NetworkConfigurationValues,
@@ -262,7 +262,7 @@ const NetworkConfigurationPage = ({ cluster }: { cluster: Cluster }) => {
262
262
  if (values.vipDhcpAllocation) {
263
263
  delete params.apiVips;
264
264
  delete params.ingressVips;
265
- } else if (values.stackType === SINGLE_STACK) {
265
+ } else if (values.stackType !== DUAL_STACK) {
266
266
  // The API will rebuild the default machineNetwork
267
267
  params.machineNetworks = [];
268
268
  }
@@ -1,8 +1,11 @@
1
1
  import * as Yup from 'yup';
2
2
  import { TFunction } from 'i18next';
3
+ import { Address6 } from 'ip-address';
3
4
  import {
4
5
  clusterNetworksValidationSchema,
5
6
  dualStackValidationSchema,
7
+ getIPv6FromDualstack,
8
+ isPrimaryIPv6,
6
9
  HostSubnets,
7
10
  isDualStack,
8
11
  isSNO,
@@ -10,6 +13,7 @@ import {
10
13
  NetworkConfigurationValues,
11
14
  serviceNetworkValidationSchema,
12
15
  IPv4ValidationSchema,
16
+ IPv6ValidationSchema,
13
17
  sshPublicKeyValidationSchema,
14
18
  SINGLE_STACK,
15
19
  DUAL_STACK,
@@ -36,6 +40,38 @@ export const getNetworkInitialValues = (
36
40
  ): NetworkConfigurationValues => {
37
41
  const isSNOCluster = isSNO(cluster);
38
42
  const isDualStackType = isDualStack(cluster);
43
+ const primaryMachineNetworkCidr = cluster.machineNetworks?.[0]?.cidr;
44
+ const isIPv6OnlyStack =
45
+ !isDualStackType && !!primaryMachineNetworkCidr && Address6.isValid(primaryMachineNetworkCidr);
46
+
47
+ const getStackType = (): NetworkConfigurationValues['stackType'] => {
48
+ if (isDualStackType) return DUAL_STACK;
49
+ return SINGLE_STACK;
50
+ };
51
+
52
+ const getDefaultClusterNetworks = () => {
53
+ if (isDualStackType) return defaultNetworkValues.clusterNetworksDualstack;
54
+ if (isIPv6OnlyStack) {
55
+ const ipv6Entry = getIPv6FromDualstack(defaultNetworkValues.clusterNetworksDualstack);
56
+ return ipv6Entry ? [{ ...ipv6Entry, clusterId: cluster?.id }] : undefined;
57
+ }
58
+ return defaultNetworkValues.clusterNetworksIpv4?.map((network) => ({
59
+ ...network,
60
+ clusterId: cluster?.id,
61
+ }));
62
+ };
63
+
64
+ const getDefaultServiceNetworks = () => {
65
+ if (isDualStackType) return defaultNetworkValues.serviceNetworksDualstack;
66
+ if (isIPv6OnlyStack) {
67
+ const ipv6Entry = getIPv6FromDualstack(defaultNetworkValues.serviceNetworksDualstack);
68
+ return ipv6Entry ? [{ ...ipv6Entry, clusterId: cluster?.id }] : undefined;
69
+ }
70
+ return defaultNetworkValues.serviceNetworksIpv4?.map((network) => ({
71
+ ...network,
72
+ clusterId: cluster?.id,
73
+ }));
74
+ };
39
75
 
40
76
  return {
41
77
  apiVips: cluster.apiVips,
@@ -50,23 +86,9 @@ export const getNetworkInitialValues = (
50
86
  : 'clusterManaged',
51
87
  networkType: cluster.networkType || NETWORK_TYPE_OVN,
52
88
  machineNetworks: cluster.machineNetworks || [],
53
- stackType: isDualStackType ? DUAL_STACK : SINGLE_STACK,
54
- clusterNetworks:
55
- cluster.clusterNetworks ||
56
- (isDualStackType
57
- ? defaultNetworkValues.clusterNetworksDualstack
58
- : defaultNetworkValues.clusterNetworksIpv4?.map((network) => ({
59
- ...network,
60
- clusterId: cluster?.id,
61
- }))),
62
- serviceNetworks:
63
- cluster.serviceNetworks ||
64
- (isDualStackType
65
- ? defaultNetworkValues.serviceNetworksDualstack
66
- : defaultNetworkValues.serviceNetworksIpv4?.map((network) => ({
67
- ...network,
68
- clusterId: cluster?.id,
69
- }))),
89
+ stackType: getStackType(),
90
+ clusterNetworks: cluster.clusterNetworks || getDefaultClusterNetworks(),
91
+ serviceNetworks: cluster.serviceNetworks || getDefaultServiceNetworks(),
70
92
  };
71
93
  };
72
94
 
@@ -87,7 +109,12 @@ export const getNetworkConfigurationValidationSchema = (
87
109
  : machineNetworksValidationSchema.when('stackType', {
88
110
  is: (stackType: NetworkConfigurationValues['stackType']) =>
89
111
  stackType === SINGLE_STACK,
90
- then: () => machineNetworksValidationSchema.concat(IPv4ValidationSchema),
112
+ then: () => {
113
+ if (isPrimaryIPv6(values.machineNetworks)) {
114
+ return machineNetworksValidationSchema.concat(IPv6ValidationSchema);
115
+ }
116
+ return machineNetworksValidationSchema.concat(IPv4ValidationSchema);
117
+ },
91
118
  otherwise: () =>
92
119
  values.machineNetworks && values.machineNetworks?.length >= 2
93
120
  ? machineNetworksValidationSchema.concat(
@@ -97,13 +124,23 @@ export const getNetworkConfigurationValidationSchema = (
97
124
  }),
98
125
  clusterNetworks: clusterNetworksValidationSchema(t).when('stackType', {
99
126
  is: (stackType: NetworkConfigurationValues['stackType']) => stackType === SINGLE_STACK,
100
- then: (schema) => schema.concat(IPv4ValidationSchema),
127
+ then: (schema) => {
128
+ if (isPrimaryIPv6(values.machineNetworks)) {
129
+ return schema.concat(IPv6ValidationSchema);
130
+ }
131
+ return schema.concat(IPv4ValidationSchema);
132
+ },
101
133
  otherwise: (schema) =>
102
134
  schema.concat(dualStackValidationSchema('cluster network', t, openshiftVersion)),
103
135
  }),
104
136
  serviceNetworks: serviceNetworkValidationSchema(t).when('stackType', {
105
137
  is: (stackType: NetworkConfigurationValues['stackType']) => stackType === SINGLE_STACK,
106
- then: (schema) => schema.concat(IPv4ValidationSchema),
138
+ then: (schema) => {
139
+ if (isPrimaryIPv6(values.machineNetworks)) {
140
+ return schema.concat(IPv6ValidationSchema);
141
+ }
142
+ return schema.concat(IPv4ValidationSchema);
143
+ },
107
144
  otherwise: (schema) =>
108
145
  schema.concat(dualStackValidationSchema('service network', t, openshiftVersion)),
109
146
  }),
@@ -8,6 +8,7 @@ import {
8
8
  useTranslation,
9
9
  } from '../../../../common';
10
10
  import { getManagementType, getStackTypeLabel } from './utils';
11
+ import { useFeature } from '../../../hooks/use-feature';
11
12
  import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
12
13
 
13
14
  type ReviewTableRowsType = {
@@ -17,6 +18,7 @@ type ReviewTableRowsType = {
17
18
 
18
19
  export const ReviewNetworkingTable = ({ cluster }: { cluster: Cluster }) => {
19
20
  const { t } = useTranslation();
21
+ const isSingleClusterFeature = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE');
20
22
  const rows = React.useMemo(() => {
21
23
  const networkRows = [
22
24
  {
@@ -34,7 +36,7 @@ export const ReviewNetworkingTable = ({ cluster }: { cluster: Cluster }) => {
34
36
  cells: [
35
37
  { title: 'Stack type', colSpan: 2 },
36
38
  {
37
- title: getStackTypeLabel(cluster),
39
+ title: getStackTypeLabel(cluster, isSingleClusterFeature),
38
40
  props: { 'data-testid': 'stack-type', colSpan: 2 },
39
41
  },
40
42
  ],
@@ -125,7 +127,7 @@ export const ReviewNetworkingTable = ({ cluster }: { cluster: Cluster }) => {
125
127
  });
126
128
 
127
129
  return networkRows;
128
- }, [cluster]);
130
+ }, [cluster, isSingleClusterFeature]);
129
131
 
130
132
  const rowsAdvanced = React.useMemo(() => {
131
133
  return [
@@ -169,6 +169,47 @@ describe('getStackTypeLabel', () => {
169
169
  });
170
170
  });
171
171
 
172
+ describe('with isSingleClusterFeature=true', () => {
173
+ test('returns "Single stack" for IPv4 single-stack cluster', () => {
174
+ const cluster = createCluster({
175
+ machineNetworks: [createMachineNetwork('192.168.1.0/24')],
176
+ clusterNetworks: [createClusterNetwork('10.128.0.0/14', 23)],
177
+ serviceNetworks: [createServiceNetwork('172.30.0.0/16')],
178
+ });
179
+
180
+ expect(getStackTypeLabel(cluster, true)).toBe('Single stack');
181
+ });
182
+
183
+ test('returns "Single stack" for IPv6 single-stack cluster', () => {
184
+ const cluster = createCluster({
185
+ machineNetworks: [createMachineNetwork('2001:db8::/64')],
186
+ clusterNetworks: [createClusterNetwork('fd01::/48', 64)],
187
+ serviceNetworks: [createServiceNetwork('fd02::/112')],
188
+ });
189
+
190
+ expect(getStackTypeLabel(cluster, true)).toBe('Single stack');
191
+ });
192
+
193
+ test('still returns "Dual-stack" for dual-stack cluster', () => {
194
+ const cluster = createCluster({
195
+ machineNetworks: [
196
+ createMachineNetwork('192.168.1.0/24'),
197
+ createMachineNetwork('2001:db8::/64'),
198
+ ],
199
+ clusterNetworks: [
200
+ createClusterNetwork('10.128.0.0/14', 23),
201
+ createClusterNetwork('fd01::/48', 64),
202
+ ],
203
+ serviceNetworks: [
204
+ createServiceNetwork('172.30.0.0/16'),
205
+ createServiceNetwork('fd02::/112'),
206
+ ],
207
+ });
208
+
209
+ expect(getStackTypeLabel(cluster, true)).toBe('Dual-stack');
210
+ });
211
+ });
212
+
172
213
  describe('edge cases', () => {
173
214
  test('handles undefined openshiftVersion', () => {
174
215
  const cluster = createCluster({
@@ -5,8 +5,11 @@ import { Cluster, DiskEncryption } from '@openshift-assisted/types/assisted-inst
5
5
  export const getManagementType = ({ userManagedNetworking }: Cluster): string =>
6
6
  userManagedNetworking ? 'User-managed networking' : 'Cluster-managed networking';
7
7
 
8
- export const getStackTypeLabel = (cluster: Cluster): string =>
9
- isDualStack(cluster) ? 'Dual-stack' : 'IPv4';
8
+ export const getStackTypeLabel = (cluster: Cluster, isSingleClusterFeature = false): string => {
9
+ if (isDualStack(cluster)) return 'Dual-stack';
10
+ if (isSingleClusterFeature) return 'Single stack';
11
+ return 'IPv4';
12
+ };
10
13
 
11
14
  export const getDiskEncryptionEnabledOnStatus = (diskEncryption: DiskEncryption['enableOn']) => {
12
15
  let diskEncryptionType = null;
@@ -33,7 +33,7 @@ import {
33
33
  unstable_HistoryRouter as HistoryRouter,
34
34
  HistoryRouterProps,
35
35
  BrowserRouter,
36
- } from 'react-router-dom-v5-compat';
36
+ } from 'react-router';
37
37
 
38
38
  type AssistedInstallerDetailCardProps = {
39
39
  aiClusterId: string;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { useNavigate } from 'react-router-dom-v5-compat';
2
+ import { useNavigate } from 'react-router';
3
3
  import { Stack, StackItem, Content, ButtonVariant, GridItem, Grid } from '@patternfly/react-core';
4
4
  import { ToolbarButton, Alerts, getEnabledHosts, selectOlmOperators, isSNO } from '../../../common';
5
5
  import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
@@ -41,7 +41,7 @@ const ClusterDetail: React.FC<ClusterDetailProps> = ({ cluster }) => {
41
41
  try {
42
42
  const { data } = await ClustersAPI.allowAddHosts(cluster.id);
43
43
  updateCluster(data);
44
- navigate(`${routeBasePath}/clusters/${cluster.id}`);
44
+ void navigate(`${routeBasePath}/clusters/${cluster.id}`);
45
45
  } catch (e) {
46
46
  handleApiError(e);
47
47
  }
@@ -102,7 +102,7 @@ const ClusterDetail: React.FC<ClusterDetailProps> = ({ cluster }) => {
102
102
  {!isSingleClusterFeatureEnabled && (
103
103
  <ToolbarButton
104
104
  variant={ButtonVariant.link}
105
- onClick={() => navigate('..')}
105
+ onClick={() => void navigate('..')}
106
106
  id={getClusterDetailId('button-back-to-all-clusters')}
107
107
  >
108
108
  Back to all clusters
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { useLocation, useNavigate } from 'react-router-dom-v5-compat';
2
+ import { useLocation, useNavigate } from 'react-router';
3
3
  import { useDispatch } from 'react-redux';
4
4
  import {
5
5
  useAlerts,
@@ -89,7 +89,7 @@ const ClusterDetails = ({ cluster, infraEnv }: ClusterDetailsProps) => {
89
89
  isAssistedMigration,
90
90
  isSingleClusterFeatureEnabled,
91
91
  );
92
- navigate(`../${cluster.id}`, { state: ClusterWizardFlowStateNew });
92
+ void navigate(`../${cluster.id}`, { state: ClusterWizardFlowStateNew });
93
93
 
94
94
  if (isAssistedMigration) {
95
95
  try {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { useSelector } from 'react-redux';
3
- import { useLocation } from 'react-router-dom-v5-compat';
3
+ import { useLocation } from 'react-router';
4
4
  import { Flex, Grid, GridItem } from '@patternfly/react-core';
5
5
  import isUndefined from 'lodash-es/isUndefined.js';
6
6
  import { Formik, FormikHelpers } from 'formik';
@@ -3,6 +3,7 @@ import { HostsNetworkConfigurationType } from '../../services';
3
3
  import { StaticIpView } from '../clusterConfiguration/staticIp/data/dataTypes';
4
4
  import { ClusterWizardStepsType } from './wizardTransition';
5
5
  import { UISettingsValues } from '../../../common';
6
+ import { Cluster, InfraEnv } from '@openshift-assisted/types/assisted-installer-service';
6
7
 
7
8
  export type ClusterWizardContextType = {
8
9
  currentStepId: ClusterWizardStepsType;
@@ -18,6 +19,10 @@ export type ClusterWizardContextType = {
18
19
  uiSettings?: UISettingsValues;
19
20
  installDisconnected: boolean;
20
21
  setInstallDisconnected: (enabled: boolean) => void;
22
+ disconnectedCluster?: Cluster;
23
+ setDisconnectedCluster: (cluster: Cluster | undefined) => void;
24
+ disconnectedInfraEnv?: InfraEnv;
25
+ setDisconnectedInfraEnv: (infraEnv: InfraEnv | undefined) => void;
21
26
  };
22
27
 
23
28
  export const ClusterWizardContext = React.createContext<ClusterWizardContextType | null>(null);
@@ -1,5 +1,5 @@
1
1
  import React, { PropsWithChildren } from 'react';
2
- import { useLocation } from 'react-router-dom-v5-compat';
2
+ import { useLocation } from 'react-router';
3
3
  import { ClusterWizardContextType, ClusterWizardContext } from './ClusterWizardContext';
4
4
  import {
5
5
  ClusterWizardFlowStateType,
@@ -88,6 +88,8 @@ const ClusterWizardContextProvider = ({
88
88
  const [connectedWizardStepIds, setWizardStepIds] = React.useState<ClusterWizardStepsType[]>();
89
89
  const [wizardPerPage, setWizardPerPage] = React.useState(10);
90
90
  const [installDisconnected, setInstallDisconnected] = React.useState(false);
91
+ const [disconnectedCluster, setDisconnectedCluster] = React.useState<Cluster | undefined>();
92
+ const [disconnectedInfraEnv, setDisconnectedInfraEnv] = React.useState<InfraEnv | undefined>();
91
93
  const location = useLocation();
92
94
  const locationState = location.state as ClusterWizardFlowStateType | undefined;
93
95
  const {
@@ -228,6 +230,10 @@ const ClusterWizardContextProvider = ({
228
230
  connectedWizardStepIds?.length && onSetCurrentStepId(connectedWizardStepIds[0]);
229
231
  }
230
232
  },
233
+ disconnectedCluster,
234
+ setDisconnectedCluster,
235
+ disconnectedInfraEnv,
236
+ setDisconnectedInfraEnv,
231
237
  };
232
238
  }, [
233
239
  wizardStepIds,
@@ -240,6 +246,9 @@ const ClusterWizardContextProvider = ({
240
246
  updateUISettings,
241
247
  installDisconnected,
242
248
  connectedWizardStepIds,
249
+ disconnectedCluster,
250
+ disconnectedInfraEnv,
251
+ setDisconnectedInfraEnv,
243
252
  ]);
244
253
 
245
254
  if (!contextValue) {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { useNavigate } from 'react-router-dom-v5-compat';
2
+ import { useNavigate } from 'react-router';
3
3
  import { Alert, AlertGroup, AlertVariant } from '@patternfly/react-core';
4
4
  import {
5
5
  WizardFooter,
@@ -4,6 +4,7 @@ import ClusterDetails from './ClusterDetails';
4
4
  import { useClusterWizardContext } from './ClusterWizardContext';
5
5
  import ReviewStep from './disconnected/ReviewStep';
6
6
  import BasicStep from './disconnected/BasicStep';
7
+ import OptionalConfigurationsStep from './disconnected/OptionalConfigurationsStep';
7
8
  import { ClusterWizardStepsType } from './wizardTransition';
8
9
  import { useInfraEnv } from '../../hooks';
9
10
  import { CpuArchitecture } from '../../../common/types';
@@ -13,6 +14,8 @@ const getCurrentStep = (currentStepId: ClusterWizardStepsType, infraEnv?: InfraE
13
14
  switch (currentStepId) {
14
15
  case 'disconnected-review':
15
16
  return <ReviewStep />;
17
+ case 'disconnected-optional-configurations':
18
+ return <OptionalConfigurationsStep />;
16
19
  case 'disconnected-basic':
17
20
  return <BasicStep />;
18
21
  default:
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { useDispatch } from 'react-redux';
3
- import { useLocation, useNavigate } from 'react-router-dom-v5-compat';
3
+ import { useLocation, useNavigate } from 'react-router';
4
4
  import { Formik, FormikConfig, useFormikContext } from 'formik';
5
5
  import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
6
6
  import {
@@ -74,7 +74,7 @@ const OperatorsForm = ({ cluster }: { cluster: Cluster }) => {
74
74
 
75
75
  const handleNext = () => {
76
76
  if (window.location.pathname.indexOf('assisted-installer') > -1) {
77
- navigate(pathname, { state: undefined, replace: true });
77
+ void navigate(pathname, { state: undefined, replace: true });
78
78
  }
79
79
  clusterWizardContext.moveNext();
80
80
  };
@@ -14,6 +14,7 @@ export const wizardStepNames: { [key in ClusterWizardStepsType]: string } = {
14
14
  'credentials-download': 'Download credentials',
15
15
  'disconnected-review': 'Review and download ISO',
16
16
  'disconnected-basic': 'Basic information',
17
+ 'disconnected-optional-configurations': 'Optional configurations',
17
18
  };
18
19
 
19
20
  export const defaultWizardSteps: ClusterWizardStepsType[] = [