@openshift-assisted/ui-lib 2.54.1 → 2.55.0

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 (180) 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/components/clusterConfiguration/DiscoveryImageConfigForm.d.ts.map +1 -1
  4. package/build/@types/common/components/clusterConfiguration/utils.d.ts +9 -1
  5. package/build/@types/common/components/clusterConfiguration/utils.d.ts.map +1 -1
  6. package/build/@types/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.d.ts.map +1 -1
  7. package/build/@types/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.d.ts.map +1 -1
  8. package/build/@types/common/components/operators/operatorSpecs.d.ts.map +1 -1
  9. package/build/@types/common/config/docs_links.d.ts.map +1 -1
  10. package/build/@types/common/utils.d.ts.map +1 -1
  11. package/build/@types/ocm/components/Routes.d.ts +1 -1
  12. package/build/@types/ocm/components/Routes.d.ts.map +1 -1
  13. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.d.ts +10 -2
  14. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.d.ts.map +1 -1
  15. package/build/@types/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.d.ts.map +1 -1
  16. package/build/@types/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.d.ts.map +1 -1
  17. package/build/@types/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.d.ts.map +1 -1
  18. package/build/@types/ocm/components/clusterConfiguration/review/utils.d.ts +1 -1
  19. package/build/@types/ocm/components/clusterConfiguration/review/utils.d.ts.map +1 -1
  20. package/build/@types/ocm/components/clusterDetail/AssistedInstallerDetailCard.d.ts +1 -1
  21. package/build/@types/ocm/components/clusterDetail/AssistedInstallerDetailCard.d.ts.map +1 -1
  22. package/build/@types/ocm/components/ui/Buttons/BackButton.d.ts +1 -1
  23. package/build/@types/ocm/components/ui/Buttons/BackButton.d.ts.map +1 -1
  24. package/build/@types/ocm/store/hooks.d.ts +1 -1
  25. package/build/@types/ocm/store/slices/clusters/selectors.d.ts +5 -61
  26. package/build/@types/ocm/store/slices/clusters/selectors.d.ts.map +1 -1
  27. package/build/@types/ocm/store/slices/feature-flags/selectors.d.ts +2 -20
  28. package/build/@types/ocm/store/slices/feature-flags/selectors.d.ts.map +1 -1
  29. package/build/@types/ocm/store/slices/infra-envs/selectors.d.ts +4 -21
  30. package/build/@types/ocm/store/slices/infra-envs/selectors.d.ts.map +1 -1
  31. package/build/cjs/cim/components/Agent/NoAgentsAlert.js +2 -2
  32. package/build/cjs/cim/components/Agent/NoAgentsAlert.js.map +1 -1
  33. package/build/cjs/cim/components/Agent/tableColumns.js +3 -3
  34. package/build/cjs/cim/components/Agent/tableColumns.js.map +1 -1
  35. package/build/cjs/cim/components/ClusterDeployment/ClusterInstallationError.js +1 -1
  36. package/build/cjs/cim/components/ClusterDeployment/ClusterInstallationError.js.map +1 -1
  37. package/build/cjs/cim/components/Hypershift/DetailsPage/NodePoolsTable.js +2 -2
  38. package/build/cjs/cim/components/Hypershift/DetailsPage/NodePoolsTable.js.map +1 -1
  39. package/build/cjs/cim/components/InfraEnv/AddHostDropdown.js +2 -2
  40. package/build/cjs/cim/components/InfraEnv/AddHostDropdown.js.map +1 -1
  41. package/build/cjs/cim/components/InfraEnv/InfraEnvFormPage.js +1 -1
  42. package/build/cjs/cim/components/InfraEnv/InfraEnvFormPage.js.map +1 -1
  43. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigProgressAlert.js +3 -3
  44. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigProgressAlert.js.map +1 -1
  45. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationFormFields.js +1 -1
  46. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationFormFields.js.map +1 -1
  47. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationModal.js +2 -2
  48. package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationModal.js.map +1 -1
  49. package/build/cjs/cim/components/modals/CimConfiguration/CimStorageMissingAlert.js +4 -4
  50. package/build/cjs/cim/components/modals/CimConfiguration/CimStorageMissingAlert.js.map +1 -1
  51. package/build/cjs/cim/components/modals/CimConfiguration/constants.js +1 -1
  52. package/build/cjs/cim/components/modals/MassDeleteAgentModal.js +2 -2
  53. package/build/cjs/cim/components/modals/MassDeleteAgentModal.js.map +1 -1
  54. package/build/cjs/common/components/clusterConfiguration/DiscoveryImageConfigForm.js +1 -1
  55. package/build/cjs/common/components/clusterConfiguration/DiscoveryImageConfigForm.js.map +1 -1
  56. package/build/cjs/common/components/clusterConfiguration/DownloadIso.js +1 -1
  57. package/build/cjs/common/components/clusterConfiguration/DownloadIso.js.map +1 -1
  58. package/build/cjs/common/components/clusterConfiguration/utils.js +13 -1
  59. package/build/cjs/common/components/clusterConfiguration/utils.js.map +1 -1
  60. package/build/cjs/common/components/clusterConfiguration/utils.test.js +36 -0
  61. package/build/cjs/common/components/clusterConfiguration/utils.test.js.map +1 -1
  62. package/build/cjs/common/components/clusterDetail/ConsoleModal.js +1 -1
  63. package/build/cjs/common/components/clusterDetail/ConsoleModal.js.map +1 -1
  64. package/build/cjs/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.js +29 -31
  65. package/build/cjs/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.js.map +1 -1
  66. package/build/cjs/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.js +19 -30
  67. package/build/cjs/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.js.map +1 -1
  68. package/build/cjs/common/components/operators/operatorSpecs.js +0 -3
  69. package/build/cjs/common/components/operators/operatorSpecs.js.map +1 -1
  70. package/build/cjs/common/config/docs_links.js +5 -4
  71. package/build/cjs/common/config/docs_links.js.map +1 -1
  72. package/build/cjs/common/utils.js +3 -0
  73. package/build/cjs/common/utils.js.map +1 -1
  74. package/build/cjs/common/validationSchemas/addressValidation.js +1 -1
  75. package/build/cjs/common/validationSchemas/addressValidation.js.map +1 -1
  76. package/build/cjs/ocm/components/Routes.js +8 -8
  77. package/build/cjs/ocm/components/Routes.js.map +1 -1
  78. package/build/cjs/ocm/components/clusterConfiguration/OcmClusterProgressItems.js +1 -1
  79. package/build/cjs/ocm/components/clusterConfiguration/OcmClusterProgressItems.js.map +1 -1
  80. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.js.map +1 -1
  81. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.js +68 -17
  82. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.js.map +1 -1
  83. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.js +1 -1
  84. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.js.map +1 -1
  85. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.js +50 -13
  86. package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.js.map +1 -1
  87. package/build/cjs/ocm/components/clusterConfiguration/platformIntegration/ExternalPlatformDropdown.js +1 -1
  88. package/build/cjs/ocm/components/clusterConfiguration/platformIntegration/ExternalPlatformDropdown.js.map +1 -1
  89. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.js +4 -2
  90. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.js.map +1 -1
  91. package/build/cjs/ocm/components/clusterConfiguration/review/utils.js +7 -1
  92. package/build/cjs/ocm/components/clusterConfiguration/review/utils.js.map +1 -1
  93. package/build/cjs/ocm/components/clusterConfiguration/review/utils.test.js +35 -0
  94. package/build/cjs/ocm/components/clusterConfiguration/review/utils.test.js.map +1 -1
  95. package/build/cjs/ocm/components/clusterDetail/AssistedInstallerDetailCard.js +4 -4
  96. package/build/cjs/ocm/components/clusterDetail/AssistedInstallerDetailCard.js.map +1 -1
  97. package/build/cjs/ocm/components/clusterDetail/ClusterDetail.js +4 -4
  98. package/build/cjs/ocm/components/clusterDetail/ClusterDetail.js.map +1 -1
  99. package/build/cjs/ocm/components/clusterDetail/ClusterInstallationError.js +1 -1
  100. package/build/cjs/ocm/components/clusterDetail/ClusterInstallationError.js.map +1 -1
  101. package/build/cjs/ocm/components/clusterDetail/ProgressBarAlerts.js +1 -1
  102. package/build/cjs/ocm/components/clusterDetail/ProgressBarAlerts.js.map +1 -1
  103. package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js +4 -4
  104. package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js.map +1 -1
  105. package/build/cjs/ocm/components/clusterWizard/ClusterDetailsForm.js +2 -2
  106. package/build/cjs/ocm/components/clusterWizard/ClusterDetailsForm.js.map +1 -1
  107. package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js +2 -2
  108. package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js.map +1 -1
  109. package/build/cjs/ocm/components/clusterWizard/ClusterWizardFooter.js +2 -2
  110. package/build/cjs/ocm/components/clusterWizard/ClusterWizardFooter.js.map +1 -1
  111. package/build/cjs/ocm/components/clusterWizard/Operators.js +4 -4
  112. package/build/cjs/ocm/components/clusterWizard/Operators.js.map +1 -1
  113. package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js +3 -3
  114. package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js.map +1 -1
  115. package/build/cjs/ocm/components/clusters/ClusterBreadcrumbs.js +2 -2
  116. package/build/cjs/ocm/components/clusters/ClusterBreadcrumbs.js.map +1 -1
  117. package/build/cjs/ocm/components/clusters/ClusterPage.js +4 -4
  118. package/build/cjs/ocm/components/clusters/ClusterPage.js.map +1 -1
  119. package/build/cjs/ocm/components/clusters/Clusters.js +3 -3
  120. package/build/cjs/ocm/components/clusters/Clusters.js.map +1 -1
  121. package/build/cjs/ocm/components/clusters/ClustersListToolbar.js +3 -3
  122. package/build/cjs/ocm/components/clusters/ClustersListToolbar.js.map +1 -1
  123. package/build/cjs/ocm/components/ui/Buttons/BackButton.js +2 -2
  124. package/build/cjs/ocm/components/ui/Buttons/BackButton.js.map +1 -1
  125. package/build/cjs/ocm/store/slices/clusters/selectors.js +2 -2
  126. package/build/cjs/ocm/store/slices/clusters/selectors.js.map +1 -1
  127. package/build/cjs/ocm/store/slices/feature-flags/selectors.js.map +1 -1
  128. package/build/cjs/ocm/store/slices/infra-envs/selectors.js.map +1 -1
  129. package/lib/cim/components/Agent/NoAgentsAlert.tsx +1 -1
  130. package/lib/cim/components/Agent/tableColumns.tsx +1 -1
  131. package/lib/cim/components/ClusterDeployment/ClusterInstallationError.tsx +1 -1
  132. package/lib/cim/components/Hypershift/DetailsPage/NodePoolsTable.tsx +1 -1
  133. package/lib/cim/components/InfraEnv/AddHostDropdown.tsx +1 -1
  134. package/lib/cim/components/InfraEnv/InfraEnvFormPage.tsx +1 -1
  135. package/lib/cim/components/modals/CimConfiguration/CimConfigProgressAlert.tsx +2 -2
  136. package/lib/cim/components/modals/CimConfiguration/CimConfigurationFormFields.tsx +1 -1
  137. package/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.tsx +2 -2
  138. package/lib/cim/components/modals/CimConfiguration/CimStorageMissingAlert.tsx +9 -3
  139. package/lib/cim/components/modals/CimConfiguration/constants.ts +1 -1
  140. package/lib/cim/components/modals/MassDeleteAgentModal.tsx +1 -1
  141. package/lib/common/components/clusterConfiguration/DiscoveryImageConfigForm.tsx +3 -1
  142. package/lib/common/components/clusterConfiguration/DownloadIso.tsx +1 -1
  143. package/lib/common/components/clusterConfiguration/utils.test.ts +43 -1
  144. package/lib/common/components/clusterConfiguration/utils.ts +13 -0
  145. package/lib/common/components/clusterDetail/ConsoleModal.tsx +1 -1
  146. package/lib/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.tsx +31 -57
  147. package/lib/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.tsx +33 -38
  148. package/lib/common/components/operators/operatorSpecs.tsx +0 -16
  149. package/lib/common/config/docs_links.ts +5 -4
  150. package/lib/common/utils.ts +3 -0
  151. package/lib/common/validationSchemas/addressValidation.tsx +2 -2
  152. package/lib/ocm/components/Routes.tsx +2 -2
  153. package/lib/ocm/components/clusterConfiguration/OcmClusterProgressItems.tsx +2 -2
  154. package/lib/ocm/components/clusterConfiguration/manifestsConfiguration/components/customManifestsValidationSchema.tsx +2 -2
  155. package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx +86 -22
  156. package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.tsx +2 -2
  157. package/lib/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.ts +57 -20
  158. package/lib/ocm/components/clusterConfiguration/platformIntegration/ExternalPlatformDropdown.tsx +1 -1
  159. package/lib/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.tsx +4 -2
  160. package/lib/ocm/components/clusterConfiguration/review/utils.test.ts +41 -0
  161. package/lib/ocm/components/clusterConfiguration/review/utils.tsx +5 -2
  162. package/lib/ocm/components/clusterDetail/AssistedInstallerDetailCard.tsx +1 -1
  163. package/lib/ocm/components/clusterDetail/ClusterDetail.tsx +3 -3
  164. package/lib/ocm/components/clusterDetail/ClusterInstallationError.tsx +1 -1
  165. package/lib/ocm/components/clusterDetail/ProgressBarAlerts.tsx +1 -1
  166. package/lib/ocm/components/clusterWizard/ClusterDetails.tsx +2 -2
  167. package/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx +1 -1
  168. package/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx +1 -1
  169. package/lib/ocm/components/clusterWizard/ClusterWizardFooter.tsx +1 -1
  170. package/lib/ocm/components/clusterWizard/Operators.tsx +2 -2
  171. package/lib/ocm/components/clusterWizard/disconnected/ReviewStep.tsx +2 -2
  172. package/lib/ocm/components/clusters/ClusterBreadcrumbs.tsx +1 -1
  173. package/lib/ocm/components/clusters/ClusterPage.tsx +1 -1
  174. package/lib/ocm/components/clusters/Clusters.tsx +2 -2
  175. package/lib/ocm/components/clusters/ClustersListToolbar.tsx +2 -2
  176. package/lib/ocm/components/ui/Buttons/BackButton.tsx +1 -1
  177. package/lib/ocm/store/slices/clusters/selectors.tsx +7 -5
  178. package/lib/ocm/store/slices/feature-flags/selectors.ts +5 -2
  179. package/lib/ocm/store/slices/infra-envs/selectors.ts +4 -2
  180. package/package.json +8 -8
@@ -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
  }),
@@ -155,7 +155,7 @@ export const ExternalPlatformDropdown = ({
155
155
 
156
156
  const handleClick = (event: MouseEvent<HTMLButtonElement>, href: string): void => {
157
157
  event.stopPropagation(); // Stop event propagation here
158
- window.open(href, '_blank');
158
+ window.open(href, '_blank', 'noopener,noreferrer');
159
159
  };
160
160
 
161
161
  const { getFeatureSupportLevel, getFeatureDisabledReason } = useNewFeatureSupportLevel();
@@ -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
@@ -42,7 +42,7 @@ const ClusterInstallationError: React.FC<ClusterInstallationErrorProps> = ({
42
42
  Download Installation Logs
43
43
  </AlertActionLink>
44
44
  <AlertActionLink
45
- onClick={() => window.open(getReportIssueLink(), '_blank')}
45
+ onClick={() => window.open(getReportIssueLink(), '_blank', 'noopener,noreferrer')}
46
46
  id={getID('button-report-bug')}
47
47
  >
48
48
  Report a bug
@@ -157,7 +157,7 @@ export const HostsInstallationFailed = ({
157
157
  Download installation logs
158
158
  </AlertActionLink>
159
159
  <AlertActionLink
160
- onClick={() => window.open(getReportIssueLink(), '_blank')}
160
+ onClick={() => window.open(getReportIssueLink(), '_blank', 'noopener,noreferrer')}
161
161
  id={getID('button-report-bug')}
162
162
  >
163
163
  Report a bug
@@ -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';
@@ -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,
@@ -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,
@@ -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
  };
@@ -26,7 +26,7 @@ import {
26
26
  } from '@patternfly/react-core';
27
27
  import { Formik } from 'formik';
28
28
  import { saveAs } from 'file-saver';
29
- import { useNavigate } from 'react-router-dom-v5-compat';
29
+ import { useNavigate } from 'react-router';
30
30
 
31
31
  import { getOperatorSpecs } from '../../../../common/components/operators/operatorSpecs';
32
32
 
@@ -51,7 +51,7 @@ const ReviewStep = () => {
51
51
  <ClusterWizardFooter
52
52
  onNext={() => {
53
53
  downloadUrl && saveAs(downloadUrl);
54
- navigate('/cluster-list');
54
+ void navigate('/cluster-list');
55
55
  }}
56
56
  onBack={moveBack}
57
57
  nextButtonText="Download ISO"
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Breadcrumb, BreadcrumbItem, PageSection } from '@patternfly/react-core';
3
- import { Link } from 'react-router-dom-v5-compat';
3
+ import { Link } from 'react-router';
4
4
  import { isInOcm } from '../../../common/api';
5
5
 
6
6
  const ClusterBreadcrumbs = ({ clusterName }: { clusterName?: string }) => {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { useParams, Navigate } from 'react-router-dom-v5-compat';
2
+ import { useParams, Navigate } from 'react-router';
3
3
  import { useDispatch } from 'react-redux';
4
4
  import { PageSection, Content } from '@patternfly/react-core';
5
5
  import {
@@ -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 { Button, ButtonVariant, Content, PageSection } from '@patternfly/react-core';
4
4
  import { AddCircleOIcon } from '@patternfly/react-icons/dist/js/icons/add-circle-o-icon';
5
5
  import {
@@ -85,7 +85,7 @@ const Clusters = () => {
85
85
  primaryAction={
86
86
  <Button
87
87
  variant={ButtonVariant.primary}
88
- onClick={() => navigate(`~new`)}
88
+ onClick={() => void navigate(`~new`)}
89
89
  id="empty-state-new-cluster-button"
90
90
  data-ouia-id="button-create-new-cluster"
91
91
  >
@@ -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 {
4
4
  Toolbar,
5
5
  ToolbarItem,
@@ -172,7 +172,7 @@ const ClustersListToolbar: React.FC<ClustersListToolbarProps> = ({
172
172
  </CustomToolbarFilter>
173
173
  <ToolbarButton
174
174
  variant={ButtonVariant.primary}
175
- onClick={() => navigate(`~new`)}
175
+ onClick={() => void navigate(`~new`)}
176
176
  id="button-create-new-cluster"
177
177
  data-ouia-id="button-create-new-cluster"
178
178
  >
@@ -1,4 +1,4 @@
1
- import { Link, LinkProps } from 'react-router-dom-v5-compat';
1
+ import { Link, LinkProps } from 'react-router';
2
2
  import type { ButtonProps } from '@patternfly/react-core';
3
3
  import { Button } from '@patternfly/react-core';
4
4
  import React from 'react';
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
2
  import { createSelector } from '@reduxjs/toolkit';
3
+ import type { Selector } from 'reselect';
3
4
  import type { IRow, IRowData } from '@patternfly/react-table';
4
- import { Link } from 'react-router-dom-v5-compat';
5
+ import { Link } from 'react-router';
5
6
  import type { TFunction } from 'i18next';
6
7
  import {
7
8
  DASH,
@@ -22,7 +23,7 @@ const selectClusters = (state: RootStateDay1) =>
22
23
  state.clusters.data.filter((c) => c.kind !== 'DisconnectedCluster');
23
24
  const clustersUIState = (state: RootStateDay1) => state.clusters.uiState;
24
25
 
25
- export const selectClustersUIState = createSelector(
26
+ export const selectClustersUIState: (state: RootStateDay1) => ResourceUIState = createSelector(
26
27
  [selectClusters, clustersUIState],
27
28
  (clusters, uiState): ResourceUIState => {
28
29
  const { LOADED, EMPTY } = ResourceUIState;
@@ -95,13 +96,14 @@ const clusterToClusterTableRow = (cluster: Cluster, t: TFunction): IRow => {
95
96
  export const getClusterTableStatusCell = (rowData: IRowData) =>
96
97
  rowData?.cells?.[3] as HumanizedSortable;
97
98
 
98
- export const selectClusterTableRows = (t: TFunction) => {
99
+ export const selectClusterTableRows = (t: TFunction): Selector<RootStateDay1, ClusterTableRows> => {
99
100
  return createSelector(
100
101
  selectClusters,
101
102
  (clusters): ClusterTableRows => clusters.map((c) => clusterToClusterTableRow(c, t)),
102
103
  );
103
104
  };
104
105
 
105
- export const selectClusterNames = createSelector(selectClusters, (clusters) =>
106
- clusters.map((c) => c.name),
106
+ export const selectClusterNames: Selector<RootStateDay1, (string | undefined)[]> = createSelector(
107
+ selectClusters,
108
+ (clusters) => clusters.map((c) => c.name),
107
109
  );
@@ -1,12 +1,15 @@
1
1
  import type { FeatureListType } from '../../../../common/features/featureGate';
2
2
  import type { RootStateDay1 } from '../../store-day1';
3
3
  import { createSelector } from '@reduxjs/toolkit';
4
+ import type { Selector } from 'reselect';
4
5
 
5
6
  export const selectFeatureFlagsSlice = (state: RootStateDay1) => state.featureFlags;
6
7
 
7
- export const isFeatureEnabled = (featureId: keyof FeatureListType) =>
8
+ export const isFeatureEnabled = (
9
+ featureId: keyof FeatureListType,
10
+ ): Selector<RootStateDay1, boolean> =>
8
11
  createSelector(
9
12
  selectFeatureFlagsSlice,
10
- (featureFlags: ReturnType<typeof selectFeatureFlagsSlice>) =>
13
+ (featureFlags: ReturnType<typeof selectFeatureFlagsSlice>): boolean =>
11
14
  featureFlags.data[featureId] ?? false,
12
15
  );
@@ -1,10 +1,12 @@
1
1
  import { createSelector } from '@reduxjs/toolkit';
2
+ import type { Selector } from 'reselect';
2
3
  import type { RootStateDay1 } from '../../store-day1';
3
4
  import type { CpuArchitecture } from '../../../../common';
5
+ import type { InfraEnv } from '@openshift-assisted/types/assisted-installer-service';
4
6
 
5
7
  export const selectInfraEnvsSlice = (state: RootStateDay1) => state.infraEnvs;
6
8
  export const selectInfraEnvByCpuArchitecture = createSelector(
7
9
  [selectInfraEnvsSlice, (_: RootStateDay1, cpuArchitecture: CpuArchitecture) => cpuArchitecture],
8
- (infraEnvs, cpuArchitecture) =>
10
+ (infraEnvs, cpuArchitecture): InfraEnv | undefined =>
9
11
  infraEnvs.find((infraEnv) => infraEnv.cpuArchitecture === cpuArchitecture),
10
- );
12
+ ) as Selector<RootStateDay1, InfraEnv | undefined, [CpuArchitecture]>;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "dependencies": {
3
- "@openshift-assisted/locales": "2.54.1",
4
- "@openshift-assisted/types": "2.54.1",
5
- "@openshift-console/dynamic-plugin-sdk": "^4.19.1",
3
+ "@openshift-assisted/locales": "2.55.0",
4
+ "@openshift-assisted/types": "2.55.0",
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",
8
8
  "@patternfly/react-core": "6.4.1",
@@ -13,7 +13,7 @@
13
13
  "@react-hook/resize-observer": "^2.0.2",
14
14
  "axios-case-converter": "^0.11.1",
15
15
  "camel-case": "^4.1.2",
16
- "cidr-tools": "^4.3.0",
16
+ "cidr-tools": "^12.1.1",
17
17
  "classnames": "^2.3.1",
18
18
  "file-saver": "^2.0.2",
19
19
  "filesize.js": "^2.0.0",
@@ -41,7 +41,7 @@
41
41
  "@types/humanize-plus": "^1.8.2",
42
42
  "@types/js-yaml": "^4.0.9",
43
43
  "@types/lodash-es": "^4.17.12",
44
- "@types/node": "^24.12.4",
44
+ "@types/node": "^24.13.3",
45
45
  "@types/react": "18.2.37",
46
46
  "@types/react-autosuggest": "^10.1.5",
47
47
  "@types/react-dom": "18.2.15",
@@ -91,7 +91,7 @@
91
91
  "peerDependencies": {
92
92
  "@reduxjs/toolkit": "^1.9.7",
93
93
  "@sentry/browser": "^5.9 || ^6",
94
- "axios": "^1.15.2",
94
+ "axios": "^1.18.1",
95
95
  "i18next": "^20.4 || ^21",
96
96
  "monaco-editor": "^0.44.0 || ^0.55.0",
97
97
  "react": "^18",
@@ -99,7 +99,7 @@
99
99
  "react-i18next": ">11.7.3",
100
100
  "react-monaco-editor": "^0.55.0 || ^0.59.0",
101
101
  "react-redux": "^8.0.5",
102
- "react-router-dom-v5-compat": "^6.30.3",
102
+ "react-router": "^7.17.0",
103
103
  "redux": "^4.2.1",
104
104
  "uuid": "^8.1",
105
105
  "yup": "^1.4.0"
@@ -136,5 +136,5 @@
136
136
  ]
137
137
  }
138
138
  },
139
- "version": "2.54.1"
139
+ "version": "2.55.0"
140
140
  }