diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/renderer/PortletInstanceAddOnPlugin.java b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/PortletInstanceAddOnPlugin.java new file mode 100644 index 000000000..4fb210637 --- /dev/null +++ b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/PortletInstanceAddOnPlugin.java @@ -0,0 +1,66 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.layout.plugin.renderer; + +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import org.exoplatform.commons.addons.AddOnPlugin; +import org.exoplatform.commons.addons.AddOnService; +import org.exoplatform.portal.config.model.Application; + +import io.meeds.layout.service.PortletInstanceRenderService; + +import jakarta.annotation.PostConstruct; + +@Component +public class PortletInstanceAddOnPlugin extends AddOnPlugin { + + private static final String PORTLET_EDITOR_DYNAMIC_CONTAINER = "portlet-editor"; + + @Autowired + private AddOnService addonService; + + @Autowired + private PortletInstanceRenderService portletInstanceRenderService; + + @PostConstruct + public void init() { + addonService.addPlugin(this); + } + + @Override + public int getPriority() { + return 1; + } + + @Override + public String getContainerName() { + return PORTLET_EDITOR_DYNAMIC_CONTAINER; + } + + @Override + public List> getApplications() { + return Collections.singletonList(new PortletInstanceApplicationAdapter(portletInstanceRenderService)); + } + +} diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/renderer/PortletInstanceApplicationAdapter.java b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/PortletInstanceApplicationAdapter.java new file mode 100644 index 000000000..55da36d34 --- /dev/null +++ b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/PortletInstanceApplicationAdapter.java @@ -0,0 +1,283 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.layout.plugin.renderer; + +import org.exoplatform.portal.application.PortalRequestContext; +import org.exoplatform.portal.config.model.Application; +import org.exoplatform.portal.config.model.ApplicationState; +import org.exoplatform.portal.config.model.ApplicationType; +import org.exoplatform.portal.config.model.ModelStyle; +import org.exoplatform.portal.config.model.Properties; +import org.exoplatform.portal.config.serialize.PortletApplication; +import org.exoplatform.portal.pom.data.ApplicationData; +import org.exoplatform.portal.pom.spi.portlet.Portlet; + +import io.meeds.layout.service.PortletInstanceRenderService; + +import lombok.SneakyThrows; + +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class PortletInstanceApplicationAdapter extends PortletApplication { + + public static final String PORTLET_EDITOR_PORTLET_CONTENT_ID = "layout/PortletEditor"; + + private ThreadLocal application = new ThreadLocal<>(); + + private PortletInstanceRenderService portletInstanceRenderService; + + public PortletInstanceApplicationAdapter(PortletInstanceRenderService portletInstanceRenderService) { + this.portletInstanceRenderService = portletInstanceRenderService; + } + + @Override + public ModelStyle getCssStyle() { + return getApplication().getCssStyle(); + } + + @Override + public void setCssStyle(ModelStyle cssStyle) { + getApplication().setCssStyle(cssStyle); + } + + @Override + public ApplicationType getType() { + return ApplicationType.PORTLET; + } + + @Override + public String getWidth() { + return getApplication().getWidth(); + } + + @Override + public void setWidth(String s) { + getApplication().setWidth(s); + } + + @Override + public String getHeight() { + return getApplication().getHeight(); + } + + @Override + public void setHeight(String s) { + getApplication().setHeight(s); + } + + @Override + public String getId() { + return getApplication().getId(); + } + + @Override + public void setId(String value) { + getApplication().setId(value); + } + + @Override + public String[] getAccessPermissions() { + return getApplication().getAccessPermissions(); + } + + @Override + public void setAccessPermissions(String[] accessPermissions) { + getApplication().setAccessPermissions(accessPermissions); + } + + @Override + public boolean isModifiable() { + return getApplication().isModifiable(); + } + + @Override + public void setModifiable(boolean modifiable) { + getApplication().setModifiable(modifiable); + } + + @Override + public ApplicationState getState() { + return getApplication().getState(); + } + + @Override + public void setState(ApplicationState value) { + getApplication().setState(value); + } + + @Override + public boolean getShowInfoBar() { + return getApplication().getShowInfoBar(); + } + + @Override + public void setShowInfoBar(boolean b) { + getApplication().setShowInfoBar(b); + } + + @Override + public boolean getShowApplicationState() { + return getApplication().getShowApplicationState(); + } + + @Override + public void setShowApplicationState(boolean b) { + getApplication().setShowApplicationState(b); + } + + @Override + public boolean getShowApplicationMode() { + return getApplication().getShowApplicationMode(); + } + + @Override + public void setShowApplicationMode(boolean b) { + getApplication().setShowApplicationMode(b); + } + + @Override + public String getIcon() { + return getApplication().getIcon(); + } + + @Override + public void setIcon(String value) { + getApplication().setIcon(value); + } + + @Override + public String getDescription() { + return getApplication().getDescription(); + } + + @Override + public void setDescription(String des) { + getApplication().setDescription(des); + } + + @Override + public String getTitle() { + return getApplication().getTitle(); + } + + @Override + public void setTitle(String value) { + getApplication().setTitle(value); + } + + @Override + public Properties getProperties() { + return getApplication().getProperties(); + } + + @Override + public void setProperties(Properties properties) { + getApplication().setProperties(properties); + } + + @Override + public String getTheme() { + return getApplication().getTheme(); + } + + @Override + public void setTheme(String theme) { + getApplication().setTheme(theme); + } + + @Override + public String getCssClass() { + return getApplication().getCssClass(); + } + + @Override + public String getBorderColor() { + return getApplication().getBorderColor(); + } + + @Override + public ApplicationData build() { + return getApplication().build(); + } + + @Override + public void resetStorage() { + getApplication().resetStorage(); + } + + @Override + public void setCssClass(String cssClass) { + getApplication().setCssClass(cssClass); + } + + @Override + public void setBorderColor(String borderColor) { + getApplication().setBorderColor(borderColor); + } + + @Override + public String getStorageId() { + return getApplication().getStorageId(); + } + + @Override + public String getStorageName() { + return getApplication().getStorageName(); + } + + @Override + public void setStorageName(String storageName) { + getApplication().setStorageName(storageName); + } + + @SneakyThrows + public Application getApplication() { // NOSONAR + Application portletApplication = application.get(); + if (portletApplication == null) { + portletApplication = portletInstanceRenderService.getPortletInstanceApplication(getCurrentUserName(), + getPortletInstanceId(), + getApplicationStorageId()); + manageRequestCache(portletApplication); + } + return portletApplication; + } + + private void manageRequestCache(Application portletApplication) { + PortalRequestContext requestContext = PortalRequestContext.getCurrentInstance(); + if (requestContext != null) { + application.set(portletApplication); + requestContext.addOnRequestEnd(() -> application.remove()); + } + } + + private String getPortletInstanceId() { + PortalRequestContext requestContext = PortalRequestContext.getCurrentInstance(); + return requestContext == null ? null : requestContext.getRequest().getParameter("portletInstanceId"); + } + + private String getApplicationStorageId() { + PortalRequestContext requestContext = PortalRequestContext.getCurrentInstance(); + return requestContext == null ? null : requestContext.getRequest().getParameter("portal:componentId"); + } + + private String getCurrentUserName() { + PortalRequestContext requestContext = PortalRequestContext.getCurrentInstance(); + return requestContext == null ? null : requestContext.getRequest().getRemoteUser(); + } + +} diff --git a/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceRenderService.java b/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceRenderService.java new file mode 100644 index 000000000..3ffdc43b8 --- /dev/null +++ b/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceRenderService.java @@ -0,0 +1,214 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.layout.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.gatein.pc.api.PortletInvoker; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; +import org.exoplatform.commons.api.settings.data.Context; +import org.exoplatform.commons.api.settings.data.Scope; +import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.exoplatform.portal.config.UserACL; +import org.exoplatform.portal.config.model.Application; +import org.exoplatform.portal.config.model.Container; +import org.exoplatform.portal.config.model.ModelObject; +import org.exoplatform.portal.config.model.Page; +import org.exoplatform.portal.config.model.TransientApplicationState; +import org.exoplatform.portal.config.serialize.PortletApplication; +import org.exoplatform.portal.mop.SiteKey; +import org.exoplatform.portal.mop.page.PageContext; +import org.exoplatform.portal.mop.page.PageKey; +import org.exoplatform.portal.mop.page.PageState; +import org.exoplatform.portal.mop.service.LayoutService; +import org.exoplatform.portal.pom.spi.portlet.Portlet; +import org.exoplatform.portal.pom.spi.portlet.PortletBuilder; + +import io.meeds.layout.model.PortletInstance; +import io.meeds.layout.model.PortletInstancePreference; + +/** + * A plugin that is used to display a selected portlet instance in the context + * of the PortletEditor page until. This should be changed to use + * {@link PortletInvoker} to process 'view' & 'edit' & 'serveResource' switch + * JSR-168 & JSR-286 requirements. But for now, to kkep WebUI based portlets + * working (which doesn't implement the JSRs portlet bridge), we will use this + * trick to allow displaying a portlet instance inside WebUI dynamic container. + */ +@Service +public class PortletInstanceRenderService { + + private static final String PORTLET_EDITOR_PORTLET_CONTENT_ID = "layout/PortletEditor"; + + private static final String PORTLET_EDITOR_SYSTEM_PAGE = "_portletEditor"; + + private static final PageKey PORTLET_EDITOR_SYSTEM_PAGE_KEY = + new PageKey(SiteKey.portal("global"), PORTLET_EDITOR_SYSTEM_PAGE); + + private static final Context CONTEXT = Context.GLOBAL.id("PORTLET_INSTANCE"); + + private static final Scope SCOPE = Scope.APPLICATION.id("PORTLET_INSTANCE_APPLICATION"); + + @Autowired + private SettingService settingService; + + @Autowired + private PortletInstanceService portletInstanceService; + + @Autowired + private LayoutService layoutService; + + private Application portletEditorApplication; + + public Application getPortletInstanceApplication(String username, // NOSONAR + String portletInstanceId, + String applicationStorageId) throws IllegalAccessException, + ObjectNotFoundException { + if (StringUtils.isNotBlank(portletInstanceId)) { + // Display the portlet instance by id + return getOrCreatePortletApplication(portletInstanceId, username); + } else if (StringUtils.isNotBlank(applicationStorageId)) { + // Display the app by storage id + return layoutService.getApplicationModel(applicationStorageId); + } else { + // Display the editor + return getPortletEditorApplication(); + } + } + + private Application getOrCreatePortletApplication(String portletInstanceId, + String userName) throws IllegalAccessException, + ObjectNotFoundException { + PortletInstance portletInstance = portletInstanceService.getPortletInstance(Long.parseLong(portletInstanceId), + userName, + Locale.ENGLISH, + false); + long applicationId = getPortletInstanceApplicationId(portletInstanceId); + if (applicationId == 0) { + return initPortletInstanceApplication(portletInstance); + } else { + try { + return layoutService.getApplicationModel(String.valueOf(applicationId)); + } catch (Exception e) { + return initPortletInstanceApplication(portletInstance); + } + } + } + + @SuppressWarnings("unchecked") + private synchronized Application initPortletInstanceApplication(PortletInstance portletInstance) { + TransientApplicationState state = new TransientApplicationState<>(portletInstance.getContentId()); + + List permissions = portletInstance.getPermissions(); + List preferences = portletInstance.getPreferences(); + if (CollectionUtils.isNotEmpty(preferences)) { + PortletBuilder builder = new PortletBuilder(); + preferences.stream().forEach(pref -> builder.add(pref.getName(), pref.getValue())); + state.setContentState(builder.build()); + } + + PortletApplication portletApplication = new PortletApplication(); + portletApplication.setState(state); + portletApplication.setAccessPermissions(CollectionUtils.isEmpty(permissions) ? new String[] { UserACL.EVERYONE } : + permissions.toArray(new String[0])); + + Page page = getPortletInstanceSystemPage(); + Container container = (Container) page.getChildren().get(0); + ArrayList children = container.getChildren(); + int index; + if (CollectionUtils.isEmpty(children)) { + index = 0; + children = new ArrayList<>(); + } else { + index = children.size(); + children = new ArrayList<>(children); + } + children.add(portletApplication); + container.setChildren(children); + page.setChildren(new ArrayList<>(Collections.singletonList(container))); + layoutService.save(page); + + container = getPortletInstanceSystemContainer(); + Application application = (Application) container.getChildren().get(index); + settingService.set(CONTEXT, + SCOPE, + String.valueOf(portletInstance.getId()), + SettingValue.create(application.getStorageId())); + return application; + } + + private long getPortletInstanceApplicationId(String portletInstanceId) { + SettingValue settingValue = settingService.get(CONTEXT, SCOPE, portletInstanceId); + long applicationId = 0; + if (settingValue != null && settingValue.getValue() != null && StringUtils.isNotBlank(settingValue.getValue().toString())) { + applicationId = Long.parseLong(settingValue.getValue().toString()); + } + return applicationId; + } + + private Container getPortletInstanceSystemContainer() { + return (Container) getPortletInstanceSystemPage().getChildren().get(0); + } + + private Page getPortletInstanceSystemPage() { + Page page = layoutService.getPage(PORTLET_EDITOR_SYSTEM_PAGE_KEY); + if (page == null) { + page = new Page(); + page.setTitle("Portlet Editor Working Page"); + page.setEditPermission("manager:/platform/administrators"); + page.setPageId(PORTLET_EDITOR_SYSTEM_PAGE_KEY.format()); + + Container container = new Container(); + container.setTemplate("nop"); + page.setChildren(new ArrayList<>(Collections.singletonList(container))); + + PageState pageState = new PageState(page.getTitle(), + page.getDescription(), + false, + null, + Arrays.asList(UserACL.EVERYONE), + page.getEditPermission(), + Arrays.asList(UserACL.EVERYONE), + Arrays.asList(UserACL.EVERYONE)); + layoutService.save(new PageContext(PORTLET_EDITOR_SYSTEM_PAGE_KEY, pageState), page); + page = layoutService.getPage(PORTLET_EDITOR_SYSTEM_PAGE_KEY); + } + return page; + } + + private Application getPortletEditorApplication() { + if (portletEditorApplication == null) { + portletEditorApplication = new PortletApplication(); + portletEditorApplication.setAccessPermissions(new String[] { UserACL.EVERYONE }); + portletEditorApplication.setState(new TransientApplicationState<>(PORTLET_EDITOR_PORTLET_CONTENT_ID)); + } + return portletEditorApplication; + } + +} 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 369fef0dc..539ef6ab4 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 @@ -29,6 +29,7 @@ import org.springframework.stereotype.Service; import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.exoplatform.portal.config.UserACL; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.resources.LocaleConfigService; @@ -47,7 +48,7 @@ @Service public class PortletInstanceService { - private static final List EVERYONE_PERMISSIONS_LIST = Collections.singletonList("Everyone"); + private static final List EVERYONE_PERMISSIONS_LIST = Collections.singletonList(UserACL.EVERYONE); private static final Log LOG = ExoLogger.getLogger(PortletInstanceService.class); diff --git a/layout-service/src/main/java/io/meeds/layout/service/injection/PortletInstanceImportService.java b/layout-service/src/main/java/io/meeds/layout/service/injection/PortletInstanceImportService.java index bd8ccbac6..bde42ea52 100644 --- a/layout-service/src/main/java/io/meeds/layout/service/injection/PortletInstanceImportService.java +++ b/layout-service/src/main/java/io/meeds/layout/service/injection/PortletInstanceImportService.java @@ -198,16 +198,16 @@ protected void importDescriptor(PortletInstanceDescriptor descriptor) { protected void importPortletInstanceCategory(PortletInstanceCategoryDescriptor d, long oldId) { String descriptorId = d.getNameId(); - LOG.info("Importing Portlet category instance {}", descriptorId); + LOG.debug("Importing Portlet category instance {}", descriptorId); try { PortletInstanceCategory category = savePortletInstanceCategory(d, oldId); if (forceReimport || oldId == 0 || category.getId() != oldId) { - LOG.info("Importing Portlet instance category {} title translations", descriptorId); + LOG.debug("Importing Portlet instance category {} title translations", descriptorId); saveCategoryNames(d, category); // Mark as imported setCategorySettingValue(descriptorId, category.getId()); } - LOG.info("Importing Portlet instance category {} finished successfully", descriptorId); + LOG.debug("Importing Portlet instance category {} finished successfully", descriptorId); } catch (Exception e) { LOG.warn("An error occurred while importing portlet instance category {}", descriptorId, e); } @@ -215,16 +215,16 @@ protected void importPortletInstanceCategory(PortletInstanceCategoryDescriptor d protected void importPortletInstance(PortletInstanceDescriptor d, long oldId) { String descriptorId = d.getNameId(); - LOG.info("Importing Portlet instance {}", descriptorId); + LOG.debug("Importing Portlet instance {}", descriptorId); try { PortletInstance portletInstance = savePortletInstance(d, oldId); if (forceReimport || oldId == 0 || portletInstance.getId() != oldId) { - LOG.info("Importing Portlet instance {} title translations", descriptorId); + LOG.debug("Importing Portlet instance {} title translations", descriptorId); saveNames(d, portletInstance); - LOG.info("Importing Portlet instance {} description translations", descriptorId); + LOG.debug("Importing Portlet instance {} description translations", descriptorId); saveDescriptions(d, portletInstance); if (StringUtils.isNotBlank(d.getIllustrationPath())) { - LOG.info("Importing Portlet instance {} illustration", descriptorId); + LOG.debug("Importing Portlet instance {} illustration", descriptorId); saveIllustration(portletInstance.getId(), d.getIllustrationPath()); } // Mark as imported 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 74fac0347..7b8ea45a6 100644 --- a/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties +++ b/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties @@ -178,6 +178,7 @@ portlets.menu.open=Open Menu portlets.label.instanceMenu={0} portlets.label.menu={0} portlets.label.closeMenu=Close Menu +portlets.label.editInstance=Edit Instance portlets.label.editLayout=Edit Layout portlets.label.system.noEditLayout=This portlet instance's layout cannot be updated portlets.label.editProperties=Edit Properties @@ -287,3 +288,5 @@ portlets.instancePreview=Preview portlets.uploadPreviewTitle=Upload an illustration for portlet instance portlets.label.createInstance=Create instance portlets.noPreviewAvailable=No preview available + +layout.editPortletInstance=Edit portlet instance {0} diff --git a/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml b/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml index f8b312a89..5921fe7fd 100644 --- a/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml +++ b/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml @@ -309,5 +309,34 @@ + + PortletEditor + + portlet-editor-group + + + extensionRegistry + + + commonVueComponents + + + attachImage + + + vue + + + vuetify + + + eXoVueI18n + + + + diff --git a/layout-webapp/src/main/webapp/WEB-INF/portlet.xml b/layout-webapp/src/main/webapp/WEB-INF/portlet.xml index 13672bd49..365aef8b0 100644 --- a/layout-webapp/src/main/webapp/WEB-INF/portlet.xml +++ b/layout-webapp/src/main/webapp/WEB-INF/portlet.xml @@ -78,6 +78,27 @@ + + PortletEditor + Portlet Editor Portlet + org.exoplatform.commons.api.portlet.GenericDispatchedViewPortlet + + portlet-view-dispatched-file-path + /html/portletEditor.html + + -1 + PUBLIC + + text/html + + en + locale.portlet.LayoutEditor + + Portlet Editor + Portlet Editor Management + + + PageTemplatesManagement Page Templates Management Portlet diff --git a/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js b/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js index 738235fc4..d5cba711f 100644 --- a/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js +++ b/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js @@ -27,7 +27,7 @@ import './services.js'; // get overridden components if exists if (extensionRegistry) { - const components = extensionRegistry.loadComponents('layoutEditor'); + const components = extensionRegistry.loadComponents('LayoutEditor'); if (components && components.length > 0) { components.forEach(cmp => { Vue.component(cmp.componentName, cmp.componentOptions); diff --git a/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/Menu.vue b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/Menu.vue index f5d3fa620..434532a6c 100644 --- a/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/Menu.vue +++ b/layout-webapp/src/main/webapp/vue-app/portlets/components/instances/Menu.vue @@ -19,9 +19,8 @@ -->