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 authored and sbegaudeau committed Mar 20, 2024
1 parent 176d8bc commit 0663ee1
Show file tree
Hide file tree
Showing 20 changed files with 293 additions and 49 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
});
Expand Down
13 changes: 13 additions & 0 deletions integration-tests/cypress/e2e/project/portals/portals.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Flow } from '../../../usecases/Flow';
import { Diagram } from '../../../workbench/Diagram';
import { Explorer } from '../../../workbench/Explorer';
import { Portal } from '../../../workbench/Portal';
import { Representations } from '../../../workbench/Representations';

const projectName = 'Cypress - portal';

Expand Down Expand Up @@ -113,6 +114,10 @@ describe('/projects/:projectId/edit - Portal', () => {
.should('be.enabled');
frame.get('.react-resizable-handle').should('be.visible');
});

const representations = new Representations();
representations.showRepresentationsView();
representations.hasTreeItems([secondPortal]);
});

it('Portal loops can not be created', () => {
Expand Down Expand Up @@ -178,6 +183,10 @@ 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');
});

const representations = new Representations();
representations.showRepresentationsView();
representations.hasTreeItems([diagramTitle]);
});

it('A portal which already contains a representation opens in direct mode', () => {
Expand Down Expand Up @@ -224,6 +233,10 @@ describe('/projects/:projectId/edit - Portal', () => {
explorer.getTreeItemByLabel('Portal').click();

portal.getFrame('New ' + diagramTitle).should('be.visible');

const representations = new Representations();
representations.showRepresentationsView();
representations.hasTreeItems(['New ' + diagramTitle]);
});

it('Deleting a diagram embedded in a portal removes its frame', () => {
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/cypress/workbench/Deck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import { Project } from '../pages/Project';
import { Projects } from '../pages/Projects';
import { isCreateProjectFromTemplateSuccessPayload } from '../support/server/createProjectFromTemplateCommand';
import { ElementStyleProps } from './Deck types';
import { ElementStyleProps } from './Deck.types';
import { Details } from './Details';
import { Explorer } from './Explorer';

Expand Down
34 changes: 34 additions & 0 deletions integration-tests/cypress/workbench/Representations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2023, 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
*******************************************************************************/

export class Representations {
public showRepresentationsView(): void {
cy.getByTestId('viewselector-Representations').click();
}

public getRepresentationsView(): Cypress.Chainable<JQuery<HTMLElement>> {
return cy.getByTestId('view-Representations');
}

public hasTreeItems(expectedItems: string[]): void {
this.getRepresentationsView().then((result) => {
cy.wrap(result)
.find('ul[role="tree"]')
.then((result) => {
expectedItems.forEach((itemText) => {
cy.wrap(result).should('contain.text', itemText);
});
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,4 @@ public <T extends IRepresentationEventProcessor> Optional<T> createRepresentatio
}
return Optional.empty();
}

}
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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,
}
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading

0 comments on commit 0663ee1

Please sign in to comment.