From 88e97641bed2c13c67e13ef58a1514fd215f54f3 Mon Sep 17 00:00:00 2001 From: Boubaker Khanfir Date: Tue, 7 May 2024 12:19:14 +0100 Subject: [PATCH] fix: Fix Dynamic Layout Edition - MEED-6791 - Meeds-io/MIPs#131 (#55) Prior to this change, when cloning a page for edition, the dynamic container isn't replaced by child applications. This change ensures to retrieve the list of applications of dynamic container instead of the dynamic container itself when editing a page. --- .../layout/service/PageLayoutService.java | 30 +++++++++++++++++++ .../layout/service/PageLayoutServiceTest.java | 21 ++++++++++++- .../layout-editor/components/LayoutEditor.vue | 19 ++++-------- .../content/container/Container.vue | 4 +++ 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java b/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java index 8501c9812..2093fc652 100644 --- a/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java +++ b/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java @@ -19,6 +19,7 @@ package io.meeds.layout.service; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; import java.util.UUID; @@ -188,6 +189,7 @@ public PageKey clonePage(PageKey pageKey, page.resetStorage(); page.setName(page.getName() + "_draft_" + username); page.setTitle(page.getTitle() + " Draft " + username); + replaceAddonContainerChildren(page); layoutService.save(new PageContext(page.getPageKey(), Utils.toPageState(page)), page); return page.getPageKey(); @@ -328,6 +330,34 @@ private void expandAddonContainerChildren(Container container) { } } + private void replaceAddonContainerChildren(Container container) { + ArrayList subContainers = container.getChildren(); + if (subContainers == null) { + return; + } + LinkedHashMap>> addonContainerChildren = new LinkedHashMap<>(); + for (int i = subContainers.size() - 1; i >= 0; i--) { + ModelObject modelObject = subContainers.get(i); + if (modelObject instanceof Container subContainer) { + if (StringUtils.equals(subContainer.getFactoryId(), "addonContainer")) { + List> applications = addOnService.getApplications(subContainer.getName()); + if (CollectionUtils.isNotEmpty(applications)) { + addonContainerChildren.put(i, applications); + } + } else { + replaceAddonContainerChildren(subContainer); + } + } + } + if (!addonContainerChildren.isEmpty()) { + addonContainerChildren.forEach((index, applications) -> { + subContainers.remove(index.intValue()); + subContainers.addAll(index, applications); + }); + container.setChildren(subContainers); + } + } + private void validateCSSInputs(ModelObject modelObject) { String width; String height; diff --git a/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java b/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java index 4452052fb..b99570052 100644 --- a/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java +++ b/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java @@ -158,6 +158,7 @@ public void getPageLayout() throws IllegalAccessException, ObjectNotFoundExcepti assertEquals(page, pageLayoutService.getPageLayout(PAGE_KEY, TEST_USER)); } + @SuppressWarnings("unchecked") @Test public void getPageLayoutWithDynamicContainer() { when(layoutService.getPage(PAGE_KEY)).thenReturn(page); @@ -168,7 +169,8 @@ public void getPageLayoutWithDynamicContainer() { Application application = mock(Application.class); when(addOnService.getApplications("testAddonContainer")).thenReturn(Collections.singletonList(application)); pageLayoutService.getPageLayout(PAGE_KEY); - verify(dynamicContainer).setChildren(argThat(children -> children != null && children.size() == 1 && children.get(0) == application)); + verify(dynamicContainer).setChildren(argThat(children -> children != null && children.size() == 1 + && children.get(0) == application)); } @Test @@ -230,6 +232,23 @@ public void clonePage() throws IllegalAccessException, ObjectNotFoundException { verify(layoutService).save(any(PageContext.class), eq(page)); } + @SuppressWarnings("unchecked") + @Test + public void clonePageWithDynamicContainer() throws IllegalAccessException, ObjectNotFoundException { + when(layoutService.getPage(PAGE_KEY)).thenReturn(page); + Container dynamicContainer = mock(Container.class); + when(dynamicContainer.getFactoryId()).thenReturn("addonContainer"); + when(dynamicContainer.getName()).thenReturn("testAddonContainer"); + when(page.getChildren()).thenReturn(new ArrayList<>(Collections.singleton(dynamicContainer))); + Application application = mock(Application.class); + when(addOnService.getApplications("testAddonContainer")).thenReturn(Collections.singletonList(application)); + when(aclService.canEditPage(PAGE_KEY, TEST_USER)).thenReturn(true); + when(page.getName()).thenReturn(PAGE_KEY.getName()); + + pageLayoutService.clonePage(PAGE_KEY, TEST_USER); + verify(page).setChildren(argThat(children -> children != null && children.size() == 1 && children.get(0) == application)); + } + @SuppressWarnings("unchecked") @Test public void updatePageLayout() throws IllegalAccessException, ObjectNotFoundException { diff --git a/layout-webapp/src/main/webapp/vue-app/layout-editor/components/LayoutEditor.vue b/layout-webapp/src/main/webapp/vue-app/layout-editor/components/LayoutEditor.vue index 8008d4f78..da77f6c34 100644 --- a/layout-webapp/src/main/webapp/vue-app/layout-editor/components/LayoutEditor.vue +++ b/layout-webapp/src/main/webapp/vue-app/layout-editor/components/LayoutEditor.vue @@ -26,11 +26,11 @@
@@ -42,7 +42,7 @@ export default { data: () => ({ node: null, - page: null, + pageContext: null, draftNode: null, draftLayout: null, nodeLabels: null, @@ -67,24 +67,15 @@ export default { draftPageRef() { return this.draftPageKey?.ref || (this.draftPageKey && `${this.draftPageKey.site.typeName}::${this.draftPageKey.site.name}::${this.draftPageKey.name}`); }, - pageLoaded() { - return !!this.draftPageRef && !!this.page; - }, }, watch: { - pageLoaded() { - if (this.pageLoaded) { - this.$pageLayoutService.getPageLayout(this.draftPageRef, 'contentId') - .then(draftLayout => this.setDraftLayout(draftLayout)); - } - }, pageRef: { immediate: true, handler() { if (this.pageRef) { this.$root.pageRef = this.pageRef; this.$pageLayoutService.getPage(this.pageRef) - .then(page => this.page = page); + .then(page => this.pageContext = page); } }, }, @@ -93,6 +84,8 @@ export default { handler() { if (this.draftPageRef) { this.$root.draftPageRef = this.draftPageRef; + this.$pageLayoutService.getPageLayout(this.draftPageRef, 'contentId') + .then(draftLayout => this.setDraftLayout(draftLayout)); } }, }, diff --git a/layout-webapp/src/main/webapp/vue-app/layout-editor/components/content/container/Container.vue b/layout-webapp/src/main/webapp/vue-app/layout-editor/components/content/container/Container.vue index 6a8163e29..b97170c8b 100644 --- a/layout-webapp/src/main/webapp/vue-app/layout-editor/components/content/container/Container.vue +++ b/layout-webapp/src/main/webapp/vue-app/layout-editor/components/content/container/Container.vue @@ -32,6 +32,10 @@ export default { type: Object, default: null, }, + parentId: { + type: String, + default: null, + }, index: { type: Number, default: null,