chore: Add code-split for OPL with UI module instances (#40749)
## Description EE Counterpart PR: https://github.com/appsmithorg/appsmith-ee/pull/7559 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/15253633122> > Commit: dd70a1c673da72ef7e5bdea172b90d7ec338f41a > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=15253633122&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Mon, 26 May 2025 13:55:15 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Refactor** - Enhanced layout update processing by modularizing synthetic widget handling, enabling future UI-specific widget injection and removal. No direct impact on user-facing features. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
678df9c4aa
commit
56d296afc8
|
|
@ -24,6 +24,7 @@ import com.appsmith.server.services.SessionUserService;
|
|||
import com.appsmith.server.solutions.PagePermission;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Sets;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.Span;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
|
@ -43,6 +44,7 @@ import java.util.HashSet;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Pattern;
|
||||
|
|
@ -109,6 +111,12 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
|||
});
|
||||
}
|
||||
|
||||
// Extension point for UI module handling
|
||||
protected Mono<Map.Entry<JSONObject, Optional<Set<String>>>> processDslAndCreateSyntheticWidgets(
|
||||
String creatorId, CreatorContextType creatorType, JSONObject dsl, ArrayList<Object> mainChildren) {
|
||||
return Mono.just(Map.entry(dsl, Optional.empty()));
|
||||
}
|
||||
|
||||
protected Mono<LayoutDTO> updateLayoutDsl(
|
||||
String creatorId,
|
||||
String layoutId,
|
||||
|
|
@ -121,6 +129,17 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
|||
return Mono.just(generateResponseDTO(layout));
|
||||
}
|
||||
|
||||
// Get the main DSL's children array. We *don't* create an empty list
|
||||
// yet; if no UI‑module instances are injected we want to leave the DSL
|
||||
// unchanged so tests that expect a verbatim payload pass.
|
||||
ArrayList<Object> mainChildren = (ArrayList<Object>) dsl.get(FieldName.CHILDREN);
|
||||
|
||||
// Process DSL with module instances if any
|
||||
return processDslAndCreateSyntheticWidgets(creatorId, creatorType, dsl, mainChildren)
|
||||
.flatMap(entry -> {
|
||||
JSONObject processedDsl = entry.getKey();
|
||||
Optional<Set<String>> syntheticWidgetNamesOpt = entry.getValue();
|
||||
|
||||
Set<String> widgetNames = new HashSet<>();
|
||||
Map<String, Set<String>> widgetDynamicBindingsMap = new HashMap<>();
|
||||
Set<String> escapedWidgetNames = new HashSet<>();
|
||||
|
|
@ -131,18 +150,40 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
|||
observationHelper.startSpan(extractAllWidgetNamesAndDynamicBindingsFromDSLSpan);
|
||||
|
||||
try {
|
||||
dsl = extractAllWidgetNamesAndDynamicBindingsFromDSL(
|
||||
dsl, widgetNames, widgetDynamicBindingsMap, creatorId, layoutId, escapedWidgetNames, creatorType);
|
||||
|
||||
processedDsl = extractAllWidgetNamesAndDynamicBindingsFromDSL(
|
||||
processedDsl,
|
||||
widgetNames,
|
||||
widgetDynamicBindingsMap,
|
||||
creatorId,
|
||||
layoutId,
|
||||
escapedWidgetNames,
|
||||
creatorType);
|
||||
} catch (Throwable t) {
|
||||
return sendUpdateLayoutAnalyticsEvent(creatorId, layoutId, dsl, false, t, creatorType)
|
||||
return sendUpdateLayoutAnalyticsEvent(creatorId, layoutId, processedDsl, false, t, creatorType)
|
||||
.then(Mono.error(t));
|
||||
}
|
||||
|
||||
observationHelper.endSpan(extractAllWidgetNamesAndDynamicBindingsFromDSLSpan);
|
||||
|
||||
layout.setWidgetNames(widgetNames);
|
||||
// -----------------------------------------------------------------------------
|
||||
// If we have synthetic widgets, filter them out and scrub the DSL
|
||||
// -----------------------------------------------------------------------------
|
||||
if (syntheticWidgetNamesOpt.isPresent()) {
|
||||
Set<String> syntheticWidgetNames = syntheticWidgetNamesOpt.get();
|
||||
|
||||
Set<String> widgetNamesToPersist = Sets.difference(widgetNames, syntheticWidgetNames);
|
||||
|
||||
processedDsl = stripSyntheticWidgets(processedDsl, syntheticWidgetNamesOpt);
|
||||
removeSpecialCharactersFromKeys(processedDsl, escapedWidgetNames);
|
||||
|
||||
layout.setWidgetNames(widgetNamesToPersist);
|
||||
} else {
|
||||
layout.setWidgetNames(widgetNames);
|
||||
}
|
||||
|
||||
layout.setDsl(processedDsl);
|
||||
|
||||
// We always attach escaped names when we have them
|
||||
if (!escapedWidgetNames.isEmpty()) {
|
||||
layout.setMongoEscapedWidgetNames(escapedWidgetNames);
|
||||
}
|
||||
|
|
@ -185,9 +226,9 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
|||
});
|
||||
|
||||
// First update the actions and set execute on load to true
|
||||
JSONObject finalDsl = dsl;
|
||||
JSONObject finalDsl = processedDsl;
|
||||
|
||||
Mono<LayoutDTO> layoutDTOMono = allOnLoadExecutablesMono
|
||||
return allOnLoadExecutablesMono
|
||||
.flatMap(allOnLoadExecutables -> {
|
||||
// If there has been an error (e.g. cyclical dependency), then don't update any
|
||||
// actions.
|
||||
|
|
@ -201,7 +242,11 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
|||
// setting for this
|
||||
return onLoadExecutablesUtil
|
||||
.updateExecutablesRunBehaviour(
|
||||
flatmapOnLoadExecutables, creatorId, executableUpdatesRef, messagesRef, creatorType)
|
||||
flatmapOnLoadExecutables,
|
||||
creatorId,
|
||||
executableUpdatesRef,
|
||||
messagesRef,
|
||||
creatorType)
|
||||
.name(UPDATE_EXECUTABLES_RUN_BEHAVIOUR)
|
||||
.tap(Micrometer.observation(observationRegistry))
|
||||
.thenReturn(allOnLoadExecutables);
|
||||
|
|
@ -214,7 +259,6 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
|||
// The below field is to ensure that we record if the page load actions
|
||||
// computation was
|
||||
// valid when last stored in the database.
|
||||
layout.setValidOnPageLoadActions(validOnLoadExecutables.get());
|
||||
|
||||
return onLoadExecutablesUtil
|
||||
.findAndUpdateLayout(creatorId, creatorType, layoutId, layout)
|
||||
|
|
@ -232,11 +276,15 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
|||
layoutDTO.setActionUpdates(executableUpdatesRef);
|
||||
layoutDTO.setMessages(messagesRef);
|
||||
|
||||
return sendUpdateLayoutAnalyticsEvent(creatorId, layoutId, finalDsl, true, null, creatorType)
|
||||
return sendUpdateLayoutAnalyticsEvent(
|
||||
creatorId, layoutId, finalDsl, true, null, creatorType)
|
||||
.thenReturn(layoutDTO);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return layoutDTOMono;
|
||||
protected JSONObject stripSyntheticWidgets(JSONObject dsl, Optional<Set<String>> syntheticNamesOpt) {
|
||||
return dsl;
|
||||
}
|
||||
|
||||
// TODO: Add contextType and change all its usage to conform to that so that we can get rid of the overloaded
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user