diff --git a/locales/en/plugin__kubevirt-plugin.json b/locales/en/plugin__kubevirt-plugin.json
index 28e8e37f42..2a05004404 100644
--- a/locales/en/plugin__kubevirt-plugin.json
+++ b/locales/en/plugin__kubevirt-plugin.json
@@ -546,8 +546,10 @@
"IP addresses": "IP addresses",
"It may take several minutes until the clone is done and the VirtualMachine is ready.": "It may take several minutes until the clone is done and the VirtualMachine is ready.",
"It seems that your browser does not trust the certificate of the upload proxy. {uploadProxyURL && (\n <>\n Please{' '}\n \n approve this certificate\n {' '}\n and try again\n >\n )}": "It seems that your browser does not trust the certificate of the upload proxy. {uploadProxyURL && (\n <>\n Please{' '}\n \n approve this certificate\n {' '}\n and try again\n >\n )}",
+ "Kernel Samepage Merging (KSM)": "Kernel Samepage Merging (KSM)",
"key": "key",
"Key": "Key",
+ "KSM is a memory-saving de-duplication feature designed to fit more VirtualMachines into physical memory by sharing the data common between them.": "KSM is a memory-saving de-duplication feature designed to fit more VirtualMachines into physical memory by sharing the data common between them.",
"Kubernetes NMState Operator": "Kubernetes NMState Operator",
"KV data transfer rate": "KV data transfer rate",
"Label selectors let you select Nodes based on the value of one or more labels.": "Label selectors let you select Nodes based on the value of one or more labels.",
@@ -743,6 +745,7 @@
"Node labels": "Node labels",
"Node port": "Node port",
"Node selector": "Node selector",
+ "Node selector configuration": "Node selector configuration",
"Nodes": "Nodes",
"None": "None",
"Not available": "Not available",
@@ -873,6 +876,7 @@
"Reset": "Reset",
"Resource": "Resource",
"Resource already selected": "Resource already selected",
+ "Resource management": "Resource management",
"Resource name": "Resource name",
"Resources": "Resources",
"Resources are being removed, please wait.": "Resources are being removed, please wait.",
diff --git a/src/utils/components/NodeSelectorModal/NodeSelectorModal.tsx b/src/utils/components/NodeSelectorModal/NodeSelectorModal.tsx
index adccb4f394..e1fc8f76f6 100644
--- a/src/utils/components/NodeSelectorModal/NodeSelectorModal.tsx
+++ b/src/utils/components/NodeSelectorModal/NodeSelectorModal.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React, { FC, useMemo } from 'react';
import produce from 'immer';
import { NodeModel } from '@kubevirt-ui/kubevirt-api/console';
@@ -29,7 +29,7 @@ type NodeSelectorModalProps = {
vmi?: V1VirtualMachineInstance;
};
-const NodeSelectorModal: React.FC = ({
+const NodeSelectorModal: FC = ({
isOpen,
nodes,
nodesLoaded,
@@ -50,7 +50,7 @@ const NodeSelectorModal: React.FC = ({
const onSelectorLabelAdd = () => onLabelAdd({ id: null, key: '', value: '' });
- const updatedVirtualMachine = React.useMemo(() => {
+ const updatedVirtualMachine = useMemo(() => {
const updatedVM = produce(vm, (vmDraft: V1VirtualMachine) => {
ensurePath(vmDraft, ['spec.template.template.spec.nodeSelector']);
if (!vmDraft.spec.template.spec.nodeSelector) {
diff --git a/src/views/clusteroverview/SettingsTab/ClusterTab/ClusterTab.tsx b/src/views/clusteroverview/SettingsTab/ClusterTab/ClusterTab.tsx
index 18b7299711..60300a7827 100644
--- a/src/views/clusteroverview/SettingsTab/ClusterTab/ClusterTab.tsx
+++ b/src/views/clusteroverview/SettingsTab/ClusterTab/ClusterTab.tsx
@@ -7,6 +7,7 @@ import EnableLoadBalancerSection from './components/EnableLoadBalancerSection/En
import EnablePreviewFeaturesSection from './components/EnablePreviewFeaturesSection/EnablePreviewFeaturesSection';
import GeneralInformation from './components/GeneralInformation/GeneralInformation';
import LiveMigrationSection from './components/LiveMigrationSection/LiveMigrationSection';
+import ResourceManagementSection from './components/ResourceManagementSection/ResourceManagementSection';
import TemplatesProjectSection from './components/TemplatesProjectSection/TemplatesProjectSection';
const ClusterTab: FC = () => {
@@ -22,6 +23,8 @@ const ClusterTab: FC = () => {
+
+
>
);
};
diff --git a/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/ResourceManagementSection.tsx b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/ResourceManagementSection.tsx
new file mode 100644
index 0000000000..e1a2031f2e
--- /dev/null
+++ b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/ResourceManagementSection.tsx
@@ -0,0 +1,19 @@
+import React, { FC } from 'react';
+
+import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
+
+import ExpandSection from '../../../ExpandSection/ExpandSection';
+
+import KernelSamepageMerging from './components/KernelSamepageMerging/KernelSamepageMerging';
+
+const ResourceManagementSection: FC = () => {
+ const { t } = useKubevirtTranslation();
+
+ return (
+
+
+
+ );
+};
+
+export default ResourceManagementSection;
diff --git a/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/KernelSamepageMerging.scss b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/KernelSamepageMerging.scss
new file mode 100644
index 0000000000..fcc445a516
--- /dev/null
+++ b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/KernelSamepageMerging.scss
@@ -0,0 +1,28 @@
+.KernelSamepageMerging {
+ &__ExpandSection {
+ padding-left: var(--pf-global--spacer--lg);
+
+ .pf-c-expandable-section__content {
+ padding-left: var(--pf-global--spacer--lg);
+ }
+
+ .pf-c-expandable-section__toggle {
+ padding-right: var(--pf-global--spacer--sm);
+ }
+ }
+
+ &__HelpIcon,
+ .pf-c-switch {
+ vertical-align: -moz-middle-with-baseline !important;
+ }
+
+ &__HelpIcon {
+ color: var(--pf-global--Color--100);
+ }
+
+ &__HelpTextIcon {
+ .pf-c-popover__content {
+ width: 400px;
+ }
+ }
+}
diff --git a/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/KernelSamepageMerging.tsx b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/KernelSamepageMerging.tsx
new file mode 100644
index 0000000000..cb93fccacf
--- /dev/null
+++ b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/KernelSamepageMerging.tsx
@@ -0,0 +1,44 @@
+import React, { FC, useState } from 'react';
+import ExpandSection from 'src/views/clusteroverview/SettingsTab/ExpandSection/ExpandSection';
+
+import HelpTextIcon from '@kubevirt-utils/components/HelpTextIcon/HelpTextIcon';
+import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
+import { PopoverPosition, Split, SplitItem, Switch } from '@patternfly/react-core';
+
+import NodeSelectorConfiguration from './components/NodeSelectorConfiguration/NodeSelectorConfiguration';
+
+import './KernelSamepageMerging.scss';
+
+const KernelSamepageMerging: FC = () => {
+ const { t } = useKubevirtTranslation();
+ const [isEnabled, setIsEnabled] = useState(false);
+ // TODO enable KSM if isEnabled
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default KernelSamepageMerging;
diff --git a/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/components/NodeSelectorConfiguration/NodeSelectorConfiguration.tsx b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/components/NodeSelectorConfiguration/NodeSelectorConfiguration.tsx
new file mode 100644
index 0000000000..3dca4e6eba
--- /dev/null
+++ b/src/views/clusteroverview/SettingsTab/ClusterTab/components/ResourceManagementSection/components/KernelSamepageMerging/components/NodeSelectorConfiguration/NodeSelectorConfiguration.tsx
@@ -0,0 +1,48 @@
+import React, { FC } from 'react';
+
+import { useWizardVMContext } from '@catalog/utils/WizardVMContext';
+import { modelToGroupVersionKind, NodeModel } from '@kubevirt-ui/kubevirt-api/console';
+import { IoK8sApiCoreV1Node } from '@kubevirt-ui/kubevirt-api/kubernetes';
+import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider';
+import NodeSelectorModal from '@kubevirt-utils/components/NodeSelectorModal/NodeSelectorModal';
+import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation';
+import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
+import { Button, ButtonVariant } from '@patternfly/react-core';
+import { PencilAltIcon } from '@patternfly/react-icons';
+
+const NodeSelectorConfiguration: FC = () => {
+ const { createModal } = useModal();
+ const { t } = useKubevirtTranslation();
+ const { updateVM } = useWizardVMContext();
+
+ const [nodes, nodesLoaded] = useK8sWatchResource({
+ groupVersionKind: modelToGroupVersionKind(NodeModel),
+ isList: true,
+ });
+
+ const onNodeConfigure = () =>
+ createModal(({ isOpen, onClose }) => (
+
+ ));
+
+ return (
+
+ );
+};
+
+export default NodeSelectorConfiguration;
diff --git a/src/views/templates/details/tabs/scheduling/components/NodeSelector.tsx b/src/views/templates/details/tabs/scheduling/components/NodeSelector.tsx
index 2a5639ffc7..8abe8e8fe7 100644
--- a/src/views/templates/details/tabs/scheduling/components/NodeSelector.tsx
+++ b/src/views/templates/details/tabs/scheduling/components/NodeSelector.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { FC } from 'react';
import { TemplateSchedulingGridProps } from 'src/views/templates/details/tabs/scheduling/components/TemplateSchedulingLeftGrid';
import { getNodeSelector } from 'src/views/templates/utils/selectors';
@@ -7,6 +7,7 @@ import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTransla
import { isEmpty } from '@kubevirt-utils/utils/utils';
import {
Button,
+ ButtonVariant,
DescriptionListDescription,
DescriptionListGroup,
DescriptionListTerm,
@@ -17,7 +18,7 @@ import { PencilAltIcon } from '@patternfly/react-icons';
import NodeSelectorModal from './NodeSelectorModal';
-const NodeSelector: React.FC = ({ editable, onSubmit, template }) => {
+const NodeSelector: FC = ({ editable, onSubmit, template }) => {
const { t } = useKubevirtTranslation();
const { createModal } = useModal();
const nodeSelector = getNodeSelector(template);
@@ -51,7 +52,7 @@ const NodeSelector: React.FC = ({ editable, onSubmi
isInline
onClick={onEditClick}
type="button"
- variant="link"
+ variant={ButtonVariant.link}
>
{nodeSelectorLabels}