feat: enhance navigation state handling in PageEntity and saga (#41081)

## Description
<ins>Problem</ins>

Navigation state was not included when dispatching the
navigateToAnotherPage action, causing the invokedBy property to be unset
and leading to flakiness in the cypress spec:

`app/client/cypress/e2e/Regression/ClientSide/IDE/Canvas_Context_Selected_Widgets_spec.js`

<ins>Root cause</ins>

The PageEntity component did not pass navigation state, and the
NavigateActionSaga’s pushToHistory function did not effectively handle
navigation with state, leading to incomplete navigation data.

<ins>Solution</ins>

This PR handles updating the PageEntity component to include navigation
state when dispatching the navigateToAnotherPage action, ensuring the
invokedBy property is set to NavigationMethod.EntityExplorer. It also
refactors the pushToHistory function in the NavigateActionSaga to better
support navigation with state, preserving backward compatibility. The
NavigateToAnotherPagePayload type is updated to make state and query
optional for greater flexibility.

Fixes a regression introduced here:
https://github.com/appsmithorg/appsmith/pull/41074
_or_  
Fixes `Issue URL`
> [!WARNING]  
> _If no issue exists, please create an issue first, and check with the
maintainers if the issue is valid._

## Automation

/ok-to-test tags="@tag.All"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/16065286850>
> Commit: 548dd7e404761c1f7bfcc71ad285843c83caf8b6
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=16065286850&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Fri, 04 Jul 2025 05:06:13 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Improved navigation behavior to include additional context about the
source of navigation within the app.

* **Bug Fixes**
* Enhanced compatibility for navigation actions, ensuring consistent
handling of various navigation payload types.

* **Documentation**
* Added detailed comments to clarify supported navigation patterns and
their handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Rahul Barwal 2025-07-04 10:38:40 +05:30 committed by GitHub
parent ea7bfd09d7
commit ec9d6f756e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 3 deletions

View File

@ -23,6 +23,7 @@ import { EntityItem } from "@appsmith/ads";
import { useNameEditorState } from "IDE/hooks/useNameEditorState"; import { useNameEditorState } from "IDE/hooks/useNameEditorState";
import { useValidateEntityName } from "IDE"; import { useValidateEntityName } from "IDE";
import { noop } from "lodash"; import { noop } from "lodash";
import { NavigationMethod } from "utils/history";
export const PageEntity = ({ export const PageEntity = ({
onClick, onClick,
@ -89,7 +90,14 @@ export const PageEntity = ({
toUrl: navigateToUrl, toUrl: navigateToUrl,
}); });
dispatch(toggleInOnboardingWidgetSelection(true)); dispatch(toggleInOnboardingWidgetSelection(true));
dispatch(navigateToAnotherPage(navigateToUrl)); dispatch(
navigateToAnotherPage({
pageURL: navigateToUrl,
state: {
invokedBy: NavigationMethod.EntityExplorer,
},
}),
);
if (onClick) { if (onClick) {
onClick(); onClick();

View File

@ -114,6 +114,24 @@ export function* navigateToAnyPageInApplication(
yield call(pushToHistory, action.payload); yield call(pushToHistory, action.payload);
} }
/**
* Pushes navigation state to browser history after executing page unload actions.
*
* This function handles three different variants of history.push() calls to maintain
* backward compatibility with existing code patterns:
*
* 1. String payload: Direct path navigation without query or state
* - Uses: history.push(path)
*
* 2. Payload with state but no query: Navigation with state object
* - Uses: history.push(pageURL, state)
*
* 3. Payload with query and/or state: Full navigation with all parameters
* - Uses: history.push({ pathname, search, state })
*
* These variants exist to conform to how the code was working previously and
* ensure consistent behavior across different navigation scenarios.
*/
export function* pushToHistory(payload: NavigateToAnotherPagePayload | Path) { export function* pushToHistory(payload: NavigateToAnotherPagePayload | Path) {
yield put({ yield put({
type: ReduxActionTypes.EXECUTE_PAGE_UNLOAD_ACTIONS, type: ReduxActionTypes.EXECUTE_PAGE_UNLOAD_ACTIONS,
@ -130,6 +148,12 @@ export function* pushToHistory(payload: NavigateToAnotherPagePayload | Path) {
return; return;
} }
if (!payload.query && payload.state) {
history.push(payload.pageURL, payload.state);
return;
}
const historyState: LocationDescriptor<AppsmithLocationState> = { const historyState: LocationDescriptor<AppsmithLocationState> = {
pathname: payload.pageURL, pathname: payload.pageURL,
search: payload.query, search: payload.query,

View File

@ -2,6 +2,6 @@ import type { AppsmithLocationState } from "utils/history";
export interface NavigateToAnotherPagePayload { export interface NavigateToAnotherPagePayload {
pageURL: string; pageURL: string;
query: string; query?: string;
state: AppsmithLocationState; state?: AppsmithLocationState;
} }