diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/RunBehaviorEnum.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/RunBehaviorEnum.java new file mode 100644 index 0000000000..fbe37d2a1e --- /dev/null +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/RunBehaviorEnum.java @@ -0,0 +1,9 @@ +package com.appsmith.external.models; + +/** + * Enum to define the behavior for running actions + */ +public enum RunBehaviorEnum { + MANUAL, // Action will only run when manually triggered + ON_PAGE_LOAD // Action will run when the page loads +} diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java index 0e90f105ad..3409139b37 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ce/ActionCE_DTO.java @@ -15,6 +15,7 @@ import com.appsmith.external.models.Executable; import com.appsmith.external.models.PluginType; import com.appsmith.external.models.Policy; import com.appsmith.external.models.Property; +import com.appsmith.external.models.RunBehaviorEnum; import com.appsmith.external.views.FromRequest; import com.appsmith.external.views.Git; import com.appsmith.external.views.Views; @@ -100,9 +101,17 @@ public class ActionCE_DTO implements Identifiable, Executable { @JsonView(Views.Public.class) List errorReports; + /** + * @deprecated This field is deprecated and will be removed in a future release. + * Use runBehavior instead. + */ + @Deprecated @JsonView({Views.Public.class, FromRequest.class, Git.class}) Boolean executeOnLoad; + @JsonView({Views.Public.class, FromRequest.class, Git.class}) + RunBehaviorEnum runBehavior = RunBehaviorEnum.MANUAL; + @JsonView({Views.Public.class, FromRequest.class, Git.class}) Boolean clientSideExecution; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ActionControllerCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ActionControllerCE.java index 39498b77a6..fddfb6addb 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ActionControllerCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/ce/ActionControllerCE.java @@ -2,6 +2,7 @@ package com.appsmith.server.controllers.ce; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.ActionExecutionResult; +import com.appsmith.external.models.RunBehaviorEnum; import com.appsmith.external.views.FromRequest; import com.appsmith.external.views.Views; import com.appsmith.server.constants.FieldName; @@ -115,6 +116,20 @@ public class ActionControllerCE { .map(actions -> new ResponseDTO<>(HttpStatus.OK, actions)); } + @JsonView(Views.Public.class) + @PutMapping("/runBehavior/{branchedActionId}") + public Mono> setRunBehavior( + @PathVariable String branchedActionId, @RequestParam RunBehaviorEnum behavior) { + log.debug("Going to set run behavior for action id {} to {}", branchedActionId, behavior); + return layoutActionService + .setRunBehavior(branchedActionId, behavior) + .map(action -> new ResponseDTO<>(HttpStatus.OK, action)); + } + + /** + * @deprecated This endpoint is deprecated. Use /runBehavior/{branchedActionId} instead. + */ + @Deprecated @JsonView(Views.Public.class) @PutMapping("/executeOnLoad/{branchedActionId}") public Mono> setExecuteOnLoad( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCE.java index 264c910545..2d727c8a51 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCE.java @@ -1,6 +1,7 @@ package com.appsmith.server.services.ce; import com.appsmith.external.models.ActionDTO; +import com.appsmith.external.models.RunBehaviorEnum; import com.appsmith.server.dtos.ActionMoveDTO; import com.appsmith.server.dtos.CreateActionMetaDTO; import reactor.core.publisher.Mono; @@ -17,6 +18,8 @@ public interface LayoutActionServiceCE { Mono setExecuteOnLoad(String id, Boolean isExecuteOnLoad); + Mono setRunBehavior(String id, RunBehaviorEnum behavior); + Mono createAction(ActionDTO actionDTO); Mono createSingleAction(ActionDTO actionDTO); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java index a90a1e8cd6..f37f6092a4 100755 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/LayoutActionServiceCEImpl.java @@ -6,6 +6,7 @@ import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.PluginType; +import com.appsmith.external.models.RunBehaviorEnum; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.datasources.base.DatasourceService; @@ -300,6 +301,42 @@ public class LayoutActionServiceCEImpl implements LayoutActionServiceCE { action.setUserSetOnLoad(true); action.setExecuteOnLoad(isExecuteOnLoad); + // Update runBehavior based on executeOnLoad for forward compatibility + if (Boolean.TRUE.equals(isExecuteOnLoad)) { + action.setRunBehavior(RunBehaviorEnum.ON_PAGE_LOAD); + } else { + action.setRunBehavior(RunBehaviorEnum.MANUAL); + } + + newAction.setUnpublishedAction(action); + + return newActionService.save(newAction).flatMap(savedAction -> updateLayoutService + .updatePageLayoutsByPageId( + savedAction.getUnpublishedAction().getPageId()) + .name(UPDATE_PAGE_LAYOUT_BY_PAGE_ID) + .tap(Micrometer.observation(observationRegistry)) + .thenReturn(newActionService.generateActionByViewMode(savedAction, false))); + }); + } + + @Override + public Mono setRunBehavior(String id, RunBehaviorEnum behavior) { + return newActionService + .findById(id, actionPermission.getEditPermission()) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.ACTION, id))) + .flatMap(newAction -> { + ActionDTO action = newAction.getUnpublishedAction(); + + action.setUserSetOnLoad(true); + action.setRunBehavior(behavior); + + // Update executeOnLoad based on RunBehaviorEnum for backward compatibility + if (RunBehaviorEnum.ON_PAGE_LOAD.equals(behavior)) { + action.setExecuteOnLoad(true); + } else { + action.setExecuteOnLoad(false); + } + newAction.setUnpublishedAction(action); return newActionService.save(newAction).flatMap(savedAction -> updateLayoutService @@ -386,6 +423,15 @@ public class LayoutActionServiceCEImpl implements LayoutActionServiceCE { // page or application clone event. if (!AppsmithEventContextType.CLONE_PAGE.equals(eventContext.getAppsmithEventContextType())) { actionDTO.setExecuteOnLoad(false); + + actionDTO.setRunBehavior(RunBehaviorEnum.MANUAL); + } else { + // For cloned pages, if executeOnLoad is true, set runBehavior to ON_PAGE_LOAD + if (Boolean.TRUE.equals(actionDTO.getExecuteOnLoad())) { + actionDTO.setRunBehavior(RunBehaviorEnum.ON_PAGE_LOAD); + } else { + actionDTO.setRunBehavior(RunBehaviorEnum.MANUAL); + } } newAction.setUnpublishedAction(actionDTO); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java index c6bcf1a583..d567156203 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java @@ -8,6 +8,7 @@ import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.PluginType; import com.appsmith.external.models.Property; +import com.appsmith.external.models.RunBehaviorEnum; import com.appsmith.server.actioncollections.base.ActionCollectionService; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.constants.ArtifactType; @@ -1352,4 +1353,90 @@ class LayoutActionServiceTest { parentDsl.put("children", children); return parentDsl; } + + @Test + @WithUserDetails(value = "api_user") + void testSetRunBehavior_WhenRunBehaviorChanged_ValuesUpdatedCorrectly() { + Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any())) + .thenReturn(Mono.just(new MockPluginExecutor())); + + // Create a new action + ActionDTO action = new ActionDTO(); + action.setName("testRunBehaviorAction"); + action.setPageId(testPage.getId()); + ActionConfiguration actionConfiguration = new ActionConfiguration(); + actionConfiguration.setHttpMethod(HttpMethod.GET); + action.setActionConfiguration(actionConfiguration); + action.setDatasource(datasource); + + // Create the action and validate default values + ActionDTO createdAction = + layoutActionService.createSingleAction(action, Boolean.FALSE).block(); + assertNotNull(createdAction); + assertEquals(RunBehaviorEnum.MANUAL, createdAction.getRunBehavior()); + assertEquals(Boolean.FALSE, createdAction.getExecuteOnLoad()); + + // Test setting runBehavior to ON_PAGE_LOAD + ActionDTO updatedAction = layoutActionService + .setRunBehavior(createdAction.getId(), RunBehaviorEnum.ON_PAGE_LOAD) + .block(); + assertNotNull(updatedAction); + assertEquals(RunBehaviorEnum.ON_PAGE_LOAD, updatedAction.getRunBehavior()); + assertEquals(Boolean.TRUE, updatedAction.getExecuteOnLoad()); + assertEquals(Boolean.TRUE, updatedAction.getUserSetOnLoad()); + + // Test setting runBehavior back to MANUAL + updatedAction = layoutActionService + .setRunBehavior(createdAction.getId(), RunBehaviorEnum.MANUAL) + .block(); + assertNotNull(updatedAction); + assertEquals(RunBehaviorEnum.MANUAL, updatedAction.getRunBehavior()); + assertEquals(Boolean.FALSE, updatedAction.getExecuteOnLoad()); + assertEquals(Boolean.TRUE, updatedAction.getUserSetOnLoad()); + + // Ensure the changes were persisted by getting the action again + NewAction savedAction = actionRepository.findById(createdAction.getId()).block(); + assertNotNull(savedAction); + assertEquals(RunBehaviorEnum.MANUAL, savedAction.getUnpublishedAction().getRunBehavior()); + assertEquals(Boolean.FALSE, savedAction.getUnpublishedAction().getExecuteOnLoad()); + } + + @Test + @WithUserDetails(value = "api_user") + void testSetExecuteOnLoad_AlsoUpdatesRunBehavior() { + Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any())) + .thenReturn(Mono.just(new MockPluginExecutor())); + + // Create a new action + ActionDTO action = new ActionDTO(); + action.setName("testExecuteLoadRunBehaviorAction"); + action.setPageId(testPage.getId()); + ActionConfiguration actionConfiguration = new ActionConfiguration(); + actionConfiguration.setHttpMethod(HttpMethod.GET); + action.setActionConfiguration(actionConfiguration); + action.setDatasource(datasource); + + // Create the action and validate default values + ActionDTO createdAction = + layoutActionService.createSingleAction(action, Boolean.FALSE).block(); + assertNotNull(createdAction); + assertEquals(RunBehaviorEnum.MANUAL, createdAction.getRunBehavior()); + assertEquals(Boolean.FALSE, createdAction.getExecuteOnLoad()); + + // Test setting executeOnLoad to TRUE + ActionDTO updatedAction = layoutActionService + .setExecuteOnLoad(createdAction.getId(), Boolean.TRUE) + .block(); + assertNotNull(updatedAction); + assertEquals(RunBehaviorEnum.ON_PAGE_LOAD, updatedAction.getRunBehavior()); + assertEquals(Boolean.TRUE, updatedAction.getExecuteOnLoad()); + + // Test setting executeOnLoad to FALSE + updatedAction = layoutActionService + .setExecuteOnLoad(createdAction.getId(), Boolean.FALSE) + .block(); + assertNotNull(updatedAction); + assertEquals(RunBehaviorEnum.MANUAL, updatedAction.getRunBehavior()); + assertEquals(Boolean.FALSE, updatedAction.getExecuteOnLoad()); + } }