diff --git a/app/client/cypress/support/Pages/JSEditor.ts b/app/client/cypress/support/Pages/JSEditor.ts
index 89a9fe9d8f..43be9a7178 100644
--- a/app/client/cypress/support/Pages/JSEditor.ts
+++ b/app/client/cypress/support/Pages/JSEditor.ts
@@ -6,10 +6,10 @@ const agHelper = new AggregateHelper();
const locator = new CommonLocators();
export class JSEditor {
- private _runButton = "//li//*[local-name() = 'svg' and @class='run-button']/parent::li"
- private _outputConsole = ".CodeEditorTarget"
- private _jsObjName = ".t--js-action-name-edit-field span"
- private _jsObjTxt = ".t--js-action-name-edit-field input"
+ private _runButton = "//li//*[local-name() = 'svg' and @class='run-button']";
+ private _outputConsole = ".CodeEditorTarget";
+ private _jsObjName = ".t--js-action-name-edit-field span";
+ private _jsObjTxt = ".t--js-action-name-edit-field input";
private _newJSobj = "span:contains('New JS Object')"
private _bindingsClose = ".t--entity-property-close"
diff --git a/app/client/src/actions/evaluationActions.ts b/app/client/src/actions/evaluationActions.ts
index 0e57aa5b4b..3d0931ac16 100644
--- a/app/client/src/actions/evaluationActions.ts
+++ b/app/client/src/actions/evaluationActions.ts
@@ -45,6 +45,7 @@ export const EVALUATE_REDUX_ACTIONS = [
ReduxActionTypes.FETCH_JS_ACTIONS_VIEW_MODE_SUCCESS,
ReduxActionErrorTypes.FETCH_JS_ACTIONS_VIEW_MODE_ERROR,
ReduxActionTypes.UPDATE_JS_ACTION_BODY_SUCCESS,
+ ReduxActionTypes.EXECUTE_JS_FUNCTION_SUCCESS,
// App Data
ReduxActionTypes.SET_APP_MODE,
ReduxActionTypes.FETCH_USER_DETAILS_SUCCESS,
diff --git a/app/client/src/actions/jsPaneActions.ts b/app/client/src/actions/jsPaneActions.ts
index 7341e19e21..8968dff147 100644
--- a/app/client/src/actions/jsPaneActions.ts
+++ b/app/client/src/actions/jsPaneActions.ts
@@ -1,6 +1,6 @@
import { ReduxAction, ReduxActionTypes } from "constants/ReduxActionConstants";
import { JSCollection, JSAction } from "entities/JSCollection";
-import { RefactorAction } from "api/JSActionAPI";
+import { RefactorAction, SetFunctionPropertyPayload } from "api/JSActionAPI";
export const createNewJSCollection = (
pageId: string,
): ReduxAction<{ pageId: string }> => ({
@@ -61,3 +61,17 @@ export const executeJSFunction = (payload: {
payload,
};
};
+
+export const updateFunctionProperty = (payload: SetFunctionPropertyPayload) => {
+ return {
+ type: ReduxActionTypes.SET_FUNCTION_PROPERTY,
+ payload,
+ };
+};
+
+export const updateJSFunction = (payload: SetFunctionPropertyPayload) => {
+ return {
+ type: ReduxActionTypes.UPDATE_JS_FUNCTION_PROPERTY_INIT,
+ payload,
+ };
+};
diff --git a/app/client/src/actions/pluginActionActions.ts b/app/client/src/actions/pluginActionActions.ts
index 5a40184d29..d448c25afe 100644
--- a/app/client/src/actions/pluginActionActions.ts
+++ b/app/client/src/actions/pluginActionActions.ts
@@ -279,6 +279,20 @@ export const setActionsToExecuteOnPageLoad = (
};
};
+export const setJSActionsToExecuteOnPageLoad = (
+ actions: Array<{
+ executeOnLoad: boolean;
+ id: string;
+ name: string;
+ collectionId?: string;
+ }>,
+) => {
+ return {
+ type: ReduxActionTypes.SET_JS_ACTION_TO_EXECUTE_ON_PAGELOAD,
+ payload: actions,
+ };
+};
+
export const bindDataOnCanvas = (payload: {
queryId: string;
applicationId: string;
diff --git a/app/client/src/api/JSActionAPI.tsx b/app/client/src/api/JSActionAPI.tsx
index 6fb1011d49..bf2ee37e13 100644
--- a/app/client/src/api/JSActionAPI.tsx
+++ b/app/client/src/api/JSActionAPI.tsx
@@ -32,6 +32,11 @@ export interface CreateJSCollectionRequest {
pluginType: PluginType;
}
+export type SetFunctionPropertyPayload = {
+ action: JSAction;
+ propertyName: string;
+ value: any;
+};
export interface RefactorAction {
pageId: string;
actionId: string;
diff --git a/app/client/src/api/PageApi.tsx b/app/client/src/api/PageApi.tsx
index 89b08f39c4..0194d3e6b6 100644
--- a/app/client/src/api/PageApi.tsx
+++ b/app/client/src/api/PageApi.tsx
@@ -58,6 +58,7 @@ export interface SavePageResponse extends ApiResponse {
executeOnLoad: boolean;
id: string;
name: string;
+ collectionId?: string;
}>;
};
}
diff --git a/app/client/src/assets/icons/menu/settings.svg b/app/client/src/assets/icons/menu/settings.svg
new file mode 100644
index 0000000000..7361abf4b9
--- /dev/null
+++ b/app/client/src/assets/icons/menu/settings.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts
index bcade5423a..aca97146e2 100644
--- a/app/client/src/ce/constants/messages.ts
+++ b/app/client/src/ce/constants/messages.ts
@@ -450,6 +450,15 @@ export const JS_EXECUTION_SUCCESS = () => "JS Function executed successfully";
export const JS_EXECUTION_FAILURE = () => "JS Function execution failed";
export const JS_EXECUTION_FAILURE_TOASTER = () =>
"There was an error while executing function";
+export const JS_SETTINGS_ONPAGELOAD = () => "Run Function on Page load";
+export const JS_SETTINGS_ONPAGELOAD_SUBTEXT = () =>
+ "Will refresh data every time page is reloaded";
+export const JS_SETTINGS_CONFIRM_EXECUTION = () =>
+ "Request confirmation before calling Function?";
+export const JS_SETTINGS_CONFIRM_EXECUTION_SUBTEXT = () =>
+ "Ask confirmation from the user every time before refreshing data";
+export const JS_SETTINGS_EXECUTE_TIMEOUT = () =>
+ "Function Timeout (in milliseconds)";
// Import/Export Application features
export const IMPORT_APPLICATION_MODAL_TITLE = () => "Import application";
diff --git a/app/client/src/components/editorComponents/JSResponseView.tsx b/app/client/src/components/editorComponents/JSResponseView.tsx
index 5299258ac8..bfced16e48 100644
--- a/app/client/src/components/editorComponents/JSResponseView.tsx
+++ b/app/client/src/components/editorComponents/JSResponseView.tsx
@@ -40,6 +40,8 @@ import { setCurrentTab } from "actions/debuggerActions";
import { DEBUGGER_TAB_KEYS } from "./Debugger/helpers";
import EntityBottomTabs from "./EntityBottomTabs";
import Icon from "components/ads/Icon";
+import { ReactComponent as FunctionSettings } from "assets/icons/menu/settings.svg";
+import JSFunctionSettings from "pages/Editor/JSEditor/JSFunctionSettings";
import FlagBadge from "components/utils/FlagBadge";
const ResponseContainer = styled.div`
@@ -94,9 +96,16 @@ const ResponseTabAction = styled.li`
display: inline-block;
flex: 1;
}
+ .function-actions {
+ margin-left: auto;
+ order: 2;
+ svg {
+ display: inline-block;
+ }
+ }
.run-button {
+ margin: 0 15px;
margin-left: 10px;
- margin-right: 15px;
}
&.active {
background-color: #f0f0f0;
@@ -192,6 +201,18 @@ function JSResponseView(props: Props) {
dispatch(setCurrentTab(DEBUGGER_TAB_KEYS.ERROR_TAB));
}, []);
+ const [openSettings, setOpenSettings] = useState(false);
+ const [selectedFunction, setSelectedFunction] = useState<
+ undefined | JSAction
+ >(undefined);
+ const isSelectedFunctionAsync = (id: string) => {
+ const jsAction = jsObject.actions.find((action) => action.id === id);
+ if (!!jsAction) {
+ return jsAction?.actionConfiguration.isAsync;
+ }
+ return false;
+ };
+
const tabs = [
{
key: "body",
@@ -232,17 +253,35 @@ function JSResponseView(props: Props) {
}
key={action.id}
onClick={() => {
- runAction(action);
+ setSelectActionId(action.id);
}}
>
{" "}
{action.name}
- {action.actionConfiguration.isAsync ? (
-
- ) : (
- ""
- )}
-
+
+ {action.actionConfiguration.isAsync ? (
+
+ ) : (
+ ""
+ )}
+ {isSelectedFunctionAsync(action.id) ? (
+ {
+ setSelectedFunction(action);
+ setOpenSettings(true);
+ }}
+ />
+ ) : (
+ ""
+ )}
+
+ {
+ runAction(action);
+ }}
+ />
+
);
})}
@@ -271,6 +310,17 @@ function JSResponseView(props: Props) {
/>
)}
+ {openSettings &&
+ !!selectedFunction &&
+ isSelectedFunctionAsync(selectedFunction.id) && (
+ {
+ setOpenSettings(!openSettings);
+ }}
+ />
+ )}
>
)}
diff --git a/app/client/src/components/utils/FlagBadge.tsx b/app/client/src/components/utils/FlagBadge.tsx
index 171113d859..b003290052 100644
--- a/app/client/src/components/utils/FlagBadge.tsx
+++ b/app/client/src/components/utils/FlagBadge.tsx
@@ -8,6 +8,7 @@ const Flag = styled.span`
text-transform: uppercase;
font-size: 10px;
font-weight: 600;
+ margin-right: 10px;
`;
function FlagBadge(props: { name: string }) {
diff --git a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx
index 4f3408a05d..efa5f50188 100644
--- a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx
+++ b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx
@@ -19,6 +19,9 @@ export type ExecutionResult = {
export type TriggerSource = {
id: string;
name: string;
+ collectionId?: string;
+ isJSAction?: boolean;
+ actionId?: string;
};
export type ExecuteTriggerPayload = {
@@ -107,6 +110,8 @@ export interface PageAction {
name: string;
jsonPathKeys: string[];
timeoutInMillisecond: number;
+ clientSideExecution?: boolean;
+ collectionId?: string;
}
export interface ExecuteErrorPayload extends ErrorActionPayload {
diff --git a/app/client/src/constants/ReduxActionConstants.tsx b/app/client/src/constants/ReduxActionConstants.tsx
index 013b0093e9..eaa4f53669 100644
--- a/app/client/src/constants/ReduxActionConstants.tsx
+++ b/app/client/src/constants/ReduxActionConstants.tsx
@@ -640,6 +640,13 @@ export const ReduxActionTypes = {
UPDATE_JS_ACTION_BODY_INIT: "UPDATE_JS_ACTION_BODY_INIT",
UPDATE_JS_ACTION_BODY_SUCCESS: "UPDATE_JS_ACTION_BODY_SUCCESS",
SEND_TEST_EMAIL: "SEND_TEST_EMAIL",
+ SET_FUNCTION_PROPERTY: "SET_FUNCTION_PROPERTY",
+ UPDATE_JS_FUNCTION_PROPERTY_INIT: "UPDATE_JS_FUNCTION_PROPERTY_INIT",
+ UPDATE_JS_FUNCTION_PROPERTY_SUCCESS: "UPDATE_JS_FUNCTION_PROPERTY_SUCCESS",
+ TOGGLE_FUNCTION_EXECUTE_ON_LOAD_INIT: "TOGGLE_FUNCTION_EXECUTE_ON_LOAD_INIT",
+ TOGGLE_FUNCTION_EXECUTE_ON_LOAD_SUCCESS:
+ "TOGGLE_FUNCTION_EXECUTE_ON_LOAD_SUCCESS",
+ SET_JS_ACTION_TO_EXECUTE_ON_PAGELOAD: "SET_JS_ACTION_TO_EXECUTE_ON_PAGELOAD",
ENABLE_GUIDED_TOUR: "ENABLE_GUIDED_TOUR",
GUIDED_TOUR_MARK_STEP_COMPLETED: "GUIDED_TOUR_MARK_STEP_COMPLETED",
SET_CURRENT_STEP: "SET_CURRENT_STEP",
@@ -838,6 +845,7 @@ export const ReduxActionErrorTypes = {
FETCH_RELEASES_ERROR: "FETCH_RELEASES_ERROR",
RESTART_SERVER_ERROR: "RESTART_SERVER_ERROR",
UPDATE_JS_ACTION_BODY_ERROR: "UPDATE_JS_ACTION_BODY_ERROR",
+ UPDATE_JS_FUNCTION_PROPERTY_ERROR: "UPDATE_JS_FUNCTION_PROPERTY_ERROR",
DELETE_ORG_ERROR: "DELETE_ORG_ERROR",
REFLOW_BETA_FLAGS_INIT_ERROR: "REFLOW_BETA_FLAGS_INIT_ERROR",
GET_ALL_TEMPLATES_ERROR: "GET_ALL_TEMPLATES_ERROR",
diff --git a/app/client/src/entities/DataTree/actionTriggers.ts b/app/client/src/entities/DataTree/actionTriggers.ts
index e6eba816a0..6ad9701684 100644
--- a/app/client/src/entities/DataTree/actionTriggers.ts
+++ b/app/client/src/entities/DataTree/actionTriggers.ts
@@ -17,6 +17,7 @@ export enum ActionTriggerType {
GET_CURRENT_LOCATION = "GET_CURRENT_LOCATION",
WATCH_CURRENT_LOCATION = "WATCH_CURRENT_LOCATION",
STOP_WATCHING_CURRENT_LOCATION = "STOP_WATCHING_CURRENT_LOCATION",
+ CONFIRMATION_MODAL = "CONFIRMATION_MODAL",
}
export const ActionTriggerFunctionNames: Record = {
@@ -35,6 +36,7 @@ export const ActionTriggerFunctionNames: Record = {
[ActionTriggerType.GET_CURRENT_LOCATION]: "getCurrentLocation",
[ActionTriggerType.WATCH_CURRENT_LOCATION]: "watchLocation",
[ActionTriggerType.STOP_WATCHING_CURRENT_LOCATION]: "stopWatch",
+ [ActionTriggerType.CONFIRMATION_MODAL]: "ConfirmationModal",
};
export type RunPluginActionDescription = {
@@ -158,6 +160,11 @@ export type StopWatchingCurrentLocationDescription = {
payload?: Record;
};
+export type ConfirmationModal = {
+ type: ActionTriggerType.CONFIRMATION_MODAL;
+ payload?: Record;
+};
+
export type ActionDescription =
| RunPluginActionDescription
| ClearPluginActionDescription
@@ -173,4 +180,5 @@ export type ActionDescription =
| ClearIntervalDescription
| GetCurrentLocationDescription
| WatchCurrentLocationDescription
- | StopWatchingCurrentLocationDescription;
+ | StopWatchingCurrentLocationDescription
+ | ConfirmationModal;
diff --git a/app/client/src/entities/DataTree/dataTreeFactory.ts b/app/client/src/entities/DataTree/dataTreeFactory.ts
index 3a904a252a..f6744255ba 100644
--- a/app/client/src/entities/DataTree/dataTreeFactory.ts
+++ b/app/client/src/entities/DataTree/dataTreeFactory.ts
@@ -81,6 +81,8 @@ export interface DataTreeJSAction {
export interface MetaArgs {
arguments: Variable[];
+ isAsync: boolean;
+ confirmBeforeExecute: boolean;
}
/**
* Map of overriding property as key and overridden property as values
diff --git a/app/client/src/entities/DataTree/dataTreeJSAction.ts b/app/client/src/entities/DataTree/dataTreeJSAction.ts
index f61329175c..886cbfa111 100644
--- a/app/client/src/entities/DataTree/dataTreeJSAction.ts
+++ b/app/client/src/entities/DataTree/dataTreeJSAction.ts
@@ -31,15 +31,21 @@ export const generateDataTreeJSAction = (
const dependencyMap: DependencyMap = {};
dependencyMap["body"] = [];
const actions = js.config.actions;
+ const actionsData: Record = {};
if (actions) {
for (let i = 0; i < actions.length; i++) {
const action = actions[i];
meta[action.name] = {
arguments: action.actionConfiguration.jsArguments,
+ isAsync: action.actionConfiguration.isAsync,
+ confirmBeforeExecute: !!action.confirmBeforeExecute,
};
bindingPaths[action.name] = EvaluationSubstitutionType.SMART_SUBSTITUTE;
dynamicBindingPathList.push({ key: action.name });
dependencyMap["body"].push(action.name);
+ actionsData[action.name] = {
+ data: (js.data && js.data[`${action.id}`]) || {},
+ };
}
}
return {
@@ -54,5 +60,6 @@ export const generateDataTreeJSAction = (
dynamicBindingPathList: dynamicBindingPathList,
variables: listVariables,
dependencyMap: dependencyMap,
+ ...actionsData,
};
};
diff --git a/app/client/src/entities/JSCollection/index.ts b/app/client/src/entities/JSCollection/index.ts
index ff0cdcd59b..a74975f206 100644
--- a/app/client/src/entities/JSCollection/index.ts
+++ b/app/client/src/entities/JSCollection/index.ts
@@ -21,9 +21,10 @@ export interface JSCollection {
export interface JSActionConfig {
body: string;
isAsync: boolean;
- timeoutInMilliseconds: number;
+ timeoutInMillisecond: number;
jsArguments: Array;
}
export interface JSAction extends BaseAction {
actionConfiguration: JSActionConfig;
+ clientSideExecution: boolean;
}
diff --git a/app/client/src/pages/Editor/JSEditor/JSFunctionSettings.tsx b/app/client/src/pages/Editor/JSEditor/JSFunctionSettings.tsx
new file mode 100644
index 0000000000..a5315f4571
--- /dev/null
+++ b/app/client/src/pages/Editor/JSEditor/JSFunctionSettings.tsx
@@ -0,0 +1,79 @@
+import React from "react";
+import styled from "styled-components";
+import Checkbox from "components/ads/Checkbox";
+import Dialog from "components/ads/DialogComponent";
+import { JSAction } from "entities/JSCollection";
+import { updateFunctionProperty } from "actions/jsPaneActions";
+import { useDispatch } from "react-redux";
+import {
+ createMessage,
+ JS_SETTINGS_ONPAGELOAD,
+ JS_SETTINGS_ONPAGELOAD_SUBTEXT,
+ JS_SETTINGS_CONFIRM_EXECUTION,
+ JS_SETTINGS_CONFIRM_EXECUTION_SUBTEXT,
+} from "@appsmith/constants/messages";
+
+const FormRow = styled.div`
+ margin-bottom: ${(props) => props.theme.spaces[10] + 1}px;
+ &.flex {
+ display: flex;
+ align-items: center;
+ .cs-text {
+ margin-right: 30px;
+ color: rgb(9, 7, 7);
+ }
+ }
+`;
+
+interface JSFunctionSettingsProps {
+ action: JSAction;
+ openSettings: boolean;
+ toggleSettings: () => void;
+}
+
+function JSFunctionSettings(props: JSFunctionSettingsProps) {
+ const { action } = props;
+ const dispatch = useDispatch();
+ const updateProperty = (value: boolean | number, propertyName: string) => {
+ dispatch(
+ updateFunctionProperty({
+ action: props.action,
+ propertyName: propertyName,
+ value: value,
+ }),
+ );
+ };
+
+ return (
+
+ );
+}
+export default JSFunctionSettings;
diff --git a/app/client/src/reducers/entityReducers/jsActionsReducer.tsx b/app/client/src/reducers/entityReducers/jsActionsReducer.tsx
index 1b8bf1f56a..96657ffdb3 100644
--- a/app/client/src/reducers/entityReducers/jsActionsReducer.tsx
+++ b/app/client/src/reducers/entityReducers/jsActionsReducer.tsx
@@ -5,10 +5,10 @@ import {
ReduxAction,
ReduxActionErrorTypes,
} from "constants/ReduxActionConstants";
-import { keyBy } from "lodash";
+import { set, keyBy } from "lodash";
+import produce from "immer";
const initialState: JSCollectionDataState = [];
-
export interface JSCollectionData {
isLoading: boolean;
config: JSCollection;
@@ -64,8 +64,9 @@ const jsActionsReducer = createReducer(initialState, {
action: ReduxAction<{ data: JSCollection }>,
): JSCollectionDataState =>
state.map((a) => {
- if (a.config.id === action.payload.data.id)
- return { isLoading: false, config: action.payload.data };
+ if (a.config.id === action.payload.data.id) {
+ return { ...a, isLoading: false, config: action.payload.data };
+ }
return a;
}),
[ReduxActionTypes.UPDATE_JS_ACTION_BODY_SUCCESS]: (
@@ -75,6 +76,7 @@ const jsActionsReducer = createReducer(initialState, {
state.map((a) => {
if (a.config.id === action.payload.data.id)
return {
+ ...a,
isLoading: false,
config: action.payload.data,
};
@@ -286,6 +288,71 @@ const jsActionsReducer = createReducer(initialState, {
}
return a;
}),
+ [ReduxActionTypes.UPDATE_JS_FUNCTION_PROPERTY_SUCCESS]: (
+ state: JSCollectionDataState,
+ action: ReduxAction<{ collection: JSCollection }>,
+ ): JSCollectionDataState =>
+ state.map((a) => {
+ if (a.config.id === action.payload.collection.id) {
+ return {
+ ...a,
+ data: action.payload,
+ };
+ }
+ return a;
+ }),
+ [ReduxActionTypes.TOGGLE_FUNCTION_EXECUTE_ON_LOAD_SUCCESS]: (
+ state: JSCollectionDataState,
+ action: ReduxAction<{
+ actionId: string;
+ collectionId: string;
+ executeOnLoad: boolean;
+ }>,
+ ): JSCollectionDataState =>
+ state.map((a) => {
+ if (a.config.id === action.payload.collectionId) {
+ const updatedActions = a.config.actions.map((jsAction) => {
+ if (jsAction.id === action.payload.actionId) {
+ set(jsAction, `executeOnLoad`, action.payload.executeOnLoad);
+ }
+ return jsAction;
+ });
+ return {
+ ...a,
+ config: {
+ ...a.config,
+ actions: updatedActions,
+ },
+ };
+ }
+ return a;
+ }),
+ [ReduxActionTypes.SET_JS_ACTION_TO_EXECUTE_ON_PAGELOAD]: (
+ state: JSCollectionDataState,
+ action: ReduxAction<
+ Array<{
+ executeOnLoad: boolean;
+ id: string;
+ name: string;
+ collectionId: string;
+ }>
+ >,
+ ) => {
+ return produce(state, (draft) => {
+ const CollectionUpdateSearch = keyBy(action.payload, "collectionId");
+ const actionUpdateSearch = keyBy(action.payload, "id");
+ draft.forEach((action, index) => {
+ if (action.config.id in CollectionUpdateSearch) {
+ const allActions = draft[index].config.actions;
+ allActions.forEach((js) => {
+ if (js.id in actionUpdateSearch) {
+ js.executeOnLoad = actionUpdateSearch[js.id].executeOnLoad;
+ }
+ });
+ }
+ });
+ });
+ },
});
export default jsActionsReducer;
diff --git a/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts b/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts
index 53ed741935..731feee4ff 100644
--- a/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts
+++ b/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts
@@ -38,11 +38,14 @@ import {
clearIntervalSaga,
setIntervalSaga,
} from "sagas/ActionExecution/SetIntervalSaga";
+import { UserCancelledActionExecutionError } from "sagas/ActionExecution/errorUtils";
import {
getCurrentLocationSaga,
stopWatchCurrentLocation,
watchCurrentLocation,
} from "sagas/ActionExecution/GetCurrentLocationSaga";
+import { requestModalConfirmationSaga } from "sagas/UtilSagas";
+import { ModalType } from "reducers/uiReducers/modalActionReducer";
export type TriggerMeta = {
source?: TriggerSource;
@@ -125,6 +128,17 @@ export function* executeActionTriggers(
case ActionTriggerType.STOP_WATCHING_CURRENT_LOCATION:
response = yield call(stopWatchCurrentLocation, eventType, triggerMeta);
break;
+ case ActionTriggerType.CONFIRMATION_MODAL:
+ const payloadInfo = {
+ name: trigger?.payload?.funName,
+ modalOpen: true,
+ modalType: ModalType.RUN_ACTION,
+ };
+ const flag = yield call(requestModalConfirmationSaga, payloadInfo);
+ if (!flag) {
+ throw new UserCancelledActionExecutionError();
+ }
+ break;
default:
log.error("Trigger type unknown", trigger);
throw Error("Trigger type unknown");
diff --git a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts
index 628002e7dd..a61c690207 100644
--- a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts
+++ b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts
@@ -23,6 +23,7 @@ import {
getCurrentPageNameByActionId,
isActionDirty,
isActionSaving,
+ getJSCollection,
} from "selectors/entitiesSelector";
import {
getAppMode,
@@ -89,6 +90,8 @@ import {
UserCancelledActionExecutionError,
} from "sagas/ActionExecution/errorUtils";
import { trimQueryString } from "utils/helpers";
+import { JSCollection } from "entities/JSCollection";
+import { executeJSFunction } from "actions/jsPaneActions";
import {
executeAppAction,
TriggerMeta,
@@ -587,85 +590,109 @@ function* runActionSaga(
}
}
-function* executePageLoadAction(pageAction: PageAction) {
- const pageId = yield select(getCurrentPageId);
- let currentApp: ApplicationPayload = yield select(getCurrentApplication);
- currentApp = currentApp || {};
- const appMode = yield select(getAppMode);
- AnalyticsUtil.logEvent("EXECUTE_ACTION", {
- type: pageAction.pluginType,
- name: pageAction.name,
- pageId: pageId,
- appMode: appMode,
- appId: currentApp.id,
- onPageLoad: true,
- appName: currentApp.name,
- isExampleApp: currentApp.appIsExample,
- });
-
- let payload = EMPTY_RESPONSE;
- let isError = true;
- const error = `The action "${pageAction.name}" has failed.`;
- try {
- const executePluginActionResponse: ExecutePluginActionResponse = yield call(
- executePluginActionSaga,
- pageAction,
+function* executeOnPageLoadJSAction(pageAction: PageAction) {
+ const collectionId = pageAction.collectionId;
+ if (collectionId) {
+ const collection: JSCollection = yield select(
+ getJSCollection,
+ collectionId,
);
- payload = executePluginActionResponse.payload;
- isError = executePluginActionResponse.isError;
- } catch (e) {
- log.error(e);
+ const jsAction = collection.actions.find((d) => d.id === pageAction.id);
+ if (!!jsAction) {
+ yield put(
+ executeJSFunction({
+ collectionName: collection.name,
+ action: jsAction,
+ collectionId: collectionId,
+ }),
+ );
+ }
}
+}
- if (isError) {
- AppsmithConsole.addError({
- id: pageAction.id,
- logType: LOG_TYPE.ACTION_EXECUTION_ERROR,
- text: `Execution failed with status ${payload.statusCode}`,
- source: {
- type: ENTITY_TYPE.ACTION,
- name: pageAction.name,
- id: pageAction.id,
- },
- state: payload.request,
- messages: [
- {
- message: error,
- type: PLATFORM_ERROR.PLUGIN_EXECUTION,
- subType: payload.errorType,
- },
- ],
+function* executePageLoadAction(pageAction: PageAction) {
+ if (pageAction.hasOwnProperty("collectionId")) {
+ yield call(executeOnPageLoadJSAction, pageAction);
+ } else {
+ const pageId = yield select(getCurrentPageId);
+ let currentApp: ApplicationPayload = yield select(getCurrentApplication);
+ currentApp = currentApp || {};
+ const appMode = yield select(getAppMode);
+ AnalyticsUtil.logEvent("EXECUTE_ACTION", {
+ type: pageAction.pluginType,
+ name: pageAction.name,
+ pageId: pageId,
+ appMode: appMode,
+ appId: currentApp.id,
+ onPageLoad: true,
+ appName: currentApp.name,
+ isExampleApp: currentApp.appIsExample,
});
- yield put(
- executePluginActionError({
- actionId: pageAction.id,
- isPageLoad: true,
- error: { message: error },
- data: payload,
- }),
- );
- PerformanceTracker.stopAsyncTracking(
- PerformanceTransactionName.EXECUTE_ACTION,
- {
- failed: true,
- },
- pageAction.id,
- );
- } else {
- PerformanceTracker.stopAsyncTracking(
- PerformanceTransactionName.EXECUTE_ACTION,
- undefined,
- pageAction.id,
- );
- yield put(
- executePluginActionSuccess({
+ let payload = EMPTY_RESPONSE;
+ let isError = true;
+ const error = `The action "${pageAction.name}" has failed.`;
+ try {
+ const executePluginActionResponse: ExecutePluginActionResponse = yield call(
+ executePluginActionSaga,
+ pageAction,
+ );
+ payload = executePluginActionResponse.payload;
+ isError = executePluginActionResponse.isError;
+ } catch (e) {
+ log.error(e);
+ }
+
+ if (isError) {
+ AppsmithConsole.addError({
id: pageAction.id,
- response: payload,
- isPageLoad: true,
- }),
- );
- yield take(ReduxActionTypes.SET_EVALUATED_TREE);
+ logType: LOG_TYPE.ACTION_EXECUTION_ERROR,
+ text: `Execution failed with status ${payload.statusCode}`,
+ source: {
+ type: ENTITY_TYPE.ACTION,
+ name: pageAction.name,
+ id: pageAction.id,
+ },
+ state: payload.request,
+ messages: [
+ {
+ message: error,
+ type: PLATFORM_ERROR.PLUGIN_EXECUTION,
+ subType: payload.errorType,
+ },
+ ],
+ });
+
+ yield put(
+ executePluginActionError({
+ actionId: pageAction.id,
+ isPageLoad: true,
+ error: { message: error },
+ data: payload,
+ }),
+ );
+ PerformanceTracker.stopAsyncTracking(
+ PerformanceTransactionName.EXECUTE_ACTION,
+ {
+ failed: true,
+ },
+ pageAction.id,
+ );
+ } else {
+ PerformanceTracker.stopAsyncTracking(
+ PerformanceTransactionName.EXECUTE_ACTION,
+ undefined,
+ pageAction.id,
+ );
+ yield put(
+ executePluginActionSuccess({
+ id: pageAction.id,
+ response: payload,
+ isPageLoad: true,
+ }),
+ );
+ yield take(ReduxActionTypes.SET_EVALUATED_TREE);
+ }
}
}
diff --git a/app/client/src/sagas/EvaluationsSaga.ts b/app/client/src/sagas/EvaluationsSaga.ts
index 9307b879eb..4567313707 100644
--- a/app/client/src/sagas/EvaluationsSaga.ts
+++ b/app/client/src/sagas/EvaluationsSaga.ts
@@ -220,9 +220,14 @@ export function* evaluateAndExecuteDynamicTrigger(
* We raise an error telling the user that an uncaught error has occurred
* */
if (requestData.result.errors.length) {
- throw new UncaughtPromiseError(
- requestData.result.errors[0].errorMessage,
- );
+ if (
+ requestData.result.errors[0].errorMessage !==
+ "UncaughtPromiseRejection: User cancelled action execution"
+ ) {
+ throw new UncaughtPromiseError(
+ requestData.result.errors[0].errorMessage,
+ );
+ }
}
// It is possible to get a few triggers here if the user
// still uses the old way of action runs and not promises. For that we
diff --git a/app/client/src/sagas/JSPaneSagas.ts b/app/client/src/sagas/JSPaneSagas.ts
index 1a03a6ffd7..ac3dc1a490 100644
--- a/app/client/src/sagas/JSPaneSagas.ts
+++ b/app/client/src/sagas/JSPaneSagas.ts
@@ -6,6 +6,7 @@ import {
debounce,
call,
take,
+ takeLatest,
} from "redux-saga/effects";
import {
ReduxAction,
@@ -31,11 +32,16 @@ import {
pushLogsForObjectUpdate,
createDummyJSCollectionActions,
} from "../utils/JSPaneUtils";
-import JSActionAPI, { RefactorAction } from "../api/JSActionAPI";
+import JSActionAPI, {
+ RefactorAction,
+ SetFunctionPropertyPayload,
+} from "../api/JSActionAPI";
+import ActionAPI from "api/ActionAPI";
import {
updateJSCollectionSuccess,
refactorJSCollectionAction,
updateJSCollectionBodySuccess,
+ updateJSFunction,
} from "actions/jsPaneActions";
import { getCurrentOrgId } from "selectors/organizationSelectors";
import { getPluginIdOfPackageName } from "sagas/selectors";
@@ -59,6 +65,7 @@ import LOG_TYPE from "entities/AppsmithConsole/logtype";
import PageApi from "api/PageApi";
import { updateCanvasWithDSL } from "sagas/PageSagas";
export const JS_PLUGIN_PACKAGE_NAME = "js-plugin";
+import { set } from "lodash";
import { updateReplayEntity } from "actions/pageActions";
function* handleCreateNewJsActionSaga(action: ReduxAction<{ pageId: string }>) {
@@ -280,7 +287,7 @@ function* handleJSObjectNameChangeSuccessSaga(
}
}
-function* handleExecuteJSFunctionSaga(
+export function* handleExecuteJSFunctionSaga(
data: ReduxAction<{
collectionName: string;
action: JSAction;
@@ -291,7 +298,6 @@ function* handleExecuteJSFunctionSaga(
const actionId = action.id;
try {
const result = yield call(executeFunction, collectionName, action);
-
yield put({
type: ReduxActionTypes.EXECUTE_JS_FUNCTION_SUCCESS,
payload: {
@@ -338,7 +344,7 @@ function* handleUpdateJSCollectionBody(
actionPayload: ReduxAction<{ body: string; id: string; isReplay: boolean }>,
) {
const jsCollection = yield select(getJSCollection, actionPayload.payload.id);
- jsCollection.body = actionPayload.payload.body;
+ jsCollection["body"] = actionPayload.payload.body;
try {
if (jsCollection) {
const response = yield JSActionAPI.updateJSCollection(jsCollection);
@@ -418,6 +424,132 @@ function* handleRefactorJSActionNameSaga(
}
}
+function* setFunctionPropertySaga(
+ data: ReduxAction,
+) {
+ const { action, propertyName, value } = data.payload;
+ if (!action.id) return;
+ const actionId = action.id;
+ if (propertyName === "executeOnLoad") {
+ yield put({
+ type: ReduxActionTypes.TOGGLE_FUNCTION_EXECUTE_ON_LOAD_INIT,
+ payload: {
+ collectionId: action.collectionId,
+ actionId,
+ shouldExecute: value,
+ },
+ });
+ return;
+ }
+ yield put(updateJSFunction({ ...data.payload }));
+}
+
+function* handleUpdateJSFunctionPropertySaga(
+ data: ReduxAction,
+) {
+ const { action, propertyName, value } = data.payload;
+ if (!action.id) return;
+ const actionId = action.id;
+ let collection: JSCollection;
+ if (action.collectionId) {
+ collection = yield select(getJSCollection, action.collectionId);
+
+ try {
+ const actions: JSAction[] = collection.actions;
+ const updatedActions = actions.map((jsAction: JSAction) => {
+ if (jsAction.id === actionId) {
+ set(jsAction, propertyName, value);
+ return jsAction;
+ }
+ return jsAction;
+ });
+ collection.actions = updatedActions;
+ const response = yield JSActionAPI.updateJSCollection(collection);
+ const isValidResponse = yield validateResponse(response);
+ if (isValidResponse) {
+ const fieldToBeUpdated = propertyName.replace(
+ "actionConfiguration",
+ "config",
+ );
+ AppsmithConsole.info({
+ logType: LOG_TYPE.ACTION_UPDATE,
+ text: "Configuration updated",
+ source: {
+ type: ENTITY_TYPE.JSACTION,
+ name: collection.name + "." + action.name,
+ id: actionId,
+ propertyPath: fieldToBeUpdated,
+ },
+ state: {
+ [fieldToBeUpdated]: value,
+ },
+ });
+ yield put({
+ type: ReduxActionTypes.UPDATE_JS_FUNCTION_PROPERTY_SUCCESS,
+ payload: {
+ collection,
+ },
+ });
+ }
+ } catch (e) {
+ yield put({
+ type: ReduxActionErrorTypes.UPDATE_JS_FUNCTION_PROPERTY_ERROR,
+ payload: collection,
+ });
+ }
+ }
+}
+
+function* toggleFunctionExecuteOnLoadSaga(
+ action: ReduxAction<{
+ collectionId: string;
+ actionId: string;
+ shouldExecute: boolean;
+ }>,
+) {
+ try {
+ const { actionId, collectionId, shouldExecute } = action.payload;
+ const collection = yield select(getJSCollection, collectionId);
+ const jsAction = collection.actions.find(
+ (action: JSAction) => actionId === action.id,
+ );
+ const response = yield call(
+ ActionAPI.toggleActionExecuteOnLoad,
+ actionId,
+ shouldExecute,
+ );
+ const isValidResponse = yield validateResponse(response);
+ if (isValidResponse) {
+ AppsmithConsole.info({
+ logType: LOG_TYPE.ACTION_UPDATE,
+ text: "Configuration updated",
+ source: {
+ type: ENTITY_TYPE.JSACTION,
+ name: collection.name + "." + jsAction.name,
+ id: actionId,
+ propertyPath: "executeOnLoad",
+ },
+ state: {
+ ["executeOnLoad"]: shouldExecute,
+ },
+ });
+ yield put({
+ type: ReduxActionTypes.TOGGLE_FUNCTION_EXECUTE_ON_LOAD_SUCCESS,
+ payload: {
+ actionId: actionId,
+ collectionId: collectionId,
+ executeOnLoad: shouldExecute,
+ },
+ });
+ }
+ } catch (error) {
+ yield put({
+ type: ReduxActionErrorTypes.TOGGLE_ACTION_EXECUTE_ON_LOAD_ERROR,
+ payload: error,
+ });
+ }
+}
+
export default function* root() {
yield all([
takeEvery(
@@ -445,5 +577,14 @@ export default function* root() {
ReduxActionTypes.UPDATE_JS_ACTION_BODY_INIT,
handleUpdateJSCollectionBody,
),
+ takeEvery(ReduxActionTypes.SET_FUNCTION_PROPERTY, setFunctionPropertySaga),
+ takeLatest(
+ ReduxActionTypes.UPDATE_JS_FUNCTION_PROPERTY_INIT,
+ handleUpdateJSFunctionPropertySaga,
+ ),
+ takeLatest(
+ ReduxActionTypes.TOGGLE_FUNCTION_EXECUTE_ON_LOAD_INIT,
+ toggleFunctionExecuteOnLoadSaga,
+ ),
]);
}
diff --git a/app/client/src/sagas/PageSagas.tsx b/app/client/src/sagas/PageSagas.tsx
index 5f76277cb5..ebbbbfe290 100644
--- a/app/client/src/sagas/PageSagas.tsx
+++ b/app/client/src/sagas/PageSagas.tsx
@@ -75,6 +75,7 @@ import {
executePageLoadActions,
fetchActionsForPage,
setActionsToExecuteOnPageLoad,
+ setJSActionsToExecuteOnPageLoad,
} from "actions/pluginActionActions";
import { UrlDataState } from "reducers/entityReducers/appReducer";
import { APP_MODE } from "entities/App";
@@ -403,7 +404,18 @@ function* savePageSaga(action: ReduxAction<{ isRetry?: boolean }>) {
}
// Update actions
if (actionUpdates && actionUpdates.length > 0) {
- yield put(setActionsToExecuteOnPageLoad(actionUpdates));
+ const actions = actionUpdates.filter(
+ (d) => !d.hasOwnProperty("collectionId"),
+ );
+ if (actions && actions.length) {
+ yield put(setActionsToExecuteOnPageLoad(actions));
+ }
+ const jsActions = actionUpdates.filter((d) =>
+ d.hasOwnProperty("collectionId"),
+ );
+ if (jsActions && jsActions.length) {
+ yield put(setJSActionsToExecuteOnPageLoad(jsActions));
+ }
}
yield put(setLastUpdatedTime(Date.now() / 1000));
yield put(savePageSuccess(savePageResponse));
diff --git a/app/client/src/utils/DynamicBindingUtils.ts b/app/client/src/utils/DynamicBindingUtils.ts
index 68955665ad..9633da8ab4 100644
--- a/app/client/src/utils/DynamicBindingUtils.ts
+++ b/app/client/src/utils/DynamicBindingUtils.ts
@@ -307,10 +307,13 @@ export const unsafeFunctionForEval = [
export const isChildPropertyPath = (
parentPropertyPath: string,
childPropertyPath: string,
-): boolean =>
- parentPropertyPath === childPropertyPath ||
- childPropertyPath.startsWith(`${parentPropertyPath}.`) ||
- childPropertyPath.startsWith(`${parentPropertyPath}[`);
+): boolean => {
+ return (
+ parentPropertyPath === childPropertyPath ||
+ childPropertyPath.startsWith(`${parentPropertyPath}.`) ||
+ childPropertyPath.startsWith(`${parentPropertyPath}[`)
+ );
+};
/**
* Paths set via evaluator on entities
diff --git a/app/client/src/utils/JSPaneUtils.tsx b/app/client/src/utils/JSPaneUtils.tsx
index 0ec48bbfa4..f421d2f9c1 100644
--- a/app/client/src/utils/JSPaneUtils.tsx
+++ b/app/client/src/utils/JSPaneUtils.tsx
@@ -113,7 +113,7 @@ export const getDifferenceInJSCollection = (
actionConfiguration: {
body: action.body,
isAsync: action.isAsync,
- timeoutInMilliseconds: 0,
+ timeoutInMillisecond: 0,
jsArguments: [],
},
};
@@ -196,9 +196,10 @@ export const createDummyJSCollectionActions = (
actionConfiguration: {
body: "() => {\n\t\t//write code here\n\t}",
isAsync: false,
- timeoutInMilliseconds: 0,
+ timeoutInMillisecond: 0,
jsArguments: [],
},
+ clientSideExecution: true,
},
{
name: "myFun2",
@@ -206,11 +207,12 @@ export const createDummyJSCollectionActions = (
organizationId,
executeOnLoad: false,
actionConfiguration: {
- body: "async () => {\n\t\t//write code here\n\t}",
+ body: "async () => {\n\t\t//use async-await or promises\n\t}",
isAsync: true,
- timeoutInMilliseconds: 0,
+ timeoutInMillisecond: 0,
jsArguments: [],
},
+ clientSideExecution: true,
},
];
return {
diff --git a/app/client/src/workers/DataTreeEvaluator.ts b/app/client/src/workers/DataTreeEvaluator.ts
index 069c305638..6f79f09676 100644
--- a/app/client/src/workers/DataTreeEvaluator.ts
+++ b/app/client/src/workers/DataTreeEvaluator.ts
@@ -178,13 +178,27 @@ export default class DataTreeEvaluator {
return { evalTree: this.evalTree, jsUpdates: jsUpdates };
}
+ isJSObjectFunction(dataTree: DataTree, jsObjectName: string, key: string) {
+ const entity = dataTree[jsObjectName];
+ if (isJSAction(entity)) {
+ return entity.meta.hasOwnProperty(key);
+ }
+ return false;
+ }
+
updateLocalUnEvalTree(dataTree: DataTree) {
//add functions and variables to unevalTree
Object.keys(this.currentJSCollectionState).forEach((update) => {
const updates = this.currentJSCollectionState[update];
if (!!dataTree[update]) {
Object.keys(updates).forEach((key) => {
- _.set(dataTree, `${update}.${key}`, updates[key]);
+ const data = _.get(dataTree, `${update}.${key}.data`, undefined);
+ if (this.isJSObjectFunction(dataTree, update, key)) {
+ _.set(dataTree, `${update}.${key}`, new String(updates[key]));
+ _.set(dataTree, `${update}.${key}.data`, data);
+ } else {
+ _.set(dataTree, `${update}.${key}`, updates[key]);
+ }
});
}
});
@@ -548,7 +562,8 @@ export default class DataTreeEvaluator {
Object.keys(entity.bindingPaths).forEach((propertyPath) => {
const existingDeps =
dependencies[`${entityName}.${propertyPath}`] || [];
- const jsSnippets = [_.get(entity, propertyPath)];
+ const unevalPropValue = _.get(entity, propertyPath).toString();
+ const { jsSnippets } = getDynamicBindings(unevalPropValue, entity);
dependencies[`${entityName}.${propertyPath}`] = existingDeps.concat(
jsSnippets.filter((jsSnippet) => !!jsSnippet),
);
diff --git a/app/client/src/workers/PromisifyAction.ts b/app/client/src/workers/PromisifyAction.ts
index 23ea5176f8..7c693e120a 100644
--- a/app/client/src/workers/PromisifyAction.ts
+++ b/app/client/src/workers/PromisifyAction.ts
@@ -9,7 +9,10 @@ const ctx: Worker = self as any;
* needs a REQUEST_ID to be passed in to know which request is going on right now
*/
import { EVAL_WORKER_ACTIONS } from "utils/DynamicBindingUtils";
-import { ActionDescription } from "entities/DataTree/actionTriggers";
+import {
+ ActionDescription,
+ ActionTriggerType,
+} from "entities/DataTree/actionTriggers";
import _ from "lodash";
import { dataTreeEvaluator } from "workers/evaluation.worker";
@@ -99,3 +102,18 @@ export const completePromise = (requestId: string, result: EvalResult) => {
requestId,
});
};
+
+export const confirmationPromise = function(
+ requestId: string,
+ func: any,
+ name: string,
+ ...args: any[]
+) {
+ const payload: ActionDescription = {
+ type: ActionTriggerType.CONFIRMATION_MODAL,
+ payload: {
+ funName: name,
+ },
+ };
+ return promisifyAction(requestId, payload).then(() => func(...args));
+};
diff --git a/app/client/src/workers/evaluate.ts b/app/client/src/workers/evaluate.ts
index ece0f63e59..e9a7b2c30c 100644
--- a/app/client/src/workers/evaluate.ts
+++ b/app/client/src/workers/evaluate.ts
@@ -11,7 +11,7 @@ import { Severity } from "entities/AppsmithConsole";
import { enhanceDataTreeWithFunctions } from "./Actions";
import { isEmpty } from "lodash";
import { getLintingErrors } from "workers/lint";
-import { completePromise } from "workers/PromisifyAction";
+import { completePromise, confirmationPromise } from "workers/PromisifyAction";
import { ActionDescription } from "entities/DataTree/actionTriggers";
export type EvalResult = {
@@ -147,7 +147,23 @@ export const createGlobalData = (
Object.keys(resolvedObject).forEach((key: any) => {
const dataTreeKey = GLOBAL_DATA[datum];
if (dataTreeKey) {
- dataTreeKey[key] = resolvedObject[key];
+ const data = dataTreeKey[key]?.data;
+ const isAsync = dataTreeKey?.meta[key]?.isAsync || false;
+ const confirmBeforeExecute =
+ dataTreeKey?.meta[key]?.confirmBeforeExecute || false;
+ if (isAsync && confirmBeforeExecute) {
+ dataTreeKey[key] = confirmationPromise.bind(
+ {},
+ context?.requestId,
+ resolvedObject[key],
+ dataTreeKey.name + "." + key,
+ );
+ } else {
+ dataTreeKey[key] = resolvedObject[key];
+ }
+ if (!!data) {
+ dataTreeKey[key]["data"] = data;
+ }
}
});
});
@@ -355,7 +371,23 @@ export function isFunctionAsync(
Object.keys(resolvedObject).forEach((key: any) => {
const dataTreeKey = GLOBAL_DATA[datum];
if (dataTreeKey) {
- dataTreeKey[key] = resolvedObject[key];
+ const data = dataTreeKey[key]?.data;
+ const isAsync = dataTreeKey.meta[key]?.isAsync || false;
+ const confirmBeforeExecute =
+ dataTreeKey.meta[key]?.confirmBeforeExecute || false;
+ if (isAsync && confirmBeforeExecute) {
+ dataTreeKey[key] = confirmationPromise.bind(
+ {},
+ "",
+ resolvedObject[key],
+ key,
+ );
+ } else {
+ dataTreeKey[key] = resolvedObject[key];
+ }
+ if (!!data) {
+ dataTreeKey[key].data = data;
+ }
}
});
});
@@ -368,7 +400,6 @@ export function isFunctionAsync(
// @ts-ignore: No types available
self[key] = GLOBAL_DATA[key];
});
-
try {
if (typeof userFunction === "function") {
const returnValue = userFunction();
diff --git a/app/client/src/workers/evaluationUtils.ts b/app/client/src/workers/evaluationUtils.ts
index 5f7ee4fd85..28f18cf450 100644
--- a/app/client/src/workers/evaluationUtils.ts
+++ b/app/client/src/workers/evaluationUtils.ts
@@ -605,33 +605,68 @@ export const updateJSCollectionInDataTree = (
const action = parsedBody.actions[i];
if (jsCollection.hasOwnProperty(action.name)) {
if (jsCollection[action.name] !== action.body) {
+ const data = _.get(
+ modifiedDataTree,
+ `${jsCollection.name}.${action.name}.data`,
+ {},
+ );
_.set(
modifiedDataTree,
`${jsCollection.name}.${action.name}`,
- action.body,
+ new String(action.body),
+ );
+
+ _.set(
+ modifiedDataTree,
+ `${jsCollection.name}.${action.name}.data`,
+ data,
);
}
} else {
const bindingPaths = jsCollection.bindingPaths;
bindingPaths[action.name] = EvaluationSubstitutionType.SMART_SUBSTITUTE;
- _.set(modifiedDataTree, `${jsCollection}.bindingPaths`, bindingPaths);
+ bindingPaths[`${action.name}.data`] =
+ EvaluationSubstitutionType.TEMPLATE;
+ _.set(
+ modifiedDataTree,
+ `${jsCollection.name}.bindingPaths`,
+ bindingPaths,
+ );
const dynamicBindingPathList = jsCollection.dynamicBindingPathList;
dynamicBindingPathList.push({ key: action.name });
_.set(
modifiedDataTree,
- `${jsCollection}.dynamicBindingPathList`,
+ `${jsCollection.name}.dynamicBindingPathList`,
dynamicBindingPathList,
);
const dependencyMap = jsCollection.dependencyMap;
dependencyMap["body"].push(action.name);
- _.set(modifiedDataTree, `${jsCollection}.dependencyMap`, dependencyMap);
+ _.set(
+ modifiedDataTree,
+ `${jsCollection.name}.dependencyMap`,
+ dependencyMap,
+ );
const meta = jsCollection.meta;
- meta[action.name] = { arguments: action.arguments };
+ meta[action.name] = {
+ arguments: action.arguments,
+ isAsync: false,
+ confirmBeforeExecute: false,
+ };
_.set(modifiedDataTree, `${jsCollection.name}.meta`, meta);
+ const data = _.get(
+ modifiedDataTree,
+ `${jsCollection.name}.${action.name}.data`,
+ {},
+ );
_.set(
modifiedDataTree,
`${jsCollection.name}.${action.name}`,
- action.body,
+ new String(action.body.toString()),
+ );
+ _.set(
+ modifiedDataTree,
+ `${jsCollection.name}.${action.name}.data`,
+ data,
);
}
}
@@ -675,6 +710,7 @@ export const updateJSCollectionInDataTree = (
delete meta[preAction];
_.set(modifiedDataTree, `${jsCollection.name}.meta`, meta);
delete modifiedDataTree[`${jsCollection.name}`][`${preAction}`];
+ delete modifiedDataTree[`${jsCollection.name}`][`${preAction}.data`];
}
}
}