Skip to content

Commit

Permalink
fix: update newly created queries body with correct widget bindings (a…
Browse files Browse the repository at this point in the history
…ppsmithorg#34248)

## Description
When multiple blocks of the same type are dropped unto the canvas right
after each other, the query body of the newly created query does not
update the binding to the latest version of the widgets.

## Solution
We have gotten the newlyUpdatedQueries from the block API, then we
update the actionConfiguration.body and the jsonPathKeys to match the
updated binding name for the block and implement the action in the local
state.


Fixes appsmithorg#34237

## Automation
/ok-to-test tags="@tag.Widget"

### 🔍 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/9644500854>
> Commit: 562ad23
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=9644500854&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Widget`

<!-- end of auto-generated comment: Cypress test results  -->






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


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

- **New Features**
- Enhanced functionality for saving building block widgets to the store.

- **Tests**
  - Updated and added new test cases for pasting building block widgets.

- **Bug Fixes**
- Fixed issues with the import and usage of action types and selectors
in the building block sagas.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
jacquesikot authored and Shivam-z committed Jul 10, 2024
1 parent ec9c47d commit 3374652
Show file tree
Hide file tree
Showing 11 changed files with 479 additions and 253 deletions.
14 changes: 8 additions & 6 deletions app/client/src/ce/api/ApplicationApi.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import type { ApplicationVersion } from "@appsmith/actions/applicationActions";
import { getSnapShotAPIRoute } from "@appsmith/constants/ApiConstants";
import Api from "api/Api";
import type { ApiResponse } from "api/ApiResponses";
import type { AxiosProgressEvent, AxiosPromise } from "axios";
import type { NavigationSetting, ThemeSetting } from "constants/AppConstants";
import type { AppColorCode } from "constants/DefaultTheme";
import type { EvaluationVersion } from "constants/EvalConstants";
import type { IconNames } from "design-system";
import type { AppLayoutConfig } from "reducers/entityReducers/pageListReducer";
import type { Action, BaseAction } from "entities/Action";
import type { APP_MODE } from "entities/App";
import type { ApplicationVersion } from "@appsmith/actions/applicationActions";
import type { Datasource } from "entities/Datasource";
import type { NavigationSetting, ThemeSetting } from "constants/AppConstants";
import { getSnapShotAPIRoute } from "@appsmith/constants/ApiConstants";
import type {
LayoutSystemTypeConfig,
LayoutSystemTypes,
} from "layoutSystems/types";
import type { BaseAction } from "entities/Action";
import type { EvaluationVersion } from "constants/EvalConstants";
import type { AppLayoutConfig } from "reducers/entityReducers/pageListReducer";

export interface PublishApplicationRequest {
applicationId: string;
Expand Down Expand Up @@ -276,6 +276,8 @@ interface ImportBuildingBlockOnPageActions extends BaseAction {
export interface ImportBuildingBlockToApplicationResponse {
widgetDsl: string;
onPageLoadActions: ImportBuildingBlockOnPageActions[];
newActionList: Action[];
datasourceList: Datasource[];
}

export class ApplicationApi extends Api {
Expand Down
2 changes: 2 additions & 0 deletions app/client/src/ce/constants/ReduxActionConstants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ const ActionTypes = {
DELETE_ACTION_INIT: "DELETE_ACTION_INIT",
SET_DATASOURCE_EDITOR_MODE: "SET_DATASOURCE_EDITOR_MODE",
SET_DATASOURCE_EDITOR_MODE_FLAG: "SET_DATASOURCE_EDITOR_MODE_FLAG",
APPEND_ACTION_AFTER_BUILDING_BLOCK_DROP:
"APPEND_ACTION_AFTER_BUILDING_BLOCK_DROP",
SET_DATASOURCE_COLLAPSIBLE_STATE: "SET_DATASOURCE_COLLAPSIBLE_STATE",
SET_ALL_DATASOURCE_COLLAPSIBLE_STATE: "SET_ALL_DATASOURCE_COLLAPSIBLE_STATE",
DELETE_ACTION_SUCCESS: "DELETE_ACTION_SUCCESS",
Expand Down
6 changes: 6 additions & 0 deletions app/client/src/ce/reducers/entityReducers/actionsReducer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ export const handlers = {
}
});
},
[ReduxActionTypes.APPEND_ACTION_AFTER_BUILDING_BLOCK_DROP]: (
draftMetaState: ActionDataState,
action: ReduxAction<{ data: Action }>,
) => {
return [...draftMetaState, action.payload.data];
},
[ReduxActionTypes.UPDATE_ACTION_PROPERTY]: (
draftMetaState: ActionDataState,
action: ReduxAction<UpdateActionPropertyActionPayload>,
Expand Down
11 changes: 11 additions & 0 deletions app/client/src/sagas/ActionSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,17 @@ export function* updateActionSaga(actionPayload: ReduxAction<{ id: string }>) {
}
}

export function* apiCallToSaveAction(action: Action) {
const response: ApiResponse<Action> = yield call(updateActionAPICall, action);

const isValidResponse: boolean = yield validateResponse(response);
if (isValidResponse) {
yield put(updateActionSuccess({ data: response.data }));
checkAndLogErrorsIfCyclicDependency((response.data as Action).errorReports);
}
return { isValidResponse, response };
}

export function* deleteActionSaga(
actionPayload: ReduxAction<{
id: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,29 +69,34 @@ import ApplicationApi, {
import { getCurrentWorkspaceId } from "@appsmith/selectors/selectedWorkspaceSelectors";
import type { WidgetAddChild } from "actions/pageActions";
import { runAction } from "actions/pluginActionActions";
import { selectWidgetInitAction } from "actions/widgetSelectionActions";
import type { ApiResponse } from "api/ApiResponses";
import type { Template } from "api/TemplatesApi";
import type { Action } from "entities/Action";
import { PluginType } from "entities/Action";
import type { JSCollection } from "entities/JSCollection";
import type { WidgetDraggingUpdateParams } from "layoutSystems/common/canvasArenas/ArenaTypes";
import type { DragDetails } from "reducers/uiReducers/dragResizeReducer";
import { race } from "redux-saga/effects";
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
import { getBuildingBlockDragStartTimestamp } from "selectors/buildingBlocksSelectors";
import {
getCurrentApplicationId,
getJSCollectionById,
} from "selectors/editorSelectors";
import { getTemplatesSelector } from "selectors/templatesSelectors";
import { initiateBuildingBlockDropEvent } from "utils/buildingBlockUtils";
import { saveBuildingBlockWidgetsToStore } from ".";
import {
addNewlyAddedActionsToRedux,
saveBuildingBlockWidgetsToStore,
updateWidgetsNameInNewQueries,
} from ".";
import { addWidgetAndMoveWidgetsSaga } from "../CanvasSagas/DraggingCanvasSagas";
import { validateResponse } from "../ErrorSagas";
import { postPageAdditionSaga } from "../TemplatesSagas";
import { addChildSaga } from "../WidgetAdditionSagas";
import { calculateNewWidgetPosition } from "../WidgetOperationSagas";
import { getDragDetails, getWidgetByName } from "../selectors";
import { selectWidgetInitAction } from "actions/widgetSelectionActions";
import { SelectionRequestType } from "sagas/WidgetSelectUtils";

function* addBuildingBlockActionsToApplication(dragDetails: DragDetails) {
const applicationId: string = yield select(getCurrentApplicationId);
Expand Down Expand Up @@ -225,6 +230,7 @@ export function* loadBuildingBlocksIntoApplication(
left: leftColumn,
},
buildingBlockWidget.widgetId,
response.data.newActionList,
);

const timeTakenToDropWidgetsInSeconds =
Expand Down Expand Up @@ -405,6 +411,7 @@ export function* pasteBuildingBlockWidgetsSaga(
left: number;
},
pastingIntoWidgetId: string,
newActions: Action[] = [],
) {
const {
flexLayers,
Expand Down Expand Up @@ -552,6 +559,13 @@ export function* pasteBuildingBlockWidgetsSaga(
},
);
}
if (oldWidgetName !== newWidgetName) {
newActions = updateWidgetsNameInNewQueries(
oldWidgetName,
newWidgetName,
newActions,
);
}

handleSelfWidgetReferencesDuringBuildingBlockPaste(
widget,
Expand Down Expand Up @@ -691,6 +705,8 @@ export function* pasteBuildingBlockWidgetsSaga(
),
);

yield addNewlyAddedActionsToRedux(newActions);

//calculate the new positions of the reflowed widgets
let reflowedWidgets = getReflowedPositions(
widgets,
Expand Down
75 changes: 74 additions & 1 deletion app/client/src/sagas/BuildingBlockSagas/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import type { ImportBuildingBlockToApplicationResponse } from "@appsmith/api/ApplicationApi";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { getAction } from "@appsmith/selectors/entitiesSelector";
import { flattenDSL } from "@shared/dsl";
import type { WidgetProps } from "@shared/dsl/src/migrate/types";
import type { FlattenedWidgetProps } from "WidgetProvider/constants";
import type { ApiResponse } from "api/ApiResponses";
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
import type { Action } from "entities/Action";
import type { WidgetLayoutPositionInfo } from "layoutSystems/anvil/utils/layouts/widgetPositionUtils";
import type { CopiedWidgetData } from "layoutSystems/anvil/utils/paste/types";
import { getWidgetHierarchy } from "layoutSystems/anvil/utils/paste/utils";
import { all } from "redux-saga/effects";
import { all, call, put, select } from "redux-saga/effects";
import { apiCallToSaveAction } from "sagas/ActionSagas";
import { saveCopiedWidgets } from "utils/storage";

export function* saveBuildingBlockWidgetsToStore(
Expand Down Expand Up @@ -44,3 +48,72 @@ export function* saveBuildingBlockWidgetsToStore(
}),
);
}

export function updateWidgetsNameInNewQueries(
oldWidgetName: string,
newWidgetName: string,
queries: Action[],
) {
if (!oldWidgetName || !newWidgetName || !queries) {
throw new Error(
"Invalid input: oldWidgetName, newWidgetName, or queries are missing or empty",
);
}

if (typeof oldWidgetName !== "string" || typeof newWidgetName !== "string") {
throw new Error(
"Invalid input: oldWidgetName and newWidgetName must be strings",
);
}

if (!Array.isArray(queries)) {
throw new Error("Invalid input: queries must be an array");
}

return queries
.filter((query) => !!query)
.map((query) => {
if (!query.actionConfiguration.body || !query.jsonPathKeys) {
return query;
}
query.actionConfiguration.body =
query.actionConfiguration.body.replaceAll(oldWidgetName, newWidgetName);
query.jsonPathKeys = query.jsonPathKeys.map((path: string) =>
path.replaceAll(oldWidgetName, newWidgetName),
);
return query;
});
}

// new actions needed after the drop of a block need to be added to the redux local state
export function* addNewlyAddedActionsToRedux(actions: Action[]) {
for (const action of actions) {
if (!action) {
continue;
}

const existingAction: Action = yield select(getAction, action.id);
if (existingAction) {
continue;
}

try {
const actionDataPayload = {
isLoading: false,
config: action,
data: undefined,
};

yield put({
type: ReduxActionTypes.APPEND_ACTION_AFTER_BUILDING_BLOCK_DROP,
payload: {
data: actionDataPayload,
},
});

yield call(apiCallToSaveAction, action);
} catch (error) {
throw new Error("Error adding new action to Redux");
}
}
}
Loading

0 comments on commit 3374652

Please sign in to comment.