Repository: openshift-assisted/assisted-installer-ui
Pull request #2884: MGMT-20200: Add new operators to virtualization bundle
Author: login: danmanor
Labels: name: lgtm
description: Indicates that a PR is ready to be merged.
name: approved
description: Indicates a PR has been approved by an approver from all required OWNERS files.
name: size/L
description: Denotes a PR that changes 100-499 lines, ignoring generated files.
name: jira/valid-reference
description: Indicates that this PR references a valid Jira ticket of any type.
Created: 2025-03-30T16:28:10Z | Merged: 2025-04-01T14:05:14Z

This PR adds 5 new operators to the virtualization bundle:

1. `Node Healthcheck`.
2. `Self Node Remediation`.
3. `Fence Agents Remdiation`.
4. `Node Miantenance`.
5. `Kube Descheduler`.

All these operators are enabled only when the bundle is selected.

![image](https://github.com/user-attachments/assets/661685e6-dfda-46e6-a71c-273e8b516310)

![image](https://github.com/user-attachments/assets/39a902be-0e0a-4257-bb5b-e5b07e6830eb)


Diff:
diff --git a/libs/locales/lib/en/translation.json b/libs/locales/lib/en/translation.json
index 505088900c..f5dc9c123f 100644
--- a/libs/locales/lib/en/translation.json
+++ b/libs/locales/lib/en/translation.json
@@ -336,6 +336,8 @@
   "ai:Failed to update the AgentServiceConfig": "Failed to update the AgentServiceConfig",
   "ai:Failed validations:": "Failed validations:",
   "ai:Failing infrastructure environment": "Failing infrastructure environment",
+  "ai:Fence Agents Remediation": "Fence Agents Remediation",
+  "ai:Fence Agents Remediation requirements": "Fence Agents Remediation requirements",
   "ai:File is not structured correctly. Use the template to use the right file structure.": "File is not structured correctly. Use the template to use the right file structure.",
   "ai:File size is too big. Upload a new {{maxFileSizeKb}} Kb or less.": "File size is too big. Upload a new file that is {{maxFileSizeKb}} Kb or less.",
   "ai:File type is not supported. File type must be {{acceptedFiles}}.": "File type is not supported. File type must be {{acceptedFiles}}.",
@@ -476,6 +478,8 @@
   "ai:Keep the field empty to match <bold>any</bold> location.": "Keep the field empty to match <bold>any</bold> location.",
   "ai:Kernel Module Management": "Kernel Module Management",
   "ai:Kernel Module Management requirements": "Kernel Module Management requirements",
+  "ai:Kube Descheduler": "Kube Descheduler",
+  "ai:Kube Descheduler requirements": "Kube Descheduler requirements",
   "ai:Kubeconfig is empty.": "Kubeconfig is empty.",
   "ai:Labels": "Labels",
   "ai:Labels matching hosts": "Labels matching hosts",
@@ -591,6 +595,10 @@
   "ai:No version selected": "No version selected",
   "ai:Node Feature Discovery": "Node Feature Discovery",
   "ai:Node Feature Discovery requirements": "Node Feature Discovery requirements",
+  "ai:Node Healthcheck": "Node Healthcheck",
+  "ai:Node Healthcheck requirements": "Node Healthcheck requirements",
+  "ai:Node Maintenace": "Node Maintenace",
+  "ai:Node Maintenance requirements": "Node Maintenance requirements",
   "ai:Nodepool": "Nodepool",
   "ai:Nodepool conditions": "Nodepool conditions",
   "ai:Nodepool name": "Nodepool name",
@@ -731,6 +739,8 @@
   "ai:Select one or multiple locations to choose the hosts from.": "Select one or multiple locations of the hosts.",
   "ai:selected": "selected",
   "ai:Selected image does not support arm64": "Selected image does not support arm64",
+  "ai:Self Node Remediation": "Self Node Remediation",
+  "ai:Self Node Remediation requirements": "Self Node Remediation requirements",
   "ai:Serial": "Serial",
   "ai:Serial number": "Serial number",
   "ai:Serverless": "Serverless",
diff --git a/libs/types/assisted-installer-service.d.ts b/libs/types/assisted-installer-service.d.ts
index c59feb49c0..0583e69dee 100644
--- a/libs/types/assisted-installer-service.d.ts
+++ b/libs/types/assisted-installer-service.d.ts
@@ -658,7 +658,12 @@ export type ClusterValidationId =
   | 'authorino-requirements-satisfied'
   | 'nmstate-requirements-satisfied'
   | 'amd-gpu-requirements-satisfied'
-  | 'kmm-requirements-satisfied';
+  | 'kmm-requirements-satisfied'
+  | 'node-healthcheck-requirements-satisfied'
+  | 'self-node-remediation-requirements-satisfied'
+  | 'fence-agents-remediation-requirements-satisfied'
+  | 'node-maintenance-requirements-satisfied'
+  | 'kube-descheduler-requirements-satisfied';
 export interface CompletionParams {
   isSuccess: boolean;
   errorInfo?: string;
@@ -1053,7 +1058,12 @@ export type FeatureSupportLevelId =
   | 'USER_MANAGED_LOAD_BALANCER'
   | 'NMSTATE'
   | 'AMD_GPU'
-  | 'KMM';
+  | 'KMM'
+  | 'NODE_HEALTHCHECK'
+  | 'SELF_NODE_REMEDIATION'
+  | 'FENCE_AGENTS_REMEDIATION'
+  | 'NODE_MAINTENANCE'
+  | 'KUBE_DESCHEDULER';
 /**
  * Cluster finalizing stage managed by controller
  */
@@ -1609,7 +1619,12 @@ export type HostValidationId =
   | 'mtu-valid'
   | 'nmstate-requirements-satisfied'
   | 'amd-gpu-requirements-satisfied'
-  | 'kmm-requirements-satisfied';
+  | 'kmm-requirements-satisfied'
+  | 'node-healthcheck-requirements-satisfied'
+  | 'self-node-remediation-requirements-satisfied'
+  | 'fence-agents-remediation-requirements-satisfied'
+  | 'node-maintenance-requirements-satisfied'
+  | 'kube-descheduler-requirements-satisfied';
 /**
  * Explicit ignition endpoint overrides the default ignition endpoint.
  */
diff --git a/libs/ui-lib/lib/common/config/constants.ts b/libs/ui-lib/lib/common/config/constants.ts
index 3ca54af0b4..2029663cda 100644
--- a/libs/ui-lib/lib/common/config/constants.ts
+++ b/libs/ui-lib/lib/common/config/constants.ts
@@ -140,6 +140,11 @@ export const hostValidationLabels = (t: TFunction): { [key in HostValidationId]:
   'nmstate-requirements-satisfied': '',
   'amd-gpu-requirements-satisfied': t('ai:AMD GPU requirements'),
   'kmm-requirements-satisfied': t('ai:Kernel Module Management requirements'),
+  'node-healthcheck-requirements-satisfied': t('ai:Node Healthcheck requirements'),
+  'self-node-remediation-requirements-satisfied': t('ai:Self Node Remediation requirements'),
+  'fence-agents-remediation-requirements-satisfied': t('ai:Fence Agents Remediation requirements'),
+  'node-maintenance-requirements-satisfied': t('ai:Node Maintenance requirements'),
+  'kube-descheduler-requirements-satisfied': t('ai:Kube Descheduler requirements'),
 });
 
 export const hostValidationFailureHints = (
@@ -202,6 +207,11 @@ export const hostValidationFailureHints = (
   'nmstate-requirements-satisfied': '',
   'amd-gpu-requirements-satisfied': '',
   'kmm-requirements-satisfied': '',
+  'node-healthcheck-requirements-satisfied': '',
+  'self-node-remediation-requirements-satisfied': '',
+  'fence-agents-remediation-requirements-satisfied': '',
+  'node-maintenance-requirements-satisfied': '',
+  'kube-descheduler-requirements-satisfied': '',
 });
 
 export const clusterValidationLabels = (
@@ -307,6 +317,11 @@ export const OPERATOR_NAME_NMSTATE = 'nmstate';
 export const OPERATOR_NAME_AUTHORINO = 'authorino';
 export const OPERATOR_NAME_AMD_GPU = 'amd-gpu';
 export const OPERATOR_NAME_KMM = 'kmm';
+export const OPERATOR_NAME_NODE_HEALTHCHECK = 'node-healthcheck';
+export const OPERATOR_NAME_SELF_NODE_REMEDIATION = 'self-node-remediation';
+export const OPERATOR_NAME_FENCE_AGENTS_REMEDIATION = 'fence-agents-remediation';
+export const OPERATOR_NAME_NODE_MAINTENANCE = 'node-maintenance';
+export const OPERATOR_NAME_KUBE_DESCHEDULER = 'kube-descheduler';
 
 const OperatorNames = [
   OPERATOR_NAME_CNV,
@@ -327,6 +342,11 @@ const OperatorNames = [
   OPERATOR_NAME_AUTHORINO,
   OPERATOR_NAME_AMD_GPU,
   OPERATOR_NAME_KMM,
+  OPERATOR_NAME_NODE_HEALTHCHECK,
+  OPERATOR_NAME_SELF_NODE_REMEDIATION,
+  OPERATOR_NAME_FENCE_AGENTS_REMEDIATION,
+  OPERATOR_NAME_NODE_MAINTENANCE,
+  OPERATOR_NAME_KUBE_DESCHEDULER,
 ];
 export const ExposedOperatorNames = [
   OPERATOR_NAME_CNV,
@@ -346,6 +366,11 @@ export const ExposedOperatorNames = [
   OPERATOR_NAME_AUTHORINO,
   OPERATOR_NAME_AMD_GPU,
   OPERATOR_NAME_KMM,
+  OPERATOR_NAME_NODE_HEALTHCHECK,
+  OPERATOR_NAME_SELF_NODE_REMEDIATION,
+  OPERATOR_NAME_FENCE_AGENTS_REMEDIATION,
+  OPERATOR_NAME_NODE_MAINTENANCE,
+  OPERATOR_NAME_KUBE_DESCHEDULER,
 ];
 
 export type OperatorName = (typeof OperatorNames)[number];
@@ -393,6 +418,11 @@ export const operatorLabels = (
     [OPERATOR_NAME_AUTHORINO]: t('ai:Authorino'),
     [OPERATOR_NAME_AMD_GPU]: t('ai:AMD GPU'),
     [OPERATOR_NAME_KMM]: t('ai:Kernel Module Management'),
+    [OPERATOR_NAME_NODE_HEALTHCHECK]: t('ai:Node Healthcheck'),
+    [OPERATOR_NAME_SELF_NODE_REMEDIATION]: t('ai:Self Node Remediation'),
+    [OPERATOR_NAME_FENCE_AGENTS_REMEDIATION]: t('ai:Fence Agents Remediation'),
+    [OPERATOR_NAME_NODE_MAINTENANCE]: t('ai:Node Maintenace'),
+    [OPERATOR_NAME_KUBE_DESCHEDULER]: t('ai:Kube Descheduler'),
   };
 };
 
diff --git a/libs/ui-lib/lib/common/config/docs_links.ts b/libs/ui-lib/lib/common/config/docs_links.ts
index 9c2a4ddda6..2114a14de4 100644
--- a/libs/ui-lib/lib/common/config/docs_links.ts
+++ b/libs/ui-lib/lib/common/config/docs_links.ts
@@ -105,6 +105,23 @@ export const getLvmsDocsLink = (ocpVersion?: string) =>
     ocpVersion,
   )}/html/storage/configuring-persistent-storage#overview-of-lvm-storage-functionality_ways-to-provision-local-storage`;
 
+export const NODE_HEALTHCHECK_LINK =
+  'https://docs.redhat.com/en/documentation/workload_availability_for_red_hat_openshift/latest/html/remediation_fencing_and_maintenance/node-health-check-operator';
+
+export const SELF_NODE_REMEDIATION_LINK =
+  'https://docs.redhat.com/en/documentation/workload_availability_for_red_hat_openshift/latest/html/remediation_fencing_and_maintenance/self-node-remediation-operator-remediate-nodes';
+
+export const FENCE_AGENTS_REMEDIATION_LINK =
+  'https://docs.redhat.com/en/documentation/workload_availability_for_red_hat_openshift/latest/html/remediation_fencing_and_maintenance/fence-agents-remediation-operator-remediate-nodes';
+
+export const NODE_MAINTENANCE_LINK =
+  'https://docs.redhat.com/en/documentation/workload_availability_for_red_hat_openshift/latest/html/remediation_fencing_and_maintenance/node-maintenance-operator';
+
+export const getKubeDeschedulerLink = (ocpVersion?: string) =>
+  `https://docs.redhat.com/en/documentation/openshift_container_platform/${getShortOpenshiftVersion(
+    ocpVersion,
+  )}/html/nodes/controlling-pod-placement-onto-nodes-scheduling#descheduler`;
+
 //Others
 export const REDHAT_CONSOLE_OPENSHIFT = 'https://console.redhat.com/openshift';
 
diff --git a/libs/ui-lib/lib/common/types/clusters.ts b/libs/ui-lib/lib/common/types/clusters.ts
index 9321545e25..d3d0844551 100644
--- a/libs/ui-lib/lib/common/types/clusters.ts
+++ b/libs/ui-lib/lib/common/types/clusters.ts
@@ -76,6 +76,11 @@ export type OperatorsValues = V2ClusterUpdateParams & {
   useNvidiaGpu: boolean;
   useAmdGpu: boolean;
   useKmm: boolean;
+  useNodeHealthcheck: boolean;
+  useSelfNodeRemediation: boolean;
+  useFenceAgentsRemediation: boolean;
+  useNodeMaintenance: boolean;
+  useKubeDescheduler: boolean;
 };
 
 export type SupportedPlatformType = Extract<PlatformType, 'vsphere' | 'nutanix' | 'external'>;
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
new file mode 100644
index 0000000000..8d0dcfeee5
--- /dev/null
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Fence Agents Remediation </span>
+      </Tooltip>
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel | undefined;
+}) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+
+  return (
+    <FormGroup isInline fieldId={fieldId}>
+      <OcmCheckboxField
+        name={FENCE_AGENTS_REMEDIATION_FIELD_NAME}
+        label={
+          <FenceAgentsRemediationLabel
+            disabledReason={disabledReason}
+            supportLevel={supportLevel}
+          />
+        }
+        helperText={<FenceAgentsRemediationHelperText />}
+        isDisabled={!!disabledReason}
+      />
+    </FormGroup>
+  );
+};
+
+export default FenceAgentsRemediationCheckbox;
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/KubeDeschedulerCheckbox.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/KubeDeschedulerCheckbox.tsx
new file mode 100644
index 0000000000..679ba2b8e8
--- /dev/null
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/KubeDeschedulerCheckbox.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const KUBE_DESCHEDULER_FIELD_NAME = 'useKubeDescheduler';
+const KUBE_DESCHEDULER_FEATURE_ID = 'KUBE_DESCHEDULER';
+
+const KubeDeschedulerLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Kube Descheduler </span>
+      </Tooltip>
+      <NewFeatureSupportLevelBadge
+        featureId={KUBE_DESCHEDULER_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const KubeDeschedulerHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Evicts pods to reschedule them onto more suitable nodes.{' '}
+        <a href={NODE_HEALTHCHECK_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const KubeDeschedulerCheckbox = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel | undefined;
+}) => {
+  const fieldId = getFieldId(KUBE_DESCHEDULER_FIELD_NAME, 'input');
+
+  return (
+    <FormGroup isInline fieldId={fieldId}>
+      <OcmCheckboxField
+        name={KUBE_DESCHEDULER_FIELD_NAME}
+        label={<KubeDeschedulerLabel disabledReason={disabledReason} supportLevel={supportLevel} />}
+        helperText={<KubeDeschedulerHelperText />}
+        isDisabled={!!disabledReason}
+      />
+    </FormGroup>
+  );
+};
+
+export default KubeDeschedulerCheckbox;
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeHealthcheckCheckbox.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeHealthcheckCheckbox.tsx
new file mode 100644
index 0000000000..80ee53667f
--- /dev/null
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeHealthcheckCheckbox.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const NODE_HEALTHCHECK_FIELD_NAME = 'useNodeHealthcheck';
+const NODE_HEALTHCHECK_FEATURE_ID = 'NODE_HEALTHCHECK';
+
+const NodeHealthcheckLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Node Healthcheck </span>
+      </Tooltip>
+      <NewFeatureSupportLevelBadge
+        featureId={NODE_HEALTHCHECK_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const NodeHealthcheckHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Identify Unhealthy Nodes.{' '}
+        <a href={NODE_HEALTHCHECK_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const NodeHealthcheckCheckbox = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel | undefined;
+}) => {
+  const fieldId = getFieldId(NODE_HEALTHCHECK_FIELD_NAME, 'input');
+
+  return (
+    <FormGroup isInline fieldId={fieldId}>
+      <OcmCheckboxField
+        name={NODE_HEALTHCHECK_FIELD_NAME}
+        label={<NodeHealthcheckLabel disabledReason={disabledReason} supportLevel={supportLevel} />}
+        helperText={<NodeHealthcheckHelperText />}
+        isDisabled={!!disabledReason}
+      />
+    </FormGroup>
+  );
+};
+
+export default NodeHealthcheckCheckbox;
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeMaintenanceOperatorCheckbox.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeMaintenanceOperatorCheckbox.tsx
new file mode 100644
index 0000000000..9dac6bb6ca
--- /dev/null
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeMaintenanceOperatorCheckbox.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const NODE_MAINTENANCE_FIELD_NAME = 'useNodeMaintenance';
+const NODE_MAINTENANCE_FEATURE_ID = 'NODE_MAINTENANCE';
+
+const NodeMaintenanceLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Node Maintenance </span>
+      </Tooltip>
+      <NewFeatureSupportLevelBadge
+        featureId={NODE_MAINTENANCE_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const NodeMaintenanceHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Place nodes in maintenance mode.{' '}
+        <a href={NODE_HEALTHCHECK_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const NodeMaintenanceCheckbox = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel | undefined;
+}) => {
+  const fieldId = getFieldId(NODE_MAINTENANCE_FIELD_NAME, 'input');
+
+  return (
+    <FormGroup isInline fieldId={fieldId}>
+      <OcmCheckboxField
+        name={NODE_MAINTENANCE_FIELD_NAME}
+        label={<NodeMaintenanceLabel disabledReason={disabledReason} supportLevel={supportLevel} />}
+        helperText={<NodeMaintenanceHelperText />}
+        isDisabled={!!disabledReason}
+      />
+    </FormGroup>
+  );
+};
+
+export default NodeMaintenanceCheckbox;
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SelfNodeRemediationCheckbox.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SelfNodeRemediationCheckbox.tsx
new file mode 100644
index 0000000000..070accf280
--- /dev/null
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SelfNodeRemediationCheckbox.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, SELF_NODE_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const SELF_NODE_REMEDIATION_FIELD_NAME = 'useSelfNodeRemediation';
+const SELF_NODE_REMEDIATION_FEATURE_ID = 'SELF_NODE_REMEDIATION';
+
+const SelfNodeRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Self Node Remediation </span>
+      </Tooltip>
+      <NewFeatureSupportLevelBadge
+        featureId={SELF_NODE_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const SelfNodeRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Allows nodes to reboot themselves when they become unhealthy.{' '}
+        <a href={SELF_NODE_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const SelfNodeRemediationCheckbox = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel | undefined;
+}) => {
+  const fieldId = getFieldId(SELF_NODE_REMEDIATION_FIELD_NAME, 'input');
+
+  return (
+    <FormGroup isInline fieldId={fieldId}>
+      <OcmCheckboxField
+        name={SELF_NODE_REMEDIATION_FIELD_NAME}
+        label={
+          <SelfNodeRemediationLabel disabledReason={disabledReason} supportLevel={supportLevel} />
+        }
+        helperText={<SelfNodeRemediationHelperText />}
+        isDisabled={!!disabledReason}
+      />
+    </FormGroup>
+  );
+};
+
+export default SelfNodeRemediationCheckbox;
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SupportedOperators.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SupportedOperators.tsx
index a41606f0a6..8e6c3c4178 100644
--- a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SupportedOperators.tsx
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SupportedOperators.tsx
@@ -16,6 +16,11 @@ import ServiceMeshCheckbox from './ServicemeshCheckbox';
 import NvidiaGpuCheckbox from './NvidiaGpuCheckbox';
 import AmdGpuCheckbox from './AmdGpuCheckbox';
 import KmmCheckbox from './KmmCheckbox';
+import NodeHealthcheckCheckbox from './NodeHealthcheckCheckbox';
+import SelfNodeRemediationCheckbox from './SelfNodeRemediationCheckbox';
+import FenceAgentsRemediationCheckbox from './FenceAgentsRemediationCheckbox';
+import NodeMaintenanceCheckbox from './NodeMaintenanceOperatorCheckbox';
+import KubeDeschedulerCheckbox from './KubeDeschedulerCheckbox';
 import {
   FeatureId,
   OPERATOR_NAME_AMD_GPU,
@@ -35,6 +40,11 @@ import {
   OPERATOR_NAME_PIPELINES,
   OPERATOR_NAME_SERVERLESS,
   OPERATOR_NAME_SERVICEMESH,
+  OPERATOR_NAME_NODE_HEALTHCHECK,
+  OPERATOR_NAME_SELF_NODE_REMEDIATION,
+  OPERATOR_NAME_FENCE_AGENTS_REMEDIATION,
+  OPERATOR_NAME_NODE_MAINTENANCE,
+  OPERATOR_NAME_KUBE_DESCHEDULER,
 } from '../../../../common';
 import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
 
@@ -72,6 +82,11 @@ export const operatorComponentMap: Record<string, (props: OperatorProps) => JSX.
   'nvidia-gpu': (props) => <NvidiaGpuCheckbox {...props} />,
   'amd-gpu': (props) => <AmdGpuCheckbox {...props} />,
   kmm: (props) => <KmmCheckbox {...props} />,
+  'node-healthcheck': (props) => <NodeHealthcheckCheckbox {...props} />,
+  'self-node-remediation': (props) => <SelfNodeRemediationCheckbox {...props} />,
+  'fence-agents-remediation': (props) => <FenceAgentsRemediationCheckbox {...props} />,
+  'node-maintenance': (props) => <NodeMaintenanceCheckbox {...props} />,
+  'kube-descheduler': (props) => <KubeDeschedulerCheckbox {...props} />,
 };
 
 export const mapOperatorsToFieldIds: { [key: string]: string } = {
@@ -92,6 +107,11 @@ export const mapOperatorsToFieldIds: { [key: string]: string } = {
   [OPERATOR_NAME_NVIDIA_GPU]: 'useNvidiaGpu',
   [OPERATOR_NAME_AMD_GPU]: 'useAmdGpu',
   [OPERATOR_NAME_KMM]: 'useKmm',
+  [OPERATOR_NAME_NODE_HEALTHCHECK]: 'useNodeHealthcheck',
+  [OPERATOR_NAME_SELF_NODE_REMEDIATION]: 'useSelfNodeRemediation',
+  [OPERATOR_NAME_FENCE_AGENTS_REMEDIATION]: 'useFenceAgentsRemediation',
+  [OPERATOR_NAME_NODE_MAINTENANCE]: 'useNodeMaintenance',
+  [OPERATOR_NAME_KUBE_DESCHEDULER]: 'useKubeDescheduler',
 };
 
 export const mapOperatorIdToFeatureId: { [key: string]: FeatureId } = {
@@ -112,4 +132,9 @@ export const mapOperatorIdToFeatureId: { [key: string]: FeatureId } = {
   [OPERATOR_NAME_NVIDIA_GPU]: 'NVIDIA_GPU',
   [OPERATOR_NAME_AMD_GPU]: 'AMD_GPU',
   [OPERATOR_NAME_KMM]: 'KMM',
+  [OPERATOR_NAME_NODE_HEALTHCHECK]: 'NODE_HEALTHCHECK',
+  [OPERATOR_NAME_SELF_NODE_REMEDIATION]: 'SELF_NODE_REMEDIATION',
+  [OPERATOR_NAME_FENCE_AGENTS_REMEDIATION]: 'FENCE_AGENTS_REMEDIATION',
+  [OPERATOR_NAME_NODE_MAINTENANCE]: 'NODE_MAINTENANCE',
+  [OPERATOR_NAME_KUBE_DESCHEDULER]: 'KUBE_DESCHEDULER',
 };
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/VirtualizationRequirements.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/VirtualizationRequirements.tsx
index 301a01d262..41144324ec 100644
--- a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/VirtualizationRequirements.tsx
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/VirtualizationRequirements.tsx
@@ -22,6 +22,11 @@ const VirtualizationRequirements = () => {
         <ListItem>Migration Toolkit for Virtualization</ListItem>
         <ListItem>Nmstate</ListItem>
         <ListItem>Storage operator (either LSO/LVMS)</ListItem>
+        <ListItem>Node Healthcheck</ListItem>
+        <ListItem>Self Node Remediation</ListItem>
+        <ListItem>Fence Agents Remediation</ListItem>
+        <ListItem>Node Maintenance</ListItem>
+        <ListItem>Kube Descheduler</ListItem>
       </List>
     </>
   );
diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/Operators.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/Operators.tsx
index 23103b27ab..7c579a4c65 100644
--- a/libs/ui-lib/lib/ocm/components/clusterWizard/Operators.tsx
+++ b/libs/ui-lib/lib/ocm/components/clusterWizard/Operators.tsx
@@ -22,6 +22,11 @@ import {
   OPERATOR_NAME_PIPELINES,
   OPERATOR_NAME_SERVERLESS,
   OPERATOR_NAME_SERVICEMESH,
+  OPERATOR_NAME_NODE_HEALTHCHECK,
+  OPERATOR_NAME_SELF_NODE_REMEDIATION,
+  OPERATOR_NAME_FENCE_AGENTS_REMEDIATION,
+  OPERATOR_NAME_NODE_MAINTENANCE,
+  OPERATOR_NAME_KUBE_DESCHEDULER,
   OperatorsValues,
   selectMonitoredOperators,
   useAlerts,
@@ -60,6 +65,11 @@ export const getOperatorsInitialValues = (
     useNvidiaGpu: isOperatorEnabled([OPERATOR_NAME_NVIDIA_GPU]),
     useAmdGpu: isOperatorEnabled([OPERATOR_NAME_AMD_GPU]),
     useKmm: isOperatorEnabled([OPERATOR_NAME_KMM]),
+    useNodeHealthcheck: isOperatorEnabled([OPERATOR_NAME_NODE_HEALTHCHECK]),
+    useSelfNodeRemediation: isOperatorEnabled([OPERATOR_NAME_SELF_NODE_REMEDIATION]),
+    useFenceAgentsRemediation: isOperatorEnabled([OPERATOR_NAME_FENCE_AGENTS_REMEDIATION]),
+    useNodeMaintenance: isOperatorEnabled([OPERATOR_NAME_NODE_MAINTENANCE]),
+    useKubeDescheduler: isOperatorEnabled([OPERATOR_NAME_KUBE_DESCHEDULER]),
   };
 };
 
diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx
index 15fa42a7ad..c8fedb5585 100644
--- a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx
+++ b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx
@@ -60,6 +60,11 @@ const operatorsThatCanNotBeInstalledAlone = [
   'lso',
   'amd-gpu',
   'nvidia-gpu',
+  'node-healthcheck',
+  'self-node-remediation',
+  'fence-agents-remediation',
+  'node-maintenance',
+  'kube-descheduler',
 ];
 
 export const OperatorsStep = (props: ClusterOperatorProps) => {
@@ -426,7 +431,7 @@ export const OperatorsStep = (props: ClusterOperatorProps) => {
         <Stack hasGutter data-testid={'operators-form'}>
           {supportedOperators.map((operatorKey) => {
             const isOperatorSelected = bundleOperators.includes(operatorKey);
-            const isOperatorPartOfAIBundle =
+            const isOperatorNotAllowedAlone =
               operatorsThatCanNotBeInstalledAlone.includes(operatorKey);
             const disabledReason = getDisabledReasonForOperator(operatorKey, values);
             const featureSupportLevel = featureSupportLevelData.getFeatureSupportLevel(
@@ -446,7 +451,7 @@ export const OperatorsStep = (props: ClusterOperatorProps) => {
                   disabledReason={
                     isOperatorSelected
                       ? 'This operator is part of a bundle and cannot be deselected.'
-                      : isOperatorPartOfAIBundle
+                      : isOperatorNotAllowedAlone
                       ? 'This operator cannot be installed as a standalone'
                       : disabledReason
                   }
diff --git a/libs/ui-lib/lib/ocm/services/OperatorsService.tsx b/libs/ui-lib/lib/ocm/services/OperatorsService.tsx
index 8055e51c46..d65c013b34 100644
--- a/libs/ui-lib/lib/ocm/services/OperatorsService.tsx
+++ b/libs/ui-lib/lib/ocm/services/OperatorsService.tsx
@@ -18,6 +18,11 @@ import {
   OPERATOR_NAME_NVIDIA_GPU,
   OPERATOR_NAME_AMD_GPU,
   OPERATOR_NAME_KMM,
+  OPERATOR_NAME_NODE_HEALTHCHECK,
+  OPERATOR_NAME_SELF_NODE_REMEDIATION,
+  OPERATOR_NAME_FENCE_AGENTS_REMEDIATION,
+  OPERATOR_NAME_NODE_MAINTENANCE,
+  OPERATOR_NAME_KUBE_DESCHEDULER,
 } from '../../common';
 import { getOlmOperatorCreateParamsByName } from '../components/clusters/utils';
 import {
@@ -56,6 +61,11 @@ const OperatorsService = {
     setOperator(OPERATOR_NAME_NVIDIA_GPU, values.useNvidiaGpu);
     setOperator(OPERATOR_NAME_AMD_GPU, values.useAmdGpu);
     setOperator(OPERATOR_NAME_KMM, values.useKmm);
+    setOperator(OPERATOR_NAME_NODE_HEALTHCHECK, values.useNodeHealthcheck);
+    setOperator(OPERATOR_NAME_SELF_NODE_REMEDIATION, values.useNodeMaintenance);
+    setOperator(OPERATOR_NAME_FENCE_AGENTS_REMEDIATION, values.useFenceAgentsRemediation);
+    setOperator(OPERATOR_NAME_NODE_MAINTENANCE, values.useNodeMaintenance);
+    setOperator(OPERATOR_NAME_KUBE_DESCHEDULER, values.useKubeDescheduler);
 
     return Object.values(enabledOlmOperatorsByName);
   },


Reviews:
user: login: rawagner
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-01T06:42:26Z
user: login: danmanor
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T07:38:40Z
user: login: rawagner
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T07:45:45Z
user: login: ammont82
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-01T08:15:39Z
user: login: rawagner
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T11:31:47Z
user: login: danmanor
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T12:20:30Z
user: login: danmanor
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T12:21:06Z
user: login: rawagner
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T12:51:58Z
user: login: ammont82
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-01T13:34:52Z
user: login: rawagner
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-01T14:03:39Z

Review comments:
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
+      </Tooltip>
+      <PopoverIcon
+        id={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        component={'a'}
+        bodyContent={'No additional requirements needed'}
+      />
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({ disabledReason }: { disabledReason?: string }) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+  const featureSupportLevel = useNewFeatureSupportLevel();
+  const [disabledReasonFenceAgentsRemediation, setDisabledReason] = useState<string | undefined>();
+
+  React.useEffect(() => {
+    const reason = featureSupportLevel.getFeatureDisabledReason(
+      FENCE_AGENTS_REMEDIATION_FEATURE_ID,
+    );
+    setDisabledReason(reason);
+  }, [featureSupportLevel]);
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: rawagner
body: why are you using `useState` + `useEffect` ? This can be done without it.

Applies for all others as well.
created_at: 2025-04-01T06:42:21Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
+      </Tooltip>
+      <PopoverIcon
+        id={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        component={'a'}
+        bodyContent={'No additional requirements needed'}
+      />
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({ disabledReason }: { disabledReason?: string }) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+  const featureSupportLevel = useNewFeatureSupportLevel();
+  const [disabledReasonFenceAgentsRemediation, setDisabledReason] = useState<string | undefined>();
+
+  React.useEffect(() => {
+    const reason = featureSupportLevel.getFeatureDisabledReason(
+      FENCE_AGENTS_REMEDIATION_FEATURE_ID,
+    );
+    setDisabledReason(reason);
+  }, [featureSupportLevel]);
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: danmanor
body: I was coping https://github.com/openshift-assisted/assisted-installer-ui/blob/edf64c4aac1ae424d478f95223b1520f69d5c1b6/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/KmmCheckbox.tsx#L46 LMK if you think I should change it.
created_at: 2025-04-01T07:38:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
+      </Tooltip>
+      <PopoverIcon
+        id={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        component={'a'}
+        bodyContent={'No additional requirements needed'}
+      />
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({ disabledReason }: { disabledReason?: string }) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+  const featureSupportLevel = useNewFeatureSupportLevel();
+  const [disabledReasonFenceAgentsRemediation, setDisabledReason] = useState<string | undefined>();
+
+  React.useEffect(() => {
+    const reason = featureSupportLevel.getFeatureDisabledReason(
+      FENCE_AGENTS_REMEDIATION_FEATURE_ID,
+    );
+    setDisabledReason(reason);
+  }, [featureSupportLevel]);
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: rawagner
body: Yes, please lets change it. No need to repeat a bad pattern.
created_at: 2025-04-01T07:45:45Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,78 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const KUBE_DESCHEDULER_FIELD_NAME = 'useKubeDescheduler';
+const KUBE_DESCHEDULER_FEATURE_ID = 'KUBE_DESCHEDULER';
+
+const KubeDeschedulerLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Kube Descheduler </span>
+      </Tooltip>
+      <PopoverIcon
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/KubeDeschedulerCheckbox.tsx
user: login: ammont82
body: Remove the <PopoverIcon ... when "No additionals requirements are needed". We are doing the same in this PR: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882.
It applies for the rest of operators.
created_at: 2025-04-01T08:10:27Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,78 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const NODE_HEALTHCHECK_FIELD_NAME = 'useNodeHealthcheck';
+const NODE_HEALTHCHECK_FEATURE_ID = 'NODE_HEALTHCHECK';
+
+const NodeHealthcheckLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Node Healthcheck </span>
+      </Tooltip>
+      <PopoverIcon
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeHealthcheckCheckbox.tsx
user: login: ammont82
body: Remove the <PopoverIcon ... when "No additionals requirements are needed". We are doing the same in this PR: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882.
It applies for the rest of operators.
created_at: 2025-04-01T08:10:47Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,78 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const NODE_MAINTENANCE_FIELD_NAME = 'useNodeMaintenance';
+const NODE_MAINTENANCE_FEATURE_ID = 'NODE_MAINTENANCE';
+
+const NodeMaintenanceLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Node Maintenance </span>
+      </Tooltip>
+      <PopoverIcon
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeMaintenanceOperatorCheckbox.tsx
user: login: ammont82
body: Remove the <PopoverIcon ... when "No additionals requirements are needed". We are doing the same in this PR: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882.
It applies for the rest of operators.
created_at: 2025-04-01T08:10:54Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,80 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, SELF_NODE_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const SELF_NODE_REMEDIATION_FIELD_NAME = 'useSelfNodeRemediation';
+const SELF_NODE_REMEDIATION_FEATURE_ID = 'SELF_NODE_REMEDIATION';
+
+const SelfNodeRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Self Node Remediation </span>
+      </Tooltip>
+      <PopoverIcon
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SelfNodeRemediationCheckbox.tsx
user: login: ammont82
body: Remove the <PopoverIcon ... when "No additionals requirements are needed". We are doing the same in this PR: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882.
It applies for the rest of operators.
created_at: 2025-04-01T08:11:01Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: ammont82
body: Remove "Install" word for all the operators. We are doing the same here: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882
created_at: 2025-04-01T08:12:29Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,78 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const KUBE_DESCHEDULER_FIELD_NAME = 'useKubeDescheduler';
+const KUBE_DESCHEDULER_FEATURE_ID = 'KUBE_DESCHEDULER';
+
+const KubeDeschedulerLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Kube Descheduler </span>
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/KubeDeschedulerCheckbox.tsx
user: login: ammont82
body: Remove "Install" word for all operators.  We are doing the same in this PR: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882
created_at: 2025-04-01T08:12:34Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,78 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const NODE_HEALTHCHECK_FIELD_NAME = 'useNodeHealthcheck';
+const NODE_HEALTHCHECK_FEATURE_ID = 'NODE_HEALTHCHECK';
+
+const NodeHealthcheckLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Node Healthcheck </span>
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeHealthcheckCheckbox.tsx
user: login: ammont82
body: Remove "Install" word for all the operators. We are doing the same here: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882
created_at: 2025-04-01T08:12:39Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,78 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, NODE_HEALTHCHECK_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const NODE_MAINTENANCE_FIELD_NAME = 'useNodeMaintenance';
+const NODE_MAINTENANCE_FEATURE_ID = 'NODE_MAINTENANCE';
+
+const NodeMaintenanceLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Node Maintenance </span>
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/NodeMaintenanceOperatorCheckbox.tsx
user: login: ammont82
body: Remove "Install" word for all the operators. We are doing the same here: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882
created_at: 2025-04-01T08:12:45Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,80 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, SELF_NODE_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const SELF_NODE_REMEDIATION_FIELD_NAME = 'useSelfNodeRemediation';
+const SELF_NODE_REMEDIATION_FEATURE_ID = 'SELF_NODE_REMEDIATION';
+
+const SelfNodeRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Self Node Remediation </span>
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/SelfNodeRemediationCheckbox.tsx
user: login: ammont82
body: Remove "Install" word for all the operators. We are doing the same here: https://github.com/openshift-assisted/assisted-installer-ui/pull/2882
created_at: 2025-04-01T08:12:50Z
author_association: MEMBER
diff_hunk: @@ -140,6 +140,11 @@ export const hostValidationLabels = (t: TFunction): { [key in HostValidationId]:
   'nmstate-requirements-satisfied': '',
   'amd-gpu-requirements-satisfied': t('ai:AMD GPU requirements'),
   'kmm-requirements-satisfied': t('ai:Kernel Module Management requirements'),
+  'node-healthcheck-requirements-satisfied': t('ai: Node Healthcheck requirements'),
path: libs/ui-lib/lib/common/config/constants.ts
user: login: ammont82
body: Remove the space between ai: and the rest of the sentence.
`t('ai:Node Healthcheck requirements')`

It applies for the rest of the new operators.

After this change you have to regenerate the locales files.
created_at: 2025-04-01T08:15:15Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
+      </Tooltip>
+      <PopoverIcon
+        id={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        component={'a'}
+        bodyContent={'No additional requirements needed'}
+      />
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({ disabledReason }: { disabledReason?: string }) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+  const featureSupportLevel = useNewFeatureSupportLevel();
+  const [disabledReasonFenceAgentsRemediation, setDisabledReason] = useState<string | undefined>();
+
+  React.useEffect(() => {
+    const reason = featureSupportLevel.getFeatureDisabledReason(
+      FENCE_AGENTS_REMEDIATION_FEATURE_ID,
+    );
+    setDisabledReason(reason);
+  }, [featureSupportLevel]);
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: rawagner
body: I dont think this is a correct fix ? You need to check `FENCE_AGENTS_REMEDIATION_FEATURE_ID`, but there is no need to do it via `useState` + `useEffect`. Just call the `featureSupportLevel.getFeatureDisabledReason` directly in render loop.
created_at: 2025-04-01T11:31:47Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
+      </Tooltip>
+      <PopoverIcon
+        id={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        component={'a'}
+        bodyContent={'No additional requirements needed'}
+      />
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({ disabledReason }: { disabledReason?: string }) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+  const featureSupportLevel = useNewFeatureSupportLevel();
+  const [disabledReasonFenceAgentsRemediation, setDisabledReason] = useState<string | undefined>();
+
+  React.useEffect(() => {
+    const reason = featureSupportLevel.getFeatureDisabledReason(
+      FENCE_AGENTS_REMEDIATION_FEATURE_ID,
+    );
+    setDisabledReason(reason);
+  }, [featureSupportLevel]);
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: danmanor
body: We are passing this value as a prop - https://github.com/openshift-assisted/assisted-installer-ui/blob/7335061627634f25c65438b22ef0c8d3f50d8a44/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx#L451, so I am not sure if we need to. We get it here - https://github.com/openshift-assisted/assisted-installer-ui/blob/7335061627634f25c65438b22ef0c8d3f50d8a44/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx#L240
created_at: 2025-04-01T12:20:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
+      </Tooltip>
+      <PopoverIcon
+        id={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        component={'a'}
+        bodyContent={'No additional requirements needed'}
+      />
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({ disabledReason }: { disabledReason?: string }) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+  const featureSupportLevel = useNewFeatureSupportLevel();
+  const [disabledReasonFenceAgentsRemediation, setDisabledReason] = useState<string | undefined>();
+
+  React.useEffect(() => {
+    const reason = featureSupportLevel.getFeatureDisabledReason(
+      FENCE_AGENTS_REMEDIATION_FEATURE_ID,
+    );
+    setDisabledReason(reason);
+  }, [featureSupportLevel]);
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: danmanor
body: WDYT ? @rawagner 
created_at: 2025-04-01T12:21:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,82 @@
+import React, { useState } from 'react';
+import { FormGroup, HelperText, HelperTextItem, Tooltip } from '@patternfly/react-core';
+import { getFieldId, PopoverIcon, FENCE_AGENTS_REMEDIATION_LINK } from '../../../../common';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { OcmCheckboxField } from '../../ui/OcmFormFields';
+import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels';
+import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge';
+import { SupportLevel } from '@openshift-assisted/types/./assisted-installer-service';
+
+const FENCE_AGENTS_REMEDIATION_FIELD_NAME = 'useFenceAgentsRemediation';
+const FENCE_AGENTS_REMEDIATION_FEATURE_ID = 'FENCE_AGENTS_REMEDIATION';
+
+const FenceAgentsRemediationLabel = ({
+  disabledReason,
+  supportLevel,
+}: {
+  disabledReason?: string;
+  supportLevel?: SupportLevel;
+}) => {
+  return (
+    <>
+      <Tooltip hidden={!disabledReason} content={disabledReason}>
+        <span>Install Fence Agents Remediation </span>
+      </Tooltip>
+      <PopoverIcon
+        id={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        component={'a'}
+        bodyContent={'No additional requirements needed'}
+      />
+      <NewFeatureSupportLevelBadge
+        featureId={FENCE_AGENTS_REMEDIATION_FEATURE_ID}
+        supportLevel={supportLevel}
+      />
+    </>
+  );
+};
+
+const FenceAgentsRemediationHelperText = () => {
+  return (
+    <HelperText>
+      <HelperTextItem variant="indeterminate">
+        Externally fences failed nodes using power controllers.{' '}
+        <a href={FENCE_AGENTS_REMEDIATION_LINK} target="_blank" rel="noopener noreferrer">
+          {'Learn more'} <ExternalLinkAltIcon />
+        </a>
+      </HelperTextItem>
+    </HelperText>
+  );
+};
+
+const FenceAgentsRemediationCheckbox = ({ disabledReason }: { disabledReason?: string }) => {
+  const fieldId = getFieldId(FENCE_AGENTS_REMEDIATION_FIELD_NAME, 'input');
+  const featureSupportLevel = useNewFeatureSupportLevel();
+  const [disabledReasonFenceAgentsRemediation, setDisabledReason] = useState<string | undefined>();
+
+  React.useEffect(() => {
+    const reason = featureSupportLevel.getFeatureDisabledReason(
+      FENCE_AGENTS_REMEDIATION_FEATURE_ID,
+    );
+    setDisabledReason(reason);
+  }, [featureSupportLevel]);
path: libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/FenceAgentsRemediationCheckbox.tsx
user: login: rawagner
body: Ok, I see. Great that you removed this duplication!
created_at: 2025-04-01T12:51:58Z
author_association: MEMBER

PR comments:
user: login: openshift-ci-robot
created_at: 2025-03-30T16:28:14Z
body: @danmanor: This pull request references [MGMT-20200](https://issues.redhat.com//browse/MGMT-20200) which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.19.0" version, but no target version was set.

<details>

In response to [this](https://github.com/openshift-assisted/assisted-installer-ui/pull/2884):

>This PR adds 5 new operators to the virtualization bundle:
>
>1. `Node Healthcheck`.
>2. `Self Node Remediation`.
>3. `Fence Agents Remdiation`.
>4. `Node Miantenance`.
>5. `Kube Descheduler`.
>
>All these operators are enabled only when the bundle is selected.


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift-assisted%2Fassisted-installer-ui).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: NONE
user: login: openshift-ci-robot
created_at: 2025-03-30T16:29:42Z
body: @danmanor: This pull request references [MGMT-20200](https://issues.redhat.com//browse/MGMT-20200) which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.19.0" version, but no target version was set.

<details>

In response to [this](https://github.com/openshift-assisted/assisted-installer-ui/pull/2884):

>This PR adds 5 new operators to the virtualization bundle:
>
>1. `Node Healthcheck`.
>2. `Self Node Remediation`.
>3. `Fence Agents Remdiation`.
>4. `Node Miantenance`.
>5. `Kube Descheduler`.
>
>All these operators are enabled only when the bundle is selected.
>
>![image](https://github.com/user-attachments/assets/8a08e739-d101-449a-a021-4c3a3f247984)
>
>![image](https://github.com/user-attachments/assets/3ea99f20-1122-433d-91f3-c9d5f3f2d79e)


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift-assisted%2Fassisted-installer-ui).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: NONE
user: login: openshift-ci-robot
created_at: 2025-03-30T16:31:45Z
body: @danmanor: This pull request references [MGMT-20200](https://issues.redhat.com//browse/MGMT-20200) which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.19.0" version, but no target version was set.

<details>

In response to [this](https://github.com/openshift-assisted/assisted-installer-ui/pull/2884):

>This PR adds 5 new operators to the virtualization bundle:
>
>1. `Node Healthcheck`.
>2. `Self Node Remediation`.
>3. `Fence Agents Remdiation`.
>4. `Node Miantenance`.
>5. `Kube Descheduler`.
>
>All these operators are enabled only when the bundle is selected.
>
>![image](https://github.com/user-attachments/assets/b6ded257-0d2b-4df0-8692-a7641d6fa8a1)
>
>![image](https://github.com/user-attachments/assets/aa5b192f-f7c8-49a1-ad6e-71e8cc94276d)


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift-assisted%2Fassisted-installer-ui).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: NONE
user: login: openshift-ci-robot
created_at: 2025-04-01T11:13:56Z
body: @danmanor: This pull request references [MGMT-20200](https://issues.redhat.com//browse/MGMT-20200) which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.19.0" version, but no target version was set.

<details>

In response to [this](https://github.com/openshift-assisted/assisted-installer-ui/pull/2884):

>This PR adds 5 new operators to the virtualization bundle:
>
>1. `Node Healthcheck`.
>2. `Self Node Remediation`.
>3. `Fence Agents Remdiation`.
>4. `Node Miantenance`.
>5. `Kube Descheduler`.
>
>All these operators are enabled only when the bundle is selected.
>
>![image](https://github.com/user-attachments/assets/661685e6-dfda-46e6-a71c-273e8b516310)
>
>![image](https://github.com/user-attachments/assets/39a902be-0e0a-4257-bb5b-e5b07e6830eb)


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift-assisted%2Fassisted-installer-ui).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: NONE
user: login: rawagner
created_at: 2025-04-01T12:52:15Z
body: /approve
/lgtm
author_association: MEMBER
user: login: danmanor
created_at: 2025-04-01T13:11:20Z
body: @rawagner is there anything blocking it for merge ? or is it waiting
author_association: CONTRIBUTOR
user: login: ammont82
created_at: 2025-04-01T13:34:41Z
body: /lgtm
author_association: MEMBER
user: login: openshift-ci[bot]
created_at: 2025-04-01T14:03:44Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/openshift-assisted/assisted-installer-ui/pull/2884#pullrequestreview-2732720723" title="Approved">ammont82</a>*, *<a href="https://github.com/openshift-assisted/assisted-installer-ui/pull/2884#" title="Author self-approved">danmanor</a>*, *<a href="https://github.com/openshift-assisted/assisted-installer-ui/pull/2884#pullrequestreview-2732816141" title="Approved">rawagner</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=openshift-assisted%2Fassisted-installer-ui).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/openshift-assisted/assisted-installer-ui/blob/master/OWNERS)~~ [ammont82,rawagner]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: NONE