Skip to content

Commit

Permalink
fix: auto redirect from datasource page to module editor (appsmithorg…
Browse files Browse the repository at this point in the history
…#35164)

## Description
When create datasource is initiated from the API editor by clicking
"Save as datasource", it fixes the redirection back to the API editor
when `Save` is clicked for modules in package editor.

This PR also refactors the usage of typing of `actionRouteInfo` and
introduces `parentEntityId` instead of using `pageId`, `moduleId`,
`workflowId` separately.

This fix also verifies the sanity of
1. API  in apps
2. API in workflows

Fixes appsmithorg#31506

## Automation

/ok-to-test tags="@tag.Datasource,@tag.Sanity"

### 🔍 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/10093685845>
> Commit: 785cbe3
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10093685845&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Datasource,@tag.Sanity`
> Spec:
> <hr>Thu, 25 Jul 2024 12:39:50 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**
- Introduced a new function to retrieve the current module ID, enhancing
state management.
- Added support for handling `parentEntityId` in various data source
sagas.

- **Bug Fixes**
	- Improved type safety for action handling in sagas.

- **Tests**
- Added a new test suite for the `handleDatasourceCreatedSaga` to
validate its behavior upon datasource creation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
ashit-rath authored and MajaharZemoso committed Jul 28, 2024
1 parent 8dc7f96 commit 4661fc3
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 24 deletions.
2 changes: 2 additions & 0 deletions app/client/src/ce/selectors/modulesSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ import type { Module } from "@appsmith/constants/ModuleConstants";
export const getAllModules = (
state: AppState,
): Record<string, Module> | any => {};

export const getCurrentModuleId = (state: AppState) => "";
9 changes: 2 additions & 7 deletions app/client/src/reducers/uiReducers/datasourcePaneReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface DatasourcePaneReduxState {
actionRouteInfo: Partial<{
apiId: string;
datasourceId: string;
pageId: string;
parentEntityId: string;
applicationId: string;
}>;
newDatasource: string;
Expand Down Expand Up @@ -60,12 +60,7 @@ const datasourcePaneReducer = createReducer(initialState, {
}),
[ReduxActionTypes.STORE_AS_DATASOURCE_UPDATE]: (
state: DatasourcePaneReduxState,
action: ReduxAction<{
apiId: string;
datasourceId: string;
pageId: string;
applicationId: string;
}>,
action: ReduxAction<DatasourcePaneReduxState["actionRouteInfo"]>,
) => {
return {
...state,
Expand Down
12 changes: 4 additions & 8 deletions app/client/src/sagas/ApiPaneSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ function* handleActionCreatedSaga(actionPayload: ReduxAction<Action>) {
}
}

function* handleDatasourceCreatedSaga(
export function* handleDatasourceCreatedSaga(
actionPayload: CreateDatasourceSuccessAction,
) {
const plugin: Plugin | undefined = yield select(
Expand All @@ -608,12 +608,8 @@ function* handleDatasourceCreatedSaga(
? application?.defaultPageId
: yield select(getCurrentPageId);

const actionRouteInfo: Partial<{
apiId: string;
datasourceId: string;
pageId: string;
applicationId: string;
}> = yield select(getDatasourceActionRouteInfo);
const actionRouteInfo: ReturnType<typeof getDatasourceActionRouteInfo> =
yield select(getDatasourceActionRouteInfo);

// This will ensure that API if saved as datasource, will get attached with datasource
// once the datasource is saved
Expand Down Expand Up @@ -649,7 +645,7 @@ function* handleDatasourceCreatedSaga(
if (actionRouteInfo && redirect) {
history.push(
apiEditorIdURL({
pageId: actionRouteInfo?.pageId ?? "",
parentEntityId: actionRouteInfo?.parentEntityId ?? "",
apiId: actionRouteInfo.apiId ?? "",
}),
);
Expand Down
14 changes: 6 additions & 8 deletions app/client/src/sagas/DatasourcesSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ import { MAX_DATASOURCE_SUGGESTIONS } from "constants/DatasourceEditorConstants"
import { getFromServerWhenNoPrefetchedResult } from "./helper";
import { executeGoogleApi } from "./loadGoogleApi";
import type { ActionParentEntityTypeInterface } from "@appsmith/entities/Engine/actionHelpers";
import { getCurrentModuleId } from "@appsmith/selectors/modulesSelector";

function* fetchDatasourcesSaga(
action: ReduxAction<
Expand Down Expand Up @@ -1062,12 +1063,8 @@ function* createDatasourceFromFormSaga(
) {
try {
const workspaceId: string = yield select(getCurrentWorkspaceId);
const actionRouteInfo: Partial<{
apiId: string;
datasourceId: string;
pageId: string;
applicationId: string;
}> = yield select(getDatasourceActionRouteInfo);
const actionRouteInfo: ReturnType<typeof getDatasourceActionRouteInfo> =
yield select(getDatasourceActionRouteInfo);
yield call(
checkAndGetPluginFormConfigsSaga,
actionPayload.payload.pluginId,
Expand Down Expand Up @@ -1305,6 +1302,7 @@ function* storeAsDatasourceSaga() {
const { values } = yield select(getFormData, API_EDITOR_FORM_NAME);
const applicationId: string = yield select(getCurrentApplicationId);
const pageId: string | undefined = yield select(getCurrentPageId);
const moduleId: string | undefined = yield select(getCurrentModuleId);
let datasource = get(values, "datasource");
datasource = omit(datasource, ["name"]);
const originalHeaders = get(values, "actionConfiguration.headers", []);
Expand Down Expand Up @@ -1360,9 +1358,9 @@ function* storeAsDatasourceSaga() {
yield put({
type: ReduxActionTypes.STORE_AS_DATASOURCE_UPDATE,
payload: {
pageId,
applicationId,
apiId: values.id,
parentEntityId: pageId || moduleId,
datasourceId: createdDatasource.id,
},
});
Expand Down Expand Up @@ -1404,7 +1402,7 @@ function* updateDatasourceSuccessSaga(action: UpdateDatasourceSuccessAction) {
) {
history.push(
apiEditorIdURL({
pageId: actionRouteInfo.pageId!,
parentEntityId: actionRouteInfo.parentEntityId || "",
apiId: actionRouteInfo.apiId!,
}),
);
Expand Down
90 changes: 89 additions & 1 deletion app/client/src/sagas/__tests__/ApiPaneSagas.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import urlBuilder from "@appsmith/entities/URLRedirect/URLAssembly";
import type { CreateApiActionDefaultsParams } from "entities/Action";
import { createDefaultApiActionPayload } from "sagas/ApiPaneSagas";
import type { Saga } from "redux-saga";
import { runSaga, stdChannel } from "redux-saga";
import {
createDefaultApiActionPayload,
handleDatasourceCreatedSaga,
} from "sagas/ApiPaneSagas";
import { testStore } from "store";
import MockPluginsState, { PluginIDs } from "test/factories/MockPluginsState";
import history from "utils/history";

describe("tests the sagas in ApiPaneSagas", () => {
const inputPayload: CreateApiActionDefaultsParams = {
Expand Down Expand Up @@ -50,3 +60,81 @@ describe("tests the sagas in ApiPaneSagas", () => {
expect(outputPayload?.actionConfiguration.autoGeneratedHeaders).toEqual([]);
});
});

describe("handleDatasourceCreatedSaga", () => {
beforeEach(() => {
jest.resetAllMocks();
});

it("should pass parentEntityId to apiEditorIdURL and redirect to correct url when in app", async () => {
const applicationId = "app-id";
const pageId = "669e868199b66f0d2176fc1d";
const store = testStore({
entities: {
...({} as any),
plugins: MockPluginsState,
},
ui: {
...({} as any),
datasourcePane: {
actionRouteInfo: {
apiId: "api-id",
applicationId,
datasourceId: "ds-id",
parentEntityId: pageId,
},
},
},
});

const dispatched: any[] = [];
const spy = jest.spyOn(history, "push").mockImplementation(jest.fn());
const channel = stdChannel();
const appParams = {
applicationId,
applicationSlug: "app-slug",
ApplicationVersion: "1",
};

const pageParams = [
{
pageId,
pageSlug: "page-slug",
},
];

urlBuilder.updateURLParams(appParams, pageParams);

runSaga(
{
dispatch: (action: any) => {
dispatched.push(action);
channel.put(action);
},
getState: () => store.getState(),
channel,
},
handleDatasourceCreatedSaga as Saga,
{
redirect: true,
payload: {
pluginId: PluginIDs["restapi-plugin"],
},
},
).toPromise();

// Simulate the dispatch of UPDATE_ACTION_SUCCESS action with delay
setTimeout(() => {
channel.put({ type: ReduxActionTypes.UPDATE_ACTION_SUCCESS });
}, 2000);

// Wait for saga to process the action
await new Promise((resolve) => setTimeout(resolve, 3000));

expect(history.push).toHaveBeenCalledWith(
`/app/app-slug/page-slug-${pageId}/edit/api/api-id`,
);

spy.mockReset();
});
});

0 comments on commit 4661fc3

Please sign in to comment.