diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/BuildingBlockResponseDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/BuildingBlockResponseDTO.java index 1b31474357..ff4b6fa0ce 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/BuildingBlockResponseDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/BuildingBlockResponseDTO.java @@ -1,10 +1,9 @@ package com.appsmith.server.dtos; import com.appsmith.external.dtos.DslExecutableDTO; +import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.Datasource; -import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.CustomJSLib; -import com.appsmith.server.domains.NewAction; import lombok.Data; import java.util.List; @@ -16,10 +15,7 @@ public class BuildingBlockResponseDTO { List onPageLoadActions; // New actions created in the current flow - List newActionList; - - // New actionCollection created in the current flow - List actionCollectionList; + List newActionList; // All datasource in the workspace List datasourceList; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java index df841c64d4..2f18023cde 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceCEImpl.java @@ -2,6 +2,7 @@ package com.appsmith.server.imports.internal.partial; import com.appsmith.external.constants.AnalyticsEvents; import com.appsmith.external.helpers.Stopwatch; +import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.Datasource; import com.appsmith.server.acl.AclPermission; @@ -30,6 +31,7 @@ import com.appsmith.server.helpers.ImportArtifactPermissionProvider; import com.appsmith.server.imports.importable.ImportableService; import com.appsmith.server.imports.internal.ImportService; import com.appsmith.server.jslibs.base.CustomJSLibService; +import com.appsmith.server.layouts.UpdateLayoutService; import com.appsmith.server.newactions.base.NewActionService; import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.refactors.applications.RefactoringService; @@ -50,6 +52,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.codec.multipart.Part; import org.springframework.transaction.reactive.TransactionalOperator; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -58,10 +62,11 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.appsmith.server.constants.ce.FieldNameCE.WORKSPACE_ID; + @RequiredArgsConstructor @Slf4j public class PartialImportServiceCEImpl implements PartialImportServiceCE { @@ -93,6 +98,7 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE { private final ActionCollectionService actionCollectionService; private final DatasourceService datasourceService; private final CustomJSLibService customJSLibService; + private final UpdateLayoutService updateLayoutService; @Override public Mono importResourceInPage( @@ -422,6 +428,9 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE { Mono applicationJsonMono = applicationTemplateService.getApplicationJsonFromTemplate(buildingBlockDTO.getTemplateId()); + Mono branchedPageIdMono = + newPageService.findBranchedPageId(branchName, buildingBlockDTO.getPageId(), AclPermission.MANAGE_PAGES); + Stopwatch processStopwatch = new Stopwatch("Download Content from Cloud service"); return applicationJsonMono.flatMap(applicationJson -> { processStopwatch.stopAndLogTimeInMillis(); @@ -432,7 +441,10 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE { buildingBlockDTO.getPageId(), branchName, applicationJson) - .flatMap(buildingBlockImportDTO -> { + .zipWith(branchedPageIdMono) + .flatMap(tuple -> { + BuildingBlockImportDTO buildingBlockImportDTO = tuple.getT1(); + String branchedPageId = tuple.getT2(); processStopwatch1.stopAndLogTimeInMillis(); // Fetch layout and get new onPageLoadActions // This data is not present in a client, since these are created @@ -441,117 +453,77 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE { buildingBlockResponseDTO.setWidgetDsl(buildingBlockImportDTO.getWidgetDsl()); buildingBlockResponseDTO.setOnPageLoadActions(new ArrayList<>()); - Set newOnPageLoadActionNames = new HashSet<>(); - applicationJson - .getPageList() - .get(0) - .getPublishedPage() - .getLayouts() - .get(0) - .getLayoutOnLoadActions() - .forEach(dslExecutableDTOS -> { - dslExecutableDTOS.forEach(dslExecutableDTO -> { - if (dslExecutableDTO.getName() != null) { - // Use the refactored names to get the correct ids - if (buildingBlockImportDTO - .getRefactoredEntityNameMap() - .get(dslExecutableDTO.getName()) - != null) { - dslExecutableDTO.setName(buildingBlockImportDTO - .getRefactoredEntityNameMap() - .get(dslExecutableDTO.getName())); - } - newOnPageLoadActionNames.add( - dslExecutableDTO.getName().contains(".") - ? dslExecutableDTO.getName() - .split("\\.")[0] - : dslExecutableDTO.getName()); - buildingBlockResponseDTO - .getOnPageLoadActions() - .add(dslExecutableDTO); - } - }); - }); // Fetch the datasource and customJsLibs - Mono> datasourceList = datasourceService - .getAllByWorkspaceIdWithStorages( - buildingBlockDTO.getWorkspaceId(), AclPermission.MANAGE_DATASOURCES) - .collectList(); + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add(WORKSPACE_ID, buildingBlockDTO.getWorkspaceId()); + Mono> datasourceList = + datasourceService.getAllWithStorages(params).collectList(); + Mono> customJSLibs = customJSLibService.getAllJSLibsInContext( buildingBlockDTO.getApplicationId(), CreatorContextType.APPLICATION, branchName, false); - // Fetch all actions and action collections and update the onPageLoadActions with correct ids - return Mono.zip( - actionCollectionService - .findByPageId(buildingBlockDTO.getPageId()) - .collectList(), - newActionService - .findByPageId(buildingBlockDTO.getPageId()) - .collectList(), - datasourceList, - customJSLibs) - .flatMap(tuple -> { - List actionCollections = tuple.getT1(); - List newActions = tuple.getT2(); + Mono> actionList = newActionService + .getUnpublishedActionsByPageId(branchedPageId, AclPermission.MANAGE_ACTIONS) + .collectList(); - buildingBlockResponseDTO.setDatasourceList(tuple.getT3()); - buildingBlockResponseDTO.setCustomJSLibList(tuple.getT4()); - // Filter the newly created actions and actionCollection - buildingBlockResponseDTO.setNewActionList(newActions.stream() - .filter(newAction -> buildingBlockImportDTO - .getRefactoredEntityNameMap() - .containsValue(newAction - .getUnpublishedAction() - .getName())) - .toList()); - buildingBlockResponseDTO.setActionCollectionList(actionCollections.stream() - .filter(actionCollection -> buildingBlockImportDTO - .getRefactoredEntityNameMap() - .containsValue(actionCollection - .getUnpublishedCollection() - .getName())) - .toList()); + MultiValueMap params1 = new LinkedMultiValueMap<>(); + params1.add(FieldName.PAGE_ID, branchedPageId); + newActionService.getUnpublishedActions(params1, branchName); - actionCollections.forEach(actionCollection -> { - if (newOnPageLoadActionNames.contains(actionCollection - .getUnpublishedCollection() - .getName())) { - buildingBlockResponseDTO - .getOnPageLoadActions() - .forEach(dslExecutableDTO -> { - if (dslExecutableDTO.getCollectionId() != null) { - String name = dslExecutableDTO.getCollectionId() - .split("_")[1]; - if (name.equals(actionCollection - .getUnpublishedCollection() - .getName())) { - dslExecutableDTO.setId(actionCollection.getId()); - dslExecutableDTO.setCollectionId( - actionCollection.getId()); - } - } - }); - } - }); + List newActionNames = applicationJson.getActionList().stream() + .map(newAction -> + newAction.getUnpublishedAction().getName()) + .toList(); - newActions.forEach(newAction -> { - if (newOnPageLoadActionNames.contains( - newAction.getUnpublishedAction().getName())) { - buildingBlockResponseDTO - .getOnPageLoadActions() - .forEach(dslExecutableDTO -> { - if (dslExecutableDTO - .getName() - .equals(newAction - .getUnpublishedAction() - .getName())) { - dslExecutableDTO.setId(newAction.getId()); - } - }); - } - }); + return newPageService + .findByBranchNameAndDefaultPageId( + branchName, buildingBlockDTO.getPageId(), AclPermission.MANAGE_PAGES) + .flatMap(newPage -> { + String layoutId = newPage.getUnpublishedPage() + .getLayouts() + .get(0) + .getId(); + Layout layout = applicationJson + .getPageList() + .get(0) + .getUnpublishedPage() + .getLayouts() + .get(0); + layout.setDsl(widgetRefactorUtil.convertDslStringToJSONObject( + buildingBlockImportDTO.getWidgetDsl())); + // fetch the layout and get the onPageLoadActions + return updateLayoutService + .getOnPageLoadActions( + buildingBlockDTO.getPageId(), + layoutId, + layout, + buildingBlockImportDTO + .getApplication() + .getEvaluationVersion(), + CreatorContextType.PAGE) + .flatMap(layoutDTO -> { + layoutDTO.forEach(actionSet -> { + buildingBlockResponseDTO + .getOnPageLoadActions() + .addAll(actionSet.stream() + .toList()); + }); - return Mono.just(buildingBlockResponseDTO); + return Mono.zip(datasourceList, customJSLibs, actionList); + }) + .map(tuple3 -> { + buildingBlockResponseDTO.setDatasourceList(tuple3.getT1()); + buildingBlockResponseDTO.setCustomJSLibList(tuple3.getT2()); + buildingBlockResponseDTO.setNewActionList(tuple3.getT3()); + return buildingBlockResponseDTO; + }); + }) + // Remove the existing actions in the page from the newActions list + .flatMap(buildingBlockResponseDTO1 -> { + buildingBlockResponseDTO1 + .getNewActionList() + .removeIf(actionDTO -> !newActionNames.contains(actionDTO.getName())); + return Mono.just(buildingBlockResponseDTO1); }); }); }); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceImpl.java index 1e9638bef4..48fe93526e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/imports/internal/partial/PartialImportServiceImpl.java @@ -12,6 +12,7 @@ import com.appsmith.server.domains.Plugin; import com.appsmith.server.imports.importable.ImportableService; import com.appsmith.server.imports.internal.ImportService; import com.appsmith.server.jslibs.base.CustomJSLibService; +import com.appsmith.server.layouts.UpdateLayoutService; import com.appsmith.server.newactions.base.NewActionService; import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.refactors.applications.RefactoringService; @@ -64,7 +65,8 @@ public class PartialImportServiceImpl extends PartialImportServiceCEImpl impleme NewActionService newActionService, ActionCollectionService actionCollectionService, DatasourceService datasourceService, - CustomJSLibService customJSLibService) { + CustomJSLibService customJSLibService, + UpdateLayoutService updateLayoutService) { super( importService, workspaceService, @@ -92,6 +94,7 @@ public class PartialImportServiceImpl extends PartialImportServiceCEImpl impleme newActionService, actionCollectionService, datasourceService, - customJSLibService); + customJSLibService, + updateLayoutService); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCE.java index 6d53ad2fbc..ed625f2185 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCE.java @@ -1,11 +1,16 @@ package com.appsmith.server.layouts; +import com.appsmith.external.dtos.DslExecutableDTO; +import com.appsmith.external.models.CreatorContextType; import com.appsmith.server.domains.Layout; import com.appsmith.server.dtos.LayoutDTO; import com.appsmith.server.dtos.UpdateMultiplePageLayoutDTO; import net.minidev.json.JSONObject; import reactor.core.publisher.Mono; +import java.util.List; +import java.util.Set; + public interface UpdateLayoutServiceCE { Mono updateLayout(String pageId, String applicationId, String layoutId, Layout layout); @@ -18,4 +23,7 @@ public interface UpdateLayoutServiceCE { JSONObject unescapeMongoSpecialCharacters(Layout layout); Mono updatePageLayoutsByPageId(String pageId); + + Mono>> getOnPageLoadActions( + String creatorId, String layoutId, Layout layout, Integer evaluatedVersion, CreatorContextType creatorType); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCEImpl.java index e0124e3b94..15119edadb 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/layouts/UpdateLayoutServiceCEImpl.java @@ -304,6 +304,67 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE { .then(Mono.just(pageId)); } + @Override + public Mono>> getOnPageLoadActions( + String creatorId, + String layoutId, + Layout layout, + Integer evaluatedVersion, + CreatorContextType creatorType) { + JSONObject dsl = layout.getDsl(); + if (dsl == null) { + // There is no DSL here. No need to process anything. Return as is. + return Mono.just(new ArrayList<>()); + } + + Set widgetNames = new HashSet<>(); + Map> widgetDynamicBindingsMap = new HashMap<>(); + Set escapedWidgetNames = new HashSet<>(); + try { + dsl = extractAllWidgetNamesAndDynamicBindingsFromDSL( + dsl, widgetNames, widgetDynamicBindingsMap, creatorId, layoutId, escapedWidgetNames, creatorType); + } catch (Throwable t) { + return sendUpdateLayoutAnalyticsEvent(creatorId, layoutId, dsl, false, t, creatorType) + .then(Mono.error(t)); + } + + layout.setWidgetNames(widgetNames); + + if (!escapedWidgetNames.isEmpty()) { + layout.setMongoEscapedWidgetNames(escapedWidgetNames); + } + Set edges = new HashSet<>(); + Set executablesUsedInDSL = new HashSet<>(); + List flatmapOnLoadExecutables = new ArrayList<>(); + + AtomicReference validOnLoadExecutables = new AtomicReference<>(Boolean.TRUE); + + // setting the layoutOnLoadActionActionErrors to empty to remove the existing errors before new DAG calculation. + layout.setLayoutOnLoadActionErrors(new ArrayList<>()); + + return onLoadExecutablesUtil + .findAllOnLoadExecutables( + creatorId, + evaluatedVersion, + widgetNames, + edges, + widgetDynamicBindingsMap, + flatmapOnLoadExecutables, + executablesUsedInDSL, + creatorType) + .onErrorResume(AppsmithException.class, error -> { + log.info(error.getMessage()); + validOnLoadExecutables.set(FALSE); + layout.setLayoutOnLoadActionErrors(List.of(new ErrorDTO( + error.getAppErrorCode(), + error.getErrorType(), + layoutOnLoadActionErrorToastMessage, + error.getMessage(), + error.getTitle()))); + return Mono.just(new ArrayList<>()); + }); + } + private JSONObject unEscapeDslKeys(JSONObject dsl, Set escapedWidgetNames) { String widgetName = (String) dsl.get(FieldName.WIDGET_NAME); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/widgets/refactors/WidgetRefactorUtil.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/widgets/refactors/WidgetRefactorUtil.java index f46860ae7a..18b7301580 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/widgets/refactors/WidgetRefactorUtil.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/widgets/refactors/WidgetRefactorUtil.java @@ -2,6 +2,8 @@ package com.appsmith.server.widgets.refactors; import com.appsmith.external.models.MustacheBindingToken; import com.appsmith.server.constants.FieldName; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.DslUtils; import com.appsmith.server.services.AstService; import com.fasterxml.jackson.databind.JsonNode; @@ -10,7 +12,10 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; +import net.minidev.json.parser.ParseException; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -24,6 +29,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +@Slf4j @Component @RequiredArgsConstructor public class WidgetRefactorUtil { @@ -197,4 +203,14 @@ public class WidgetRefactorUtil { public JsonNode convertDslStringToJsonNode(JSONObject dsl) { return objectMapper.convertValue(dsl, JsonNode.class); } + + public JSONObject convertDslStringToJSONObject(String dsl) { + JSONParser jsonParser = new JSONParser(); + try { + return (JSONObject) jsonParser.parse(dsl); + } catch (ParseException exception) { + log.error("Error parsing the page dsl for page: {}", exception.getMessage()); + throw new AppsmithException(AppsmithError.JSON_PROCESSING_ERROR); + } + } }