Skip to content

CONSOLE-5034: Migrate tile-view-page and value-from-pair to TypeScript#16412

Open
logonoff wants to merge 3 commits intoopenshift:mainfrom
logonoff:CONSOLE-5034-proptypes
Open

CONSOLE-5034: Migrate tile-view-page and value-from-pair to TypeScript#16412
logonoff wants to merge 3 commits intoopenshift:mainfrom
logonoff:CONSOLE-5034-proptypes

Conversation

@logonoff
Copy link
Copy Markdown
Member

@logonoff logonoff commented May 7, 2026

Solution description:

  • tile-view-page: Migrate from JSX to TSX, replace PropTypes/defaultProps TypeScript interfaces and default parameter values. Fix barrel imports (useDebounceCallback, getURLWithParams) to use direct file paths.
  • value-from-pair: Migrate from JSX to TSX, convert ValueFromPair class component to a function component, replace PropTypes with TypeScript interfaces.
  • name-value-editor: Widen onChange value type to PairChangeValue to correctly reflect that ValueFromPair passes RefChangeValue objects.

Test cases:

  • OperatorHub catalog page loads, category tabs filter correctly, keyword search works, and sidebar filters update counts
  • Environment variable editor renders ConfigMap/Secret value-from dropdowns, selecting a resource populates the key dropdown, and values persist
  • Knative event source form SecretKeySelector selects a secret and key correctly
  • Drag-and-drop reordering of environment variable rows still works

Summary by CodeRabbit

  • Refactor
    • Improved type safety and consistency across value-editing and tile/filter views; several components migrated to modern typed functional implementations.
  • Tests
    • Test imports adjusted to match updated component structure (no test behavior changes).
  • Chores
    • Linting note added and dependency listing cleaned up (internal maintenance only).

@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented May 7, 2026

@logonoff: This pull request references CONSOLE-5034 which is a valid jira issue.

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

Details

In response to this:

Analysis / Root cause:
React 19 removes Component.propTypes and Component.defaultProps (deprecated since React 18).
tile-view-page.jsx and value-from-pair.jsx use both. See
CONSOLE-5034.

Solution description:

  • tile-view-page: Migrate from JSX to TSX, replace PropTypes/defaultProps
    with TypeScript interfaces and default parameter values. Fix barrel imports
    (useDebounceCallback, getURLWithParams) to use direct file paths. Replace
    all any with proper types (TileItem, KeywordCompareResult, etc.).
  • value-from-pair: Migrate from JSX to TSX, convert ValueFromPair class
    component to a function component, replace PropTypes with TypeScript interfaces.
    Replace all any with proper types (RefComponentProps, RefChangeValue, etc.).
  • name-value-editor: Widen onChange value type to PairChangeValue to
    correctly reflect that ValueFromPair passes RefChangeValue objects.
  • SecretKeySelector: Use bracket notation for typed RefChangeValue access.

Screenshots / screen recording:
N/A — no visual changes, refactor only.

Test setup:
No special setup required.

Test cases:

  • OperatorHub catalog page loads, category tabs filter correctly, keyword search works, and sidebar filters update counts
  • Environment variable editor renders ConfigMap/Secret value-from dropdowns, selecting a resource populates the key dropdown, and values persist
  • Knative event source form SecretKeySelector selects a secret and key correctly
  • Drag-and-drop reordering of environment variable rows still works

Browser conformance:

  • Chrome
  • Firefox
  • Safari (or Epiphany on Linux)

Additional info:
N/A

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-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 7, 2026
@openshift-ci openshift-ci Bot requested review from rhamilto and spadgett May 7, 2026 21:43
@openshift-ci openshift-ci Bot added the component/core Related to console core functionality label May 7, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 7, 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 the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 7, 2026
@logonoff logonoff force-pushed the CONSOLE-5034-proptypes branch from 793dc6f to 199fb2a Compare May 7, 2026 21:44
@logonoff
Copy link
Copy Markdown
Member Author

logonoff commented May 7, 2026

/label px-approved
/label docs-approved

@openshift-ci openshift-ci Bot added px-approved Signifies that Product Support has signed off on this PR docs-approved Signifies that Docs has signed off on this PR labels May 7, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

📝 Walkthrough

Walkthrough

This PR adds and tightens TypeScript typings across several utility components and updates imports/tests for compatibility. value-from-pair.tsx is rewritten from a class to a typed functional component with new exported types (e.g., ValueFromPairProps, RefChangeValue, PairValue) and typed internal subcomponents. name-value-editor.tsx changes pair change-handler types to accept a union PairChangeValue = string | RefChangeValue and propagates that type through child/parent handlers. tile-view-page.tsx gains comprehensive typed models, typed helper exports (including categorizeItems, updateActiveFilters, getFilterSearchParam) and removes runtime propTypes/defaultProps. Tests and ESLint config imports are adjusted accordingly.

🚥 Pre-merge checks | ✅ 12
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main refactoring effort: migrating two key components (tile-view-page and value-from-pair) from JSX to TypeScript.
Description check ✅ Passed The description covers the solution approach, file-specific changes, and test cases, though it lacks sections for Analysis/Root Cause, Setup, Browser Conformance checklist marks, and Reviewers/Assignees as specified in the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Custom check not applicable. PR contains only frontend TypeScript/JavaScript code tested with Jest, not Go code with Ginkgo tests. Check is designed for Ginkgo test naming; zero Ginkgo tests present.
Test Structure And Quality ✅ Passed Not applicable. PR modifies React/TypeScript frontend, not Go code. Ginkgo test review required by check, but no Ginkgo tests present.
Microshift Test Compatibility ✅ Passed PR contains no new Ginkgo e2e tests—only TypeScript migration of frontend React components with Jest unit tests. The MicroShift compatibility check does not apply.
Single Node Openshift (Sno) Test Compatibility ✅ Passed This PR adds no Ginkgo e2e tests. All changes are frontend TypeScript/React component refactoring with Jest unit tests that don't test cluster topology. SNO compatibility check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed Frontend UI refactoring only—no K8s manifests, operator code, controllers, or scheduling constraints present. Check not applicable to this PR scope.
Ote Binary Stdout Contract ✅ Passed OTE Binary Stdout Contract check is not applicable. PR contains only frontend React/TypeScript refactoring (no Go binaries, test runners, or process-level code).
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR contains zero Ginkgo e2e tests. This is a React/TypeScript frontend component migration PR with no Go test files or Ginkgo syntax. Check is not applicable.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@logonoff logonoff force-pushed the CONSOLE-5034-proptypes branch from 2a75676 to 8ecf6e8 Compare May 7, 2026 21:51
Copy link
Copy Markdown
Contributor

@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: 3

🧹 Nitpick comments (2)
frontend/public/components/utils/tile-view-page.tsx (1)

991-991: 💤 Low value

Minor: Redundant type assertion on ref.

The filterByKeywordInput ref is already typed as RefObject<HTMLInputElement> at declaration (line 659). This cast is unnecessary.

♻️ Suggested simplification
                   <SearchInput
                     data-test="search-operatorhub"
-                    ref={filterByKeywordInput as RefObject<HTMLInputElement>}
+                    ref={filterByKeywordInput}
                     placeholder={t('public~Filter by keyword...')}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/public/components/utils/tile-view-page.tsx` at line 991, Remove the
redundant type assertion on the ref prop: replace the usage of
filterByKeywordInput as RefObject<HTMLInputElement> in the JSX ref attribute
with the already-typed filterByKeywordInput; ensure the declared ref
(filterByKeywordInput) remains typed as RefObject<HTMLInputElement> (from its
declaration around line 659) so no further changes are needed to types.
frontend/public/components/utils/value-from-pair.tsx (1)

92-101: ⚡ Quick win

Narrow pair type to match the object structure the component actually requires.

The current PairValue union (string | number | Record<string, unknown>) is too broad. Line 415 calls Object.keys(pair)[0], and line 424 performs indexed access—both expecting a plain object. Primitives passed here would silently fail (returning null at line 419) instead of being caught at the type level.

The proposed type Record<string, FieldRefData | ResourceFieldRefData | RefValue> aligns perfectly with the component's actual contract: each call site extracts a value (e.g., pair[EnvFromPair.Resource]) that maps to the expected data types for RefComponentProps. This tightening improves early error detection without affecting existing safe callers.

Proposed fix
 export type PairValue = string | number | Record<string, unknown>;
+
+type ValueFromData = Record<string, FieldRefData | ResourceFieldRefData | RefValue>;
 
 export type ValueFromPairProps = {
-  pair: PairValue;
+  pair: ValueFromData;
   configMaps?: K8sItemList;
   secrets?: K8sItemList;
   serviceAccounts?: K8sItemList;
   onChange?: (e: { target: { value: RefChangeValue } }) => void;
   disabled?: boolean;
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/public/components/utils/value-from-pair.tsx` around lines 92 - 101,
The PairValue union is too permissive for ValueFromPairProps: the component uses
Object.keys(pair)[0] and indexed accesses (e.g., pair[EnvFromPair.Resource]) so
primitives can slip through; change the PairValue alias to a Record<string,
FieldRefData | ResourceFieldRefData | RefValue> to reflect the actual object
shape the component expects, update ValueFromPairProps to use this narrowed
PairValue, and ensure any call sites constructing pair conform to those
FieldRefData/ResourceFieldRefData/RefValue types used by RefComponentProps so
TypeScript will catch invalid primitives at compile time.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/public/components/utils/name-value-editor.tsx`:
- Around line 58-67: The parent handlers currently declare the value parameter
as string but child callbacks (handleChangeValueFromPair and
handleChangeResource) pass RefChangeValue, so update the type contract to accept
the full union PairChangeValue; specifically change the onChange handler
signatures used in the parent components (the functions referenced where
PairElementProps.onChange is passed) to accept value: PairChangeValue (string |
RefChangeValue) instead of string, and ensure any downstream uses narrow/handle
the RefChangeValue case (type guards or discriminants) where appropriate; keep
PairElementProps.onChange and the PairChangeValue type as the single source of
truth.

In `@frontend/public/components/utils/tile-view-page.tsx`:
- Around line 533-538: defaultFilters is a module-level object that is being
referenced directly in the component state and then mutated by functions like
updateActiveFilters and clearActiveFilters via _.set, causing state pollution;
fix this by cloning defaultFilters when initializing state (e.g., pass a deep
clone into useState) and ensure updateActiveFilters and clearActiveFilters make
and mutate a deep clone of the current filters (not the original/default object)
before calling setState; also review getAvailableFilters to ensure it returns
clones rather than references to defaultFilters or nested objects so no
mutations leak back to the module-level constant.
- Around line 691-726: getUpdatedState is defined with an empty dependency array
but closes over items, itemsSorter, keywordCompare, and filterGroups causing
stale behavior; update the useCallback deps to include items, itemsSorter,
keywordCompare, and filterGroups so recategorizeItems and getFilterGroupCounts
see current values, and if that introduces re-render loops ensure itemsSorter
and filterGroups are memoized/stable in the parent (e.g., useMemo/useCallback)
to avoid churn.

---

Nitpick comments:
In `@frontend/public/components/utils/tile-view-page.tsx`:
- Line 991: Remove the redundant type assertion on the ref prop: replace the
usage of filterByKeywordInput as RefObject<HTMLInputElement> in the JSX ref
attribute with the already-typed filterByKeywordInput; ensure the declared ref
(filterByKeywordInput) remains typed as RefObject<HTMLInputElement> (from its
declaration around line 659) so no further changes are needed to types.

In `@frontend/public/components/utils/value-from-pair.tsx`:
- Around line 92-101: The PairValue union is too permissive for
ValueFromPairProps: the component uses Object.keys(pair)[0] and indexed accesses
(e.g., pair[EnvFromPair.Resource]) so primitives can slip through; change the
PairValue alias to a Record<string, FieldRefData | ResourceFieldRefData |
RefValue> to reflect the actual object shape the component expects, update
ValueFromPairProps to use this narrowed PairValue, and ensure any call sites
constructing pair conform to those FieldRefData/ResourceFieldRefData/RefValue
types used by RefComponentProps so TypeScript will catch invalid primitives at
compile time.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 998a0bf1-5ef3-438b-a8d4-fa688c5217a7

📥 Commits

Reviewing files that changed from the base of the PR and between 2291108 and 199fb2a.

📒 Files selected for processing (4)
  • frontend/public/components/utils/__tests__/name-value-editor.spec.tsx
  • frontend/public/components/utils/name-value-editor.tsx
  • frontend/public/components/utils/tile-view-page.tsx
  • frontend/public/components/utils/value-from-pair.tsx
📜 Review details
🔇 Additional comments (6)
frontend/public/components/utils/tile-view-page.tsx (5)

45-125: Type definitions look solid for a generic catalog page component.

The flexible TileItem = Record<string, unknown> trades compile-time safety for runtime flexibility, which is a reasonable choice given this component handles various item shapes from different consumers. The function types with optional properties (useScoring, name) are a pragmatic approach for optional behavior.


24-26: Good: Barrel imports replaced with direct file paths.

Moving from @console/shared to direct paths like @console/shared/src/hooks/useDebounceCallback improves tree-shaking and can reduce bundle size by avoiding pulling in the entire barrel.


40-43: Nice use of as const for FilterTypes.

This enables TypeScript to infer literal types ('category' | 'keyword') rather than widening to string, providing better type safety for filter type checks throughout the file.


644-656: Proper React 19 migration: Default parameter values replace defaultProps.

Using inline default values in the destructuring pattern (filterGroupNameMap = {}, emptyStateTitle = '...') is the correct approach for React 19, where defaultProps on function components is removed.


907-909: Standard pattern for typed checkbox event handling.

The (e.target as HTMLInputElement).checked assertion is the typical approach when the click handler's event type doesn't narrow to the input element. Acceptable given PatternFly's FilterSidePanelCategoryItem API.

frontend/public/components/utils/__tests__/name-value-editor.spec.tsx (1)

5-6: Import split looks correct and keeps test typing aligned with the migrated modules.

Comment thread frontend/public/components/utils/name-value-editor.tsx
Comment thread frontend/public/components/utils/tile-view-page.tsx
Comment thread frontend/public/components/utils/tile-view-page.tsx
logonoff and others added 3 commits May 7, 2026 18:01
Replace PropTypes and defaultProps with TypeScript interfaces and
default parameter values. Fix barrel imports for useDebounceCallback
and getURLWithParams to use direct file paths, and remove unused
`shown` prop on VerticalTabs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Convert ValueFromPair from a class component to a function component,
replace PropTypes with TypeScript interfaces, and export
ValueFromPairProps type for consumers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@logonoff logonoff force-pushed the CONSOLE-5034-proptypes branch from 8ecf6e8 to 53bad89 Compare May 7, 2026 22:02
@logonoff
Copy link
Copy Markdown
Member Author

logonoff commented May 7, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
frontend/public/components/utils/value-from-pair.tsx (1)

92-92: ⚡ Quick win

PairValue type is too permissive—reduces TypeScript's value here.

The PairValue = string | number | Record<string, unknown> union accepts primitives that Kubernetes valueFrom fields will never actually be. When you index pair[valueFromKey] at line 424, the result type is unknown, which then gets passed to Component expecting FieldRefData | ResourceFieldRefData | RefValue. This compiles but offers no real type safety.

Consider narrowing to the actual shape:

-export type PairValue = string | number | Record<string, unknown>;
+export type PairValue = Record<string, FieldRefData | ResourceFieldRefData | RefValue>;

This would:

  1. Eliminate impossible primitive cases
  2. Provide accurate typing for pair[valueFromKey] without needing type assertions
  3. Catch misuse at compile time rather than relying on the runtime null guard

If backward compatibility requires accepting primitives from upstream callers, at minimum add a type guard before line 415 to narrow the type explicitly.

Also applies to: 415-424

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/public/components/utils/value-from-pair.tsx` at line 92, PairValue
is too permissive (string | number | Record<string, unknown>) so indexing
pair[valueFromKey] yields unknown while Component expects FieldRefData |
ResourceFieldRefData | RefValue; update the PairValue alias to the concrete
expected shapes (e.g. the specific interfaces used by Component: FieldRefData,
ResourceFieldRefData, RefValue) instead of allowing primitives, or if you must
keep the broader type, add a narrowing type guard immediately before using
pair[valueFromKey] that asserts and refines it to FieldRefData |
ResourceFieldRefData | RefValue so no unsafe type assertions are needed when
passing the value into Component.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@frontend/public/components/utils/value-from-pair.tsx`:
- Line 92: PairValue is too permissive (string | number | Record<string,
unknown>) so indexing pair[valueFromKey] yields unknown while Component expects
FieldRefData | ResourceFieldRefData | RefValue; update the PairValue alias to
the concrete expected shapes (e.g. the specific interfaces used by Component:
FieldRefData, ResourceFieldRefData, RefValue) instead of allowing primitives, or
if you must keep the broader type, add a narrowing type guard immediately before
using pair[valueFromKey] that asserts and refines it to FieldRefData |
ResourceFieldRefData | RefValue so no unsafe type assertions are needed when
passing the value into Component.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 169a7e3a-ab05-4e82-9bd5-606167c8bb00

📥 Commits

Reviewing files that changed from the base of the PR and between 199fb2a and 53bad89.

⛔ Files ignored due to path filters (1)
  • frontend/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • frontend/.eslintrc.js
  • frontend/package.json
  • frontend/public/components/utils/__tests__/name-value-editor.spec.tsx
  • frontend/public/components/utils/name-value-editor.tsx
  • frontend/public/components/utils/tile-view-page.tsx
  • frontend/public/components/utils/value-from-pair.tsx
💤 Files with no reviewable changes (1)
  • frontend/package.json
✅ Files skipped from review due to trivial changes (2)
  • frontend/.eslintrc.js
  • frontend/public/components/utils/tests/name-value-editor.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/public/components/utils/tile-view-page.tsx
  • frontend/public/components/utils/name-value-editor.tsx
📜 Review details
🔇 Additional comments (4)
frontend/public/components/utils/value-from-pair.tsx (4)

119-236: Solid TypeScript migration of NameKeyDropdownPair.

The conversion to a typed FC with explicit NameKeyDropdownPairProps is well done. Good use of useTranslation for i18n, and the default parameter isKeyRef = true cleanly replaces the old defaultProps pattern.


238-370: Clean typed presentational components.

The internal components (FieldRef, ConfigMapSecretKeyRef, ConfigMapSecretRef, ResourceFieldRef) are properly typed with their respective data shapes. PatternFly v6 classes and disabled state modifiers are correctly applied. Good i18n coverage with the translation hook.


372-405: Good component routing map with proper typing.

The keyStringToComponent record cleanly maps Kubernetes valueFrom reference types to their corresponding React components. The routing logic ensures the correct component receives the appropriate data shape.


407-433: Well-structured functional component with proper null safety.

The conversion from class to FC is clean. The optional chaining on onChange?.() at line 429 and the early null return when componentInfo is missing are good defensive patterns. The component correctly delegates to the appropriate sub-component based on the valueFrom key.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 7, 2026

@logonoff: The following tests 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/images 53bad89 link true /test images
ci/prow/e2e-gcp-console 53bad89 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/core Related to console core functionality docs-approved Signifies that Docs has signed off on this PR jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. px-approved Signifies that Product Support has signed off on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants