Add action settings tab to api and query pane (#434)

* Add action settings tab to api and query pane

- Ask for confirmation before running an action

* Update  property of actions basedon the updateLayout response

Prevent confirmation dialog for Action run, until  property of action is true

Send an API Request when the user toggles the  property of an Action

* update http method to toggle executeOnLoad for an action to PUT

* Fix save layout response type

* Remove console.log

* If updating executeOnLoad, avoid calling update action API

Co-authored-by: Abhinav Jha <abhinav@appsmith.com>
This commit is contained in:
akash-codemonk 2020-08-27 21:09:16 +05:30 committed by GitHub
parent dfabda6009
commit dbfd986d0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 432 additions and 50 deletions

View File

@ -55,6 +55,7 @@
"fusioncharts": "^3.15.0-sr.1",
"history": "^4.10.1",
"husky": "^3.0.5",
"immer": "^7.0.8",
"instantsearch.css": "^7.4.2",
"instantsearch.js": "^4.4.1",
"interweave": "^12.1.1",

View File

@ -67,6 +67,38 @@ export const runAction = (id: string, paginationField?: PaginationField) => {
};
};
export const runActionInit = (
id: string,
paginationField?: PaginationField,
) => {
return {
type: ReduxActionTypes.RUN_ACTION_INIT,
payload: {
id,
paginationField,
},
};
};
export const showRunActionConfirmModal = (show: boolean) => {
return {
type: ReduxActionTypes.SHOW_RUN_ACTION_CONFIRM_MODAL,
payload: show,
};
};
export const cancelRunActionConfirmModal = () => {
return {
type: ReduxActionTypes.CANCEL_RUN_ACTION_CONFIRM_MODAL,
};
};
export const acceptRunActionConfirmModal = () => {
return {
type: ReduxActionTypes.ACCEPT_RUN_ACTION_CONFIRM_MODAL,
};
};
export const updateAction = (payload: { id: string }) => {
return batchAction({
type: ReduxActionTypes.UPDATE_ACTION_INIT,
@ -196,6 +228,13 @@ export const updateActionProperty = (
});
};
export const setActionsToExecuteOnPageLoad = (actions: string[]) => {
return {
type: ReduxActionTypes.SET_ACTION_TO_EXECUTE_ON_PAGELOAD,
payload: actions,
};
};
export default {
createAction: createActionRequest,
fetchActions,

View File

@ -182,6 +182,12 @@ class ActionAPI extends API {
static executeQuery(executeAction: any): AxiosPromise<ActionApiResponse> {
return API.post(ActionAPI.url + "/execute", executeAction);
}
static toggleActionExecuteOnLoad(actionId: string, shouldExecute: boolean) {
return API.put(ActionAPI.url + `/executeOnLoad/${actionId}`, undefined, {
flag: shouldExecute.toString(),
});
}
}
export default ActionAPI;

View File

@ -45,7 +45,11 @@ export type FetchPublishedPageResponse = ApiResponse & {
};
export interface SavePageResponse extends ApiResponse {
pageId: string;
data: {
id: string;
layoutOnLoadActions: PageAction[][];
dsl: Partial<ContainerWidgetProps<any>>;
};
}
export interface CreatePageRequest {

View File

@ -24,7 +24,7 @@ import {
const Wrapper = styled.div`
.dynamic-text-field {
border-radius: 4px;
border: 1px solid #d0d7dd;
border: none;
font-size: 14px;
height: calc(100vh / 4);
}

View File

@ -21,21 +21,30 @@ const SwitchWrapped = styled.div`
}
`;
const Info = styled.div`
font-size: 12px;
opacity: 0.7;
margin-top: 8px;
`;
export class SwitchField extends React.Component<Props> {
render() {
const { label, isRequired, input } = this.props;
const { label, isRequired, input, info } = this.props;
return (
<SwitchWrapped>
<StyledFormLabel>
{label} {isRequired && "*"}
</StyledFormLabel>
<StyledSwitch
checked={input.value}
onChange={value => input.onChange(value)}
large
/>
</SwitchWrapped>
<div>
<SwitchWrapped>
<StyledFormLabel>
{label} {isRequired && "*"}
</StyledFormLabel>
<StyledSwitch
checked={input.value}
onChange={value => input.onChange(value)}
large
/>
</SwitchWrapped>
{info && <Info>{info}</Info>}
</div>
);
}
}
@ -56,6 +65,8 @@ class SwitchControl extends BaseControl<SwitchControlProps> {
}
}
export type SwitchControlProps = ControlProps;
export interface SwitchControlProps extends ControlProps {
info?: string;
}
export default SwitchControl;

View File

@ -27,6 +27,7 @@ export const ReduxActionTypes: { [key: string]: string } = {
REMOVE_PAGE_WIDGET: "REMOVE_PAGE_WIDGET",
LOAD_API_RESPONSE: "LOAD_API_RESPONSE",
LOAD_QUERY_RESPONSE: "LOAD_QUERY_RESPONSE",
RUN_ACTION_INIT: "RUN_ACTION_INIT",
RUN_ACTION_REQUEST: "RUN_ACTION_REQUEST",
RUN_ACTION_SUCCESS: "RUN_ACTION_SUCCESS",
INIT_API_PANE: "INIT_API_PANE",
@ -59,6 +60,9 @@ export const ReduxActionTypes: { [key: string]: string } = {
UPDATE_ACTION_SUCCESS: "UPDATE_ACTION_SUCCESS",
DELETE_ACTION_INIT: "DELETE_ACTION_INIT",
DELETE_ACTION_SUCCESS: "DELETE_ACTION_SUCCESS",
SHOW_RUN_ACTION_CONFIRM_MODAL: "SHOW_RUN_ACTION_CONFIRM_MODAL",
CANCEL_RUN_ACTION_CONFIRM_MODAL: "CANCEL_RUN_ACTION_CONFIRM_MODAL",
ACCEPT_RUN_ACTION_CONFIRM_MODAL: "ACCEPT_RUN_ACTION_CONFIRM_MODAL",
CREATE_QUERY_INIT: "CREATE_QUERY_INIT",
FETCH_DATASOURCES_INIT: "FETCH_DATASOURCES_INIT",
FETCH_DATASOURCES_SUCCESS: "FETCH_DATASOURCES_SUCCESS",
@ -254,6 +258,10 @@ export const ReduxActionTypes: { [key: string]: string } = {
TOGGLE_PROPERTY_PANE_WIDGET_NAME_EDIT:
"TOGGLE_PROPERTY_PANE_WIDGET_NAME_EDIT",
UPDATE_APP_STORE: "UPDATE_APP_STORE",
SET_ACTION_TO_EXECUTE_ON_PAGELOAD: "SET_ACTION_TO_EXECUTE_ON_PAGELOAD",
TOGGLE_ACTION_EXECUTE_ON_LOAD_SUCCESS:
"TOGGLE_ACTION_EXECUTE_ON_LOAD_SUCCESS",
TOGGLE_ACTION_EXECUTE_ON_LOAD_INIT: "TOGGLE_ACTION_EXECUTE_ON_LOAD_INIT",
};
export type ReduxActionType = typeof ReduxActionTypes[keyof typeof ReduxActionTypes];
@ -344,6 +352,7 @@ export const ReduxActionErrorTypes: { [key: string]: string } = {
SAVE_API_NAME_ERROR: "SAVE_API_NAME_ERROR",
POPULATE_PAGEDSLS_ERROR: "POPULATE_PAGEDSLS_ERROR",
FETCH_PAGE_DSL_ERROR: "FETCH_PAGE_DSL_ERROR",
TOGGLE_ACTION_EXECUTE_ON_LOAD_ERROR: "TOGGLE_ACTION_EXECUTE_ON_LOAD_ERROR",
};
export const ReduxFormActionTypes: { [key: string]: string } = {

View File

@ -0,0 +1,41 @@
export const queryActionSettingsConfig = [
{
sectionName: "",
id: 1,
children: [
{
label: "Run query on Page load",
configProperty: "executeOnLoad",
controlType: "SWITCH",
info: "Will refresh data everytime page is reloaded",
},
// {
// label: "Request confirmation before running query",
// configProperty: "requestConfirmation",
// controlType: "SWITCH",
// info: "Ask confirmation from the user everytime before refreshing data",
// },
],
},
];
export const apiActionSettingsConfig = [
{
sectionName: "",
id: 1,
children: [
{
label: "Run api on Page load",
configProperty: "executeOnLoad",
controlType: "SWITCH",
info: "Will refresh data everytime page is reloaded",
},
// {
// label: "Request confirmation before running api",
// configProperty: "requestConfirmation",
// controlType: "SWITCH",
// info: "Ask confirmation from the user everytime before refreshing data",
// },
],
},
];

View File

@ -25,6 +25,8 @@ import EmbeddedDatasourcePathField from "components/editorComponents/form/fields
import { AppState } from "reducers";
import { getApiName } from "selectors/formSelectors";
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
import ActionSettings from "pages/Editor/ActionSettings";
import { apiActionSettingsConfig } from "mockResponses/ActionSettings";
const Form = styled.form`
display: flex;
@ -111,6 +113,13 @@ const RequestParamsWrapper = styled.div`
padding-right: 10px;
`;
const SettingsWrapper = styled.div`
padding-left: 15px;
${FormLabel} {
padding: 0px;
}
`;
const HeadersSection = styled.div`
margin-bottom: 32px;
`;
@ -256,6 +265,17 @@ const ApiEditorForm: React.FC<Props> = (props: Props) => {
/>
),
},
{
key: "settings",
title: "Settings",
panelComponent: (
<SettingsWrapper>
<ActionSettings
actionSettingsConfig={apiActionSettingsConfig}
/>
</SettingsWrapper>
),
},
]}
/>
</TabbedViewContainer>

View File

@ -4,7 +4,7 @@ import { submit } from "redux-form";
import ApiEditorForm from "./Form";
import RapidApiEditorForm from "./RapidApiEditorForm";
import ApiHomeScreen from "./ApiHomeScreen";
import { runAction, deleteAction } from "actions/actionActions";
import { deleteAction, runActionInit } from "actions/actionActions";
import { PaginationField } from "api/ActionAPI";
import { AppState } from "reducers";
import { RouteComponentProps } from "react-router";
@ -234,7 +234,7 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
submitForm: (name: string) => dispatch(submit(name)),
runAction: (id: string, paginationField?: PaginationField) =>
dispatch(runAction(id, paginationField)),
dispatch(runActionInit(id, paginationField)),
deleteAction: (id: string, name: string) =>
dispatch(deleteAction({ id, name })),
changeAPIPage: (actionId: string) => dispatch(changeApi(actionId)),

View File

@ -0,0 +1,37 @@
import React from "react";
import FormControlFactory from "utils/FormControlFactory";
import { ControlProps } from "components/formControls/BaseControl";
interface ActionSettingsProps {
actionSettingsConfig: any;
}
const ActionSettings = (props: ActionSettingsProps): JSX.Element => {
return <>{props.actionSettingsConfig.map(renderEachConfig)}</>;
};
const renderEachConfig = (section: any): any => {
return section.children.map((propertyControlOrSection: ControlProps) => {
if ("children" in propertyControlOrSection) {
return renderEachConfig(propertyControlOrSection);
} else {
try {
const { configProperty } = propertyControlOrSection;
return (
<div key={configProperty} style={{ marginTop: "18px" }}>
{FormControlFactory.createControl(
{ ...propertyControlOrSection },
{},
false,
)}
</div>
);
} catch (e) {
console.log(e);
}
}
return null;
});
};
export default ActionSettings;

View File

@ -0,0 +1,61 @@
import React from "react";
import { connect } from "react-redux";
import { AppState } from "reducers";
import { Dialog, Classes } from "@blueprintjs/core";
import Button from "components/editorComponents/Button";
import {
showRunActionConfirmModal,
cancelRunActionConfirmModal,
acceptRunActionConfirmModal,
} from "actions/actionActions";
type Props = {
isModalOpen: boolean;
dispatch: any;
};
class ConfirmRunModal extends React.Component<Props> {
render() {
const { dispatch, isModalOpen } = this.props;
const handleClose = () => {
dispatch(showRunActionConfirmModal(false));
};
return (
<Dialog title="Confirm run" isOpen={isModalOpen} onClose={handleClose}>
<div className={Classes.DIALOG_BODY}>
Are you sure you want to refresh your current data
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button
filled
text="Cancel"
onClick={() => {
dispatch(cancelRunActionConfirmModal());
handleClose();
}}
/>
<Button
filled
text="Confirm and run"
intent="primary"
onClick={() => {
dispatch(acceptRunActionConfirmModal());
handleClose();
}}
/>
</div>
</div>
</Dialog>
);
}
}
const mapStateToProps = (state: AppState) => ({
isModalOpen: state.ui.confirmRunAction.modalOpen,
});
export default connect(mapStateToProps)(ConfirmRunModal);

View File

@ -1,10 +1,5 @@
import React from "react";
import {
formValueSelector,
InjectedFormProps,
reduxForm,
Field,
} from "redux-form";
import { formValueSelector, InjectedFormProps, reduxForm } from "redux-form";
import styled, { createGlobalStyle } from "styled-components";
import { Icon, Popover, Spinner, Tag } from "@blueprintjs/core";
import {
@ -22,6 +17,7 @@ import FormRow from "components/editorComponents/FormRow";
import DropdownField from "components/editorComponents/form/fields/DropdownField";
import { BaseButton } from "components/designSystems/blueprint/ButtonComponent";
import { Datasource } from "api/DatasourcesApi";
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
import { Colors } from "constants/Colors";
import JSONViewer from "./JSONViewer";
@ -39,7 +35,8 @@ import {
import FormControlFactory from "utils/FormControlFactory";
import { ControlProps } from "components/formControls/BaseControl";
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import { SwitchField } from "components/formControls/SwitchControl";
import ActionSettings from "pages/Editor/ActionSettings";
import { queryActionSettingsConfig } from "mockResponses/ActionSettings";
const QueryFormContainer = styled.div`
padding: 20px 32px;
@ -216,6 +213,22 @@ const LoadingContainer = styled(CenteredWrapper)`
height: 50%;
`;
const TabContainerView = styled.div`
height: calc(100vh / 3);
.react-tabs__tab-panel {
border: 1px solid #ebeff2;
}
.react-tabs__tab-list {
margin: 0px;
}
`;
const SettingsWrapper = styled.div`
padding-left: 15px;
padding-top: 8px;
`;
type QueryFormProps = {
onDeleteClick: () => void;
onRunClick: () => void;
@ -442,29 +455,44 @@ const QueryEditorForm: React.FC<Props> = (props: Props) => {
)}
</div>
{editorConfig && editorConfig.length > 0 ? (
editorConfig.map(renderEachConfig)
) : (
<>
<ErrorMessage>An unexpected error occurred</ErrorMessage>
<Tag
round
intent="warning"
interactive
minimal
onClick={() => window.location.reload()}
>
Refresh
</Tag>
</>
)}
<div className="executeOnLoad">
<Field
name="executeOnLoad"
component={SwitchField}
label={"Run on Page Load"}
<TabContainerView>
<BaseTabbedView
tabs={[
{
key: "query",
title: "Query",
panelComponent:
editorConfig && editorConfig.length > 0 ? (
editorConfig.map(renderEachConfig)
) : (
<>
<ErrorMessage>An unexpected error occurred</ErrorMessage>
<Tag
round
intent="warning"
interactive
minimal
onClick={() => window.location.reload()}
>
Refresh
</Tag>
</>
),
},
{
key: "settings",
title: "Settings",
panelComponent: (
<SettingsWrapper>
<ActionSettings
actionSettingsConfig={queryActionSettingsConfig}
/>
</SettingsWrapper>
),
},
]}
/>
</div>
</TabContainerView>
</form>
{dataSources.length === 0 && (

View File

@ -6,11 +6,9 @@ import { getPluginTemplates } from "selectors/entitiesSelector";
const Container = styled.div`
display: flex;
height: 185px;
padding: 16px 24px;
flex: 1;
border-radius: 4px;
border: 1px solid #d0d7dd;
flex-direction: column;
color: #4e5d78;
`;

View File

@ -6,7 +6,7 @@ import styled from "styled-components";
import { QueryEditorRouteParams } from "constants/routes";
import QueryEditorForm from "./Form";
import QueryHomeScreen from "./QueryHomeScreen";
import { deleteAction, runAction } from "actions/actionActions";
import { deleteAction, runActionInit } from "actions/actionActions";
import { AppState } from "reducers";
import { getIsEditorInitialized } from "selectors/editorSelectors";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
@ -187,7 +187,7 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
const mapDispatchToProps = (dispatch: any): ReduxDispatchProps => ({
deleteAction: (id: string, name: string) =>
dispatch(deleteAction({ id, name })),
runAction: (actionId: string) => dispatch(runAction(actionId)),
runAction: (actionId: string) => dispatch(runActionInit(actionId)),
changeQueryPage: (queryId: string) => {
dispatch(changeQuery(queryId));
},

View File

@ -39,6 +39,7 @@ import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import { getAppsmithConfigs } from "configs";
import { getCurrentUser } from "selectors/usersSelectors";
import { User } from "constants/userConstants";
import ConfirmRunModal from "pages/Editor/ConfirmRunModal";
const { cloudHosting, intercomAppID } = getAppsmithConfigs();
@ -192,6 +193,7 @@ class Editor extends Component<Props> {
</div>
</Dialog>
</div>
<ConfirmRunModal />
</DndProvider>
);
}

View File

@ -9,6 +9,8 @@ import { ExecuteErrorPayload } from "constants/ActionConstants";
import _ from "lodash";
import { RapidApiAction, RestAction } from "entities/Action";
import { UpdateActionPropertyActionPayload } from "actions/actionActions";
import produce from "immer";
export interface ActionData {
isLoading: boolean;
config: RestAction | RapidApiAction;
@ -294,6 +296,18 @@ const actionsReducer = createReducer(initialState, {
return true;
}),
[ReduxActionTypes.SET_ACTION_TO_EXECUTE_ON_PAGELOAD]: (
state: ActionDataState,
actionIds: ReduxAction<string[]>,
) => {
return produce(state, draft => {
draft.forEach((action, index) => {
if (actionIds.payload.indexOf(action.config.id) > -1) {
draft[index].config.executeOnLoad = true;
}
});
});
},
});
export default actionsReducer;

View File

@ -30,6 +30,7 @@ import { HelpReduxState } from "./uiReducers/helpReducer";
import { ApiNameReduxState } from "./uiReducers/apiNameReducer";
import { ExplorerReduxState } from "./uiReducers/explorerReducer";
import { PageDSLsReduxState } from "./uiReducers/pageDSLReducer";
import { ConfirmRunActionReduxState } from "./uiReducers/confirmRunActionReducer";
import { AppDataState } from "@appsmith/reducers/entityReducers/appReducer";
import { DatasourceNameReduxState } from "./uiReducers/datasourceNameReducer";
@ -63,6 +64,7 @@ export interface AppState {
apiName: ApiNameReduxState;
explorer: ExplorerReduxState;
pageDSLs: PageDSLsReduxState;
confirmRunAction: ConfirmRunActionReduxState;
datasourceName: DatasourceNameReduxState;
};
entities: {

View File

@ -0,0 +1,21 @@
import { createReducer } from "utils/AppsmithUtils";
import { ReduxAction, ReduxActionTypes } from "constants/ReduxActionConstants";
const initialState: ConfirmRunActionReduxState = {
modalOpen: false,
};
const confirmRunActionReducer = createReducer(initialState, {
[ReduxActionTypes.SHOW_RUN_ACTION_CONFIRM_MODAL]: (
state: ConfirmRunActionReduxState,
action: ReduxAction<boolean>,
) => {
return { ...state, modalOpen: action.payload };
},
});
export interface ConfirmRunActionReduxState {
modalOpen: boolean;
}
export default confirmRunActionReducer;

View File

@ -19,6 +19,7 @@ import helpReducer from "./helpReducer";
import apiNameReducer from "./apiNameReducer";
import explorerReducer from "./explorerReducer";
import pageDSLsReducer from "./pageDSLReducer";
import confirmRunActionReducer from "./confirmRunActionReducer";
import datasourceNameReducer from "./datasourceNameReducer";
const uiReducer = combineReducers({
@ -43,5 +44,6 @@ const uiReducer = combineReducers({
apiName: apiNameReducer,
explorer: explorerReducer,
pageDSLs: pageDSLsReducer,
confirmRunAction: confirmRunActionReducer,
});
export default uiReducer;

View File

@ -19,6 +19,7 @@ import {
take,
takeEvery,
takeLatest,
race,
} from "redux-saga/effects";
import {
evaluateDataTreeWithFunctions,
@ -50,6 +51,7 @@ import {
executeApiActionRequest,
executeApiActionSuccess,
updateAction,
showRunActionConfirmModal,
} from "actions/actionActions";
import { Action, RestAction } from "entities/Action";
import ActionAPI, {
@ -500,6 +502,35 @@ function* runActionSaga(
}
}
function* confirmRunActionSaga(
reduxAction: ReduxAction<{
id: string;
paginationField: PaginationField;
}>,
) {
const action = yield select(getAction, reduxAction.payload.id);
if (action.requestConfirmation) {
yield put(showRunActionConfirmModal(true));
const { accept } = yield race({
cancel: take(ReduxActionTypes.CANCEL_RUN_ACTION_CONFIRM_MODAL),
accept: take(ReduxActionTypes.ACCEPT_RUN_ACTION_CONFIRM_MODAL),
});
if (accept) {
yield put({
type: ReduxActionTypes.RUN_ACTION_REQUEST,
payload: reduxAction.payload,
});
}
} else {
yield put({
type: ReduxActionTypes.RUN_ACTION_REQUEST,
payload: reduxAction.payload,
});
}
}
function* executePageLoadAction(pageAction: PageAction) {
yield put(executeApiActionRequest({ id: pageAction.id }));
const params: Property[] = yield call(
@ -545,6 +576,7 @@ export function* watchActionExecutionSagas() {
yield all([
takeEvery(ReduxActionTypes.EXECUTE_ACTION, executeAppAction),
takeLatest(ReduxActionTypes.RUN_ACTION_REQUEST, runActionSaga),
takeLatest(ReduxActionTypes.RUN_ACTION_INIT, confirmRunActionSaga),
takeLatest(
ReduxActionTypes.EXECUTE_PAGE_LOAD_ACTIONS,
executePageLoadActionsSaga,

View File

@ -442,6 +442,7 @@ function* setActionPropertySaga(action: ReduxAction<SetActionPropertyPayload>) {
const { actionId, value, propertyName } = action.payload;
if (!actionId) return;
if (propertyName === "name") return;
const actionObj = yield select(getAction, actionId);
const effects: Record<string, any> = {};
// Value change effect
@ -457,9 +458,42 @@ function* setActionPropertySaga(action: ReduxAction<SetActionPropertyPayload>) {
put(updateActionProperty({ id: actionId, field, value: effects[field] })),
),
);
if (propertyName === "executeOnLoad") {
yield put({
type: ReduxActionTypes.TOGGLE_ACTION_EXECUTE_ON_LOAD_INIT,
payload: {
actionId,
shouldExecute: value,
},
});
return;
}
yield put(updateAction({ id: actionId }));
}
function* toggleActionExecuteOnLoadSaga(
action: ReduxAction<{ actionId: string; shouldExecute: boolean }>,
) {
try {
const response = yield call(
ActionAPI.toggleActionExecuteOnLoad,
action.payload.actionId,
action.payload.shouldExecute,
);
const isValidResponse = yield validateResponse(response);
if (isValidResponse) {
yield put({
type: ReduxActionTypes.TOGGLE_ACTION_EXECUTE_ON_LOAD_SUCCESS,
});
}
} catch (error) {
yield put({
type: ReduxActionErrorTypes.TOGGLE_ACTION_EXECUTE_ON_LOAD_ERROR,
payload: error,
});
}
}
function* handleMoveOrCopySaga(actionPayload: ReduxAction<{ id: string }>) {
const { id } = actionPayload.payload;
const action: Action = yield select(getAction, id);
@ -499,5 +533,9 @@ export function* watchActionSagas() {
takeEvery(ReduxActionTypes.COPY_ACTION_SUCCESS, handleMoveOrCopySaga),
takeEvery(ReduxActionErrorTypes.MOVE_ACTION_ERROR, handleMoveOrCopySaga),
takeEvery(ReduxActionErrorTypes.COPY_ACTION_ERROR, handleMoveOrCopySaga),
takeLatest(
ReduxActionTypes.TOGGLE_ACTION_EXECUTE_ON_LOAD_INIT,
toggleActionExecuteOnLoadSaga,
),
]);
}

View File

@ -65,7 +65,10 @@ import {
getCurrentPageId,
getCurrentPageName,
} from "selectors/editorSelectors";
import { fetchActionsForPage } from "actions/actionActions";
import {
fetchActionsForPage,
setActionsToExecuteOnPageLoad,
} from "actions/actionActions";
import { clearCaches } from "utils/DynamicBindingUtils";
import { UrlDataState } from "reducers/entityReducers/appReducer";
import { getQueryParams } from "utils/AppsmithUtils";
@ -245,6 +248,14 @@ function* savePageSaga() {
);
const isValidResponse = yield validateResponse(savePageResponse);
if (isValidResponse) {
if (
savePageResponse.data.layoutOnLoadActions &&
savePageResponse.data.layoutOnLoadActions.length > 0
) {
for (const actionSet of savePageResponse.data.layoutOnLoadActions) {
yield put(setActionsToExecuteOnPageLoad(actionSet.map(a => a.id)));
}
}
yield put(savePageSuccess(savePageResponse));
}
} catch (error) {

View File

@ -9258,6 +9258,11 @@ immer@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
immer@^7.0.8:
version "7.0.8"
resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.8.tgz#41dcbc5669a76500d017bef3ad0d03ce0a1d7c1e"
integrity sha512-XnpIN8PXBBaOD43U8Z17qg6RQiKQYGDGGCIbz1ixmLGwBkSWwmrmx5X7d+hTtXDM8ur7m5OdLE0PiO+y5RB3pw==
immutable@3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"