Skip to content

Commit

Permalink
[2890] Display the contents of a Portal in the Representations view
Browse files Browse the repository at this point in the history
Bug: #2890
Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
  • Loading branch information
pcdavid committed Mar 19, 2024
1 parent dd3eefb commit 2c509aa
Show file tree
Hide file tree
Showing 14 changed files with 266 additions and 41 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Expand Up @@ -193,6 +193,8 @@ 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/3066[#3066] [core] `IObjectService` now can also find/resolve representations.
- https://github.com/eclipse-sirius/sirius-web/issues/2890[#2890] [portal] Display the contents of a Portal in the Representations view

== v2024.1.0

Expand Down
20 changes: 20 additions & 0 deletions integration-tests/cypress/e2e/project/portals/portals.cy.ts
Expand Up @@ -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 = '';
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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', () => {
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -50,6 +51,8 @@ public class RepresentationsEventProcessorFactory implements IRepresentationEven

private final List<IWidgetDescriptor> widgetDescriptors;

private final IRepresentationSearchService representationSearchService;

private final List<IFormEventHandler> formEventHandlers;

private final ISubscriptionManagerFactory subscriptionManagerFactory;
Expand All @@ -61,14 +64,15 @@ public class RepresentationsEventProcessorFactory implements IRepresentationEven
private final IFormPostProcessor formPostProcessor;

public RepresentationsEventProcessorFactory(IRepresentationsDescriptionProvider representationsDescriptionProvider, ISubscriptionManagerFactory subscriptionManagerFactory,
IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, List<IWidgetDescriptor> widgetDescriptors, FormEventProcessorFactoryConfiguration formConfiguration) {
IRepresentationRefreshPolicyRegistry representationRefreshPolicyRegistry, List<IWidgetDescriptor> widgetDescriptors, FormEventProcessorFactoryConfiguration formConfiguration, IRepresentationSearchService representationSearchService) {
this.representationsDescriptionProvider = Objects.requireNonNull(representationsDescriptionProvider);
this.objectService = Objects.requireNonNull(formConfiguration.getObjectService());
this.widgetDescriptors = Objects.requireNonNull(widgetDescriptors);
this.formEventHandlers = Objects.requireNonNull(formConfiguration.getFormEventHandlers());
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());
}

Expand Down Expand Up @@ -106,5 +110,4 @@ public <T extends IRepresentationEventProcessor> Optional<T> createRepresentatio
}
return Optional.empty();
}

}
Expand Up @@ -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) => ({
Expand All @@ -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();
Expand All @@ -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<GQLSubscriber> = new Set();
widgetSubscriptions.forEach((subscription) =>
Expand All @@ -49,6 +58,22 @@ export const RepresentationsView = (props: WorkbenchViewComponentProps) => {
/>
</div>
);
} else if (isTree(widget)) {
const uniqueSubscribers: Set<GQLSubscriber> = new Set();
widgetSubscriptions.forEach((subscription) =>
subscription.subscribers.forEach((subscriber) => uniqueSubscribers.add(subscriber))
);
return (
<div className={classes.content}>
<TreePropertySection
editingContextId={props.editingContextId}
formId={form.id}
readOnly={props.readOnly}
widget={widget}
subscribers={[...uniqueSubscribers.values()]}
/>
</div>
);
} else {
return <div className={classes.content} />;
}
Expand Down
@@ -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,
}
Expand Up @@ -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);
}
}

Expand Down
Expand Up @@ -24,6 +24,8 @@
* @author pcdavid
*/
public interface IPortalEventHandler {
String NEXT_PORTAL_PARAMETER = "nextPortal";

boolean canHandle(IPortalInput portalInput);

void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDescriptionSink, PortalContext context);
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -81,7 +82,9 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> 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());
}
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -72,7 +73,8 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> 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);
Expand Down
Expand Up @@ -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;
Expand All @@ -34,7 +35,7 @@
import reactor.core.publisher.Sinks.One;

/**
* The handler for the addPortalView mutation.
* The handler for the removePortalView mutation.
*
* @author pcdavid
*/
Expand Down Expand Up @@ -69,7 +70,8 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> 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);
Expand Down
Expand Up @@ -76,6 +76,7 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> 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);
Expand Down
Expand Up @@ -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();
Expand Down

0 comments on commit 2c509aa

Please sign in to comment.