Skip to content

OCPBUGS-85121: Skip redundant navigate() in setPerspective when target matches current URL#16410

Open
logonoff wants to merge 1 commit intoopenshift:mainfrom
logonoff:OCPBUGS-85121-router-perspective
Open

OCPBUGS-85121: Skip redundant navigate() in setPerspective when target matches current URL#16410
logonoff wants to merge 1 commit intoopenshift:mainfrom
logonoff:OCPBUGS-85121-router-perspective

Conversation

@logonoff
Copy link
Copy Markdown
Member

@logonoff logonoff commented May 7, 2026

Closes #16254

Analysis / Root cause:

setActivePerspective() always called navigate() unconditionally, causing redundant page reloads for custom perspective plugins. When the target URL matched the current location, this triggered namespace handler validation loops and visible re-renders.

This also stripped the ?perspective= param in DetectPerspective to prevent it from persisting and re-triggering the effect.

Solution description:

Skip navigate() when the target URL matches the current location

Screenshots / screen recording:

Test setup:

Refer to reproduction steps in linked issue

Test cases:

Ensure reproduction steps in linked issue are no longer reproducible

Summary by CodeRabbit

  • Bug Fixes
    • Improved perspective selection and URL query parameter synchronization.
    • Optimized navigation behavior when switching perspectives.

@openshift-ci-robot openshift-ci-robot added 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 May 7, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

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

  • expected the bug to target the "5.0.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:

Closes #16254

Analysis / Root cause:

setActivePerspective() always called navigate() unconditionally, causing redundant page reloads for custom perspective plugins. When the target URL matched the current location, this triggered namespace handler validation loops and visible re-renders.

This also stripped the ?perspective= param in DetectPerspective to prevent it from persisting and re-triggering the effect, and removed the hardcoded ACM perspective fallback in favor of letting PerspectiveDetector handle first-visit detection generically.

Solution description:

Skip navigate() when the target URL matches the current location

Screenshots / screen recording:

Test setup:

Refer to reproduction steps in linked issue

Test cases:

Ensure reproduction steps in linked issue are no longer reproducible

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 review from Leo6Leo and fsgreco May 7, 2026 17:15
@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
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

📝 Walkthrough

Walkthrough

These changes refactor perspective synchronization logic in the console's perspective detection system. The DetectPerspective component now obtains the router location via useLocation() and reconstructs navigation targets using createPath(), which includes removal of the perspective query parameter. The useValuesForPerspectiveContext hook removes prior ACM-dependent perspective fallback logic, derives perspective solely from active or latest perspective state, imports createPath() for path comparison, and updates navigation to execute only when the proposed destination differs from the current location.

🚥 Pre-merge checks | ✅ 10 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description covers analysis, root cause, and solution but lacks test setup details, test cases, browser conformance, and reviewers—key template sections. Add explicit test cases, browser conformance checks, and designate reviewers as required by the template.
Test Structure And Quality ❓ Inconclusive No result was produced after verification. Marking as INCONCLUSIVE. Re-run the check or adjust instructions to produce a final result.
✅ Passed checks (10 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: skipping redundant navigation when perspective target matches current URL.
Linked Issues check ✅ Passed The code changes implement Option A from the issue—skip navigate() when target URL matches current location—and additionally strip the ?perspective= param to prevent re-triggering.
Out of Scope Changes check ✅ Passed Changes are tightly scoped: perspective navigation logic in useValuesForPerspectiveContext and param cleanup in DetectPerspective. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Stable And Deterministic Test Names ✅ Passed Custom check not applicable. Repository uses Jest (TypeScript), not Ginkgo (Go testing framework). No Go test files exist; PR modifies only TypeScript components.
Microshift Test Compatibility ✅ Passed PR does not add any Ginkgo e2e tests. Changes are frontend React/TypeScript files only. Custom check for e2e test MicroShift compatibility is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests added. PR modifies frontend React/TypeScript perspective navigation components only. Custom check applies exclusively to new Ginkgo e2e test additions, which are absent here.
Topology-Aware Scheduling Compatibility ✅ Passed Not applicable. This PR modifies frontend React/TS components only. Contains no deployment manifests, operator code, controllers, or scheduling constraints.
Ote Binary Stdout Contract ✅ Passed OTE Binary Stdout Contract check is inapplicable: PR modifies only React/TypeScript frontend files, not Go binaries or test infrastructure. No process-level code or OTE concerns present.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Check not applicable: PR modifies only TypeScript/React frontend components, no new Ginkgo e2e tests. The check targets Go test files only.

✏️ 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.

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: 1

🧹 Nitpick comments (4)
frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx (1)

28-30: 💤 Low value

Consider using the useLocation() return value for perspectiveParam computation.

getPerspectiveURLParam reads window.location.search directly while useLocation() is called separately as a subscription trigger. These two sources are synchronised in a browser SPA context, so this is not a bug — but composing them more explicitly avoids any future divergence.

♻️ Suggested refactor
-  const perspectiveParam = getPerspectiveURLParam(perspectiveExtensions);
-  // Subscribe to location changes so perspectiveParam is recalculated on navigation
-  useLocation();
+  const location = useLocation();
+  const perspectiveParam = getPerspectiveURLParam(perspectiveExtensions, location.search);

And update getPerspectiveURLParam accordingly:

-const getPerspectiveURLParam = (perspectives: Perspective[]) => {
-  const perspectiveIDs = perspectives.map(
-    (nextPerspective: Perspective) => nextPerspective.properties.id,
-  );
-  const urlParams = new URLSearchParams(window.location.search);
+const getPerspectiveURLParam = (perspectives: Perspective[], search: string) => {
+  const perspectiveIDs = perspectives.map(
+    (nextPerspective: Perspective) => nextPerspective.properties.id,
+  );
+  const urlParams = new URLSearchParams(search);
   const perspectiveParam = urlParams.get('perspective');
   return perspectiveParam && perspectiveIDs.includes(perspectiveParam) ? perspectiveParam : '';
 };
🤖 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/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx`
around lines 28 - 30, The current code calls useLocation() only as a
subscription trigger while getPerspectiveURLParam reads window.location.search
directly; change this to derive perspectiveParam from the location object
returned by useLocation() so the two are explicitly composed. Specifically, get
the location via const location = useLocation(), pass either location or
location.search into getPerspectiveURLParam (or update getPerspectiveURLParam to
accept a search string), and compute perspectiveParam from that argument instead
of reading window.location; update any call sites to the modified
getPerspectiveURLParam signature (e.g., the perspectiveParam assignment) and
ensure types are adjusted accordingly.
frontend/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts (2)

24-24: 💤 Low value

latestPerspective typing — false in the falsy chain is intentional, but warrants a note.

latestPerspective evaluates to false when loaded is false, because false && (...) short-circuits. The expression activePerspective || latestPerspective || '' then correctly collapses it to ''. This works, though an explicit (loaded && ...) || '' would make the intent clearer and avoid the implicit false-to-'' coercion if the type signature ever widens.

🤖 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/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts`
at line 24, The current expression uses activePerspective || latestPerspective
|| '' where latestPerspective can be false when loaded is false; change it to
explicitly guard by loaded to avoid implicit false-to-empty-string coercion:
replace the assignment to perspective with activePerspective || ((loaded &&
latestPerspective) || '') or equivalently (activePerspective || (loaded &&
latestPerspective) || '') so intent is clear and types remain correct
(referencing variables perspective, activePerspective, latestPerspective, and
loaded).

2-2: Consider using useLocation() for type-safe location handling instead of window.location.

While window.location and react-router's Location type are structurally compatible (both expose pathname, search, hash as strings), they're maintained independently. The codebase consistently uses react-router's useLocation() hook elsewhere (e.g., PerspectiveDetector.tsx, useTabbedTableBreadcrumb.ts). Using useLocation() here would provide better type consistency and clarity about intent—whether the component needs the route location or the actual browser location. If actual browser location is intentional here, consider adding a comment explaining why window.location is preferred over useLocation().

🤖 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/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts`
at line 2, The code imports createPath and useNavigate from 'react-router' but
elsewhere in this file it uses window.location; replace usage of window.location
with react-router's useLocation() for type-safe location handling and import
useLocation from 'react-router' alongside createPath/useNavigate (or if the
intent truly is to read the raw browser URL, add a clarifying comment where
window.location is used). Update the hook usage in the component (e.g., call
useLocation() and use its pathname/search/hash) and remove direct references to
window.location to keep consistency with other modules like
PerspectiveDetector.tsx and useTabbedTableBreadcrumb.ts.
frontend/packages/console-app/src/components/detect-perspective/__tests__/useValuesForPerspectiveContext.spec.ts (1)

28-103: ⚡ Quick win

Add test coverage for the core navigation guard in setPerspective.

The central fix in this PR — skipping navigate() when target === createPath(window.location) — has no unit test coverage at all. Without it, a regression is invisible. Consider adding at least two cases using jest.spyOn or mocking useNavigate:

  1. When target equals the current path → navigate is NOT called.
  2. When target differs from the current path → navigate IS called with the correct value.
🤖 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/packages/console-app/src/components/detect-perspective/__tests__/useValuesForPerspectiveContext.spec.ts`
around lines 28 - 103, Add unit tests covering the navigation guard in
setPerspective: write one test that mocks/window.location and createPath to
return the same string as the target and spies on useNavigate/navigate to assert
navigate is NOT called, and a second test where createPath(window.location)
differs from target and assert navigate IS called with the expected path;
reference setPerspective, createPath, and useNavigate/navigate when locating the
logic to test and use jest.spyOn or a useNavigate mock to observe calls.
🤖 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/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts`:
- Around line 32-35: The current code sets target = next || '/' which navigates
to '/' when next is undefined; change the default so missing next uses the
current location instead: set target to next ?? createPath(window.location) (or
use next ? next : createPath(window.location)) so the existing guard (if (target
!== createPath(window.location)) navigate(target)) will no-op when callers omit
next; update the code around the target assignment in
useValuesForPerspectiveContext to use createPath(window.location) as the
fallback rather than '/'.

---

Nitpick comments:
In
`@frontend/packages/console-app/src/components/detect-perspective/__tests__/useValuesForPerspectiveContext.spec.ts`:
- Around line 28-103: Add unit tests covering the navigation guard in
setPerspective: write one test that mocks/window.location and createPath to
return the same string as the target and spies on useNavigate/navigate to assert
navigate is NOT called, and a second test where createPath(window.location)
differs from target and assert navigate IS called with the expected path;
reference setPerspective, createPath, and useNavigate/navigate when locating the
logic to test and use jest.spyOn or a useNavigate mock to observe calls.

In
`@frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx`:
- Around line 28-30: The current code calls useLocation() only as a subscription
trigger while getPerspectiveURLParam reads window.location.search directly;
change this to derive perspectiveParam from the location object returned by
useLocation() so the two are explicitly composed. Specifically, get the location
via const location = useLocation(), pass either location or location.search into
getPerspectiveURLParam (or update getPerspectiveURLParam to accept a search
string), and compute perspectiveParam from that argument instead of reading
window.location; update any call sites to the modified getPerspectiveURLParam
signature (e.g., the perspectiveParam assignment) and ensure types are adjusted
accordingly.

In
`@frontend/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts`:
- Line 24: The current expression uses activePerspective || latestPerspective ||
'' where latestPerspective can be false when loaded is false; change it to
explicitly guard by loaded to avoid implicit false-to-empty-string coercion:
replace the assignment to perspective with activePerspective || ((loaded &&
latestPerspective) || '') or equivalently (activePerspective || (loaded &&
latestPerspective) || '') so intent is clear and types remain correct
(referencing variables perspective, activePerspective, latestPerspective, and
loaded).
- Line 2: The code imports createPath and useNavigate from 'react-router' but
elsewhere in this file it uses window.location; replace usage of window.location
with react-router's useLocation() for type-safe location handling and import
useLocation from 'react-router' alongside createPath/useNavigate (or if the
intent truly is to read the raw browser URL, add a clarifying comment where
window.location is used). Update the hook usage in the component (e.g., call
useLocation() and use its pathname/search/hash) and remove direct references to
window.location to keep consistency with other modules like
PerspectiveDetector.tsx and useTabbedTableBreadcrumb.ts.
🪄 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: 687f30ba-a6a9-47a4-a20a-5736009b28c9

📥 Commits

Reviewing files that changed from the base of the PR and between 1b45874 and d30067e.

📒 Files selected for processing (3)
  • frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx
  • frontend/packages/console-app/src/components/detect-perspective/__tests__/useValuesForPerspectiveContext.spec.ts
  • frontend/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts
📜 Review details
🔇 Additional comments (1)
frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx (1)

31-39: LGTM — the ?perspective= cleanup and loop-prevention logic are correct.

Stripping the param before passing it as target ensures the one-shot useEffect fire doesn't create a navigation loop: after navigate(target) the new URL lacks ?perspective=, so perspectiveParam evaluates to '' on the next render and the guard perspectiveParam && perspectiveParam !== activePerspective is false.

@logonoff
Copy link
Copy Markdown
Member Author

logonoff commented May 7, 2026

/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 May 7, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@logonoff: This pull request references Jira Issue OCPBUGS-85121, 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 (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)
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.

@logonoff logonoff force-pushed the OCPBUGS-85121-router-perspective branch 6 times, most recently from 33b99a5 to 474fc47 Compare May 7, 2026 17:54
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

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

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

In response to this:

Closes #16254

Analysis / Root cause:

setActivePerspective() always called navigate() unconditionally, causing redundant page reloads for custom perspective plugins. When the target URL matched the current location, this triggered namespace handler validation loops and visible re-renders.

This also stripped the ?perspective= param in DetectPerspective to prevent it from persisting and re-triggering the effect.

Solution description:

Skip navigate() when the target URL matches the current location

Screenshots / screen recording:

Test setup:

Refer to reproduction steps in linked issue

Test cases:

Ensure reproduction steps in linked issue are no longer reproducible

Summary by CodeRabbit

  • Bug Fixes
  • Improved perspective parameter handling during route navigation to ensure the correct perspective is maintained when navigating between pages.
  • Optimized navigation behavior to prevent unnecessary navigation attempts when already at the target route.
  • Adjusted default perspective detection when no user preference is configured.

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

Actionable comments posted: 1

🤖 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/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx`:
- Around line 31-39: The code currently only removes the perspective query when
perspectiveParam !== activePerspective; change the logic to always clear the
'perspective' query when perspectiveParam is present, but only call
setActivePerspective(perspectiveParam, ...) if it differs from
activePerspective. In DetectPerspective.tsx, detect perspectiveParam, construct
params via new URLSearchParams(location.search), params.delete('perspective'),
build search and path with createPath({ ...location, search: search ?
`?${search}` : '' }), and then call setActivePerspective only when
perspectiveParam !== activePerspective; this ensures the ?perspective= param is
removed in all cases while preserving the existing behavior of
setActivePerspective.
🪄 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: 3271d260-c303-41b3-9729-7bfb83927a07

📥 Commits

Reviewing files that changed from the base of the PR and between d30067e and 474fc47.

📒 Files selected for processing (2)
  • frontend/packages/console-app/src/components/detect-perspective/DetectPerspective.tsx
  • frontend/packages/console-app/src/components/detect-perspective/useValuesForPerspectiveContext.ts

…t matches current URL

setActivePerspective() always called navigate() unconditionally, causing
redundant page reloads for custom perspective plugins. When the target URL
matched the current location, this triggered namespace handler validation
loops and visible re-renders. This also stripped the ?perspective= param
in DetectPerspective to prevent it from persisting and re-triggering the
effect.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@logonoff logonoff force-pushed the OCPBUGS-85121-router-perspective branch from 474fc47 to bbd3ece Compare May 7, 2026 19:23
@logonoff
Copy link
Copy Markdown
Member Author

logonoff commented May 7, 2026

https://github.com/coderabbitai review

@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/e2e-gcp-console bbd3ece link true /test e2e-gcp-console
ci/prow/images bbd3ece link true /test images

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

setActivePerspective always triggers navigate(), causing redundant page reloads for custom perspective plugins

2 participants