Skip to content

Conversation

@logonoff
Copy link
Member

@logonoff logonoff commented Jan 12, 2026

Previously, if a catalog/item-type was disabled in console-operator config, the hooks associated with that catalog type would still resolve and run.

image

Now, if a catalog category is disabled, the associated hooks will not run.

image

Summary by CodeRabbit

  • New Features

    • Added catalog relevance scoring, Red Hat prioritization, keyword-aware comparison, and stable sorting options.
    • Server-flag driven sub-catalog visibility with memoized computation for consistent, faster results.
    • New utilities exported to support sorting and relevance logic.
  • Bug Fixes

    • Disabled catalog types are consistently filtered across extension flows so unavailable items no longer appear.
  • Tests

    • Updated tests to align with the new extensions retrieval behavior and memoized visibility logic.

✏️ Tip: You can customize this high-level summary in your review settings.

@openshift-ci-robot openshift-ci-robot added jira/severity-moderate Referenced Jira bug's severity is moderate for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jan 12, 2026
@openshift-ci-robot
Copy link
Contributor

@logonoff: This pull request references Jira Issue OCPBUGS-72585, which is invalid:

  • expected the bug to target the "4.22.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Previously, if a catalog/item-type was disabled in console-operator config, the hooks associated with that catalog type would still run.

image

Now, if a catalog category is disabled, the associated hooks will not run.

image

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@logonoff logonoff marked this pull request as ready for review January 12, 2026 15:21
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 12, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

Walkthrough

Filters disabled catalog item types during extension processing, replaces useResolvedExtensions with useExtensions, derives disabled sub-catalogs from SERVER_FLAGS via a memoized hook, adds item relevance scoring/sorting helpers, and updates tests to mock/use the new useExtensions behavior.

Changes

Cohort / File(s) Summary
Catalog extension gating & predicates
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
Adds import/usage of useGetAllDisabledSubCatalogs, computes disabledCatalogs, introduces isNotDisabledType, and applies it across multiple extension type guards (CatalogItemType, CatalogItemTypeMetadata, CatalogItemProvider, CatalogItemFilter, CatalogCategoriesProvider, CatalogItemMetadataProvider). Filters item-type extensions before metadata augmentation and updates dependency arrays. Public APIs unchanged.
Catalog utilities, hook migration & relevance/sorting helpers
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx
Replaces useResolvedExtensions with useExtensions, adds getSoftwareCatalogTypes() and SoftwareCatalogTypesConfig parsing of window.SERVER_FLAGS, refactors useGetAllDisabledSubCatalogs to use useExtensions + useMemo, and introduces exported utilities: calculateCatalogItemRelevanceScore, getRedHatPriority, keywordCompare, and sortCatalogItems. Adjusts imports and memoization.
Tests: hook mock updates
frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts
Updates tests to mock useExtensions (single-value return) instead of useResolvedExtensions (previous tuple-like mock), adapts mocked return shape and wraps hook evaluations in test harnesses to match new hook behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: preventing catalog item hooks from running when disabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 12, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 12, 2026
@logonoff
Copy link
Member Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jan 12, 2026
@openshift-ci-robot
Copy link
Contributor

@logonoff: This pull request references Jira Issue OCPBUGS-72585, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.22.0) matches configured target version for branch (4.22.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @yapei

Details

In response to this:

/jira refresh

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot requested a review from yapei January 12, 2026 15:22
@openshift-ci-robot
Copy link
Contributor

@logonoff: This pull request references Jira Issue OCPBUGS-72585, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.22.0) matches configured target version for branch (4.22.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @yapei

Details

In response to this:

Previously, if a catalog/item-type was disabled in console-operator config, the hooks associated with that catalog type would still run.

image

Now, if a catalog category is disabled, the associated hooks will not run.

image

Summary by CodeRabbit

  • New Features
  • Catalog type management: Administrators can now configure which catalog types are visible in the developer catalog through console operator settings. This enables better control over which resources are available to developers. Supported types include Templates, Builder Images, Devfiles, Samples, Helm Charts, Event Types, Event Sources, Event Sinks, Operators, and Operator-backed Services.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/packages/operator-lifecycle-manager/console-extensions.json (1)

378-388: Add SOFTWARE_CATALOG_TYPE_OPERATOR_DISABLED to operator item-provider flags for consistent gating.

The console.catalog/item-provider for operators (line 386) only disallows OLMV1_ENABLED, while the corresponding console.catalog/item-type (line 440) and categories-provider (line 450) both include SOFTWARE_CATALOG_TYPE_OPERATOR_DISABLED. This asymmetric gating breaks the established pattern: the OperatorBackedService item-provider and item-type both use their respective SOFTWARE_CATALOG_TYPE_*_DISABLED flags consistently. The operator item-provider should include SOFTWARE_CATALOG_TYPE_OPERATOR_DISABLED in its disallowed array to ensure symmetric feature gating and prevent data fetching when the operator catalog is disabled.

🤖 Fix all issues with AI agents
In @frontend/packages/dev-console/src/actions/providers.tsx:
- Around line 370-384: useDisabledCatalogTypes currently only sets
SOFTWARE_CATALOG_TYPE_<TYPE>_DISABLED to true for items in catalogTypes.disabled
and never resets flags to false; update the logic in useDisabledCatalogTypes so
you compute the union of catalogTypes.disabled and catalogTypes.enabled (or a
known set of types), then call setFeatureFlag for each type: set true when the
type is in catalogTypes.disabled, otherwise set false, ensuring flags are
explicitly reset when a type is re-enabled; reference the
useDisabledCatalogTypes function, the catalogTypes.disabled/
catalogTypes.enabled values, and the setFeatureFlag call.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a1355a3 and 951e59a.

📒 Files selected for processing (8)
  • frontend/packages/dev-console/console-extensions.json
  • frontend/packages/dev-console/src/actions/providers.tsx
  • frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx
  • frontend/packages/dev-console/src/types/catalog.ts
  • frontend/packages/helm-plugin/console-extensions.json
  • frontend/packages/knative-plugin/console-extensions.json
  • frontend/packages/operator-lifecycle-manager-v1/console-extensions.json
  • frontend/packages/operator-lifecycle-manager/console-extensions.json
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx (1)
frontend/packages/dev-console/src/types/catalog.ts (1)
  • DeveloperCatalogTypes (3-7)
frontend/packages/dev-console/src/actions/providers.tsx (2)
frontend/packages/console-dynamic-plugin-sdk/src/extensions/feature-flags.ts (1)
  • FeatureFlagHandler (46-46)
frontend/packages/dev-console/src/types/catalog.ts (1)
  • SoftwareCatalogTypesConsoleConfig (9-17)
🔇 Additional comments (19)
frontend/packages/operator-lifecycle-manager-v1/console-extensions.json (1)

52-76: LGTM! Consistent gating of OLMv1 operator catalog extensions.

Both console.catalog/item-provider and console.catalog/categories-provider are correctly gated with SOFTWARE_CATALOG_TYPE_OPERATOR_DISABLED disallowed flag. This ensures hooks won't execute when the operator catalog type is disabled via console-operator config.

frontend/packages/operator-lifecycle-manager/console-extensions.json (2)

264-295: LGTM! OperatorBackedService extensions properly gated.

Both console.catalog/item-type and console.catalog/item-provider for OperatorBackedService are correctly configured with SOFTWARE_CATALOG_TYPE_OPERATORBACKEDSERVICE_DISABLED in the disallowed flags. This ensures the hooks won't run when this catalog type is disabled.


438-452: LGTM! Operator item-type and categories-provider correctly gated.

The console.catalog/item-type for operators and console.catalog/categories-provider both include SOFTWARE_CATALOG_TYPE_OPERATOR_DISABLED in their disallowed flags, ensuring proper feature-flag gating when the catalog type is disabled.

frontend/packages/helm-plugin/console-extensions.json (1)

182-217: LGTM! Helm chart catalog extensions properly gated.

Both console.catalog/item-type and console.catalog/item-provider for HelmChart correctly include SOFTWARE_CATALOG_TYPE_HELMCHART_DISABLED in their disallowed flags alongside the existing OPENSHIFT_HELM required flag. This ensures Helm chart hooks won't execute when the catalog type is disabled.

frontend/packages/knative-plugin/console-extensions.json (3)

473-504: LGTM! EventType catalog extensions properly gated.

Both console.catalog/item-type and console.catalog/item-provider for EventType correctly include SOFTWARE_CATALOG_TYPE_EVENTTYPE_DISABLED in disallowed flags.


706-750: LGTM! EventSource catalog extensions comprehensively gated.

All three EventSource-related extensions are properly configured:

  • console.catalog/item-type for EventSource
  • console.catalog/item-provider using useEventSourceProvider
  • console.catalog/item-provider using useKameletsProvider

All include SOFTWARE_CATALOG_TYPE_EVENTSOURCE_DISABLED in their disallowed flags.


751-795: LGTM! EventSink catalog extensions comprehensively gated.

All three EventSink-related extensions are properly configured:

  • console.catalog/item-type for EventSink
  • console.catalog/item-provider using useKameletsSinkProvider
  • console.catalog/item-provider using useKafkaSinkProvider

All include SOFTWARE_CATALOG_TYPE_EVENTSINK_DISABLED in their disallowed flags, ensuring consistent behavior when the catalog type is disabled.

frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx (2)

18-18: LGTM! Clean type consolidation.

Good refactoring to import DeveloperCatalogTypes and SoftwareCatalogTypesConsoleConfig from the centralized types file. This improves maintainability by having a single source of truth for these types, which aligns with the broader PR changes introducing the catalog type gating mechanism.


52-52: LGTM! State typing updated correctly.

The useState<DeveloperCatalogTypes>() correctly aligns with the imported type, which per the code snippet includes state: 'Enabled' | 'Disabled' plus optional enabled and disabled arrays. This matches the existing usage throughout the component.

frontend/packages/dev-console/src/types/catalog.ts (2)

9-17: LGTM!

The SoftwareCatalogTypesConsoleConfig type properly extends K8sResourceKind and uses appropriate optional chaining for the nested config structure. This aligns well with the console operator config schema pattern.


3-7: The state field and enabled array are actively used throughout the codebase and the type definition is well-implemented. The state field determines the filtering mode: 'Enabled' operates as an allowlist (only types in the enabled array are shown), while 'Disabled' operates as a denylist (types in the disabled array are hidden). Both CatalogTypesConfiguration and the shared catalog utilities properly respect this semantic. No changes needed.

frontend/packages/dev-console/src/actions/providers.tsx (2)

72-80: LGTM!

The useSoftwareCatalogProvider correctly uses the FeatureFlagHandler type, aligning with the established pattern in this codebase. The hook calls within this handler follow the console.flag/hookProvider extension contract.


26-26: LGTM!

New imports for useConsoleOperatorConfig and SoftwareCatalogTypesConsoleConfig are appropriate for the new functionality.

Also applies to: 39-39

frontend/packages/dev-console/console-extensions.json (6)

174-179: LGTM!

The new console.flag/hookProvider extension correctly wires useDisabledCatalogTypes to set feature flags based on console operator config. This follows the established pattern used by useSoftwareCatalogProvider.


469-486: LGTM!

The disallowed flags for BuilderImage item-type and item-provider are correctly added. The flag name SOFTWARE_CATALOG_TYPE_BUILDERIMAGE_DISABLED matches the uppercase transformation in useDisabledCatalogTypes.


495-512: LGTM!

Template item-type and item-provider correctly gated with SOFTWARE_CATALOG_TYPE_TEMPLATE_DISABLED.


521-538: LGTM!

Devfile item-type and item-provider correctly gated with SOFTWARE_CATALOG_TYPE_DEVFILE_DISABLED.


562-587: LGTM!

The samples-catalog providers for BuilderImage and Devfile types are correctly gated with their respective _DISABLED flags. This ensures that when a catalog type is disabled, both the main catalog and the samples catalog respect the configuration.


539-561: Flag naming and usage are consistent and correct.

The codebase dynamically generates SOFTWARE_CATALOG_TYPE_<TYPE>_DISABLED flags from the operator config's disabled array values (see frontend/packages/dev-console/src/actions/providers.tsx). This ensures that cluster admins simply list catalog type names (e.g., "Sample") and the flag name generation handles consistency automatically.

Note: CONSOLESAMPLE is a separate feature flag for the ConsoleSample provider itself and serves a different purpose than the catalog type disabling mechanism. The two are used correctly.

@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch from 951e59a to b0ab1fb Compare January 12, 2026 15:26
@openshift-ci openshift-ci bot added the component/dev-console Related to dev-console label Jan 12, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 12, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: logonoff

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added component/helm Related to helm-plugin approved Indicates a PR has been approved by an approver from all required OWNERS files. component/knative Related to knative-plugin component/olm Related to OLM labels Jan 12, 2026
@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch from b0ab1fb to 706397e Compare January 12, 2026 15:35
@openshift-ci openshift-ci bot added the component/shared Related to console-shared label Jan 12, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
@frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts:
- Around line 34-44: The isNotDisabledType predicate currently returns falsy
when e.properties.type is undefined, which incorrectly filters out
global/typeless extensions; update the isNotDisabledType callback so it returns
true when e.properties.type is not set (i.e., allow typeless entries) and only
checks catalogTypes.disabled.includes(e.properties.type) when a type exists;
ensure you modify the function named isNotDisabledType (used alongside
CatalogCategoriesProvider predicates) to first short-circuit for
!e.properties.type and otherwise check the disabled list.
🧹 Nitpick comments (3)
frontend/packages/console-shared/src/components/cluster-configuration/useConsoleOperatorConfig.ts (1)

7-13: Consider making the hook return type explicit (to prevent tuple-shape drift).

Since callers commonly destructure this hook, an explicit return type (based on useK8sWatchResource) can help catch mismatches early if the watch hook’s signature evolves.

frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (2)

3-4: Type import layering: console-shared depending on dev-console types is awkward long-term.

Even as a type-only import, this creates coupling from console-shared to dev-console. Consider moving SoftwareCatalogTypesConsoleConfig (or a narrower “developerCatalog.types” shape) into a shared location within console-shared (or a common types package) to keep dependency direction clean.


46-116: Add focused tests for disabled types + type-less extensions.

Given the new filtering is now a cross-cutting gate for all resolved extension kinds, please add coverage for:

  • a disabled type being filtered out for each extension kind you expect to be typed
  • an extension with no properties.type still being retained (if supported/expected), especially for CatalogCategoriesProvider

Also applies to: 118-147

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between b0ab1fb and 706397e.

📒 Files selected for processing (5)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
  • frontend/packages/console-shared/src/components/cluster-configuration/index.ts
  • frontend/packages/console-shared/src/components/cluster-configuration/useConsoleOperatorConfig.ts
  • frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx
  • frontend/packages/dev-console/src/types/catalog.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/packages/dev-console/src/types/catalog.ts
  • frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (2)
frontend/packages/console-shared/src/components/cluster-configuration/useConsoleOperatorConfig.ts (1)
  • useConsoleOperatorConfig (7-13)
frontend/packages/dev-console/src/types/catalog.ts (1)
  • SoftwareCatalogTypesConsoleConfig (9-17)
frontend/packages/console-shared/src/components/cluster-configuration/useConsoleOperatorConfig.ts (1)
frontend/packages/console-shared/src/components/cluster-configuration/index.ts (1)
  • useConsoleOperatorConfig (3-3)
🔇 Additional comments (1)
frontend/packages/console-shared/src/components/cluster-configuration/index.ts (1)

3-3: Refactor to named export is safe—no default imports remain.

The codebase has been successfully sanitized: no default imports of useConsoleOperatorConfig exist. Both the source file and the index correctly export it as a named export, forcing all consumers to use the named import pattern. The transition is complete with no breaking references lingering.

@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch from 706397e to 8f769d4 Compare January 12, 2026 15:48
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
@frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts:
- Around line 34-48: The isNotDisabledType callback must handle
DeveloperCatalogTypes' state modes and guard against undefined arrays: if
e.properties.type is missing, keep returning true; otherwise read catalogTypes
from consoleConfig and if catalogTypes.state === 'Enabled' return
catalogTypes.enabled?.includes(e.properties.type) === true; if
catalogTypes.state === 'Disabled' and catalogTypes.disabled is undefined treat
that as "everything disabled" (return false), else return
!catalogTypes.disabled?.includes(e.properties.type); ensure you never call
.includes on an undefined array by using optional chaining or nullish coalescing
when checking enabled/disabled arrays.
- Line 3: The import of SoftwareCatalogTypesConsoleConfig (and similarly
INCONTEXT_ACTIONS_CONNECTS_TO) from the plugin package creates a forbidden
coupling; move the shared catalog types/constants into the console-shared
package and update imports: extract SoftwareCatalogTypesConsoleConfig into a new
type file (e.g., console-shared's types catalog export) and extract
INCONTEXT_ACTIONS_CONNECTS_TO into a console-shared constants module, export
them, then replace the import in useCatalogExtensions.ts (and any other
references) to import from the new console-shared types/constants instead of
from @console/dev-console.
🧹 Nitpick comments (1)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)

127-129: Redundant filtering — itemTypeExtensions already filtered.

The itemTypeExtensions array was already filtered by isNotDisabledType during useResolvedExtensions resolution (line 54). This second .filter(isNotDisabledType) iterates the array again without effect.

♻️ Remove redundant filter
       (catalogType
         ? itemTypeExtensions.filter((e) => e.properties.type === catalogType)
         : itemTypeExtensions
-      )
-        .filter(isNotDisabledType)
-        .map((e) => {
+      ).map((e) => {

Also remove isNotDisabledType from the dependency array at line 150 if this is cleaned up.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 706397e and 8f769d4.

📒 Files selected for processing (5)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
  • frontend/packages/console-shared/src/components/cluster-configuration/index.ts
  • frontend/packages/console-shared/src/components/cluster-configuration/useConsoleOperatorConfig.ts
  • frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx
  • frontend/packages/dev-console/src/types/catalog.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/packages/console-shared/src/components/cluster-configuration/useConsoleOperatorConfig.ts
  • frontend/packages/dev-console/src/types/catalog.ts
  • frontend/packages/console-shared/src/components/cluster-configuration/index.ts
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx (1)
frontend/packages/dev-console/src/types/catalog.ts (1)
  • DeveloperCatalogTypes (3-7)
🔇 Additional comments (2)
frontend/packages/dev-console/src/components/catalog/CatalogTypesConfiguration.tsx (1)

18-18: Clean type extraction to shared module — LGTM.

Good separation of concerns moving DeveloperCatalogTypes and SoftwareCatalogTypesConsoleConfig to a dedicated types module. This aligns with our pattern of keeping reusable types accessible across packages.

Also applies to: 52-52

frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)

50-120: Consistent filtering across all extension types — good pattern.

The isNotDisabledType predicate is correctly applied to all relevant extension resolution callbacks (CatalogItemType, CatalogItemTypeMetadata, CatalogItemProvider, CatalogItemFilter, CatalogCategoriesProvider, CatalogItemMetadataProvider), and dependency arrays are properly updated.

Once the logic issue in isNotDisabledType is addressed, this will properly prevent disabled catalog hooks from executing.

@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch from 8f769d4 to c14b708 Compare January 12, 2026 17:39
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (1)

127-132: Remove debug console.log statements before merging.

These debug logs (console.log('🔍 Enhanced keywordCompare called:..., console.log('📂 keywordCompare (No Search)..., etc.) will pollute the browser console in production. They should be removed or guarded behind a debug flag.

🧹 Proposed fix to remove debug logs
 export const keywordCompare = (filterString: string, items: CatalogItem[]): CatalogItem[] => {
-  // eslint-disable-next-line no-console
-  console.log('🔍 Enhanced keywordCompare called:', {
-    filterString,
-    itemCount: items.length,
-    catalogType: items[0]?.type || 'unknown',
-  });
-
   if (!filterString) {
     // No search term - sort by Red Hat priority and then alphabetically
     const sortedItems = [...items].sort((a, b) => {
-    // Reduced logging - detailed logging now happens in CatalogView after all filtering
-    if (sortedItems.length > 0 && sortedItems[0]?.type === 'operator') {
-      // eslint-disable-next-line no-console
-      console.log(
-        `📂 keywordCompare (No Search) - Red Hat Priority Sorting (${sortedItems.length} items)`,
-      );
-    }
-
     return sortedItems;
-  // Reduced logging - detailed logging now happens in CatalogView after all filtering
-  if (sortedItems.length > 0 && sortedItems[0]?.type === 'operator') {
-    // eslint-disable-next-line no-console
-    console.log(
-      `🔍 keywordCompare (Search: "${filterString}") - Relevance Scoring (${sortedItems.length} matches)`,
-    );
-  }
-
   // Remove the added properties before returning

Also applies to: 150-155, 197-202

🤖 Fix all issues with AI agents
In
@frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts:
- Around line 31-43: The hook call to useGetAllDisabledSubCatalogs() is
returning an array-wrapped value, so disabledCatalogs is currently an array of
arrays and includes checks in isNotDisabledType never match; change the
assignment so disabledCatalogs is the inner flat array (destructure the returned
tuple/array or otherwise extract/flatten the first element from
useGetAllDisabledSubCatalogs()), then keep the isNotDisabledType logic the same
to correctly check disabledCatalogs.includes(e.properties.type).
🧹 Nitpick comments (1)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)

117-145: Redundant isNotDisabledType filter on already-filtered extensions.

itemTypeExtensions is already filtered by isNotDisabledType in the useResolvedExtensions callback at line 48-51. The additional .filter(isNotDisabledType) at line 123 is redundant and adds unnecessary iteration.

♻️ Suggested simplification
   const catalogTypeExtensions = useMemo<ResolvedExtension<CatalogItemType>[]>(
     () =>
       (catalogType
         ? itemTypeExtensions.filter((e) => e.properties.type === catalogType)
         : itemTypeExtensions
       )
-        .filter(isNotDisabledType)
         .map((e) => {
           const metadataExts = typeMetadataExtensions.filter(
             (em) => e.properties.type === em.properties.type,
           );
           // ... rest unchanged
         }),
-    [catalogType, itemTypeExtensions, typeMetadataExtensions, isNotDisabledType],
+    [catalogType, itemTypeExtensions, typeMetadataExtensions],
   );
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 8f769d4 and c14b708.

📒 Files selected for processing (2)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
  • frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (2)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (1)
  • useGetAllDisabledSubCatalogs (380-405)
frontend/packages/console-dynamic-plugin-sdk/src/extensions/catalog.ts (3)
  • CatalogItemType (7-25)
  • isCatalogItemType (112-114)
  • isCatalogItemTypeMetadata (116-118)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (2)
frontend/packages/console-plugin-sdk/src/api/useExtensions.ts (1)
  • useExtensions (44-90)
frontend/packages/console-dynamic-plugin-sdk/src/extensions/catalog.ts (2)
  • CatalogItemType (7-25)
  • isCatalogItemType (112-114)
🔇 Additional comments (2)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (1)

2-2: LGTM on the hook switch from useResolvedExtensions to useExtensions.

The change is appropriate here. Both useGetAllDisabledSubCatalogs and useIsSoftwareCatalogEnabled only access type.properties.type (a plain string), so there's no need for CodeRef resolution that useResolvedExtensions provides. This avoids unnecessary async resolution overhead for these utility functions.

Also applies to: 11-11, 381-381, 409-409

frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)

45-53: LGTM on the comprehensive filtering approach.

Solid implementation applying isNotDisabledType consistently across all six extension resolution hooks: CatalogItemType, CatalogItemTypeMetadata, CatalogItemProvider, CatalogItemFilter, CatalogCategoriesProvider, and CatalogItemMetadataProvider. The dependency arrays are correctly updated to include isNotDisabledType.

The fallback in isNotDisabledType (lines 36-38) correctly handles extensions without a type property by considering them not disabled — good defensive coding.

Also applies to: 55-65, 67-76, 78-87, 89-102, 104-115

@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch 2 times, most recently from a79f9a7 to 567f091 Compare January 12, 2026 17:50
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (2)

127-159: Remove console.log statements from production code.

These debug logging statements will pollute the browser console in production. OpenShift Console follows PatternFly and K8s best practices where debug logging should be conditional or removed entirely.

🛠️ Proposed fix
 export const keywordCompare = (filterString: string, items: CatalogItem[]): CatalogItem[] => {
-  // eslint-disable-next-line no-console
-  console.log('🔍 Enhanced keywordCompare called:', {
-    filterString,
-    itemCount: items.length,
-    catalogType: items[0]?.type || 'unknown',
-  });
-
   if (!filterString) {
     // No search term - sort by Red Hat priority and then alphabetically
     const sortedItems = [...items].sort((a, b) => {
       const aPriority = getRedHatPriority(a);
       const bPriority = getRedHatPriority(b);

       // Primary sort by Red Hat priority
       if (aPriority !== bPriority) {
         return bPriority - aPriority;
       }

       // Secondary sort by name (alphabetical)
       return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
     });

-    // Reduced logging - detailed logging now happens in CatalogView after all filtering
-    if (sortedItems.length > 0 && sortedItems[0]?.type === 'operator') {
-      // eslint-disable-next-line no-console
-      console.log(
-        `📂 keywordCompare (No Search) - Red Hat Priority Sorting (${sortedItems.length} items)`,
-      );
-    }
-
     return sortedItems;
   }

197-207: Additional console.log to remove.

Same issue as above - remove this debug logging from production code.

🛠️ Proposed fix
-  // Reduced logging - detailed logging now happens in CatalogView after all filtering
-  if (sortedItems.length > 0 && sortedItems[0]?.type === 'operator') {
-    // eslint-disable-next-line no-console
-    console.log(
-      `🔍 keywordCompare (Search: "${filterString}") - Relevance Scoring (${sortedItems.length} matches)`,
-    );
-  }
-
   // Remove the added properties before returning
   return sortedItems.map(({ relevanceScore, redHatPriority, ...item }) => item);
 };
🧹 Nitpick comments (4)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (2)

145-148: Add null safety for a.name and b.name in sorting.

If a CatalogItem has a missing or null name property, calling .toLowerCase() will throw. While unlikely given the data model, defensive coding here prevents potential runtime errors.

♻️ Suggested improvement
       // Secondary sort by name (alphabetical)
-      return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
+      return (a.name ?? '').toLowerCase().localeCompare((b.name ?? '').toLowerCase());

413-424: Potential performance concern: duplicate useExtensions calls.

Both useGetAllDisabledSubCatalogs (line 387) and useIsSoftwareCatalogEnabled (line 415) call useExtensions<CatalogItemType>(isCatalogItemType). Since useIsSoftwareCatalogEnabled already calls useGetAllDisabledSubCatalogs, you could return the catalog types from that hook instead of making a second useExtensions call.

♻️ Consider returning catalog types from useGetAllDisabledSubCatalogs

The second element of the tuple already contains catalogTypeExtensions in some code paths (line 404). You could standardize this to always return it, avoiding the duplicate hook call:

-export const useGetAllDisabledSubCatalogs = (): [string[], string[]?] => {
+export const useGetAllDisabledSubCatalogs = (): [string[], string[]] => {
   const catalogExtensionsArray = useExtensions<CatalogItemType>(isCatalogItemType);

   return useMemo(() => {
     const catalogTypeExtensions = catalogExtensionsArray.map((type) => type.properties.type);

     if (SOFTWARE_CATALOG_TYPES) {
       // ... existing logic ...
     }
-    return [[]];
+    return [[], catalogTypeExtensions];
   }, [catalogExtensionsArray]);
 };

 export const useIsSoftwareCatalogEnabled = (): boolean => {
-  const [disabledSubCatalogs] = useGetAllDisabledSubCatalogs();
-  const catalogExtensionsArray = useExtensions<CatalogItemType>(isCatalogItemType);
-  const catalogTypeExtensions = catalogExtensionsArray.map((type) => {
-    return type.properties.type;
-  });
+  const [disabledSubCatalogs, catalogTypeExtensions] = useGetAllDisabledSubCatalogs();
   // ... rest of logic
 };
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (2)

117-146: Redundant .filter(isNotDisabledType) on line 123.

The itemTypeExtensions array is already filtered by isNotDisabledType in the useResolvedExtensions call on lines 45-53. Filtering again on line 123 is unnecessary and adds a small performance overhead.

♻️ Remove redundant filter
   const catalogTypeExtensions = useMemo<ResolvedExtension<CatalogItemType>[]>(
     () =>
       (catalogType
         ? itemTypeExtensions.filter((e) => e.properties.type === catalogType)
         : itemTypeExtensions
       )
-        .filter(isNotDisabledType)
         .map((e) => {
           const metadataExts = typeMetadataExtensions.filter(
             (em) => e.properties.type === em.properties.type,
           );
           // ... rest unchanged
         }),
-    [catalogType, itemTypeExtensions, typeMetadataExtensions, isNotDisabledType],
+    [catalogType, itemTypeExtensions, typeMetadataExtensions],
   );

148-152: Mutating sort on catalogProviderExtensions outside of useMemo.

This .sort() mutates the array in place, which can cause subtle bugs with React's referential equality checks. While it works because useResolvedExtensions returns a new array on each resolution, wrapping in useMemo with a spread copy would be safer and more idiomatic React.

♻️ Use immutable sort pattern
-  catalogProviderExtensions.sort((a, b) => {
-    const p1 = a.properties.priority ?? 0;
-    const p2 = b.properties.priority ?? 0;
-    return p1 - p2;
-  });
+  const sortedCatalogProviderExtensions = useMemo(
+    () =>
+      [...catalogProviderExtensions].sort((a, b) => {
+        const p1 = a.properties.priority ?? 0;
+        const p2 = b.properties.priority ?? 0;
+        return p1 - p2;
+      }),
+    [catalogProviderExtensions],
+  );

   // Update return to use sortedCatalogProviderExtensions
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between c14b708 and a79f9a7.

📒 Files selected for processing (2)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
  • frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)
frontend/packages/console-dynamic-plugin-sdk/src/extensions/catalog.ts (6)
  • CatalogItemType (7-25)
  • isCatalogItemType (112-114)
  • isCatalogItemTypeMetadata (116-118)
  • CatalogItemProvider (43-58)
  • isCatalogItemProvider (120-122)
  • CatalogItemFilter (62-72)
🔇 Additional comments (8)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (4)

1-13: LGTM on import reorganization.

The switch from useResolvedExtensions to useExtensions aligns with the PR objective of filtering disabled catalog types earlier in the pipeline. The addition of useMemo for memoization is appropriate.


20-45: Constants for scoring look well-structured.

The scoring and priority constants are cleanly organized with as const for type safety. The threshold values are reasonable for the relevance calculation use case.


386-411: Core PR logic: useGetAllDisabledSubCatalogs implementation looks correct.

The hook properly:

  1. Uses useExtensions to get catalog type extensions
  2. Computes disabled sub-catalogs based on server flags
  3. Memoizes the result with proper dependencies

The return type [string[], string[]?] is a bit unconventional (second element is optional), but I see it's consumed correctly downstream.


381-385: Timing concern does not apply here—initialization is safe.

window.SERVER_FLAGS is set via server-side template injection in index.html (window.SERVER_FLAGS = [[ .ServerFlags ]];) as an inline script in the <head>, which executes before any JavaScript modules load. Unlike dynamic flag initialization, this guarantees availability at module evaluation time. The pattern is intentional and correct.

SOFTWARE_CATALOG_TYPES and isCatalogTypeEnabled also handle the missing developerCatalogTypes case consistently: both treat an absent or falsy value as "all catalogs enabled" (the default), and useGetAllDisabledSubCatalogs properly guards access with an if (SOFTWARE_CATALOG_TYPES) check at line 396.

frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (4)

18-18: LGTM on the import.

The useGetAllDisabledSubCatalogs import aligns with the refactored utility function in catalog-utils.tsx.


31-43: Well-designed isNotDisabledType predicate.

The callback is properly memoized with useCallback and handles the edge case where type is undefined (considers it "not disabled"). This is a sensible default that prevents accidentally filtering out extensions that don't specify a type.


45-53: Consistent application of isNotDisabledType across all extension type guards.

All six useResolvedExtensions calls now properly filter out disabled catalog types:

  • CatalogItemType
  • CatalogItemTypeMetadata
  • CatalogItemProvider
  • CatalogItemFilter
  • CatalogCategoriesProvider
  • CatalogItemMetadataProvider

The dependency arrays are correctly updated to include isNotDisabledType. This is the core fix for the PR objective.

Also applies to: 55-65, 67-76, 78-87, 89-102, 104-115


162-174: Return tuple correctly aggregates all resolved states.

The boolean at index 5 properly combines all resolution states, ensuring consumers know when the full extension set is ready. This is important for showing loading states in the UI.

@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch from 567f091 to a57720d Compare January 12, 2026 17:51
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (2)

127-156: Remove debug console.log statements before merging.

These debug logs (lines 129-133, 152-155) will pollute the browser console in production. If observability is needed, consider using the console's structured logging utilities or remove them entirely.

Additionally, line 147 assumes a.name and b.name are always defined. If a catalog item lacks a name, toLowerCase() will throw:

-      return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
+      return (a.name ?? '').toLowerCase().localeCompare((b.name ?? '').toLowerCase());

197-207: Another debug log to remove.

Lines 199-202 contain additional debug logging that should be removed for production.

The cleanup on line 206 stripping relevanceScore and redHatPriority before returning is correct—ensures the returned items match the expected CatalogItem type.

🤖 Fix all issues with AI agents
In
@frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx:
- Around line 381-388: SOFTWARE_CATALOG_TYPES initialization can throw if
window.SERVER_FLAGS.developerCatalogTypes is malformed JSON; wrap the JSON.parse
call in a try/catch around the code that sets SOFTWARE_CATALOG_TYPES
(referencing SOFTWARE_CATALOG_TYPES and
window.SERVER_FLAGS.developerCatalogTypes), catch parse errors, log the error
(e.g., console.error) with context, and fall back to undefined (or an empty safe
value) so module initialization does not crash.
- Around line 390-415: The hook useGetAllDisabledSubCatalogs returns
inconsistent array shapes; change the branch that currently returns two elements
to return a single-element array like the others. Specifically, in the branch
where SOFTWARE_CATALOG_TYPES?.state === CatalogVisibilityState.Disabled and
SOFTWARE_CATALOG_TYPES?.disabled?.length > 0, return
[SOFTWARE_CATALOG_TYPES.disabled] (i.e., only the disabled list) instead of
[SOFTWARE_CATALOG_TYPES.disabled, catalogTypeExtensions], ensuring all code
paths return a single-element array (matching callers that do const
[disabledSubCatalogs] = useGetAllDisabledSubCatalogs()).
🧹 Nitpick comments (3)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (3)

75-90: Consider defensive type coercion for array elements.

While you're checking Array.isArray, individual elements could be non-strings in edge cases (malformed extension data). A safer approach:

-    const keywords = item.tags.map((k) => k.toLowerCase());
+    const keywords = item.tags.map((k) => String(k).toLowerCase());

Same applies to item.attributes.keywords on line 86. Low risk since extensions should be well-typed, but defensive coding prevents runtime surprises.


225-240: Redundant filtering for RELEVANCE case.

When sortOrder === CatalogSortOrder.RELEVANCE, the filtering in lines 227-233 computes filteredItems but then line 240 passes the original items to keywordCompare, which does its own filtering. This means calculateCatalogItemRelevanceScore runs twice per item for the RELEVANCE case.

Consider restructuring to avoid the double computation:

+  // Only pre-filter for ASC/DESC cases; RELEVANCE handles its own filtering
+  if (sortOrder === CatalogSortOrder.RELEVANCE) {
+    return keywordCompare(searchKeyword, items);
+  }
+
   let filteredItems = items;
   if (searchKeyword) {
     const searchTerm = searchKeyword.toLowerCase();
     filteredItems = items.filter((item) => {
       const relevanceScore = calculateCatalogItemRelevanceScore(searchTerm, item);
       return relevanceScore > 0;
     });
   }
 
   switch (sortOrder) {
-    case CatalogSortOrder.RELEVANCE:
-      return keywordCompare(searchKeyword, items);
-
     case CatalogSortOrder.ASC:

417-428: Duplicate useExtensions call—consider returning catalog types from useGetAllDisabledSubCatalogs.

useExtensions<CatalogItemType>(isCatalogItemType) is called both inside useGetAllDisabledSubCatalogs (line 391) and again here (line 419). Since the hook already computes catalogTypeExtensions internally, consider returning it as part of the tuple to avoid the redundant hook call:

-export const useGetAllDisabledSubCatalogs = () => {
+export const useGetAllDisabledSubCatalogs = (): [string[], string[]] => {
   const catalogExtensionsArray = useExtensions<CatalogItemType>(isCatalogItemType);
 
   return useMemo(() => {
     const catalogTypeExtensions = catalogExtensionsArray.map((type) => type.properties.type);
     // ... existing logic, but always return [disabledSubCatalogs, catalogTypeExtensions]

Then update useIsSoftwareCatalogEnabled to destructure both values without calling useExtensions again.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a79f9a7 and a57720d.

📒 Files selected for processing (2)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
  • frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (2)
frontend/packages/console-plugin-sdk/src/api/useExtensions.ts (1)
  • useExtensions (44-90)
frontend/packages/console-dynamic-plugin-sdk/src/extensions/catalog.ts (2)
  • CatalogItemType (7-25)
  • isCatalogItemType (112-114)
🔇 Additional comments (3)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (3)

1-13: LGTM on import changes.

The migration from useResolvedExtensions to useExtensions is appropriate here since you're only interested in the extension list itself, not the loading/error states. The useMemo import aligns with the memoization added downstream.


20-45: Well-organized scoring constants.

Good use of as const for immutability. The tiered scoring hierarchy (title > keyword > description) follows standard search relevance patterns. Consider adding a brief JSDoc comment above these constants explaining their purpose for future maintainers.


108-122: LGTM on Red Hat priority logic.

The regex pattern handles common Red Hat provider name variations, and the fallback from item.attributes?.provider to item.provider correctly handles different catalog item structures.

@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch from a57720d to a330a09 Compare January 12, 2026 17:59
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (1)

145-151: Remove or guard debug console.log statements before merging.

These console.log calls with emoji prefixes (🔍, 📂) are useful during development but will pollute the browser console in production. Even with the eslint-disable comments, shipping debug logging to users degrades the experience and can leak implementation details.

Either remove them entirely or wrap them in a __DEV__ / process.env.NODE_ENV !== 'production' check if you need them for future debugging.

♻️ Proposed fix to conditionally log only in development
 export const keywordCompare = (filterString: string, items: CatalogItem[]): CatalogItem[] => {
-  // eslint-disable-next-line no-console
-  console.log('🔍 Enhanced keywordCompare called:', {
-    filterString,
-    itemCount: items.length,
-    catalogType: items[0]?.type || 'unknown',
-  });
+  if (process.env.NODE_ENV === 'development') {
+    // eslint-disable-next-line no-console
+    console.log('🔍 Enhanced keywordCompare called:', {
+      filterString,
+      itemCount: items.length,
+      catalogType: items[0]?.type || 'unknown',
+    });
+  }

Apply similar changes to the other console.log statements at lines 170-173 and 217-220.

Also applies to: 169-174, 216-221

frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)

148-152: Mutating catalogProviderExtensions array in-place with .sort().

Array.prototype.sort() mutates the original array. Since catalogProviderExtensions comes from useResolvedExtensions, mutating it could cause subtle bugs if the same array reference is used elsewhere or if React's reconciliation relies on reference equality.

🐛 Proposed fix to avoid mutation
-  catalogProviderExtensions.sort((a, b) => {
+  const sortedProviderExtensions = [...catalogProviderExtensions].sort((a, b) => {
     const p1 = a.properties.priority ?? 0;
     const p2 = b.properties.priority ?? 0;
     return p1 - p2;
   });

Then use sortedProviderExtensions in the return statement at line 164.

🧹 Nitpick comments (5)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (4)

243-251: Redundant filtering: sortCatalogItems filters items, then keywordCompare filters again.

When sortOrder === CatalogSortOrder.RELEVANCE, lines 244-251 filter by searchKeyword, but then line 258 passes the original items (not filteredItems) to keywordCompare, which performs its own filtering. This means:

  1. The filtering work at lines 247-250 is discarded for the RELEVANCE case.
  2. The comment on line 257 acknowledges this but it's still wasteful.

Consider restructuring to avoid the double-filter for RELEVANCE, or move the filtering logic to a single place.

♻️ Proposed simplification
 export const sortCatalogItems = (
   items: CatalogItem[],
   sortOrder: CatalogSortOrder = CatalogSortOrder.RELEVANCE,
   searchKeyword = '',
 ): CatalogItem[] => {
   if (!items || items.length === 0) {
     return items;
   }

+  // For RELEVANCE sorting, keywordCompare handles its own filtering
+  if (sortOrder === CatalogSortOrder.RELEVANCE) {
+    return keywordCompare(searchKeyword, items);
+  }
+
   // First, filter items by search keyword if provided
   let filteredItems = items;
   if (searchKeyword) {
     const searchTerm = searchKeyword.toLowerCase();
     filteredItems = items.filter((item) => {
       const relevanceScore = calculateCatalogItemRelevanceScore(searchTerm, item);
       return relevanceScore > 0;
     });
   }

   // Then, sort the filtered items based on the selected sort order
   switch (sortOrder) {
-    case CatalogSortOrder.RELEVANCE:
-      // Use the existing keywordCompare function for relevance-based sorting
-      // Note: keywordCompare handles its own filtering, so we pass the original items
-      return keywordCompare(searchKeyword, items);
-
     case CatalogSortOrder.ASC:
       // Sort alphabetically A-Z
       return [...filteredItems].sort((a, b) => {
         return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
       });

     case CatalogSortOrder.DESC:
       // Sort alphabetically Z-A
       return [...filteredItems].sort((a, b) => {
         return b.name.toLowerCase().localeCompare(a.name.toLowerCase());
       });

     default:
-      // Fallback to relevance sorting
       return keywordCompare(searchKeyword, items);
   }
 };

Also applies to: 254-258


381-393: Excessive optional chaining on a constant that's already checked for truthiness.

After if (SOFTWARE_CATALOG_TYPES) confirms the value is defined, using SOFTWARE_CATALOG_TYPES?.state, SOFTWARE_CATALOG_TYPES?.enabled, etc. is redundant. The optional chaining adds unnecessary runtime checks.

♻️ Proposed cleanup
 export const isCatalogTypeEnabled = (catalogType: string): boolean => {
   if (SOFTWARE_CATALOG_TYPES) {
     if (
-      SOFTWARE_CATALOG_TYPES?.state === CatalogVisibilityState.Enabled &&
-      SOFTWARE_CATALOG_TYPES?.enabled?.length > 0
+      SOFTWARE_CATALOG_TYPES.state === CatalogVisibilityState.Enabled &&
+      SOFTWARE_CATALOG_TYPES.enabled?.length > 0
     ) {
-      return SOFTWARE_CATALOG_TYPES?.enabled.includes(catalogType);
+      return SOFTWARE_CATALOG_TYPES.enabled.includes(catalogType);
     }
-    if (SOFTWARE_CATALOG_TYPES?.state === CatalogVisibilityState.Disabled) {
-      if (SOFTWARE_CATALOG_TYPES?.disabled?.length > 0) {
-        return !SOFTWARE_CATALOG_TYPES?.disabled.includes(catalogType);
+    if (SOFTWARE_CATALOG_TYPES.state === CatalogVisibilityState.Disabled) {
+      if (SOFTWARE_CATALOG_TYPES.disabled?.length > 0) {
+        return !SOFTWARE_CATALOG_TYPES.disabled.includes(catalogType);
       }
       return false;
     }
   }
   return true;
 };

425-437: useIsSoftwareCatalogEnabled calls useExtensions redundantly.

useGetAllDisabledSubCatalogs already calls useExtensions<CatalogItemType>(isCatalogItemType) internally. Then useIsSoftwareCatalogEnabled calls the same hook again at line 427, resulting in duplicate work.

Consider either:

  1. Returning catalogTypeExtensions from useGetAllDisabledSubCatalogs as a second tuple element, or
  2. Extracting the extensions fetch to a shared hook that both consume.
♻️ Proposed refactor to avoid redundant hook calls
-export const useGetAllDisabledSubCatalogs = () => {
+export const useGetAllDisabledSubCatalogs = (): [string[], string[]] => {
   const catalogExtensionsArray = useExtensions<CatalogItemType>(isCatalogItemType);
+  const catalogTypeExtensions = useMemo(
+    () => catalogExtensionsArray.map((type) => type.properties.type),
+    [catalogExtensionsArray],
+  );

   return useMemo(() => {
-    const catalogTypeExtensions = catalogExtensionsArray.map((type) => type.properties.type);
-
     if (SOFTWARE_CATALOG_TYPES) {
       // ... existing logic ...
     }
-    return [[]];
-  }, [catalogExtensionsArray]);
+    return [[], catalogTypeExtensions];
+  }, [catalogTypeExtensions]);
+
+  // Return both disabled catalogs and all catalog types
+  return [disabledSubCatalogs, catalogTypeExtensions];
 };

 export const useIsSoftwareCatalogEnabled = (): boolean => {
-  const [disabledSubCatalogs] = useGetAllDisabledSubCatalogs();
-  const catalogExtensionsArray = useExtensions<CatalogItemType>(isCatalogItemType);
-  const catalogTypeExtensions = catalogExtensionsArray.map((type) => {
-    return type.properties.type;
-  });
+  const [disabledSubCatalogs, catalogTypeExtensions] = useGetAllDisabledSubCatalogs();
   // ... rest unchanged ...
 };

20-36: Remove debug console.log statements from keywordCompare function.

Lines 147–151, 171–174, and 218–221 contain console.log calls in production code. These debugging statements should be removed entirely or gated behind a feature flag. Keeping them increases bundle size and pollutes production logs.

frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)

117-145: Redundant .filter(isNotDisabledType) at line 123—extensions are already filtered.

itemTypeExtensions is already filtered by isNotDisabledType in the useResolvedExtensions callback at line 49. Filtering again at line 123 is unnecessary and adds overhead for each render.

♻️ Proposed fix to remove redundant filter
   const catalogTypeExtensions = useMemo<ResolvedExtension<CatalogItemType>[]>(
     () =>
       (catalogType
         ? itemTypeExtensions.filter((e) => e.properties.type === catalogType)
         : itemTypeExtensions
-      )
-        .filter(isNotDisabledType)
-        .map((e) => {
+      ).map((e) => {
           const metadataExts = typeMetadataExtensions.filter(
             (em) => e.properties.type === em.properties.type,
           );
           // ... rest unchanged
         }),
-    [catalogType, itemTypeExtensions, typeMetadataExtensions, isNotDisabledType],
+    [catalogType, itemTypeExtensions, typeMetadataExtensions],
   );
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a79f9a7 and a330a09.

📒 Files selected for processing (2)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
  • frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx
🔇 Additional comments (4)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (1)

398-423: Hook returns a memoized tuple structure correctly; minor note on return type.

The refactoring to useExtensions and useMemo looks correct. The dependency array properly includes catalogExtensionsArray.

One small observation: returning [disabledSubCatalogs] (a single-element array) as a tuple is a bit unusual. If future consumers only need the array, consider returning it directly. However, if this pattern is intentional for API consistency with other hooks or to allow future expansion, it's acceptable.

frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (3)

31-43: Well-implemented predicate for filtering disabled catalog types.

The isNotDisabledType callback is correctly memoized with useCallback and properly handles the case where type is undefined (returns true, allowing type-less extensions through). The dependency array correctly includes disabledCatalogs.

This directly addresses the PR objective of preventing hooks from running for disabled catalog types.


45-53: Filter predicates correctly integrate isNotDisabledType.

The type guards now properly compose isCatalogItemType / isCatalogItemTypeMetadata with isNotDisabledType and the catalog type filter. The dependency arrays are updated to include isNotDisabledType, ensuring re-evaluation when disabled catalogs change.

Also applies to: 58-65


162-174: Return tuple correctly aggregates all resolved states.

The boolean at line 168-173 properly combines all resolved flags, ensuring consumers know when all extensions are fully loaded. The overall implementation achieves the PR's goal: disabled catalog types are filtered out before extension resolution, preventing their hooks from executing.

@logonoff logonoff force-pushed the OCPBUGS-72585-devfile branch from a330a09 to e0bca65 Compare January 12, 2026 18:55
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (2)

149-230: Remove console.log from shared sorting utilities (too noisy for prod).
These logs will fire on every sort and can flood the console (and any log capture), impacting performance and signal-to-noise. If you need diagnostics, gate behind an explicit debug flag.

Proposed minimal fix
 export const keywordCompare = (filterString: string, items: CatalogItem[]): CatalogItem[] => {
-  // eslint-disable-next-line no-console
-  console.log('🔍 Enhanced keywordCompare called:', {
-    filterString,
-    itemCount: items.length,
-    catalogType: items[0]?.type || 'unknown',
-  });
-
   if (!filterString) {
     // No search term - sort by Red Hat priority and then alphabetically
     const sortedItems = [...items].sort((a, b) => {
       const aPriority = getRedHatPriority(a);
       const bPriority = getRedHatPriority(b);
@@
-    if (sortedItems.length > 0 && sortedItems[0]?.type === 'operator') {
-      // eslint-disable-next-line no-console
-      console.log(
-        `📂 keywordCompare (No Search) - Red Hat Priority Sorting (${sortedItems.length} items)`,
-      );
-    }
-
     return sortedItems;
   }
@@
-  if (sortedItems.length > 0 && sortedItems[0]?.type === 'operator') {
-    // eslint-disable-next-line no-console
-    console.log(
-      `🔍 keywordCompare (Search: "${filterString}") - Relevance Scoring (${sortedItems.length} matches)`,
-    );
-  }
-
   // Remove the added properties before returning
   return sortedItems.map(({ relevanceScore, redHatPriority, ...item }) => item);
 };

432-444: Simplify/strengthen “software catalog enabled” logic (avoid length + stringify compare).
Current logic is brittle with duplicates/unknown types; use set membership: “enabled iff exists at least one catalog type not disabled”.

Proposed fix
 export const useIsSoftwareCatalogEnabled = (): boolean => {
   const [disabledSubCatalogs] = useGetAllDisabledSubCatalogs();
   const catalogExtensionsArray = useExtensions<CatalogItemType>(isCatalogItemType);
-  const catalogTypeExtensions = catalogExtensionsArray.map((type) => {
-    return type.properties.type;
-  });
-  if (disabledSubCatalogs?.length === catalogTypeExtensions?.length) {
-    return (
-      JSON.stringify(disabledSubCatalogs.sort()) !== JSON.stringify(catalogTypeExtensions.sort())
-    );
-  }
-  return true;
+  const catalogTypeExtensions = catalogExtensionsArray.map((type) => type.properties.type);
+
+  // Enabled if there's at least one catalog type that is not disabled.
+  return catalogTypeExtensions.some((t) => !disabledSubCatalogs.includes(t));
 };
🧹 Nitpick comments (4)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (2)

18-43: Good: centralized “disabled type” predicate; watch for predicate churn if disabledCatalogs identity isn’t stable.
If useGetAllDisabledSubCatalogs() returns a fresh array each render, isNotDisabledType will change and force all useResolvedExtensions predicates to be recreated (potentially triggering extra work). Consider ensuring the disabled list is memoized/stable at the source.


117-146: Minor: redundant .filter(isNotDisabledType) (already filtered upstream) + repeated metadata scans.
Given the type-guard predicates already apply isNotDisabledType, the extra filter is likely unnecessary. Also, typeMetadataExtensions.filter(...) inside .map(...) is O(N*M); consider pre-indexing metadata by type if this runs hot.

frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts (1)

2-17: Make the useExtensions mock per-test to avoid cross-test coupling.
Move useExtensionsMock.mockReturnValue(...) into beforeEach (and reset/clear mocks) so future tests can safely override without order-dependence.

Proposed tweak
 const useExtensionsMock = useExtensions as jest.Mock;
-useExtensionsMock.mockReturnValue(mockExtensions);
+beforeEach(() => {
+  useExtensionsMock.mockReset();
+  useExtensionsMock.mockReturnValue(mockExtensions);
+});
 
 beforeEach(() => {
   delete window.SERVER_FLAGS.developerCatalogTypes;
 });
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (1)

26-41: useMemo is undermined by unstable softwareCatalogTypes identity (recomputes every render).
Because getSoftwareCatalogTypes() returns a new object each call, it defeats memoization and can cascade into downstream callback churn (notably in useCatalogExtensions). Suggest memoizing on the raw string value.

Proposed tweak
-const getSoftwareCatalogTypes = (): SoftwareCatalogTypesConfig | undefined => {
-  if (!window.SERVER_FLAGS.developerCatalogTypes) {
+const getSoftwareCatalogTypes = (
+  developerCatalogTypes?: string,
+): SoftwareCatalogTypesConfig | undefined => {
+  if (!developerCatalogTypes) {
     return undefined;
   }
   try {
-    return JSON.parse(window.SERVER_FLAGS.developerCatalogTypes) as SoftwareCatalogTypesConfig;
+    return JSON.parse(developerCatalogTypes) as SoftwareCatalogTypesConfig;
   } catch (e) {
     // eslint-disable-next-line no-console
     console.error('Failed to parse developerCatalogTypes:', e);
     return undefined;
   }
 };
 
 export const useGetAllDisabledSubCatalogs = () => {
   const catalogExtensionsArray = useExtensions<CatalogItemType>(isCatalogItemType);
-  const softwareCatalogTypes = getSoftwareCatalogTypes();
+  const developerCatalogTypes = window.SERVER_FLAGS.developerCatalogTypes;
+  const softwareCatalogTypes = useMemo(
+    () => getSoftwareCatalogTypes(developerCatalogTypes),
+    [developerCatalogTypes],
+  );

Also applies to: 404-430

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a330a09 and e0bca65.

📒 Files selected for processing (3)
  • frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts
  • frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx
  • frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (2)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (1)
  • useGetAllDisabledSubCatalogs (404-430)
frontend/packages/console-dynamic-plugin-sdk/src/extensions/catalog.ts (7)
  • CatalogItemType (7-25)
  • isCatalogItemType (112-114)
  • isCatalogItemTypeMetadata (116-118)
  • CatalogItemProvider (43-58)
  • isCatalogItemProvider (120-122)
  • CatalogItemFilter (62-72)
  • isCatalogItemFilter (124-126)
frontend/packages/console-shared/src/components/catalog/utils/catalog-utils.tsx (3)
frontend/public/module/auth.js (1)
  • window (5-12)
frontend/packages/console-plugin-sdk/src/api/useExtensions.ts (1)
  • useExtensions (44-90)
frontend/packages/console-dynamic-plugin-sdk/src/extensions/catalog.ts (2)
  • CatalogItemType (7-25)
  • isCatalogItemType (112-114)
🔇 Additional comments (2)
frontend/packages/console-shared/src/components/catalog/hooks/useCatalogExtensions.ts (1)

45-115: Correct: exclude disabled types at the extension-selection boundary (prevents providers/filters/metadata hooks from resolving).
This is the right place to cut off execution paths before hooks resolve/run.

frontend/packages/console-shared/src/utils/__tests__/isSubCatalogTypeEnabled.spec.ts (1)

76-120: Good: hook assertions are now executed under testHook (prevents invalid hook usage).

@logonoff
Copy link
Member Author

/retest

1 similar comment
@logonoff
Copy link
Member Author

/retest

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 15, 2026

@logonoff: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-gcp-console e0bca65 link true /test e2e-gcp-console

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. component/dev-console Related to dev-console component/helm Related to helm-plugin component/knative Related to knative-plugin component/olm Related to OLM component/shared Related to console-shared jira/severity-moderate Referenced Jira bug's severity is moderate for the branch this PR is targeting. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants