feat: Add API to support partial import (#28357)

## Description
> PR to support partial import changes

#### PR fixes following issue(s)
Fixes #28223 

#### Type of change
- New feature (non-breaking change which adds functionality)

## Testing
#### How Has This Been Tested?
- [ ] Manual

## Checklist:
#### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [x] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
Anagh Hegde 2023-10-30 14:46:13 +05:30 committed by GitHub
parent 62383c975c
commit 08e0cc0431
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 457 additions and 48 deletions

View File

@ -84,7 +84,9 @@ public enum AnalyticsEvents {
DS_TEST_EVENT_FAILED("Test_Datasource_Failed"),
GIT_STALE_FILE_LOCK_DELETED,
SERVER_SETUP_COMPLETE("server_setup_complete");
SERVER_SETUP_COMPLETE("server_setup_complete"),
PARTIAL_IMPORT;
private final String eventName;

View File

@ -6,6 +6,7 @@ import com.appsmith.server.exports.internal.ExportApplicationService;
import com.appsmith.server.exports.internal.PartialExportService;
import com.appsmith.server.fork.internal.ApplicationForkingService;
import com.appsmith.server.imports.internal.ImportApplicationService;
import com.appsmith.server.imports.internal.PartialImportService;
import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.ApplicationService;
import com.appsmith.server.services.ApplicationSnapshotService;
@ -27,7 +28,8 @@ public class ApplicationController extends ApplicationControllerCE {
ExportApplicationService exportApplicationService,
ThemeService themeService,
ApplicationSnapshotService applicationSnapshotService,
PartialExportService partialExportService) {
PartialExportService partialExportService,
PartialImportService partialImportService) {
super(
service,
applicationPageService,
@ -37,6 +39,7 @@ public class ApplicationController extends ApplicationControllerCE {
exportApplicationService,
themeService,
applicationSnapshotService,
partialExportService);
partialExportService,
partialImportService);
}
}

View File

@ -12,6 +12,7 @@ import com.appsmith.server.dtos.ApplicationAccessDTO;
import com.appsmith.server.dtos.ApplicationImportDTO;
import com.appsmith.server.dtos.ApplicationPagesDTO;
import com.appsmith.server.dtos.GitAuthDTO;
import com.appsmith.server.dtos.PartialExportFileDTO;
import com.appsmith.server.dtos.ReleaseItemsDTO;
import com.appsmith.server.dtos.ResponseDTO;
import com.appsmith.server.dtos.UserHomepageDTO;
@ -21,6 +22,7 @@ import com.appsmith.server.exports.internal.ExportApplicationService;
import com.appsmith.server.exports.internal.PartialExportService;
import com.appsmith.server.fork.internal.ApplicationForkingService;
import com.appsmith.server.imports.internal.ImportApplicationService;
import com.appsmith.server.imports.internal.PartialImportService;
import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.ApplicationService;
import com.appsmith.server.services.ApplicationSnapshotService;
@ -64,8 +66,8 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
private final ExportApplicationService exportApplicationService;
private final ThemeService themeService;
private final ApplicationSnapshotService applicationSnapshotService;
private final PartialExportService partialExportService;
private final PartialImportService partialImportService;
@Autowired
public ApplicationControllerCE(
@ -77,7 +79,8 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
ExportApplicationService exportApplicationService,
ThemeService themeService,
ApplicationSnapshotService applicationSnapshotService,
PartialExportService partialExportService) {
PartialExportService partialExportService,
PartialImportService partialImportService) {
super(service);
this.applicationPageService = applicationPageService;
this.applicationFetcher = applicationFetcher;
@ -87,6 +90,7 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
this.themeService = themeService;
this.applicationSnapshotService = applicationSnapshotService;
this.partialExportService = partialExportService;
this.partialImportService = partialImportService;
}
@JsonView(Views.Public.class)
@ -368,20 +372,34 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
}
@JsonView(Views.Public.class)
@PostMapping("/export/partial/{applicationId}/{pageId}")
@PostMapping(value = "/export/partial/{applicationId}/{pageId}", consumes = MediaType.APPLICATION_JSON_VALUE)
public Mono<ResponseEntity<Object>> exportApplicationPartially(
@PathVariable String applicationId,
@PathVariable String pageId,
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName,
@RequestBody MultiValueMap<String, String> params,
@RequestBody String widgets) {
@Valid @RequestBody PartialExportFileDTO fileDTO) {
// params - contains ids of jsLib, actions and datasourceIds to be exported
return partialExportService
.getPartialExportResources(applicationId, pageId, branchName, params, widgets)
.getPartialExportResources(applicationId, pageId, branchName, fileDTO)
.map(fetchedResource -> {
HttpHeaders responseHeaders = fetchedResource.getHttpHeaders();
Object applicationResource = fetchedResource.getApplicationResource();
return new ResponseEntity<>(applicationResource, responseHeaders, HttpStatus.OK);
});
}
@JsonView(Views.Public.class)
@PostMapping(
value = "/import/partial/{workspaceId}/{applicationId}",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<ResponseDTO<Application>> importApplicationPartially(
@RequestPart("file") Mono<Part> fileMono,
@PathVariable String workspaceId,
@PathVariable String applicationId,
@RequestParam String pageId,
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
return fileMono.flatMap(fileData -> partialImportService.importResourceInPage(
workspaceId, applicationId, pageId, branchName, fileData))
.map(fetchedResource -> new ResponseDTO<>(HttpStatus.OK.value(), fetchedResource, null));
}
}

View File

@ -0,0 +1,20 @@
package com.appsmith.server.dtos;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class PartialExportFileDTO {
List<String> actionList = new ArrayList<>();
List<String> actionCollectionList = new ArrayList<>();
List<String> customJsLib = new ArrayList<>();
List<String> datasourceList = new ArrayList<>();
String widget = "";
}

View File

@ -1,14 +1,10 @@
package com.appsmith.server.exports.internal;
import com.appsmith.server.dtos.ExportFileDTO;
import org.springframework.util.MultiValueMap;
import com.appsmith.server.dtos.PartialExportFileDTO;
import reactor.core.publisher.Mono;
public interface PartialExportServiceCE {
Mono<ExportFileDTO> getPartialExportResources(
String applicationId,
String pageId,
String branchName,
MultiValueMap<String, String> params,
String widgets);
String applicationId, String pageId, String branchName, PartialExportFileDTO partialExportFileDTO);
}

View File

@ -15,6 +15,7 @@ import com.appsmith.server.dtos.ApplicationJson;
import com.appsmith.server.dtos.ExportFileDTO;
import com.appsmith.server.dtos.ExportingMetaDTO;
import com.appsmith.server.dtos.MappedExportableResourcesDTO;
import com.appsmith.server.dtos.PartialExportFileDTO;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.exports.exportable.ExportableService;
@ -31,12 +32,10 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.appsmith.server.constants.ResourceModes.EDIT;
@ -60,11 +59,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
@Override
public Mono<ExportFileDTO> getPartialExportResources(
String applicationId,
String pageId,
String branchName,
MultiValueMap<String, String> params,
String widgets) {
String applicationId, String pageId, String branchName, PartialExportFileDTO partialExportFileDTO) {
/*
* Params has ids for actions, customJsLibs and datasource
* Export the resources based on the value of these entities
@ -96,21 +91,25 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
return applicationMono
.flatMap(application -> {
applicationJson.setExportedApplication(application);
return pluginExportableService.getExportableEntities(
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson);
return pluginExportableService
.getExportableEntities(
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson)
.thenReturn(applicationJson);
})
.flatMap(pluginList -> {
if (params.containsKey(FieldName.DATASOURCE_LIST)) {
return datasourceExportableService.getExportableEntities(
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson);
if (partialExportFileDTO.getDatasourceList().size() > 0) {
return datasourceExportableService
.getExportableEntities(
exportingMetaDTO, mappedResourcesDTO, applicationMono, applicationJson)
.thenReturn(applicationJson);
}
return Mono.just(applicationJson);
})
.flatMap(appJson -> {
if (params.containsKey(FieldName.CUSTOM_JS_LIB_LIST)) {
if (partialExportFileDTO.getCustomJsLib().size() > 0) {
return exportFilteredCustomJSLib(
applicationId,
Set.copyOf(params.get(FieldName.CUSTOM_JS_LIB_LIST)),
partialExportFileDTO.getCustomJsLib(),
applicationJson,
branchName)
.flatMap(jsLibList -> {
@ -129,33 +128,34 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
// update page name in meta and exportable DTO for resource to name mapping
.flatMap(branchedPageId -> updatePageNameInResourceMapDTO(branchedPageId, mappedResourcesDTO))
// export actions
// export js objects
.flatMap(branchedPageId -> {
if (params.containsKey(FieldName.ACTION_LIST)
|| params.containsKey(FieldName.ACTION_COLLECTION_LIST)) {
return exportActions(
if (partialExportFileDTO.getActionCollectionList().size() > 0) {
return exportActionCollections(
branchedPageId,
Set.copyOf(params.get(FieldName.ACTION_LIST)),
partialExportFileDTO.getActionCollectionList(),
applicationJson,
mappedResourcesDTO)
.then(Mono.just(branchedPageId));
}
return Mono.just(branchedPageId);
})
// export js objects
.flatMap(branchedPageId -> {
if (params.containsKey(FieldName.ACTION_COLLECTION_LIST)) {
return exportActionCollections(
branchedPageId,
Set.copyOf(params.get(FieldName.ACTION_COLLECTION_LIST)),
applicationJson,
mappedResourcesDTO);
if (partialExportFileDTO.getActionCollectionList().size() > 0
|| partialExportFileDTO.getActionList().size() > 0) {
return exportActions(
branchedPageId,
partialExportFileDTO.getActionList(),
applicationJson,
mappedResourcesDTO)
.then(Mono.just(branchedPageId));
}
return Mono.just(applicationJson);
return Mono.just(branchedPageId);
})
.flatMap(appJson -> {
// Remove the datasources not in use
if (params.containsKey(FieldName.DATASOURCE_LIST)) {
exportDatasource(Set.copyOf(params.get(FieldName.DATASOURCE_LIST)), applicationJson);
if (partialExportFileDTO.getDatasourceList().size() > 0) {
exportDatasource(partialExportFileDTO.getDatasourceList(), applicationJson);
// Sanitise the datasource
datasourceExportableService.sanitizeEntities(
exportingMetaDTO,
@ -168,7 +168,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
.map(exportedJson -> {
String applicationName =
applicationJson.getExportedApplication().getName();
applicationJson.setWidgets(widgets);
applicationJson.setWidgets(partialExportFileDTO.getWidget());
applicationJson.setExportedApplication(null);
String stringifiedFile = gson.toJson(exportedJson);
Object jsonObject = gson.fromJson(stringifiedFile, Object.class);
@ -186,7 +186,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
});
}
private void exportDatasource(Set<String> validDatasource, ApplicationJson applicationJson) {
private void exportDatasource(List<String> validDatasource, ApplicationJson applicationJson) {
List<DatasourceStorage> datasourceList = applicationJson.getDatasourceList().stream()
.filter(datasourceStorage -> validDatasource.contains(datasourceStorage.getDatasourceId()))
.toList();
@ -194,7 +194,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
}
private Mono<ApplicationJson> exportFilteredCustomJSLib(
String applicationId, Set<String> customJSLibSet, ApplicationJson applicationJson, String branchName) {
String applicationId, List<String> customJSLibSet, ApplicationJson applicationJson, String branchName) {
return customJSLibService
.getAllJSLibsInApplication(applicationId, branchName, false)
.flatMap(customJSLibs -> {
@ -209,7 +209,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
private Mono<ApplicationJson> exportActions(
String pageId,
Set<String> validActions,
List<String> validActions,
ApplicationJson applicationJson,
MappedExportableResourcesDTO mappedResourcesDTO) {
return newActionService.findByPageId(pageId).collectList().flatMap(actions -> {
@ -229,7 +229,7 @@ public class PartialExportServiceCEImpl implements PartialExportServiceCE {
private Mono<ApplicationJson> exportActionCollections(
String pageId,
Set<String> validActions,
List<String> validActions,
ApplicationJson applicationJson,
MappedExportableResourcesDTO mappedResourcesDTO) {
return actionCollectionService.findByPageId(pageId).collectList().flatMap(actionCollections -> {

View File

@ -0,0 +1,3 @@
package com.appsmith.server.imports.internal;
public interface PartialImportService extends PartialImportServiceCE {}

View File

@ -0,0 +1,11 @@
package com.appsmith.server.imports.internal;
import com.appsmith.server.domains.Application;
import org.springframework.http.codec.multipart.Part;
import reactor.core.publisher.Mono;
public interface PartialImportServiceCE {
Mono<Application> importResourceInPage(
String workspaceId, String applicationId, String pageId, String branchName, Part file);
}

View File

@ -0,0 +1,280 @@
package com.appsmith.server.imports.internal;
import com.appsmith.external.constants.AnalyticsEvents;
import com.appsmith.external.models.Datasource;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.ActionCollection;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.CustomJSLib;
import com.appsmith.server.domains.NewAction;
import com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.Workspace;
import com.appsmith.server.dtos.ApplicationJson;
import com.appsmith.server.dtos.ImportingMetaDTO;
import com.appsmith.server.dtos.MappedImportableResourcesDTO;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.helpers.ce.ImportApplicationPermissionProvider;
import com.appsmith.server.imports.importable.ImportableService;
import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.repositories.PermissionGroupRepository;
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.ApplicationService;
import com.appsmith.server.services.WorkspaceService;
import com.appsmith.server.solutions.ActionPermission;
import com.appsmith.server.solutions.ApplicationPermission;
import com.appsmith.server.solutions.DatasourcePermission;
import com.appsmith.server.solutions.PagePermission;
import com.appsmith.server.solutions.WorkspacePermission;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.codec.multipart.Part;
import org.springframework.transaction.reactive.TransactionalOperator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@RequiredArgsConstructor
@Slf4j
public class PartialImportServiceCEImpl implements PartialImportServiceCE {
private final ImportApplicationService importApplicationService;
private final WorkspaceService workspaceService;
private final ApplicationService applicationService;
private final AnalyticsService analyticsService;
private final DatasourcePermission datasourcePermission;
private final WorkspacePermission workspacePermission;
private final ApplicationPermission applicationPermission;
private final PagePermission pagePermission;
private final ActionPermission actionPermission;
private final Gson gson;
private final TransactionalOperator transactionalOperator;
private final PermissionGroupRepository permissionGroupRepository;
private final ImportableService<Plugin> pluginImportableService;
private final ImportableService<NewPage> newPageImportableService;
private final ImportableService<CustomJSLib> customJSLibImportableService;
private final ImportableService<Datasource> datasourceImportableService;
private final ImportableService<NewAction> newActionImportableService;
private final ImportableService<ActionCollection> actionCollectionImportableService;
private final NewPageService newPageService;
@Override
public Mono<Application> importResourceInPage(
String workspaceId, String applicationId, String pageId, String branchName, Part file) {
/*
1. Get branchedPageId from pageId and branchName
2. Get Application Mono
3. Prepare the Meta DTO's
4. Get plugin data
5. Import datasources
6. Import customJsLib
7. Import actions
8. Import actionCollection
*/
MappedImportableResourcesDTO mappedImportableResourcesDTO = new MappedImportableResourcesDTO();
Mono<String> branchedPageIdMono =
newPageService.findBranchedPageId(branchName, pageId, AclPermission.MANAGE_PAGES);
// Extract file and get App Json
Mono<Application> partiallyImportedAppMono = importApplicationService
.extractApplicationJson(file)
.zipWith(getImportApplicationPermissions())
.flatMap(tuple -> {
ApplicationJson applicationJson = tuple.getT1();
ImportApplicationPermissionProvider permissionProvider = tuple.getT2();
// Set Application in App JSON, remove the pages other than the one to be imported in
// Set the current page in the JSON to be imported
// Debug and get the value from getImportApplicationMono method if any difference
// Modify the Application set in JSON to be imported
Mono<Workspace> workspaceMono = workspaceService
.findById(workspaceId, permissionProvider.getRequiredPermissionOnTargetWorkspace())
.switchIfEmpty(Mono.defer(() -> {
log.error(
"No workspace found with id: {} and permission: {}",
workspaceId,
permissionProvider.getRequiredPermissionOnTargetWorkspace());
return Mono.error(new AppsmithException(
AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.WORKSPACE, workspaceId));
}))
.cache();
ImportingMetaDTO importingMetaDTO =
new ImportingMetaDTO(workspaceId, applicationId, branchName, false, permissionProvider);
// Get the Application from DB
Mono<Application> importedApplicationMono = applicationService
.findByBranchNameAndDefaultApplicationId(
branchName,
applicationId,
permissionProvider.getRequiredPermissionOnTargetApplication())
.cache();
return importedApplicationMono
.flatMap(application -> {
applicationJson.setExportedApplication(application);
return Mono.just(applicationJson);
})
// Import Custom Js Lib and Datasource
.then(getApplicationImportableEntities(
importingMetaDTO,
mappedImportableResourcesDTO,
workspaceMono,
importedApplicationMono,
applicationJson))
.thenReturn("done")
// Update the pageName map for actions and action collection
.then(paneNameMapForActionAndActionCollectionInAppJson(
branchedPageIdMono, applicationJson, mappedImportableResourcesDTO))
.thenReturn("done")
// Import Actions and action collection
.then(getActionAndActionCollectionImport(
importingMetaDTO,
mappedImportableResourcesDTO,
workspaceMono,
importedApplicationMono,
applicationJson))
.thenReturn("done")
.then(Mono.defer(() -> {
Application application = applicationJson.getExportedApplication();
return newActionImportableService
.updateImportedEntities(
application, importingMetaDTO, mappedImportableResourcesDTO)
.then(newPageImportableService.updateImportedEntities(
application, importingMetaDTO, mappedImportableResourcesDTO))
.flatMap(
newPage -> applicationService.update(application.getId(), application));
}));
})
.as(transactionalOperator::transactional);
// Send Analytics event
return partiallyImportedAppMono.flatMap(application -> {
final Map<String, Object> eventData = Map.of(FieldName.APPLICATION, application);
final Map<String, Object> data = Map.of(
FieldName.APPLICATION_ID, application.getId(),
FieldName.WORKSPACE_ID, application.getWorkspaceId(),
FieldName.EVENT_DATA, eventData);
return analyticsService.sendObjectEvent(AnalyticsEvents.PARTIAL_IMPORT, application, data);
});
}
private Mono<ImportApplicationPermissionProvider> getImportApplicationPermissions() {
return permissionGroupRepository.getCurrentUserPermissionGroups().flatMap(userPermissionGroups -> {
ImportApplicationPermissionProvider permissionProvider = ImportApplicationPermissionProvider.builder(
applicationPermission,
pagePermission,
actionPermission,
datasourcePermission,
workspacePermission)
.requiredPermissionOnTargetWorkspace(workspacePermission.getReadPermission())
.requiredPermissionOnTargetApplication(applicationPermission.getEditPermission())
.permissionRequiredToCreateDatasource(true)
.permissionRequiredToEditDatasource(true)
.currentUserPermissionGroups(userPermissionGroups)
.build();
return Mono.just(permissionProvider);
});
}
private Mono<Void> getApplicationImportableEntities(
ImportingMetaDTO importingMetaDTO,
MappedImportableResourcesDTO mappedImportableResourcesDTO,
Mono<Workspace> workspaceMono,
Mono<Application> importedApplicationMono,
ApplicationJson applicationJson) {
Mono<Void> customJSLibMono = pluginImportableService.importEntities(
importingMetaDTO,
mappedImportableResourcesDTO,
workspaceMono,
importedApplicationMono,
applicationJson);
Mono<Void> datasourceMono = datasourceImportableService.importEntities(
importingMetaDTO,
mappedImportableResourcesDTO,
workspaceMono,
importedApplicationMono,
applicationJson);
Mono<Void> customJsLibMono = customJSLibImportableService.importEntities(
importingMetaDTO, mappedImportableResourcesDTO, null, null, applicationJson);
return Flux.merge(List.of(customJsLibMono, datasourceMono, customJSLibMono))
.then();
}
private Mono<Void> getActionAndActionCollectionImport(
ImportingMetaDTO importingMetaDTO,
MappedImportableResourcesDTO mappedImportableResourcesDTO,
Mono<Workspace> workspaceMono,
Mono<Application> importedApplicationMono,
ApplicationJson applicationJson) {
Mono<Void> actionMono = newActionImportableService.importEntities(
importingMetaDTO,
mappedImportableResourcesDTO,
workspaceMono,
importedApplicationMono,
applicationJson);
Mono<Void> actionCollectionMono = actionCollectionImportableService.importEntities(
importingMetaDTO,
mappedImportableResourcesDTO,
workspaceMono,
importedApplicationMono,
applicationJson);
return Flux.merge(List.of(actionMono, actionCollectionMono)).then();
}
private Mono<String> paneNameMapForActionAndActionCollectionInAppJson(
Mono<String> branchedPageIdMono,
ApplicationJson applicationJson,
MappedImportableResourcesDTO mappedImportableResourcesDTO) {
return branchedPageIdMono.flatMap(
pageId -> newPageService.findById(pageId, Optional.empty()).flatMap(newPage -> {
String pageName = newPage.getUnpublishedPage().getName();
// update page name reference with newPage
Map<String, NewPage> pageNameMap = new HashMap<>();
pageNameMap.put(pageName, newPage);
mappedImportableResourcesDTO.setPageNameMap(pageNameMap);
applicationJson.getActionList().forEach(action -> {
action.getPublishedAction().setPageId(pageName);
action.getUnpublishedAction().setPageId(pageName);
if (action.getPublishedAction().getCollectionId() != null) {
String collectionName = action.getPublishedAction()
.getCollectionId()
.split("_")[1];
action.getPublishedAction().setCollectionId(pageName + "_" + collectionName);
action.getUnpublishedAction().setCollectionId(pageName + "_" + collectionName);
}
String actionName = action.getId().split("_")[1];
action.setId(pageName + "_" + actionName);
action.setGitSyncId(null);
});
applicationJson.getActionCollectionList().forEach(actionCollection -> {
actionCollection.getPublishedCollection().setPageId(pageName);
actionCollection.getUnpublishedCollection().setPageId(pageName);
String collectionName = actionCollection.getId().split("_")[1];
actionCollection.setId(pageName + "_" + collectionName);
actionCollection.setGitSyncId(null);
});
return Mono.just(pageName);
}));
}
}

View File

@ -0,0 +1,72 @@
package com.appsmith.server.imports.internal;
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 com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.Plugin;
import com.appsmith.server.imports.importable.ImportableService;
import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.repositories.PermissionGroupRepository;
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.ApplicationService;
import com.appsmith.server.services.WorkspaceService;
import com.appsmith.server.solutions.ActionPermission;
import com.appsmith.server.solutions.ApplicationPermission;
import com.appsmith.server.solutions.DatasourcePermission;
import com.appsmith.server.solutions.PagePermission;
import com.appsmith.server.solutions.WorkspacePermission;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.reactive.TransactionalOperator;
@Slf4j
@Service
@Primary
public class PartialImportServiceImpl extends PartialImportServiceCEImpl implements PartialImportService {
public PartialImportServiceImpl(
ImportApplicationService importApplicationService,
WorkspaceService workspaceService,
ApplicationService applicationService,
AnalyticsService analyticsService,
DatasourcePermission datasourcePermission,
WorkspacePermission workspacePermission,
ApplicationPermission applicationPermission,
PagePermission pagePermission,
ActionPermission actionPermission,
Gson gson,
TransactionalOperator transactionalOperator,
PermissionGroupRepository permissionGroupRepository,
ImportableService<Plugin> pluginImportableService,
ImportableService<NewPage> newPageImportableService,
ImportableService<CustomJSLib> customJSLibImportableService,
ImportableService<Datasource> datasourceImportableService,
ImportableService<NewAction> newActionImportableService,
ImportableService<ActionCollection> actionCollectionImportableService,
NewPageService newPageService) {
super(
importApplicationService,
workspaceService,
applicationService,
analyticsService,
datasourcePermission,
workspacePermission,
applicationPermission,
pagePermission,
actionPermission,
gson,
transactionalOperator,
permissionGroupRepository,
pluginImportableService,
newPageImportableService,
customJSLibImportableService,
datasourceImportableService,
newActionImportableService,
actionCollectionImportableService,
newPageService);
}
}

View File

@ -11,6 +11,7 @@ import com.appsmith.server.fork.internal.ApplicationForkingService;
import com.appsmith.server.helpers.GitFileUtils;
import com.appsmith.server.helpers.RedisUtils;
import com.appsmith.server.imports.internal.ImportApplicationService;
import com.appsmith.server.imports.internal.PartialImportService;
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.ApplicationPageService;
import com.appsmith.server.services.ApplicationService;
@ -83,6 +84,9 @@ public class ApplicationControllerTest {
@MockBean
PartialExportService partialExportService;
@MockBean
PartialImportService partialImportService;
private String getFileName(int length) {
StringBuilder fileName = new StringBuilder();
for (int count = 0; count < length; count++) {