diff --git a/app/client/src/actions/jsPaneActions.ts b/app/client/src/actions/jsPaneActions.ts index 2eab41195988..fc35a64edeb3 100644 --- a/app/client/src/actions/jsPaneActions.ts +++ b/app/client/src/actions/jsPaneActions.ts @@ -24,14 +24,6 @@ export const createNewJSCollection = ( payload: { pageId, from, functionName }, }); -export const updateJSCollection = ( - body: string, - id: string, -): ReduxAction<{ body: string; id: string }> => ({ - type: ReduxActionTypes.UPDATE_JS_ACTION_INIT, - payload: { body, id }, -}); - export const updateJSCollectionBody = ( body: string, id: string, @@ -57,6 +49,13 @@ export const updateJSCollectionBodySuccess = (payload: { }; }; +export const jsSaveActionStart = (payload: { id: string }) => { + return { + type: ReduxActionTypes.JS_ACTION_SAVE_START, + payload, + }; +}; + export const refactorJSCollectionAction = (payload: { refactorAction: RefactorAction; actionCollection: JSCollection; @@ -67,6 +66,13 @@ export const refactorJSCollectionAction = (payload: { }; }; +export const jsSaveActionComplete = (payload: { id: string }) => { + return { + type: ReduxActionTypes.JS_ACTION_SAVE_COMPLETE, + payload, + }; +}; + export const executeJSFunctionInit = (payload: { collection: JSCollection; action: JSAction; diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index 6d8aaf340ae7..8b9b26f49580 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -592,8 +592,9 @@ const ActionTypes = { DELETE_JS_ACTION_INIT: "DELETE_JS_ACTION_INIT", DELETE_JS_ACTION_SUCCESS: "DELETE_JS_ACTION_SUCCESS", PARSE_UPDATE_JS_ACTION: "PARSE_UPDATE_JS_ACTION", - UPDATE_JS_ACTION_INIT: "UPDATE_JS_ACTION_INIT", UPDATE_JS_ACTION_SUCCESS: "UPDATE_JS_ACTION_SUCCESS", + JS_ACTION_SAVE_START: "JS_ACTION_SAVE_START", + JS_ACTION_SAVE_COMPLETE: "JS_ACTION_SAVE_COMPLETE", EXECUTE_COMMAND: "EXECUTE_COMMAND", SAVE_JS_COLLECTION_NAME_INIT: "SAVE_JS_COLLECTION_NAME_INIT", FETCH_JS_ACTIONS_FOR_PAGE_INIT: "FETCH_JS_ACTIONS_FOR_PAGE_INIT", diff --git a/app/client/src/ce/selectors/entitiesSelector.ts b/app/client/src/ce/selectors/entitiesSelector.ts index d827a61899c7..a42257098b0f 100644 --- a/app/client/src/ce/selectors/entitiesSelector.ts +++ b/app/client/src/ce/selectors/entitiesSelector.ts @@ -796,7 +796,8 @@ export function getPageNameByPageId(state: AppState, pageId: string): string { } const getQueryPaneSavingMap = (state: AppState) => state.ui.queryPane.isSaving; -const getApiPaneSavingMap = (state: AppState) => state.ui.apiPane.isSaving; +export const getApiPaneSavingMap = (state: AppState) => + state.ui.apiPane.isSaving; const getActionDirtyState = (state: AppState) => state.ui.apiPane.isDirty; export const isActionSaving = (id: string) => diff --git a/app/client/src/reducers/uiReducers/jsPaneReducer.ts b/app/client/src/reducers/uiReducers/jsPaneReducer.ts index 0403411d87b6..b6cae9c6bda2 100644 --- a/app/client/src/reducers/uiReducers/jsPaneReducer.ts +++ b/app/client/src/reducers/uiReducers/jsPaneReducer.ts @@ -72,7 +72,7 @@ const jsPaneReducer = createReducer(initialState, { ...state, isCreating: false, }), - [ReduxActionTypes.UPDATE_JS_ACTION_INIT]: ( + [ReduxActionTypes.JS_ACTION_SAVE_START]: ( state: JsPaneReduxState, action: ReduxAction<{ id: string }>, ) => ({ @@ -82,38 +82,18 @@ const jsPaneReducer = createReducer(initialState, { [action.payload.id]: true, }, }), - [ReduxActionTypes.UPDATE_JS_ACTION_BODY_INIT]: ( + [ReduxActionTypes.JS_ACTION_SAVE_COMPLETE]: ( state: JsPaneReduxState, action: ReduxAction<{ id: string }>, ) => ({ ...state, isSaving: { ...state.isSaving, - [action.payload.id]: true, - }, - }), - [ReduxActionTypes.UPDATE_JS_ACTION_SUCCESS]: ( - state: JsPaneReduxState, - action: ReduxAction<{ data: JSCollection }>, - ) => ({ - ...state, - isSaving: { - ...state.isSaving, - [action.payload.data.id]: false, + [action.payload.id]: false, }, isDirty: { ...state.isDirty, - [action.payload.data.id]: false, - }, - }), - [ReduxActionTypes.UPDATE_JS_ACTION_BODY_SUCCESS]: ( - state: JsPaneReduxState, - action: ReduxAction<{ data: JSCollection }>, - ) => ({ - ...state, - isSaving: { - ...state.isSaving, - [action.payload.data.id]: false, + [action.payload.id]: false, }, }), [ReduxActionErrorTypes.UPDATE_JS_ACTION_BODY_ERROR]: ( @@ -126,21 +106,6 @@ const jsPaneReducer = createReducer(initialState, { [action.payload.data.id]: false, }, }), - [ReduxActionTypes.REFACTOR_JS_ACTION_NAME_SUCCESS]: ( - state: JsPaneReduxState, - action: ReduxAction<{ collectionId: string }>, - ) => ({ - ...state, - isSaving: { - ...state.isSaving, - [action.payload.collectionId]: false, - }, - isDirty: { - ...state.isDirty, - [action.payload.collectionId]: false, - }, - }), - [ReduxActionErrorTypes.UPDATE_JS_ACTION_ERROR]: ( state: JsPaneReduxState, action: ReduxAction<{ data: JSCollection }>, diff --git a/app/client/src/sagas/ActionSagas.ts b/app/client/src/sagas/ActionSagas.ts index 48aa5cfc2e37..23b41bef42be 100644 --- a/app/client/src/sagas/ActionSagas.ts +++ b/app/client/src/sagas/ActionSagas.ts @@ -1121,7 +1121,7 @@ function* updateEntitySavingStatus() { yield race([ take(ReduxActionTypes.UPDATE_ACTION_SUCCESS), take(ReduxActionTypes.SAVE_PAGE_SUCCESS), - take(ReduxActionTypes.UPDATE_JS_ACTION_BODY_SUCCESS), + take(ReduxActionTypes.EXECUTE_JS_UPDATES), ]); yield put({ diff --git a/app/client/src/sagas/JSPaneSagas.ts b/app/client/src/sagas/JSPaneSagas.ts index c157024a1c7a..f8fb06a013d6 100644 --- a/app/client/src/sagas/JSPaneSagas.ts +++ b/app/client/src/sagas/JSPaneSagas.ts @@ -15,6 +15,7 @@ import { } from "@appsmith/constants/ReduxActionConstants"; import { getCurrentApplicationId, + getCurrentLayoutId, getCurrentPageId, getIsSavingEntity, } from "selectors/editorSelectors"; @@ -50,12 +51,13 @@ import JSActionAPI from "@appsmith/api/JSActionAPI"; import ActionAPI from "api/ActionAPI"; import { updateJSCollectionSuccess, - refactorJSCollectionAction, updateJSCollectionBodySuccess, updateJSFunction, executeJSFunctionInit, setJsPaneDebuggerState, createNewJSCollection, + jsSaveActionComplete, + jsSaveActionStart, } from "actions/jsPaneActions"; import { getCurrentWorkspaceId } from "@appsmith/selectors/selectedWorkspaceSelectors"; import { getPluginIdOfPackageName } from "sagas/selectors"; @@ -75,8 +77,6 @@ import { PLATFORM_ERROR, } from "@appsmith/entities/AppsmithConsole/utils"; import LOG_TYPE from "entities/AppsmithConsole/logtype"; -import type { FetchPageRequest, FetchPageResponse } from "api/PageApi"; -import PageApi from "api/PageApi"; import { updateCanvasWithDSL } from "@appsmith/sagas/PageSagas"; import { set } from "lodash"; import { updateReplayEntity } from "actions/pageActions"; @@ -208,18 +208,17 @@ function* handleEachUpdateJSCollection(update: JSUpdate) { const data = getDifferenceInJSCollection(parsedBody, jsAction); if (data.nameChangedActions.length) { for (let i = 0; i < data.nameChangedActions.length; i++) { - yield put( - refactorJSCollectionAction({ - refactorAction: { - actionId: data.nameChangedActions[i].id, - collectionName: jsAction.name, - pageId: data.nameChangedActions[i].pageId, - moduleId: data.nameChangedActions[i].moduleId, - oldName: data.nameChangedActions[i].oldName, - newName: data.nameChangedActions[i].newName, - }, - actionCollection: jsActionTobeUpdated, - }), + yield call( + handleRefactorJSActionNameSaga, + { + actionId: data.nameChangedActions[i].id, + collectionName: jsAction.name, + pageId: data.nameChangedActions[i].pageId, + moduleId: data.nameChangedActions[i].moduleId, + oldName: data.nameChangedActions[i].oldName, + newName: data.nameChangedActions[i].newName, + }, + jsActionTobeUpdated, ); } } else { @@ -293,11 +292,23 @@ export function* makeUpdateJSCollection( ) { const jsUpdates: Record = action.payload || {}; + yield all( + Object.keys(jsUpdates).map((key) => + put(jsSaveActionStart({ id: jsUpdates[key].id })), + ), + ); + yield all( Object.keys(jsUpdates).map((key) => call(handleEachUpdateJSCollection, jsUpdates[key]), ), ); + + yield all( + Object.keys(jsUpdates).map((key) => + put(jsSaveActionComplete({ id: jsUpdates[key].id })), + ), + ); } function* updateJSCollection(data: { @@ -626,60 +637,49 @@ function* handleUpdateJSCollectionBody( } function* handleRefactorJSActionNameSaga( - data: ReduxAction<{ - refactorAction: RefactorAction; - actionCollection: JSCollection; - }>, + refactorAction: RefactorAction, + actionCollection: JSCollection, ) { - const { pageId } = data.payload.refactorAction; - if (!pageId) { + const { pageId } = refactorAction; + const layoutId: string | undefined = yield select(getCurrentLayoutId); + if (!pageId || !layoutId) { return; } - const params: FetchPageRequest = { - id: data.payload.refactorAction.pageId || "", - migrateDSL: true, + const requestData = { + ...refactorAction, + layoutId, + actionCollection: actionCollection, }; - const pageResponse: FetchPageResponse = yield call(PageApi.fetchPage, params); - const isPageRequestSuccessful: boolean = yield validateResponse(pageResponse); - if (isPageRequestSuccessful) { - // get the layoutId from the page response - const layoutId = pageResponse.data.layouts[0].id; - const requestData = { - ...data.payload.refactorAction, - layoutId: layoutId, - actionCollection: data.payload.actionCollection, - }; - // call to refactor action - try { - const refactorResponse: ApiResponse = - yield JSActionAPI.updateJSCollectionActionRefactor(requestData); + // call to refactor action + try { + const refactorResponse: ApiResponse = + yield JSActionAPI.updateJSCollectionActionRefactor(requestData); - const isRefactorSuccessful: boolean = - yield validateResponse(refactorResponse); + const isRefactorSuccessful: boolean = + yield validateResponse(refactorResponse); - const currentPageId: string | undefined = yield select(getCurrentPageId); + const currentPageId: string | undefined = yield select(getCurrentPageId); - if (isRefactorSuccessful) { - yield put({ - type: ReduxActionTypes.REFACTOR_JS_ACTION_NAME_SUCCESS, - payload: { collectionId: data.payload.actionCollection.id }, - }); - if (currentPageId === data.payload.refactorAction.pageId) { - yield updateCanvasWithDSL( - // @ts-expect-error: response is of type unknown - refactorResponse.data, - data.payload.refactorAction.pageId, - layoutId, - ); - } - } - } catch (error) { + if (isRefactorSuccessful) { yield put({ - type: ReduxActionErrorTypes.REFACTOR_JS_ACTION_NAME_ERROR, - payload: { collectionId: data.payload.actionCollection.id }, + type: ReduxActionTypes.REFACTOR_JS_ACTION_NAME_SUCCESS, + payload: { collectionId: actionCollection.id }, }); + if (currentPageId === refactorAction.pageId) { + yield updateCanvasWithDSL( + // @ts-expect-error: response is of type unknown + refactorResponse.data, + refactorAction.pageId, + layoutId, + ); + } } + } catch (error) { + yield put({ + type: ReduxActionErrorTypes.REFACTOR_JS_ACTION_NAME_ERROR, + payload: { collectionId: actionCollection.id }, + }); } } @@ -825,10 +825,6 @@ export default function* root() { ReduxActionTypes.START_EXECUTE_JS_FUNCTION, handleStartExecuteJSFunctionSaga, ), - takeEvery( - ReduxActionTypes.REFACTOR_JS_ACTION_NAME, - handleRefactorJSActionNameSaga, - ), debounce( 100, ReduxActionTypes.UPDATE_JS_ACTION_BODY_INIT, diff --git a/app/client/src/selectors/editorSelectors.tsx b/app/client/src/selectors/editorSelectors.tsx index ec497749cf32..1456b89c007f 100644 --- a/app/client/src/selectors/editorSelectors.tsx +++ b/app/client/src/selectors/editorSelectors.tsx @@ -30,6 +30,7 @@ import type { MainCanvasReduxState } from "reducers/uiReducers/mainCanvasReducer import { getActions, + getApiPaneSavingMap, getCanvasWidgets, getJSCollections, } from "@appsmith/selectors/entitiesSelector"; @@ -73,33 +74,40 @@ export const getIsFetchingPage = (state: AppState) => export const getLoadingError = (state: AppState) => state.ui.editor.loadingStates.loadingError; -export const getIsPageSaving = (state: AppState) => { - let areApisSaving = false; - let areJsObjectsSaving = false; - - const savingApis = state.ui.apiPane.isSaving; - const savingJSObjects = state.ui.jsPane.isSaving; - const isSavingAppTheme = state.ui.appTheming.isSaving; - const isSavingNavigationSetting = - state.ui.applications.isSavingNavigationSetting; - - Object.keys(savingApis).forEach((apiId) => { - areApisSaving = savingApis[apiId] || areApisSaving; - }); - - Object.keys(savingJSObjects).forEach((collectionId) => { - areJsObjectsSaving = savingJSObjects[collectionId] || areJsObjectsSaving; - }); +export const getIsPageSaving = createSelector( + [ + getApiPaneSavingMap, + (state: AppState) => state.ui.jsPane.isSaving, + (state: AppState) => state.ui.appTheming.isSaving, + (state: AppState) => state.ui.applications.isSavingNavigationSetting, + (state: AppState) => state.ui.editor.loadingStates.savingEntity, + (state: AppState) => state.ui.editor.loadingStates.saving, + ], + ( + savingApis, + savingJSObjects, + isSavingAppTheme, + isSavingNavigationSetting, + isEditorSavingEntity, + isEditorSaving, + ) => { + const areApisSaving = Object.keys(savingApis).some( + (apiId) => savingApis[apiId], + ); + const areJsObjectsSaving = Object.keys(savingJSObjects).some( + (collectionId) => savingJSObjects[collectionId], + ); - return ( - state.ui.editor.loadingStates.saving || - areApisSaving || - areJsObjectsSaving || - isSavingAppTheme || - state.ui.editor.loadingStates.savingEntity || - isSavingNavigationSetting - ); -}; + return ( + isEditorSavingEntity || + areApisSaving || + areJsObjectsSaving || + isSavingAppTheme || + isEditorSaving || + isSavingNavigationSetting + ); + }, +); export const snipingModeSelector = (state: AppState) => state.ui.editor.isSnipingMode; @@ -124,7 +132,7 @@ export const getIsPublishingApplication = (state: AppState) => export const getPublishingError = (state: AppState) => state.ui.editor.loadingStates.publishingError; -export const getCurrentLayoutId = (state: AppState) => +export const getCurrentLayoutId = (state: AppState): string | undefined => state.ui.editor.currentLayoutId; export const getPageList = (state: AppState) => state.entities.pageList.pages; diff --git a/app/client/src/utils/JSPaneUtils.tsx b/app/client/src/utils/JSPaneUtils.tsx index b745afa87ecf..0b359f0c60ab 100644 --- a/app/client/src/utils/JSPaneUtils.tsx +++ b/app/client/src/utils/JSPaneUtils.tsx @@ -20,10 +20,25 @@ export interface JSUpdate { parsedBody: ParsedBody | undefined; } +export interface JSCollectionDifference { + newActions: Partial[]; + updateActions: JSAction[]; + deletedActions: JSAction[]; + nameChangedActions: Array<{ + id: string; + collectionId?: string; + oldName: string; + newName: string; + pageId: string; + moduleId?: string; + }>; + changedVariables: Variable[]; +} + export const getDifferenceInJSCollection = ( parsedBody: ParsedBody, jsAction: JSCollection, -) => { +): JSCollectionDifference => { const newActions: ParsedJSSubAction[] = []; const toBearchivedActions: JSAction[] = []; const toBeUpdatedActions: JSAction[] = [];