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..a787ec00e 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,35 @@ 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 = 0; i < subContainers.size(); 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.reversed() + .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,