diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d560898f3c..099888b213 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -195,6 +195,7 @@ In other scenarios, the default creation position border remains the eastern one - https://github.com/eclipse-sirius/sirius-web/issues/3246[#3246] [view] Make the `ViewRepresentationDescriptionSearchService` independent from specific representations - https://github.com/eclipse-sirius/sirius-web/issues/3220[#3220] [deck] Add documentation - https://github.com/eclipse-sirius/sirius-web/issues/3178[#3178] [portal] Add documentation for portals +- https://github.com/eclipse-sirius/sirius-web/issues/2890[#2890] [portal] Display the contents of a Portal in the Representations view == v2024.1.0 diff --git a/integration-tests/cypress/e2e/project/diagrams/diagram-readonly.cy.ts b/integration-tests/cypress/e2e/project/diagrams/diagram-readonly.cy.ts index cc088d5f22..2174712c1f 100644 --- a/integration-tests/cypress/e2e/project/diagrams/diagram-readonly.cy.ts +++ b/integration-tests/cypress/e2e/project/diagrams/diagram-readonly.cy.ts @@ -68,8 +68,8 @@ describe('Diagram read-only', () => { cy.getByTestId('reveal-faded-elements').should('exist').should('be.disabled'); cy.getByTestId('unpin-all-elements').should('exist').should('be.disabled'); diagram.getPalette().should('not.exist'); - diagram.getNodes('diagram', 'DSP').should('exist').click('bottom'); - diagram.getSelectedNodes('diagram', 'DSP').should('exist'); + diagram.getNodes('diagram', 'Motion_Engine').should('exist').click('bottom'); + diagram.getSelectedNodes('diagram', 'Motion_Engine').should('exist'); diagram.getPalette().should('not.exist'); }); }); diff --git a/integration-tests/cypress/e2e/project/portals/portals.cy.ts b/integration-tests/cypress/e2e/project/portals/portals.cy.ts index 987384cbf8..907e596ad1 100644 --- a/integration-tests/cypress/e2e/project/portals/portals.cy.ts +++ b/integration-tests/cypress/e2e/project/portals/portals.cy.ts @@ -19,6 +19,20 @@ import { Portal } from '../../../workbench/Portal'; const projectName = 'Cypress - portal'; +function checkRepresentationsView(expectedItems: string[]): void { + cy.getByTestId('viewselector-Representations').click(); + cy.getByTestId('view-Representations').then((res) => { + const view = cy.wrap(res); + view.should('contain.text', 'Portal content'); + view.find('ul[role="tree"]').then((res) => { + const tree = cy.wrap(res); + expectedItems.forEach((itemText) => { + tree.should('contain.text', itemText); + }); + }); + }); +} + describe('/projects/:projectId/edit - Portal', () => { context('Given a flow project with a robot document', () => { let projectId: string = ''; @@ -113,6 +127,8 @@ describe('/projects/:projectId/edit - Portal', () => { .should('be.enabled'); frame.get('.react-resizable-handle').should('be.visible'); }); + + checkRepresentationsView([secondPortal]); }); it('Portal loops can not be created', () => { @@ -178,6 +194,8 @@ describe('/projects/:projectId/edit - Portal', () => { toolbar.get('[aria-label="edit portal configuration').should('be.visible').should('be.enabled'); toolbar.get('[aria-label="edit representations').should('be.visible').should('be.disabled'); }); + + checkRepresentationsView([diagramTitle]); }); it('A portal which already contains a representation opens in direct mode', () => { @@ -224,6 +242,8 @@ describe('/projects/:projectId/edit - Portal', () => { explorer.getTreeItemByLabel('Portal').click(); portal.getFrame('New ' + diagramTitle).should('be.visible'); + + checkRepresentationsView(['New ' + diagramTitle]); }); it('Deleting a diagram embedded in a portal removes its frame', () => { diff --git a/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/RepresentationsEventProcessorFactory.java b/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/RepresentationsEventProcessorFactory.java index 52ccc7440e..f47eb98556 100644 --- a/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/RepresentationsEventProcessorFactory.java +++ b/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/RepresentationsEventProcessorFactory.java @@ -20,6 +20,7 @@ import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessor; import org.eclipse.sirius.components.collaborative.api.IRepresentationEventProcessorFactory; import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicyRegistry; +import org.eclipse.sirius.components.collaborative.api.IRepresentationSearchService; import org.eclipse.sirius.components.collaborative.api.ISubscriptionManagerFactory; import org.eclipse.sirius.components.collaborative.forms.api.FormCreationParameters; import org.eclipse.sirius.components.collaborative.forms.api.IFormEventHandler; @@ -50,6 +51,8 @@ public class RepresentationsEventProcessorFactory implements IRepresentationEven private final List widgetDescriptors; + private final IRepresentationSearchService representationSearchService; + private final List formEventHandlers; private final ISubscriptionManagerFactory subscriptionManagerFactory; @@ -61,7 +64,7 @@ public class RepresentationsEventProcessorFactory implements IRepresentationEven private final IFormPostProcessor formPostProcessor; public RepresentationsEventProcessorFactory(IRepresentationsDescriptionProvider representationsDescriptionProvider, ISubscriptionManagerFactory subscriptionManagerFactory, - IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, List widgetDescriptors, FormEventProcessorFactoryConfiguration formConfiguration) { + IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, List widgetDescriptors, FormEventProcessorFactoryConfiguration formConfiguration, IRepresentationSearchService representationSearchService) { this.representationsDescriptionProvider = Objects.requireNonNull(representationsDescriptionProvider); this.objectService = Objects.requireNonNull(formConfiguration.getObjectService()); this.widgetDescriptors = Objects.requireNonNull(widgetDescriptors); @@ -69,6 +72,7 @@ public RepresentationsEventProcessorFactory(IRepresentationsDescriptionProvider this.subscriptionManagerFactory = Objects.requireNonNull(subscriptionManagerFactory); this.widgetSubscriptionManagerFactory = Objects.requireNonNull(formConfiguration.getWidgetSubscriptionManagerFactory()); this.representationRefreshPolicyRegistry = Objects.requireNonNull(representationRefreshPolicyRegistry); + this.representationSearchService = Objects.requireNonNull(representationSearchService); this.formPostProcessor = Objects.requireNonNull(formConfiguration.getFormPostProcessor()); } @@ -106,5 +110,4 @@ public Optional createRepresentatio } return Optional.empty(); } - } diff --git a/packages/forms/frontend/sirius-components-forms/src/views/RepresentationsView.tsx b/packages/forms/frontend/sirius-components-forms/src/views/RepresentationsView.tsx index 4f28e2ce9d..29289a734e 100644 --- a/packages/forms/frontend/sirius-components-forms/src/views/RepresentationsView.tsx +++ b/packages/forms/frontend/sirius-components-forms/src/views/RepresentationsView.tsx @@ -12,8 +12,16 @@ *******************************************************************************/ import { WorkbenchViewComponentProps } from '@eclipse-sirius/sirius-components-core'; import { makeStyles } from '@material-ui/core/styles'; -import { GQLForm, GQLList, GQLSubscriber, GQLWidget, GQLWidgetSubscription } from '../form/FormEventFragments.types'; +import { + GQLForm, + GQLList, + GQLSubscriber, + GQLTree, + GQLWidget, + GQLWidgetSubscription, +} from '../form/FormEventFragments.types'; import { ListPropertySection } from '../propertysections/ListPropertySection'; +import { TreePropertySection } from '../propertysections/TreePropertySection'; import { FormBasedView } from './FormBasedView'; const useRepresentationsViewStyles = makeStyles((theme) => ({ @@ -22,7 +30,8 @@ const useRepresentationsViewStyles = makeStyles((theme) => ({ }, })); -const isList = (widget: GQLWidget): widget is GQLList => widget.__typename === 'List'; +const isList = (widget: GQLWidget | undefined): widget is GQLList => widget && widget.__typename === 'List'; +const isTree = (widget: GQLWidget | undefined): widget is GQLTree => widget && widget.__typename === 'TreeWidget'; export const RepresentationsView = (props: WorkbenchViewComponentProps) => { const classes = useRepresentationsViewStyles(); @@ -32,7 +41,7 @@ export const RepresentationsView = (props: WorkbenchViewComponentProps) => { form: GQLForm, widgetSubscriptions: GQLWidgetSubscription[] ): JSX.Element => { - const widget = form.pages[0]?.groups[0]?.widgets[0]; + const widget: GQLWidget | undefined = form.pages[0]?.groups[0]?.widgets[0]; if (isList(widget)) { const uniqueSubscribers: Set = new Set(); widgetSubscriptions.forEach((subscription) => @@ -49,6 +58,22 @@ export const RepresentationsView = (props: WorkbenchViewComponentProps) => { /> ); + } else if (isTree(widget)) { + const uniqueSubscribers: Set = new Set(); + widgetSubscriptions.forEach((subscription) => + subscription.subscribers.forEach((subscriber) => uniqueSubscribers.add(subscriber)) + ); + return ( +
+ +
+ ); } else { return
; } diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/PortalChangeKind.java b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/PortalChangeKind.java new file mode 100644 index 0000000000..f0f99602e6 --- /dev/null +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/PortalChangeKind.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.components.collaborative.portals; + +/** + * Description of the changes performed by portal event handlers. + * + * @author pcdavid + */ +public enum PortalChangeKind { + PORTAL_LAYOUT_CHANGE, + PORTAL_VIEW_ADDITION, + PORTAL_VIEW_REMOVAL, +} diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/PortalEventProcessor.java b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/PortalEventProcessor.java index d0d65ee6f3..278aa99bd1 100644 --- a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/PortalEventProcessor.java +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/PortalEventProcessor.java @@ -133,6 +133,8 @@ public void refresh(ChangeDescription changeDescription) { if (portalServices.referencesRepresentation(this.currentPortal, renamedRepresentationId)) { this.emitNewPortal(changeDescription.getInput()); } + } else if (changeDescription.getSourceId().equals(this.currentPortal.getId()) && changeDescription.getParameters().get(IPortalEventHandler.NEXT_PORTAL_PARAMETER) instanceof Portal nextPortal) { + this.updatePortal(changeDescription.getInput(), nextPortal); } } diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/api/IPortalEventHandler.java b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/api/IPortalEventHandler.java index 6e0393f227..d542626d77 100644 --- a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/api/IPortalEventHandler.java +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/api/IPortalEventHandler.java @@ -24,6 +24,8 @@ * @author pcdavid */ public interface IPortalEventHandler { + String NEXT_PORTAL_PARAMETER = "nextPortal"; + boolean canHandle(IPortalInput portalInput); void handle(One payloadSink, Many changeDescriptionSink, PortalContext context); diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/AddPortalViewEventHandler.java b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/AddPortalViewEventHandler.java index f02276126c..c5dc43f092 100644 --- a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/AddPortalViewEventHandler.java +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/AddPortalViewEventHandler.java @@ -19,6 +19,7 @@ import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.collaborative.api.IRepresentationSearchService; import org.eclipse.sirius.components.collaborative.api.Monitoring; +import org.eclipse.sirius.components.collaborative.portals.PortalChangeKind; import org.eclipse.sirius.components.collaborative.portals.api.IPortalEventHandler; import org.eclipse.sirius.components.collaborative.portals.api.IPortalInput; import org.eclipse.sirius.components.collaborative.portals.api.PortalContext; @@ -81,7 +82,9 @@ public void handle(One payloadSink, Many changeDesc if (optionalNewPortal.isPresent()) { context.setNextPortal(optionalNewPortal.get()); payload = new SuccessPayload(addPortalViewInput.id(), List.of()); - changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, context.getEditingContext().getId(), context.getInput()); + + changeDescription = new ChangeDescription(PortalChangeKind.PORTAL_VIEW_ADDITION.name(), optionalNewPortal.get().getId(), context.getInput()); + changeDescription.getParameters().put(IPortalEventHandler.NEXT_PORTAL_PARAMETER, optionalNewPortal.get()); } else { payload = new ErrorPayload(addPortalViewInput.id(), this.messageService.forbiddenLoop()); } diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/LayoutPortalEventHandler.java b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/LayoutPortalEventHandler.java index 01e29a7abd..6d222e94b9 100644 --- a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/LayoutPortalEventHandler.java +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/LayoutPortalEventHandler.java @@ -18,6 +18,7 @@ import org.eclipse.sirius.components.collaborative.api.ChangeDescription; import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.collaborative.api.Monitoring; +import org.eclipse.sirius.components.collaborative.portals.PortalChangeKind; import org.eclipse.sirius.components.collaborative.portals.api.IPortalEventHandler; import org.eclipse.sirius.components.collaborative.portals.api.IPortalInput; import org.eclipse.sirius.components.collaborative.portals.api.PortalContext; @@ -72,7 +73,8 @@ public void handle(One payloadSink, Many changeDesc var newPortal = context.getServices().layout(context.getCurrentPortal(), layoutData); context.setNextPortal(newPortal); payload = new SuccessPayload(layoutPortalInput.id(), List.of()); - changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, context.getEditingContext().getId(), context.getInput()); + changeDescription = new ChangeDescription(PortalChangeKind.PORTAL_LAYOUT_CHANGE.name(), newPortal.getId(), context.getInput()); + changeDescription.getParameters().put(IPortalEventHandler.NEXT_PORTAL_PARAMETER, newPortal); } } finally { payloadSink.tryEmitValue(payload); diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RemovePortalViewEventHandler.java b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RemovePortalViewEventHandler.java index 8085a488c5..8d0523cf03 100644 --- a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RemovePortalViewEventHandler.java +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RemovePortalViewEventHandler.java @@ -18,6 +18,7 @@ import org.eclipse.sirius.components.collaborative.api.ChangeDescription; import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.collaborative.api.Monitoring; +import org.eclipse.sirius.components.collaborative.portals.PortalChangeKind; import org.eclipse.sirius.components.collaborative.portals.api.IPortalEventHandler; import org.eclipse.sirius.components.collaborative.portals.api.IPortalInput; import org.eclipse.sirius.components.collaborative.portals.api.PortalContext; @@ -34,7 +35,7 @@ import reactor.core.publisher.Sinks.One; /** - * The handler for the addPortalView mutation. + * The handler for the removePortalView mutation. * * @author pcdavid */ @@ -69,7 +70,8 @@ public void handle(One payloadSink, Many changeDesc var newPortal = context.getServices().removeView(context.getCurrentPortal(), removePortalViewInput.portalViewId()); context.setNextPortal(newPortal); payload = new SuccessPayload(removePortalViewInput.id(), List.of()); - changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, context.getEditingContext().getId(), context.getInput()); + changeDescription = new ChangeDescription(PortalChangeKind.PORTAL_VIEW_REMOVAL.name(), newPortal.getId(), context.getInput()); + changeDescription.getParameters().put(IPortalEventHandler.NEXT_PORTAL_PARAMETER, newPortal); } } finally { payloadSink.tryEmitValue(payload); diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RenamePortalEventHandler.java b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RenamePortalEventHandler.java index 72164ccfc7..c97f0e497d 100644 --- a/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RenamePortalEventHandler.java +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/main/java/org/eclipse/sirius/components/collaborative/portals/handlers/RenamePortalEventHandler.java @@ -76,6 +76,7 @@ public void handle(One payloadSink, Many changeDesc payload = new RenameRepresentationSuccessPayload(portalInput.id(), renamedPortal); changeDescription = new ChangeDescription(ChangeKind.REPRESENTATION_RENAMING, renameRepresentationInput.representationId(), portalInput); + changeDescription.getParameters().put(IPortalEventHandler.NEXT_PORTAL_PARAMETER, renamedPortal); } } finally { payloadSink.tryEmitValue(payload); diff --git a/packages/portals/backend/sirius-components-collaborative-portals/src/test/java/org/eclipse/sirius/components/collaborative/portals/services/PortalServicesTests.java b/packages/portals/backend/sirius-components-collaborative-portals/src/test/java/org/eclipse/sirius/components/collaborative/portals/services/PortalServicesTests.java index 5e234f7281..5f94edff1a 100644 --- a/packages/portals/backend/sirius-components-collaborative-portals/src/test/java/org/eclipse/sirius/components/collaborative/portals/services/PortalServicesTests.java +++ b/packages/portals/backend/sirius-components-collaborative-portals/src/test/java/org/eclipse/sirius/components/collaborative/portals/services/PortalServicesTests.java @@ -100,6 +100,28 @@ public void testRemoveReferencedRepresentationRemovesFromBothViewsAndLayoutData( assertThat(newPortal.getLayoutData()).hasSize(portal.getLayoutData().size() - 1); } + @Test + public void testRemovePortalView() { + Portal portal = this.createSamplePortal(3); + assertThat(portal.getViews()).hasSize(3); + Portal newPortal = this.services.removeView(portal, "view-0"); + assertThat(newPortal.getViews()).hasSize(2); + assertThat(newPortal.getLayoutData()).hasSize(2); + } + + @Test + public void testChangeLayoutPortal() { + String viewId = "view-0"; + Portal portal = this.createSamplePortal(1); + Portal newPortal = this.services.layout(portal, List.of(PortalViewLayoutData.newPortalViewLayoutData(viewId).x(2).y(2).width(4).height(4).build())); + var optionalLayout = newPortal.getLayoutData().stream().filter(layoutdata -> layoutdata.getPortalViewId().equals(viewId)).findFirst(); + assertThat(optionalLayout).isPresent(); + assertThat(optionalLayout.get()).extracting(PortalViewLayoutData::getX).isEqualTo(2); + assertThat(optionalLayout.get()).extracting(PortalViewLayoutData::getY).isEqualTo(2); + assertThat(optionalLayout.get()).extracting(PortalViewLayoutData::getWidth).isEqualTo(4); + assertThat(optionalLayout.get()).extracting(PortalViewLayoutData::getHeight).isEqualTo(4); + } + @Test public void testPreventDirectLoop() { Portal portal = Portal.newPortal(PORTAL_ID).descriptionId(PORTAL_DESCRIPTION_ID).label(PORTAL_ID).targetObjectId(TARGET_OBJECT_ID).build(); diff --git a/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsDescriptionProvider.java b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsDescriptionProvider.java index 26416cf37e..84707d29ef 100644 --- a/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsDescriptionProvider.java +++ b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsDescriptionProvider.java @@ -24,21 +24,29 @@ import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.collaborative.api.IRepresentationImageProvider; +import org.eclipse.sirius.components.collaborative.api.IRepresentationSearchService; import org.eclipse.sirius.components.collaborative.editingcontext.EditingContextEventProcessor; import org.eclipse.sirius.components.collaborative.forms.api.IRepresentationsDescriptionProvider; -import org.eclipse.sirius.components.forms.WidgetIdProvider; import org.eclipse.sirius.components.core.CoreImageConstants; import org.eclipse.sirius.components.core.RepresentationMetadata; import org.eclipse.sirius.components.core.api.IEditingContext; import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.forms.TreeNode; +import org.eclipse.sirius.components.forms.WidgetIdProvider; import org.eclipse.sirius.components.forms.components.ListComponent; +import org.eclipse.sirius.components.forms.components.TreeComponent; import org.eclipse.sirius.components.forms.description.AbstractControlDescription; import org.eclipse.sirius.components.forms.description.FormDescription; import org.eclipse.sirius.components.forms.description.GroupDescription; +import org.eclipse.sirius.components.forms.description.IfDescription; import org.eclipse.sirius.components.forms.description.ListDescription; import org.eclipse.sirius.components.forms.description.PageDescription; +import org.eclipse.sirius.components.forms.description.TreeDescription; +import org.eclipse.sirius.components.portals.Portal; +import org.eclipse.sirius.components.portals.PortalView; import org.eclipse.sirius.components.representations.Failure; import org.eclipse.sirius.components.representations.GetOrCreateRandomIdProvider; +import org.eclipse.sirius.components.representations.IRepresentation; import org.eclipse.sirius.components.representations.IStatus; import org.eclipse.sirius.components.representations.Success; import org.eclipse.sirius.components.representations.VariableManager; @@ -59,13 +67,17 @@ public class RepresentationsDescriptionProvider implements IRepresentationsDescr private final IRepresentationService representationService; + private final IRepresentationSearchService representationSearchService; + private final List representationImageProviders; private final Function semanticTargetIdProvider; - public RepresentationsDescriptionProvider(IObjectService objectService, IRepresentationService representationService, List representationImageProviders) { + public RepresentationsDescriptionProvider(IObjectService objectService, IRepresentationService representationService, IRepresentationSearchService representationSearchService, + List representationImageProviders) { this.objectService = Objects.requireNonNull(objectService); this.representationService = Objects.requireNonNull(representationService); + this.representationSearchService = Objects.requireNonNull(representationSearchService); this.representationImageProviders = Objects.requireNonNull(representationImageProviders); this.semanticTargetIdProvider = variableManager -> variableManager.get(VariableManager.SELF, Object.class).map(this.objectService::getId).orElse(null); } @@ -107,27 +119,67 @@ private PageDescription getPageDescription(List groupDescripti private GroupDescription getGroupDescription() { List controlDescriptions = new ArrayList<>(); - Function itemClickHandlerProvider = variableManager -> new Success(); ListDescription listDescription = ListDescription.newListDescription("RepresentationsList") .idProvider(new WidgetIdProvider()) - .labelProvider((variableManager) -> "Representations") + .labelProvider(variableManager -> "Representations") .itemsProvider(this.getItemsProvider()) .itemIdProvider(this.getItemIdProvider()) .itemLabelProvider(this.getItemLabelProvider()) .itemIconURLProvider(this.getItemIconURLProvider()) .itemDeletableProvider(this.getItemDeletableProvider()) - .itemClickHandlerProvider(itemClickHandlerProvider) + .itemClickHandlerProvider(variableManager -> new Success()) .itemDeleteHandlerProvider(this.getItemDeleteHandlerProvider()) .itemKindProvider(this.getItemKindProvider()) - .diagnosticsProvider((variableManager) -> List.of()) - .kindProvider((object) -> "") - .messageProvider((object) -> "") + .diagnosticsProvider(variableManager -> List.of()) + .kindProvider(object -> "") + .messageProvider(object -> "") .styleProvider(variableManager -> null) .targetObjectIdProvider(this.semanticTargetIdProvider) .build(); - controlDescriptions.add(listDescription); + IfDescription ifSemanticElementDescription = IfDescription.newIfDescription("ifSemanticElement") + .targetObjectIdProvider(this.semanticTargetIdProvider) + .predicate(variableManager -> { + var optionalSelf = variableManager.get(VariableManager.SELF, Object.class); + if (optionalSelf.isEmpty() || optionalSelf.get() instanceof IRepresentation) { + return false; + } else { + return this.objectService.getId(optionalSelf.get()) != null; + } + }) + .controlDescriptions(List.of(listDescription)) + .build(); + controlDescriptions.add(ifSemanticElementDescription); + + TreeDescription treeDescription = TreeDescription.newTreeDescription("PortalContentsTree") + .idProvider(new WidgetIdProvider()) + .targetObjectIdProvider(this.semanticTargetIdProvider) + .labelProvider(variableManager -> variableManager.get(VariableManager.SELF, Portal.class).map(Portal::getLabel).orElse("Portal") + " contents") + .iconURLProvider(variableManager -> List.of()) + + .childrenProvider(this.getChildrenProvider()) + .nodeIdProvider(this::getNodeId) + .nodeLabelProvider(this::getNodeLabel) + .nodeKindProvider(this::getNodeKind) + .nodeIconURLProvider(this::getNodeIconURL) + .nodeEndIconsURLProvider(variableManager -> List.of()) + .nodeSelectableProvider(this::isNodeSelectable) + .isCheckableProvider(vm -> false) + .checkedValueProvider(vm -> false) + .newCheckedValueHandler((vm, newValue) -> new Success()) + .expandedNodeIdsProvider(this::collectAllNodeIds) + .diagnosticsProvider(variableManager -> List.of()) + .kindProvider(object -> "") + .messageProvider(object -> "") + .build(); + + IfDescription ifPortalDescription = IfDescription.newIfDescription("ifPortal") + .targetObjectIdProvider(this.semanticTargetIdProvider) + .predicate(variableManager -> variableManager.get(VariableManager.SELF, Portal.class).isPresent()) + .controlDescriptions(List.of(treeDescription)) + .build(); + controlDescriptions.add(ifPortalDescription); return GroupDescription.newGroupDescription("representationsGroupId") .idProvider(variableManager -> "Representations Group") @@ -137,6 +189,20 @@ private GroupDescription getGroupDescription() { .build(); } + private boolean isNodeSelectable(VariableManager variableManager) { + return true; + } + + private List collectAllNodeIds(VariableManager variableManager) { + List result = new ArrayList<>(); + for (var element : variableManager.get(TreeComponent.NODES_VARIABLE, List.class).orElse(List.of())) { + if (element instanceof TreeNode node) { + result.add(node.getId()); + } + } + return result; + } + private Function getItemDeleteHandlerProvider() { return variableManager -> { return variableManager.get(ListComponent.CANDIDATE_VARIABLE, RepresentationMetadata.class) @@ -202,10 +268,69 @@ private Function> getItemsProvider() { var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); if (optionalEditingContext.isPresent() && id != null) { IEditingContext editingContext = optionalEditingContext.get(); - List items = this.representationService.findAllByTargetObjectId(editingContext, id); - return items; + return this.representationService.findAllByTargetObjectId(editingContext, id); } return List.of(); }; } + + private String getNodeId(VariableManager variableManager) { + return variableManager.get(VariableManager.SELF, RepresentationMetadata.class) + .map(RepresentationMetadata::getId) + .orElse(null); + } + + private String getNodeLabel(VariableManager variableManager) { + return variableManager.get(VariableManager.SELF, RepresentationMetadata.class) + .map(RepresentationMetadata::getLabel) + .orElse(null); + } + + private String getNodeKind(VariableManager variableManager) { + return variableManager.get(VariableManager.SELF, RepresentationMetadata.class) + .map(RepresentationMetadata::getKind) + .orElse(null); + } + + private List getNodeIconURL(VariableManager variableManager) { + var optionalRepresentationMetadata = variableManager.get(VariableManager.SELF, RepresentationMetadata.class); + if (optionalRepresentationMetadata.isPresent()) { + RepresentationMetadata representationMetadata = optionalRepresentationMetadata.get(); + + return this.representationImageProviders.stream() + .map(representationImageProvider -> representationImageProvider.getImageURL(representationMetadata.getKind())) + .flatMap(Optional::stream) + .toList(); + } + return List.of(CoreImageConstants.DEFAULT_SVG); + } + + private Function> getChildrenProvider() { + return variableManager -> { + List items = List.of(); + var optionalEditingContext = variableManager.get(IEditingContext.EDITING_CONTEXT, IEditingContext.class); + if (optionalEditingContext.isPresent()) { + IEditingContext editingContext = optionalEditingContext.get(); + Object object = variableManager.getVariables().get(VariableManager.SELF); + String id = this.objectService.getId(object); + if (object instanceof Portal portal) { + items = this.getPortalChildren(optionalEditingContext.get(), portal); + } else if (id != null) { + items = this.representationService.findAllByTargetObjectId(editingContext, id); + } else if (object instanceof RepresentationMetadata representationMetadata && Portal.KIND.equals(representationMetadata.getKind())) { + Optional optionalPortal = this.representationSearchService.findById(editingContext, representationMetadata.getId(), Portal.class); + items = optionalPortal.map(portal -> this.getPortalChildren(editingContext, portal)).orElse(List.of()); + } + } + return items; + }; + } + + private List getPortalChildren(IEditingContext editingContext, Portal portal) { + return portal.getViews().stream() + .map(PortalView::getRepresentationId) + .flatMap(representationId -> this.representationSearchService.findById(editingContext, representationId, IRepresentation.class).stream()) + .map(representation -> new RepresentationMetadata(representation.getId(), representation.getKind(), representation.getLabel(), representation.getDescriptionId())) + .toList(); + } } diff --git a/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsRepresentationRefreshPolicyProvider.java b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsRepresentationRefreshPolicyProvider.java index 7da548dfdb..3208b8c9c8 100644 --- a/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsRepresentationRefreshPolicyProvider.java +++ b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/representations/RepresentationsRepresentationRefreshPolicyProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2023 Obeo. + * Copyright (c) 2021, 2024 Obeo. * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -12,12 +12,14 @@ *******************************************************************************/ package org.eclipse.sirius.web.services.representations; +import java.util.Set; import java.util.UUID; import org.eclipse.sirius.components.collaborative.api.ChangeKind; import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicy; import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicyProvider; import org.eclipse.sirius.components.collaborative.api.IRepresentationRefreshPolicyRegistry; +import org.eclipse.sirius.components.collaborative.portals.PortalChangeKind; import org.eclipse.sirius.components.representations.IRepresentationDescription; import org.springframework.stereotype.Service; @@ -29,6 +31,14 @@ @Service public class RepresentationsRepresentationRefreshPolicyProvider implements IRepresentationRefreshPolicyProvider { + private static final Set IMPACTING_CHANGES = Set.of( + ChangeKind.REPRESENTATION_CREATION, + ChangeKind.REPRESENTATION_DELETION, + ChangeKind.REPRESENTATION_RENAMING, + ChangeKind.REPRESENTATION_TO_DELETE, + PortalChangeKind.PORTAL_VIEW_ADDITION.name(), + PortalChangeKind.PORTAL_VIEW_REMOVAL.name()); + public RepresentationsRepresentationRefreshPolicyProvider(IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry) { representationRefreshPolicyRegistry.add(this); } @@ -40,26 +50,8 @@ public boolean canHandle(IRepresentationDescription representationDescription) { @Override public IRepresentationRefreshPolicy getRepresentationRefreshPolicy(IRepresentationDescription representationDescription) { - return (changeDescription) -> { - boolean shouldRefresh = false; - - switch (changeDescription.getKind()) { - case ChangeKind.REPRESENTATION_CREATION: - shouldRefresh = true; - break; - case ChangeKind.REPRESENTATION_DELETION: - shouldRefresh = true; - break; - case ChangeKind.REPRESENTATION_RENAMING: - shouldRefresh = true; - break; - case ChangeKind.REPRESENTATION_TO_DELETE: - shouldRefresh = true; - break; - default: - shouldRefresh = false; - } - return shouldRefresh; + return changeDescription -> { + return IMPACTING_CHANGES.contains(changeDescription.getKind()); }; } diff --git a/scripts/check-coverage.jsh b/scripts/check-coverage.jsh index e89697997c..68e2706ed6 100644 --- a/scripts/check-coverage.jsh +++ b/scripts/check-coverage.jsh @@ -65,8 +65,8 @@ var moduleCoverageData = List.of( new ModuleCoverage("sirius-components-validation", 0.0), new ModuleCoverage("sirius-components-collaborative-validation", 5.0), new ModuleCoverage("sirius-components-validation-graphql", 22.0), - new ModuleCoverage("sirius-components-portals", 62.0), - new ModuleCoverage("sirius-components-collaborative-portals", 38.0), + new ModuleCoverage("sirius-components-portals", 65.0), + new ModuleCoverage("sirius-components-collaborative-portals", 43.0), new ModuleCoverage("sirius-components-portals-graphql", 59.0), new ModuleCoverage("sirius-components-interpreter", 80.0), new ModuleCoverage("sirius-components-emf", 67.0), @@ -145,4 +145,4 @@ for (var moduleCoverage: moduleCoverageData) { isValidCoverage = isValidCoverage && coverage >= moduleCoverage.expectedCoverage(); } -/exit isValidCoverage ? 0 : 1 \ No newline at end of file +/exit isValidCoverage ? 0 : 1