chore: Add code-split for widget refactoring in UI module (#40226)

## Description
EE Counterpart: https://github.com/appsmithorg/appsmith-ee/pull/7143


Fixes #`Issue Number`  
_or_  
Fixes `Issue URL`
> [!WARNING]  
> _If no issue exists, please create an issue first, and check with the
maintainers if the issue is valid._

## Automation

/ok-to-test tags="@tag.All"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/14404193022>
> Commit: 5585f90660cc8d16e3a6954db12c999b3e8b6060
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14404193022&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Fri, 11 Apr 2025 14:44:36 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced context-aware layout management that enhances page design
updates and dynamic refactoring.
- Added improved handling for layout and widget updates, offering a
smoother editing experience.

- **Refactor**
- Streamlined layout update processes with adaptive behavior based on
context.
- Optimized service interactions for more robust and modular page and
widget processing.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
subratadeypappu 2025-04-16 15:56:50 +06:00 committed by GitHub
parent 86c5a77fa5
commit d4a0852955
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 443 additions and 155 deletions

View File

@ -0,0 +1,13 @@
package com.appsmith.server.domains.ce;
import com.appsmith.server.domains.Layout;
import java.util.List;
public interface LayoutContainer {
List<Layout> getLayouts();
void setLayouts(List<Layout> layouts);
String getId();
}

View File

@ -5,6 +5,7 @@ import com.appsmith.external.models.Policy;
import com.appsmith.external.views.Git; import com.appsmith.external.views.Git;
import com.appsmith.external.views.Views; import com.appsmith.external.views.Views;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.ce.LayoutContainer;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.annotation.JsonView;
import lombok.Getter; import lombok.Getter;
@ -26,7 +27,7 @@ import java.util.Set;
@NoArgsConstructor @NoArgsConstructor
@ToString @ToString
@FieldNameConstants @FieldNameConstants
public class PageDTO { public class PageDTO implements LayoutContainer {
@Transient @Transient
@JsonView({Views.Public.class}) @JsonView({Views.Public.class})

View File

@ -14,6 +14,9 @@ import java.util.Set;
public interface UpdateLayoutServiceCE { public interface UpdateLayoutServiceCE {
Mono<LayoutDTO> updateLayout(String pageId, String applicationId, String layoutId, Layout layout); Mono<LayoutDTO> updateLayout(String pageId, String applicationId, String layoutId, Layout layout);
Mono<LayoutDTO> updateLayout(
String pageId, String applicationId, String layoutId, Layout layout, CreatorContextType contextType);
Mono<Integer> updateMultipleLayouts( Mono<Integer> updateMultipleLayouts(
String defaultApplicationId, UpdateMultiplePageLayoutDTO updateMultiplePageLayoutDTO); String defaultApplicationId, UpdateMultiplePageLayoutDTO updateMultiplePageLayoutDTO);

View File

@ -7,7 +7,6 @@ import com.appsmith.external.exceptions.ErrorDTO;
import com.appsmith.external.helpers.MustacheHelper; import com.appsmith.external.helpers.MustacheHelper;
import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.CreatorContextType;
import com.appsmith.external.models.Executable; import com.appsmith.external.models.Executable;
import com.appsmith.server.applications.base.ApplicationService;
import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.ExecutableDependencyEdge; import com.appsmith.server.domains.ExecutableDependencyEdge;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
@ -21,6 +20,7 @@ import com.appsmith.server.helpers.ObservationHelperImpl;
import com.appsmith.server.helpers.WidgetSpecificUtils; import com.appsmith.server.helpers.WidgetSpecificUtils;
import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.onload.internal.OnLoadExecutablesUtil; import com.appsmith.server.onload.internal.OnLoadExecutablesUtil;
import com.appsmith.server.refactors.resolver.ContextLayoutRefactorResolver;
import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.solutions.PagePermission; import com.appsmith.server.solutions.PagePermission;
@ -59,6 +59,7 @@ import static com.appsmith.external.constants.spans.LayoutSpan.UPDATE_LAYOUT_MET
import static com.appsmith.external.constants.spans.PageSpan.GET_PAGE_BY_ID; import static com.appsmith.external.constants.spans.PageSpan.GET_PAGE_BY_ID;
import static com.appsmith.external.constants.spans.ce.LayoutSpanCE.UPDATE_LAYOUT_BASED_ON_CONTEXT; import static com.appsmith.external.constants.spans.ce.LayoutSpanCE.UPDATE_LAYOUT_BASED_ON_CONTEXT;
import static com.appsmith.server.constants.CommonConstants.EVALUATION_VERSION; import static com.appsmith.server.constants.CommonConstants.EVALUATION_VERSION;
import static com.appsmith.server.helpers.ContextTypeUtils.isPageContext;
import static java.lang.Boolean.FALSE; import static java.lang.Boolean.FALSE;
@Slf4j @Slf4j
@ -71,10 +72,10 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
private final NewPageService newPageService; private final NewPageService newPageService;
private final AnalyticsService analyticsService; private final AnalyticsService analyticsService;
private final PagePermission pagePermission; private final PagePermission pagePermission;
private final ApplicationService applicationService;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final ObservationRegistry observationRegistry; private final ObservationRegistry observationRegistry;
private final ObservationHelperImpl observationHelper; private final ObservationHelperImpl observationHelper;
private final ContextLayoutRefactorResolver contextLayoutRefactorResolver;
private final String layoutOnLoadActionErrorToastMessage = private final String layoutOnLoadActionErrorToastMessage =
"A cyclic dependency error has been encountered on current page, \nqueries on page load will not run. \n Please check debugger and Appsmith documentation for more information"; "A cyclic dependency error has been encountered on current page, \nqueries on page load will not run. \n Please check debugger and Appsmith documentation for more information";
@ -117,7 +118,7 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
}); });
} }
private Mono<LayoutDTO> updateLayoutDsl( protected Mono<LayoutDTO> updateLayoutDsl(
String creatorId, String creatorId,
String layoutId, String layoutId,
Layout layout, Layout layout,
@ -247,22 +248,29 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
return layoutDTOMono; return layoutDTOMono;
} }
// TODO: Add contextType and change all its usage to conform to that so that we can get rid of the overloaded
// updateLayout method
@Override @Override
public Mono<LayoutDTO> updateLayout(String pageId, String applicationId, String layoutId, Layout layout) { public Mono<LayoutDTO> updateLayout(String pageId, String applicationId, String layoutId, Layout layout) {
return applicationService return contextLayoutRefactorResolver
.findById(applicationId) .getContextLayoutRefactorHelper(null)
.switchIfEmpty(Mono.error(new AppsmithException( .getEvaluationVersionMono(applicationId)
AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.APPLICATION_ID, applicationId))) .flatMap(evaluationVersion -> {
.flatMap(application -> {
Integer evaluationVersion = application.getEvaluationVersion();
if (evaluationVersion == null) {
evaluationVersion = EVALUATION_VERSION;
}
return updateLayoutDsl(pageId, layoutId, layout, evaluationVersion, CreatorContextType.PAGE) return updateLayoutDsl(pageId, layoutId, layout, evaluationVersion, CreatorContextType.PAGE)
.name(UPDATE_LAYOUT_DSL_METHOD); .name(UPDATE_LAYOUT_DSL_METHOD);
}); });
} }
@Override
public Mono<LayoutDTO> updateLayout(
String pageId, String applicationId, String layoutId, Layout layout, CreatorContextType contextType) {
if (isPageContext(contextType)) {
return updateLayout(pageId, applicationId, layoutId, layout);
} else {
return updateLayoutDsl(pageId, layoutId, layout, EVALUATION_VERSION, contextType);
}
}
@Override @Override
public Mono<Integer> updateMultipleLayouts( public Mono<Integer> updateMultipleLayouts(
String baseApplicationId, UpdateMultiplePageLayoutDTO updateMultiplePageLayoutDTO) { String baseApplicationId, UpdateMultiplePageLayoutDTO updateMultiplePageLayoutDTO) {

View File

@ -1,9 +1,9 @@
package com.appsmith.server.layouts; package com.appsmith.server.layouts;
import com.appsmith.server.applications.base.ApplicationService;
import com.appsmith.server.helpers.ObservationHelperImpl; import com.appsmith.server.helpers.ObservationHelperImpl;
import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.onload.internal.OnLoadExecutablesUtil; import com.appsmith.server.onload.internal.OnLoadExecutablesUtil;
import com.appsmith.server.refactors.resolver.ContextLayoutRefactorResolver;
import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.solutions.PagePermission; import com.appsmith.server.solutions.PagePermission;
@ -13,26 +13,25 @@ import org.springframework.stereotype.Service;
@Service @Service
public class UpdateLayoutServiceImpl extends UpdateLayoutServiceCEImpl implements UpdateLayoutService { public class UpdateLayoutServiceImpl extends UpdateLayoutServiceCEImpl implements UpdateLayoutService {
public UpdateLayoutServiceImpl( public UpdateLayoutServiceImpl(
OnLoadExecutablesUtil onLoadExecutablesUtil, OnLoadExecutablesUtil onLoadExecutablesUtil,
SessionUserService sessionUserService, SessionUserService sessionUserService,
NewPageService newPageService, NewPageService newPageService,
AnalyticsService analyticsService, AnalyticsService analyticsService,
PagePermission pagePermission, PagePermission pagePermission,
ApplicationService applicationService,
ObjectMapper objectMapper, ObjectMapper objectMapper,
ObservationRegistry observationRegistry, ObservationRegistry observationRegistry,
ObservationHelperImpl observationHelper) { ObservationHelperImpl observationHelper,
ContextLayoutRefactorResolver contextLayoutRefactorResolver) {
super( super(
onLoadExecutablesUtil, onLoadExecutablesUtil,
sessionUserService, sessionUserService,
newPageService, newPageService,
analyticsService, analyticsService,
pagePermission, pagePermission,
applicationService,
objectMapper, objectMapper,
observationRegistry, observationRegistry,
observationHelper); observationHelper,
contextLayoutRefactorResolver);
} }
} }

View File

@ -0,0 +1,109 @@
package com.appsmith.server.newpages.refactors;
import com.appsmith.server.applications.base.ApplicationService;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.ce.LayoutContainer;
import com.appsmith.server.dtos.PageDTO;
import com.appsmith.server.dtos.RefactorEntityNameDTO;
import com.appsmith.server.dtos.RefactoringMetaDTO;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.refactors.ContextLayoutRefactoringService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.List;
import static com.appsmith.server.constants.ce.CommonConstantsCE.EVALUATION_VERSION;
@Component
@RequiredArgsConstructor
@Slf4j
public class PageLayoutRefactoringServiceImpl implements ContextLayoutRefactoringService<NewPage, PageDTO> {
private final NewPageService newPageService;
private final ApplicationService applicationService;
@Override
public Mono<PageDTO> updateContext(String contextId, LayoutContainer dto) {
return newPageService.saveUnpublishedPage((PageDTO) dto);
}
@Override
public Mono<PageDTO> getContextDTOMono(String contextId, boolean viewMode) {
return newPageService.findPageById(contextId, null, viewMode);
}
@Override
public Mono<PageDTO> getContextDTOMono(RefactoringMetaDTO refactoringMetaDTO) {
return refactoringMetaDTO.getPageDTOMono();
}
@Override
public Mono<Integer> getEvaluationVersionMono(
String contextId, RefactorEntityNameDTO refactorEntityNameDTO, RefactoringMetaDTO refactoringMetaDTO) {
Mono<PageDTO> pageDTOMono = getContextDTOMono(contextId, false);
refactoringMetaDTO.setPageDTOMono(pageDTOMono);
return pageDTOMono.flatMap(
page -> applicationService.findById(page.getApplicationId()).map(application -> {
Integer evaluationVersion = application.getEvaluationVersion();
if (evaluationVersion == null) {
evaluationVersion = EVALUATION_VERSION;
}
return evaluationVersion;
}));
}
@Override
public Mono<Integer> getEvaluationVersionMono(String artifactId) {
return applicationService
.findById(artifactId)
.switchIfEmpty(Mono.error(new AppsmithException(
AppsmithError.ACL_NO_RESOURCE_FOUND, FieldName.APPLICATION_ID, artifactId)))
.map(application -> {
Integer evaluationVersion = application.getEvaluationVersion();
if (evaluationVersion == null) {
evaluationVersion = EVALUATION_VERSION;
}
return evaluationVersion;
});
}
@Override
public List<Layout> getLayouts(RefactoringMetaDTO refactoringMetaDTO) {
PageDTO updatedPage = refactoringMetaDTO.getUpdatedPage();
if (updatedPage == null) {
return null;
}
return updatedPage.getLayouts();
}
@Override
public Mono<PageDTO> updateLayoutByContextId(String contextId, Layout layout) {
// Implementation for updating page layout
return Mono.empty();
}
@Override
public String getId(RefactoringMetaDTO refactoringMetaDTO) {
return refactoringMetaDTO.getUpdatedPage() != null
? refactoringMetaDTO.getUpdatedPage().getId()
: null;
}
@Override
public String getArtifactId(RefactoringMetaDTO refactoringMetaDTO) {
return refactoringMetaDTO.getUpdatedPage() != null
? refactoringMetaDTO.getUpdatedPage().getApplicationId()
: null;
}
@Override
public void setUpdatedContext(RefactoringMetaDTO refactoringMetaDTO, LayoutContainer updatedContext) {
refactoringMetaDTO.setUpdatedPage((PageDTO) updatedContext);
}
}

View File

@ -167,7 +167,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
widgetDynamicBindingsMap, widgetDynamicBindingsMap,
executableNameToExecutableMapMono, executableNameToExecutableMapMono,
executableBindingsInDslRef, executableBindingsInDslRef,
evaluatedVersion) evaluatedVersion,
creatorType)
.name(ADD_DIRECTLY_REFERENCED_EXECUTABLES_TO_GRAPH) .name(ADD_DIRECTLY_REFERENCED_EXECUTABLES_TO_GRAPH)
.tap(Micrometer.observation(observationRegistry)); .tap(Micrometer.observation(observationRegistry));
@ -197,7 +198,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
executablesFoundDuringWalkRef, executablesFoundDuringWalkRef,
bindingsFromExecutablesRef, bindingsFromExecutablesRef,
executableNameToExecutableMapMono, executableNameToExecutableMapMono,
evaluatedVersion)) evaluatedVersion,
creatorType))
.name(RECURSIVELY_ADD_EXECUTABLES_AND_THEIR_DEPENDENTS_TO_GRAPH_FROM_BINDINGS) .name(RECURSIVELY_ADD_EXECUTABLES_AND_THEIR_DEPENDENTS_TO_GRAPH_FROM_BINDINGS)
.tap(Micrometer.observation(observationRegistry)) .tap(Micrometer.observation(observationRegistry))
// At last, add all the widget relationships to the graph as well. // At last, add all the widget relationships to the graph as well.
@ -410,7 +412,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
// Finally update the actions which require an update // Finally update the actions which require an update
return Flux.fromIterable(toUpdateExecutables) return Flux.fromIterable(toUpdateExecutables)
.flatMap(executable -> this.updateUnpublishedExecutable(executable.getId(), executable)) .flatMap(executable ->
this.updateUnpublishedExecutable(executable.getId(), executable, creatorType))
.then(Mono.just(TRUE)); .then(Mono.just(TRUE));
}); });
} }
@ -418,12 +421,13 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
@Override @Override
public Mono<Layout> findAndUpdateLayout( public Mono<Layout> findAndUpdateLayout(
String creatorId, CreatorContextType creatorType, String layoutId, Layout layout) { String creatorId, CreatorContextType creatorType, String layoutId, Layout layout) {
return pageExecutableOnLoadService.findAndUpdateLayout(creatorId, layoutId, layout); return getExecutableOnLoadService(creatorType).findAndUpdateLayout(creatorId, layoutId, layout);
} }
private Mono<Executable> updateUnpublishedExecutable(String id, Executable executable) { private Mono<Executable> updateUnpublishedExecutable(
String id, Executable executable, CreatorContextType contextType) {
if (executable instanceof ActionDTO actionDTO) { if (executable instanceof ActionDTO actionDTO) {
return pageExecutableOnLoadService.updateUnpublishedExecutable(id, actionDTO); return getExecutableOnLoadService(contextType).updateUnpublishedExecutable(id, actionDTO);
} else return Mono.just(executable); } else return Mono.just(executable);
} }
@ -437,7 +441,7 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
} }
protected Flux<Executable> getAllExecutablesByCreatorIdFlux(String creatorId, CreatorContextType creatorType) { protected Flux<Executable> getAllExecutablesByCreatorIdFlux(String creatorId, CreatorContextType creatorType) {
return pageExecutableOnLoadService return getExecutableOnLoadService(creatorType)
.getAllExecutablesByCreatorIdFlux(creatorId) .getAllExecutablesByCreatorIdFlux(creatorId)
.name(GET_ALL_EXECUTABLES_BY_CREATOR_ID) .name(GET_ALL_EXECUTABLES_BY_CREATOR_ID)
.tap(Micrometer.observation(observationRegistry)); .tap(Micrometer.observation(observationRegistry));
@ -701,7 +705,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
Map<String, Set<String>> widgetDynamicBindingsMap, Map<String, Set<String>> widgetDynamicBindingsMap,
Mono<Map<String, Executable>> executableNameToExecutableMapMono, Mono<Map<String, Executable>> executableNameToExecutableMapMono,
Set<EntityDependencyNode> executableBindingsInDslRef, Set<EntityDependencyNode> executableBindingsInDslRef,
int evalVersion) { int evalVersion,
CreatorContextType contextType) {
Map<String, Set<EntityDependencyNode>> bindingToWidgetNodesMap = new HashMap<>(); Map<String, Set<EntityDependencyNode>> bindingToWidgetNodesMap = new HashMap<>();
List<String> allBindings = new ArrayList<>(); List<String> allBindings = new ArrayList<>();
@ -741,7 +746,7 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
// candidate for on page load // candidate for on page load
executablesUsedInDSLRef.add(possibleEntity.getValidEntityName()); executablesUsedInDSLRef.add(possibleEntity.getValidEntityName());
return updateExecutableSelfReferencingPaths(possibleEntity) return updateExecutableSelfReferencingPaths(possibleEntity, contextType)
.name(UPDATE_EXECUTABLE_SELF_REFERENCING_PATHS) .name(UPDATE_EXECUTABLE_SELF_REFERENCING_PATHS)
.tap(Micrometer.observation(observationRegistry)) .tap(Micrometer.observation(observationRegistry))
.flatMap(executable -> extractAndSetExecutableBindingsInGraphEdges( .flatMap(executable -> extractAndSetExecutableBindingsInGraphEdges(
@ -763,16 +768,19 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
.thenReturn(edgesRef); .thenReturn(edgesRef);
} }
protected Mono<Executable> updateExecutableSelfReferencingPaths(EntityDependencyNode possibleEntity) { protected Mono<Executable> updateExecutableSelfReferencingPaths(
return this.fillSelfReferencingPaths(possibleEntity.getExecutable()).map(executable -> { EntityDependencyNode possibleEntity, CreatorContextType contextType) {
possibleEntity.setExecutable(executable); return this.fillSelfReferencingPaths(possibleEntity.getExecutable(), contextType)
return executable; .map(executable -> {
}); possibleEntity.setExecutable(executable);
return executable;
});
} }
protected <T extends Executable> Mono<Executable> fillSelfReferencingPaths(T executable) { protected <T extends Executable> Mono<Executable> fillSelfReferencingPaths(
T executable, CreatorContextType contextType) {
if (executable instanceof ActionDTO actionDTO) { if (executable instanceof ActionDTO actionDTO) {
return pageExecutableOnLoadService.fillSelfReferencingPaths(actionDTO); return getExecutableOnLoadService(contextType).fillSelfReferencingPaths(actionDTO);
} else return Mono.just(executable); } else return Mono.just(executable);
} }
@ -1007,7 +1015,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
Map<String, EntityDependencyNode> executablesFoundDuringWalk, Map<String, EntityDependencyNode> executablesFoundDuringWalk,
Set<String> dynamicBindings, Set<String> dynamicBindings,
Mono<Map<String, Executable>> executableNameToExecutableMapMono, Mono<Map<String, Executable>> executableNameToExecutableMapMono,
int evalVersion) { int evalVersion,
CreatorContextType contextType) {
if (dynamicBindings == null || dynamicBindings.isEmpty()) { if (dynamicBindings == null || dynamicBindings.isEmpty()) {
return Mono.just(edges); return Mono.just(edges);
} }
@ -1024,7 +1033,7 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
// Add dependencies of the executables found in the DSL in the graph. // Add dependencies of the executables found in the DSL in the graph.
.flatMap(possibleEntity -> { .flatMap(possibleEntity -> {
if (getExecutableTypes().contains(possibleEntity.getEntityReferenceType())) { if (getExecutableTypes().contains(possibleEntity.getEntityReferenceType())) {
return updateExecutableSelfReferencingPaths(possibleEntity) return updateExecutableSelfReferencingPaths(possibleEntity, contextType)
.name(UPDATE_EXECUTABLE_SELF_REFERENCING_PATHS) .name(UPDATE_EXECUTABLE_SELF_REFERENCING_PATHS)
.tap(Micrometer.observation(observationRegistry)) .tap(Micrometer.observation(observationRegistry))
.then(extractAndSetExecutableBindingsInGraphEdges( .then(extractAndSetExecutableBindingsInGraphEdges(
@ -1052,7 +1061,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
executablesFoundDuringWalk, executablesFoundDuringWalk,
newBindings, newBindings,
executableNameToExecutableMapMono, executableNameToExecutableMapMono,
evalVersion) evalVersion,
contextType)
.name(RECURSIVELY_ADD_EXECUTABLES_AND_THEIR_DEPENDENTS_TO_GRAPH_FROM_BINDINGS) .name(RECURSIVELY_ADD_EXECUTABLES_AND_THEIR_DEPENDENTS_TO_GRAPH_FROM_BINDINGS)
.tap(Micrometer.observation(observationRegistry)); .tap(Micrometer.observation(observationRegistry));
}); });
@ -1091,7 +1101,7 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
return getUnpublishedOnLoadExecutablesExplicitSetByUserInCreatorContextFlux(creatorId, creatorType) return getUnpublishedOnLoadExecutablesExplicitSetByUserInCreatorContextFlux(creatorId, creatorType)
.name(GET_UNPUBLISHED_ON_LOAD_EXECUTABLES_EXPLICIT_SET_BY_USER_IN_CREATOR_CONTEXT) .name(GET_UNPUBLISHED_ON_LOAD_EXECUTABLES_EXPLICIT_SET_BY_USER_IN_CREATOR_CONTEXT)
.tap(Micrometer.observation(observationRegistry)) .tap(Micrometer.observation(observationRegistry))
.flatMap(this::fillSelfReferencingPaths) .flatMap(executable -> fillSelfReferencingPaths(executable, creatorType))
// Add the vertices and edges to the graph for these executables // Add the vertices and edges to the graph for these executables
.flatMap(executable -> { .flatMap(executable -> {
EntityDependencyNode entityDependencyNode = new EntityDependencyNode( EntityDependencyNode entityDependencyNode = new EntityDependencyNode(
@ -1119,7 +1129,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
protected Flux<Executable> getUnpublishedOnLoadExecutablesExplicitSetByUserInCreatorContextFlux( protected Flux<Executable> getUnpublishedOnLoadExecutablesExplicitSetByUserInCreatorContextFlux(
String creatorId, CreatorContextType creatorType) { String creatorId, CreatorContextType creatorType) {
return pageExecutableOnLoadService.getUnpublishedOnLoadExecutablesExplicitSetByUserInPageFlux(creatorId); return getExecutableOnLoadService(creatorType)
.getUnpublishedOnLoadExecutablesExplicitSetByUserInPageFlux(creatorId);
} }
/** /**
@ -1464,4 +1475,8 @@ public class OnLoadExecutablesUtilCEImpl implements OnLoadExecutablesUtilCE {
return onPageLoadCandidates; return onPageLoadCandidates;
} }
protected ExecutableOnLoadService<?> getExecutableOnLoadService(CreatorContextType contextType) {
return pageExecutableOnLoadService;
}
} }

View File

@ -0,0 +1,107 @@
package com.appsmith.server.refactors;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.ce.LayoutContainer;
import com.appsmith.server.dtos.RefactorEntityNameDTO;
import com.appsmith.server.dtos.RefactoringMetaDTO;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* Service interface for handling layout-related refactoring operations within a context
* such as a page or module. It provides methods to retrieve, update, and evaluate layouts
* while preserving consistency during entity renaming or structural changes.
*
* @param <U> The domain type associated with the context (e.g., Page, Module)
* @param <T> The layout container type that holds layouts (e.g., PageDTO, ModuleDTO)
*/
public interface ContextLayoutRefactoringService<U extends BaseDomain, T extends LayoutContainer> {
/**
* Updates the context identified by the given contextId with the provided layout container.
*
* @param contextId The unique identifier of the context to update
* @param dto The layout container containing updated layout information
* @return A Mono emitting the updated layout container
*/
Mono<T> updateContext(String contextId, LayoutContainer dto);
/**
* Retrieves the layout container (DTO) for the given contextId and view mode.
*
* @param contextId The unique identifier of the context
* @param viewMode true for published version, false for unpublished
* @return A Mono emitting the requested layout container
*/
Mono<T> getContextDTOMono(String contextId, boolean viewMode);
/**
* Retrieves the layout container using metadata derived from the refactoring context.
*
* @param refactoringMetaDTO Metadata describing the refactoring context
* @return A Mono emitting the corresponding layout container
*/
Mono<T> getContextDTOMono(RefactoringMetaDTO refactoringMetaDTO);
/**
* Retrieves the evaluation version associated with the context, used to guide DSL parsing or upgrades.
*
* @param contextId The unique identifier of the context
* @param refactorEntityNameDTO DTO containing the old and new entity names
* @param refactoringMetaDTO Metadata describing the refactoring context
* @return A Mono emitting the evaluation version for the context
*/
Mono<Integer> getEvaluationVersionMono(
String contextId, RefactorEntityNameDTO refactorEntityNameDTO, RefactoringMetaDTO refactoringMetaDTO);
/**
* Retrieves the evaluation version for the context without refactor-specific inputs.
*
* @param artifactId The unique identifier of the artifact
* @return A Mono emitting the evaluation version
*/
Mono<Integer> getEvaluationVersionMono(String artifactId);
/**
* Extracts layouts from the provided refactoring metadata.
*
* @param refactoringMetaDTO Metadata describing the refactoring context
* @return A list of layouts associated with the context
*/
List<Layout> getLayouts(RefactoringMetaDTO refactoringMetaDTO);
/**
* Updates a specific layout for the context identified by contextId.
*
* @param contextId The unique identifier of the context
* @param layout The layout to update
* @return A Mono emitting the updated layout container
*/
Mono<T> updateLayoutByContextId(String contextId, Layout layout);
/**
* Retrieves the context ID from the provided refactoring metadata.
*
* @param refactoringMetaDTO Metadata describing the refactoring context
* @return The unique context identifier
*/
String getId(RefactoringMetaDTO refactoringMetaDTO);
/**
* Retrieves the artifact ID from the provided refactoring metadata.
*
* @param refactoringMetaDTO Metadata describing the refactoring context
* @return The artifact identifier associated with the context
*/
String getArtifactId(RefactoringMetaDTO refactoringMetaDTO);
/**
* Updates the in-memory copy of the refactored context in the given metadata object.
*
* @param refactoringMetaDTO Metadata describing the refactoring context
* @param updatedContext The updated layout container to persist in metadata
*/
void setUpdatedContext(RefactoringMetaDTO refactoringMetaDTO, LayoutContainer updatedContext);
}

View File

@ -2,24 +2,23 @@ package com.appsmith.server.refactors.applications;
import com.appsmith.external.constants.AnalyticsEvents; import com.appsmith.external.constants.AnalyticsEvents;
import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.CreatorContextType;
import com.appsmith.server.applications.base.ApplicationService;
import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.ActionCollection;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewAction;
import com.appsmith.server.dtos.EntityType; import com.appsmith.server.dtos.EntityType;
import com.appsmith.server.dtos.LayoutDTO; import com.appsmith.server.dtos.LayoutDTO;
import com.appsmith.server.dtos.PageDTO;
import com.appsmith.server.dtos.RefactorEntityNameDTO; import com.appsmith.server.dtos.RefactorEntityNameDTO;
import com.appsmith.server.dtos.RefactoringMetaDTO; import com.appsmith.server.dtos.RefactoringMetaDTO;
import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.layouts.UpdateLayoutService; import com.appsmith.server.layouts.UpdateLayoutService;
import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.refactors.ContextLayoutRefactoringService;
import com.appsmith.server.refactors.entities.EntityRefactoringService; import com.appsmith.server.refactors.entities.EntityRefactoringService;
import com.appsmith.server.refactors.resolver.ContextLayoutRefactorResolver;
import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.solutions.PagePermission;
import com.appsmith.server.validations.EntityValidationService; import com.appsmith.server.validations.EntityValidationService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -36,7 +35,6 @@ import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.appsmith.server.constants.CommonConstants.EVALUATION_VERSION;
import static com.appsmith.server.helpers.ContextTypeUtils.getDefaultContextIfNull; import static com.appsmith.server.helpers.ContextTypeUtils.getDefaultContextIfNull;
@Slf4j @Slf4j
@ -44,8 +42,6 @@ import static com.appsmith.server.helpers.ContextTypeUtils.getDefaultContextIfNu
public class RefactoringServiceCEImpl implements RefactoringServiceCE { public class RefactoringServiceCEImpl implements RefactoringServiceCE {
private final NewPageService newPageService; private final NewPageService newPageService;
private final UpdateLayoutService updateLayoutService; private final UpdateLayoutService updateLayoutService;
private final ApplicationService applicationService;
private final PagePermission pagePermission;
private final AnalyticsService analyticsService; private final AnalyticsService analyticsService;
private final SessionUserService sessionUserService; private final SessionUserService sessionUserService;
private final EntityValidationService entityValidationService; private final EntityValidationService entityValidationService;
@ -54,6 +50,7 @@ public class RefactoringServiceCEImpl implements RefactoringServiceCE {
protected final EntityRefactoringService<NewAction> newActionEntityRefactoringService; protected final EntityRefactoringService<NewAction> newActionEntityRefactoringService;
protected final EntityRefactoringService<ActionCollection> actionCollectionEntityRefactoringService; protected final EntityRefactoringService<ActionCollection> actionCollectionEntityRefactoringService;
protected final EntityRefactoringService<Layout> widgetEntityRefactoringService; protected final EntityRefactoringService<Layout> widgetEntityRefactoringService;
protected final ContextLayoutRefactorResolver contextLayoutRefactorResolver;
/* /*
* To replace fetchUsers in `{{JSON.stringify(fetchUsers)}}` with getUsers, the following regex is required : * To replace fetchUsers in `{{JSON.stringify(fetchUsers)}}` with getUsers, the following regex is required :
@ -73,7 +70,7 @@ public class RefactoringServiceCEImpl implements RefactoringServiceCE {
* @return : The DSL after refactor updates * @return : The DSL after refactor updates
*/ */
Mono<Tuple2<LayoutDTO, Set<String>>> refactorName(RefactorEntityNameDTO refactorEntityNameDTO) { Mono<Tuple2<LayoutDTO, Set<String>>> refactorName(RefactorEntityNameDTO refactorEntityNameDTO) {
String pageId = refactorEntityNameDTO.getPageId(); String contextId = getBranchedContextId(refactorEntityNameDTO);
String layoutId = refactorEntityNameDTO.getLayoutId(); String layoutId = refactorEntityNameDTO.getLayoutId();
String oldName = refactorEntityNameDTO.getOldFullyQualifiedName(); String oldName = refactorEntityNameDTO.getOldFullyQualifiedName();
@ -83,21 +80,30 @@ public class RefactoringServiceCEImpl implements RefactoringServiceCE {
refactoringMetaDTO.setOldNamePattern(oldNamePattern); refactoringMetaDTO.setOldNamePattern(oldNamePattern);
refactoringMetaDTO.setEvalVersionMono( refactoringMetaDTO.setEvalVersionMono(contextLayoutRefactorResolver
getContextBasedEvalVersionMono(pageId, refactorEntityNameDTO, refactoringMetaDTO)); .getContextLayoutRefactorHelper(refactorEntityNameDTO.getContextType())
.getEvaluationVersionMono(contextId, refactorEntityNameDTO, refactoringMetaDTO));
Mono<Void> refactoredReferencesMono = refactorAllReferences(refactorEntityNameDTO, refactoringMetaDTO); Mono<Void> refactoredReferencesMono = refactorAllReferences(refactorEntityNameDTO, refactoringMetaDTO);
return refactoredReferencesMono.then(Mono.defer(() -> { return refactoredReferencesMono.then(Mono.defer(() -> {
PageDTO page = refactoringMetaDTO.getUpdatedPage();
Set<String> updatedBindingPaths = refactoringMetaDTO.getUpdatedBindingPaths(); Set<String> updatedBindingPaths = refactoringMetaDTO.getUpdatedBindingPaths();
if (page != null) { ContextLayoutRefactoringService<?, ?> contextLayoutRefactorHelper =
List<Layout> layouts = page.getLayouts(); contextLayoutRefactorResolver.getContextLayoutRefactorHelper(
refactorEntityNameDTO.getContextType());
List<Layout> layouts = contextLayoutRefactorHelper.getLayouts(refactoringMetaDTO);
if (layouts != null) {
for (Layout layout : layouts) { for (Layout layout : layouts) {
if (layoutId.equals(layout.getId())) { if (layoutId.equals(layout.getId())) {
layout.setDsl(updateLayoutService.unescapeMongoSpecialCharacters(layout)); layout.setDsl(updateLayoutService.unescapeMongoSpecialCharacters(layout));
String artifactId = contextLayoutRefactorHelper.getArtifactId(refactoringMetaDTO);
return updateLayoutService return updateLayoutService
.updateLayout(page.getId(), page.getApplicationId(), layout.getId(), layout) .updateLayout(
contextId,
artifactId,
layout.getId(),
layout,
refactorEntityNameDTO.getContextType())
.zipWith(Mono.just(updatedBindingPaths)); .zipWith(Mono.just(updatedBindingPaths));
} }
} }
@ -107,27 +113,6 @@ public class RefactoringServiceCEImpl implements RefactoringServiceCE {
})); }));
} }
protected Mono<Integer> getContextBasedEvalVersionMono(
String contextId, RefactorEntityNameDTO refactorEntityNameDTO, RefactoringMetaDTO refactoringMetaDTO) {
Mono<PageDTO> pageMono = newPageService
// fetch the unpublished page
.findPageById(contextId, pagePermission.getEditPermission(), false)
.cache();
refactoringMetaDTO.setPageDTOMono(pageMono);
Mono<Integer> evalVersionMono = pageMono.flatMap(page -> {
return applicationService.findById(page.getApplicationId()).map(application -> {
Integer evaluationVersion = application.getEvaluationVersion();
if (evaluationVersion == null) {
evaluationVersion = EVALUATION_VERSION;
}
return evaluationVersion;
});
})
.cache();
return evalVersionMono;
}
protected static Pattern getReplacementPattern(String oldName) { protected static Pattern getReplacementPattern(String oldName) {
String regexPattern = preWord + oldName + postWord; String regexPattern = preWord + oldName + postWord;
return Pattern.compile(regexPattern); return Pattern.compile(regexPattern);

View File

@ -1,15 +1,14 @@
package com.appsmith.server.refactors.applications; package com.appsmith.server.refactors.applications;
import com.appsmith.server.applications.base.ApplicationService;
import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.ActionCollection;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewAction;
import com.appsmith.server.layouts.UpdateLayoutService; import com.appsmith.server.layouts.UpdateLayoutService;
import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.refactors.entities.EntityRefactoringService; import com.appsmith.server.refactors.entities.EntityRefactoringService;
import com.appsmith.server.refactors.resolver.ContextLayoutRefactorResolver;
import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.solutions.PagePermission;
import com.appsmith.server.validations.EntityValidationService; import com.appsmith.server.validations.EntityValidationService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -17,30 +16,27 @@ import org.springframework.stereotype.Service;
@Service @Service
@Slf4j @Slf4j
public class RefactoringServiceImpl extends RefactoringServiceCEImpl implements RefactoringService { public class RefactoringServiceImpl extends RefactoringServiceCEImpl implements RefactoringService {
public RefactoringServiceImpl( public RefactoringServiceImpl(
NewPageService newPageService, NewPageService newPageService,
UpdateLayoutService updateLayoutService, UpdateLayoutService updateLayoutService,
ApplicationService applicationService,
PagePermission pagePermission,
AnalyticsService analyticsService, AnalyticsService analyticsService,
SessionUserService sessionUserService, SessionUserService sessionUserService,
EntityValidationService entityValidationService, EntityValidationService entityValidationService,
EntityRefactoringService<Void> jsActionEntityRefactoringService, EntityRefactoringService<Void> jsActionEntityRefactoringService,
EntityRefactoringService<NewAction> newActionEntityRefactoringService, EntityRefactoringService<NewAction> newActionEntityRefactoringService,
EntityRefactoringService<ActionCollection> actionCollectionEntityRefactoringService, EntityRefactoringService<ActionCollection> actionCollectionEntityRefactoringService,
EntityRefactoringService<Layout> widgetEntityRefactoringService) { EntityRefactoringService<Layout> widgetEntityRefactoringService,
ContextLayoutRefactorResolver contextLayoutRefactorResolver) {
super( super(
newPageService, newPageService,
updateLayoutService, updateLayoutService,
applicationService,
pagePermission,
analyticsService, analyticsService,
sessionUserService, sessionUserService,
entityValidationService, entityValidationService,
jsActionEntityRefactoringService, jsActionEntityRefactoringService,
newActionEntityRefactoringService, newActionEntityRefactoringService,
actionCollectionEntityRefactoringService, actionCollectionEntityRefactoringService,
widgetEntityRefactoringService); widgetEntityRefactoringService,
contextLayoutRefactorResolver);
} }
} }

View File

@ -0,0 +1,13 @@
package com.appsmith.server.refactors.resolver;
import com.appsmith.server.domains.NewPage;
import com.appsmith.server.dtos.PageDTO;
import com.appsmith.server.refactors.ContextLayoutRefactoringService;
import org.springframework.stereotype.Service;
@Service
public class ContextLayoutRefactorResolver extends ContextLayoutRefactorResolverCE {
public ContextLayoutRefactorResolver(ContextLayoutRefactoringService<NewPage, PageDTO> pageLayoutRefactorService) {
super(pageLayoutRefactorService);
}
}

View File

@ -0,0 +1,21 @@
package com.appsmith.server.refactors.resolver;
import com.appsmith.external.models.CreatorContextType;
import com.appsmith.server.domains.NewPage;
import com.appsmith.server.dtos.PageDTO;
import com.appsmith.server.refactors.ContextLayoutRefactoringService;
import org.springframework.stereotype.Service;
@Service
public class ContextLayoutRefactorResolverCE {
private final ContextLayoutRefactoringService<NewPage, PageDTO> pageLayoutRefactorService;
public ContextLayoutRefactorResolverCE(
ContextLayoutRefactoringService<NewPage, PageDTO> pageLayoutRefactorService) {
this.pageLayoutRefactorService = pageLayoutRefactorService;
}
public ContextLayoutRefactoringService<?, ?> getContextLayoutRefactorHelper(CreatorContextType contextType) {
return pageLayoutRefactorService;
}
}

View File

@ -1,18 +1,19 @@
package com.appsmith.server.widgets.refactors; package com.appsmith.server.widgets.refactors;
import com.appsmith.external.constants.AnalyticsEvents; import com.appsmith.external.constants.AnalyticsEvents;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.external.models.CreatorContextType; import com.appsmith.external.models.CreatorContextType;
import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.ce.LayoutContainer;
import com.appsmith.server.dtos.EntityType; import com.appsmith.server.dtos.EntityType;
import com.appsmith.server.dtos.PageDTO;
import com.appsmith.server.dtos.RefactorEntityNameDTO; import com.appsmith.server.dtos.RefactorEntityNameDTO;
import com.appsmith.server.dtos.RefactoringMetaDTO; import com.appsmith.server.dtos.RefactoringMetaDTO;
import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.refactors.ContextLayoutRefactoringService;
import com.appsmith.server.refactors.entities.EntityRefactoringServiceCE; import com.appsmith.server.refactors.entities.EntityRefactoringServiceCE;
import com.appsmith.server.services.AstService; import com.appsmith.server.refactors.resolver.ContextLayoutRefactorResolver;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -26,16 +27,15 @@ import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static com.appsmith.external.constants.AnalyticsEvents.REFACTOR_WIDGET; import static com.appsmith.external.constants.AnalyticsEvents.REFACTOR_WIDGET;
import static com.appsmith.server.helpers.ContextTypeUtils.isModuleContext;
import static com.appsmith.server.helpers.ContextTypeUtils.isPageContext; import static com.appsmith.server.helpers.ContextTypeUtils.isPageContext;
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public class WidgetRefactoringServiceCEImpl implements EntityRefactoringServiceCE<Layout> { public class WidgetRefactoringServiceCEImpl implements EntityRefactoringServiceCE<Layout> {
protected final ObjectMapper objectMapper;
private final NewPageService newPageService; protected final WidgetRefactorUtil widgetRefactorUtil;
private final AstService astService; private final ContextLayoutRefactorResolver contextLayoutRefactorResolver;
private final ObjectMapper objectMapper;
private final WidgetRefactorUtil widgetRefactorUtil;
@Override @Override
public AnalyticsEvents getRefactorAnalyticsEvent(EntityType entityType) { public AnalyticsEvents getRefactorAnalyticsEvent(EntityType entityType) {
@ -45,53 +45,67 @@ public class WidgetRefactoringServiceCEImpl implements EntityRefactoringServiceC
@Override @Override
public Mono<Void> refactorReferencesInExistingEntities( public Mono<Void> refactorReferencesInExistingEntities(
RefactorEntityNameDTO refactorEntityNameDTO, RefactoringMetaDTO refactoringMetaDTO) { RefactorEntityNameDTO refactorEntityNameDTO, RefactoringMetaDTO refactoringMetaDTO) {
if (!isPageContext(refactorEntityNameDTO.getContextType())) { if (!isPageContext(refactorEntityNameDTO.getContextType())
&& !isModuleContext(refactorEntityNameDTO.getContextType())) {
return Mono.empty().then(); return Mono.empty().then();
} }
Mono<PageDTO> pageMono = refactoringMetaDTO.getPageDTOMono();
Mono<Integer> evalVersionMono = refactoringMetaDTO.getEvalVersionMono();
Set<String> updatedBindingPaths = refactoringMetaDTO.getUpdatedBindingPaths();
Pattern oldNamePattern = refactoringMetaDTO.getOldNamePattern();
CreatorContextType contextType = refactorEntityNameDTO.getContextType();
String layoutId = refactorEntityNameDTO.getLayoutId(); String layoutId = refactorEntityNameDTO.getLayoutId();
String oldName = refactorEntityNameDTO.getOldFullyQualifiedName(); String oldName = refactorEntityNameDTO.getOldFullyQualifiedName();
String newName = refactorEntityNameDTO.getNewFullyQualifiedName(); String newName = refactorEntityNameDTO.getNewFullyQualifiedName();
Mono<PageDTO> pageDTOMono = Mono.zip(pageMono, evalVersionMono).flatMap(tuple -> { Set<String> updatedBindingPaths = refactoringMetaDTO.getUpdatedBindingPaths();
PageDTO page = tuple.getT1(); Pattern oldNamePattern = refactoringMetaDTO.getOldNamePattern();
int evalVersion = tuple.getT2();
List<Layout> layouts = page.getLayouts(); // Get the appropriate context refactor service based on context type
for (Layout layout : layouts) { ContextLayoutRefactoringService<? extends BaseDomain, ? extends LayoutContainer> contextLayoutRefactorHelper =
if (layoutId.equals(layout.getId()) && layout.getDsl() != null) { contextLayoutRefactorResolver.getContextLayoutRefactorHelper(contextType);
// DSL has removed all the old names and replaced it with new name. If the change of name
// was one of the mongoEscaped widgets, then update the names in the set as well
Set<String> mongoEscapedWidgetNames = layout.getMongoEscapedWidgetNames();
if (mongoEscapedWidgetNames != null && mongoEscapedWidgetNames.contains(oldName)) {
mongoEscapedWidgetNames.remove(oldName);
mongoEscapedWidgetNames.add(newName);
}
final JsonNode dslNode = objectMapper.convertValue(layout.getDsl(), JsonNode.class); // Get context DTO mono (either PageDTO or ModuleDTO)
Mono<PageDTO> refactorNameInDslMono = widgetRefactorUtil Mono<? extends LayoutContainer> contextDTOMono =
.refactorNameInDsl(dslNode, oldName, newName, evalVersion, oldNamePattern) contextLayoutRefactorHelper.getContextDTOMono(refactoringMetaDTO);
.flatMap(dslBindingPaths -> {
updatedBindingPaths.addAll(dslBindingPaths);
layout.setDsl(objectMapper.convertValue(dslNode, JSONObject.class));
page.setLayouts(layouts);
refactoringMetaDTO.setUpdatedPage(page);
return Mono.just(page);
});
// Since the page has most probably changed, save the page and return. return contextDTOMono
return refactorNameInDslMono.flatMap(newPageService::saveUnpublishedPage); .flatMap(contextDTO -> {
} String contextId = contextDTO.getId();
} Mono<Integer> evalVersionMono = contextLayoutRefactorHelper.getEvaluationVersionMono(
// If we have reached here, the layout was not found and the page should be returned as is. contextId, refactorEntityNameDTO, refactoringMetaDTO);
return Mono.just(page);
});
return pageDTOMono.then(); return evalVersionMono.flatMap(evalVersion -> {
List<Layout> layouts = contextDTO.getLayouts();
if (layouts == null) {
return Mono.just(contextDTO);
}
for (Layout layout : layouts) {
if (layoutId.equals(layout.getId()) && layout.getDsl() != null) {
// DSL has removed all the old names and replaced it with new name. If the change of
// name
// was one of the mongoEscaped widgets, then update the names in the set as well
Set<String> mongoEscapedWidgetNames = layout.getMongoEscapedWidgetNames();
if (mongoEscapedWidgetNames != null && mongoEscapedWidgetNames.contains(oldName)) {
mongoEscapedWidgetNames.remove(oldName);
mongoEscapedWidgetNames.add(newName);
}
final JsonNode dslNode = objectMapper.convertValue(layout.getDsl(), JsonNode.class);
return widgetRefactorUtil
.refactorNameInDsl(dslNode, oldName, newName, evalVersion, oldNamePattern)
.flatMap(dslBindingPaths -> {
updatedBindingPaths.addAll(dslBindingPaths);
layout.setDsl(objectMapper.convertValue(dslNode, JSONObject.class));
contextDTO.setLayouts(layouts);
contextLayoutRefactorHelper.setUpdatedContext(
refactoringMetaDTO, contextDTO);
return contextLayoutRefactorHelper.updateContext(contextId, contextDTO);
});
}
}
return Mono.just(contextDTO);
});
})
.then();
} }
@Override @Override
@ -103,23 +117,26 @@ public class WidgetRefactoringServiceCEImpl implements EntityRefactoringServiceC
@Override @Override
public Flux<String> getExistingEntityNames( public Flux<String> getExistingEntityNames(
String contextId, CreatorContextType contextType, String layoutId, boolean viewMode) { String contextId, CreatorContextType contextType, String layoutId, boolean viewMode) {
return newPageService Mono<?> contextDTOMono = contextLayoutRefactorResolver
// fetch the unpublished page .getContextLayoutRefactorHelper(contextType)
.findPageById(contextId, null, viewMode) .getContextDTOMono(contextId, viewMode);
.flatMapMany(page -> { return contextDTOMono.flatMapMany(contextDTO -> {
List<Layout> layouts = page.getLayouts(); LayoutContainer layoutContainer = (LayoutContainer) contextDTO;
for (Layout layout : layouts) { List<Layout> layouts = layoutContainer.getLayouts();
if (layoutId.equals(layout.getId())) { if (layouts == null) {
if (layout.getWidgetNames() != null return Flux.empty();
&& layout.getWidgetNames().size() > 0) { }
return Flux.fromIterable(layout.getWidgetNames()); for (Layout layout : layouts) {
} if (layoutId.equals(layout.getId())) {
// In case of no widget names (which implies that there is no DSL), return an empty set. if (layout.getWidgetNames() != null
return Flux.empty(); && !layout.getWidgetNames().isEmpty()) {
} return Flux.fromIterable(layout.getWidgetNames());
} }
return Flux.error( // In case of no widget names (which implies that there is no DSL), return an empty set.
new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.LAYOUT_ID, layoutId)); return Flux.empty();
}); }
}
return Flux.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.LAYOUT_ID, layoutId));
});
} }
} }

View File

@ -1,9 +1,8 @@
package com.appsmith.server.widgets.refactors; package com.appsmith.server.widgets.refactors;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.refactors.entities.EntityRefactoringService; import com.appsmith.server.refactors.entities.EntityRefactoringService;
import com.appsmith.server.services.AstService; import com.appsmith.server.refactors.resolver.ContextLayoutRefactorResolver;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -11,10 +10,9 @@ import org.springframework.stereotype.Service;
public class WidgetRefactoringServiceImpl extends WidgetRefactoringServiceCEImpl public class WidgetRefactoringServiceImpl extends WidgetRefactoringServiceCEImpl
implements EntityRefactoringService<Layout> { implements EntityRefactoringService<Layout> {
public WidgetRefactoringServiceImpl( public WidgetRefactoringServiceImpl(
NewPageService newPageService,
AstService astService,
ObjectMapper objectMapper, ObjectMapper objectMapper,
WidgetRefactorUtil widgetRefactorUtil) { WidgetRefactorUtil widgetRefactorUtil,
super(newPageService, astService, objectMapper, widgetRefactorUtil); ContextLayoutRefactorResolver contextLayoutRefactorResolver) {
super(objectMapper, widgetRefactorUtil, contextLayoutRefactorResolver);
} }
} }

View File

@ -20,6 +20,7 @@ import com.appsmith.server.newactions.base.NewActionService;
import com.appsmith.server.newpages.base.NewPageService; import com.appsmith.server.newpages.base.NewPageService;
import com.appsmith.server.refactors.applications.RefactoringServiceCEImpl; import com.appsmith.server.refactors.applications.RefactoringServiceCEImpl;
import com.appsmith.server.refactors.entities.EntityRefactoringService; import com.appsmith.server.refactors.entities.EntityRefactoringService;
import com.appsmith.server.refactors.resolver.ContextLayoutRefactorResolver;
import com.appsmith.server.repositories.ActionCollectionRepository; import com.appsmith.server.repositories.ActionCollectionRepository;
import com.appsmith.server.services.AnalyticsService; import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.SessionUserService; import com.appsmith.server.services.SessionUserService;
@ -90,6 +91,9 @@ class RefactoringServiceCEImplTest {
@SpyBean @SpyBean
private EntityRefactoringService<Layout> widgetEntityRefactoringService; private EntityRefactoringService<Layout> widgetEntityRefactoringService;
@SpyBean
private ContextLayoutRefactorResolver contextLayoutRefactorResolver;
@Autowired @Autowired
private EntityValidationService entityValidationService; private EntityValidationService entityValidationService;
@ -101,15 +105,14 @@ class RefactoringServiceCEImplTest {
refactoringServiceCE = new RefactoringServiceCEImpl( refactoringServiceCE = new RefactoringServiceCEImpl(
newPageService, newPageService,
updateLayoutService, updateLayoutService,
applicationService,
pagePermission,
analyticsService, analyticsService,
sessionUserService, sessionUserService,
entityValidationService, entityValidationService,
jsActionEntityRefactoringService, jsActionEntityRefactoringService,
newActionEntityRefactoringService, newActionEntityRefactoringService,
actionCollectionEntityRefactoringService, actionCollectionEntityRefactoringService,
widgetEntityRefactoringService); widgetEntityRefactoringService,
contextLayoutRefactorResolver);
} }
@Test @Test
@ -167,7 +170,7 @@ class RefactoringServiceCEImplTest {
.thenReturn(Flux.empty()); .thenReturn(Flux.empty());
Mockito.when(updateLayoutService.updateLayout( Mockito.when(updateLayoutService.updateLayout(
Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any())) Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any()))
.thenReturn(Mono.just(layout)); .thenReturn(Mono.just(layout));
Mockito.doReturn(Flux.just(oldUnpublishedCollection.getName())) Mockito.doReturn(Flux.just(oldUnpublishedCollection.getName()))
@ -305,7 +308,7 @@ class RefactoringServiceCEImplTest {
layout.setLayoutOnLoadActions(new ArrayList<>()); layout.setLayoutOnLoadActions(new ArrayList<>());
Mockito.when(updateLayoutService.updateLayout( Mockito.when(updateLayoutService.updateLayout(
Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any())) Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.any(), Mockito.any()))
.thenReturn(Mono.just(layout)); .thenReturn(Mono.just(layout));
Mockito.doReturn(Flux.just(oldUnpublishedCollection.getName())) Mockito.doReturn(Flux.just(oldUnpublishedCollection.getName()))