Skip to content

CONSOLE-4990: Replace history object navigation with useNavigate hook#15959

Open
rhamilto wants to merge 8 commits intoopenshift:mainfrom
rhamilto:CONSOLE-4990-programmatic-navigation
Open

CONSOLE-4990: Replace history object navigation with useNavigate hook#15959
rhamilto wants to merge 8 commits intoopenshift:mainfrom
rhamilto:CONSOLE-4990-programmatic-navigation

Conversation

@rhamilto
Copy link
Member

@rhamilto rhamilto commented Jan 29, 2026

Summary

This PR completes the migration from the deprecated history object to React Router's useNavigate hook across all remaining packages in the OpenShift Console frontend.

Changes

This PR migrates all remaining instances of the deprecated history object to use the useNavigate hook from react-router-dom-v5-compat, except for:

  • public/components/app.tsx (will be handled in CONSOLE-4392)
  • public/components/factory/modal.tsx (will be handled in CONSOLE-5012)

Packages Migrated

  1. console-app

    • Updated navigation patterns to use useNavigate hook
  2. console-shared

    • Updated navigation patterns to use useNavigate hook
    • Updated catalog-utils.tsx to use NavigateFunction type for DRY principles
    • ErrorBoundary fix: Changed from using location.pathname as a key prop (which caused component remounting on every URL change) to passing it as a regular prop and using componentDidUpdate to reset error state only when there's an active error AND the location changes. This prevents unnecessary component remounting during tab navigation.
  3. dev-console

    • ProjectAccess.tsx: Replace history.goBack with navigate(-1)
    • ProjectAccess.spec.tsx: Updated test mocks (removed obsolete history mock, added useNavigate mock)
    • ProjectDetailsPage.tsx: Added NavigateFunction type for consistency
    • ProjectDetailsPage.spec.tsx: Updated to use renderWithProviders utility
    • EditApplication.tsx, ImportForm.tsx: Removed unnecessary return statements before handleRedirect()
    • import-submit-utils.ts: Changed to type-only import for NavigateFunction
  4. knative-plugin

    • DeleteRevisionModalController.tsx: Replace history.push() with navigate()
    • FunctionDetailsPage.tsx: Use generatePath() for safer route parameter interpolation
    • CreateKnatifyPage.tsx: Removed unnecessary return statement before handleRedirect()
  5. helm-plugin

    • Updated navigation patterns to use useNavigate hook
    • HelmReleaseDetailsPage.tsx: Wrapped handleNamespaceChange in useCallback for performance optimization
  6. operator-lifecycle-manager

    • create-catalog-source.tsx: Replace history.goBack with navigate(-1)
    • operator-hub-items.tsx: Replace history.replace with navigate
    • operator-hub-subscribe.tsx: Replace history.push with navigate
    • install-plan.tsx: Replace history.push with navigate
    • uninstall-operator-modal.tsx: Replace history.push with navigate
    • operand-form.tsx: Replace history.push/replace/goBack with navigate equivalents
    • DEPRECATED_operand-form.tsx: Replace history.push/goBack with navigate equivalents
    • subscription.tsx: Replace history.push with navigate
  7. metal3-plugin

    • AddBareMetalHost.tsx: Replace history.push() with navigate()
  8. public/components

    • attach-storage.tsx: Removed unused history: History type definition
  9. console-dynamic-plugin-sdk

    • console-types.ts: Changed to type-only import for To type from React Router
    • Updated release notes with migration guide for history package to React Router types

Code Quality Improvements

Based on PR review feedback:

  • Type-only imports: Changed to import type syntax where appropriate for better TypeScript practices
  • DRY principles: Replaced inline function types with NavigateFunction type for consistency
  • Performance optimization: Added useCallback wrapper for namespace change handlers
  • Safer path construction: Used generatePath() for route parameter interpolation to prevent potential path traversal issues
  • Test improvements: Updated tests to use renderWithProviders utility for better test consistency
  • Code cleanup: Removed unnecessary return statements from void-returning functions

Test Updates

  • Updated ProjectAccess.spec.tsx to remove the obsolete history mock and add proper useNavigate mock
  • Updated ProjectDetailsPage.spec.tsx to use renderWithProviders utility instead of manual MemoryRouter wrapping

Migration Patterns Used

All migrations follow the established patterns:

  • history.push(path)navigate(path)
  • history.replace(path)navigate(path, { replace: true })
  • history.goBack()navigate(-1)
  • Added useNavigate() hook imports from react-router-dom-v5-compat
  • Updated component implementations to use the navigate function
  • Used NavigateFunction type for function parameters
  • Used generatePath() for parameterized routes

Commit Structure

The commits are organized by package for easier review:

  1. CONSOLE-4990: Migrate console-app to useNavigate hook
  2. CONSOLE-4990: Migrate console-shared to useNavigate hook
  3. CONSOLE-4990: Migrate dev-console to useNavigate hook
  4. CONSOLE-4990: Migrate knative-plugin to useNavigate hook
  5. CONSOLE-4990: Migrate helm-plugin to useNavigate hook
  6. CONSOLE-4990: Migrate operator-lifecycle-manager to useNavigate hook
  7. CONSOLE-4990: Migrate remaining packages to useNavigate hook
  8. CONSOLE-4990: Replace history types with React Router types

Bug Fix

Fixed resource tab navigation causing full page reloads (#15959 (comment))

The ErrorBoundary component was using location.pathname as a key prop, which caused the entire component tree to remount whenever the URL changed. This resulted in:

  • Components unmounting and remounting when switching between resource tabs (Details → YAML → Events)
  • Unnecessary data refetching
  • Loss of component state

Solution: Changed to pass locationPathname as a prop and use componentDidUpdate to reset error state only when there's an active error AND the location changes. This preserves the error reset behavior while avoiding unnecessary remounts.

Related Issues

Testing

  • All modified components have been updated to use useNavigate() hook
  • Test files updated to properly mock the new hook
  • No functional changes to navigation behavior
  • All existing navigation patterns preserved
  • ErrorBoundary tests pass with new implementation
  • Code quality improvements applied based on review feedback

Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com

@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 29, 2026
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jan 29, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 29, 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-robot
Copy link
Contributor

openshift-ci-robot commented Jan 29, 2026

@rhamilto: This pull request references CONSOLE-4990 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 "4.22.0" version, but no target version was set.

Details

In response to this:

Summary

Migrates all programmatic navigation from the deprecated history object to the React Router v6/v7 compatible useNavigate hook as part of the React Router v7 upgrade effort.

Epic: CONSOLE-4392 - Upgrade to react-router v7

Related PR: #15956 (Query parameter management migration)

Changes Overview

This PR migrates 54 files across 9 packages, organized into 6 commits by package for easier review.

Migration Pattern

Before:

import { history } from '@console/internal/components/utils/router';

const MyComponent = () => {
 const navigate = () => history.push('/path');
 const goBack = () => history.goBack();
 return <button onClick={navigate}>Navigate</button>;
};

After:

import { useNavigate } from 'react-router-dom-v5-compat';

const MyComponent = () => {
 const navigate = useNavigate();
 const handleNavigate = () => navigate('/path');
 const goBack = () => navigate(-1);
 return <button onClick={handleNavigate}>Navigate</button>;
};

Changes by Package

1. console-app (9 files)

  • cronjob-factory.ts - Converted to dependency injection pattern
  • cronjob-provider.ts - Use navigate in action creator
  • 7 component files - Standard migration pattern

Key Pattern: Dependency injection for action creators

2. console-shared (8 files)

  • error-boundary.tsx - Used key prop pattern for location-based reset
  • catalog-utils.tsx - Utility file with parameter injection
  • 6 component files - Standard migration pattern

Key Patterns:

  • Key prop for class component reset on navigation
  • Parameter injection for utility functions

3. dev-console (17 files)

  • import-submit-utils.ts - Updated to accept NavigateFunction
  • jar-file-upload-utils.ts - Utility with parameter injection
  • add-page-utils.ts - Utility with parameter injection
  • 14 component files - Standard migration pattern

Key Pattern: Dependency injection for shared utility functions

4. knative-plugin (8 files)

  • create-eventsources-utils.ts - Utility with parameter injection
  • 7 component files - Standard migration pattern

5. helm-plugin (5 files)

  • All component files - Standard migration pattern

6. Other packages (6 files)

  • operator-lifecycle-manager (2 files)
  • topology (1 file)
  • shipwright-plugin (1 file)
  • metal3-plugin (1 file)
  • public (1 file)

Replacements Made

  • history.push(path)navigate(path)
  • history.replace(path)navigate(path, { replace: true })
  • history.goBack()navigate(-1)

Testing

  • ✅ TypeScript compilation: 0 errors
  • ✅ ESLint pre-commit hooks: Passing for all commits
  • ✅ No remaining history imports for programmatic navigation
  • ✅ All 54 files successfully migrated

What Remains

The history object export is intentionally kept in router.ts as it's still used by:

  • Router component initialization in app.tsx
  • Monkey-patching for base path handling (removeBasePath)
  • Will be removed in a future PR as part of the final React Router v7 migration

Commit Structure

Each commit is scoped to a single package for easier review:

  1. CONSOLE-4990: Migrate console-app to useNavigate hook
  2. CONSOLE-4990: Migrate console-shared to useNavigate hook
  3. CONSOLE-4990: Migrate dev-console to useNavigate hook
  4. CONSOLE-4990: Migrate knative-plugin to useNavigate hook
  5. CONSOLE-4990: Migrate helm-plugin to useNavigate hook
  6. CONSOLE-4990: Migrate remaining packages to useNavigate hook

Related Issues

Part of CONSOLE-4392 - React Router v7 upgrade epic

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 added the component/core Related to console core functionality label Jan 29, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 29, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: rhamilto

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/dev-console Related to dev-console approved Indicates a PR has been approved by an approver from all required OWNERS files. component/helm Related to helm-plugin component/knative Related to knative-plugin component/metal3 Related to metal3-plugin component/olm Related to OLM component/shared Related to console-shared component/topology Related to topology labels Jan 29, 2026
@rhamilto rhamilto changed the title CONSOLE-4990: Replace history object navigation with useNavigate hook [WIP] CONSOLE-4990: Replace history object navigation with useNavigate hook Jan 29, 2026
@rhamilto rhamilto marked this pull request as ready for review January 29, 2026 19:07
@openshift-ci openshift-ci bot requested review from jhadvig and rawagner January 29, 2026 19:08
@rhamilto rhamilto force-pushed the CONSOLE-4990-programmatic-navigation branch from fab6845 to 4c78f4b Compare January 29, 2026 21:55
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Jan 29, 2026

@rhamilto: This pull request references CONSOLE-4990 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 "4.22.0" version, but no target version was set.

Details

In response to this:

Summary

Migrates all programmatic navigation from the deprecated history object to the React Router v6/v7 compatible useNavigate hook as part of the React Router v7 upgrade effort.

Epic: CONSOLE-4392 - Upgrade to react-router v7

Changes Overview

This PR migrates 81 files across multiple packages, organized into 7 commits by package for easier review.

Migration Patterns

1. Basic Navigation Migration

Before:

import { history } from '@console/internal/components/utils/router';

const MyComponent = () => {
 const navigate = () => history.push('/path');
 const goBack = () => history.goBack();
 return <button onClick={navigate}>Navigate</button>;
};

After:

import { useNavigate } from 'react-router-dom-v5-compat';
import { useCallback } from 'react';

const MyComponent = () => {
 const navigate = useNavigate();
 const handleNavigate = useCallback(() => navigate('/path'), [navigate]);
 const handleCancel = useCallback(() => navigate(-1), [navigate]);
 return <button onClick={handleNavigate}>Navigate</button>;
};

2. Utility Function Pattern (Dependency Injection)

Before:

import { history } from '@console/internal/components/utils/router';

export const navigateToResource = (path: string) => {
 history.push(path);
};

After:

type NavigateFunction = (to: string, options?: { replace?: boolean }) => void;

export const navigateToResource = (path: string, navigate: NavigateFunction) => {
 navigate(path);
};

3. Query Parameter Management

All query parameter mutations now use the new useQueryParamsMutator hook (introduced in the first commit):

const { getQueryArgument, setQueryArgument, removeQueryArgument } = useQueryParamsMutator();

Key Improvements

Performance Optimization: All navigation callbacks properly wrapped in useCallback to prevent unnecessary re-renders
Dependency Injection: Utility functions accept navigate as a parameter for better testability
Type Safety: Proper TypeScript typing with NavigateFunction throughout
Comprehensive Testing: 251 lines of tests for the new useQueryParamsMutator hook

Changes by Commit

1. 9215732b94 - Core Infrastructure Migration

  • New Hook: useQueryParamsMutator with comprehensive API
  • Test Coverage: 251 lines of unit tests
  • Pattern: Functional wrapper for class components (PodLogs)
  • Files: 8 core files including router utilities

2. 0b76e669fc - console-app Migration

  • Files: 12 files
  • Key Pattern: Dependency injection for cronjob-factory
  • New Hook: Foundation for useCronJobActions (completed in commit 7)

3. d39392028f - console-shared Migration

  • Files: 13 files
  • Key Patterns:
  • Key prop for ErrorBoundary reset on navigation
  • Parameter injection for catalog utilities
  • All callbacks properly memoized with useCallback

4. 7ba04a6760 - dev-console Migration

  • Files: 18 files
  • Key Pattern: Dependency injection for import/jar utilities
  • Consistency: All form cancel handlers use useCallback(() => navigate(-1), [navigate])

5. 85e900fdbe - knative-plugin Migration

  • Files: 8 files
  • Key Pattern: Dependency injection for create-eventsources-utils
  • Consistency: All callbacks properly wrapped in useCallback

6. def35a3651 - helm-plugin Migration

  • Files: 5 files
  • Key Pattern: Complex navigation logic with multiple paths
  • Consistency: All callbacks properly wrapped in useCallback

7. 4c78f4b1d0 - Remaining Packages + Advanced Patterns

  • Files: 10 files
  • New Hook: useCronJobActions with excellent design patterns
  • Packages: operator-lifecycle-manager, topology, shipwright, metal3, public
  • Advanced: Refactored operator-hub-items to use useQueryParamsMutator

Replacements Made

  • history.push(path)navigate(path)
  • history.replace(path)navigate(path, { replace: true })
  • history.goBack()navigate(-1)
  • All inline navigation callbacks → wrapped in useCallback with proper dependencies

Code Quality

Consistent Patterns: All 81 files follow the same migration patterns
useCallback Usage: Every navigation callback properly memoized
Dependency Arrays: All callbacks have correct dependency arrays
Type Safety: Proper TypeScript types throughout
Documentation: JSDoc for complex hooks (e.g., useCronJobActions)
Testing: Comprehensive test coverage for new utilities

Testing

  • ✅ TypeScript compilation: 0 errors
  • ✅ ESLint pre-commit hooks: Passing for all commits
  • ✅ All useCallback dependencies validated by react-hooks/exhaustive-deps
  • ✅ Unit tests: 251 lines of comprehensive tests for useQueryParamsMutator
  • ✅ All 81 files successfully migrated

What Remains

The history object export is intentionally kept in router.ts as it's still used by:

  • Router component initialization in app.tsx
  • Monkey-patching for base path handling (removeBasePath)
  • Legacy getQueryArgument function (marked @deprecated, 28+ usages to migrate separately)

These will be removed in future PRs as part of the final React Router v7 migration.

Commit Structure

Each commit is scoped to a package/layer for easier review:

  1. Core Infrastructure: useQueryParamsMutator hook + tests
  2. console-app: Action creators and components
  3. console-shared: Shared utilities and components
  4. dev-console: Developer console package
  5. knative-plugin: Knative serverless plugin
  6. helm-plugin: Helm chart plugin
  7. Remaining packages: operator-lifecycle-manager, topology, shipwright, metal3, public

Review Notes

This migration has been thoroughly reviewed for:

  • ✅ Correct migration patterns
  • ✅ useCallback consistency and correctness
  • ✅ Dependency injection for utilities
  • ✅ Type safety
  • ✅ Performance optimization
  • ✅ Test coverage

Status: Ready for final review and merge

Related Issues

Part of CONSOLE-4392 - React Router v7 upgrade epic

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.

@rhamilto rhamilto changed the title [WIP] CONSOLE-4990: Replace history object navigation with useNavigate hook CONSOLE-4990: Replace history object navigation with useNavigate hook Jan 29, 2026
@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 29, 2026
@rhamilto rhamilto changed the title CONSOLE-4990: Replace history object navigation with useNavigate hook [WIP] CONSOLE-4990: Replace history object navigation with useNavigate hook Jan 29, 2026
@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 29, 2026
@rhamilto rhamilto force-pushed the CONSOLE-4990-programmatic-navigation branch 2 times, most recently from 738897a to b7a45bf Compare January 29, 2026 22:06
@openshift-ci openshift-ci bot added the kind/i18n Indicates issue or PR relates to internationalization or has content that needs to be translated label Jan 29, 2026
@rhamilto rhamilto changed the title [WIP] CONSOLE-4990: Replace history object navigation with useNavigate hook CONSOLE-4990: Replace history object navigation with useNavigate hook Jan 29, 2026
@openshift-ci-robot
Copy link
Contributor

@rhamilto: The /verified command must be used with one of the following actions: by, later, remove, or bypass. See https://docs.ci.openshift.org/docs/architecture/jira/#premerge-verification for more information.

Details

In response to this:

Pushed a test fix.
/verified

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.

@rhamilto
Copy link
Member Author

/verified by @rhamilto

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Feb 11, 2026
@openshift-ci-robot
Copy link
Contributor

@rhamilto: This PR has been marked as verified by @rhamilto.

Details

In response to this:

/verified by @rhamilto

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.

@rhamilto
Copy link
Member Author

/retest

@rhamilto
Copy link
Member Author

tech debt
/label px-approved
/label docs-approved
/assign @jhadvig

@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 Feb 12, 2026
@rhamilto
Copy link
Member Author

/label acknowledge-critical-fixes-only

@openshift-ci openshift-ci bot added the acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. label Feb 17, 2026
Copy link
Member

@logonoff logonoff left a comment

Choose a reason for hiding this comment

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

good stuff! here are a bunch of nitpicks

Comment on lines 21 to 46
## Migration from `history` package to React Router types

Console has migrated from using the `history` package to React Router's native types. This affects
the following public API types:

- `UseDeleteModal` hook's `redirectTo` parameter type has changed from `LocationDescriptor` (from `history`)
to `To` (from `react-router-dom-v5-compat`)

### Migration guide

If your plugin uses the `useDeleteModal` hook and passes a `redirectTo` parameter, update your imports:

```diff
- import { LocationDescriptor } from 'history';
+ import { To } from 'react-router-dom-v5-compat';

const MyComponent = ({ resource }) => {
- const launchDeleteModal = useDeleteModal(resource, redirectTo as LocationDescriptor);
+ const launchDeleteModal = useDeleteModal(resource, redirectTo as To);
// ...
};
```

The `To` type is compatible with the previous `LocationDescriptor` type (accepts strings and location
objects), so most plugins should only need to update their imports.

Copy link
Member

Choose a reason for hiding this comment

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

I'd like to put this in a seperate react-router subsection given we'll likely have other stuff there

Copy link
Member Author

Choose a reason for hiding this comment

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

Once the react-router upgrade is done, we'll add the following and demote the headings being added.

## React Router upgrade

Console has upgraded from react router 5 to 6. As a result, some changes to the plugin API were made. Here is how you upgrade your plugin:

### Migration from `history` package to React Router types
...

Copy link
Member Author

@rhamilto rhamilto left a comment

Choose a reason for hiding this comment

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

Addressed review comments:

Type-only imports (comments #2817764074, #2817781098, #2817782328):

  • Changed to import type { To } in console-types.ts
  • Changed to import type { NavigateFunction } in import-submit-utils.ts
  • Added NavigateFunction type in ProjectDetailsPage.tsx

DRY NavigateFunction type (comments #2817769613, #2817770687):

  • Updated setURLParams and updateURLParams in catalog-utils.tsx to use NavigateFunction type

Remove unnecessary return statements (comments #2817777547, #2817801167, #2817801364):

  • Removed return before handleRedirect() in EditApplication.tsx
  • Removed return before handleRedirect() in ImportForm.tsx
  • Removed return before handleRedirect() in CreateKnatifyPage.tsx

useCallback optimization (comment #2817790079):

  • Wrapped handleNamespaceChange in useCallback in HelmReleaseDetailsPage.tsx

Use renderWithProviders (comment #2817785414):

  • Updated ProjectDetailsPage.spec.tsx to use renderWithProviders utility

Use generatePath (comment #2818935424):

  • Updated FunctionDetailsPage.tsx to use generatePath for safer path construction

All changes have been squashed into their respective commits.

@rhamilto rhamilto force-pushed the CONSOLE-4990-programmatic-navigation branch from 2f4ced5 to 783cf6a Compare February 17, 2026 20:54
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Feb 17, 2026
@openshift-ci-robot
Copy link
Contributor

@rhamilto: This pull request references CONSOLE-4990 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 "4.22.0" version, but no target version was set.

Details

In response to this:

Summary

This PR completes the migration from the deprecated history object to React Router's useNavigate hook across all remaining packages in the OpenShift Console frontend.

Changes

This PR migrates all remaining instances of the deprecated history object to use the useNavigate hook from react-router-dom-v5-compat, except for:

  • public/components/app.tsx (will be handled in CONSOLE-4392)
  • public/components/factory/modal.tsx (will be handled in CONSOLE-5012)

Packages Migrated

  1. console-app
  • Updated navigation patterns to use useNavigate hook
  1. console-shared
  • Updated navigation patterns to use useNavigate hook
  • Updated catalog-utils.tsx to use NavigateFunction type for DRY principles
  • ErrorBoundary fix: Changed from using location.pathname as a key prop (which caused component remounting on every URL change) to passing it as a regular prop and using componentDidUpdate to reset error state only when there's an active error AND the location changes. This prevents unnecessary component remounting during tab navigation.
  1. dev-console
  • ProjectAccess.tsx: Replace history.goBack with navigate(-1)
  • ProjectAccess.spec.tsx: Updated test mocks (removed obsolete history mock, added useNavigate mock)
  • ProjectDetailsPage.tsx: Added NavigateFunction type for consistency
  • ProjectDetailsPage.spec.tsx: Updated to use renderWithProviders utility
  • EditApplication.tsx, ImportForm.tsx: Removed unnecessary return statements before handleRedirect()
  • import-submit-utils.ts: Changed to type-only import for NavigateFunction
  1. knative-plugin
  • DeleteRevisionModalController.tsx: Replace history.push() with navigate()
  • FunctionDetailsPage.tsx: Use generatePath() for safer route parameter interpolation
  • CreateKnatifyPage.tsx: Removed unnecessary return statement before handleRedirect()
  1. helm-plugin
  • Updated navigation patterns to use useNavigate hook
  • HelmReleaseDetailsPage.tsx: Wrapped handleNamespaceChange in useCallback for performance optimization
  1. operator-lifecycle-manager
  • create-catalog-source.tsx: Replace history.goBack with navigate(-1)
  • operator-hub-items.tsx: Replace history.replace with navigate
  • operator-hub-subscribe.tsx: Replace history.push with navigate
  • install-plan.tsx: Replace history.push with navigate
  • uninstall-operator-modal.tsx: Replace history.push with navigate
  • operand-form.tsx: Replace history.push/replace/goBack with navigate equivalents
  • DEPRECATED_operand-form.tsx: Replace history.push/goBack with navigate equivalents
  • subscription.tsx: Replace history.push with navigate
  1. metal3-plugin
  • AddBareMetalHost.tsx: Replace history.push() with navigate()
  1. public/components
  • attach-storage.tsx: Removed unused history: History type definition
  1. console-dynamic-plugin-sdk
  • console-types.ts: Changed to type-only import for To type from React Router
  • Updated release notes with migration guide for history package to React Router types

Code Quality Improvements

Based on PR review feedback:

  • Type-only imports: Changed to import type syntax where appropriate for better TypeScript practices
  • DRY principles: Replaced inline function types with NavigateFunction type for consistency
  • Performance optimization: Added useCallback wrapper for namespace change handlers
  • Safer path construction: Used generatePath() for route parameter interpolation to prevent potential path traversal issues
  • Test improvements: Updated tests to use renderWithProviders utility for better test consistency
  • Code cleanup: Removed unnecessary return statements from void-returning functions

Test Updates

  • Updated ProjectAccess.spec.tsx to remove the obsolete history mock and add proper useNavigate mock
  • Updated ProjectDetailsPage.spec.tsx to use renderWithProviders utility instead of manual MemoryRouter wrapping

Migration Patterns Used

All migrations follow the established patterns:

  • history.push(path)navigate(path)
  • history.replace(path)navigate(path, { replace: true })
  • history.goBack()navigate(-1)
  • Added useNavigate() hook imports from react-router-dom-v5-compat
  • Updated component implementations to use the navigate function
  • Used NavigateFunction type for function parameters
  • Used generatePath() for parameterized routes

Commit Structure

The commits are organized by package for easier review:

  1. CONSOLE-4990: Migrate console-app to useNavigate hook
  2. CONSOLE-4990: Migrate console-shared to useNavigate hook
  3. CONSOLE-4990: Migrate dev-console to useNavigate hook
  4. CONSOLE-4990: Migrate knative-plugin to useNavigate hook
  5. CONSOLE-4990: Migrate helm-plugin to useNavigate hook
  6. CONSOLE-4990: Migrate operator-lifecycle-manager to useNavigate hook
  7. CONSOLE-4990: Migrate remaining packages to useNavigate hook
  8. CONSOLE-4990: Replace history types with React Router types

Bug Fix

Fixed resource tab navigation causing full page reloads (#15959 (comment))

The ErrorBoundary component was using location.pathname as a key prop, which caused the entire component tree to remount whenever the URL changed. This resulted in:

  • Components unmounting and remounting when switching between resource tabs (Details → YAML → Events)
  • Unnecessary data refetching
  • Loss of component state

Solution: Changed to pass locationPathname as a prop and use componentDidUpdate to reset error state only when there's an active error AND the location changes. This preserves the error reset behavior while avoiding unnecessary remounts.

Related Issues

Testing

  • All modified components have been updated to use useNavigate() hook
  • Test files updated to properly mock the new hook
  • No functional changes to navigation behavior
  • All existing navigation patterns preserved
  • ErrorBoundary tests pass with new implementation
  • Code quality improvements applied based on review feedback

Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com

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.

rhamilto and others added 3 commits February 18, 2026 17:11
Replace history object usage with useNavigate hook in console-app package.

Changes:
- cronjob-factory.ts: Converted to dependency injection pattern
- cronjob-provider.ts: Use navigate in action creator
- ClusterConfigurationPage.tsx: Replace history.push with navigate
- Lightspeed.tsx: Replace history.push with navigate
- clone-pvc-modal.tsx: Replace history.push with navigate
- restore-pvc-modal.tsx: Replace history.push with navigate
- PDBForm.tsx: Replace history.push with navigate
- UserPreferencePage.tsx: Replace history.push with navigate
- create-volume-snapshot.tsx: Replace history.push with navigate

All changes:
- Replaced history.push(path) with navigate(path)
- Added useNavigate() hook calls
- Updated imports to use react-router-dom-v5-compat

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace history object usage with useNavigate hook in console-shared package.

Changes:
- ActionMenuItem.tsx: Replace history.push with navigate
- CatalogTile.tsx: Replace history.push with navigate
- CatalogView.tsx: Replace history.push with navigate
- catalog-utils.tsx: Accept NavigateFunction as parameter
- dynamic-form/index.tsx: Replace history.goBack with navigate(-1)
- error-boundary.tsx: Use componentDidUpdate instead of key prop for location-based reset
- DeleteResourceModal.tsx: Replace history.push with navigate
- MultiTabListPage.tsx: Replace history.push with navigate

Migration patterns:
- Components: Added useNavigate() hook
- Utilities: Parameter injection for NavigateFunction
- ErrorBoundary: Pass locationPathname as prop and use componentDidUpdate to reset
  error state only when there's an active error AND location changes. This avoids
  unnecessary component remounting during tab navigation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace history object usage with useNavigate hook in dev-console package.

Changes:
- AddCardItem.tsx: Pass navigate to navigateTo utility
- EditBuildConfig.tsx: Replace history.push with navigate
- EditDeployment.tsx: Replace history.push with navigate
- EditApplication.tsx: Replace history.goBack with navigate(-1)
- AddHealthChecks.tsx: Replace history.push with navigate
- AddHealthChecksForm.tsx: Replace history.goBack with navigate(-1)
- HPAFormikForm.tsx: Replace history.goBack with navigate(-1)
- DeployImage.tsx: Pass navigate to handleRedirect
- ImportForm.tsx: Pass navigate to handleRedirect
- ImportSamplePage.tsx: Pass navigate to handleRedirect
- import-submit-utils.ts: Accept NavigateFunction parameter
- UploadJar.tsx: Replace history.goBack with navigate(-1)
- useUploadJarFormToast.ts: Accept navigate as parameter
- AddServerlessFunction.tsx: Replace history.goBack with navigate(-1)
- jar-file-upload-utils.ts: Accept navigate as parameter
- MonitoringPage.tsx: Replace history.push with navigate
- ProjectDetailsPage.tsx: Replace history.push with navigate
- add-page-utils.ts: Accept navigate as parameter

All utility functions updated to use dependency injection pattern.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@rhamilto rhamilto force-pushed the CONSOLE-4990-programmatic-navigation branch from 783cf6a to 6819723 Compare February 18, 2026 22:16
rhamilto and others added 4 commits February 19, 2026 09:04
Replace history object usage with useNavigate hook in knative-plugin package.

Changes:
- EventSink.tsx: Replace history.goBack with navigate(-1)
- EventSource.tsx: Replace history.goBack with navigate(-1)
- AddBroker.tsx: Replace history.goBack with navigate(-1)
- AddChannel.tsx: Replace history.goBack with navigate(-1)
- Subscribe.tsx: Replace history.push with navigate
- FunctionDetailsPage.tsx: Replace history.push with navigate
- CreateKnatifyPage.tsx: Replace history.goBack with navigate(-1)
- create-eventsources-utils.ts: Accept NavigateFunction parameter

All components updated to use useNavigate() hook.
Utility function updated to use dependency injection pattern.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace history object usage with useNavigate hook in helm-plugin package.

Changes:
- HelmReleaseDetailsPage.tsx: Replace history.push with navigate
- CreateHelmChartRepository.tsx: Replace history.goBack with navigate(-1)
- CreateHelmChartRepositoryPage.tsx: Replace history.push with navigate
- HelmInstallUpgradePage.tsx: Replace history.push/goBack with navigate
- HelmReleaseRollbackPage.tsx: Replace history.push/goBack with navigate

All components updated to use useNavigate() hook from react-router-dom-v5-compat.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace history object usage with useNavigate hook in operator-lifecycle-manager package.

Changes:
- create-catalog-source.tsx: Replace history.goBack with navigate(-1)
- operator-hub-items.tsx: Replace history.replace with navigate
- operator-hub-subscribe.tsx: Replace history.push with navigate
- install-plan.tsx: Replace history.push with navigate
- uninstall-operator-modal.tsx: Replace history.push with navigate
- operand-form.tsx: Replace history.push/replace/goBack with navigate
- DEPRECATED_operand-form.tsx: Replace history.push/goBack with navigate
- subscription.tsx: Replace history.push with navigate

All components updated to use useNavigate() hook from react-router-dom-v5-compat.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace history object usage with useNavigate hook in remaining packages.

Changes:
- topology/ExportViewLogButton.tsx: Replace history.push with navigate
- shipwright-plugin/EditBuild.tsx: Replace history.push/goBack with navigate
- metal3-plugin/AddBareMetalHost.tsx: Replace history.push with navigate
- metal3-plugin/AddBareMetalHostForm.tsx: Replace history.goBack with navigate(-1)
- public/QuickCreate.tsx: Replace history.push with navigate
- public/attach-storage.tsx: Remove unused history type definition

All components updated to use useNavigate() hook from react-router-dom-v5-compat.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@rhamilto rhamilto force-pushed the CONSOLE-4990-programmatic-navigation branch from 6819723 to ee61fdf Compare February 19, 2026 14:05
Replace `LocationDescriptor` and `Location` types from the history
package with `To` and `Location` types from react-router-dom-v5-compat.
This is part of the migration to programmatic navigation using React
Router hooks instead of the history object.

Changes:
- Replace LocationDescriptor with To in console-types.ts (SDK)
- Replace LocationDescriptor with To in delete-modal.tsx
- Replace History.LocationDescriptor with To in LinkStatus.tsx
- Replace Location import in telemetry.ts

Breaking Change: The UseDeleteModal hook's redirectTo parameter type
has changed from LocationDescriptor (history) to To (react-router-dom).
Plugin developers should update their imports accordingly.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@rhamilto rhamilto force-pushed the CONSOLE-4990-programmatic-navigation branch from ee61fdf to 9eab703 Compare February 19, 2026 15:26
Comment on lines +1 to +15
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom-v5-compat';
import { Action } from '@console/dynamic-plugin-sdk';
import { useDeepCompareMemoize } from '@console/dynamic-plugin-sdk/src/utils/k8s/hooks/useDeepCompareMemoize';
import { resourceObjPath } from '@console/internal/components/utils/resource-link';
import { JobModel } from '@console/internal/models';
import {
k8sCreate,
CronJobKind,
JobKind,
referenceFor,
K8sResourceCommon,
} from '@console/internal/module/k8s';
import { CronJobActionCreator } from './types';
Copy link
Member

Choose a reason for hiding this comment

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

@typescript-eslint/consistent-type-imports - use import type

},
};

return k8sCreate(JobModel, reqPayload as K8sResourceCommon);
Copy link
Member

Choose a reason for hiding this comment

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

type assertion doesnt appear needed

Suggested change
return k8sCreate(JobModel, reqPayload as K8sResourceCommon);
return k8sCreate(JobModel, reqPayload);

resource: 'jobs',
name: obj.metadata?.name,
namespace: obj.metadata?.namespace,
verb: 'create' as const,
Copy link
Member

Choose a reason for hiding this comment

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

why is as const needed? do we/should we do this elsewhere?

Comment on lines +81 to +91
const { t } = useTranslation();
const navigate = useNavigate();

const memoizedFilterActions = useDeepCompareMemoize(filterActions);

const factory = useMemo(
() => ({
[CronJobActionCreator.StartJob]: () => ({
id: 'start-job',
label: t('console-app~Start Job'),
cta: () => {
Copy link
Member

Choose a reason for hiding this comment

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

nit

Suggested change
const { t } = useTranslation();
const navigate = useNavigate();
const memoizedFilterActions = useDeepCompareMemoize(filterActions);
const factory = useMemo(
() => ({
[CronJobActionCreator.StartJob]: () => ({
id: 'start-job',
label: t('console-app~Start Job'),
cta: () => {
const { t } = useTranslation('console-app');
const navigate = useNavigate();
const memoizedFilterActions = useDeepCompareMemoize(filterActions);
const factory = useMemo(
() => ({
[CronJobActionCreator.StartJob]: () => ({
id: 'start-job',
label: t('Start Job'),
cta: () => {

Comment on lines +100 to +103
// TODO: Show error in notification in the follow on tech-debt.
// eslint-disable-next-line no-console
console.error('Failed to start a Job.', error);
});
Copy link
Member

Choose a reason for hiding this comment

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

this is already a hook. this doesn't have to be tech debt, we can just use useToast here

Comment on lines -48 to +53
requiredFileExtension.properties.handler(f, namespace);
const path = requiredFileExtension.properties.handler(f, namespace);
if (path) {
navigate(path);
}
Copy link
Member

Choose a reason for hiding this comment

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

does this change any existing behaviour?

}

// Functional wrapper to handle location changes
const ErrorBoundary: FC<ErrorBoundaryProps> = ({ children, FallbackComponent }) => {
Copy link
Member

Choose a reason for hiding this comment

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

this makes locationPathname a prop from a typescript perspective when it is not

Comment on lines +1 to +2
export const jarFileUploadHandler = (file: File, namespace: string): string => {
return `/upload-jar/ns/${namespace}`;
Copy link
Member

Choose a reason for hiding this comment

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

i would like to DRY up this type

Suggested change
export const jarFileUploadHandler = (file: File, namespace: string): string => {
return `/upload-jar/ns/${namespace}`;
import type { FileUploadHandler } from '@console/dynamic-plugin-sdk/src/extensions/file-upload';
export const jarFileUploadHandler: FileUploadHandler = (file, namespace) => {
return `/upload-jar/ns/${namespace}`;

export const MONITORING_ALL_NS_PAGE_URI = '/dev-monitoring/all-namespaces';

const handleNamespaceChange = (newNamespace: string): void => {
const handleNamespaceChange = (newNamespace: string, navigate: (url: string) => void): void => {
Copy link
Member

Choose a reason for hiding this comment

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

nit: use NavigateFunction type here for consistency

Comment on lines +103 to +111
return undefined;
}
return undefined;
} catch {
const resourceActions = knatifyResources(values, appName, true).then(() =>
knatifyResources(values, appName),
);

resourceActions
return resourceActions
Copy link
Member

Choose a reason for hiding this comment

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

why the need for all these returns?

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 19, 2026

@rhamilto: 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 9eab703 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.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 19, 2026
@openshift-merge-robot
Copy link
Contributor

PR needs rebase.

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.

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

Labels

acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. approved Indicates a PR has been approved by an approver from all required OWNERS files. component/core Related to console core functionality component/dev-console Related to dev-console component/helm Related to helm-plugin component/knative Related to knative-plugin component/metal3 Related to metal3-plugin component/olm Related to OLM component/sdk Related to console-plugin-sdk component/shared Related to console-shared component/topology Related to topology 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. kind/i18n Indicates issue or PR relates to internationalization or has content that needs to be translated needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. plugin-api-changed Categorizes a PR as containing plugin API changes 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.

8 participants

Comments