@openshift-assisted/ui-lib 2.53.1 → 2.54.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 (163) hide show
  1. package/build/@types/cim/components/ClusterDeployment/clusterDetails/ACMClusterDeploymentDetailsStep.d.ts.map +1 -1
  2. package/build/@types/cim/components/ClusterDeployment/clusterDetails/ClusterDeploymentDetailsStep.d.ts +0 -17
  3. package/build/@types/cim/components/ClusterDeployment/clusterDetails/ClusterDeploymentDetailsStep.d.ts.map +1 -1
  4. package/build/@types/cim/components/ClusterDeployment/clusterDetails/ClusterDetailsFormFields.d.ts.map +1 -1
  5. package/build/@types/cim/components/ClusterDeployment/clusterDetails/useDetailsFormik.d.ts +19 -0
  6. package/build/@types/cim/components/ClusterDeployment/clusterDetails/useDetailsFormik.d.ts.map +1 -0
  7. package/build/@types/cim/components/common/CpuArchitectureDropdown.d.ts.map +1 -1
  8. package/build/@types/common/components/clusterConfiguration/DiskEncryptionFields/DiskEncryptionControlGroup.d.ts +2 -1
  9. package/build/@types/common/components/clusterConfiguration/DiskEncryptionFields/DiskEncryptionControlGroup.d.ts.map +1 -1
  10. package/build/@types/common/components/clusterConfiguration/ExternalPlatformsDropdown.d.ts.map +1 -1
  11. package/build/@types/common/components/clusterWizard/ReviewValidations.d.ts.map +1 -1
  12. package/build/@types/common/components/clusterWizard/validationsInfoUtils.d.ts +0 -1
  13. package/build/@types/common/components/clusterWizard/validationsInfoUtils.d.ts.map +1 -1
  14. package/build/@types/common/selectors/clusterSelectors.d.ts +0 -1
  15. package/build/@types/common/selectors/clusterSelectors.d.ts.map +1 -1
  16. package/build/@types/common/types/clusters.d.ts +2 -2
  17. package/build/@types/common/types/clusters.d.ts.map +1 -1
  18. package/build/@types/ocm/components/clusterConfiguration/DiscoveryImageForm.d.ts.map +1 -1
  19. package/build/@types/ocm/components/clusterConfiguration/DiscoveryImageModal.d.ts +0 -1
  20. package/build/@types/ocm/components/clusterConfiguration/DiscoveryImageModal.d.ts.map +1 -1
  21. package/build/@types/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.d.ts.map +1 -1
  22. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.d.ts.map +1 -1
  23. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/CustomManifestsForm.d.ts.map +1 -1
  24. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/utils.d.ts +4 -0
  25. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/utils.d.ts.map +1 -1
  26. package/build/@types/ocm/components/clusterConfiguration/operators/OperatorCheckbox.d.ts.map +1 -1
  27. package/build/@types/ocm/components/clusterConfiguration/operators/bundleSpecs.d.ts.map +1 -1
  28. package/build/@types/ocm/components/clusterConfiguration/operators/utils.d.ts +2 -2
  29. package/build/@types/ocm/components/clusterConfiguration/operators/utils.d.ts.map +1 -1
  30. package/build/@types/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.d.ts.map +1 -1
  31. package/build/@types/ocm/components/clusterConfiguration/review/ReviewSummary.d.ts.map +1 -1
  32. package/build/@types/ocm/components/clusterConfiguration/review/TableSummaryExpandable.d.ts +1 -0
  33. package/build/@types/ocm/components/clusterConfiguration/review/TableSummaryExpandable.d.ts.map +1 -1
  34. package/build/@types/ocm/components/clusterConfiguration/staticIp/components/StaticIpForm.d.ts.map +1 -1
  35. package/build/@types/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.d.ts.map +1 -1
  36. package/build/@types/ocm/components/clusterWizard/ClusterDetails.d.ts.map +1 -1
  37. package/build/@types/ocm/components/clusterWizard/ClusterWizardContextProvider.d.ts.map +1 -1
  38. package/build/@types/ocm/components/clusterWizard/NewClusterWizard.d.ts.map +1 -1
  39. package/build/@types/ocm/components/clusterWizard/Operators.d.ts.map +1 -1
  40. package/build/@types/ocm/components/clusterWizard/OperatorsBundle.d.ts +3 -3
  41. package/build/@types/ocm/components/clusterWizard/OperatorsBundle.d.ts.map +1 -1
  42. package/build/@types/ocm/components/clusterWizard/OptionalOperatorsDropdown.d.ts +13 -0
  43. package/build/@types/ocm/components/clusterWizard/OptionalOperatorsDropdown.d.ts.map +1 -0
  44. package/build/@types/ocm/components/clusterWizard/wizardTransition.d.ts +2 -3
  45. package/build/@types/ocm/components/clusterWizard/wizardTransition.d.ts.map +1 -1
  46. package/build/@types/ocm/services/InfraEnvsService.d.ts.map +1 -1
  47. package/build/@types/ocm/store/slices/current-cluster/slice.d.ts +2 -0
  48. package/build/@types/ocm/store/slices/current-cluster/slice.d.ts.map +1 -1
  49. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/ACMClusterDeploymentDetailsStep.js +4 -2
  50. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/ACMClusterDeploymentDetailsStep.js.map +1 -1
  51. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/ClusterDeploymentDetailsStep.js +5 -31
  52. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/ClusterDeploymentDetailsStep.js.map +1 -1
  53. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/ClusterDetailsFormFields.js +1 -11
  54. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/ClusterDetailsFormFields.js.map +1 -1
  55. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/useDetailsFormik.js +41 -0
  56. package/build/cjs/cim/components/ClusterDeployment/clusterDetails/useDetailsFormik.js.map +1 -0
  57. package/build/cjs/cim/components/common/CpuArchitectureDropdown.js +1 -1
  58. package/build/cjs/cim/components/common/CpuArchitectureDropdown.js.map +1 -1
  59. package/build/cjs/common/components/clusterConfiguration/DiskEncryptionFields/DiskEncryptionControlGroup.js +9 -3
  60. package/build/cjs/common/components/clusterConfiguration/DiskEncryptionFields/DiskEncryptionControlGroup.js.map +1 -1
  61. package/build/cjs/common/components/clusterConfiguration/ExternalPlatformsDropdown.js +1 -1
  62. package/build/cjs/common/components/clusterConfiguration/ExternalPlatformsDropdown.js.map +1 -1
  63. package/build/cjs/common/components/clusterWizard/ReviewValidations.js +16 -0
  64. package/build/cjs/common/components/clusterWizard/ReviewValidations.js.map +1 -1
  65. package/build/cjs/common/components/clusterWizard/validationsInfoUtils.js +1 -17
  66. package/build/cjs/common/components/clusterWizard/validationsInfoUtils.js.map +1 -1
  67. package/build/cjs/common/selectors/clusterSelectors.js +2 -8
  68. package/build/cjs/common/selectors/clusterSelectors.js.map +1 -1
  69. package/build/cjs/common/types/clusters.js.map +1 -1
  70. package/build/cjs/ocm/components/clusterConfiguration/DiscoveryImageForm.js +5 -2
  71. package/build/cjs/ocm/components/clusterConfiguration/DiscoveryImageForm.js.map +1 -1
  72. package/build/cjs/ocm/components/clusterConfiguration/DiscoveryImageModal.js +2 -2
  73. package/build/cjs/ocm/components/clusterConfiguration/DiscoveryImageModal.js.map +1 -1
  74. package/build/cjs/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.js +6 -2
  75. package/build/cjs/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.js.map +1 -1
  76. package/build/cjs/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.js +1 -1
  77. package/build/cjs/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.js.map +1 -1
  78. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.js +3 -1
  79. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.js.map +1 -1
  80. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/CustomManifestsForm.js +3 -1
  81. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/CustomManifestsForm.js.map +1 -1
  82. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/utils.js +11 -8
  83. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/utils.js.map +1 -1
  84. package/build/cjs/ocm/components/clusterConfiguration/operators/OperatorCheckbox.js +33 -13
  85. package/build/cjs/ocm/components/clusterConfiguration/operators/OperatorCheckbox.js.map +1 -1
  86. package/build/cjs/ocm/components/clusterConfiguration/operators/bundleSpecs.js +1 -2
  87. package/build/cjs/ocm/components/clusterConfiguration/operators/bundleSpecs.js.map +1 -1
  88. package/build/cjs/ocm/components/clusterConfiguration/operators/utils.js +3 -3
  89. package/build/cjs/ocm/components/clusterConfiguration/operators/utils.js.map +1 -1
  90. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.js +75 -20
  91. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.js.map +1 -1
  92. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewSummary.js +2 -2
  93. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewSummary.js.map +1 -1
  94. package/build/cjs/ocm/components/clusterConfiguration/review/TableSummaryExpandable.css +3 -0
  95. package/build/cjs/ocm/components/clusterConfiguration/review/TableSummaryExpandable.js +2 -3
  96. package/build/cjs/ocm/components/clusterConfiguration/review/TableSummaryExpandable.js.map +1 -1
  97. package/build/cjs/ocm/components/clusterConfiguration/staticIp/components/StaticIpForm.js +10 -1
  98. package/build/cjs/ocm/components/clusterConfiguration/staticIp/components/StaticIpForm.js.map +1 -1
  99. package/build/cjs/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.js +5 -5
  100. package/build/cjs/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.js.map +1 -1
  101. package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js +2 -9
  102. package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js.map +1 -1
  103. package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js +4 -4
  104. package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js.map +1 -1
  105. package/build/cjs/ocm/components/clusterWizard/NewClusterWizard.js +6 -3
  106. package/build/cjs/ocm/components/clusterWizard/NewClusterWizard.js.map +1 -1
  107. package/build/cjs/ocm/components/clusterWizard/Operators.js +36 -8
  108. package/build/cjs/ocm/components/clusterWizard/Operators.js.map +1 -1
  109. package/build/cjs/ocm/components/clusterWizard/OperatorsBundle.js +34 -15
  110. package/build/cjs/ocm/components/clusterWizard/OperatorsBundle.js.map +1 -1
  111. package/build/cjs/ocm/components/clusterWizard/OperatorsSelect.test.js +11 -5
  112. package/build/cjs/ocm/components/clusterWizard/OperatorsSelect.test.js.map +1 -1
  113. package/build/cjs/ocm/components/clusterWizard/OperatorsStep.js +1 -1
  114. package/build/cjs/ocm/components/clusterWizard/OperatorsStep.js.map +1 -1
  115. package/build/cjs/ocm/components/clusterWizard/OptionalOperatorsDropdown.js +34 -0
  116. package/build/cjs/ocm/components/clusterWizard/OptionalOperatorsDropdown.js.map +1 -0
  117. package/build/cjs/ocm/components/clusterWizard/wizardTransition.js +67 -28
  118. package/build/cjs/ocm/components/clusterWizard/wizardTransition.js.map +1 -1
  119. package/build/cjs/ocm/hooks/useInfraEnvId.js +2 -2
  120. package/build/cjs/ocm/hooks/useInfraEnvId.js.map +1 -1
  121. package/build/cjs/ocm/services/InfraEnvsService.js +4 -1
  122. package/build/cjs/ocm/services/InfraEnvsService.js.map +1 -1
  123. package/lib/cim/components/ClusterDeployment/clusterDetails/ACMClusterDeploymentDetailsStep.tsx +3 -1
  124. package/lib/cim/components/ClusterDeployment/clusterDetails/ClusterDeploymentDetailsStep.tsx +5 -86
  125. package/lib/cim/components/ClusterDeployment/clusterDetails/ClusterDetailsFormFields.tsx +1 -12
  126. package/lib/cim/components/ClusterDeployment/clusterDetails/useDetailsFormik.tsx +97 -0
  127. package/lib/cim/components/common/CpuArchitectureDropdown.tsx +2 -1
  128. package/lib/common/components/clusterConfiguration/DiskEncryptionFields/DiskEncryptionControlGroup.tsx +18 -8
  129. package/lib/common/components/clusterConfiguration/ExternalPlatformsDropdown.tsx +3 -1
  130. package/lib/common/components/clusterWizard/ReviewValidations.tsx +24 -0
  131. package/lib/common/components/clusterWizard/validationsInfoUtils.ts +0 -20
  132. package/lib/common/selectors/clusterSelectors.ts +2 -9
  133. package/lib/common/types/clusters.ts +3 -1
  134. package/lib/ocm/components/clusterConfiguration/DiscoveryImageForm.tsx +11 -2
  135. package/lib/ocm/components/clusterConfiguration/DiscoveryImageModal.tsx +13 -3
  136. package/lib/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.tsx +9 -1
  137. package/lib/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.tsx +1 -1
  138. package/lib/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.tsx +8 -1
  139. package/lib/ocm/components/clusterConfiguration/manifestsConfiguration/components/CustomManifestsForm.tsx +3 -1
  140. package/lib/ocm/components/clusterConfiguration/manifestsConfiguration/components/utils.tsx +12 -6
  141. package/lib/ocm/components/clusterConfiguration/operators/OperatorCheckbox.tsx +37 -17
  142. package/lib/ocm/components/clusterConfiguration/operators/bundleSpecs.tsx +2 -3
  143. package/lib/ocm/components/clusterConfiguration/operators/utils.tsx +5 -4
  144. package/lib/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.tsx +114 -24
  145. package/lib/ocm/components/clusterConfiguration/review/ReviewSummary.tsx +1 -4
  146. package/lib/ocm/components/clusterConfiguration/review/TableSummaryExpandable.css +3 -0
  147. package/lib/ocm/components/clusterConfiguration/review/TableSummaryExpandable.tsx +1 -1
  148. package/lib/ocm/components/clusterConfiguration/staticIp/components/StaticIpForm.tsx +10 -1
  149. package/lib/ocm/components/clusterConfiguration/staticIp/components/StaticIpPage.tsx +9 -6
  150. package/lib/ocm/components/clusterWizard/ClusterDetails.tsx +2 -14
  151. package/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx +5 -13
  152. package/lib/ocm/components/clusterWizard/NewClusterWizard.tsx +7 -3
  153. package/lib/ocm/components/clusterWizard/Operators.tsx +45 -10
  154. package/lib/ocm/components/clusterWizard/OperatorsBundle.tsx +72 -26
  155. package/lib/ocm/components/clusterWizard/OperatorsSelect.test.ts +11 -5
  156. package/lib/ocm/components/clusterWizard/OperatorsStep.tsx +1 -1
  157. package/lib/ocm/components/clusterWizard/OptionalOperatorsDropdown.tsx +106 -0
  158. package/lib/ocm/components/clusterWizard/wizardTransition.ts +90 -36
  159. package/lib/ocm/hooks/useInfraEnvId.ts +2 -2
  160. package/lib/ocm/services/InfraEnvsService.ts +4 -1
  161. package/package.json +11 -11
  162. package/build/cjs/ocm/components/clusterConfiguration/DiscoveryImageModal.css +0 -3
  163. package/lib/ocm/components/clusterConfiguration/DiscoveryImageModal.css +0 -3
@@ -47,6 +47,20 @@ const PendingValidations = ({ id, count }: { id: string; count: number }) => {
47
47
  return <div id={id}>{t('ai:There is still {{count}} pending check', { count: count })}</div>;
48
48
  };
49
49
 
50
+ const InformationalValidation = ({ validation }: { validation: ClusterValidation }) => {
51
+ const { t } = useTranslation();
52
+ const label = clusterValidationLabels(t)[validation.id] || validation.id || '';
53
+
54
+ return (
55
+ <div id={`info-validation-${validation.id}`}>
56
+ <Icon status="success">
57
+ <CheckCircleIcon />
58
+ </Icon>{' '}
59
+ {label}. {validation.message}
60
+ </div>
61
+ );
62
+ };
63
+
50
64
  const ValidationActionLink = <S extends string>({
51
65
  step,
52
66
  setCurrentStepId,
@@ -173,6 +187,16 @@ export const ClusterValidations = <S extends string>({
173
187
  />,
174
188
  );
175
189
  }
190
+
191
+ if (
192
+ validation.status === 'success' &&
193
+ validation.id === 'openshift-ai-gpu-requirements-satisfied' &&
194
+ validation.message
195
+ ) {
196
+ failingValidations.push(
197
+ <InformationalValidation key={`info-${validation.id}`} validation={validation} />,
198
+ );
199
+ }
176
200
  };
177
201
 
178
202
  validationsInfo[group]?.forEach(addFailingValidation);
@@ -282,23 +282,3 @@ export const areOnlySoftValidationsOfWizardStepFailing = <ClusterWizardStepsType
282
282
  }
283
283
  return true;
284
284
  };
285
-
286
- export const findValidationStep = <ClusterWizardStepsType extends string>(
287
- validationId: ClusterValidationId | HostValidationId,
288
- wizardStepsValidationsMap: WizardStepsValidationMap<ClusterWizardStepsType>,
289
- minimumStep: ClusterWizardStepsType,
290
- ): ClusterWizardStepsType | undefined => {
291
- const wizardStepsIds = lodashKeys(wizardStepsValidationsMap) as ClusterWizardStepsType[];
292
- let isBeforeMinimumStep = true;
293
- return wizardStepsIds.find((wizardStepId) => {
294
- if (wizardStepId === minimumStep) {
295
- isBeforeMinimumStep = false;
296
- }
297
- if (isBeforeMinimumStep) {
298
- return false;
299
- }
300
- // find first matching validation-map name, ignoring steps before minimumStep
301
- const { host: hostValidationMap } = wizardStepsValidationsMap[wizardStepId];
302
- return hostValidationMap.validationIds.includes(validationId as HostValidationId);
303
- });
304
- };
@@ -39,7 +39,8 @@ export const selectMonitoredOperators = (monitoredOperators: Cluster['monitoredO
39
39
 
40
40
  export const selectOlmOperators = (cluster?: Pick<Cluster, 'monitoredOperators'>) => {
41
41
  return selectMonitoredOperators(cluster?.monitoredOperators).filter(
42
- (operator) => operator.operatorType === 'olm',
42
+ (operator) =>
43
+ operator.operatorType === 'olm' && !!operator.name && operator.dependencyOnly !== true,
43
44
  );
44
45
  };
45
46
 
@@ -120,11 +121,3 @@ export const isClusterPlatformTypeVM = ({ platform }: Pick<Cluster, 'platform'>)
120
121
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
121
122
  // @ts-ignore
122
123
  SupportedPlatformIntegrations.includes(platform?.type ?? 'none');
123
-
124
- export const numberOfEnabledOperators = (monitoredOperators: Cluster['monitoredOperators']) => {
125
- return monitoredOperators
126
- ? selectMonitoredOperators(
127
- monitoredOperators.filter((operator) => operator.operatorType === 'olm'),
128
- ).length
129
- : 0;
130
- };
@@ -1,5 +1,6 @@
1
1
  import { IRow } from '@patternfly/react-table';
2
2
  import {
3
+ BundleCreateParams,
3
4
  Cluster,
4
5
  V2ClusterUpdateParams,
5
6
  ClusterValidationId,
@@ -57,8 +58,9 @@ export type HostDiscoveryValues = V2ClusterUpdateParams & {
57
58
  export type StorageValues = V2ClusterUpdateParams & {
58
59
  nodeLabeling: string;
59
60
  };
61
+
60
62
  export type OperatorsValues = {
61
- selectedBundles: string[];
63
+ selectedBundles: BundleCreateParams[];
62
64
  selectedOperators: string[];
63
65
  };
64
66
 
@@ -19,6 +19,7 @@ import { mapClusterCpuArchToInfraEnvCpuArch } from '../../services/CpuArchitectu
19
19
  import { usePullSecret } from '../../hooks';
20
20
  import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
21
21
  import { isOciPlatformType } from '../utils';
22
+ import { ModalBody } from '@patternfly/react-core';
22
23
 
23
24
  type DiscoveryImageFormProps = {
24
25
  cluster: Cluster;
@@ -93,10 +94,18 @@ const DiscoveryImageForm = ({
93
94
  };
94
95
 
95
96
  if (infraEnvError) {
96
- return <ErrorState />;
97
+ return (
98
+ <ModalBody style={{ height: '696px' }}>
99
+ <ErrorState />
100
+ </ModalBody>
101
+ );
97
102
  }
98
103
  if (!infraEnv) {
99
- return <LoadingState />;
104
+ return (
105
+ <ModalBody style={{ height: '696px' }}>
106
+ <LoadingState />
107
+ </ModalBody>
108
+ );
100
109
  }
101
110
  return (
102
111
  <OcmDiscoveryImageConfigForm
@@ -1,5 +1,12 @@
1
1
  import React from 'react';
2
- import { Button, ButtonVariant, Modal, ModalHeader, ModalVariant } from '@patternfly/react-core';
2
+ import {
3
+ Button,
4
+ ButtonVariant,
5
+ Modal,
6
+ ModalBody,
7
+ ModalHeader,
8
+ ModalVariant,
9
+ } from '@patternfly/react-core';
3
10
  import { pluralize } from 'humanize-plus';
4
11
  import {
5
12
  AI_CISCO_INTERSIGHT_TAG,
@@ -14,7 +21,6 @@ import { useModalDialogsContext } from '../hosts/ModalDialogsContext';
14
21
  import useInfraEnvImageUrl from '../../hooks/useInfraEnvImageUrl';
15
22
  import useInfraEnvIpxeImageUrl from '../../hooks/useInfraEnvIpxeImageUrl';
16
23
  import DownloadIpxeScript from '../../../common/components/clusterConfiguration/DownloadIpxeScript';
17
- import './DiscoveryImageModal.css';
18
24
  import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
19
25
  import { ClustersService } from '../../services';
20
26
  import { useDispatch } from 'react-redux';
@@ -115,7 +121,11 @@ export const DiscoveryImageModal = () => {
115
121
  data-testid="discovery-modal-title"
116
122
  title={`Add ${pluralize(+isSNOCluster, 'host')}`}
117
123
  />
118
- {(isoDownloadError || ipxeDownloadError) && <ErrorState />}
124
+ {(isoDownloadError || ipxeDownloadError) && (
125
+ <ModalBody>
126
+ <ErrorState />
127
+ </ModalBody>
128
+ )}
119
129
  {isoDownloadUrl ? (
120
130
  <DownloadIso
121
131
  fileName={`discovery_image_${cluster.name || ''}.iso`}
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-console */
2
1
  import * as React from 'react';
3
2
  import { Form } from '@patternfly/react-core';
4
3
  import { useFormikContext } from 'formik';
@@ -40,6 +39,7 @@ import ControlPlaneNodesDropdown, {
40
39
  DEFAULT_VALUE_CPN,
41
40
  isCPNDropdownItemEnabled,
42
41
  } from './ControlPlaneNodesDropdown';
42
+ import { isFeatureSupportedAndAvailable } from '../featureSupportLevels/featureStateUtils';
43
43
 
44
44
  export type OcmClusterDetailsFormFieldsProps = {
45
45
  cluster?: Cluster;
@@ -79,6 +79,13 @@ export const OcmClusterDetailsFormFields = ({
79
79
  architectureData[values.cpuArchitecture as SupportedCpuArchitecture].label;
80
80
 
81
81
  const featureSupportLevelContext = useNewFeatureSupportLevel();
82
+ const tnaSupport = featureSupportLevelContext.getFeatureSupportLevel(
83
+ 'TNA',
84
+ featureSupportLevelData ?? undefined,
85
+ );
86
+ const isArbiterEncryptionAvailable = isSingleClusterFeatureEnabled
87
+ ? false
88
+ : isFeatureSupportedAndAvailable(tnaSupport);
82
89
 
83
90
  React.useEffect(() => {
84
91
  nameInputRef.current?.focus();
@@ -223,6 +230,7 @@ export const OcmClusterDetailsFormFields = ({
223
230
  values={values}
224
231
  isDisabled={cluster?.pullSecretSet}
225
232
  isSNO={values.controlPlaneCount === 1}
233
+ isArbiterEncryptionAvailable={isArbiterEncryptionAvailable}
226
234
  docVersion={openshiftVersion}
227
235
  />
228
236
  </Form>
@@ -145,7 +145,7 @@ export const OcmDiscoveryImageConfigForm = ({
145
145
  {({ submitForm, isSubmitting, status, setStatus }) => {
146
146
  return (
147
147
  <>
148
- <ModalBody>
148
+ <ModalBody style={{ maxHeight: '611px' }}>
149
149
  <Stack hasGutter>
150
150
  <StackItem>
151
151
  <Alert variant={AlertVariant.info} isInline title={alertDiscoveryText} />
@@ -22,6 +22,7 @@ import { getFieldId } from '../../../../common/components/ui/formik';
22
22
  import { isOciPlatformType } from '../../utils';
23
23
  import DeleteCustomManifestModal from './DeleteCustomManifestModal';
24
24
  import { ClustersService } from '../../../services';
25
+ import { userProvidedManifests } from './components/utils';
25
26
  import { useClusterWizardContext } from '../../clusterWizard/ClusterWizardContext';
26
27
 
27
28
  export const CustomManifestsPage = ({
@@ -77,7 +78,13 @@ export const CustomManifestsPage = ({
77
78
  const cleanCustomManifests = React.useCallback(async () => {
78
79
  if (!clusterWizardContext.uiSettings?.customManifestsAdded || !cluster.id) return;
79
80
  const { data: manifests } = await ClustersAPI.getManifests(cluster.id);
80
- await ClustersService.removeClusterManifests(manifests, cluster.id);
81
+ const manifestsToRemove = userProvidedManifests(manifests).map((manifest) => ({
82
+ ...manifest,
83
+ folder: manifest.folder || 'manifests',
84
+ fileName: manifest.fileName || '',
85
+ yamlContent: '',
86
+ }));
87
+ await ClustersService.removeClusterManifests(manifestsToRemove, cluster.id);
81
88
  setUseCustomManifests(false);
82
89
  setDeleteModalOpen(false);
83
90
  await clusterWizardContext.updateUISettings({
@@ -23,6 +23,7 @@ import { CustomManifestValues, ManifestFormData } from '../data/dataTypes';
23
23
  import useClusterCustomManifests from '../../../../hooks/useClusterCustomManifests';
24
24
  import { ClustersService } from '../../../../services';
25
25
  import { CustomManifestsArray } from './CustomManifestsArray';
26
+ import { userProvidedManifests } from './utils';
26
27
  import { selectCurrentClusterPermissionsState } from '../../../../store/slices/current-cluster/selectors';
27
28
  import { useClusterWizardContext } from '../../../clusterWizard/ClusterWizardContext';
28
29
  import { ClustersAPI } from '../../../../services/apis';
@@ -70,7 +71,8 @@ export const CustomManifestsForm = ({
70
71
  if (customManifests && !customManifestsLocalRef.current.length) {
71
72
  const initValues = getInitialValues(customManifests);
72
73
  setInitialValues(initValues);
73
- customManifestsLocalRef.current = !!customManifests.length ? initValues.manifests : [];
74
+ customManifestsLocalRef.current =
75
+ userProvidedManifests(customManifests).length > 0 ? initValues.manifests : [];
74
76
  }
75
77
  }, [customManifests, getInitialValues]);
76
78
 
@@ -1,5 +1,10 @@
1
1
  import { CustomManifestValues, ListManifestsExtended, ManifestFormData } from '../data/dataTypes';
2
2
 
3
+ /** Manifests created by the installer (e.g. OVE defaults); not editable in the wizard. */
4
+ export const userProvidedManifests = <T extends { manifestSource?: string }>(
5
+ manifests: T[] | undefined,
6
+ ): T[] => (manifests ?? []).filter((m) => m.manifestSource !== 'system');
7
+
3
8
  export const getManifestName = (manifestIdx: number) => `Custom manifest ${manifestIdx + 1}`;
4
9
 
5
10
  export const getFormData = (manifests: ListManifestsExtended): ManifestFormData => {
@@ -18,11 +23,11 @@ export const getEmptyManifest = (): CustomManifestValues => {
18
23
  };
19
24
 
20
25
  export const getManifestValues = (manifests: ListManifestsExtended): ManifestFormData => {
21
- if (!!manifests.length) {
22
- return getFormData(manifests);
23
- } else {
24
- return getEmptyManifestsValues();
26
+ const userManifests = userProvidedManifests(manifests);
27
+ if (userManifests.length > 0) {
28
+ return getFormData(userManifests);
25
29
  }
30
+ return getEmptyManifestsValues();
26
31
  };
27
32
 
28
33
  export const getEmptyManifestsValues = (): ManifestFormData => {
@@ -32,8 +37,9 @@ export const getEmptyManifestsValues = (): ManifestFormData => {
32
37
  export const getClusterCustomManifests = (
33
38
  customManifests: ListManifestsExtended,
34
39
  ): CustomManifestValues[] => {
35
- if (customManifests && customManifests.length > 0) {
36
- return customManifests.map((manifest) => ({
40
+ const userManifests = userProvidedManifests(customManifests);
41
+ if (userManifests.length > 0) {
42
+ return userManifests.map((manifest) => ({
37
43
  folder: manifest.folder || 'manifests',
38
44
  filename: manifest.fileName || '',
39
45
  manifestYaml: manifest.yamlContent || '',
@@ -136,31 +136,51 @@ const OperatorCheckbox = ({
136
136
  const fieldId = getFieldId(operatorId, 'input');
137
137
  const supportLevel = getFeatureSupportLevel(featureId);
138
138
 
139
- const isInBundle = values.selectedBundles.some(
140
- (sb) => !!bundles.find((b) => b.id === sb)?.operators?.includes(operatorId),
139
+ const isRequiredByBundle = values.selectedBundles.some(
140
+ (selectedBundle) =>
141
+ !!bundles.find((bundle) => bundle.id === selectedBundle.id)?.operators?.includes(operatorId),
141
142
  );
143
+ const isSelectedForBundle = values.selectedBundles.some((selectedBundle) =>
144
+ selectedBundle.optionalOperators?.includes(operatorId),
145
+ );
146
+ const isInBundle = isRequiredByBundle || isSelectedForBundle;
147
+
148
+ const isOperatorActive = (opName: string) =>
149
+ values.selectedOperators.includes(opName) ||
150
+ values.selectedBundles.some((selectedBundle) => {
151
+ const bundle = bundles.find(({ id }) => id === selectedBundle.id);
152
+ return (
153
+ bundle?.operators?.includes(opName) || selectedBundle.optionalOperators?.includes(opName)
154
+ );
155
+ });
142
156
 
143
157
  const isChecked = values.selectedOperators.includes(operatorId) || isInBundle;
144
158
 
145
- const parentOperator = preflightRequirements?.operators?.find((op) =>
146
- op.dependencies?.includes(operatorId),
159
+ const parentOperator = preflightRequirements?.operators?.find(
160
+ (op) =>
161
+ !!op.operatorName &&
162
+ op.dependencies?.includes(operatorId) &&
163
+ isOperatorActive(op.operatorName),
147
164
  );
148
165
 
149
- let parentOperatorName = '';
150
- if (
151
- parentOperator?.operatorName &&
152
- values.selectedOperators.includes(parentOperator.operatorName)
153
- ) {
154
- parentOperatorName = opSpecs[parentOperator.operatorName]?.title || parentOperator.operatorName;
166
+ let requiredByOperatorName = '';
167
+ if (parentOperator?.operatorName) {
168
+ requiredByOperatorName =
169
+ opSpecs[parentOperator.operatorName]?.title || parentOperator.operatorName;
155
170
  }
156
171
 
157
- const disabledReason = isInBundle
158
- ? 'This operator is part of a bundle and cannot be deselected.'
159
- : notStandalone
160
- ? 'This operator cannot be installed as a standalone'
161
- : parentOperatorName
162
- ? `This operator is a dependency of ${parentOperatorName}`
163
- : getFeatureDisabledReason(featureId);
172
+ let disabledReason = getFeatureDisabledReason(featureId);
173
+
174
+ if (isRequiredByBundle) {
175
+ disabledReason = 'This operator is part of a selected bundle and cannot be deselected.';
176
+ } else if (isSelectedForBundle) {
177
+ disabledReason =
178
+ 'This optional operator is selected through a bundle. Use the bundle card to change it.';
179
+ } else if (requiredByOperatorName) {
180
+ disabledReason = `This operator is required by ${requiredByOperatorName}`;
181
+ } else if (notStandalone && !values.selectedOperators.includes(operatorId)) {
182
+ disabledReason = 'This operator cannot be installed as a standalone';
183
+ }
164
184
 
165
185
  return (
166
186
  <FormGroup fieldId={fieldId} id={`form-control__${fieldId}`}>
@@ -31,10 +31,9 @@ export const bundleSpecs: { [key: string]: BundleSpec } = {
31
31
  incompatibleBundles: [],
32
32
  Description: () => (
33
33
  <List>
34
- <ListItem>GPUs are recommended for optimal AI/ML workload performance.</ListItem>
35
34
  <ListItem>
36
- NVIDIA GPU, AMD GPU and Kernel Module Management may or may not be installed based on the
37
- GPU discovered on your hosts.
35
+ GPUs are recommended for optimal AI/ML workload performance. Please select the GPU
36
+ operators you want to install.
38
37
  </ListItem>
39
38
  </List>
40
39
  ),
@@ -1,4 +1,5 @@
1
1
  import {
2
+ BundleCreateParams,
2
3
  Bundle,
3
4
  PreflightHardwareRequirements,
4
5
  } from '@openshift-assisted/types/assisted-installer-service';
@@ -68,7 +69,7 @@ const getBundleOperators = (
68
69
 
69
70
  export const getNewBundleOperators = (
70
71
  currentOperators: string[],
71
- currentBundles: string[],
72
+ currentBundles: BundleCreateParams[],
72
73
  allBundles: Bundle[],
73
74
  newBundle: Bundle,
74
75
  preflightRequirements: PreflightHardwareRequirements | undefined,
@@ -81,10 +82,10 @@ export const getNewBundleOperators = (
81
82
  return Array.from(new Set(combined));
82
83
  }
83
84
 
84
- const newBundles = currentBundles.filter((b) => b !== newBundle.id);
85
+ const newBundles = currentBundles.filter((bundle) => bundle.id !== newBundle.id);
85
86
  const operatorsToKeep = [
86
- ...newBundles.reduce((acc, bundleId) => {
87
- const bundle = allBundles.find(({ id }) => id === bundleId);
87
+ ...newBundles.reduce((acc, selectedBundle) => {
88
+ const bundle = allBundles.find(({ id }) => id === selectedBundle.id);
88
89
  if (bundle) {
89
90
  const bundleOperators = getBundleOperators(bundle, preflightRequirements);
90
91
  bundleOperators.forEach((op) => {
@@ -1,17 +1,75 @@
1
1
  import React from 'react';
2
+ import { Title } from '@patternfly/react-core';
2
3
  import { Table, TableVariant, Tbody, Td, Tr } from '@patternfly/react-table';
3
- import { genericTableRowKey } from '../../../../common';
4
- import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
4
+ import { genericTableRowKey, selectOlmOperators } from '../../../../common';
5
+ import { useStateSafely } from '../../../../common/hooks';
6
+ import { Bundle, Cluster } from '@openshift-assisted/types/assisted-installer-service';
5
7
  import { TableSummaryExpandable } from './TableSummaryExpandable';
6
8
  import { useOperatorSpecs } from '../../../../common/components/operators/operatorSpecs';
9
+ import BundleService from '../../../services/BundleService';
10
+
11
+ const fetchBundles = async (
12
+ openshiftVersion: string,
13
+ cpuArchitecture: string,
14
+ platformType: string,
15
+ ): Promise<Bundle[]> => {
16
+ try {
17
+ return await BundleService.listBundles(
18
+ openshiftVersion,
19
+ cpuArchitecture,
20
+ platformType,
21
+ undefined,
22
+ );
23
+ } catch (_e) {
24
+ return [] as Bundle[];
25
+ }
26
+ };
7
27
 
8
28
  export const ReviewOperatorsTable = ({ cluster }: { cluster: Cluster }) => {
9
29
  const { byKey: opSpecs } = useOperatorSpecs();
30
+ const selectedBundles = cluster.operatorBundles || [];
31
+ const [bundleTitlesById, setBundleTitlesById] = useStateSafely<Record<string, string>>({});
32
+ const hasFetchedBundles = React.useRef(false);
33
+ const hasSelectedBundles = selectedBundles.length > 0;
34
+ React.useEffect(() => {
35
+ if (!hasFetchedBundles.current && hasSelectedBundles) {
36
+ hasFetchedBundles.current = true;
37
+ void (async () => {
38
+ const bundles = await fetchBundles(
39
+ cluster.openshiftVersion || '',
40
+ cluster.cpuArchitecture || '',
41
+ cluster.platform?.type || '',
42
+ );
43
+ const titlesById = Object.fromEntries(
44
+ bundles
45
+ .filter((bundle) => !!bundle.id && !!bundle.title)
46
+ .map((bundle) => [bundle.id, bundle.title]),
47
+ ) as Record<string, string>;
48
+ setBundleTitlesById(titlesById);
49
+ })();
50
+ }
51
+ }, [
52
+ cluster.cpuArchitecture,
53
+ cluster.openshiftVersion,
54
+ cluster.platform?.type,
55
+ hasSelectedBundles,
56
+ setBundleTitlesById,
57
+ ]);
58
+
59
+ const bundleRows = selectedBundles.map((bundle) => ({
60
+ rowId: `bundle-${bundle.id}`,
61
+ cells: [
62
+ {
63
+ title: bundleTitlesById[bundle.id] || bundle.id,
64
+ props: { 'data-testid': `bundle-${bundle.id}` },
65
+ },
66
+ ],
67
+ }));
10
68
 
11
69
  const rows = React.useMemo(
12
70
  () =>
13
- cluster.monitoredOperators
14
- ?.filter(({ name }) => !!name && !!opSpecs[name])
71
+ selectOlmOperators(cluster)
72
+ .filter(({ name }) => !!name && !!opSpecs[name])
15
73
  .map((op) => {
16
74
  const opId = op.name as string;
17
75
  return {
@@ -25,33 +83,65 @@ export const ReviewOperatorsTable = ({ cluster }: { cluster: Cluster }) => {
25
83
  ],
26
84
  };
27
85
  }),
28
- [cluster.monitoredOperators, opSpecs],
86
+ [cluster, opSpecs],
29
87
  );
30
88
 
31
- if (!rows?.length) {
89
+ if (!rows?.length && selectedBundles.length === 0) {
32
90
  return null;
33
91
  }
34
92
 
35
93
  return (
36
- <TableSummaryExpandable title={'Operators'} id={'operators-expandable'}>
37
- <Table
38
- variant={TableVariant.compact}
39
- borders={false}
40
- aria-label={'Operators review table'}
41
- className="review-table"
42
- >
43
- <Tbody>
44
- {rows.map((row, i) => (
45
- <Tr key={genericTableRowKey(row.rowId)}>
46
- {row.cells.map((cell, j) => (
47
- <Td key={`cell-${i}-${j}`} {...cell.props}>
48
- {cell.title}
49
- </Td>
94
+ <TableSummaryExpandable title={'Bundles and operators'} id={'operators-expandable'}>
95
+ {bundleRows.length > 0 && (
96
+ <>
97
+ <Title headingLevel="h4" size="md" className="pf-v6-u-mb-sm">
98
+ Bundles ({bundleRows.length})
99
+ </Title>
100
+ <Table
101
+ variant={TableVariant.compact}
102
+ borders={false}
103
+ aria-label={'Bundles review table'}
104
+ className="review-table pf-v6-u-mb-md"
105
+ >
106
+ <Tbody>
107
+ {bundleRows.map((row, i) => (
108
+ <Tr key={genericTableRowKey(row.rowId)}>
109
+ {row.cells.map((cell, j) => (
110
+ <Td key={`bundle-cell-${i}-${j}`} {...cell.props}>
111
+ {cell.title}
112
+ </Td>
113
+ ))}
114
+ </Tr>
115
+ ))}
116
+ </Tbody>
117
+ </Table>
118
+ </>
119
+ )}
120
+ {rows.length > 0 && (
121
+ <>
122
+ <Title headingLevel="h4" size="md" className="pf-v6-u-mb-sm">
123
+ Operators ({rows.length})
124
+ </Title>
125
+ <Table
126
+ variant={TableVariant.compact}
127
+ borders={false}
128
+ aria-label={'Operators review table'}
129
+ className="review-table"
130
+ >
131
+ <Tbody>
132
+ {rows.map((row, i) => (
133
+ <Tr key={genericTableRowKey(row.rowId)}>
134
+ {row.cells.map((cell, j) => (
135
+ <Td key={`cell-${i}-${j}`} {...cell.props}>
136
+ {cell.title}
137
+ </Td>
138
+ ))}
139
+ </Tr>
50
140
  ))}
51
- </Tr>
52
- ))}
53
- </Tbody>
54
- </Table>
141
+ </Tbody>
142
+ </Table>
143
+ </>
144
+ )}
55
145
  </TableSummaryExpandable>
56
146
  );
57
147
  };
@@ -19,10 +19,7 @@ import { ReviewCustomManifestsTable } from './ReviewCustomManifestsTable';
19
19
  import PlatformIntegrationNote from '../platformIntegration/PlatformIntegrationNote';
20
20
  import useClusterCustomManifests from '../../../hooks/useClusterCustomManifests';
21
21
  import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
22
- import { ListManifestsExtended } from '../manifestsConfiguration/data/dataTypes';
23
-
24
- const userProvidedManifests = (manifests: ListManifestsExtended | undefined) =>
25
- (manifests ?? []).filter((m) => m.manifestSource !== 'system');
22
+ import { userProvidedManifests } from '../manifestsConfiguration/components/utils';
26
23
 
27
24
  export const ReviewSummaryContent = ({ cluster }: { cluster: Cluster }) => {
28
25
  const { customManifests } = useClusterCustomManifests(cluster.id, false);
@@ -0,0 +1,3 @@
1
+ .pf-v6-c-expandable-section:not(.pf-m-expanded) {
2
+ --pf-v6-c-expandable-section__content--MaxHeight: 0;
3
+ }
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ExpandableSection, Content } from '@patternfly/react-core';
3
+ import './TableSummaryExpandable.css';
3
4
 
4
5
  export const TableSummaryExpandable = ({
5
6
  title,
@@ -20,7 +21,6 @@ export const TableSummaryExpandable = ({
20
21
  id={id ? id : title}
21
22
  >
22
23
  {children}
23
- <br />
24
24
  </ExpandableSection>
25
25
  );
26
26
  };
@@ -8,6 +8,8 @@ import { useErrorMonitor } from '../../../../../common/components/ErrorHandling/
8
8
  import { getApiErrorMessage } from '../../../../../common/api';
9
9
  import { StaticIpFormProps } from './propTypes';
10
10
  import { selectCurrentClusterPermissionsState } from '../../../../store/slices/current-cluster/selectors';
11
+ import { useFeature } from '../../../../hooks/use-feature';
12
+ import { getStaticNetworkConfig } from '../data/fromInfraEnv';
11
13
 
12
14
  /** Reports form state and triggers save on every value change (useFormikAutoSave) */
13
15
  const AutosaveWithParentUpdate = <StaticIpFormValues extends object>({
@@ -69,7 +71,14 @@ export const StaticIpForm = <StaticIpFormValues extends object>({
69
71
  const { clearAlerts, addAlert } = useAlerts();
70
72
  const { captureException } = useErrorMonitor();
71
73
  const { isViewerMode } = useSelector(selectCurrentClusterPermissionsState);
72
- const initialValues = showEmptyValues ? getEmptyValues() : getInitialValues(infraEnv);
74
+ const isSingleClusterFeatureEnabled = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE');
75
+ const prefillFromInfraEnv = isSingleClusterFeatureEnabled && !!getStaticNetworkConfig(infraEnv);
76
+ const initialValues = React.useMemo(() => {
77
+ if (showEmptyValues && !prefillFromInfraEnv) {
78
+ return getEmptyValues();
79
+ }
80
+ return getInitialValues(infraEnv);
81
+ }, [showEmptyValues, prefillFromInfraEnv, infraEnv, getInitialValues, getEmptyValues]);
73
82
 
74
83
  const handleSubmit = async (values: StaticIpFormValues) => {
75
84
  clearAlerts();