@openshift-assisted/ui-lib 2.42.0 → 2.42.2

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 (68) hide show
  1. package/build/@types/common/components/newFeatureSupportLevels/types.d.ts +1 -1
  2. package/build/@types/common/components/newFeatureSupportLevels/types.d.ts.map +1 -1
  3. package/build/@types/common/components/operators/operatorDescriptions.d.ts +23 -0
  4. package/build/@types/common/components/operators/operatorDescriptions.d.ts.map +1 -0
  5. package/build/@types/common/components/operators/operatorSpecs.d.ts +32 -4
  6. package/build/@types/common/components/operators/operatorSpecs.d.ts.map +1 -1
  7. package/build/@types/common/components/operators/test.d.ts +50 -0
  8. package/build/@types/common/components/operators/test.d.ts.map +1 -0
  9. package/build/@types/ocm/components/clusterConfiguration/ControlPlaneNodesDropdown.d.ts +2 -0
  10. package/build/@types/ocm/components/clusterConfiguration/ControlPlaneNodesDropdown.d.ts.map +1 -1
  11. package/build/@types/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.d.ts.map +1 -1
  12. package/build/@types/ocm/components/clusterConfiguration/manifestsConfiguration/components/FolderDropdown.d.ts.map +1 -1
  13. package/build/@types/ocm/components/clusterConfiguration/operators/OperatorCheckbox.d.ts +2 -1
  14. package/build/@types/ocm/components/clusterConfiguration/operators/OperatorCheckbox.d.ts.map +1 -1
  15. package/build/@types/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.d.ts.map +1 -1
  16. package/build/@types/ocm/components/clusterWizard/OperatorsBundle.d.ts +2 -1
  17. package/build/@types/ocm/components/clusterWizard/OperatorsBundle.d.ts.map +1 -1
  18. package/build/@types/ocm/components/clusterWizard/OperatorsSelect.d.ts +2 -1
  19. package/build/@types/ocm/components/clusterWizard/OperatorsSelect.d.ts.map +1 -1
  20. package/build/@types/ocm/components/clusterWizard/OperatorsStep.d.ts.map +1 -1
  21. package/build/@types/ocm/components/featureSupportLevels/featureStateUtils.d.ts.map +1 -1
  22. package/build/cjs/common/components/clusterDetail/OperatorsProgressItem.js +1 -1
  23. package/build/cjs/common/components/clusterDetail/OperatorsProgressItem.js.map +1 -1
  24. package/build/cjs/common/components/operators/operatorDescriptions.js +26 -0
  25. package/build/cjs/common/components/operators/operatorDescriptions.js.map +1 -0
  26. package/build/cjs/common/components/operators/operatorSpecs.js +303 -190
  27. package/build/cjs/common/components/operators/operatorSpecs.js.map +1 -1
  28. package/build/cjs/common/components/operators/test.js +323 -0
  29. package/build/cjs/common/components/operators/test.js.map +1 -0
  30. package/build/cjs/ocm/components/clusterConfiguration/ControlPlaneNodesDropdown.js +20 -10
  31. package/build/cjs/ocm/components/clusterConfiguration/ControlPlaneNodesDropdown.js.map +1 -1
  32. package/build/cjs/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.js +16 -0
  33. package/build/cjs/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.js.map +1 -1
  34. package/build/cjs/ocm/components/clusterConfiguration/OcmOperatorProgressItem.js +1 -1
  35. package/build/cjs/ocm/components/clusterConfiguration/OcmOperatorProgressItem.js.map +1 -1
  36. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/FolderDropdown.js +1 -1
  37. package/build/cjs/ocm/components/clusterConfiguration/manifestsConfiguration/components/FolderDropdown.js.map +1 -1
  38. package/build/cjs/ocm/components/clusterConfiguration/operators/OperatorCheckbox.js +4 -4
  39. package/build/cjs/ocm/components/clusterConfiguration/operators/OperatorCheckbox.js.map +1 -1
  40. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.js +1 -1
  41. package/build/cjs/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.js.map +1 -1
  42. package/build/cjs/ocm/components/clusterDetail/ProgressBarAlerts.js +1 -1
  43. package/build/cjs/ocm/components/clusterDetail/ProgressBarAlerts.js.map +1 -1
  44. package/build/cjs/ocm/components/clusterWizard/OperatorsBundle.js +17 -18
  45. package/build/cjs/ocm/components/clusterWizard/OperatorsBundle.js.map +1 -1
  46. package/build/cjs/ocm/components/clusterWizard/OperatorsSelect.js +36 -20
  47. package/build/cjs/ocm/components/clusterWizard/OperatorsSelect.js.map +1 -1
  48. package/build/cjs/ocm/components/clusterWizard/OperatorsStep.js +13 -3
  49. package/build/cjs/ocm/components/clusterWizard/OperatorsStep.js.map +1 -1
  50. package/build/cjs/ocm/components/featureSupportLevels/featureStateUtils.js +5 -15
  51. package/build/cjs/ocm/components/featureSupportLevels/featureStateUtils.js.map +1 -1
  52. package/lib/common/components/clusterDetail/OperatorsProgressItem.tsx +1 -1
  53. package/lib/common/components/newFeatureSupportLevels/types.ts +1 -0
  54. package/lib/common/components/operators/operatorDescriptions.tsx +58 -0
  55. package/lib/common/components/operators/operatorSpecs.tsx +392 -264
  56. package/lib/common/components/operators/test.tsx +469 -0
  57. package/lib/ocm/components/clusterConfiguration/ControlPlaneNodesDropdown.tsx +26 -14
  58. package/lib/ocm/components/clusterConfiguration/OcmClusterDetailsFormFields.tsx +33 -1
  59. package/lib/ocm/components/clusterConfiguration/OcmOperatorProgressItem.tsx +1 -1
  60. package/lib/ocm/components/clusterConfiguration/manifestsConfiguration/components/FolderDropdown.tsx +1 -0
  61. package/lib/ocm/components/clusterConfiguration/operators/OperatorCheckbox.tsx +6 -3
  62. package/lib/ocm/components/clusterConfiguration/review/ReviewOperatorsTable.tsx +2 -1
  63. package/lib/ocm/components/clusterDetail/ProgressBarAlerts.tsx +1 -1
  64. package/lib/ocm/components/clusterWizard/OperatorsBundle.tsx +25 -23
  65. package/lib/ocm/components/clusterWizard/OperatorsSelect.tsx +67 -44
  66. package/lib/ocm/components/clusterWizard/OperatorsStep.tsx +30 -3
  67. package/lib/ocm/components/featureSupportLevels/featureStateUtils.ts +7 -18
  68. package/package.json +3 -3
@@ -0,0 +1,469 @@
1
+ import React from 'react';
2
+ import { Cluster, SupportLevel } from '@openshift-assisted/types/assisted-installer-service';
3
+ import { FeatureId } from '../../types';
4
+ import {
5
+ OPERATOR_NAME_AMD_GPU,
6
+ OPERATOR_NAME_AUTHORINO,
7
+ OPERATOR_NAME_CNV,
8
+ OPERATOR_NAME_KMM,
9
+ OPERATOR_NAME_LSO,
10
+ OPERATOR_NAME_LVM,
11
+ OPERATOR_NAME_MCE,
12
+ OPERATOR_NAME_MTV,
13
+ OPERATOR_NAME_NMSTATE,
14
+ OPERATOR_NAME_NODE_FEATURE_DISCOVERY,
15
+ OPERATOR_NAME_NVIDIA_GPU,
16
+ OPERATOR_NAME_ODF,
17
+ OPERATOR_NAME_OPENSHIFT_AI,
18
+ OPERATOR_NAME_OSC,
19
+ OPERATOR_NAME_PIPELINES,
20
+ OPERATOR_NAME_SERVERLESS,
21
+ OPERATOR_NAME_SERVICEMESH,
22
+ OPERATOR_NAME_NODE_MAINTENANCE,
23
+ OPERATOR_NAME_KUBE_DESCHEDULER,
24
+ } from '../../config/constants';
25
+ import { ExternalLink } from '../ui';
26
+ import {
27
+ AUTHORINO_OPERATOR_LINK,
28
+ CNV_LINK,
29
+ getKmmDocsLink,
30
+ getKubeDeschedulerLink,
31
+ getLsoLink,
32
+ getLvmsDocsLink,
33
+ getMceDocsLink,
34
+ getNmstateLink,
35
+ getNodeFeatureDiscoveryLink,
36
+ getNvidiaGpuLink,
37
+ getServiceMeshLink,
38
+ MTV_LINK,
39
+ NODE_MAINTENANCE_LINK,
40
+ ODF_LINK,
41
+ ODF_REQUIREMENTS_LINK,
42
+ OPENSHIFT_AI_LINK,
43
+ OPENSHIFT_AI_REQUIREMENTS_LINK,
44
+ OSC_LINK,
45
+ OSC_REQUIREMENTS_LINK,
46
+ PIPELINES_OPERATOR_LINK,
47
+ SERVERLESS_OPERATOR_LINK,
48
+ } from '../../config';
49
+ import { getMajorMinorVersion } from '../../utils';
50
+ import { GetFeatureSupportLevel, useNewFeatureSupportLevel } from '../newFeatureSupportLevels';
51
+ import {
52
+ DESCRIPTION_AMD_GPU,
53
+ DESCRIPTION_AUTHORINO,
54
+ DESCRIPTION_LSO,
55
+ DESCRIPTION_MTV,
56
+ DESCRIPTION_CNV,
57
+ DESCRIPTION_KMM,
58
+ DESCRIPTION_KUBE_DESCHEDULER,
59
+ DESCRIPTION_MCE,
60
+ DESCRIPTION_NMSTATE,
61
+ DESCRIPTION_NODE_FEATURE_DISCOVERY,
62
+ DESCRIPTION_NODE_MAINTENANCE,
63
+ DESCRIPTION_NVIDIA_GPU,
64
+ DESCRIPTION_ODF,
65
+ DESCRIPTION_OPENSHIFT_AI,
66
+ DESCRIPTION_OSC,
67
+ DESCRIPTION_PIPELINES,
68
+ DESCRIPTION_SERVERLESS,
69
+ DESCRIPTION_SERVICEMESH,
70
+ DESCRIPTION_LVM,
71
+ } from './operatorDescriptions';
72
+
73
+ // TODO check if it's unused and it can be deleted in favor of "isMajorMinorVersionEqualOrGreater"
74
+ export const isOCPVersionEqualsOrMore = (
75
+ openshiftVersion: string,
76
+ ocpVersionToCompare: string,
77
+ ): boolean => {
78
+ const [majorA, minorA] = getMajorMinorVersion(openshiftVersion).split('.');
79
+ const [majorB, minorB] = ocpVersionToCompare.split('.');
80
+ return (
81
+ Number(majorA) > Number(majorB) ||
82
+ (Number(majorA) === Number(majorB) && Number(minorA) >= Number(minorB))
83
+ );
84
+ };
85
+
86
+ export const highlightMatch = (text: string, searchTerm?: string): React.ReactNode => {
87
+ if (!searchTerm) return text;
88
+ const escapeSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
89
+ const regex = new RegExp(`(${escapeSearchTerm})`, 'gi');
90
+
91
+ const parts = text.split(regex);
92
+
93
+ return parts.map((part, i) =>
94
+ part.toLowerCase() === searchTerm.toLowerCase() ? <mark key={i}>{part}</mark> : part,
95
+ );
96
+ };
97
+
98
+ export const HighlightedText = ({ text, searchTerm }: { text: string; searchTerm?: string }) => (
99
+ <>{highlightMatch(text, searchTerm)}</>
100
+ );
101
+
102
+ export type OperatorSpec = {
103
+ operatorKey: string;
104
+ title: string;
105
+ featureId: FeatureId;
106
+ descriptionText?: string;
107
+ Description?: React.ComponentType<{ openshiftVersion?: string; searchTerm?: string }>;
108
+ notStandalone?: boolean;
109
+ Requirements?: React.ComponentType<{ cluster: Cluster }>;
110
+ supportLevel?: SupportLevel | undefined;
111
+ };
112
+
113
+ export const getOperatorSpecs = (
114
+ getFeatureSupportLevel: GetFeatureSupportLevel,
115
+ useLVMS?: boolean,
116
+ ): { [category: string]: OperatorSpec[] } => {
117
+ return {
118
+ [categories[Category.STORAGE]]: [
119
+ {
120
+ operatorKey: OPERATOR_NAME_LSO,
121
+ title: 'Local Storage Operator',
122
+ featureId: 'LSO',
123
+ descriptionText: DESCRIPTION_LSO,
124
+ Description: ({ openshiftVersion, searchTerm }) => (
125
+ <>
126
+ <HighlightedText text={DESCRIPTION_LSO} searchTerm={searchTerm} />{' '}
127
+ <ExternalLink href={getLsoLink(openshiftVersion)}>Learn more</ExternalLink>
128
+ </>
129
+ ),
130
+ notStandalone: true,
131
+ supportLevel: getFeatureSupportLevel('LSO'),
132
+ },
133
+ {
134
+ operatorKey: OPERATOR_NAME_LVM,
135
+ title: useLVMS ? 'Logical Volume Manager Storage' : 'Logical Volume Manager',
136
+ featureId: 'LVM',
137
+ descriptionText: DESCRIPTION_LVM,
138
+ Description: ({ openshiftVersion, searchTerm }) =>
139
+ useLVMS ? (
140
+ <>
141
+ <HighlightedText text={DESCRIPTION_LVM} searchTerm={searchTerm} />{' '}
142
+ <ExternalLink href={getLvmsDocsLink(openshiftVersion)}>Learn more</ExternalLink>
143
+ </>
144
+ ) : (
145
+ <>{DESCRIPTION_LVM}</>
146
+ ),
147
+ supportLevel: getFeatureSupportLevel('LVM'),
148
+ },
149
+ {
150
+ operatorKey: OPERATOR_NAME_ODF,
151
+ title: 'OpenShift Data Foundation',
152
+ featureId: 'ODF',
153
+ descriptionText: DESCRIPTION_ODF,
154
+ Requirements: () => (
155
+ <ExternalLink href={ODF_REQUIREMENTS_LINK}>
156
+ Learn more about the requirements for OpenShift Data Foundation
157
+ </ExternalLink>
158
+ ),
159
+ Description: ({ searchTerm }) => (
160
+ <>
161
+ <HighlightedText text={DESCRIPTION_ODF} searchTerm={searchTerm} />{' '}
162
+ <ExternalLink href={ODF_LINK}>Learn more</ExternalLink>
163
+ </>
164
+ ),
165
+ supportLevel: getFeatureSupportLevel('ODF'),
166
+ },
167
+ ],
168
+ [categories[Category.VIRT]]: [
169
+ {
170
+ operatorKey: OPERATOR_NAME_CNV,
171
+ title: 'OpenShift Virtualization',
172
+ featureId: 'CNV',
173
+ descriptionText: DESCRIPTION_CNV,
174
+ Requirements: () => (
175
+ <>Enabled CPU virtualization support in BIOS (Intel-VT / AMD-V) on all nodes</>
176
+ ),
177
+ Description: ({ searchTerm }) => (
178
+ <>
179
+ <HighlightedText text={DESCRIPTION_CNV} searchTerm={searchTerm} />{' '}
180
+ <ExternalLink href={CNV_LINK}>Learn more</ExternalLink>
181
+ </>
182
+ ),
183
+ supportLevel: getFeatureSupportLevel('CNV'),
184
+ },
185
+ {
186
+ operatorKey: OPERATOR_NAME_MTV,
187
+ title: 'Migration Toolkit for Virtualization',
188
+ featureId: 'MTV',
189
+ descriptionText: DESCRIPTION_MTV,
190
+ Description: ({ searchTerm }) => (
191
+ <>
192
+ <HighlightedText text={DESCRIPTION_MTV} searchTerm={searchTerm} />{' '}
193
+ <ExternalLink href={MTV_LINK}>Learn more</ExternalLink>
194
+ </>
195
+ ),
196
+ supportLevel: getFeatureSupportLevel('MTV'),
197
+ },
198
+ {
199
+ operatorKey: OPERATOR_NAME_OSC,
200
+ title: 'OpenShift sandboxed containers',
201
+ featureId: 'OSC',
202
+ descriptionText: DESCRIPTION_OSC,
203
+ Requirements: () => (
204
+ <ExternalLink href={OSC_REQUIREMENTS_LINK}>
205
+ Learn more about the requirements for OpenShift sandboxed containers
206
+ </ExternalLink>
207
+ ),
208
+ Description: () => (
209
+ <>
210
+ {DESCRIPTION_OSC} <ExternalLink href={OSC_LINK}>Learn more</ExternalLink>
211
+ </>
212
+ ),
213
+ supportLevel: getFeatureSupportLevel('OSC'),
214
+ },
215
+ ],
216
+ [categories[Category.AI]]: [
217
+ {
218
+ operatorKey: OPERATOR_NAME_OPENSHIFT_AI,
219
+ title: 'OpenShift AI',
220
+ featureId: 'OPENSHIFT_AI',
221
+ descriptionText: DESCRIPTION_OPENSHIFT_AI,
222
+ Requirements: () => (
223
+ <ExternalLink href={OPENSHIFT_AI_REQUIREMENTS_LINK}>Learn more</ExternalLink>
224
+ ),
225
+ Description: ({ searchTerm }) => (
226
+ <>
227
+ <HighlightedText text={DESCRIPTION_OPENSHIFT_AI} searchTerm={searchTerm} />{' '}
228
+ <ExternalLink href={OPENSHIFT_AI_LINK}>Learn more</ExternalLink>
229
+ </>
230
+ ),
231
+ supportLevel: getFeatureSupportLevel('OPENSHIFT_AI'),
232
+ },
233
+ {
234
+ operatorKey: OPERATOR_NAME_AMD_GPU,
235
+ title: 'AMD GPU',
236
+ featureId: 'AMD_GPU',
237
+ descriptionText: DESCRIPTION_AMD_GPU,
238
+ Requirements: () => <>Requires at least one supported AMD GPU</>,
239
+ Description: ({ searchTerm }) => (
240
+ <>
241
+ {' '}
242
+ <HighlightedText text={DESCRIPTION_AMD_GPU} searchTerm={searchTerm} />{' '}
243
+ </>
244
+ ),
245
+ supportLevel: getFeatureSupportLevel('AMD_GPU'),
246
+ },
247
+ {
248
+ operatorKey: OPERATOR_NAME_NVIDIA_GPU,
249
+ title: 'NVIDIA GPU',
250
+ featureId: 'NVIDIA_GPU',
251
+ descriptionText: DESCRIPTION_NVIDIA_GPU,
252
+ Requirements: () => <>Requires at least one supported NVIDIA GPU</>,
253
+ Description: ({ openshiftVersion, searchTerm }) => (
254
+ <>
255
+ <HighlightedText text={DESCRIPTION_NVIDIA_GPU} searchTerm={searchTerm} />{' '}
256
+ <ExternalLink href={getNvidiaGpuLink(openshiftVersion)}>Learn more</ExternalLink>
257
+ </>
258
+ ),
259
+ supportLevel: getFeatureSupportLevel('NVIDIA_GPU'),
260
+ },
261
+ ],
262
+ [categories[Category.NETWORK]]: [
263
+ {
264
+ operatorKey: OPERATOR_NAME_NMSTATE,
265
+ title: 'NMState',
266
+ featureId: 'NMSTATE',
267
+ descriptionText: DESCRIPTION_NMSTATE,
268
+ Description: ({ openshiftVersion, searchTerm }) => (
269
+ <>
270
+ <HighlightedText text={DESCRIPTION_NMSTATE} searchTerm={searchTerm} />{' '}
271
+ <ExternalLink href={getNmstateLink(openshiftVersion)}>Learn more</ExternalLink>
272
+ </>
273
+ ),
274
+ supportLevel: getFeatureSupportLevel('NMSTATE'),
275
+ },
276
+ {
277
+ operatorKey: OPERATOR_NAME_SERVICEMESH,
278
+ title: 'Service Mesh',
279
+ featureId: 'SERVICEMESH',
280
+ descriptionText: DESCRIPTION_SERVICEMESH,
281
+ Description: ({ openshiftVersion, searchTerm }) => (
282
+ <>
283
+ <HighlightedText text={DESCRIPTION_SERVICEMESH} searchTerm={searchTerm} />{' '}
284
+ <ExternalLink href={getServiceMeshLink(openshiftVersion)}>Learn more</ExternalLink>
285
+ </>
286
+ ),
287
+ notStandalone: true,
288
+ supportLevel: getFeatureSupportLevel('SERVICEMESH'),
289
+ },
290
+ ],
291
+ [categories[Category.SECURITY]]: [
292
+ {
293
+ operatorKey: OPERATOR_NAME_AUTHORINO,
294
+ title: 'Authorino',
295
+ featureId: 'AUTHORINO',
296
+ descriptionText: DESCRIPTION_AUTHORINO,
297
+ Description: ({ searchTerm }) => (
298
+ <>
299
+ <HighlightedText text={DESCRIPTION_AUTHORINO} searchTerm={searchTerm} />{' '}
300
+ <ExternalLink href={AUTHORINO_OPERATOR_LINK}>Learn more</ExternalLink>
301
+ </>
302
+ ),
303
+ notStandalone: true,
304
+ supportLevel: getFeatureSupportLevel('AUTHORINO'),
305
+ },
306
+ {
307
+ operatorKey: OPERATOR_NAME_KMM,
308
+ title: 'Kernel Module Management',
309
+ featureId: 'KMM',
310
+ descriptionText: DESCRIPTION_KMM,
311
+ Description: ({ openshiftVersion, searchTerm }) => (
312
+ <>
313
+ <HighlightedText text={DESCRIPTION_KMM} searchTerm={searchTerm} />{' '}
314
+ <ExternalLink href={getKmmDocsLink(openshiftVersion)}>Learn more</ExternalLink>
315
+ </>
316
+ ),
317
+ supportLevel: getFeatureSupportLevel('KMM'),
318
+ },
319
+ ],
320
+ [categories[Category.CI_CD]]: [
321
+ {
322
+ operatorKey: OPERATOR_NAME_PIPELINES,
323
+ title: 'Pipelines',
324
+ featureId: 'PIPELINES',
325
+ descriptionText: DESCRIPTION_PIPELINES,
326
+ Description: ({ searchTerm }) => (
327
+ <>
328
+ <HighlightedText text={DESCRIPTION_PIPELINES} searchTerm={searchTerm} />{' '}
329
+ <ExternalLink href={PIPELINES_OPERATOR_LINK}>Learn more</ExternalLink>
330
+ </>
331
+ ),
332
+ notStandalone: true,
333
+ supportLevel: getFeatureSupportLevel('PIPELINES'),
334
+ },
335
+ {
336
+ operatorKey: OPERATOR_NAME_SERVERLESS,
337
+ title: 'Serverless',
338
+ featureId: 'SERVERLESS',
339
+ descriptionText: DESCRIPTION_SERVERLESS,
340
+ Description: ({ searchTerm }) => (
341
+ <>
342
+ <HighlightedText text={DESCRIPTION_SERVERLESS} searchTerm={searchTerm} />{' '}
343
+ <ExternalLink href={SERVERLESS_OPERATOR_LINK}>Learn more</ExternalLink>
344
+ </>
345
+ ),
346
+ notStandalone: true,
347
+ supportLevel: getFeatureSupportLevel('SERVERLESS'),
348
+ },
349
+ ],
350
+ [categories[Category.PLATFORM]]: [
351
+ {
352
+ operatorKey: OPERATOR_NAME_MCE,
353
+ title: 'Multicluster engine',
354
+ featureId: 'MCE',
355
+ descriptionText: DESCRIPTION_MCE,
356
+ Description: ({ openshiftVersion, searchTerm }) => (
357
+ <>
358
+ <HighlightedText text={DESCRIPTION_MCE} searchTerm={searchTerm} />{' '}
359
+ <ExternalLink href={getMceDocsLink(openshiftVersion)}>Learn more</ExternalLink>
360
+ </>
361
+ ),
362
+ supportLevel: getFeatureSupportLevel('MCE'),
363
+ },
364
+ {
365
+ operatorKey: OPERATOR_NAME_NODE_MAINTENANCE,
366
+ title: 'Node Maintenance',
367
+ featureId: 'NODE_MAINTENANCE',
368
+ descriptionText: DESCRIPTION_NODE_MAINTENANCE,
369
+ Description: () => (
370
+ <>
371
+ {DESCRIPTION_NODE_MAINTENANCE}{' '}
372
+ <ExternalLink href={NODE_MAINTENANCE_LINK}>Learn more</ExternalLink>
373
+ </>
374
+ ),
375
+ notStandalone: true,
376
+ supportLevel: getFeatureSupportLevel('NODE_MAINTENANCE'),
377
+ },
378
+ ],
379
+ [categories[Category.SCHEDULING]]: [
380
+ {
381
+ operatorKey: OPERATOR_NAME_NODE_FEATURE_DISCOVERY,
382
+ title: 'Node Feature Discovery',
383
+ featureId: 'NODE_FEATURE_DISCOVERY',
384
+ descriptionText: DESCRIPTION_NODE_FEATURE_DISCOVERY,
385
+ Description: ({ openshiftVersion }) => (
386
+ <>
387
+ {DESCRIPTION_NODE_FEATURE_DISCOVERY}{' '}
388
+ <ExternalLink href={getNodeFeatureDiscoveryLink(openshiftVersion)}>
389
+ Learn more
390
+ </ExternalLink>
391
+ </>
392
+ ),
393
+ supportLevel: getFeatureSupportLevel('NODE_FEATURE_DISCOVERY'),
394
+ },
395
+ {
396
+ operatorKey: OPERATOR_NAME_KUBE_DESCHEDULER,
397
+ title: 'Kube Descheduler',
398
+ featureId: 'KUBE_DESCHEDULER',
399
+ descriptionText: DESCRIPTION_KUBE_DESCHEDULER,
400
+ Description: ({ openshiftVersion, searchTerm }) => (
401
+ <>
402
+ <HighlightedText text={DESCRIPTION_KUBE_DESCHEDULER} searchTerm={searchTerm} />{' '}
403
+ <ExternalLink href={getKubeDeschedulerLink(openshiftVersion)}>Learn more</ExternalLink>
404
+ </>
405
+ ),
406
+ notStandalone: true,
407
+ supportLevel: getFeatureSupportLevel('KUBE_DESCHEDULER'),
408
+ },
409
+ ],
410
+ };
411
+ };
412
+
413
+ export const useOperatorSpecs = () => {
414
+ const { getFeatureSupportLevel } = useNewFeatureSupportLevel();
415
+ const useLVMS = getFeatureSupportLevel('LVM') === 'supported';
416
+
417
+ // Grouped by category
418
+ const byCategory = React.useMemo(
419
+ () => getOperatorSpecs(getFeatureSupportLevel, useLVMS),
420
+ [getFeatureSupportLevel, useLVMS],
421
+ );
422
+
423
+ // Flat map operatorKey -> spec
424
+ const byKey: Record<string, OperatorSpec> = React.useMemo(() => {
425
+ return Object.values(byCategory).reduce((acc, specs) => {
426
+ specs.forEach((spec) => {
427
+ acc[spec.operatorKey] = spec;
428
+ });
429
+ return acc;
430
+ }, {} as Record<string, OperatorSpec>);
431
+ }, [byCategory]);
432
+
433
+ return { byCategory, byKey };
434
+ };
435
+
436
+ export const getOperatorTitleByFeatureId = (featureId: FeatureId): string | undefined => {
437
+ const allSpecs = getOperatorSpecs(() => undefined);
438
+
439
+ for (const categorySpecs of Object.values(allSpecs)) {
440
+ const spec = categorySpecs.find((s) => s.featureId === featureId);
441
+ if (spec) {
442
+ return spec.title;
443
+ }
444
+ }
445
+
446
+ return undefined;
447
+ };
448
+
449
+ enum Category {
450
+ STORAGE,
451
+ VIRT,
452
+ AI,
453
+ NETWORK,
454
+ CI_CD,
455
+ PLATFORM,
456
+ SECURITY,
457
+ SCHEDULING,
458
+ }
459
+
460
+ export const categories: { [key in Category]: string } = {
461
+ [Category.STORAGE]: 'Storage',
462
+ [Category.VIRT]: 'Virtualization',
463
+ [Category.AI]: 'AI',
464
+ [Category.NETWORK]: 'Network',
465
+ [Category.SECURITY]: 'Security & Access Control',
466
+ [Category.CI_CD]: 'CI/CD & Dev Productivity',
467
+ [Category.PLATFORM]: 'Platform Operations & Lifecycle',
468
+ [Category.SCHEDULING]: 'Scheduling',
469
+ };
@@ -9,18 +9,19 @@ import {
9
9
  DropdownList,
10
10
  } from '@patternfly/react-core';
11
11
  import { useField } from 'formik';
12
- import { getFieldId, PopoverIcon } from '../../../common';
12
+ import { getFieldId, PopoverIcon, PreviewBadgePosition, TechnologyPreview } from '../../../common';
13
13
  import {
14
14
  NewFeatureSupportLevelMap,
15
15
  useNewFeatureSupportLevel,
16
16
  } from '../../../common/components/newFeatureSupportLevels';
17
+ import { isFeatureSupportedAndAvailable } from '../featureSupportLevels/featureStateUtils';
17
18
  import OcmTNADisclaimer from './OcmTNADisclaimer';
18
19
  import toNumber from 'lodash-es/toNumber';
19
20
  import OcmSNODisclaimer from './OcmSNODisclaimer';
20
21
 
21
22
  const INPUT_NAME = 'controlPlaneCount';
22
23
  const fieldId = getFieldId(INPUT_NAME, 'input');
23
- const DEFAULT_VALUE = 3;
24
+ export const DEFAULT_VALUE_CPN = 3;
24
25
 
25
26
  export const ControlPlaneNodesLabel = () => {
26
27
  return (
@@ -42,13 +43,14 @@ export const ControlPlaneNodesLabel = () => {
42
43
  interface ControlPlaneNodesOption {
43
44
  value: number;
44
45
  label: string;
46
+ badge?: React.ReactNode;
45
47
  }
46
48
 
47
49
  interface ControlPlaneNodesDropdownProps {
48
50
  featureSupportLevelData?: NewFeatureSupportLevelMap | null;
49
51
  }
50
52
 
51
- const isDropdownItemEnabled = (
53
+ export const isCPNDropdownItemEnabled = (
52
54
  controlPlaneNodeCount: number,
53
55
  isNonStandardControlPlaneEnabled: boolean,
54
56
  isTnaEnabled: boolean,
@@ -83,29 +85,37 @@ const ControlPlaneNodesDropdown: React.FC<ControlPlaneNodesDropdownProps> = ({
83
85
  );
84
86
 
85
87
  const disabledReason =
86
- 'This option is not available with the current configurations. Make sure that OpenShift version is 4.18 or newer, CPU architecture is x86_64 and no external platform integration is selected.';
88
+ 'This option is not available with the current configurations. Make sure that OpenShift version is 4.19 or newer and no external platform integration is selected.';
87
89
 
88
90
  const isNonStandardControlPlaneEnabled = newFeatureSupportLevelContext.isFeatureSupported(
89
91
  'NON_STANDARD_HA_CONTROL_PLANE',
90
92
  featureSupportLevelData ?? undefined,
91
93
  );
92
94
 
95
+ const tnaSupport = newFeatureSupportLevelContext.getFeatureSupportLevel(
96
+ 'TNA',
97
+ featureSupportLevelData ?? undefined,
98
+ );
99
+ const isTnaEnabled = isFeatureSupportedAndAvailable(tnaSupport || 'unsupported');
100
+
93
101
  const options: ControlPlaneNodesOption[] = [
94
102
  { value: 1, label: '1 (Single Node OpenShift)' },
95
- { value: 2, label: '2 (Two-Nodes Arbiter)' },
103
+ {
104
+ value: 2,
105
+ label: '2 (Two-Nodes Arbiter)',
106
+ badge:
107
+ tnaSupport === 'tech-preview' ? (
108
+ <TechnologyPreview position={PreviewBadgePosition.default} />
109
+ ) : undefined,
110
+ },
96
111
  { value: 3, label: '3 (highly available cluster)' },
97
112
  { value: 4, label: '4 (highly available cluster+)' },
98
113
  { value: 5, label: '5 (highly available cluster++)' },
99
114
  ];
100
115
 
101
- const isTnaEnabled = newFeatureSupportLevelContext.isFeatureSupported(
102
- 'TNA',
103
- featureSupportLevelData ?? undefined,
104
- );
105
-
106
116
  React.useEffect(() => {
107
117
  if (!field.value) {
108
- setValue(DEFAULT_VALUE);
118
+ setValue(DEFAULT_VALUE_CPN);
109
119
  }
110
120
  }, [field.value, setValue]);
111
121
 
@@ -115,8 +125,8 @@ const ControlPlaneNodesDropdown: React.FC<ControlPlaneNodesDropdownProps> = ({
115
125
  setOpen(false);
116
126
  };
117
127
 
118
- const dropdownItems = options.map(({ value, label }) => {
119
- const isItemEnabled = isDropdownItemEnabled(
128
+ const dropdownItems = options.map(({ value, label, badge }) => {
129
+ const isItemEnabled = isCPNDropdownItemEnabled(
120
130
  value,
121
131
  isNonStandardControlPlaneEnabled,
122
132
  isTnaEnabled,
@@ -124,7 +134,9 @@ const ControlPlaneNodesDropdown: React.FC<ControlPlaneNodesDropdownProps> = ({
124
134
  return (
125
135
  <DropdownItem key={value} id={value.toString()} isAriaDisabled={!isItemEnabled}>
126
136
  <Tooltip hidden={isItemEnabled} content={disabledReason} position="top">
127
- <div>{label}</div>
137
+ <div>
138
+ {label} {badge}
139
+ </div>
128
140
  </Tooltip>
129
141
  </DropdownItem>
130
142
  );
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  import * as React from 'react';
2
3
  import { Form } from '@patternfly/react-core';
3
4
  import { useFormikContext } from 'formik';
@@ -32,7 +33,11 @@ import { ExternalPlatformLabels } from './platformIntegration/constants';
32
33
  import { ManagedDomain, PlatformType } from '@openshift-assisted/types/assisted-installer-service';
33
34
  import { useClusterWizardContext } from '../clusterWizard/ClusterWizardContext';
34
35
  import { useFeature } from '../../hooks/use-feature';
35
- import ControlPlaneNodesDropdown, { ControlPlaneNodesLabel } from './ControlPlaneNodesDropdown';
36
+ import ControlPlaneNodesDropdown, {
37
+ ControlPlaneNodesLabel,
38
+ DEFAULT_VALUE_CPN,
39
+ isCPNDropdownItemEnabled,
40
+ } from './ControlPlaneNodesDropdown';
36
41
 
37
42
  export type OcmClusterDetailsFormFieldsProps = {
38
43
  forceOpenshiftVersion?: string;
@@ -115,6 +120,33 @@ export const OcmClusterDetailsFormFields = ({
115
120
  );
116
121
  }, [setFieldValue, featureSupportLevelContext, featureSupportLevelData]);
117
122
 
123
+ React.useEffect(() => {
124
+ const currentCount = values.controlPlaneCount;
125
+ const isNonStandardControlPlaneEnabled = featureSupportLevelContext.isFeatureSupported(
126
+ 'NON_STANDARD_HA_CONTROL_PLANE',
127
+ featureSupportLevelData ?? undefined,
128
+ );
129
+ const isTnaEnabled = featureSupportLevelContext.isFeatureSupported(
130
+ 'TNA',
131
+ featureSupportLevelData ?? undefined,
132
+ );
133
+
134
+ const isItemEnabled = isCPNDropdownItemEnabled(
135
+ currentCount,
136
+ isNonStandardControlPlaneEnabled,
137
+ isTnaEnabled,
138
+ );
139
+
140
+ if (!isItemEnabled) {
141
+ setFieldValue('controlPlaneCount', DEFAULT_VALUE_CPN, false);
142
+ }
143
+ }, [
144
+ values.openshiftVersion,
145
+ featureSupportLevelData,
146
+ featureSupportLevelContext,
147
+ values.controlPlaneCount,
148
+ setFieldValue,
149
+ ]);
118
150
  return (
119
151
  <Form id="wizard-cluster-details__form">
120
152
  <OcmRichInputField
@@ -80,7 +80,7 @@ type OperatorsPopoverProps = OperatorListProps & {
80
80
 
81
81
  const OperatorsPopover = ({ operators, children }: OperatorsPopoverProps) => {
82
82
  const { t } = useTranslation();
83
- const opSpecs = useOperatorSpecs();
83
+ const { byKey: opSpecs } = useOperatorSpecs();
84
84
 
85
85
  return (
86
86
  <Popover
@@ -56,6 +56,7 @@ export const FolderDropdown = ({ name }: FolderDropdownProps) => {
56
56
  onClick={() => setOpen(!isOpen)}
57
57
  isExpanded={isOpen}
58
58
  className="pf-v5-u-w-100"
59
+ id={fieldId}
59
60
  >
60
61
  {value || 'manifests'}
61
62
  </MenuToggle>
@@ -26,6 +26,7 @@ import { getFieldId, OperatorsValues, PopoverIcon } from '../../../../common';
26
26
  import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
27
27
  import { getNewOperators } from './utils';
28
28
  import {
29
+ highlightMatch,
29
30
  OperatorSpec,
30
31
  useOperatorSpecs,
31
32
  } from '../../../../common/components/operators/operatorSpecs';
@@ -118,15 +119,17 @@ const OperatorCheckbox = ({
118
119
  Requirements,
119
120
  openshiftVersion,
120
121
  preflightRequirements,
122
+ searchTerm,
121
123
  }: {
122
124
  bundles: Bundle[];
123
125
  cluster: Cluster;
124
126
  operatorId: string;
125
127
  openshiftVersion?: string;
126
128
  preflightRequirements: PreflightHardwareRequirements | undefined;
129
+ searchTerm?: string;
127
130
  } & OperatorSpec) => {
128
131
  const { getFeatureSupportLevel, getFeatureDisabledReason } = useNewFeatureSupportLevel();
129
- const opSpecs = useOperatorSpecs();
132
+ const { byKey: opSpecs } = useOperatorSpecs();
130
133
 
131
134
  const { isViewerMode } = useSelector(selectCurrentClusterPermissionsState);
132
135
  const { values, setFieldValue } = useFormikContext<OperatorsValues>();
@@ -166,7 +169,7 @@ const OperatorCheckbox = ({
166
169
  label={
167
170
  <>
168
171
  <Tooltip hidden={!disabledReason} content={disabledReason}>
169
- <span>{title} </span>
172
+ <span>{highlightMatch(title, searchTerm)} </span>
170
173
  </Tooltip>
171
174
  <OperatorRequirements
172
175
  operatorId={operatorId}
@@ -196,7 +199,7 @@ const OperatorCheckbox = ({
196
199
  !!Description && (
197
200
  <HelperText>
198
201
  <HelperTextItem variant="indeterminate">
199
- <Description openshiftVersion={openshiftVersion} />
202
+ <Description openshiftVersion={openshiftVersion} searchTerm={searchTerm} />
200
203
  </HelperTextItem>
201
204
  </HelperText>
202
205
  )