From b21dac3822547fc1db2b3294d8d98cb3a0d1bc46 Mon Sep 17 00:00:00 2001 From: Montse Ortega Date: Thu, 26 Jun 2025 10:49:41 +0200 Subject: [PATCH 1/6] MGMT-20842: Add search to operators page --- .../components/operators/operatorSpecs.tsx | 105 +++++++++++------- .../operators/OperatorCheckbox.tsx | 7 +- .../clusterWizard/OperatorsBundle.tsx | 20 +++- .../clusterWizard/OperatorsSelect.tsx | 23 +++- .../clusterWizard/OperatorsStep.tsx | 33 +++++- 5 files changed, 134 insertions(+), 54 deletions(-) diff --git a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx index 6c99d57116..36d13318b0 100644 --- a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx +++ b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import React from 'react'; import { Cluster, SupportLevel } from '@openshift-assisted/types/assisted-installer-service'; import { FeatureId } from '../../types'; @@ -83,12 +84,31 @@ export const isOCPVersionEqualsOrMore = ( ); }; +export const highlightMatch = (text: string, searchTerm?: string): React.ReactNode => { + console.log('-------------'); + console.log(text); + console.log(searchTerm); + console.log('-----------'); + if (!searchTerm) return text; + const regex = new RegExp(`(${searchTerm})`, 'gi'); + + const parts = text.split(regex); + + return parts.map((part, i) => + part.toLowerCase() === searchTerm.toLowerCase() ? {part} : part, + ); +}; + +export const HighlightedText = ({ text, searchTerm }: { text: string; searchTerm?: string }) => ( + <>{highlightMatch(text, searchTerm)} +); + export type OperatorSpec = { operatorKey: string; title: string; featureId: FeatureId; descriptionText?: string; - Description?: React.ComponentType<{ openshiftVersion?: string }>; + Description?: React.ComponentType<{ openshiftVersion?: string; searchTerm?: string }>; notStandalone?: boolean; Requirements?: React.ComponentType<{ cluster: Cluster }>; category: string; @@ -106,9 +126,9 @@ export const getOperatorSpecs = ( title: 'Local Storage Operator', featureId: 'LSO', descriptionText: DESCRIPTION_LSO, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_LSO}{' '} + {' '} Learn more ), @@ -121,10 +141,10 @@ export const getOperatorSpecs = ( title: useLVMS ? 'Logical Volume Manager Storage' : 'Logical Volume Manager', featureId: 'LVM', descriptionText: DESCRIPTION_LVM, - Description: ({ openshiftVersion }) => + Description: ({ openshiftVersion, searchTerm }) => useLVMS ? ( <> - {DESCRIPTION_LVM}{' '} + {' '} Learn more ) : ( @@ -143,9 +163,10 @@ export const getOperatorSpecs = ( Learn more about the requirements for OpenShift Data Foundation ), - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_ODF} Learn more + {' '} + Learn more ), category: categories[Category.STORAGE], @@ -161,9 +182,10 @@ export const getOperatorSpecs = ( Requirements: () => ( <>Enabled CPU virtualization support in BIOS (Intel-VT / AMD-V) on all nodes ), - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_CNV} Learn more + {' '} + Learn more ), category: categories[Category.VIRT], @@ -174,9 +196,10 @@ export const getOperatorSpecs = ( title: 'Migration Toolkit for Virtualization', featureId: 'MTV', descriptionText: DESCRIPTION_MTV, - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_MTV} Learn more + {' '} + Learn more ), category: categories[Category.VIRT], @@ -192,9 +215,9 @@ export const getOperatorSpecs = ( Requirements: () => ( Learn more ), - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_OPENSHIFT_AI}{' '} + {' '} Learn more ), @@ -207,7 +230,12 @@ export const getOperatorSpecs = ( featureId: 'AMD_GPU', descriptionText: DESCRIPTION_AMD_GPU, Requirements: () => <>Requires at least one supported AMD GPU, - Description: () => <>{DESCRIPTION_AMD_GPU}, + Description: ({ searchTerm }) => ( + <> + {' '} + {' '} + + ), category: categories[Category.AI], supportLevel: getFeatureSupportLevel('AMD_GPU'), }, @@ -217,9 +245,9 @@ export const getOperatorSpecs = ( featureId: 'NVIDIA_GPU', descriptionText: DESCRIPTION_NVIDIA_GPU, Requirements: () => <>Requires at least one supported NVIDIA GPU, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_NVIDIA_GPU} + {' '} Learn more ), @@ -233,9 +261,9 @@ export const getOperatorSpecs = ( title: 'NMState', featureId: 'NMSTATE', descriptionText: DESCRIPTION_NMSTATE, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_NMSTATE}{' '} + {' '} Learn more ), @@ -247,9 +275,9 @@ export const getOperatorSpecs = ( title: 'Service Mesh', featureId: 'SERVICEMESH', descriptionText: DESCRIPTION_SERVICEMESH, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_SERVICEMESH}{' '} + {' '} Learn more ), @@ -264,9 +292,9 @@ export const getOperatorSpecs = ( title: 'Authorino', featureId: 'AUTHORINO', descriptionText: DESCRIPTION_AUTHORINO, - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_AUTHORINO}{' '} + {' '} Learn more ), @@ -279,9 +307,9 @@ export const getOperatorSpecs = ( title: 'Node Feature Discovery', featureId: 'NODE_FEATURE_DISCOVERY', descriptionText: DESCRIPTION_NODE_FEATURE_DISCOVERY, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_NODE_FEATURE_DISCOVERY}{' '} + {' '} Learn more @@ -295,9 +323,9 @@ export const getOperatorSpecs = ( title: 'Pipelines', featureId: 'PIPELINES', descriptionText: DESCRIPTION_PIPELINES, - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_PIPELINES}{' '} + {' '} Learn more ), @@ -310,9 +338,9 @@ export const getOperatorSpecs = ( title: 'Serverless', featureId: 'SERVERLESS', descriptionText: DESCRIPTION_SERVERLESS, - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_SERVERLESS}{' '} + {' '} Learn more ), @@ -325,9 +353,9 @@ export const getOperatorSpecs = ( title: 'Kernel Module Management', featureId: 'KMM', descriptionText: DESCRIPTION_KMM, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_KMM}{' '} + {' '} Learn more ), @@ -339,9 +367,9 @@ export const getOperatorSpecs = ( title: 'Multicluster engine', featureId: 'MCE', descriptionText: DESCRIPTION_MCE, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_MCE}{' '} + {' '} Learn more ), @@ -358,9 +386,10 @@ export const getOperatorSpecs = ( Learn more about the requirements for OpenShift sandboxed containers ), - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_OSC} Learn more + {' '} + Learn more ), category: categories[Category.OTHER], @@ -371,9 +400,9 @@ export const getOperatorSpecs = ( title: 'Kube Descheduler', featureId: 'KUBE_DESCHEDULER', descriptionText: DESCRIPTION_KUBE_DESCHEDULER, - Description: ({ openshiftVersion }) => ( + Description: ({ openshiftVersion, searchTerm }) => ( <> - {DESCRIPTION_KUBE_DESCHEDULER}{' '} + {' '} Learn more ), @@ -387,9 +416,9 @@ export const getOperatorSpecs = ( title: 'Node Maintenance', featureId: 'NODE_MAINTENANCE', descriptionText: DESCRIPTION_NODE_MAINTENANCE, - Description: () => ( + Description: ({ searchTerm }) => ( <> - {DESCRIPTION_NODE_MAINTENANCE}{' '} + {' '} Learn more ), diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/OperatorCheckbox.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/OperatorCheckbox.tsx index 4f0e17a346..84d8f89332 100644 --- a/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/OperatorCheckbox.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/operators/OperatorCheckbox.tsx @@ -26,6 +26,7 @@ import { getFieldId, OperatorsValues, PopoverIcon } from '../../../../common'; import { useNewFeatureSupportLevel } from '../../../../common/components/newFeatureSupportLevels'; import { getNewOperators } from './utils'; import { + highlightMatch, OperatorSpec, useOperatorSpecs, } from '../../../../common/components/operators/operatorSpecs'; @@ -118,12 +119,14 @@ const OperatorCheckbox = ({ Requirements, openshiftVersion, preflightRequirements, + searchTerm, }: { bundles: Bundle[]; cluster: Cluster; operatorId: string; openshiftVersion?: string; preflightRequirements: PreflightHardwareRequirements | undefined; + searchTerm?: string; } & OperatorSpec) => { const { getFeatureSupportLevel, getFeatureDisabledReason } = useNewFeatureSupportLevel(); const { byKey: opSpecs } = useOperatorSpecs(); @@ -166,7 +169,7 @@ const OperatorCheckbox = ({ label={ <> - + ) diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx index a41396f0d9..57e0f65e62 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx @@ -30,17 +30,20 @@ import { useSelector } from 'react-redux'; import { selectIsCurrentClusterSNO } from '../../store/slices/current-cluster/selectors'; import { getNewBundleOperators } from '../clusterConfiguration/operators/utils'; import { bundleSpecs } from '../clusterConfiguration/operators/bundleSpecs'; -import { OperatorSpec, useOperatorSpecs } from '../../../common/components/operators/operatorSpecs'; +import { + highlightMatch, + OperatorSpec, + useOperatorSpecs, +} from '../../../common/components/operators/operatorSpecs'; import { useClusterWizardContext } from './ClusterWizardContext'; import './OperatorsBundle.css'; -const BundleLabel = ({ bundle }: { bundle: Bundle }) => { +const BundleLabel = ({ bundle, searchTerm }: { bundle: Bundle; searchTerm?: string }) => { const { byKey: opSpecs } = useOperatorSpecs(); const bundleSpec = bundleSpecs[bundle.id || '']; - return ( <> - {bundle.title} + {highlightMatch(bundle.title || '', searchTerm)} Requirements and dependencies} @@ -100,10 +103,12 @@ const BundleCard = ({ bundle, bundles, preflightRequirements, + searchTerm, }: { bundle: Bundle; bundles: Bundle[]; preflightRequirements: PreflightHardwareRequirements | undefined; + searchTerm?: string; }) => { const { values, setFieldValue } = useFormikContext(); const isSNO = useSelector(selectIsCurrentClusterSNO); @@ -177,13 +182,13 @@ const BundleCard = ({ }} > - + -
{bundle.description}
+
{highlightMatch(bundle.description || '', searchTerm)}
@@ -206,9 +211,11 @@ const BundleCard = ({ const OperatorsBundle = ({ bundles, preflightRequirements, + searchTerm, }: { bundles: Bundle[]; preflightRequirements: PreflightHardwareRequirements | undefined; + searchTerm?: string; }) => { const isSingleClusterFeatureEnabled = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE'); @@ -230,6 +237,7 @@ const OperatorsBundle = ({ bundle={bundle} bundles={bundles} preflightRequirements={preflightRequirements} + searchTerm={searchTerm} /> ))} diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx index 86d68955dc..2010204c9e 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx @@ -24,10 +24,12 @@ const OperatorsSelect = ({ cluster, bundles, preflightRequirements, + searchTerm, }: { cluster: Cluster; bundles: Bundle[]; preflightRequirements: PreflightHardwareRequirements | undefined; + searchTerm?: string; }) => { const [isLoading, setIsLoading] = useStateSafely(true); const { addAlert } = useAlerts(); @@ -64,14 +66,14 @@ const OperatorsSelect = ({ }); }, [isSingleClusterFeatureEnabled, supportedOperators]); - if (isLoading) { - return ; - } - const selectedOperators = values.selectedOperators.filter( (opKey) => operators.includes(opKey) && !!opSpecs[opKey], ); + if (isLoading) { + return ; + } + return ( {Object.entries(byCategory).map(([categoryName, specs]) => { - const categoryOperators = specs.filter((spec) => operators.includes(spec.operatorKey)); + let categoryOperators = specs.filter((spec) => operators.includes(spec.operatorKey)); + // Filter by searchTerm + if (searchTerm?.trim()) { + const term = searchTerm.trim().toLowerCase(); + categoryOperators = categoryOperators.filter((spec) => { + const op = opSpecs[spec.operatorKey]; + const title = op?.title?.toLowerCase() || ''; + const description = op?.descriptionText?.toLowerCase() || ''; + return title.includes(term) || description.includes(term); + }); + } if (categoryOperators.length === 0) { return null; } @@ -99,6 +111,7 @@ const OperatorsSelect = ({ cluster={cluster} openshiftVersion={cluster.openshiftVersion} preflightRequirements={preflightRequirements} + searchTerm={searchTerm} {...spec} /> diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx index 4c94f947c8..91e9ad2b2d 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsStep.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Stack, StackItem } from '@patternfly/react-core'; +import { Flex, FlexItem, SearchInput, Stack, StackItem } from '@patternfly/react-core'; import { Bundle } from '@openshift-assisted/types/assisted-installer-service'; import { ClusterOperatorProps, @@ -19,6 +19,7 @@ export const OperatorsStep = ({ cluster }: ClusterOperatorProps) => { const [bundlesLoading, setBundlesLoading] = React.useState(true); const [bundles, setBundles] = React.useState([]); const { preflightRequirements, isLoading } = useClusterPreflightRequirements(cluster.id); + const [searchTerm, setSearchTerm] = React.useState(''); React.useEffect(() => { const fetchBundles = async () => { try { @@ -39,6 +40,12 @@ export const OperatorsStep = ({ cluster }: ClusterOperatorProps) => { void fetchBundles(); }, [addAlert]); + const filteredBundles = bundles.filter( + (bundle) => + bundle.title?.toLowerCase().includes(searchTerm.toLowerCase()) || + bundle.description?.toLowerCase().includes(searchTerm.toLowerCase()), + ); + if (isLoading || bundlesLoading) { return ; } @@ -46,16 +53,36 @@ export const OperatorsStep = ({ cluster }: ClusterOperatorProps) => { return ( - Operators + + + Operators + + + setSearchTerm(value)} + onClear={() => setSearchTerm('')} + /> + + - + From e66069615da7441266fb0b921445f2824b4eb2ad Mon Sep 17 00:00:00 2001 From: Montse Ortega Date: Thu, 26 Jun 2025 11:38:09 +0200 Subject: [PATCH 2/6] Remove console.log --- .../ui-lib/lib/common/components/operators/operatorSpecs.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx index 36d13318b0..aaf3a14bfb 100644 --- a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx +++ b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ import React from 'react'; import { Cluster, SupportLevel } from '@openshift-assisted/types/assisted-installer-service'; import { FeatureId } from '../../types'; @@ -85,10 +84,6 @@ export const isOCPVersionEqualsOrMore = ( }; export const highlightMatch = (text: string, searchTerm?: string): React.ReactNode => { - console.log('-------------'); - console.log(text); - console.log(searchTerm); - console.log('-----------'); if (!searchTerm) return text; const regex = new RegExp(`(${searchTerm})`, 'gi'); From 0189c14b53d89e0ede014ecafc387dd6f5710073 Mon Sep 17 00:00:00 2001 From: Montse Ortega Date: Thu, 26 Jun 2025 12:42:27 +0200 Subject: [PATCH 3/6] Add 'No results found' text --- .../clusterWizard/OperatorsBundle.tsx | 2 +- .../clusterWizard/OperatorsSelect.tsx | 94 ++++++++++--------- 2 files changed, 50 insertions(+), 46 deletions(-) diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx index 57e0f65e62..bfc6d5d46d 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsBundle.tsx @@ -223,7 +223,7 @@ const OperatorsBundle = ({ - Bundles + {bundles.length > 0 ? 'Bundles' : ''} diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx index 2010204c9e..9d2c8c8fcc 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx @@ -73,54 +73,58 @@ const OperatorsSelect = ({ if (isLoading) { return ; } - + let foundAtLeastOneOperator = false; return ( - setIsExpanded(!isExpanded)} - isExpanded={isExpanded} - data-testid="single-operators-section" - > - - {Object.entries(byCategory).map(([categoryName, specs]) => { - let categoryOperators = specs.filter((spec) => operators.includes(spec.operatorKey)); - // Filter by searchTerm - if (searchTerm?.trim()) { - const term = searchTerm.trim().toLowerCase(); - categoryOperators = categoryOperators.filter((spec) => { - const op = opSpecs[spec.operatorKey]; - const title = op?.title?.toLowerCase() || ''; - const description = op?.descriptionText?.toLowerCase() || ''; - return title.includes(term) || description.includes(term); - }); - } - if (categoryOperators.length === 0) { - return null; - } + <> + setIsExpanded(!isExpanded)} + isExpanded={isExpanded} + data-testid="single-operators-section" + > + + {Object.entries(byCategory).map(([categoryName, specs]) => { + let categoryOperators = specs.filter((spec) => operators.includes(spec.operatorKey)); + // Filter by searchTerm + if (searchTerm?.trim()) { + const term = searchTerm.trim().toLowerCase(); + categoryOperators = categoryOperators.filter((spec) => { + const op = opSpecs[spec.operatorKey]; + const title = op?.title?.toLowerCase() || ''; + const description = op?.descriptionText?.toLowerCase() || ''; + return title.includes(term) || description.includes(term); + }); + } + if (categoryOperators.length === 0) { + return null; + } + foundAtLeastOneOperator = true; - return ( - - - {categoryName} - - {categoryOperators.map((spec) => ( - - + return ( + + + {categoryName} - ))} - - ); - })} - - + {categoryOperators.map((spec) => ( + + + + ))} + + ); + })} + + + {!foundAtLeastOneOperator && !!searchTerm?.trim() && No results found} + ); }; From f099abfd10afff2058e3933ad483616b262e0395 Mon Sep 17 00:00:00 2001 From: Montse Ortega Date: Thu, 26 Jun 2025 13:47:00 +0200 Subject: [PATCH 4/6] Expand operators section when results are founded --- .../lib/ocm/components/clusterWizard/OperatorsSelect.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx index 9d2c8c8fcc..5c72e31c45 100644 --- a/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx +++ b/libs/ui-lib/lib/ocm/components/clusterWizard/OperatorsSelect.tsx @@ -99,6 +99,10 @@ const OperatorsSelect = ({ return null; } foundAtLeastOneOperator = true; + if (!!searchTerm?.trim() && !isExpanded) { + //if we found some results expand operators section + setIsExpanded(true); + } return ( From bc4c5d70d16be9dd43ecde4e2e96dbf8306fe537 Mon Sep 17 00:00:00 2001 From: Montse Ortega Date: Thu, 26 Jun 2025 14:37:59 +0200 Subject: [PATCH 5/6] Change regexp for operators search --- libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx index aaf3a14bfb..079ccf3ee2 100644 --- a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx +++ b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx @@ -85,7 +85,8 @@ export const isOCPVersionEqualsOrMore = ( export const highlightMatch = (text: string, searchTerm?: string): React.ReactNode => { if (!searchTerm) return text; - const regex = new RegExp(`(${searchTerm})`, 'gi'); + const escapeSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regex = new RegExp(`(${escapeSearchTerm})`, 'gi'); const parts = text.split(regex); From 3052aca238d096ebfbc7deda7636117e88d9594e Mon Sep 17 00:00:00 2001 From: Montse Ortega Date: Mon, 30 Jun 2025 10:57:09 +0200 Subject: [PATCH 6/6] Add try-catch to highlightMatch function in operatorSpecs file --- .../components/operators/operatorSpecs.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx index 588efa40b6..330d54f8af 100644 --- a/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx +++ b/libs/ui-lib/lib/common/components/operators/operatorSpecs.tsx @@ -85,14 +85,20 @@ export const isOCPVersionEqualsOrMore = ( export const highlightMatch = (text: string, searchTerm?: string): React.ReactNode => { if (!searchTerm) return text; - const escapeSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - const regex = new RegExp(`(${escapeSearchTerm})`, 'gi'); + try { + const escapeSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regex = new RegExp(`(${escapeSearchTerm})`, 'gi'); - const parts = text.split(regex); + const parts = text.split(regex); - return parts.map((part, i) => - part.toLowerCase() === searchTerm.toLowerCase() ? {part} : part, - ); + return parts.map((part, i) => + part.toLowerCase() === searchTerm.toLowerCase() ? {part} : part, + ); + } catch (err) { + // eslint-disable-next-line no-console + console.log('failed to highlight search text', err); + return text; + } }; export const HighlightedText = ({ text, searchTerm }: { text: string; searchTerm?: string }) => (