diff --git a/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts b/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts index f8afe64042..5284a55042 100644 --- a/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts +++ b/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts @@ -4,7 +4,7 @@ import { } from '@openshift-assisted/types/assisted-installer-service'; import { NetworkConfigurationValues } from '../../../common/types/clusters'; import { isDualStack } from '../../../common/components/clusterConfiguration/utils'; -import { DUAL_STACK, IPV4_STACK, NETWORK_TYPE_OVN } from '../../../common/config'; +import { DUAL_STACK, IPV4_STACK, NETWORK_TYPE_OVN } from '../../../common'; export const getNetworkInitialValues = ( cluster: Cluster, diff --git a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/NetworkTypeControlGroup.tsx b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/NetworkTypeControlGroup.tsx index 3b77a5e1c7..be353efd94 100644 --- a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/NetworkTypeControlGroup.tsx +++ b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/NetworkTypeControlGroup.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Split, SplitItem, Tooltip, FormGroup } from '@patternfly/react-core'; import { RadioField } from '../../ui/formik'; import { PopoverIcon } from '../../../components/ui'; -import { NETWORK_TYPE_OVN, NETWORK_TYPE_SDN } from '../../../config'; +import { NETWORK_TYPE_OVN, NETWORK_TYPE_SDN } from '../../../types/networkType'; import { useTranslation } from '../../../hooks/use-translation-wrapper'; const GROUP_NAME = 'networkType'; diff --git a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.tsx b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.tsx index 4ed14614bb..46de970841 100644 --- a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.tsx +++ b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.tsx @@ -3,15 +3,14 @@ import { ButtonVariant, FormGroup, Split, SplitItem, Tooltip } from '@patternfly import { useFormikContext } from 'formik'; import { Address4, Address6 } from 'ip-address'; -import { HostSubnets, NetworkConfigurationValues } from '../../../types'; -import { getFieldId } from '../../ui'; import { - DUAL_STACK, - IPV4_STACK, + HostSubnets, + NetworkConfigurationValues, NETWORK_TYPE_OVN, NETWORK_TYPE_SDN, - NO_SUBNET_SET, -} from '../../../config'; +} from '../../../types'; +import { getFieldId } from '../../ui'; +import { DUAL_STACK, IPV4_STACK, NO_SUBNET_SET } from '../../../config'; import { RadioField } from '../../ui/formik'; import { ConfirmationModal, PopoverIcon } from '../../ui'; import { reorderNetworksByCurrentPrimary } from './reorderNetworks'; diff --git a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/VirtualIPControlGroup.tsx b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/VirtualIPControlGroup.tsx index 990d4654c1..fb0db46afa 100644 --- a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/VirtualIPControlGroup.tsx +++ b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/VirtualIPControlGroup.tsx @@ -9,8 +9,8 @@ import { Stack, StackItem, } from '@patternfly/react-core'; -import { NetworkConfigurationValues, HostSubnets } from '../../../types'; -import { NETWORK_TYPE_SDN, DUAL_STACK } from '../../../config'; +import { NetworkConfigurationValues, HostSubnets, NETWORK_TYPE_SDN } from '../../../types'; +import { DUAL_STACK } from '../../../config'; import { selectMachineNetworkCIDR, selectApiVip, selectIngressVip } from '../../../selectors'; import { getVipValidationsById } from '../../clusterConfiguration'; import { FormikStaticField, PopoverIcon } from '../../ui'; diff --git a/libs/ui-lib/lib/common/config/constants.ts b/libs/ui-lib/lib/common/config/constants.ts index 708c6b487a..c0dda7ea50 100644 --- a/libs/ui-lib/lib/common/config/constants.ts +++ b/libs/ui-lib/lib/common/config/constants.ts @@ -333,22 +333,6 @@ export const MS_PER_DAY = 1000 * 60 * 60 * 24; export const NO_SUBNET_SET = 'NO_SUBNET_SET'; -export const NETWORK_TYPE_OVN = 'OVNKubernetes'; -export const NETWORK_TYPE_SDN = 'OpenShiftSDN'; -export const NETWORK_TYPE_CISCO_ACI = 'CiscoACI'; -export const NETWORK_TYPE_CILIUM = 'Cilium'; -export const NETWORK_TYPE_CALICO = 'Calico'; -export const NETWORK_TYPE_NONE = 'None'; - -export const NETWORK_TYPE_LABELS: Record = { - [NETWORK_TYPE_OVN]: 'Open Virtual Networking (OVN)', - [NETWORK_TYPE_SDN]: 'Software-Defined Networking (SDN)', - [NETWORK_TYPE_CISCO_ACI]: 'Cisco ACI', - [NETWORK_TYPE_CILIUM]: 'Isovalent Cilium', - [NETWORK_TYPE_CALICO]: 'Tigera Calico', - [NETWORK_TYPE_NONE]: 'None (Custom CNI)', -}; - export const IPV4_STACK = 'singleStack'; export const DUAL_STACK = 'dualStack'; diff --git a/libs/ui-lib/lib/common/types/index.ts b/libs/ui-lib/lib/common/types/index.ts index 31306d36a6..9429035700 100644 --- a/libs/ui-lib/lib/common/types/index.ts +++ b/libs/ui-lib/lib/common/types/index.ts @@ -7,6 +7,7 @@ export * from './events'; export * from './clusters'; export * from './cpuArchitecture'; export * from './featureSupportLevel'; +export * from './networkType'; export * from './typescriptExtensions'; export * from './generateIsoFields'; export * from './errortype'; diff --git a/libs/ui-lib/lib/common/types/networkType.ts b/libs/ui-lib/lib/common/types/networkType.ts new file mode 100644 index 0000000000..a18dfdae8a --- /dev/null +++ b/libs/ui-lib/lib/common/types/networkType.ts @@ -0,0 +1,37 @@ +import type { FeatureSupportLevelId } from '@openshift-assisted/types/assisted-installer-service'; + +export type NetworkTypeKey = + | 'OVNKubernetes' + | 'OpenShiftSDN' + | 'CiscoACI' + | 'Cilium' + | 'Calico' + | 'None'; + +export const NETWORK_TYPE_OVN: NetworkTypeKey = 'OVNKubernetes'; +export const NETWORK_TYPE_SDN: NetworkTypeKey = 'OpenShiftSDN'; +export const NETWORK_TYPE_CISCO_ACI: NetworkTypeKey = 'CiscoACI'; +export const NETWORK_TYPE_CILIUM: NetworkTypeKey = 'Cilium'; +export const NETWORK_TYPE_CALICO: NetworkTypeKey = 'Calico'; +export const NETWORK_TYPE_NONE: NetworkTypeKey = 'None'; + +export const NETWORK_TYPE_LABELS: Record = { + [NETWORK_TYPE_OVN]: 'Open Virtual Networking (OVN)', + [NETWORK_TYPE_SDN]: 'Software-Defined Networking (SDN)', + [NETWORK_TYPE_CISCO_ACI]: 'Cisco ACI', + [NETWORK_TYPE_CILIUM]: 'Isovalent Cilium', + [NETWORK_TYPE_CALICO]: 'Tigera Calico', + [NETWORK_TYPE_NONE]: 'None (Custom CNI)', +}; + +export const NETWORK_TYPE_FEATURE_IDS: Record = { + [NETWORK_TYPE_OVN]: 'OVN_NETWORK_TYPE', + [NETWORK_TYPE_SDN]: 'SDN_NETWORK_TYPE', + [NETWORK_TYPE_CISCO_ACI]: 'CISCO_ACI_NETWORK_TYPE', + [NETWORK_TYPE_CILIUM]: 'CILIUM_NETWORK_TYPE', + [NETWORK_TYPE_CALICO]: 'CALICO_NETWORK_TYPE', + [NETWORK_TYPE_NONE]: 'NONE_NETWORK_TYPE', +}; + +export const isThirdPartyCNI = (networkType: string | undefined): boolean => + !!networkType && networkType !== NETWORK_TYPE_OVN && networkType !== NETWORK_TYPE_SDN; diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.tsx index d46db85d56..ee2314410f 100644 --- a/libs/ui-lib/lib/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/manifestsConfiguration/CustomManifestsPage.tsx @@ -15,9 +15,9 @@ import { import { CustomManifests } from './components/CustomManifests'; import { Cluster } from '@openshift-assisted/types/assisted-installer-service'; import { CustomManifestFormState } from './components/propTypes'; -import { ClustersAPI, ClusterWizardStepHeader } from '../../../../common'; +import { ClustersAPI, ClusterWizardStepHeader, isThirdPartyCNI } from '../../../../common'; import { getFieldId } from '../../../../common/components/ui/formik'; -import { isOciPlatformType, isThirdPartyCNI } from '../../utils'; +import { isOciPlatformType } from '../../utils'; import DeleteCustomManifestModal from './DeleteCustomManifestModal'; import { ClustersService } from '../../../services'; import { useClusterWizardContext } from '../../clusterWizard/ClusterWizardContext'; diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx index b31c909bfc..63e6cfb80b 100644 --- a/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx @@ -4,7 +4,6 @@ import { useSelector } from 'react-redux'; import { Stack, StackItem, Tooltip } from '@patternfly/react-core'; import { canBeDualStack, - canSelectNetworkTypeSDN, CpuArchitecture, DUAL_STACK, HostSubnets, @@ -144,9 +143,6 @@ const NetworkConfiguration = ({ const isDualStack = values.stackType === DUAL_STACK; const isDualStackSelectable = React.useMemo(() => canBeDualStack(hostSubnets), [hostSubnets]); - const isSDNSelectable = React.useMemo(() => { - return canSelectNetworkTypeSDN(isSNOCluster, isDualStack); - }, [isSNOCluster, isDualStack]); const [isAdvanced, setAdvanced] = React.useState( isDualStack || isAdvNetworkConf(cluster, defaultNetworkSettings), @@ -262,7 +258,6 @@ const NetworkConfiguration = ({ diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkTypeDropdown.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkTypeDropdown.tsx index c25601a3aa..6f2cae8e62 100644 --- a/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkTypeDropdown.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkTypeDropdown.tsx @@ -12,82 +12,71 @@ import { StackItem, Tooltip, } from '@patternfly/react-core'; -import { - NETWORK_TYPE_CALICO, - NETWORK_TYPE_CILIUM, - NETWORK_TYPE_CISCO_ACI, - NETWORK_TYPE_LABELS, - NETWORK_TYPE_NONE, - NETWORK_TYPE_OVN, - NETWORK_TYPE_SDN, -} from '../../../../common/config'; import { getFieldId, ExternalLink } from '../../../../common/components/ui'; import { NewFeatureSupportLevelMap, useNewFeatureSupportLevel, } from '../../../../common/components/newFeatureSupportLevels'; -import { TechnologyPreview } from '../../../../common/components/ui/TechnologyPreview'; +import NewFeatureSupportLevelBadge from '../../../../common/components/newFeatureSupportLevels/NewFeatureSupportLevelBadge'; import type { NetworkConfigurationValues } from '../../../../common/types/clusters'; -import { isThirdPartyCNI } from '../../utils'; +import { + NETWORK_TYPE_OVN, + NETWORK_TYPE_LABELS, + NETWORK_TYPE_FEATURE_IDS, + isThirdPartyCNI, +} from '../../../../common/types/networkType'; import { RED_HAT_CNI_SUPPORT_MATRIX_LINK } from '../../../../common/config/docs_links'; export interface NetworkTypeDropDownProps { isDisabled?: boolean; - isSDNSelectable: boolean; featureSupportLevelData: NewFeatureSupportLevelMap | null; } export const NetworkTypeDropDown = ({ isDisabled = false, - isSDNSelectable, featureSupportLevelData, }: NetworkTypeDropDownProps) => { const [field, , { setValue }] = useField('networkType'); const [isOpen, setOpen] = React.useState(false); const { values } = useFormikContext(); - const { getFeatureDisabledReason } = useNewFeatureSupportLevel(); + const { getFeatureDisabledReason, getFeatureSupportLevel } = useNewFeatureSupportLevel(); const fieldId = getFieldId('networkType', 'input'); const showThirdPartyBanner = isThirdPartyCNI(values.networkType); - const sdnDisabledReason = React.useMemo(() => { - if (!isSDNSelectable) { - return 'SDN is not supported for SNO clusters or when IPv6 is detected.'; - } - return getFeatureDisabledReason('SDN_NETWORK_TYPE', featureSupportLevelData ?? undefined); - }, [isSDNSelectable, featureSupportLevelData, getFeatureDisabledReason]); - React.useEffect(() => { - if (field.value === NETWORK_TYPE_SDN && sdnDisabledReason) { + if ( + getFeatureDisabledReason( + NETWORK_TYPE_FEATURE_IDS[field.value], + featureSupportLevelData ?? undefined, + ) !== undefined + ) { setValue(NETWORK_TYPE_OVN); } - }, [sdnDisabledReason, field.value, setValue]); + }, [field.value, setValue, featureSupportLevelData, getFeatureDisabledReason]); const currentDisplayValue = NETWORK_TYPE_LABELS[field.value]; const dropdownItems = Object.entries(NETWORK_TYPE_LABELS).map(([value, label]) => { - const isSDN = value === NETWORK_TYPE_SDN; - const disabledReason = isSDN ? sdnDisabledReason : undefined; - const isTechPreview = [ - NETWORK_TYPE_CISCO_ACI, - NETWORK_TYPE_CILIUM, - NETWORK_TYPE_CALICO, - NETWORK_TYPE_NONE, - ].includes(value); + const disabledReason = getFeatureDisabledReason( + NETWORK_TYPE_FEATURE_IDS[value], + featureSupportLevelData ?? undefined, + ); + const featureId = NETWORK_TYPE_FEATURE_IDS[value]; + const supportLevel = featureId + ? getFeatureSupportLevel(featureId, featureSupportLevelData ?? undefined) + : undefined; + const shouldDisable = + supportLevel === 'unavailable' || + supportLevel === 'unsupported' || + disabledReason !== undefined; return ( - + @@ -132,11 +121,7 @@ export const NetworkTypeDropDown = ({ {showThirdPartyBanner && ( - + Third-party CNIs require uploading CNI manifests. Please verify you have the diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx index 307c040e05..6b42cb1ea7 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx @@ -11,9 +11,10 @@ import { getRichTextValidation, useAlerts, TechnologyPreview, + OpenshiftVersionOptionType, + getFormikErrorFields, } from '../../../common'; import { canNextClusterDetails } from './wizardTransition'; -import { OpenshiftVersionOptionType, getFormikErrorFields } from '../../../common'; import ClusterWizardFooter from './ClusterWizardFooter'; import { isInOcm } from '../../../common/api'; import { diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx index c9b6c70959..5f5ced6b23 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx @@ -13,13 +13,17 @@ import { HostsNetworkConfigurationType } from '../../services'; import { defaultWizardSteps, staticIpFormViewSubSteps } from './constants'; import { StaticIpView } from '../clusterConfiguration/staticIp/data/dataTypes'; import { getStaticIpInfo } from '../clusterConfiguration/staticIp/data/fromInfraEnv'; -import { AssistedInstallerOCMPermissionTypesListType, useAlerts } from '../../../common'; +import { + AssistedInstallerOCMPermissionTypesListType, + useAlerts, + isThirdPartyCNI, +} from '../../../common'; import useSetClusterPermissions from '../../hooks/useSetClusterPermissions'; import { Cluster, InfraEnv } from '@openshift-assisted/types/assisted-installer-service'; import { useUISettings } from '../../hooks'; import { AlertVariant } from '@patternfly/react-core'; import { useFeature } from '../../hooks/use-feature'; -import { isOciPlatformType, isThirdPartyCNI } from '../utils'; +import { isOciPlatformType } from '../utils'; const addStepToClusterWizard = ( wizardStepIds: ClusterWizardStepsType[], diff --git a/libs/ui-lib/lib/ocm/components/featureSupportLevels/featureStateUtils.ts b/libs/ui-lib/lib/ocm/components/featureSupportLevels/featureStateUtils.ts index c5d562534b..7bfd2398dc 100644 --- a/libs/ui-lib/lib/ocm/components/featureSupportLevels/featureStateUtils.ts +++ b/libs/ui-lib/lib/ocm/components/featureSupportLevels/featureStateUtils.ts @@ -3,6 +3,7 @@ import { architectureData, CpuArchitecture, FeatureId, + isDualStack, isSNO, SupportedCpuArchitecture, } from '../../../common'; @@ -143,6 +144,19 @@ const getOciDisabledReason = (cpuArchitecture: string | undefined, isSupported: } }; +const getSDNDisabledReason = (cluster: Cluster | undefined, isSupported: boolean) => { + if (cluster && isSNO(cluster)) { + return 'SDN is not supported for single-node clusters.'; + } + if (cluster && isDualStack(cluster)) { + return 'SDN is not supported for dual-stack clusters.'; + } + if (!isSupported) { + return 'SDN is not supported for the selected configuration.'; + } + return undefined; +}; + export const getNewFeatureDisabledReason = ( featureId: FeatureId, cluster: Cluster | undefined, @@ -182,10 +196,7 @@ export const getNewFeatureDisabledReason = ( return getOscDisabledReason(cluster, activeFeatureConfiguration, isSupported); } case 'SDN_NETWORK_TYPE': { - if (!isSupported) { - return 'SDN is not available for the selected configuration.'; - } - return undefined; + return getSDNDisabledReason(cluster, isSupported); } case 'NETWORK_TYPE_SELECTION': { return getNetworkTypeSelectionDisabledReason(cluster); diff --git a/libs/ui-lib/lib/ocm/components/utils.ts b/libs/ui-lib/lib/ocm/components/utils.ts index bb18268248..ef4b670068 100644 --- a/libs/ui-lib/lib/ocm/components/utils.ts +++ b/libs/ui-lib/lib/ocm/components/utils.ts @@ -1,11 +1,7 @@ import { Cluster } from '@openshift-assisted/types/./assisted-installer-service'; -import { NETWORK_TYPE_OVN, NETWORK_TYPE_SDN } from '../../common/config'; export const isOciPlatformType = (cluster: Cluster): boolean => { return ( cluster.platform?.type === 'external' && cluster.platform?.external?.platformName === 'oci' ); }; - -export const isThirdPartyCNI = (networkType: Cluster['networkType']): boolean => - !!networkType && networkType !== NETWORK_TYPE_OVN && networkType !== NETWORK_TYPE_SDN; diff --git a/libs/ui-lib/lib/ocm/store/slices/clusters/selectors.tsx b/libs/ui-lib/lib/ocm/store/slices/clusters/selectors.tsx index 16fce7d83f..9dbb403f10 100644 --- a/libs/ui-lib/lib/ocm/store/slices/clusters/selectors.tsx +++ b/libs/ui-lib/lib/ocm/store/slices/clusters/selectors.tsx @@ -11,8 +11,9 @@ import { getTotalHostCount, HostsCount, ResourceUIState, + type ClusterTableRows, + type HumanizedSortable, } from '../../../../common'; -import type { ClusterTableRows, HumanizedSortable } from '../../../../common'; import ClusterStatus, { getClusterStatusText } from '../../../components/clusters/ClusterStatus'; import { RootStateDay1 } from '../../store-day1'; import type { Cluster } from '@openshift-assisted/types/assisted-installer-service';