From 2c46788dcb9ecf26c176bf08ca566e779083e39f Mon Sep 17 00:00:00 2001 From: Boubaker Khanfir Date: Wed, 29 May 2024 15:23:26 +0100 Subject: [PATCH] feat: Allow to add, edit and delete a Portlet instance - MEED-6946 - Meeds-io/MIPs#139 (#88) --- .../rest/PortletInstanceCategoryRest.java | 10 +- .../layout/rest/PortletInstanceRest.java | 10 +- .../service/PortletInstanceService.java | 73 ++++-- .../io/meeds/layout/util/EntityMapper.java | 8 +- .../rest/PortletInstanceCategoryRestTest.java | 4 +- .../layout/rest/PortletInstanceRestTest.java | 4 +- .../service/PortletInstanceServiceTest.java | 62 +++-- .../locale/portlet/LayoutEditor_en.properties | 26 +- .../components/PageTemplatePreview.vue | 3 +- .../components/PortletsManagement.vue | 1 + .../portlets/components/header/Toolbar.vue | 21 +- .../components/instances/Categories.vue | 11 +- .../components/instances/CategoryItem.vue | 2 +- .../portlets/components/instances/Menu.vue | 42 +--- .../instances/drawer/CategoryDrawer.vue | 3 + .../instances/drawer/InstanceDrawer.vue | 223 ++++++++++++++++++ .../instances/form/CategoryInput.vue | 76 ++++++ .../instances/form/InstancePreview.vue | 143 +++++++++++ .../instances/form/PortletInput.vue | 81 +++++++ .../portlets/drawer/InstancesDrawer.vue | 1 + .../webapp/vue-app/portlets/initComponents.js | 13 +- .../src/main/webapp/vue-app/portlets/main.js | 13 +- 22 files changed, 717 insertions(+), 113 deletions(-) create mode 100644 layout-webapp/src/main/webapp/vue-app/portlets/components/instances/drawer/InstanceDrawer.vue create mode 100644 layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/CategoryInput.vue create mode 100644 layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/InstancePreview.vue create mode 100644 layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/PortletInput.vue diff --git a/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceCategoryRest.java b/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceCategoryRest.java index bfaf1acf1..791169701 100644 --- a/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceCategoryRest.java +++ b/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceCategoryRest.java @@ -59,7 +59,7 @@ public class PortletInstanceCategoryRest { description = "This retrieves portlet instance categorys") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), }) public List getPortletInstanceCategorys(HttpServletRequest request) { - return portletInstanceService.getPortletInstanceCategories(request.getLocale(), true); + return portletInstanceService.getPortletInstanceCategories(request.getRemoteUser(), request.getLocale(), true); } @GetMapping("{id}") @@ -72,7 +72,13 @@ public PortletInstanceCategory getPortletInstanceCategory( @Parameter(description = "Portlet instance category identifier") @PathVariable("id") long id) { - return portletInstanceService.getPortletInstanceCategory(id, request.getLocale(), true); + try { + return portletInstanceService.getPortletInstanceCategory(id, request.getRemoteUser(), request.getLocale(), true); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } } @PostMapping diff --git a/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceRest.java b/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceRest.java index 40660f13f..96dee9efc 100644 --- a/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceRest.java +++ b/layout-service/src/main/java/io/meeds/layout/rest/PortletInstanceRest.java @@ -63,7 +63,7 @@ public List getPortletInstances( @Parameter(description = "Portlet instance category identifier") @RequestParam(name = "categoryId", required = false, defaultValue = "0") long categoryId) { - return portletInstanceService.getPortletInstances(categoryId, request.getLocale(), true); + return portletInstanceService.getPortletInstances(categoryId, request.getRemoteUser(), request.getLocale(), true); } @GetMapping("{id}") @@ -76,7 +76,13 @@ public PortletInstance getPortletInstance( @Parameter(description = "Portlet instance identifier") @PathVariable("id") long id) { - return portletInstanceService.getPortletInstance(id, request.getLocale(), true); + try { + return portletInstanceService.getPortletInstance(id, request.getRemoteUser(), request.getLocale(), true); + } catch (ObjectNotFoundException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND); + } catch (IllegalAccessException e) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } } @PostMapping diff --git a/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java b/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java index c9eca590e..369fef0dc 100644 --- a/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java +++ b/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java @@ -18,11 +18,13 @@ */ package io.meeds.layout.service; +import java.util.Collections; import java.util.List; import java.util.Locale; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -45,7 +47,9 @@ @Service public class PortletInstanceService { - private static final Log LOG = ExoLogger.getLogger(PortletInstanceService.class); + private static final List EVERYONE_PERMISSIONS_LIST = Collections.singletonList("Everyone"); + + private static final Log LOG = ExoLogger.getLogger(PortletInstanceService.class); @Autowired private LayoutAclService layoutAclService; @@ -66,44 +70,51 @@ public class PortletInstanceService { private PortletInstanceStorage portletInstanceStorage; public List getPortletInstances() { - return getPortletInstances(null, false); - } - - public List getPortletInstances(boolean expand) { - return getPortletInstances(null, expand); - } - - public List getPortletInstances(Locale locale, - boolean expand) { - return getPortletInstances(0, locale, expand); + return portletInstanceStorage.getPortletInstances(); } public List getPortletInstances(long categoryId, + String username, Locale locale, boolean expand) { List portletInstances = categoryId < 1 ? portletInstanceStorage.getPortletInstances() : portletInstanceStorage.getPortletInstances(categoryId); + portletInstances = portletInstances.stream().filter(p -> this.hasPermission(p, username)).toList(); if (expand) { - portletInstances.forEach(portletInstance -> computePortletInstanceAttributes(locale, portletInstance)); + portletInstances.stream() + .forEach(portletInstance -> computePortletInstanceAttributes(locale, portletInstance)); } return portletInstances; } public List getPortletInstanceCategories() { - return getPortletInstanceCategories(null, false); + return portletInstanceCategoryStorage.getPortletInstanceCategories(); } - public List getPortletInstanceCategories(Locale locale, boolean expand) { + public List getPortletInstanceCategories(String username, + Locale locale, + boolean expand) { List portletInstanceCategories = portletInstanceCategoryStorage.getPortletInstanceCategories(); + portletInstanceCategories = portletInstanceCategories.stream().filter(c -> this.hasPermission(c, username)).toList(); if (expand && locale != null) { - portletInstanceCategories.forEach(portletInstance -> computePortletInstanceCategoryAttributes(locale, portletInstance)); + portletInstanceCategories.stream() + .forEach(c -> computePortletInstanceCategoryAttributes(locale, c)); } return portletInstanceCategories; } - public PortletInstance getPortletInstance(long id, Locale locale, boolean expand) { + public PortletInstance getPortletInstance(long id, + String username, + Locale locale, + boolean expand) throws IllegalAccessException, ObjectNotFoundException { PortletInstance portletInstance = portletInstanceStorage.getPortletInstance(id); - if (expand && portletInstance != null) { + if (portletInstance == null) { + throw new ObjectNotFoundException("Portlet instance not found"); + } + if (!this.hasPermission(portletInstance, username)) { + throw new IllegalAccessException(); + } + if (expand) { computePortletInstanceAttributes(locale, portletInstance); } return portletInstance; @@ -113,9 +124,19 @@ public PortletInstanceCategory getPortletInstanceCategory(long id) { return portletInstanceCategoryStorage.getPortletInstanceCategory(id); } - public PortletInstanceCategory getPortletInstanceCategory(long id, Locale locale, boolean expand) { + public PortletInstanceCategory getPortletInstanceCategory(long id, + String username, + Locale locale, + boolean expand) throws ObjectNotFoundException, + IllegalAccessException { PortletInstanceCategory portletInstanceCategory = portletInstanceCategoryStorage.getPortletInstanceCategory(id); - if (expand && portletInstanceCategory != null) { + if (portletInstanceCategory == null) { + throw new ObjectNotFoundException("Portlet instance category not found"); + } + if (!this.hasPermission(portletInstanceCategory, username)) { + throw new IllegalAccessException(); + } + if (expand) { computePortletInstanceCategoryAttributes(locale, portletInstanceCategory); } return portletInstanceCategory; @@ -273,4 +294,18 @@ private String getLabel(String objectType, long objectId, String fieldName, Loca } } + private boolean hasPermission(PortletInstance portletInstance, String username) { + List permissions = portletInstance.getPermissions(); + return CollectionUtils.isEmpty(permissions) + || permissions.equals(EVERYONE_PERMISSIONS_LIST) + || (StringUtils.isNotBlank(username) && permissions.stream().anyMatch(p -> layoutAclService.isMemberOf(username, p))); + } + + private boolean hasPermission(PortletInstanceCategory category, String username) { + List permissions = category.getPermissions(); + return CollectionUtils.isEmpty(permissions) + || permissions.equals(EVERYONE_PERMISSIONS_LIST) + || (StringUtils.isNotBlank(username) && permissions.stream().anyMatch(p -> layoutAclService.isMemberOf(username, p))); + } + } diff --git a/layout-service/src/main/java/io/meeds/layout/util/EntityMapper.java b/layout-service/src/main/java/io/meeds/layout/util/EntityMapper.java index 6e44c2b13..b7c4d1896 100644 --- a/layout-service/src/main/java/io/meeds/layout/util/EntityMapper.java +++ b/layout-service/src/main/java/io/meeds/layout/util/EntityMapper.java @@ -46,7 +46,9 @@ public static PortletInstanceCategory fromEntity(PortletInstanceCategoryEntity e null, entity.getIcon(), entity.isSystem(), - entity.getPermissions()); + entity.getPermissions() + == null ? Collections.emptyList() : + entity.getPermissions().stream().filter(StringUtils::isNotBlank).toList()); } public static PortletInstance fromEntity(PortletInstanceEntity entity, PortletDescriptor portlet) { @@ -57,7 +59,9 @@ public static PortletInstance fromEntity(PortletInstanceEntity entity, PortletDe entity.getContentId(), getPreferences(entity), 0l, - entity.getPermissions(), + entity.getPermissions() + == null ? Collections.emptyList() : + entity.getPermissions().stream().filter(StringUtils::isNotBlank).toList(), portlet == null ? null : portlet.getSupportedModes(), entity.isSystem(), entity.isDisabled(), diff --git a/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceCategoryRestTest.java b/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceCategoryRestTest.java index 8db39df3f..139861080 100644 --- a/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceCategoryRestTest.java +++ b/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceCategoryRestTest.java @@ -121,7 +121,7 @@ void getPortletInstanceCategorysAnonymously() throws Exception { void getPortletInstanceCategorysWithUser() throws Exception { ResultActions response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); response.andExpect(status().isOk()); - verify(portletInstanceService).getPortletInstanceCategories(any(), anyBoolean()); + verify(portletInstanceService).getPortletInstanceCategories(any(), any(), anyBoolean()); } @Test @@ -135,7 +135,7 @@ void getPortletInstanceCategoryAnonymously() throws Exception { void getPortletInstanceCategoryWithUser() throws Exception { ResultActions response = mockMvc.perform(get(REST_PATH + "/1").with(testSimpleUser())); response.andExpect(status().isOk()); - verify(portletInstanceService).getPortletInstanceCategory(eq(1l), any(), eq(true)); + verify(portletInstanceService).getPortletInstanceCategory(eq(1l), any(), any(), eq(true)); } @Test diff --git a/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceRestTest.java b/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceRestTest.java index 8d8893f3b..0c41b0b84 100644 --- a/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceRestTest.java +++ b/layout-service/src/test/java/io/meeds/layout/rest/PortletInstanceRestTest.java @@ -122,7 +122,7 @@ void getPortletInstancesAnonymously() throws Exception { void getPortletInstancesWithUser() throws Exception { ResultActions response = mockMvc.perform(get(REST_PATH).with(testSimpleUser())); response.andExpect(status().isOk()); - verify(portletInstanceService).getPortletInstances(anyLong(), any(), anyBoolean()); + verify(portletInstanceService).getPortletInstances(anyLong(), any(), any(), anyBoolean()); } @Test @@ -136,7 +136,7 @@ void getPortletInstanceAnonymously() throws Exception { void getPortletInstanceWithUser() throws Exception { ResultActions response = mockMvc.perform(get(REST_PATH + "/1").with(testSimpleUser())); response.andExpect(status().isOk()); - verify(portletInstanceService).getPortletInstance(eq(1l), any(), eq(true)); + verify(portletInstanceService).getPortletInstance(eq(1l), any(), any(), eq(true)); } @Test diff --git a/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java b/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java index 6bd2bf01f..9c248d709 100644 --- a/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java +++ b/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java @@ -127,7 +127,7 @@ public void getPortletInstancesByCategoryId() { when(portletInstance.getContentId()).thenReturn(CONTENT_ID); when(portletInstanceStorage.getPortletInstances(3l)).thenReturn(Collections.singletonList(portletInstance)); - List portletInstances = portletInstanceService.getPortletInstances(3l, null, false); + List portletInstances = portletInstanceService.getPortletInstances(3l, null, null, false); assertNotNull(portletInstances); assertEquals(1, portletInstances.size()); assertEquals(portletInstance.getId(), portletInstances.get(0).getId()); @@ -145,19 +145,17 @@ public void getPortletInstancesWithExpand() throws ObjectNotFoundException { when(portletInstanceStorage.getPortletInstances()).thenReturn(Collections.singletonList(template)); - List portletInstances = portletInstanceService.getPortletInstances(true); + List portletInstances = portletInstanceService.getPortletInstances(); assertNotNull(portletInstances); assertEquals(1, portletInstances.size()); assertEquals(template.getId(), portletInstances.get(0).getId()); assertEquals(template.getContentId(), portletInstances.get(0).getContentId()); - assertNull(portletInstances.get(0).getName()); - assertNull(portletInstances.get(0).getDescription()); assertEquals(template.getIllustrationId(), portletInstances.get(0).getIllustrationId()); when(translationService.getTranslationField(PortletInstanceTranslationPlugin.OBJECT_TYPE, template.getId(), PortletInstanceTranslationPlugin.TITLE_FIELD_NAME)).thenThrow(ObjectNotFoundException.class); - portletInstances = portletInstanceService.getPortletInstances(true); + portletInstances = portletInstanceService.getPortletInstances(); assertNotNull(portletInstances); assertEquals(1, portletInstances.size()); @@ -167,7 +165,10 @@ public void getPortletInstancesWithExpand() throws ObjectNotFoundException { when(translationService.getTranslationField(PortletInstanceTranslationPlugin.OBJECT_TYPE, template.getId(), PortletInstanceTranslationPlugin.TITLE_FIELD_NAME)).thenReturn(titleTranslationField); - portletInstances = portletInstanceService.getPortletInstances(true); + portletInstances = portletInstanceService.getPortletInstances(0, + null, + Locale.ENGLISH, + true); assertNotNull(portletInstances); assertEquals(1, portletInstances.size()); assertEquals(template.getId(), portletInstances.get(0).getId()); @@ -179,7 +180,10 @@ public void getPortletInstancesWithExpand() throws ObjectNotFoundException { String frTitle = TITLE; when(titleTranslationField.getLabels()).thenReturn(Collections.singletonMap(Locale.FRENCH, frTitle)); - portletInstances = portletInstanceService.getPortletInstances(true); + portletInstances = portletInstanceService.getPortletInstances(0, + null, + Locale.FRENCH, + true); assertNotNull(portletInstances); assertEquals(1, portletInstances.size()); assertEquals(frTitle, portletInstances.get(0).getName()); @@ -191,21 +195,27 @@ public void getPortletInstancesWithExpand() throws ObjectNotFoundException { String enDesc = DESCRIPTION; when(descriptionTranslationField.getLabels()).thenReturn(Collections.singletonMap(Locale.ENGLISH, enDesc)); - portletInstances = portletInstanceService.getPortletInstances(true); + portletInstances = portletInstanceService.getPortletInstances(0, + null, + Locale.ENGLISH, + true); assertNotNull(portletInstances); assertEquals(1, portletInstances.size()); assertEquals(enDesc, portletInstances.get(0).getDescription()); when(attachmentService.getAttachmentFileIds(PortletInstanceAttachmentPlugin.OBJECT_TYPE, "2")).thenReturn(Collections.singletonList("32")); - portletInstances = portletInstanceService.getPortletInstances(Locale.GERMAN, true); + portletInstances = portletInstanceService.getPortletInstances(0, + null, + Locale.ENGLISH, + true); assertNotNull(portletInstances); assertEquals(1, portletInstances.size()); assertEquals(32l, portletInstances.get(0).getIllustrationId()); } @Test - public void getPortletInstanceWithExpand() throws ObjectNotFoundException { + public void getPortletInstanceWithExpand() throws ObjectNotFoundException, IllegalAccessException { PortletInstance template = newPortletInstance(); when(localeConfigService.getDefaultLocaleConfig()).thenReturn(defaultLocaleConfig); when(defaultLocaleConfig.getLocale()).thenReturn(Locale.ENGLISH); @@ -221,7 +231,7 @@ public void getPortletInstanceWithExpand() throws ObjectNotFoundException { when(translationService.getTranslationField(PortletInstanceTranslationPlugin.OBJECT_TYPE, template.getId(), PortletInstanceTranslationPlugin.TITLE_FIELD_NAME)).thenThrow(ObjectNotFoundException.class); - retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, Locale.FRENCH, true); + retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, null, Locale.FRENCH, true); assertNotNull(retrievedPortletInstance); reset(translationService); @@ -230,7 +240,7 @@ public void getPortletInstanceWithExpand() throws ObjectNotFoundException { when(translationService.getTranslationField(PortletInstanceTranslationPlugin.OBJECT_TYPE, template.getId(), PortletInstanceTranslationPlugin.TITLE_FIELD_NAME)).thenReturn(titleTranslationField); - retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, Locale.FRENCH, true); + retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, null, Locale.FRENCH, true); assertNotNull(retrievedPortletInstance); assertEquals(template.getId(), retrievedPortletInstance.getId()); assertEquals(template.getContentId(), retrievedPortletInstance.getContentId()); @@ -241,7 +251,7 @@ public void getPortletInstanceWithExpand() throws ObjectNotFoundException { String frTitle = TITLE; when(titleTranslationField.getLabels()).thenReturn(Collections.singletonMap(Locale.FRENCH, frTitle)); - retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, Locale.FRENCH, true); + retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, null, Locale.FRENCH, true); assertEquals(frTitle, retrievedPortletInstance.getName()); TranslationField descriptionTranslationField = mock(TranslationField.class); @@ -251,13 +261,13 @@ public void getPortletInstanceWithExpand() throws ObjectNotFoundException { String enDesc = DESCRIPTION; when(descriptionTranslationField.getLabels()).thenReturn(Collections.singletonMap(Locale.ENGLISH, enDesc)); - retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, Locale.ENGLISH, true); + retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, null, Locale.ENGLISH, true); assertNotNull(retrievedPortletInstance); assertEquals(enDesc, retrievedPortletInstance.getDescription()); when(attachmentService.getAttachmentFileIds(PortletInstanceAttachmentPlugin.OBJECT_TYPE, "2")).thenReturn(Collections.singletonList("32")); - retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, Locale.GERMAN, true); + retrievedPortletInstance = portletInstanceService.getPortletInstance(2l, null, Locale.GERMAN, true); assertNotNull(retrievedPortletInstance); assertEquals(32l, retrievedPortletInstance.getIllustrationId()); } @@ -354,7 +364,7 @@ public void getPortletInstanceCategoriesWithExpand() throws ObjectNotFoundExcept when(translationService.getTranslationField(PortletInstanceCategoryTranslationPlugin.OBJECT_TYPE, category.getId(), PortletInstanceCategoryTranslationPlugin.TITLE_FIELD_NAME)).thenThrow(ObjectNotFoundException.class); - portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(Locale.ENGLISH, true); + portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(null, Locale.ENGLISH, true); assertNotNull(portletInstanceCategorys); assertEquals(1, portletInstanceCategorys.size()); @@ -364,7 +374,7 @@ public void getPortletInstanceCategoriesWithExpand() throws ObjectNotFoundExcept when(translationService.getTranslationField(PortletInstanceCategoryTranslationPlugin.OBJECT_TYPE, category.getId(), PortletInstanceCategoryTranslationPlugin.TITLE_FIELD_NAME)).thenReturn(titleTranslationField); - portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(Locale.FRENCH, true); + portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(null, Locale.FRENCH, true); assertNotNull(portletInstanceCategorys); assertEquals(1, portletInstanceCategorys.size()); assertEquals(category.getId(), portletInstanceCategorys.get(0).getId()); @@ -374,18 +384,18 @@ public void getPortletInstanceCategoriesWithExpand() throws ObjectNotFoundExcept String frTitle = TITLE; when(titleTranslationField.getLabels()).thenReturn(Collections.singletonMap(Locale.FRENCH, frTitle)); - portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(Locale.FRENCH, true); + portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(null, Locale.FRENCH, true); assertNotNull(portletInstanceCategorys); assertEquals(1, portletInstanceCategorys.size()); assertEquals(frTitle, portletInstanceCategorys.get(0).getName()); - portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(Locale.ENGLISH, true); + portletInstanceCategorys = portletInstanceService.getPortletInstanceCategories(null, Locale.ENGLISH, true); assertNotNull(portletInstanceCategorys); assertEquals(1, portletInstanceCategorys.size()); } @Test - public void getPortletInstanceCategoryWithExpand() throws ObjectNotFoundException { + public void getPortletInstanceCategoryWithExpand() throws ObjectNotFoundException, IllegalAccessException { PortletInstanceCategory category = newPortletInstanceCategory(); when(localeConfigService.getDefaultLocaleConfig()).thenReturn(defaultLocaleConfig); when(defaultLocaleConfig.getLocale()).thenReturn(Locale.ENGLISH); @@ -401,7 +411,7 @@ public void getPortletInstanceCategoryWithExpand() throws ObjectNotFoundExceptio when(translationService.getTranslationField(PortletInstanceCategoryTranslationPlugin.OBJECT_TYPE, category.getId(), PortletInstanceCategoryTranslationPlugin.TITLE_FIELD_NAME)).thenThrow(ObjectNotFoundException.class); - retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), Locale.FRENCH, true); + retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), null, Locale.FRENCH, true); assertNotNull(retrievedPortletInstanceCategory); reset(translationService); @@ -410,7 +420,7 @@ public void getPortletInstanceCategoryWithExpand() throws ObjectNotFoundExceptio when(translationService.getTranslationField(PortletInstanceCategoryTranslationPlugin.OBJECT_TYPE, category.getId(), PortletInstanceCategoryTranslationPlugin.TITLE_FIELD_NAME)).thenReturn(titleTranslationField); - retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), Locale.FRENCH, true); + retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), null, Locale.FRENCH, true); assertNotNull(retrievedPortletInstanceCategory); assertEquals(category.getId(), retrievedPortletInstanceCategory.getId()); assertEquals(category.getIcon(), retrievedPortletInstanceCategory.getIcon()); @@ -419,10 +429,10 @@ public void getPortletInstanceCategoryWithExpand() throws ObjectNotFoundExceptio String frTitle = TITLE; when(titleTranslationField.getLabels()).thenReturn(Collections.singletonMap(Locale.FRENCH, frTitle)); - retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), Locale.FRENCH, true); + retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), null, Locale.FRENCH, true); assertEquals(frTitle, retrievedPortletInstanceCategory.getName()); - retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), Locale.ENGLISH, true); + retrievedPortletInstanceCategory = portletInstanceService.getPortletInstanceCategory(category.getId(), null, Locale.ENGLISH, true); assertNotNull(retrievedPortletInstanceCategory); } @@ -491,7 +501,7 @@ private PortletInstanceCategory newPortletInstanceCategory() { null, "icon", true, - Collections.singletonList("permission")); + Collections.singletonList("Everyone")); } private PortletInstance newPortletInstance() { @@ -502,7 +512,7 @@ private PortletInstance newPortletInstance() { CONTENT_ID, Collections.singletonList(new PortletInstancePreference("prefName", "prefValue")), 7l, - Collections.singletonList("permission"), + Collections.singletonList("Everyone"), Collections.singletonList("edit"), true, false, diff --git a/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties b/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties index 2a05e1fc2..b5c653346 100644 --- a/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties +++ b/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties @@ -184,8 +184,8 @@ portlets.label.editProperties=Edit Properties portlets.label.duplicate=Duplicate portlets.label.delete=Delete portlets.label.edit=Edit -portlets.label.system.noDelete=This portlet instance cannot be deleted -portlets.label.category.system.noDelete=This category cannot be deleted +portlets.label.system.noDelete=Product Instances cannot be deleted +portlets.label.category.system.noDelete=Product categories cannot be deleted portlets.label.preview=Preview of {0} portlets.label.openIllustrationPreview=Open illustration Preview @@ -257,9 +257,31 @@ layout.portletInstance.category.namePlaceholder=Name layout.portletInstance.category.nameTranslationDrawerTitle=Category name translations layout.portletInstance.category.icon=Icon +layout.portletInstance.drawerTitie.add=Add an instance +layout.portletInstance.drawerTitie.edit=Edit an instance +layout.portletInstance.name=Name +layout.portletInstance.namePlaceholder=Give a name to your instance +layout.portletInstance.nameTranslationDrawerTitle=Instance name translations +layout.portletInstance.description=Description +layout.portletInstance.descriptionPlaceholder=Add a description to display below preview +layout.portletInstance.descriptionTranslationDrawerTitle=Instance description translations + +layout.category=Category +layout.category.placeholder=Select a category +layout.portlet=Portlet +layout.portlet.placeholder=Select a portlet + +layout.portlet.allowUsingInSpaceContext=Allow space hosts use it for space apps + +layout.portletInstance.add=Add + layout.portletInstanceCategoryCreatedSuccessfully=Portlet Instance Category created successfully layout.portletInstanceCategoryUpdatedSuccessfully=Portlet Instance Category updated successfully +layout.portletInstanceCreatedSuccessfully=Portlet Instance created successfully +layout.portletInstanceUpdatedSuccessfully=Portlet Instance updated successfully portlets.portletInstancesList=Instances using {0} portlets.previewInstance=Preview the instance portlets.noPortletInstancesYet=No instance is using this portlet for now +portlets.instancePreview=Preview +portlets.uploadPreviewTitle=Upload an illustration for portlet instance diff --git a/layout-webapp/src/main/webapp/vue-app/common-page-template/components/PageTemplatePreview.vue b/layout-webapp/src/main/webapp/vue-app/common-page-template/components/PageTemplatePreview.vue index 1c6d0660b..f4744c2e1 100644 --- a/layout-webapp/src/main/webapp/vue-app/common-page-template/components/PageTemplatePreview.vue +++ b/layout-webapp/src/main/webapp/vue-app/common-page-template/components/PageTemplatePreview.vue @@ -50,8 +50,7 @@ :src="illustrationSrc" class="border-radius" transition="none" - eager - role="presentation" /> + eager /> \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/CategoryInput.vue b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/CategoryInput.vue new file mode 100644 index 000000000..1e064e1ea --- /dev/null +++ b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/CategoryInput.vue @@ -0,0 +1,76 @@ + + + \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/InstancePreview.vue b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/InstancePreview.vue new file mode 100644 index 000000000..5231cc603 --- /dev/null +++ b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/InstancePreview.vue @@ -0,0 +1,143 @@ + + + \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/PortletInput.vue b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/PortletInput.vue new file mode 100644 index 000000000..3f2114b9c --- /dev/null +++ b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/form/PortletInput.vue @@ -0,0 +1,81 @@ + + + \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/portlets/components/portlets/drawer/InstancesDrawer.vue b/layout-webapp/src/main/webapp/vue-app/portlets/components/portlets/drawer/InstancesDrawer.vue index ccee57d11..36a397e80 100644 --- a/layout-webapp/src/main/webapp/vue-app/portlets/components/portlets/drawer/InstancesDrawer.vue +++ b/layout-webapp/src/main/webapp/vue-app/portlets/components/portlets/drawer/InstancesDrawer.vue @@ -91,6 +91,7 @@ export default { }, methods: { open(contentId, name) { + this.$root.$emit('close-alert-message'); this.contentId = contentId; this.name = name; this.$nextTick().then(() => this.$refs.drawer.open()); diff --git a/layout-webapp/src/main/webapp/vue-app/portlets/initComponents.js b/layout-webapp/src/main/webapp/vue-app/portlets/initComponents.js index 3cbac4b30..857d070cf 100644 --- a/layout-webapp/src/main/webapp/vue-app/portlets/initComponents.js +++ b/layout-webapp/src/main/webapp/vue-app/portlets/initComponents.js @@ -26,12 +26,19 @@ import InstanceMain from './components/instances/Main.vue'; import InstanceCategories from './components/instances/Categories.vue'; import InstanceCategoryMenu from './components/instances/CategoryMenu.vue'; import InstanceCategoryItem from './components/instances/CategoryItem.vue'; + import InstanceCategoryDrawer from './components/instances/drawer/CategoryDrawer.vue'; import InstanceList from './components/instances/List.vue'; import InstanceItem from './components/instances/Item.vue'; import InstanceMenu from './components/instances/Menu.vue'; +import InstanceDrawer from './components/instances/drawer/InstanceDrawer.vue'; + +import InstancePreview from './components/instances/form/InstancePreview.vue'; +import CategoryInput from './components/instances/form/CategoryInput.vue'; +import PortletInput from './components/instances/form/PortletInput.vue'; + import PortletList from './components/portlets/List.vue'; import PortletItem from './components/portlets/Item.vue'; import PortletMenu from './components/portlets/Menu.vue'; @@ -52,7 +59,11 @@ const components = { 'portlets-instance-list': InstanceList, 'portlets-instance-item': InstanceItem, - 'portlets-instance-item-menu': InstanceMenu, + 'portlets-instance-menu': InstanceMenu, + 'portlets-instance-drawer': InstanceDrawer, + 'portlets-instance-preview': InstancePreview, + 'portlets-instance-category-input': CategoryInput, + 'portlets-instance-portlet-input': PortletInput, 'portlets-list': PortletList, 'portlets-item': PortletItem, diff --git a/layout-webapp/src/main/webapp/vue-app/portlets/main.js b/layout-webapp/src/main/webapp/vue-app/portlets/main.js index ce15ac956..951914c1f 100644 --- a/layout-webapp/src/main/webapp/vue-app/portlets/main.js +++ b/layout-webapp/src/main/webapp/vue-app/portlets/main.js @@ -43,13 +43,13 @@ export function init() { template: ``, vuetify: Vue.prototype.vuetifyOptions, i18n, - data: { + data: () => ({ portlets: [], portletInstances: [], portletInstanceCategories: [], loading: 0, collator: new Intl.Collator(eXo.env.portal.language, {numeric: true, sensitivity: 'base'}), - }, + }), computed: { isMobile() { return this.$vuetify.breakpoint.smAndDown; @@ -68,12 +68,10 @@ export function init() { }, }, created() { - this.$root.$on('portlet-instance-deleted', this.refreshPortletInstances); - this.$root.$on('portlet-instance-created', this.refreshPortletInstances); - this.$root.$on('portlet-instance-updated', this.refreshPortletInstances); this.$root.$on('portlet-instance-enabled', this.refreshPortletInstances); this.$root.$on('portlet-instance-disabled', this.refreshPortletInstances); this.$root.$on('portlet-instance-saved', this.refreshPortletInstances); + this.$root.$on('portlet-instance-deleted', this.refreshPortletInstances); this.$root.$on('portlet-instance-category-saved', this.refreshPortletInstanceCategories); this.$root.$on('portlet-instance-category-deleted', this.refreshPortletInstanceCategories); @@ -85,7 +83,10 @@ export function init() { refreshPortlets() { this.loading++; return this.$portletService.getPortlets() - .then(data => this.portlets = data || []) + .then(data => this.portlets = data.map(p => ({...p, + name: this.$te(`layout.portletInstance.${p?.portletName}.name`) ? this.$t(`layout.portletInstance.${p?.portletName}.name`) : p?.name, + description: this.$te(`layout.portletInstance.${p?.portletName}.description`) ? this.$t(`layout.portletInstance.${p?.portletName}.description`) : p?.description, + })) || []) .finally(() => this.loading--); }, refreshPortletInstances() {