diff --git a/app/client/cypress/fixtures/dropDownWidget_reset_check_dsl.json b/app/client/cypress/fixtures/dropDownWidget_reset_check_dsl.json index 20a89a0058..6f36dcd53f 100644 --- a/app/client/cypress/fixtures/dropDownWidget_reset_check_dsl.json +++ b/app/client/cypress/fixtures/dropDownWidget_reset_check_dsl.json @@ -20,274 +20,6 @@ "dynamicBindingPathList": [], "leftColumn": 0, "children": [ - { - "widgetName": "Table1", - "defaultPageSize": 0, - "columnOrder": [ - "id", - "gender", - "latitude", - "longitude", - "dob", - "phone", - "email", - "image", - "country", - "name" - ], - "isVisibleDownload": true, - "dynamicPropertyPathList": [ - { - "key": "tableData" - } - ], - "displayName": "Table", - "iconSVG": "/static/media/icon.db8a9cbd.svg", - "topRow": 45, - "bottomRow": 86, - "isSortable": true, - "parentRowSpace": 10, - "type": "TABLE_WIDGET", - "defaultSelectedRow": "0", - "hideCard": false, - "animateLoading": true, - "parentColumnSpace": 33.375, - "dynamicTriggerPathList": [], - "dynamicBindingPathList": [ - { - "key": "tableData" - }, - { - "key": "primaryColumns.id.computedValue" - }, - { - "key": "primaryColumns.gender.computedValue" - }, - { - "key": "primaryColumns.latitude.computedValue" - }, - { - "key": "primaryColumns.longitude.computedValue" - }, - { - "key": "primaryColumns.dob.computedValue" - }, - { - "key": "primaryColumns.phone.computedValue" - }, - { - "key": "primaryColumns.email.computedValue" - }, - { - "key": "primaryColumns.image.computedValue" - }, - { - "key": "primaryColumns.country.computedValue" - }, - { - "key": "primaryColumns.name.computedValue" - } - ], - "leftColumn": 6, - "primaryColumns": { - "id": { - "index": 0, - "width": 150, - "id": "id", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "id", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.id))}}" - }, - "gender": { - "index": 1, - "width": 150, - "id": "gender", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "gender", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.gender))}}" - }, - "latitude": { - "index": 2, - "width": 150, - "id": "latitude", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "latitude", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.latitude))}}" - }, - "longitude": { - "index": 3, - "width": 150, - "id": "longitude", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "longitude", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.longitude))}}" - }, - "dob": { - "index": 4, - "width": 150, - "id": "dob", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "dob", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.dob))}}" - }, - "phone": { - "index": 5, - "width": 150, - "id": "phone", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "phone", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.phone))}}" - }, - "email": { - "index": 6, - "width": 150, - "id": "email", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "email", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.email))}}" - }, - "image": { - "index": 7, - "width": 150, - "id": "image", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "image", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.image))}}" - }, - "country": { - "index": 8, - "width": 150, - "id": "country", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "country", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.country))}}" - }, - "name": { - "index": 9, - "width": 150, - "id": "name", - "horizontalAlignment": "LEFT", - "verticalAlignment": "CENTER", - "columnType": "text", - "textSize": "PARAGRAPH", - "enableFilter": true, - "enableSort": true, - "isVisible": true, - "isDisabled": false, - "isCellVisible": true, - "isDerived": false, - "label": "name", - "computedValue": "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.name))}}" - } - }, - "delimiter": ",", - "key": "zwrlfvfuz3", - "derivedColumns": {}, - "rightColumn": 46, - "textSize": "PARAGRAPH", - "widgetId": "52lm2cgbcq", - "isVisibleFilters": true, - "tableData": "{{GetAllUsers.data}}", - "isVisible": true, - "label": "Data", - "searchKey": "", - "enableClientSideSearch": true, - "version": 3, - "totalRecordsCount": 0, - "parentId": "0", - "renderMode": "CANVAS", - "isLoading": false, - "horizontalAlignment": "LEFT", - "isVisibleSearch": true, - "isVisiblePagination": true, - "verticalAlignment": "CENTER", - "columnSizeMap": { - "task": 245, - "step": 62, - "status": 75 - } - }, { "widgetName": "Select2", "isFilterable": false, diff --git a/app/client/cypress/integration/Smoke_TestSuite/Application/ImportExportForkApplication_spec.js b/app/client/cypress/integration/Smoke_TestSuite/Application/ImportExportForkApplication_spec.js index 5e8f76237b..a8c5fbea0e 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/Application/ImportExportForkApplication_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/Application/ImportExportForkApplication_spec.js @@ -1,3 +1,5 @@ +/// + const homePage = require("../../../locators/HomePage.json"); //const dsl = require("../../../fixtures/forkedApp.json"); @@ -6,7 +8,7 @@ describe("Import, Export and Fork application and validate data binding", functi let appid; let newOrganizationName; - it("Import application and validate data on pageload", function() { + it("1. Import application and validate data on pageload", function() { // import application cy.get(homePage.homeIcon).click(); cy.get(homePage.optionsIcon) @@ -14,13 +16,19 @@ describe("Import, Export and Fork application and validate data binding", functi .click(); cy.get(homePage.orgImportAppOption).click({ force: true }); cy.get(homePage.orgImportAppModal).should("be.visible"); - cy.xpath(homePage.uploadLogo).attachFile("forkedApp.json"); - cy.get(homePage.orgImportAppButton).click({ force: true }); + cy.xpath(homePage.uploadLogo) + .attachFile("forkedApp.json") + .wait(500); + cy.get(homePage.orgImportAppButton) + .trigger("click") + .wait(500); + cy.get(homePage.orgImportAppModal).should("not.exist"); + cy.wait("@importNewApplication").then((interception) => { - //let appId = interception.response.body.data.id; - // let defaultPage = interception.response.body.data.pages.find( - // (eachPage) => !!eachPage.isDefault, - // ); + let appId = interception.response.body.data.id; + let defaultPage = interception.response.body.data.pages.find( + (eachPage) => !!eachPage.isDefault, + ); cy.get(homePage.toastMessage).should( "contain", @@ -43,7 +51,7 @@ describe("Import, Export and Fork application and validate data binding", functi }); }); - it("Fork application and validate data binding for the widgets", function() { + it("2. Fork application and validate data binding for the widgets", function() { // fork application cy.get(homePage.homeIcon).click(); cy.get(homePage.searchInput).type(`${this.appname}`); @@ -69,7 +77,7 @@ describe("Import, Export and Fork application and validate data binding", functi cy.xpath("//div[text()='Recusan']").should("be.visible"); }); - it("Export and import application and validate data binding for the widgets", function() { + it("3. Export and import application and validate data binding for the widgets", function() { cy.NavigateToHome(); cy.get(homePage.searchInput) .clear() diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DropDownWidget_value_reset_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DropDownWidget_value_reset_spec.js index ed4f072d42..a56d5ce740 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DropDownWidget_value_reset_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DropDownWidget_value_reset_spec.js @@ -8,6 +8,7 @@ describe("Dropdown Widget Check value does not reset on navigation", function() it("check if the dropdown value does not change on navigation", function() { //Change the value of drop down; + cy.wait(4000); //settling time for dsl into layout cy.get(".t--draggable-selectwidget .bp3-popover-target") .first() .click(); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/DslActionDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/DslActionDTO.java index cd1cf2b212..6bbff9df07 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/DslActionDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/DslActionDTO.java @@ -19,6 +19,8 @@ public class DslActionDTO { String id; @JsonIgnore String defaultActionId; + @JsonIgnore + String defaultCollectionId; String name; String collectionId; Boolean clientSideExecution; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/DefaultResourcesUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/DefaultResourcesUtils.java index 23ec2c0af9..6dad56a690 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/DefaultResourcesUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/DefaultResourcesUtils.java @@ -6,11 +6,14 @@ import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; import com.appsmith.server.dtos.ActionCollectionDTO; import com.appsmith.server.dtos.ActionDTO; +import com.appsmith.server.dtos.DslActionDTO; +import com.appsmith.server.dtos.PageDTO; import org.apache.commons.lang3.StringUtils; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.Set; public class DefaultResourcesUtils { public static T createDefaultIdsOrUpdateWithGivenResourceIds(T resource, String branchName) { @@ -61,10 +64,10 @@ public class DefaultResourcesUtils { } else if (resource instanceof NewPage) { NewPage page = (NewPage) resource; DefaultResources pageDefaultResources = page.getDefaultResources(); - boolean updateOnLoadActionTemp = false; + boolean updateOnLoadAction = false; if (Optional.ofNullable(pageDefaultResources).isEmpty()) { pageDefaultResources = new DefaultResources(); - updateOnLoadActionTemp = true; + updateOnLoadAction = true; } final String defaultApplicationId = StringUtils.isEmpty(pageDefaultResources.getApplicationId()) @@ -79,37 +82,10 @@ public class DefaultResourcesUtils { pageDefaultResources.setBranchName(branchName); // Copy layoutOnLoadAction Ids to defaultPageId - final boolean updateOnLoadAction = updateOnLoadActionTemp; - page.getUnpublishedPage() - .getLayouts() - .forEach(layout -> { - if (!CollectionUtils.isNullOrEmpty(layout.getLayoutOnLoadActions())) { - layout.getLayoutOnLoadActions() - .forEach(dslActionDTOS -> dslActionDTOS - .forEach(actionDTO -> { - if (updateOnLoadAction || StringUtils.isEmpty(actionDTO.getDefaultActionId())) { - actionDTO.setDefaultActionId(actionDTO.getId()); - } - }) - ); - } - }); + updateOnLoadActionAndCollectionIds(page.getUnpublishedPage(), updateOnLoadAction); if (page.getPublishedPage() != null && !CollectionUtils.isNullOrEmpty(page.getPublishedPage().getLayouts())) { - page.getPublishedPage() - .getLayouts() - .forEach(layout -> { - if (!CollectionUtils.isNullOrEmpty(layout.getLayoutOnLoadActions())) { - layout.getLayoutOnLoadActions() - .forEach(dslActionDTOS -> dslActionDTOS - .forEach(actionDTO -> { - if (updateOnLoadAction || StringUtils.isEmpty(actionDTO.getDefaultActionId())) { - actionDTO.setDefaultActionId(actionDTO.getId()); - } - }) - ); - } - }); + updateOnLoadActionAndCollectionIds(page.getPublishedPage(), updateOnLoadAction); } page.setDefaultResources(pageDefaultResources); } else if (resource instanceof ActionCollection) { @@ -165,4 +141,20 @@ public class DefaultResourcesUtils { } return resource; } + + static void updateOnLoadActionAndCollectionIds(PageDTO page, boolean shouldUpdate) { + page.getLayouts() + .forEach(layout -> { + if (!CollectionUtils.isNullOrEmpty(layout.getLayoutOnLoadActions())) { + for (Set layoutOnLoadAction : layout.getLayoutOnLoadActions()) { + for (DslActionDTO dslActionDTO : layoutOnLoadAction) { + if (shouldUpdate || StringUtils.isEmpty(dslActionDTO.getDefaultActionId())) { + dslActionDTO.setDefaultActionId(dslActionDTO.getId()); + dslActionDTO.setDefaultCollectionId(dslActionDTO.getCollectionId()); + } + } + } + } + }); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitFileUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitFileUtils.java index 9c5a7ae822..f3449bb1c0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitFileUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitFileUtils.java @@ -313,7 +313,10 @@ public class GitFileUtils { TreeSet sortedActions = new TreeSet<>(new CompareDslActionDTO()); sortedActions.addAll(layoutOnLoadActions.get(dslActionIndex)); sortedActions - .forEach(actionDTO -> actionDTO.setDefaultActionId(null)); + .forEach(actionDTO -> { + actionDTO.setDefaultActionId(null); + actionDTO.setDefaultCollectionId(null); + }); layoutOnLoadActions.set(dslActionIndex, sortedActions); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ResponseUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ResponseUtils.java index 0047ed0678..07db41265c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ResponseUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/ResponseUtils.java @@ -50,15 +50,9 @@ public class ResponseUtils { page.setId(defaultResourceIds.getPageId()); page.getLayouts() - .stream().filter(layout -> !CollectionUtils.isEmpty(layout.getLayoutOnLoadActions())) - .forEach(layout -> layout.getLayoutOnLoadActions() - .forEach(dslActionDTOS -> dslActionDTOS - .forEach(actionDTO -> { - if (!StringUtils.isEmpty(actionDTO.getDefaultActionId())) { - actionDTO.setId(actionDTO.getDefaultActionId()); - } - })) - ); + .stream() + .filter(layout -> !CollectionUtils.isEmpty(layout.getLayoutOnLoadActions())) + .forEach(layout -> this.updateLayoutWithDefaultResources(layout)); return page; } @@ -151,6 +145,9 @@ public class ResponseUtils { if (!StringUtils.isEmpty(onLoadAction.getDefaultActionId())) { onLoadAction.setId(onLoadAction.getDefaultActionId()); } + if (!StringUtils.isEmpty(onLoadAction.getDefaultCollectionId())) { + onLoadAction.setCollectionId(onLoadAction.getDefaultCollectionId()); + } }) ); } @@ -164,6 +161,9 @@ public class ResponseUtils { if (!StringUtils.isEmpty(onLoadAction.getDefaultActionId())) { onLoadAction.setId(onLoadAction.getDefaultActionId()); } + if (!StringUtils.isEmpty(onLoadAction.getDefaultCollectionId())) { + onLoadAction.setCollectionId(onLoadAction.getDefaultCollectionId()); + } })); } return layout; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ExamplesOrganizationClonerCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ExamplesOrganizationClonerCEImpl.java index b498edce03..b011ac9ac5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ExamplesOrganizationClonerCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ExamplesOrganizationClonerCEImpl.java @@ -281,6 +281,8 @@ public class ExamplesOrganizationClonerCEImpl implements ExamplesOrganizationClo // `clonedPages` list will also contain all pages cloned. .collect(HashMap::new, (map, tuple2) -> map.put(tuple2.getT2(), tuple2.getT1())) .flatMap(actionIdsMap -> { + // Map of + HashMap collectionIdsMap = new HashMap<>(); // Pick all action collections return actionCollectionService .findByPageId(templatePageId) @@ -326,34 +328,35 @@ public class ExamplesOrganizationClonerCEImpl implements ExamplesOrganizationClo unpublishedCollection.setDefaultToBranchedActionIdsMap(newActionIds); return actionCollectionService.create(actionCollection) - .flatMap(newActionCollection -> { - if (StringUtils.isEmpty(newActionCollection.getDefaultResources().getCollectionId())) { + .flatMap(clonedActionCollection -> { + if (StringUtils.isEmpty(clonedActionCollection.getDefaultResources().getCollectionId())) { ActionCollection updates = new ActionCollection(); - DefaultResources defaultResources2 = newActionCollection.getDefaultResources(); - defaultResources2.setCollectionId(newActionCollection.getId()); + DefaultResources defaultResources2 = clonedActionCollection.getDefaultResources(); + defaultResources2.setCollectionId(clonedActionCollection.getId()); updates.setDefaultResources(defaultResources2); - return actionCollectionService.update(newActionCollection.getId(), updates); + return actionCollectionService.update(clonedActionCollection.getId(), updates); } - return Mono.just(newActionCollection); + return Mono.just(clonedActionCollection); }) - .flatMap(newlyCreatedActionCollection -> { + .flatMap(clonedActionCollection -> { + collectionIdsMap.put(originalCollectionId, clonedActionCollection.getId()); return Flux.fromIterable(newActionIds.values()) .flatMap(newActionService::findById) .flatMap(newlyCreatedAction -> { ActionDTO unpublishedAction = newlyCreatedAction.getUnpublishedAction(); - unpublishedAction.setCollectionId(newlyCreatedActionCollection.getId()); - unpublishedAction.getDefaultResources().setCollectionId(newlyCreatedActionCollection.getId()); + unpublishedAction.setCollectionId(clonedActionCollection.getId()); + unpublishedAction.getDefaultResources().setCollectionId(clonedActionCollection.getId()); return newActionService.update(newlyCreatedAction.getId(), newlyCreatedAction); }) .collectList(); }); }) .collectList() - .thenReturn(actionIdsMap); + .then(Mono.zip(Mono.just(actionIdsMap), Mono.just(collectionIdsMap))); }); }); }) - .flatMap(actionIdsMap -> updateActionIdsInClonedPages(clonedPages, actionIdsMap)) + .flatMap(tuple -> updateActionAndCollectionsIdsInClonedPages(clonedPages, tuple.getT1(), tuple.getT2())) // Now publish all the example applications which have been cloned to ensure that there is a // view mode for the newly created user. .then(Mono.just(newApplicationIds)) @@ -362,7 +365,9 @@ public class ExamplesOrganizationClonerCEImpl implements ExamplesOrganizationClo .collectList(); } - private Flux updateActionIdsInClonedPages(List clonedPages, Map actionIdsMap) { + private Flux updateActionAndCollectionsIdsInClonedPages(List clonedPages, + Map actionIdsMap, + Map actionCollectionIdsMap) { final List> pageSaveMonos = new ArrayList<>(); for (final NewPage page : clonedPages) { @@ -376,7 +381,7 @@ public class ExamplesOrganizationClonerCEImpl implements ExamplesOrganizationClo for (final Layout layout : page.getUnpublishedPage().getLayouts()) { if (layout.getLayoutOnLoadActions() != null) { - shouldSave = updateOnLoadActionsWithNewActionIds(actionIdsMap, page.getId(), shouldSave, layout); + shouldSave = updateOnLoadActionsWithNewActionAndCollectionIds(actionIdsMap, actionCollectionIdsMap, page.getId(), shouldSave, layout); } } @@ -388,13 +393,22 @@ public class ExamplesOrganizationClonerCEImpl implements ExamplesOrganizationClo return Flux.concat(pageSaveMonos); } - private boolean updateOnLoadActionsWithNewActionIds(Map actionIdsMap, String pageId, boolean shouldSave, Layout layout) { + private boolean updateOnLoadActionsWithNewActionAndCollectionIds(Map actionIdsMap, + Map collectionIdsMap, + String pageId, + boolean shouldSave, + Layout layout) { for (final Set actionSet : layout.getLayoutOnLoadActions()) { for (final DslActionDTO actionDTO : actionSet) { if (actionIdsMap.containsKey(actionDTO.getId())) { final String srcActionId = actionDTO.getId(); + final String srcCollectionId = actionDTO.getCollectionId(); actionDTO.setId(actionIdsMap.get(srcActionId)); actionDTO.setDefaultActionId(actionIdsMap.get(srcActionId)); + if (StringUtils.hasLength(srcCollectionId)) { + actionDTO.setDefaultCollectionId(collectionIdsMap.get(actionDTO.getCollectionId())); + actionDTO.setCollectionId(collectionIdsMap.get(actionDTO.getCollectionId())); + } shouldSave = true; } else { log.error( diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java index 0d1b8fc3c4..bfaadcc38e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ImportExportApplicationServiceCEImpl.java @@ -545,10 +545,13 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica Map datasourceMap = new HashMap<>(); Map pageNameMap = new HashMap<>(); Map actionIdMap = new HashMap<>(); - Map> unpublishedActionCollectionIdMap = new HashMap<>(); - Map> publishedActionCollectionIdMap = new HashMap<>(); - Map unpublishedActionIdToCollectionIdMap = new HashMap<>(); - Map publishedActionIdToCollectionIdMap = new HashMap<>(); + // Datastructures to create a link between collectionId to embedded action ids + Map> unpublishedCollectionIdToActionIdsMap = new HashMap<>(); + Map> publishedCollectionIdToActionIdsMap = new HashMap<>(); + // Datastructures to create a link between actionIds to collectionIds + // + Map> unpublishedActionIdToCollectionIdMap = new HashMap<>(); + Map> publishedActionIdToCollectionIdMap = new HashMap<>(); Application importedApplication = importedDoc.getExportedApplication(); List importedDatasourceList = importedDoc.getDatasourceList(); @@ -911,8 +914,8 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica ); if (unpublishedAction.getCollectionId() != null) { - unpublishedActionCollectionIdMap.putIfAbsent(unpublishedAction.getCollectionId(), new HashMap<>()); - final Map actionIds = unpublishedActionCollectionIdMap.get(unpublishedAction.getCollectionId()); + unpublishedCollectionIdToActionIdsMap.putIfAbsent(unpublishedAction.getCollectionId(), new HashMap<>()); + final Map actionIds = unpublishedCollectionIdToActionIdsMap.get(unpublishedAction.getCollectionId()); actionIds.put(newAction.getDefaultResources().getActionId(), newAction.getId()); } } @@ -924,8 +927,8 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica ); if (publishedAction.getCollectionId() != null) { - publishedActionCollectionIdMap.putIfAbsent(publishedAction.getCollectionId(), new HashMap<>()); - final Map actionIds = publishedActionCollectionIdMap.get(publishedAction.getCollectionId()); + publishedCollectionIdToActionIdsMap.putIfAbsent(publishedAction.getCollectionId(), new HashMap<>()); + final Map actionIds = publishedCollectionIdToActionIdsMap.get(publishedAction.getCollectionId()); actionIds.put(newAction.getDefaultResources().getActionId(), newAction.getId()); } } @@ -957,13 +960,13 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica final String fallbackParentPageId = unpublishedCollection.getPageId(); if (unpublishedCollection.getName() != null) { - unpublishedCollection.setDefaultToBranchedActionIdsMap(unpublishedActionCollectionIdMap.get(importedActionCollectionId)); + unpublishedCollection.setDefaultToBranchedActionIdsMap(unpublishedCollectionIdToActionIdsMap.get(importedActionCollectionId)); unpublishedCollection.setPluginId(pluginMap.get(unpublishedCollection.getPluginId())); parentPage = updatePageInActionCollection(unpublishedCollection, pageNameMap); } if (publishedCollection != null && publishedCollection.getName() != null) { - publishedCollection.setDefaultToBranchedActionIdsMap(publishedActionCollectionIdMap.get(importedActionCollectionId)); + publishedCollection.setDefaultToBranchedActionIdsMap(publishedCollectionIdToActionIdsMap.get(importedActionCollectionId)); publishedCollection.setPluginId(pluginMap.get(publishedCollection.getPluginId())); if (StringUtils.isEmpty(publishedCollection.getPageId())) { publishedCollection.setPageId(fallbackParentPageId); @@ -1036,15 +1039,17 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica .flatMap(tuple -> { final String importedActionCollectionId = tuple.getT1(); final String savedActionCollectionId = tuple.getT2().getId(); - unpublishedActionCollectionIdMap + final String defaultCollectionId = tuple.getT2().getDefaultResources().getCollectionId(); + List collectionIds = List.of(savedActionCollectionId, defaultCollectionId); + unpublishedCollectionIdToActionIdsMap .getOrDefault(importedActionCollectionId, Map.of()) .forEach((defaultActionId, actionId) -> { - unpublishedActionIdToCollectionIdMap.put(actionId, savedActionCollectionId); + unpublishedActionIdToCollectionIdMap.putIfAbsent(actionId, collectionIds); }); - publishedActionCollectionIdMap + publishedCollectionIdToActionIdsMap .getOrDefault(importedActionCollectionId, Map.of()) .forEach((defaultActionId, actionId) -> { - publishedActionIdToCollectionIdMap.put(actionId, savedActionCollectionId); + publishedActionIdToCollectionIdMap.putIfAbsent(actionId, collectionIds); }); final HashSet actionIds = new HashSet<>(); actionIds.addAll(unpublishedActionIdToCollectionIdMap.keySet()); @@ -1053,10 +1058,34 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica }) .flatMap(actionId -> newActionRepository.findById(actionId, MANAGE_ACTIONS)) .map(newAction -> { - newAction.getUnpublishedAction().setCollectionId( - unpublishedActionIdToCollectionIdMap.getOrDefault(newAction.getId(), null)); - newAction.getPublishedAction().setCollectionId( - publishedActionIdToCollectionIdMap.getOrDefault(newAction.getId(), null)); + // Update collectionId and defaultCollectionIds in actionDTOs + ActionDTO unpublishedAction = newAction.getUnpublishedAction(); + ActionDTO publishedAction = newAction.getPublishedAction(); + if (!CollectionUtils.sizeIsEmpty(unpublishedActionIdToCollectionIdMap) + && !CollectionUtils.isEmpty(unpublishedActionIdToCollectionIdMap.get(newAction.getId()))) { + unpublishedAction.setCollectionId( + unpublishedActionIdToCollectionIdMap.get(newAction.getId()).get(0) + ); + if (unpublishedAction.getDefaultResources() != null + && StringUtils.isEmpty(unpublishedAction.getDefaultResources().getCollectionId())) { + + unpublishedAction.getDefaultResources().setCollectionId( + unpublishedActionIdToCollectionIdMap.get(newAction.getId()).get(1) + ); + } + } + if (!CollectionUtils.sizeIsEmpty(publishedActionIdToCollectionIdMap) + && !CollectionUtils.isEmpty(publishedActionIdToCollectionIdMap.get(newAction.getId()))) { + publishedAction.setCollectionId( + publishedActionIdToCollectionIdMap.get(newAction.getId()).get(0) + ); + + if (publishedAction.getDefaultResources() != null + && StringUtils.isEmpty(publishedAction.getDefaultResources().getCollectionId())) { + publishedAction.getDefaultResources().setCollectionId( + publishedActionIdToCollectionIdMap.get(newAction.getId()).get(1)); + } + } return newAction; }) .flatMap(newAction -> newActionService.update(newAction.getId(), newAction)) @@ -1072,7 +1101,7 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica if (newPage.getDefaultResources() != null) { newPage.getDefaultResources().setBranchName(branchName); } - return mapActionIdWithPageLayout(newPage, actionIdMap) + return mapActionAndCollectionIdWithPageLayout(newPage, actionIdMap, unpublishedActionIdToCollectionIdMap, publishedActionIdToCollectionIdMap) .flatMap(newPageService::save); }) .then(applicationService.update(importedApplication.getId(), importedApplication)) @@ -1312,7 +1341,10 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica } // This method will update the action id in saved page for layoutOnLoadAction - private Mono mapActionIdWithPageLayout(NewPage page, Map actionIdMap) { + private Mono mapActionAndCollectionIdWithPageLayout(NewPage page, + Map actionIdMap, + Map> unpublishedActionIdToCollectionIdsMap, + Map> publishedActionIdToCollectionIdsMap) { Set layoutOnLoadActions = new HashSet<>(); if (page.getUnpublishedPage().getLayouts() != null) { @@ -1322,6 +1354,10 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica layout.getLayoutOnLoadActions().forEach(onLoadAction -> onLoadAction .forEach(actionDTO -> { actionDTO.setId(actionIdMap.get(actionDTO.getId())); + if (!CollectionUtils.sizeIsEmpty(unpublishedActionIdToCollectionIdsMap) + && !CollectionUtils.isEmpty(unpublishedActionIdToCollectionIdsMap.get(actionDTO.getId()))) { + actionDTO.setCollectionId(unpublishedActionIdToCollectionIdsMap.get(actionDTO.getId()).get(0)); + } layoutOnLoadActions.add(actionDTO.getId()); })); } @@ -1335,6 +1371,10 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica layout.getLayoutOnLoadActions().forEach(onLoadAction -> onLoadAction .forEach(actionDTO -> { actionDTO.setId(actionIdMap.get(actionDTO.getId())); + if (!CollectionUtils.sizeIsEmpty(publishedActionIdToCollectionIdsMap) + && !CollectionUtils.isEmpty(publishedActionIdToCollectionIdsMap.get(actionDTO.getId()))) { + actionDTO.setCollectionId(publishedActionIdToCollectionIdsMap.get(actionDTO.getId()).get(0)); + } layoutOnLoadActions.add(actionDTO.getId()); })); } @@ -1347,25 +1387,38 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica .map(newAction -> { final String defaultActionId = newAction.getDefaultResources().getActionId(); if (page.getUnpublishedPage().getLayouts() != null) { - + final String defaultCollectionId = newAction.getUnpublishedAction().getDefaultResources().getCollectionId(); page.getUnpublishedPage().getLayouts().forEach(layout -> { if (layout.getLayoutOnLoadActions() != null) { - layout.getLayoutOnLoadActions().forEach(onLoadAction -> onLoadAction - .stream() - .filter(actionDTO -> StringUtils.equals(actionDTO.getId(), newAction.getId())) - .forEach(actionDTO -> actionDTO.setDefaultActionId(defaultActionId))); + layout.getLayoutOnLoadActions() + .forEach(onLoadAction -> onLoadAction + .stream() + .filter(actionDTO -> StringUtils.equals(actionDTO.getId(), newAction.getId())) + .forEach(actionDTO -> { + actionDTO.setDefaultActionId(defaultActionId); + actionDTO.setDefaultCollectionId(defaultCollectionId); + }) + ); } }); } if (page.getPublishedPage() != null && page.getPublishedPage().getLayouts() != null) { - page.getPublishedPage().getLayouts().forEach(layout -> { if (layout.getLayoutOnLoadActions() != null) { layout.getLayoutOnLoadActions().forEach(onLoadAction -> onLoadAction .stream() .filter(actionDTO -> StringUtils.equals(actionDTO.getId(), newAction.getId())) - .forEach(actionDTO -> actionDTO.setDefaultActionId(defaultActionId))); + .forEach(actionDTO -> { + actionDTO.setDefaultActionId(defaultActionId); + if (newAction.getPublishedAction() != null + && newAction.getPublishedAction().getDefaultResources() != null) { + actionDTO.setDefaultCollectionId( + newAction.getPublishedAction().getDefaultResources().getCollectionId() + ); + } + }) + ); } }); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PageLoadActionsUtilCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PageLoadActionsUtilCEImpl.java index 6053046430..6a03a8d7c0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PageLoadActionsUtilCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PageLoadActionsUtilCEImpl.java @@ -518,7 +518,6 @@ public class PageLoadActionsUtilCEImpl implements PageLoadActionsUtilCE { * Breadth First level by level traversal is used to compute each set of such independent actions. * * @param dag : The DAG graph containing all the edges representing dependencies between appsmith entities in the page. - * @param pageLoadActionSet * @param onPageLoadActionSet * @param actionNames : All the action names for the page * @return @@ -995,6 +994,7 @@ public class PageLoadActionsUtilCEImpl implements PageLoadActionsUtilCE { dslActionDTO.setClientSideExecution(actionDTO.getClientSideExecution()); if (actionDTO.getDefaultResources() != null) { dslActionDTO.setDefaultActionId(actionDTO.getDefaultResources().getActionId()); + dslActionDTO.setDefaultCollectionId(actionDTO.getDefaultResources().getCollectionId()); } if (actionDTO.getActionConfiguration() != null) { diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java index f5cb22fdbf..c6de905dd2 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java @@ -1207,6 +1207,14 @@ public class ApplicationServiceTest { testWidget.put("testField", "{{ cloneActionTest.data }}"); children.add(testWidget); + JSONObject secondWidget = new JSONObject(); + secondWidget.put("widgetName", "secondWidget"); + temp = new JSONArray(); + temp.addAll(List.of(new JSONObject(Map.of("key", "testField1")))); + secondWidget.put("dynamicBindingPathList", temp); + secondWidget.put("testField1", "{{ testCollection1.cloneActionCollection1.data }}"); + children.add(secondWidget); + Layout layout = testPage.getLayouts().get(0); layout.setDsl(parentDsl); @@ -1218,11 +1226,20 @@ public class ApplicationServiceTest { actionCollectionDTO.setOrganizationId(application.getOrganizationId()); actionCollectionDTO.setPluginId(testPlugin.getId()); actionCollectionDTO.setVariables(List.of(new JSValue("test", "String", "test", true))); - actionCollectionDTO.setBody("collectionBody"); + actionCollectionDTO.setBody("export default {\n" + + "\tgetData: async () => {\n" + + "\t\tconst data = await cloneActionTest.run();\n" + + "\t\treturn data;\n" + + "\t}\n" + + "}"); ActionDTO action1 = new ActionDTO(); action1.setName("cloneActionCollection1"); action1.setActionConfiguration(new ActionConfiguration()); - action1.getActionConfiguration().setBody("mockBody"); + action1.getActionConfiguration().setBody( + "async () => {\n" + + "\t\tconst data = await cloneActionTest.run();\n" + + "\t\treturn data;\n" + + "\t}"); actionCollectionDTO.setActions(List.of(action1)); actionCollectionDTO.setPluginType(PluginType.JS); @@ -1304,13 +1321,18 @@ public class ApplicationServiceTest { newPage.getUnpublishedPage() .getLayouts() - .forEach(layout -> - layout.getLayoutOnLoadActions().forEach(dslActionDTOS -> { - dslActionDTOS.forEach(actionDTO -> { - assertThat(actionDTO.getId()).isEqualTo(actionDTO.getDefaultActionId()); - }); - }) - ); + .forEach(layout -> { + assertThat(layout.getLayoutOnLoadActions()).hasSize(1); + layout.getLayoutOnLoadActions().forEach(dslActionDTOS -> { + assertThat(dslActionDTOS).hasSize(2); + dslActionDTOS.forEach(actionDTO -> { + assertThat(actionDTO.getId()).isEqualTo(actionDTO.getDefaultActionId()); + if (StringUtils.hasLength(actionDTO.getCollectionId())) { + assertThat(actionDTO.getDefaultCollectionId()).isEqualTo(actionDTO.getCollectionId()); + } + }); + }); + }); }); assertThat(actionList).hasSize(2); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java index d87eb8400e..638e1899e8 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java @@ -195,23 +195,6 @@ public class ApplicationForkingServiceTests { layoutActionService.createSingleAction(action).block(); - ObjectMapper objectMapper = new ObjectMapper(); - JSONObject parentDsl = new JSONObject(objectMapper.readValue(DEFAULT_PAGE_LAYOUT, new TypeReference>() { - })); - - ArrayList children = (ArrayList) parentDsl.get("children"); - JSONObject testWidget = new JSONObject(); - testWidget.put("widgetName", "firstWidget"); - JSONArray temp = new JSONArray(); - temp.addAll(List.of(new JSONObject(Map.of("key", "testField")))); - testWidget.put("dynamicBindingPathList", temp); - testWidget.put("testField", "{{ forkActionTest.data }}"); - children.add(testWidget); - - Layout layout = testPage.getLayouts().get(0); - layout.setDsl(parentDsl); - - layoutActionService.updateLayout(testPage.getId(), layout.getId(), layout).block(); // Save actionCollection ActionCollectionDTO actionCollectionDTO = new ActionCollectionDTO(); @@ -221,16 +204,49 @@ public class ApplicationForkingServiceTests { actionCollectionDTO.setOrganizationId(sourceOrganization.getId()); actionCollectionDTO.setPluginId(datasource.getPluginId()); actionCollectionDTO.setVariables(List.of(new JSValue("test", "String", "test", true))); - actionCollectionDTO.setBody("collectionBody"); + actionCollectionDTO.setBody("export default {\n" + + "\tgetData: async () => {\n" + + "\t\tconst data = await forkActionTest.run();\n" + + "\t\treturn data;\n" + + "\t}\n" + + "}"); ActionDTO action1 = new ActionDTO(); - action1.setName("forkTestAction1"); + action1.setName("getData"); action1.setActionConfiguration(new ActionConfiguration()); - action1.getActionConfiguration().setBody("mockBody"); + action1.getActionConfiguration().setBody( + "async () => {\n" + + "\t\tconst data = await forkActionTest.run();\n" + + "\t\treturn data;\n" + + "\t}"); actionCollectionDTO.setActions(List.of(action1)); actionCollectionDTO.setPluginType(PluginType.JS); layoutCollectionService.createCollection(actionCollectionDTO).block(); + ObjectMapper objectMapper = new ObjectMapper(); + JSONObject parentDsl = new JSONObject(objectMapper.readValue(DEFAULT_PAGE_LAYOUT, new TypeReference>() { + })); + ArrayList children = (ArrayList) parentDsl.get("children"); + JSONObject testWidget = new JSONObject(); + testWidget.put("widgetName", "firstWidget"); + JSONArray temp = new JSONArray(); + temp.addAll(List.of(new JSONObject(Map.of("key", "testField", "key1", "testField1")))); + testWidget.put("dynamicBindingPathList", temp); + testWidget.put("testField", "{{ forkActionTest.data }}"); + children.add(testWidget); + + JSONObject secondWidget = new JSONObject(); + secondWidget.put("widgetName", "secondWidget"); + temp = new JSONArray(); + temp.addAll(List.of(new JSONObject(Map.of("key", "testField1")))); + secondWidget.put("dynamicBindingPathList", temp); + secondWidget.put("testField1", "{{ testCollection1.getData.data }}"); + children.add(secondWidget); + + Layout layout = testPage.getLayouts().get(0); + layout.setDsl(parentDsl); + + layoutActionService.updateLayout(testPage.getId(), layout.getId(), layout).block(); // Invite "usertest@usertest.com" with VIEW access, api_user will be the admin of sourceOrganization and we are // controlling this with @FixMethodOrder(MethodSorters.NAME_ASCENDING) to run the TCs in a sequence. // Running TC in a sequence is a bad practice for unit TCs but here we are testing the invite user and then fork @@ -312,12 +328,18 @@ public class ApplicationForkingServiceTests { newPage.getUnpublishedPage() .getLayouts() - .forEach(layout -> + .forEach(layout -> { + assertThat(layout.getLayoutOnLoadActions()).hasSize(1); layout.getLayoutOnLoadActions().forEach(dslActionDTOS -> { + assertThat(dslActionDTOS).hasSize(2); dslActionDTOS.forEach(actionDTO -> { assertThat(actionDTO.getId()).isEqualTo(actionDTO.getDefaultActionId()); + if (!StringUtils.isEmpty(actionDTO.getCollectionId())) { + assertThat(actionDTO.getCollectionId()).isEqualTo(actionDTO.getDefaultCollectionId()); + } }); - }) + }); + } ); });