From 40aff340d2bc89fe1a0367939ae9839f3256c3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Rou=C3=ABn=C3=A9?= Date: Tue, 25 Apr 2023 13:57:11 +0200 Subject: [PATCH] [1915] Add page concept in form view DSL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: https://github.com/eclipse-sirius/sirius-components/issues/1915 Signed-off-by: Florian Rouëné --- CHANGELOG.adoc | 1 + .../xxx_add_page_description_in_view.adoc | 27 + .../project/edit/formdescriptioneditor.cy.js | 97 +- .../PropertiesDefaultDescriptionProvider.java | 3 +- .../properties/FormRendererTests.java | 31 +- .../ViewExtensionDescriptionConverter.java | 11 +- .../FormDescriptionEditorCreationService.java | 13 +- .../dto/AddGroupInput.java | 3 +- .../dto/AddPageInput.java | 26 + .../dto/DeletePageInput.java | 26 + .../dto/MoveGroupInput.java | 3 +- .../dto/MovePageInput.java | 26 + .../handlers/AddGroupEventHandler.java | 38 +- .../handlers/AddPageEventHandler.java | 108 + .../handlers/DeletePageEventHandler.java | 98 + .../handlers/MoveGroupEventHandler.java | 55 +- .../handlers/MovePageEventHandler.java | 113 + ...nameFormDescriptionEditorEventHandler.java | 7 +- .../schema/formdescriptioneditor.graphqls | 35 +- ...mDescriptionEditorEventProcessorTests.java | 4 +- .../TestFormDescriptionEditorBuilder.java | 27 +- .../handlers/AddGroupEventHandlerTests.java | 79 + .../handlers/AddPageEventHandlerTests.java | 82 + .../AddToolbarActionEventHandlerTests.java | 9 +- .../handlers/DeletePageEventHandlerTests.java | 99 + .../DeleteToolbarActionEventHandlerTests.java | 6 +- .../handlers/MoveGroupEventHandlerTests.java | 109 + .../handlers/MovePageEventHandlerTests.java | 106 + .../MoveToolbarActionEventHandlerTests.java | 14 +- ...ormDescriptionEditorEventHandlerTests.java | 5 +- .../mutation/MutationAddPageDataFetcher.java | 58 + .../MutationDeletePageDataFetcher.java | 58 + .../mutation/MutationMovePageDataFetcher.java | 58 + .../FormDescriptionEditor.java | 21 +- .../FormDescriptionEditorComponent.java | 17 +- .../FormDescriptionEditorGroupComponent.java | 4 +- .../FormDescriptionEditorPageComponent.java | 92 + ...rmDescriptionEditorPageComponentProps.java | 32 + ...criptionEditorComponentPropsValidator.java | 6 +- .../FormDescriptionEditorElementFactory.java | 12 +- .../src/FlexboxContainerWidget.tsx | 16 +- .../src/FormDescriptionEditorEventFragment.ts | 62 +- ...ormDescriptionEditorEventFragment.types.ts | 74 +- .../FormDescriptionEditorRepresentation.tsx | 199 +- .../src/Group.tsx | 44 +- .../src/Group.types.ts | 5 +- .../src/Page.tsx | 251 ++ .../src/Page.types.ts | 29 + .../src/PageList.tsx | 406 +++ .../src/PageList.types.ts | 29 + .../src/ToolbarActionWidget.tsx | 20 +- .../src/ToolbarActions.tsx | 14 +- .../src/WidgetEntry.tsx | 19 +- .../src/WidgetEntry.types.ts | 5 +- .../src/WidgetOperations.tsx | 33 +- .../src/__tests__/Group.test.tsx | 40 +- .../src/__tests__/Page.test.tsx | 253 ++ .../src/__tests__/ToolbarActions.test.tsx | 44 +- .../src/__tests__/WidgetEntry.test.tsx | 48 +- .../forms/FormDescriptionAggregator.java | 13 - .../src/main/resources/schema/form.graphqls | 1 + .../forms/FormDescriptionAggregatorTests.java | 6 +- .../forms/FormEventProcessorTests.java | 1 - .../handlers/CreateFormEventHandlerTests.java | 2 +- .../eclipse/sirius/components/forms/Page.java | 18 +- .../forms/description/FormDescription.java | 18 +- .../forms/renderer/FormElementFactory.java | 8 +- .../forms/render/RenderTextfieldTest.java | 3 +- .../src/form/FormEventFragments.types.ts | 3 +- ...ntationMetadataDescriptionDataFetcher.java | 3 +- ...ereotypeDescriptionRegistryConfigurer.java | 10 +- .../overviewform/OverviewFormProvider.java | 7 +- ...DescriptionEditorPageIntegrationTests.java | 466 +++ .../test/resources/ViewCompletionFixture.xmi | 94 +- ...ultRelatedElementsDescriptionProvider.java | 1 - .../RepresentationsDescriptionProvider.java | 3 +- .../provider/FormDescriptionItemProvider.java | 19 +- .../provider/PageDescriptionItemProvider.java | 234 ++ .../view/provider/ViewItemProvider.java | 5 +- .../ViewItemProviderAdapterFactory.java | 25 + .../icons/full/obj16/PageDescription.svg | 1 + .../src/main/resources/plugin.properties | 61 +- ...opertiesDescriptionRegistryConfigurer.java | 3 +- .../NodeStylePropertiesConfigurer.java | 3 - .../form/ViewFormDescriptionConverter.java | 139 +- .../view/emf/view/DynamicFormsTests.java | 5 +- .../components/view/FormDescription.java | 23 +- .../components/view/PageDescription.java | 153 + .../sirius/components/view/ViewFactory.java | 90 +- .../sirius/components/view/ViewPackage.java | 2772 +++++++++-------- .../view/impl/BarChartDescriptionImpl.java | 6 +- .../view/impl/CheckboxDescriptionImpl.java | 6 +- .../view/impl/FormDescriptionImpl.java | 47 +- .../view/impl/MultiSelectDescriptionImpl.java | 6 +- .../view/impl/PageDescriptionImpl.java | 441 +++ .../view/impl/PieChartDescriptionImpl.java | 6 +- .../view/impl/TextAreaDescriptionImpl.java | 6 +- .../view/impl/TextfieldDescriptionImpl.java | 6 +- .../components/view/impl/ViewFactoryImpl.java | 124 +- .../components/view/impl/ViewPackageImpl.java | 624 ++-- .../view/util/ViewAdapterFactory.java | 159 +- .../components/view/util/ViewSwitch.java | 168 +- .../src/main/resources/model/view.ecore | 12 + .../src/main/resources/model/view.genmodel | 10 +- 104 files changed, 6527 insertions(+), 2494 deletions(-) create mode 100644 doc/adrs/xxx_add_page_description_in_view.adoc create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddPageInput.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/DeletePageInput.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MovePageInput.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandler.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandler.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandler.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandlerTests.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandlerTests.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandlerTests.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandlerTests.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandlerTests.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationAddPageDataFetcher.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationDeletePageDataFetcher.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationMovePageDataFetcher.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponent.java create mode 100644 packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponentProps.java create mode 100644 packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.tsx create mode 100644 packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.types.ts create mode 100644 packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.tsx create mode 100644 packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.types.ts create mode 100644 packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Page.test.tsx create mode 100644 packages/sirius-web/backend/sirius-web-sample-application/src/test/java/org/eclipse/sirius/web/sample/tests/integration/formdescritpioneditors/FormDescriptionEditorPageIntegrationTests.java create mode 100644 packages/view/backend/sirius-components-view-edit/src/main/java/org/eclipse/sirius/components/view/provider/PageDescriptionItemProvider.java create mode 100644 packages/view/backend/sirius-components-view-edit/src/main/resources/icons/full/obj16/PageDescription.svg create mode 100644 packages/view/backend/sirius-components-view/src/main/java/org/eclipse/sirius/components/view/PageDescription.java create mode 100644 packages/view/backend/sirius-components-view/src/main/java/org/eclipse/sirius/components/view/impl/PageDescriptionImpl.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 54f26bbd56..b77885fa8f 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -18,6 +18,7 @@ All the colors are now defined in a new palette object _ColorPalette_ with the properties _name_ and _value_. A view can define as many _ColorPalette_ as desired. In the _styleDescription_, the definition of a color are now a select list of all the colors contained in the _ColorPalette_ of the view. +- https://github.com/eclipse-sirius/sirius-components/issues/1915[#1915] [view] Add the page support in the `formdescriptor` of the view DSL. === Dependency update - https://github.com/eclipse-sirius/sirius-components/issues/1936[#1936] [releng] Switch to Cypress 12.11.0 diff --git a/doc/adrs/xxx_add_page_description_in_view.adoc b/doc/adrs/xxx_add_page_description_in_view.adoc new file mode 100644 index 0000000000..1f631c8ace --- /dev/null +++ b/doc/adrs/xxx_add_page_description_in_view.adoc @@ -0,0 +1,27 @@ += ADR-xxx - Add `PageDescription` definition in the View DSL + +== Context + +In the View DSL definition (in `view.ecore`), it's only possible to organize `FormDescription` in separate groups. + +== Decision + +We will add a new level to organize groups in different pages. This new object `PageDescription` will be contained in a `FormDescription` and may contain any number of +`GroupDescription`. + +=== Frontend + +The Material-UI `Tabs` representation will be used to display the pages of the FormDescription. +A new drop area will be added to drop new page elements from the editor. +To change the page order, the `Tab` will be _draggable._ +The `Tab` are Material-UI component, and it's not recommended to add a new drop area to `Tabs` between them to offer the possibility to place `Tab` at any position. +To get around that, it will be possible to drop elements directly on the `Tab` element in order to place it before. + +=== Backend + +The new structure of the class `FormDescriptionEditor` will be just like the ecore definition i.e., the new layer `List` will be introduced in place of `List` which +is moved in the `Page` object. + +== Status + +Accepted. diff --git a/integration-tests/cypress/e2e/project/edit/formdescriptioneditor.cy.js b/integration-tests/cypress/e2e/project/edit/formdescriptioneditor.cy.js index 3d5f9f6b67..85f8fa059c 100644 --- a/integration-tests/cypress/e2e/project/edit/formdescriptioneditor.cy.js +++ b/integration-tests/cypress/e2e/project/edit/formdescriptioneditor.cy.js @@ -20,13 +20,9 @@ describe('/projects/:projectId/edit - FormDescriptionEditor', () => { cy.visit(`/projects/${projectId}/edit`); }); }); - }); - - it('try to move a toolbar action into another empty group', () => { cy.getByTestId('ViewDocument').dblclick(); cy.getByTestId('View').dblclick(); cy.getByTestId('View-more').click(); - // create the form description cy.getByTestId('treeitem-contextmenu').findByTestId('new-object').click(); //make sure the data are fetched before selecting @@ -39,10 +35,13 @@ describe('/projects/:projectId/edit - FormDescriptionEditor', () => { cy.getByTestId('New Form Description-more').click(); cy.getByTestId('treeitem-contextmenu').findByTestId('new-representation').click(); cy.getByTestId('create-representation').click(); - // create a second group + }); + + it('try to move a toolbar action into another empty group', () => { + // create another group const dataTransfer = new DataTransfer(); cy.getByTestId('FormDescriptionEditor-Group').trigger('dragstart', { dataTransfer }); - cy.getByTestId('FormDescriptionEditor-DropArea').trigger('drop', { dataTransfer }); + cy.getByTestId('Page-DropArea').trigger('drop', { dataTransfer }); // create a toolbar action in the first group cy.get('[data-testid^="Group-ToolbarActions-NewAction-"]').eq(0).click(); // move the toolbar action from the first group to the second one @@ -50,37 +49,59 @@ describe('/projects/:projectId/edit - FormDescriptionEditor', () => { cy.get('[data-testid^="Group-ToolbarActions-DropArea-"]').eq(1).trigger('drop', { dataTransfer }); }); - it('rename a form description editor', () => { - cy.getByTestId('ViewDocument').dblclick(); - cy.getByTestId('View').dblclick(); - cy.getByTestId('View-more').click(); - // create the form description - cy.getByTestId('treeitem-contextmenu').findByTestId('new-object').click(); - //make sure the data are fetched before selecting - cy.getByTestId('create-object').should('be.enabled'); - cy.getByTestId('childCreationDescription').click(); - cy.get('[data-value="Form Description"]').click(); - cy.getByTestId('create-object').click(); - // create a button widget under the group of the form description editor - cy.getByTestId('New Form Description').dblclick(); - cy.getByTestId('GroupDescription').dblclick(); - cy.getByTestId('GroupDescription-more').click(); - cy.getByTestId('treeitem-contextmenu').findByTestId('new-object').click(); - //make sure the data are fetched before selecting - cy.getByTestId('create-object').should('be.enabled'); - cy.getByTestId('childCreationDescription').click(); - cy.get('[data-value="Widgets Button Description"]').click(); - cy.getByTestId('create-object').click(); - // create the form description editor - cy.getByTestId('New Form Description').click(); - cy.getByTestId('New Form Description-more').click(); - cy.getByTestId('treeitem-contextmenu').findByTestId('new-representation').click(); - cy.getByTestId('create-representation').click(); - // rename the form description editor - cy.getByTestId('FormDescriptionEditor').click(); - cy.getByTestId('FormDescriptionEditor-more').click(); - cy.getByTestId('treeitem-contextmenu').findByTestId('rename-tree-item').click(); - cy.getByTestId('name-edit').type('Renamed-FormDescriptionEditor{enter}'); - cy.getByTestId('Renamed-FormDescriptionEditor').should('exist'); + it('try to create an empty page', () => { + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').should('have.lengthOf', 1); + const dataTransfer = new DataTransfer(); + cy.getByTestId('FormDescriptionEditor-Page').trigger('dragstart', { dataTransfer }); + cy.getByTestId('PageList-DropArea').trigger('drop', { dataTransfer }); + cy.wait(500); // Wait for representation to refresh + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').should('have.lengthOf', 2); + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(1).click(); + cy.get('[title="Group"]').should('exist'); + }); + + it('try to rename a page', () => { + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(0).click(); + cy.getByTestId('Label Expression').click().type('Page Rename{enter}'); + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').first().should('have.text', 'Page Rename'); }); + + it('try to move a page', () => { + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(0).click(); + cy.getByTestId('Label Expression').click().type('Page 1{enter}'); + const dataTransfer = new DataTransfer(); + cy.getByTestId('FormDescriptionEditor-Page').trigger('dragstart', { dataTransfer }); + cy.getByTestId('PageList-DropArea').trigger('drop', { dataTransfer }); + cy.wait(500); // Wait for representation to refresh + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').should('have.lengthOf', 2); + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(1).click(); + cy.wait(500); // Wait for representation to refresh + cy.getByTestId('Label Expression').click().type('Page 2{enter}'); + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(0).should('have.text', 'Page 1'); + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(1).should('have.text', 'Page 2'); + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(0).trigger('dragstart', { dataTransfer }); + cy.getByTestId('PageList-DropArea').trigger('drop', { dataTransfer }); + cy.wait(500); // Wait for representation to refresh + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(0).should('have.text', 'Page 2'); + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').eq(1).should('have.text', 'Page 1'); + }); + + it('try to delete a page', () => { + const dataTransfer = new DataTransfer(); + cy.getByTestId('FormDescriptionEditor-Page').trigger('dragstart', { dataTransfer }); + cy.getByTestId('PageList-DropArea').trigger('drop', { dataTransfer }); + cy.wait(500); // Wait for representation to refresh + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').should('have.lengthOf', 2); + cy.get('[data-testid^="Page-"]').eq(0).click().type('{del}'); + cy.wait(500); // Wait for representation to refresh + cy.get('[data-testid^="Page-"]').not('[data-testid="Page-DropArea"]').should('have.lengthOf', 1); + }); + + it('try to add group and widget to a page', () => { + const dataTransfer = new DataTransfer(); + cy.getByTestId('FormDescriptionEditor-BarChart').trigger('dragstart', { dataTransfer }); + cy.get('[data-testid^="Group-Widgets-DropArea-"]').eq(0).trigger('drop', { dataTransfer }); + cy.getByTestId('BarChart').should('exist'); + }); + }); diff --git a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java index b1d9994525..4715638205 100644 --- a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java +++ b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2022 Obeo. + * Copyright (c) 2019, 2023 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 @@ -97,7 +97,6 @@ public FormDescription getFormDescription() { .targetObjectIdProvider(targetObjectIdProvider) .canCreatePredicate(variableManager -> false) .pageDescriptions(pageDescriptions) - .groupDescriptions(groupDescriptions) .build(); // @formatter:on } diff --git a/packages/compatibility/backend/sirius-components-compatibility-emf/src/test/java/org/eclipse/sirius/components/compatibility/emf/compatibility/properties/FormRendererTests.java b/packages/compatibility/backend/sirius-components-compatibility-emf/src/test/java/org/eclipse/sirius/components/compatibility/emf/compatibility/properties/FormRendererTests.java index 4ea2b7874e..3391c0d2dd 100644 --- a/packages/compatibility/backend/sirius-components-compatibility-emf/src/test/java/org/eclipse/sirius/components/compatibility/emf/compatibility/properties/FormRendererTests.java +++ b/packages/compatibility/backend/sirius-components-compatibility-emf/src/test/java/org/eclipse/sirius/components/compatibility/emf/compatibility/properties/FormRendererTests.java @@ -39,6 +39,7 @@ import org.eclipse.sirius.components.forms.description.FormDescription; import org.eclipse.sirius.components.forms.description.RadioDescription; import org.eclipse.sirius.components.forms.description.SelectDescription; +import org.eclipse.sirius.components.forms.description.TextareaDescription; import org.eclipse.sirius.components.forms.description.TextfieldDescription; import org.eclipse.sirius.components.forms.renderer.FormRenderer; import org.eclipse.sirius.components.interpreter.AQLInterpreter; @@ -210,23 +211,28 @@ private org.eclipse.sirius.properties.GroupDescription createGroupDescription() private void checkResult(FormDescription description) { // test SiriusViewExtensionDescriptionConverter assertThat(description).isNotNull(); - assertThat(description.getGroupDescriptions()).hasSize(1); assertThat(description.getPageDescriptions()).hasSize(1); assertThat(description.getPageDescriptions().get(0).getGroupDescriptions()).hasSize(1); - assertThat(description.getPageDescriptions()).hasSize(1); - assertThat(description.getPageDescriptions().get(0).getGroupDescriptions().get(0)).isEqualTo(description.getGroupDescriptions().get(0)); - assertThat(description.getGroupDescriptions().stream().flatMap(g -> g.getControlDescriptions().stream())).hasSize(6); - assertThat(description.getGroupDescriptions().stream().flatMap(g -> g.getControlDescriptions().stream()).filter(CheckboxDescription.class::isInstance)).hasSize(1); - assertThat(description.getGroupDescriptions().stream().flatMap(g -> g.getControlDescriptions().stream()).filter(RadioDescription.class::isInstance)).hasSize(1); - assertThat(description.getGroupDescriptions().stream().flatMap(g -> g.getControlDescriptions().stream()).filter(SelectDescription.class::isInstance)).hasSize(1); - assertThat(description.getGroupDescriptions().stream().flatMap(g -> g.getControlDescriptions().stream()).filter(TextfieldDescription.class::isInstance)).hasSize(1); - assertThat(description.getGroupDescriptions().stream().flatMap(g -> g.getControlDescriptions().stream()).filter(TextfieldDescription.class::isInstance)).hasSize(1); - Optional forOptional = description.getGroupDescriptions().stream().flatMap(g -> g.getControlDescriptions().stream()).filter(ForDescription.class::isInstance) + assertThat(description.getPageDescriptions().stream().flatMap(g -> g.getGroupDescriptions().stream()).flatMap(g -> g.getControlDescriptions().stream())).hasSize(6); + assertThat(description.getPageDescriptions().stream().flatMap(g -> g.getGroupDescriptions().stream()).flatMap(g -> g.getControlDescriptions().stream()) + .filter(CheckboxDescription.class::isInstance)).hasSize(1); + assertThat(description.getPageDescriptions().stream().flatMap(g -> g.getGroupDescriptions().stream()).flatMap(g -> g.getControlDescriptions().stream()) + .filter(RadioDescription.class::isInstance)).hasSize(1); + assertThat(description.getPageDescriptions().stream().flatMap(g -> g.getGroupDescriptions().stream()).flatMap(g -> g.getControlDescriptions().stream()) + .filter(SelectDescription.class::isInstance)).hasSize(1); + assertThat(description.getPageDescriptions().stream().flatMap(g -> g.getGroupDescriptions().stream()).flatMap(g -> g.getControlDescriptions().stream()) + .filter(TextfieldDescription.class::isInstance)).hasSize(1); + assertThat(description.getPageDescriptions().stream().flatMap(g -> g.getGroupDescriptions().stream()).flatMap(g -> g.getControlDescriptions().stream()) + .filter(TextareaDescription.class::isInstance)).hasSize(1); + Optional forOptional = description.getPageDescriptions() + .stream() + .flatMap(g -> g.getGroupDescriptions().stream()) + .flatMap(g -> g.getControlDescriptions().stream()) + .filter(ForDescription.class::isInstance) .map(ForDescription.class::cast).findFirst(); assertThat(forOptional).isNotEmpty(); assertThat(forOptional.get().getIfDescriptions()).hasSize(1); assertThat(forOptional.get().getIfDescriptions().stream().findFirst().get().getWidgetDescription()).isNotNull(); - // Test FormRenderer VariableManager variableManager = new VariableManager(); variableManager.put(VariableManager.SELF, List.of(EcorePackage.eINSTANCE)); @@ -247,8 +253,7 @@ private void checkResult(FormDescription description) { /** * Checks that inside a group all widget id are different. * - * @param groups - * The list of groups + * @param groups The list of groups */ private void checkIdsInGroups(List groups) { for (Group group : groups) { diff --git a/packages/compatibility/backend/sirius-components-compatibility/src/main/java/org/eclipse/sirius/components/compatibility/forms/ViewExtensionDescriptionConverter.java b/packages/compatibility/backend/sirius-components-compatibility/src/main/java/org/eclipse/sirius/components/compatibility/forms/ViewExtensionDescriptionConverter.java index 1e9d8757d5..d7c7c6a212 100644 --- a/packages/compatibility/backend/sirius-components-compatibility/src/main/java/org/eclipse/sirius/components/compatibility/forms/ViewExtensionDescriptionConverter.java +++ b/packages/compatibility/backend/sirius-components-compatibility/src/main/java/org/eclipse/sirius/components/compatibility/forms/ViewExtensionDescriptionConverter.java @@ -36,7 +36,7 @@ import org.springframework.stereotype.Service; /** - * This class is used to convert a Sirius {@link ViewExtensionDescription} to an Sirius Web {@link FormDescription}. + * This class is used to convert a Sirius {@link ViewExtensionDescription} to a Sirius Web {@link FormDescription}. * * @author fbarbin */ @@ -72,13 +72,12 @@ public FormDescription convert(ViewExtensionDescription viewExtensionDescription PageDescriptionConverter pageDescriptionConverter = new PageDescriptionConverter(interpreter, this.identifierProvider, this.semanticCandidatesProviderFactory); GroupDescriptionConverter groupDescriptionConverter = new GroupDescriptionConverter(interpreter, this.objectService, this.identifierProvider, this.modelOperationHandlerSwitchProvider); - // @formatter:off Map siriusGroup2SiriusWebGroup = new HashMap<>(); - List groupDescriptions = viewExtensionDescription.getCategories().stream() + + viewExtensionDescription.getCategories().stream() .flatMap(category -> category.getPages().stream()) .flatMap(page -> page.getGroups().stream()) - .map(groupDescription -> groupDescriptionConverter.convert(groupDescription, siriusGroup2SiriusWebGroup)) - .toList(); + .forEach(groupDescription -> groupDescriptionConverter.convert(groupDescription, siriusGroup2SiriusWebGroup)); List pageDescriptions = viewExtensionDescription.getCategories().stream() .flatMap(category -> category.getPages().stream()) @@ -106,8 +105,6 @@ public FormDescription convert(ViewExtensionDescription viewExtensionDescription .canCreatePredicate(variableManager -> false) .targetObjectIdProvider(targetObjectIdProvider) .pageDescriptions(pageDescriptions) - .groupDescriptions(groupDescriptions) .build(); - // @formatter:on } } diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorCreationService.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorCreationService.java index 772aa6d980..6ec0448a3a 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorCreationService.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorCreationService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -60,23 +60,19 @@ public FormDescriptionEditorCreationService(IRepresentationDescriptionSearchServ this.representationPersistenceService = Objects.requireNonNull(representationPersistenceService); this.objectService = Objects.requireNonNull(objectService); - // @formatter:off this.timer = Timer.builder(Monitoring.REPRESENTATION_EVENT_PROCESSOR_REFRESH) .tag(Monitoring.NAME, "formdescriptioneditor") .register(meterRegistry); - // @formatter:on } @Override public FormDescriptionEditor create(String label, Object targetObject, FormDescriptionEditorDescription formDescriptionEditorDescription, IEditingContext editingContext) { - // @formatter:off FormDescriptionEditor newFormDescriptionEditor = FormDescriptionEditor.newFormDescriptionEditor(UUID.randomUUID().toString()) .label(label) .targetObjectId(this.objectService.getId(targetObject)) .descriptionId(formDescriptionEditorDescription.getId()) - .groups(List.of()) // We don't store form description editor groups, it will be re-render by the FormDescriptionEditorProcessor. + .pages(List.of()) // We don't store form description editor pages, it will be re-render by the FormDescriptionEditorProcessor. .build(); - // @formatter:on this.representationPersistenceService.save(editingContext, newFormDescriptionEditor); @@ -87,18 +83,15 @@ public FormDescriptionEditor create(String label, Object targetObject, FormDescr public FormDescriptionEditor refresh(IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext) { FormDescriptionEditor previousFormDescriptionEditor = formDescriptionEditorContext.getFormDescriptionEditor(); var optionalObject = this.objectService.getObject(editingContext, previousFormDescriptionEditor.getTargetObjectId()); - // @formatter:off var optionalFormDescriptionEditorDescription = this.representationDescriptionSearchService.findById(editingContext, previousFormDescriptionEditor.getDescriptionId()) .filter(FormDescriptionEditorDescription.class::isInstance) .map(FormDescriptionEditorDescription.class::cast); - // @formatter:on if (optionalObject.isPresent() && optionalFormDescriptionEditorDescription.isPresent()) { Object object = optionalObject.get(); FormDescriptionEditorDescription formDescriptionEditorDescription = optionalFormDescriptionEditorDescription.get(); - FormDescriptionEditor formDescriptionEditor = this.doRender(previousFormDescriptionEditor.getLabel(), object, editingContext, formDescriptionEditorDescription, + return this.doRender(previousFormDescriptionEditor.getLabel(), object, editingContext, formDescriptionEditorDescription, Optional.of(formDescriptionEditorContext)); - return formDescriptionEditor; } return null; diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddGroupInput.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddGroupInput.java index 0e9cc945f3..778bd3999c 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddGroupInput.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddGroupInput.java @@ -21,5 +21,6 @@ * * @author arichard */ -public record AddGroupInput(UUID id, String editingContextId, String representationId, int index) implements IFormDescriptionEditorInput { +public record AddGroupInput(UUID id, String editingContextId, String representationId, String pageId, int index) implements IFormDescriptionEditorInput { + } diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddPageInput.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddPageInput.java new file mode 100644 index 0000000000..55cea7b03c --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/AddPageInput.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.dto; + +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorInput; + +/** + * The input for the Form Description Editor add page mutation. + * + * @author frouene + */ +public record AddPageInput(UUID id, String editingContextId, String representationId, int index) implements IFormDescriptionEditorInput { + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/DeletePageInput.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/DeletePageInput.java new file mode 100644 index 0000000000..3eded3e81e --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/DeletePageInput.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.dto; + +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorInput; + +/** + * The input for the Form Description Editor delete page mutation. + * + * @author frouene + */ +public record DeletePageInput(UUID id, String editingContextId, String representationId, String pageId) implements IFormDescriptionEditorInput { + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MoveGroupInput.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MoveGroupInput.java index 933fa5f594..43bbf99fc4 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MoveGroupInput.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MoveGroupInput.java @@ -21,5 +21,6 @@ * * @author arichard */ -public record MoveGroupInput(UUID id, String editingContextId, String representationId, String groupId, int index) implements IFormDescriptionEditorInput { +public record MoveGroupInput(UUID id, String editingContextId, String representationId, String pageId, String groupId, int index) implements IFormDescriptionEditorInput { + } diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MovePageInput.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MovePageInput.java new file mode 100644 index 0000000000..32c701652b --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/dto/MovePageInput.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.dto; + +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorInput; + +/** + * The input for the Form Description Editor move page mutation. + * + * @author frouene + */ +public record MovePageInput(UUID id, String editingContextId, String representationId, String pageId, int index) implements IFormDescriptionEditorInput { + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandler.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandler.java index 05dd94b154..c1772acb05 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandler.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandler.java @@ -13,6 +13,7 @@ package org.eclipse.sirius.components.collaborative.formdescriptioneditors.handlers; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.sirius.components.collaborative.api.ChangeDescription; import org.eclipse.sirius.components.collaborative.api.ChangeKind; @@ -27,7 +28,7 @@ import org.eclipse.sirius.components.core.api.IObjectService; import org.eclipse.sirius.components.core.api.IPayload; import org.eclipse.sirius.components.core.api.SuccessPayload; -import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.PageDescription; import org.eclipse.sirius.components.view.ViewFactory; import org.springframework.stereotype.Service; @@ -54,11 +55,9 @@ public AddGroupEventHandler(IObjectService objectService, ICollaborativeFormDesc this.objectService = Objects.requireNonNull(objectService); this.messageService = Objects.requireNonNull(messageService); - // @formatter:off this.counter = Counter.builder(Monitoring.EVENT_HANDLER) .tag(Monitoring.NAME, this.getClass().getSimpleName()) .register(meterRegistry); - // @formatter:on } @Override @@ -75,9 +74,8 @@ public void handle(One payloadSink, Many changeDesc IPayload payload = new ErrorPayload(formDescriptionEditorInput.id(), message); ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); - if (formDescriptionEditorInput instanceof AddGroupInput) { - int index = ((AddGroupInput) formDescriptionEditorInput).index(); - boolean addGroup = this.addGroup(editingContext, formDescriptionEditorContext, index); + if (formDescriptionEditorInput instanceof AddGroupInput addGroupInput) { + boolean addGroup = this.addGroup(editingContext, addGroupInput.pageId(), addGroupInput.index()); if (addGroup) { payload = new SuccessPayload(formDescriptionEditorInput.id()); changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); @@ -88,17 +86,21 @@ public void handle(One payloadSink, Many changeDesc changeDescriptionSink.tryEmitNext(changeDescription); } - private boolean addGroup(IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, int index) { - boolean success = false; - var optionalSelf = this.objectService.getObject(editingContext, formDescriptionEditorContext.getFormDescriptionEditor().getTargetObjectId()); - if (optionalSelf.isPresent()) { - Object container = optionalSelf.get(); - if (container instanceof FormDescription) { - var groupDescription = ViewFactory.eINSTANCE.createGroupDescription(); - ((FormDescription) container).getGroups().add(index, groupDescription); - success = true; - } - } - return success; + private boolean addGroup(IEditingContext editingContext, String pageId, int index) { + AtomicBoolean success = new AtomicBoolean(false); + this.objectService.getObject(editingContext, pageId) + .filter(PageDescription.class::isInstance) + .map(PageDescription.class::cast) + .ifPresent(pageDescription -> { + this.createNewGroupInPageDescription(pageDescription, index); + success.set(true); + }); + + return success.get(); + } + + private void createNewGroupInPageDescription(PageDescription pageDescription, int index) { + var groupDescription = ViewFactory.eINSTANCE.createGroupDescription(); + pageDescription.getGroups().add(index, groupDescription); } } diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandler.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandler.java new file mode 100644 index 0000000000..6ac87bccc7 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandler.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 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.formdescriptioneditors.handlers; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +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.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorEventHandler; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.AddPageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.ErrorPayload; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.ViewFactory; +import org.springframework.stereotype.Service; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import reactor.core.publisher.Sinks.Many; +import reactor.core.publisher.Sinks.One; + +/** + * Handle the add page event on Form Description Editor. + * + * @author frouene + */ +@Service +public class AddPageEventHandler implements IFormDescriptionEditorEventHandler { + + private final IObjectService objectService; + + private final ICollaborativeFormDescriptionEditorMessageService messageService; + + private final Counter counter; + + public AddPageEventHandler(IObjectService objectService, ICollaborativeFormDescriptionEditorMessageService messageService, MeterRegistry meterRegistry) { + this.objectService = Objects.requireNonNull(objectService); + this.messageService = Objects.requireNonNull(messageService); + + this.counter = Counter.builder(Monitoring.EVENT_HANDLER) + .tag(Monitoring.NAME, this.getClass().getSimpleName()) + .register(meterRegistry); + } + + @Override + public boolean canHandle(IFormDescriptionEditorInput formDescriptionEditorInput) { + return formDescriptionEditorInput instanceof AddPageInput; + } + + @Override + public void handle(One payloadSink, Many changeDescriptionSink, IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, + IFormDescriptionEditorInput formDescriptionEditorInput) { + this.counter.increment(); + + String message = this.messageService.invalidInput(formDescriptionEditorInput.getClass().getSimpleName(), AddPageInput.class.getSimpleName()); + IPayload payload = new ErrorPayload(formDescriptionEditorInput.id(), message); + ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); + + if (formDescriptionEditorInput instanceof AddPageInput addPageInput) { + boolean addPage = this.addPage(editingContext, formDescriptionEditorContext, addPageInput.index()); + if (addPage) { + payload = new SuccessPayload(formDescriptionEditorInput.id()); + changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); + } + } + + payloadSink.tryEmitValue(payload); + changeDescriptionSink.tryEmitNext(changeDescription); + } + + private boolean addPage(IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, int index) { + AtomicBoolean success = new AtomicBoolean(false); + this.objectService.getObject(editingContext, formDescriptionEditorContext.getFormDescriptionEditor().getTargetObjectId()) + .filter(FormDescription.class::isInstance) + .map(FormDescription.class::cast) + .ifPresent(pageDescription -> { + this.createNewPageWithDefaultEmptyGroupInFormDescription(pageDescription, index); + success.set(true); + }); + + return success.get(); + } + + private void createNewPageWithDefaultEmptyGroupInFormDescription(FormDescription formDescription, int index) { + var pageDescription = ViewFactory.eINSTANCE.createPageDescription(); + var groupDescription = ViewFactory.eINSTANCE.createGroupDescription(); + pageDescription.getGroups().add(groupDescription); + formDescription.getPages().add(index, pageDescription); + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandler.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandler.java new file mode 100644 index 0000000000..6ee8cac723 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandler.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 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.formdescriptioneditors.handlers; + +import java.util.Objects; + +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.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorEventHandler; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.DeletePageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.ErrorPayload; +import org.eclipse.sirius.components.core.api.IEditService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.springframework.stereotype.Service; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import reactor.core.publisher.Sinks.Many; +import reactor.core.publisher.Sinks.One; + +/** + * Handle the delete page event on Form Description Editor. + * + * @author frouene + */ +@Service +public class DeletePageEventHandler implements IFormDescriptionEditorEventHandler { + + private final IObjectService objectService; + + private final IEditService editService; + + private final ICollaborativeFormDescriptionEditorMessageService messageService; + + private final Counter counter; + + public DeletePageEventHandler(IObjectService objectService, IEditService editService, ICollaborativeFormDescriptionEditorMessageService messageService, MeterRegistry meterRegistry) { + this.objectService = Objects.requireNonNull(objectService); + this.editService = Objects.requireNonNull(editService); + this.messageService = Objects.requireNonNull(messageService); + + this.counter = Counter.builder(Monitoring.EVENT_HANDLER) + .tag(Monitoring.NAME, this.getClass().getSimpleName()) + .register(meterRegistry); + } + + @Override + public boolean canHandle(IFormDescriptionEditorInput formDescriptionEditorInput) { + return formDescriptionEditorInput instanceof DeletePageInput; + } + + @Override + public void handle(One payloadSink, Many changeDescriptionSink, IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, + IFormDescriptionEditorInput formDescriptionEditorInput) { + this.counter.increment(); + + String message = this.messageService.invalidInput(formDescriptionEditorInput.getClass().getSimpleName(), DeletePageInput.class.getSimpleName()); + IPayload payload = new ErrorPayload(formDescriptionEditorInput.id(), message); + ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); + + if (formDescriptionEditorInput instanceof DeletePageInput deletePageInput) { + boolean deletePage = this.deletePage(editingContext, deletePageInput.pageId()); + if (deletePage) { + payload = new SuccessPayload(formDescriptionEditorInput.id()); + changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); + } + } + + payloadSink.tryEmitValue(payload); + changeDescriptionSink.tryEmitNext(changeDescription); + } + + protected boolean deletePage(IEditingContext editingContext, String pageId) { + var optionalSelf = this.objectService.getObject(editingContext, pageId); + if (optionalSelf.isPresent()) { + this.editService.delete(optionalSelf.get()); + return true; + } + return false; + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandler.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandler.java index 8658ae5995..6e71ddc621 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandler.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandler.java @@ -13,6 +13,7 @@ package org.eclipse.sirius.components.collaborative.formdescriptioneditors.handlers; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.sirius.components.collaborative.api.ChangeDescription; import org.eclipse.sirius.components.collaborative.api.ChangeKind; @@ -27,8 +28,8 @@ import org.eclipse.sirius.components.core.api.IObjectService; import org.eclipse.sirius.components.core.api.IPayload; import org.eclipse.sirius.components.core.api.SuccessPayload; -import org.eclipse.sirius.components.view.FormDescription; import org.eclipse.sirius.components.view.GroupDescription; +import org.eclipse.sirius.components.view.PageDescription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -58,11 +59,9 @@ public MoveGroupEventHandler(IObjectService objectService, ICollaborativeFormDes this.objectService = Objects.requireNonNull(objectService); this.messageService = Objects.requireNonNull(messageService); - // @formatter:off this.counter = Counter.builder(Monitoring.EVENT_HANDLER) .tag(Monitoring.NAME, this.getClass().getSimpleName()) .register(meterRegistry); - // @formatter:on } @Override @@ -79,10 +78,8 @@ public void handle(One payloadSink, Many changeDesc IPayload payload = new ErrorPayload(formDescriptionEditorInput.id(), message); ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); - if (formDescriptionEditorInput instanceof MoveGroupInput) { - String groupId = ((MoveGroupInput) formDescriptionEditorInput).groupId(); - int index = ((MoveGroupInput) formDescriptionEditorInput).index(); - boolean moveGroup = this.moveGroup(editingContext, formDescriptionEditorContext, groupId, index); + if (formDescriptionEditorInput instanceof MoveGroupInput moveGroupInput) { + boolean moveGroup = this.moveGroup(editingContext, moveGroupInput.pageId(), moveGroupInput.groupId(), moveGroupInput.index()); if (moveGroup) { payload = new SuccessPayload(formDescriptionEditorInput.id()); changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); @@ -93,28 +90,26 @@ public void handle(One payloadSink, Many changeDesc changeDescriptionSink.tryEmitNext(changeDescription); } - private boolean moveGroup(IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, String groupId, int index) { - boolean success = false; - var optionalSelf = this.objectService.getObject(editingContext, formDescriptionEditorContext.getFormDescriptionEditor().getTargetObjectId()); - if (optionalSelf.isPresent()) { - Object container = optionalSelf.get(); - if (container instanceof FormDescription) { - var objectToMove = this.objectService.getObject(editingContext, groupId); - if (objectToMove.filter(GroupDescription.class::isInstance).isPresent()) { - GroupDescription groupToMove = (GroupDescription) objectToMove.get(); - try { - if (container.equals(groupToMove.eContainer())) { - ((FormDescription) container).getGroups().move(index, groupToMove); - } else { - ((FormDescription) container).getGroups().add(index, groupToMove); - } - success = true; - } catch (IndexOutOfBoundsException exception) { - this.logger.warn(exception.getMessage(), exception); - } - } - } - } - return success; + private boolean moveGroup(IEditingContext editingContext, String pageId, String groupId, int index) { + AtomicBoolean success = new AtomicBoolean(false); + this.objectService.getObject(editingContext, pageId) + .filter(PageDescription.class::isInstance) + .map(PageDescription.class::cast) + .ifPresent(pageDescription -> this.objectService.getObject(editingContext, groupId) + .filter(GroupDescription.class::isInstance) + .map(GroupDescription.class::cast) + .ifPresent(groupDescription -> { + try { + if (pageDescription.equals(groupDescription.eContainer())) { + pageDescription.getGroups().move(index, groupDescription); + } else { + pageDescription.getGroups().add(index, groupDescription); + } + success.set(true); + } catch (IndexOutOfBoundsException exception) { + this.logger.warn(exception.getMessage(), exception); + } + })); + return success.get(); } } diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandler.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandler.java new file mode 100644 index 0000000000..e1ca04a534 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandler.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 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.formdescriptioneditors.handlers; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +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.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorEventHandler; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.MovePageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.ErrorPayload; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.PageDescription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import reactor.core.publisher.Sinks.Many; +import reactor.core.publisher.Sinks.One; + +/** + * Handle the move page event on Form Description Editor. + * + * @author frouene + */ +@Service +public class MovePageEventHandler implements IFormDescriptionEditorEventHandler { + + private final Logger logger = LoggerFactory.getLogger(MovePageEventHandler.class); + + private final IObjectService objectService; + + private final ICollaborativeFormDescriptionEditorMessageService messageService; + + private final Counter counter; + + public MovePageEventHandler(IObjectService objectService, ICollaborativeFormDescriptionEditorMessageService messageService, MeterRegistry meterRegistry) { + this.objectService = Objects.requireNonNull(objectService); + this.messageService = Objects.requireNonNull(messageService); + + this.counter = Counter.builder(Monitoring.EVENT_HANDLER) + .tag(Monitoring.NAME, this.getClass().getSimpleName()) + .register(meterRegistry); + } + + @Override + public boolean canHandle(IFormDescriptionEditorInput formDescriptionEditorInput) { + return formDescriptionEditorInput instanceof MovePageInput; + } + + @Override + public void handle(One payloadSink, Many changeDescriptionSink, IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, + IFormDescriptionEditorInput formDescriptionEditorInput) { + this.counter.increment(); + + String message = this.messageService.invalidInput(formDescriptionEditorInput.getClass().getSimpleName(), MovePageInput.class.getSimpleName()); + IPayload payload = new ErrorPayload(formDescriptionEditorInput.id(), message); + ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); + + if (formDescriptionEditorInput instanceof MovePageInput movePageInput) { + boolean movePage = this.movePage(editingContext, formDescriptionEditorContext, movePageInput.pageId(), movePageInput.index()); + if (movePage) { + payload = new SuccessPayload(formDescriptionEditorInput.id()); + changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, formDescriptionEditorInput.representationId(), formDescriptionEditorInput); + } + } + + payloadSink.tryEmitValue(payload); + changeDescriptionSink.tryEmitNext(changeDescription); + } + + + private boolean movePage(IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, String pageId, int index) { + AtomicBoolean success = new AtomicBoolean(false); + this.objectService.getObject(editingContext, formDescriptionEditorContext.getFormDescriptionEditor().getTargetObjectId()) + .filter(FormDescription.class::isInstance) + .map(FormDescription.class::cast) + .ifPresent(formDescription -> this.objectService.getObject(editingContext, pageId) + .filter(PageDescription.class::isInstance) + .map(PageDescription.class::cast) + .ifPresent(pageDescription -> { + try { + formDescription.getPages().move(index, pageDescription); + success.set(true); + } catch (IndexOutOfBoundsException exception) { + this.logger.warn(exception.getMessage(), exception); + } + })); + return success.get(); + } + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandler.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandler.java index 0037f42a45..29100fcf2c 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandler.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandler.java @@ -81,9 +81,10 @@ public void handle(One payloadSink, Many changeDesc String newLabel = renameRepresentationInput.newLabel(); FormDescriptionEditor renamedFormDescriptionEditor = FormDescriptionEditor.newFormDescriptionEditor(formDescriptionEditorContext.getFormDescriptionEditor()) - .label(newLabel) - .groups(List.of()) // We don't store form description editor groups, it will be re-render by the FormDescriptionEditorProcessor. - .build(); + .label(newLabel) + .pages(List.of()) // We don't store form description editor pages, it will be re-render by + // the FormDescriptionEditorProcessor. + .build(); this.representationPersistenceService.save(editingContext, renamedFormDescriptionEditor); payload = new RenameRepresentationSuccessPayload(formDescriptionEditorInput.id(), renamedFormDescriptionEditor); diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/resources/schema/formdescriptioneditor.graphqls b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/resources/schema/formdescriptioneditor.graphqls index 44abe99dfe..c8fc1f8c3f 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/resources/schema/formdescriptioneditor.graphqls +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/main/resources/schema/formdescriptioneditor.graphqls @@ -18,7 +18,7 @@ type FormDescriptionEditorRefreshedEventPayload { type FormDescriptionEditor implements Representation { id: ID! metadata: RepresentationMetadata! - groups: [Group!]! + pages: [Page!]! } type FormDescriptionEditorDescription implements RepresentationDescription { @@ -36,12 +36,16 @@ extend type Mutation { addToolbarAction(input: AddToolbarActionInput!): AddToolbarActionPayload! deleteToolbarAction(input: DeleteToolbarActionInput!): DeleteToolbarActionPayload! moveToolbarAction(input: MoveToolbarActionInput!): MoveToolbarActionPayload! + addPage(input: AddPageInput!): AddPagePayload! + movePage(input: MovePageInput!): MovePagePayload! + deletePage(input: DeletePageInput!): DeletePagePayload! } input AddGroupInput { id: ID! editingContextId: ID! representationId: ID! + pageId: ID! index: Int! } @@ -60,6 +64,7 @@ input MoveGroupInput { id: ID! editingContextId: ID! representationId: ID! + pageId: String! groupId: String! index: Int! } @@ -125,3 +130,31 @@ input MoveToolbarActionInput { } union MoveToolbarActionPayload = SuccessPayload | ErrorPayload + +input AddPageInput { + id: ID! + editingContextId: ID! + representationId: ID! + index: Int! +} + +union AddPagePayload = SuccessPayload | ErrorPayload + +input MovePageInput { + id: ID! + editingContextId: ID! + representationId: ID! + pageId: String! + index: Int! +} + +union MovePagePayload = SuccessPayload | ErrorPayload + +input DeletePageInput { + id: ID! + editingContextId: ID! + representationId: ID! + pageId: String! +} + +union DeletePagePayload = SuccessPayload | ErrorPayload diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorEventProcessorTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorEventProcessorTests.java index 51fc12ca00..c943778b39 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorEventProcessorTests.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/FormDescriptionEditorEventProcessorTests.java @@ -44,14 +44,12 @@ public class FormDescriptionEditorEventProcessorTests { private static final String FORMDESCRIPTIONEDITOR_DESCRIPTION_ID = UUID.randomUUID().toString(); - // @formatter:off private static final FormDescriptionEditor INITIAL_TEST_FORMDESCRIPTIONEDITOR = FormDescriptionEditor.newFormDescriptionEditor(FORMDESCRIPTIONEDITOR_ID) .descriptionId(FORMDESCRIPTIONEDITOR_DESCRIPTION_ID) .label(String.valueOf(0)) .targetObjectId("targetObjectId") - .groups(List.of()) + .pages(List.of()) .build(); - // @formatter:on private final IFormDescriptionEditorCreationService formDescriptionEditorCreationService = new MockFormDescriptionEditorCreationService(INITIAL_TEST_FORMDESCRIPTIONEDITOR); diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/TestFormDescriptionEditorBuilder.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/TestFormDescriptionEditorBuilder.java index b5370ad2ec..231ffd7f44 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/TestFormDescriptionEditorBuilder.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/TestFormDescriptionEditorBuilder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -17,6 +17,7 @@ import org.eclipse.sirius.components.formdescriptioneditors.FormDescriptionEditor; import org.eclipse.sirius.components.forms.Group; +import org.eclipse.sirius.components.forms.Page; /** * Utility class used to help build form description editors for unit tests. @@ -25,26 +26,24 @@ */ public class TestFormDescriptionEditorBuilder { - public static final String IMAGE_PNG = "/image.png"; - - public static final String TOOL_IMAGE_URL = IMAGE_PNG; - - public static final String TOOL_LABEL = "toolLabel"; - public FormDescriptionEditor getFormDescriptionEditor(String id) { - // @formatter:off Group group = Group.newGroup(UUID.randomUUID().toString()) - .label("group1") - .widgets(List.of()) - .toolbarActions(List.of()) - .build(); + .label("group1") + .widgets(List.of()) + .toolbarActions(List.of()) + .build(); + + Page page = Page.newPage(UUID.randomUUID().toString()) + .label("page1") + .groups(List.of(group)) + .toolbarActions(List.of()) + .build(); return FormDescriptionEditor.newFormDescriptionEditor(id) .label("formDescriptionEditorLabel") .descriptionId(UUID.randomUUID().toString()) .targetObjectId("formDescriptionEditorTargetObjectId") - .groups(List.of(group)) + .pages(List.of(page)) .build(); - // @formatter:on } } diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandlerTests.java new file mode 100644 index 0000000000..997656179e --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddGroupEventHandlerTests.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.handlers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.api.ChangeDescription; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.FormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.TestFormDescriptionEditorBuilder; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.AddGroupInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.PageDescription; +import org.eclipse.sirius.components.view.ViewFactory; +import org.junit.jupiter.api.Test; + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import reactor.core.publisher.Sinks; + +/** + * Tests of the add group event handler. + * + * @author frouene + */ +public class AddGroupEventHandlerTests { + + @Test + public void testAddGroupAction() { + + FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription = ViewFactory.eINSTANCE.createPageDescription(); + formDescription.getPages().add(pageDescription); + + var objectService = new IObjectService.NoOp() { + @Override + public Optional getObject(IEditingContext editingContext, String objectId) { + return Optional.of(pageDescription); + } + }; + var handler = new AddGroupEventHandler(objectService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry()); + var input = new AddGroupInput(UUID.randomUUID(), "editingContextId", "representationId", "pageId", 0); + + assertThat(handler.canHandle(input)).isTrue(); + + Sinks.One payloadSink = Sinks.one(); + Sinks.Many changeDescriptionSink = Sinks.many().unicast().onBackpressureBuffer(); + IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID() + .toString())); + + handler.handle(payloadSink, changeDescriptionSink, new IEditingContext.NoOp(), formDescriptionEditorContext, input); + + ChangeDescription changeDescription = changeDescriptionSink.asFlux().blockFirst(); + assert changeDescription != null; + assertThat(changeDescription.getKind()).isEqualTo(ChangeKind.SEMANTIC_CHANGE); + + IPayload payload = payloadSink.asMono().block(); + assertThat(payload).isInstanceOf(SuccessPayload.class); + assertThat(pageDescription.getGroups()).hasSize(1); + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandlerTests.java new file mode 100644 index 0000000000..212805607a --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddPageEventHandlerTests.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.handlers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.api.ChangeDescription; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.FormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.TestFormDescriptionEditorBuilder; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.AddPageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.PageDescription; +import org.eclipse.sirius.components.view.ViewFactory; +import org.junit.jupiter.api.Test; + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import reactor.core.publisher.Sinks; + +/** + * Tests of the add page event handler. + * + * @author frouene + */ +public class AddPageEventHandlerTests { + + @Test + public void testAddGroupAction() { + + FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription = ViewFactory.eINSTANCE.createPageDescription(); + formDescription.getPages().add(pageDescription); + + var objectService = new IObjectService.NoOp() { + @Override + public Optional getObject(IEditingContext editingContext, String objectId) { + return Optional.of(formDescription); + } + }; + var handler = new AddPageEventHandler(objectService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry()); + var input = new AddPageInput(UUID.randomUUID(), "editingContextId", "representationId", 0); + + assertThat(handler.canHandle(input)).isTrue(); + + Sinks.One payloadSink = Sinks.one(); + Sinks.Many changeDescriptionSink = Sinks.many().unicast().onBackpressureBuffer(); + IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID() + .toString())); + + handler.handle(payloadSink, changeDescriptionSink, new IEditingContext.NoOp(), formDescriptionEditorContext, input); + + ChangeDescription changeDescription = changeDescriptionSink.asFlux().blockFirst(); + assert changeDescription != null; + assertThat(changeDescription.getKind()).isEqualTo(ChangeKind.SEMANTIC_CHANGE); + + IPayload payload = payloadSink.asMono().block(); + assertThat(payload).isInstanceOf(SuccessPayload.class); + assertThat(formDescription.getPages()).hasSize(2); + // The new page must have an empty group initialized + assertThat(formDescription.getPages().get(0).getGroups()).hasSize(1); + } + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddToolbarActionEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddToolbarActionEventHandlerTests.java index 1b116ea517..2aa9c010c6 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddToolbarActionEventHandlerTests.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/AddToolbarActionEventHandlerTests.java @@ -30,6 +30,7 @@ import org.eclipse.sirius.components.core.api.SuccessPayload; import org.eclipse.sirius.components.view.FormDescription; import org.eclipse.sirius.components.view.GroupDescription; +import org.eclipse.sirius.components.view.PageDescription; import org.eclipse.sirius.components.view.ViewFactory; import org.junit.jupiter.api.Test; @@ -44,11 +45,14 @@ * @author arichard */ public class AddToolbarActionEventHandlerTests { + @Test public void testAddToolbarAction() { FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription = ViewFactory.eINSTANCE.createPageDescription(); GroupDescription groupDescription = ViewFactory.eINSTANCE.createGroupDescription(); - formDescription.getGroups().add(groupDescription); + pageDescription.getGroups().add(groupDescription); + formDescription.getPages().add(pageDescription); var objectService = new IObjectService.NoOp() { @Override public Optional getObject(IEditingContext editingContext, String objectId) { @@ -62,7 +66,8 @@ public Optional getObject(IEditingContext editingContext, String objectI One payloadSink = Sinks.one(); Many changeDescriptionSink = Sinks.many().unicast().onBackpressureBuffer(); - IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID().toString())); + IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID() + .toString())); handler.handle(payloadSink, changeDescriptionSink, new IEditingContext.NoOp(), formDescriptionEditorContext, input); diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandlerTests.java new file mode 100644 index 0000000000..7d7e598078 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeletePageEventHandlerTests.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.handlers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.sirius.components.collaborative.api.ChangeDescription; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.FormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.TestFormDescriptionEditorBuilder; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.DeletePageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.IEditService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.formdescriptioneditors.FormDescriptionEditor; +import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.PageDescription; +import org.eclipse.sirius.components.view.ViewFactory; +import org.junit.jupiter.api.Test; + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import reactor.core.publisher.Sinks; + +/** + * Tests of the delete page event handler. + * + * @author frouene + */ +public class DeletePageEventHandlerTests { + + private static final String PAGE_ID = "pageId"; + + @Test + public void testDeletePage() { + + FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription = ViewFactory.eINSTANCE.createPageDescription(); + formDescription.getPages().add(pageDescription); + + FormDescriptionEditor formDescriptionEditor = new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID().toString()); + + var objectService = new IObjectService.NoOp() { + @Override + public Optional getObject(IEditingContext editingContext, String objectId) { + Optional result = Optional.empty(); + if (PAGE_ID.equals(objectId)) { + result = Optional.of(pageDescription); + } + return result; + } + }; + AtomicBoolean pageDeleted = new AtomicBoolean(false); + IEditService.NoOp editService = new IEditService.NoOp() { + @Override + public void delete(Object object) { + if (object == pageDescription) { + pageDeleted.set(true); + } + } + }; + + var handler = new DeletePageEventHandler(objectService, editService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry()); + var input = new DeletePageInput(UUID.randomUUID(), "editingContextId", "representationId", PAGE_ID); + + assertThat(handler.canHandle(input)).isTrue(); + + Sinks.One payloadSink = Sinks.one(); + Sinks.Many changeDescriptionSink = Sinks.many().unicast().onBackpressureBuffer(); + IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(formDescriptionEditor); + + handler.handle(payloadSink, changeDescriptionSink, new IEditingContext.NoOp(), formDescriptionEditorContext, input); + + ChangeDescription changeDescription = changeDescriptionSink.asFlux().blockFirst(); + assertThat(changeDescription.getKind()).isEqualTo(ChangeKind.SEMANTIC_CHANGE); + + IPayload payload = payloadSink.asMono().block(); + assertThat(payload).isInstanceOf(SuccessPayload.class); + assertThat(pageDeleted).isTrue(); + + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeleteToolbarActionEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeleteToolbarActionEventHandlerTests.java index f335568d4b..187f9dbf60 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeleteToolbarActionEventHandlerTests.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/DeleteToolbarActionEventHandlerTests.java @@ -34,6 +34,7 @@ import org.eclipse.sirius.components.view.ButtonDescription; import org.eclipse.sirius.components.view.FormDescription; import org.eclipse.sirius.components.view.GroupDescription; +import org.eclipse.sirius.components.view.PageDescription; import org.eclipse.sirius.components.view.ViewFactory; import org.junit.jupiter.api.Test; @@ -48,6 +49,7 @@ * @author arichard */ public class DeleteToolbarActionEventHandlerTests { + private static final String TOOLBAR_ACTION_ID = "toolbarActionId"; @Test @@ -55,8 +57,10 @@ public void testDeleteToolbarAction() { FormDescriptionEditor formDescriptionEditor = new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID().toString()); FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription = ViewFactory.eINSTANCE.createPageDescription(); GroupDescription groupDescription = ViewFactory.eINSTANCE.createGroupDescription(); - formDescription.getGroups().add(groupDescription); + pageDescription.getGroups().add(groupDescription); + formDescription.getPages().add(pageDescription); ButtonDescription toolbarButton = ViewFactory.eINSTANCE.createButtonDescription(); groupDescription.getToolbarActions().add(toolbarButton); var objectService = new IObjectService.NoOp() { diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandlerTests.java new file mode 100644 index 0000000000..a1e84076d3 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveGroupEventHandlerTests.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.handlers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.api.ChangeDescription; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.FormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.TestFormDescriptionEditorBuilder; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.MoveGroupInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.formdescriptioneditors.FormDescriptionEditor; +import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.GroupDescription; +import org.eclipse.sirius.components.view.PageDescription; +import org.eclipse.sirius.components.view.ViewFactory; +import org.junit.jupiter.api.Test; + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import reactor.core.publisher.Sinks; + +/** + * Tests of the move group event handler. + * + * @author frouene + */ +public class MoveGroupEventHandlerTests { + + @Test + public void testMoveGroupAction() { + + FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription = ViewFactory.eINSTANCE.createPageDescription(); + formDescription.getPages().add(pageDescription); + + GroupDescription groupDescription1 = ViewFactory.eINSTANCE.createGroupDescription(); + pageDescription.getGroups().add(groupDescription1); + GroupDescription groupDescription2 = ViewFactory.eINSTANCE.createGroupDescription(); + pageDescription.getGroups().add(groupDescription2); + GroupDescription groupDescription3 = ViewFactory.eINSTANCE.createGroupDescription(); + pageDescription.getGroups().add(groupDescription3); + + FormDescriptionEditor formDescriptionEditor = new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID().toString()); + + var objectService = new IObjectService.NoOp() { + @Override + public Optional getObject(IEditingContext editingContext, String objectId) { + Optional result = Optional.empty(); + if ("group1".equals(objectId)) { + result = Optional.of(groupDescription1); + } else if ("group2".equals(objectId)) { + result = Optional.of(groupDescription2); + } else if ("group3".equals(objectId)) { + result = Optional.of(groupDescription3); + } else if (formDescriptionEditor.getPages().get(0).getId().equals(objectId)) { + result = Optional.of(pageDescription); + } + return result; + } + }; + + this.invokMove(formDescriptionEditor, objectService, "group2", 0); + assertThat(pageDescription.getGroups()).isEqualTo(List.of(groupDescription2, groupDescription1, groupDescription3)); + this.invokMove(formDescriptionEditor, objectService, "group1", 2); + assertThat(pageDescription.getGroups()).isEqualTo(List.of(groupDescription2, groupDescription3, groupDescription1)); + + } + + private void invokMove(FormDescriptionEditor formDescriptionEditor, IObjectService.NoOp objectService, String groupId, int index) { + var handler = new MoveGroupEventHandler(objectService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry()); + var input = new MoveGroupInput(UUID.randomUUID(), "editingContextId", formDescriptionEditor.getId(), formDescriptionEditor.getPages().get(0).getId(), groupId, index); + + assertThat(handler.canHandle(input)).isTrue(); + + Sinks.One payloadSink = Sinks.one(); + Sinks.Many changeDescriptionSink = Sinks.many().unicast().onBackpressureBuffer(); + IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID() + .toString())); + + handler.handle(payloadSink, changeDescriptionSink, new IEditingContext.NoOp(), formDescriptionEditorContext, input); + + ChangeDescription changeDescription = changeDescriptionSink.asFlux().blockFirst(); + assertThat(changeDescription.getKind()).isEqualTo(ChangeKind.SEMANTIC_CHANGE); + + IPayload payload = payloadSink.asMono().block(); + assertThat(payload).isInstanceOf(SuccessPayload.class); + } + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandlerTests.java new file mode 100644 index 0000000000..3bdbac0898 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MovePageEventHandlerTests.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2023 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.formdescriptioneditors.handlers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.eclipse.sirius.components.collaborative.api.ChangeDescription; +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.FormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.TestFormDescriptionEditorBuilder; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorContext; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.MovePageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.messages.ICollaborativeFormDescriptionEditorMessageService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectService; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.core.api.SuccessPayload; +import org.eclipse.sirius.components.formdescriptioneditors.FormDescriptionEditor; +import org.eclipse.sirius.components.view.FormDescription; +import org.eclipse.sirius.components.view.PageDescription; +import org.eclipse.sirius.components.view.ViewFactory; +import org.junit.jupiter.api.Test; + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import reactor.core.publisher.Sinks; + +/** + * Tests of the move page event handler. + * + * @author frouene + */ +public class MovePageEventHandlerTests { + + @Test + public void testMovePageAction() { + + FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription1 = ViewFactory.eINSTANCE.createPageDescription(); + formDescription.getPages().add(pageDescription1); + PageDescription pageDescription2 = ViewFactory.eINSTANCE.createPageDescription(); + formDescription.getPages().add(pageDescription2); + PageDescription pageDescription3 = ViewFactory.eINSTANCE.createPageDescription(); + formDescription.getPages().add(pageDescription3); + + + FormDescriptionEditor formDescriptionEditor = new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID().toString()); + + var objectService = new IObjectService.NoOp() { + @Override + public Optional getObject(IEditingContext editingContext, String objectId) { + Optional result = Optional.empty(); + if (formDescriptionEditor.getTargetObjectId().equals(objectId)) { + result = Optional.of(formDescription); + } else if ("page1".equals(objectId)) { + result = Optional.of(pageDescription1); + } else if ("page2".equals(objectId)) { + result = Optional.of(pageDescription2); + } else if ("page3".equals(objectId)) { + result = Optional.of(pageDescription3); + } + return result; + } + }; + + this.invokMove(formDescriptionEditor, objectService, "page2", 0); + assertThat(formDescription.getPages()).isEqualTo(List.of(pageDescription2, pageDescription1, pageDescription3)); + this.invokMove(formDescriptionEditor, objectService, "page1", 2); + assertThat(formDescription.getPages()).isEqualTo(List.of(pageDescription2, pageDescription3, pageDescription1)); + + } + + private void invokMove(FormDescriptionEditor formDescriptionEditor, IObjectService.NoOp objectService, String pageId, int index) { + var handler = new MovePageEventHandler(objectService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry()); + var input = new MovePageInput(UUID.randomUUID(), "editingContextId", formDescriptionEditor.getId(), pageId, index); + + assertThat(handler.canHandle(input)).isTrue(); + + Sinks.One payloadSink = Sinks.one(); + Sinks.Many changeDescriptionSink = Sinks.many().unicast().onBackpressureBuffer(); + IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID() + .toString())); + + handler.handle(payloadSink, changeDescriptionSink, new IEditingContext.NoOp(), formDescriptionEditorContext, input); + + ChangeDescription changeDescription = changeDescriptionSink.asFlux().blockFirst(); + assertThat(changeDescription.getKind()).isEqualTo(ChangeKind.SEMANTIC_CHANGE); + + IPayload payload = payloadSink.asMono().block(); + assertThat(payload).isInstanceOf(SuccessPayload.class); + } + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveToolbarActionEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveToolbarActionEventHandlerTests.java index d7ba701499..0a9e254e55 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveToolbarActionEventHandlerTests.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/MoveToolbarActionEventHandlerTests.java @@ -34,6 +34,7 @@ import org.eclipse.sirius.components.view.ButtonDescription; import org.eclipse.sirius.components.view.FormDescription; import org.eclipse.sirius.components.view.GroupDescription; +import org.eclipse.sirius.components.view.PageDescription; import org.eclipse.sirius.components.view.ViewFactory; import org.junit.jupiter.api.Test; @@ -48,14 +49,17 @@ * @author arichard */ public class MoveToolbarActionEventHandlerTests { + @Test public void testMoveToolbarAction() { FormDescriptionEditor formDescriptionEditor = new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID().toString()); FormDescription formDescription = ViewFactory.eINSTANCE.createFormDescription(); + PageDescription pageDescription = ViewFactory.eINSTANCE.createPageDescription(); GroupDescription groupDescription = ViewFactory.eINSTANCE.createGroupDescription(); - formDescription.getGroups().add(groupDescription); + pageDescription.getGroups().add(groupDescription); + formDescription.getPages().add(pageDescription); ButtonDescription toolbarButton1 = ViewFactory.eINSTANCE.createButtonDescription(); ButtonDescription toolbarButton2 = ViewFactory.eINSTANCE.createButtonDescription(); ButtonDescription toolbarButton3 = ViewFactory.eINSTANCE.createButtonDescription(); @@ -75,7 +79,7 @@ public Optional getObject(IEditingContext editingContext, String objectI result = Optional.of(toolbarButton2); } else if ("button3".equals(objectId)) { result = Optional.of(toolbarButton3); - } else if (formDescriptionEditor.getGroups().get(0).getId().equals(objectId)) { + } else if (formDescriptionEditor.getPages().get(0).getGroups().get(0).getId().equals(objectId)) { result = Optional.of(groupDescription); } return result; @@ -90,13 +94,15 @@ public Optional getObject(IEditingContext editingContext, String objectI private void invokMove(FormDescriptionEditor formDescriptionEditor, NoOp objectService, String toolbarActionId, int index) { var handler = new MoveToolbarActionEventHandler(objectService, new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry()); - var input = new MoveToolbarActionInput(UUID.randomUUID(), "editingContextId", formDescriptionEditor.getId(), formDescriptionEditor.getGroups().get(0).getId(), toolbarActionId, index); + var input = new MoveToolbarActionInput(UUID.randomUUID(), "editingContextId", formDescriptionEditor.getId(), formDescriptionEditor.getPages().get(0).getGroups().get(0) + .getId(), toolbarActionId, index); assertThat(handler.canHandle(input)).isTrue(); One payloadSink = Sinks.one(); Many changeDescriptionSink = Sinks.many().unicast().onBackpressureBuffer(); - IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID().toString())); + IFormDescriptionEditorContext formDescriptionEditorContext = new FormDescriptionEditorContext(new TestFormDescriptionEditorBuilder().getFormDescriptionEditor(UUID.randomUUID() + .toString())); handler.handle(payloadSink, changeDescriptionSink, new IEditingContext.NoOp(), formDescriptionEditorContext, input); diff --git a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandlerTests.java b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandlerTests.java index 235dfacd66..098521d04c 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandlerTests.java +++ b/packages/formdescriptioneditors/backend/sirius-components-collaborative-formdescriptioneditors/src/test/java/org/eclipse/sirius/components/collaborative/formdescriptioneditors/handlers/RenameFormDescriptionEditorEventHandlerTests.java @@ -40,6 +40,7 @@ * @author arichard */ public class RenameFormDescriptionEditorEventHandlerTests { + private static final String OLD_LABEL = "oldLabel"; private static final String NEW_LABEL = "newLabel"; @@ -51,14 +52,12 @@ public void testRenameRepresentation() { String representationId = UUID.randomUUID().toString(); UUID targetObjectId = UUID.randomUUID(); - // @formatter:off FormDescriptionEditor formDescriptionEditor = FormDescriptionEditor.newFormDescriptionEditor(representationId) .label(OLD_LABEL) .descriptionId(formDescriptionEditorDescriptionId) .targetObjectId(targetObjectId.toString()) - .groups(List.of()) + .pages(List.of()) .build(); - // @formatter:on RenameFormDescriptionEditorEventHandler handler = new RenameFormDescriptionEditorEventHandler(new IRepresentationPersistenceService.NoOp(), new ICollaborativeFormDescriptionEditorMessageService.NoOp(), new SimpleMeterRegistry()); diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationAddPageDataFetcher.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationAddPageDataFetcher.java new file mode 100644 index 0000000000..555f5cce21 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationAddPageDataFetcher.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 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.formdescriptioneditors.graphql.datafetchers.mutation; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.sirius.components.annotations.spring.graphql.MutationDataFetcher; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.AddPageInput; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates; +import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher; +import org.eclipse.sirius.components.graphql.api.IExceptionWrapper; + +import graphql.schema.DataFetchingEnvironment; + +/** + * The data fetcher used to add a page from a Form Description Editor. + * + * @author frouene + */ +@MutationDataFetcher(type = "Mutation", field = "addPage") +public class MutationAddPageDataFetcher implements IDataFetcherWithFieldCoordinates> { + + private static final String INPUT_ARGUMENT = "input"; + + private final ObjectMapper objectMapper; + + private final IExceptionWrapper exceptionWrapper; + + private final IEditingContextDispatcher editingContextDispatcher; + + public MutationAddPageDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) { + this.objectMapper = Objects.requireNonNull(objectMapper); + this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper); + this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher); + } + + @Override + public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { + Object argument = environment.getArgument(INPUT_ARGUMENT); + var input = this.objectMapper.convertValue(argument, AddPageInput.class); + + return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input), input).toFuture(); + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationDeletePageDataFetcher.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationDeletePageDataFetcher.java new file mode 100644 index 0000000000..1977a20c19 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationDeletePageDataFetcher.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 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.formdescriptioneditors.graphql.datafetchers.mutation; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.sirius.components.annotations.spring.graphql.MutationDataFetcher; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.DeletePageInput; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates; +import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher; +import org.eclipse.sirius.components.graphql.api.IExceptionWrapper; + +import graphql.schema.DataFetchingEnvironment; + +/** + * The data fetcher used to delete a page from a Form Description Editor. + * + * @author frouene + */ +@MutationDataFetcher(type = "Mutation", field = "deletePage") +public class MutationDeletePageDataFetcher implements IDataFetcherWithFieldCoordinates> { + + private static final String INPUT_ARGUMENT = "input"; + + private final ObjectMapper objectMapper; + + private final IExceptionWrapper exceptionWrapper; + + private final IEditingContextDispatcher editingContextDispatcher; + + public MutationDeletePageDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) { + this.objectMapper = Objects.requireNonNull(objectMapper); + this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper); + this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher); + } + + @Override + public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { + Object argument = environment.getArgument(INPUT_ARGUMENT); + var input = this.objectMapper.convertValue(argument, DeletePageInput.class); + + return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input), input).toFuture(); + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationMovePageDataFetcher.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationMovePageDataFetcher.java new file mode 100644 index 0000000000..92afc383a1 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors-graphql/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/graphql/datafetchers/mutation/MutationMovePageDataFetcher.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2023, 2023 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.formdescriptioneditors.graphql.datafetchers.mutation; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.sirius.components.annotations.spring.graphql.MutationDataFetcher; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.MovePageInput; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates; +import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher; +import org.eclipse.sirius.components.graphql.api.IExceptionWrapper; + +import graphql.schema.DataFetchingEnvironment; + +/** + * The data fetcher used to move a page from a Form Description Editor. + * + * @author frouene + */ +@MutationDataFetcher(type = "Mutation", field = "movePage") +public class MutationMovePageDataFetcher implements IDataFetcherWithFieldCoordinates> { + + private static final String INPUT_ARGUMENT = "input"; + + private final ObjectMapper objectMapper; + + private final IExceptionWrapper exceptionWrapper; + + private final IEditingContextDispatcher editingContextDispatcher; + + public MutationMovePageDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) { + this.objectMapper = Objects.requireNonNull(objectMapper); + this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper); + this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher); + } + + @Override + public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { + Object argument = environment.getArgument(INPUT_ARGUMENT); + var input = this.objectMapper.convertValue(argument, MovePageInput.class); + + return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input), input).toFuture(); + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/FormDescriptionEditor.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/FormDescriptionEditor.java index ea018260d6..1e0aee8365 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/FormDescriptionEditor.java +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/FormDescriptionEditor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -17,7 +17,7 @@ import java.util.Objects; import org.eclipse.sirius.components.annotations.Immutable; -import org.eclipse.sirius.components.forms.Group; +import org.eclipse.sirius.components.forms.Page; import org.eclipse.sirius.components.representations.IRepresentation; import org.eclipse.sirius.components.representations.ISemanticRepresentation; @@ -43,7 +43,7 @@ public final class FormDescriptionEditor implements IRepresentation, ISemanticRe private String descriptionId; - private List groups; + private List pages; private FormDescriptionEditor() { // Prevent instantiation @@ -74,8 +74,8 @@ public String getDescriptionId() { return this.descriptionId; } - public List getGroups() { - return this.groups; + public List getPages() { + return this.pages; } public static Builder newFormDescriptionEditor(String id) { @@ -99,6 +99,7 @@ public String toString() { */ @SuppressWarnings("checkstyle:HiddenField") public static final class Builder { + private String id; private String kind = KIND; @@ -109,7 +110,7 @@ public static final class Builder { private String descriptionId; - private List groups; + private List pages; private Builder(String id) { this.id = Objects.requireNonNull(id); @@ -120,7 +121,7 @@ public Builder(FormDescriptionEditor formDescriptionEditor) { this.label = formDescriptionEditor.label; this.targetObjectId = formDescriptionEditor.targetObjectId; this.descriptionId = formDescriptionEditor.descriptionId; - this.groups = formDescriptionEditor.groups; + this.pages = formDescriptionEditor.pages; } public Builder label(String label) { @@ -138,8 +139,8 @@ public Builder descriptionId(String descriptionId) { return this; } - public Builder groups(List groups) { - this.groups = Objects.requireNonNull(groups); + public Builder pages(List pages) { + this.pages = Objects.requireNonNull(pages); return this; } @@ -150,7 +151,7 @@ public FormDescriptionEditor build() { formDescriptionEditor.label = Objects.requireNonNull(this.label); formDescriptionEditor.targetObjectId = Objects.requireNonNull(this.targetObjectId); formDescriptionEditor.descriptionId = Objects.requireNonNull(this.descriptionId); - formDescriptionEditor.groups = Objects.requireNonNull(this.groups); + formDescriptionEditor.pages = Objects.requireNonNull(this.pages); return formDescriptionEditor; } } diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorComponent.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorComponent.java index 5d75d55e0b..7a9e40f03d 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorComponent.java +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorComponent.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -47,31 +47,28 @@ public Element render() { var optionalPreviousFormDescriptionEditor = this.props.getOptionalPreviousFormDescriptionEditor(); String id = optionalPreviousFormDescriptionEditor.map(FormDescriptionEditor::getId).orElseGet(() -> UUID.randomUUID().toString()); - // @formatter:off String label = optionalPreviousFormDescriptionEditor.map(FormDescriptionEditor::getLabel) .orElseGet(() -> variableManager.get(FormDescriptionEditor.LABEL, String.class) - .orElse("Form Description Editor")); - // @formatter:on + .orElse("Form Description Editor")); Function targetObjectIdProvider = formDescriptionEditorDescription.getTargetObjectIdProvider(); String targetObjectId = targetObjectIdProvider.apply(variableManager); List childrenWidgets = new ArrayList<>(); - formDescription.getGroups().forEach(viewGroupDescription -> { + formDescription.getPages().forEach(viewPageDescription -> { VariableManager childVariableManager = variableManager.createChild(); - childVariableManager.put(VariableManager.SELF, viewGroupDescription); - FormDescriptionEditorGroupComponentProps fdeGroupComponentProps = new FormDescriptionEditorGroupComponentProps(childVariableManager, this.props.getFormDescriptionEditorDescription()); - childrenWidgets.add(new Element(FormDescriptionEditorGroupComponent.class, fdeGroupComponentProps)); + childVariableManager.put(VariableManager.SELF, viewPageDescription); + FormDescriptionEditorPageComponentProps formDescriptionEditorPageComponentProps = new FormDescriptionEditorPageComponentProps(childVariableManager, + this.props.getFormDescriptionEditorDescription()); + childrenWidgets.add(new Element(FormDescriptionEditorPageComponent.class, formDescriptionEditorPageComponentProps)); }); - // @formatter:off FormDescriptionEditorElementProps formDescriptionEditorElementProps = FormDescriptionEditorElementProps.newFormDescriptionEditorElementProps(id) .label(label) .targetObjectId(targetObjectId) .descriptionId(formDescriptionEditorDescription.getId()) .children(childrenWidgets) .build(); - // @formatter:on return new Element(FormDescriptionEditorElementProps.TYPE, formDescriptionEditorElementProps); } diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorGroupComponent.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorGroupComponent.java index 0194258d40..73ce1f13d0 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorGroupComponent.java +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorGroupComponent.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -72,13 +72,11 @@ public Element render() { childrenWidgets.add(new Element(WidgetComponent.class, widgetComponentProps)); }); - // @formatter:off GroupElementProps groupElementProps = GroupElementProps.newGroupElementProps(id) .label(label) .displayMode(this.getGroupDisplayMode(groupDescription)) .children(childrenWidgets) .build(); - // @formatter:on return new Element(GroupElementProps.TYPE, groupElementProps); } diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponent.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponent.java new file mode 100644 index 0000000000..38391daaac --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponent.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2022, 2023 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.formdescriptioneditors.components; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.sirius.components.forms.components.ToolbarActionComponent; +import org.eclipse.sirius.components.forms.components.ToolbarActionComponentProps; +import org.eclipse.sirius.components.forms.description.AbstractWidgetDescription; +import org.eclipse.sirius.components.forms.description.ButtonDescription; +import org.eclipse.sirius.components.forms.elements.PageElementProps; +import org.eclipse.sirius.components.representations.Element; +import org.eclipse.sirius.components.representations.IComponent; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.view.PageDescription; + +/** + * The component used to render the form description editor page. + * + * @author arichard + */ +public class FormDescriptionEditorPageComponent implements IComponent { + + private static final String AQL_PREFIX = "aql:"; + + private final FormDescriptionEditorPageComponentProps props; + + private final ViewFormDescriptionEditorConverterSwitch converter; + + public FormDescriptionEditorPageComponent(FormDescriptionEditorPageComponentProps props) { + this.props = props; + this.converter = new ViewFormDescriptionEditorConverterSwitch(props.formDescriptionEditorDescription(), props.variableManager()); + } + + @Override + public Element render() { + VariableManager variableManager = this.props.variableManager(); + var pageDescription = variableManager.get(VariableManager.SELF, PageDescription.class).get(); + String id = this.props.formDescriptionEditorDescription().getTargetObjectIdProvider().apply(variableManager); + String label = this.getPageLabel(pageDescription, "Page"); + List childrenWidgets = new ArrayList<>(); + + pageDescription.getToolbarActions().forEach(viewToolbarActionDescription -> { + VariableManager childVariableManager = variableManager.createChild(); + childVariableManager.put(VariableManager.SELF, viewToolbarActionDescription); + AbstractWidgetDescription toolbarActionDescription = this.converter.doSwitch(viewToolbarActionDescription); + if (toolbarActionDescription instanceof ButtonDescription) { + ToolbarActionComponentProps toolbarActionComponentProps = new ToolbarActionComponentProps(childVariableManager, (ButtonDescription) toolbarActionDescription); + childrenWidgets.add(new Element(ToolbarActionComponent.class, toolbarActionComponentProps)); + } + }); + + pageDescription.getGroups().forEach(viewGroupDescription -> { + VariableManager childVariableManager = variableManager.createChild(); + childVariableManager.put(VariableManager.SELF, viewGroupDescription); + FormDescriptionEditorGroupComponentProps fdeGroupComponentProps = new FormDescriptionEditorGroupComponentProps(childVariableManager, this.props.formDescriptionEditorDescription()); + childrenWidgets.add(new Element(FormDescriptionEditorGroupComponent.class, fdeGroupComponentProps)); + }); + + PageElementProps pageElementProps = PageElementProps.newPageElementProps(id) + .label(label) + .children(childrenWidgets) + .build(); + + return new Element(PageElementProps.TYPE, pageElementProps); + } + + + public String getPageLabel(PageDescription pageDescription, String defaultLabel) { + String widgetLabel = defaultLabel; + String name = pageDescription.getName(); + String labelExpression = pageDescription.getLabelExpression(); + if (labelExpression != null && !labelExpression.isBlank() && !labelExpression.startsWith(AQL_PREFIX)) { + widgetLabel = labelExpression; + } else if (name != null && !name.isBlank()) { + widgetLabel = name; + } + return widgetLabel; + } + +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponentProps.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponentProps.java new file mode 100644 index 0000000000..dbb9e17be3 --- /dev/null +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/components/FormDescriptionEditorPageComponentProps.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2022, 2023 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.formdescriptioneditors.components; + +import java.util.Objects; + +import org.eclipse.sirius.components.formdescriptioneditors.description.FormDescriptionEditorDescription; +import org.eclipse.sirius.components.representations.IProps; +import org.eclipse.sirius.components.representations.VariableManager; + +/** + * * The properties of the form description editor page component. + * + * @author arichard + */ +public record FormDescriptionEditorPageComponentProps(VariableManager variableManager, FormDescriptionEditorDescription formDescriptionEditorDescription) implements IProps { + + public FormDescriptionEditorPageComponentProps(VariableManager variableManager, FormDescriptionEditorDescription formDescriptionEditorDescription) { + this.variableManager = Objects.requireNonNull(variableManager); + this.formDescriptionEditorDescription = Objects.requireNonNull(formDescriptionEditorDescription); + } +} diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorComponentPropsValidator.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorComponentPropsValidator.java index 6071c5eab1..1bfaf8045e 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorComponentPropsValidator.java +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorComponentPropsValidator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -16,6 +16,8 @@ import org.eclipse.sirius.components.formdescriptioneditors.components.FormDescriptionEditorComponentProps; import org.eclipse.sirius.components.formdescriptioneditors.components.FormDescriptionEditorGroupComponent; import org.eclipse.sirius.components.formdescriptioneditors.components.FormDescriptionEditorGroupComponentProps; +import org.eclipse.sirius.components.formdescriptioneditors.components.FormDescriptionEditorPageComponent; +import org.eclipse.sirius.components.formdescriptioneditors.components.FormDescriptionEditorPageComponentProps; import org.eclipse.sirius.components.forms.renderer.FormComponentPropsValidator; import org.eclipse.sirius.components.representations.IComponentPropsValidator; import org.eclipse.sirius.components.representations.IProps; @@ -41,6 +43,8 @@ public boolean validateComponentProps(Class componentType, IProps props) { checkValidProps = props instanceof FormDescriptionEditorComponentProps; } else if (FormDescriptionEditorGroupComponent.class.equals(componentType)) { checkValidProps = props instanceof FormDescriptionEditorGroupComponentProps; + } else if (FormDescriptionEditorPageComponent.class.equals(componentType)) { + checkValidProps = props instanceof FormDescriptionEditorPageComponentProps; } else { checkValidProps = this.formComponentPropsValidator.validateComponentProps(componentType, props); } diff --git a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorElementFactory.java b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorElementFactory.java index 3fff40bb61..17367883b6 100644 --- a/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorElementFactory.java +++ b/packages/formdescriptioneditors/backend/sirius-components-formdescriptioneditors/src/main/java/org/eclipse/sirius/components/formdescriptioneditors/renderer/FormDescriptionEditorElementFactory.java @@ -16,7 +16,7 @@ import org.eclipse.sirius.components.formdescriptioneditors.FormDescriptionEditor; import org.eclipse.sirius.components.formdescriptioneditors.elements.FormDescriptionEditorElementProps; -import org.eclipse.sirius.components.forms.Group; +import org.eclipse.sirius.components.forms.Page; import org.eclipse.sirius.components.forms.renderer.FormElementFactory; import org.eclipse.sirius.components.representations.IElementFactory; import org.eclipse.sirius.components.representations.IProps; @@ -46,19 +46,17 @@ public Object instantiateElement(String type, IProps props, List childre } private FormDescriptionEditor instantiateFormDescriptionEditor(FormDescriptionEditorElementProps props, List children) { - // @formatter:off - List groups = children.stream() - .filter(Group.class::isInstance) - .map(Group.class::cast) + List pages = children.stream() + .filter(Page.class::isInstance) + .map(Page.class::cast) .toList(); return FormDescriptionEditor.newFormDescriptionEditor(props.getId()) .label(props.getLabel()) .targetObjectId(props.getTargetObjectId()) .descriptionId(props.getDescriptionId()) - .groups(groups) + .pages(pages) .build(); - // @formatter:on } } diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FlexboxContainerWidget.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FlexboxContainerWidget.tsx index e88e5dc42a..d64d120d01 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FlexboxContainerWidget.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FlexboxContainerWidget.tsx @@ -11,7 +11,7 @@ * Obeo - initial API and implementation *******************************************************************************/ import { useMutation } from '@apollo/client'; -import { GQLGroup, GQLToolbarAction, GQLWidget } from '@eclipse-sirius/sirius-components-forms'; +import { GQLWidget } from '@eclipse-sirius/sirius-components-forms'; import IconButton from '@material-ui/core/IconButton'; import Snackbar from '@material-ui/core/Snackbar'; import { makeStyles, Theme } from '@material-ui/core/styles'; @@ -33,7 +33,7 @@ import { } from './FormDescriptionEditorEventFragment.types'; import { WidgetEntry } from './WidgetEntry'; import { FlexboxContainerWidgetProps } from './WidgetEntry.types'; -import { getAllToolbarActions, isKind } from './WidgetOperations'; +import { isKind } from './WidgetOperations'; const isErrorPayload = (payload: GQLAddWidgetPayload | GQLMoveWidgetPayload): payload is GQLErrorPayload => payload.__typename === 'ErrorPayload'; @@ -76,6 +76,7 @@ export const FlexboxContainerWidget = ({ editingContextId, representationId, formDescriptionEditor, + page, widget, selection, setSelection, @@ -166,13 +167,9 @@ export const FlexboxContainerWidget = ({ event.preventDefault(); event.currentTarget.classList.remove(classes.dragOver); - const id: string = event.dataTransfer.getData('text/plain'); - - if (id === 'Group') { - return; - } else if (getAllToolbarActions(formDescriptionEditor).find((tba: GQLToolbarAction) => tba.id === id)) { - return; - } else if (formDescriptionEditor.groups.find((g: GQLGroup) => g.id === id)) { + const id: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); + if (type !== 'Widget') { return; } @@ -213,6 +210,7 @@ export const FlexboxContainerWidget = ({ editingContextId={editingContextId} representationId={representationId} formDescriptionEditor={formDescriptionEditor} + page={page} container={widget} widget={childWidget} selection={selection} diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.ts b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.ts index c8e1606df6..9a79f9953b 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.ts +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.ts @@ -33,18 +33,26 @@ export const formDescriptionEditorEventSubscription = gql` id formDescriptionEditor { id - groups { + pages { id label - displayMode toolbarActions { ...commonFields ...toolbarActionFields } - widgets { - ...widgetFields - ... on FlexboxContainer { - ...flexboxContainerFields + groups { + id + label + displayMode + toolbarActions { + ...commonFields + ...toolbarActionFields + } + widgets { + ...widgetFields + ... on FlexboxContainer { + ...flexboxContainerFields + } } } } @@ -179,3 +187,45 @@ export const moveToolbarActionMutation = gql` } } `; + +export const addPageMutation = gql` + mutation addPage($input: AddPageInput!) { + addPage(input: $input) { + __typename + ... on SuccessPayload { + id + } + ... on ErrorPayload { + message + } + } + } +`; + +export const movePageMutation = gql` + mutation movePage($input: MovePageInput!) { + movePage(input: $input) { + __typename + ... on SuccessPayload { + id + } + ... on ErrorPayload { + message + } + } + } +`; + +export const deletePageMutation = gql` + mutation deletePage($input: DeletePageInput!) { + deletePage(input: $input) { + __typename + ... on SuccessPayload { + id + } + ... on ErrorPayload { + message + } + } + } +`; diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.types.ts b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.types.ts index 7262053681..94a5118df2 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.types.ts +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorEventFragment.types.ts @@ -11,7 +11,7 @@ * Obeo - initial API and implementation *******************************************************************************/ -import { GQLGroup } from '@eclipse-sirius/sirius-components-forms'; +import { GQLPage } from '@eclipse-sirius/sirius-components-forms'; export interface GQLFormDescriptionEditorEventSubscription { formDescriptionEditorEvent: GQLFormDescriptionEditorEventPayload; @@ -59,7 +59,7 @@ export interface GQLRepresentation { export interface GQLFormDescriptionEditor extends GQLRepresentation { id: string; - groups: GQLGroup[]; + pages: GQLPage[]; } export interface GQLAddWidgetInput { @@ -185,6 +185,7 @@ export interface GQLAddGroupInput { id: string; editingContextId: string; representationId: string; + pageId: string; index: number; } @@ -223,6 +224,7 @@ export interface GQLMoveGroupInput { id: string; editingContextId: string; representationId: string; + pageId: string; groupId: string; index: number; } @@ -239,6 +241,64 @@ export interface GQLMoveGroupPayload { __typename: string; } +export interface GQLAddPageInput { + id: string; + editingContextId: string; + representationId: string; + index: number; +} + +export interface GQLAddPageMutationVariables { + input: GQLAddPageInput; +} + +export interface GQLAddPageMutationData { + addPage: GQLAddPagePayload; +} + +export interface GQLAddPagePayload { + __typename: string; +} + +export interface GQLMovePageInput { + id: string; + editingContextId: string; + representationId: string; + pageId: string; + index: number; +} + +export interface GQLMovePageMutationVariables { + input: GQLMovePageInput; +} + +export interface GQLMovePageMutationData { + movePage: GQLMovePagePayload; +} + +export interface GQLMovePagePayload { + __typename: string; +} + +export interface GQLDeletePageInput { + id: string; + editingContextId: string; + representationId: string; + pageId: string; +} + +export interface GQLDeletePageMutationVariables { + input: GQLDeletePageInput; +} + +export interface GQLDeletePageMutationData { + deletePage: GQLMovePagePayload; +} + +export interface GQLDeletePagePayload { + __typename: string; +} + export interface GQLErrorPayload extends GQLAddWidgetPayload, GQLDeleteWidgetPayload, @@ -248,7 +308,10 @@ export interface GQLErrorPayload GQLMoveToolbarActionPayload, GQLAddGroupPayload, GQLDeleteGroupPayload, - GQLMoveGroupPayload { + GQLMoveGroupPayload, + GQLAddPagePayload, + GQLMovePagePayload, + GQLDeletePagePayload { message: string; } @@ -261,6 +324,9 @@ export interface GQLSuccessPayload GQLMoveToolbarActionPayload, GQLAddGroupPayload, GQLDeleteGroupPayload, - GQLMoveGroupPayload { + GQLMoveGroupPayload, + GQLAddPagePayload, + GQLMovePagePayload, + GQLDeletePagePayload { id: string; } diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorRepresentation.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorRepresentation.tsx index b6ca6d245a..59b181bb54 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorRepresentation.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/FormDescriptionEditorRepresentation.tsx @@ -10,7 +10,7 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ -import { useMutation, useSubscription } from '@apollo/client'; +import { useSubscription } from '@apollo/client'; import { RepresentationComponentProps } from '@eclipse-sirius/sirius-components-core'; import Avatar from '@material-ui/core/Avatar'; import IconButton from '@material-ui/core/IconButton'; @@ -32,26 +32,14 @@ import TextFieldsIcon from '@material-ui/icons/TextFields'; import TextFormatIcon from '@material-ui/icons/TextFormat'; import ViewAgendaIcon from '@material-ui/icons/ViewAgenda'; import ViewColumnIcon from '@material-ui/icons/ViewColumn'; +import WebIcon from '@material-ui/icons/Web'; import { useMachine } from '@xstate/react'; import React, { useEffect } from 'react'; +import { formDescriptionEditorEventSubscription } from './FormDescriptionEditorEventFragment'; import { - addGroupMutation, - formDescriptionEditorEventSubscription, - moveGroupMutation, -} from './FormDescriptionEditorEventFragment'; -import { - GQLAddGroupInput, - GQLAddGroupMutationData, - GQLAddGroupMutationVariables, - GQLAddWidgetPayload, - GQLErrorPayload, GQLFormDescriptionEditorEventInput, GQLFormDescriptionEditorEventSubscription, GQLFormDescriptionEditorEventVariables, - GQLMoveGroupInput, - GQLMoveGroupMutationData, - GQLMoveGroupMutationVariables, - GQLMoveWidgetPayload, } from './FormDescriptionEditorEventFragment.types'; import { FormDescriptionEditorRepresentationContext, @@ -63,12 +51,8 @@ import { SchemaValue, ShowToastEvent, } from './FormDescriptionEditorRepresentationMachine'; -import { Group } from './Group'; import { Button } from './icons/Button'; -import { isKind } from './WidgetOperations'; - -const isErrorPayload = (payload: GQLAddWidgetPayload | GQLMoveWidgetPayload): payload is GQLErrorPayload => - payload.__typename === 'ErrorPayload'; +import { PageList } from './PageList'; const useFormDescriptionEditorStyles = makeStyles((theme) => ({ formDescriptionEditor: { @@ -196,52 +180,6 @@ export const FormDescriptionEditorRepresentation = ({ } ); - const [addGroup, { loading: addGroupLoading, data: addGroupData, error: addGroupError }] = useMutation< - GQLAddGroupMutationData, - GQLAddGroupMutationVariables - >(addGroupMutation); - - useEffect(() => { - if (!addGroupLoading) { - if (addGroupError) { - const message: string = addGroupError.message; - const showToastEvent: ShowToastEvent = { type: 'SHOW_TOAST', message }; - dispatch(showToastEvent); - } - if (addGroupData) { - const { addGroup } = addGroupData; - if (isErrorPayload(addGroup)) { - const { message } = addGroup; - const showToastEvent: ShowToastEvent = { type: 'SHOW_TOAST', message }; - dispatch(showToastEvent); - } - } - } - }, [addGroupLoading, addGroupData, addGroupError, dispatch]); - - const [moveGroup, { loading: moveGroupLoading, data: moveGroupData, error: moveGroupError }] = useMutation< - GQLMoveGroupMutationData, - GQLMoveGroupMutationVariables - >(moveGroupMutation); - - useEffect(() => { - if (!moveGroupLoading) { - if (moveGroupError) { - const message: string = moveGroupError.message; - const showToastEvent: ShowToastEvent = { type: 'SHOW_TOAST', message }; - dispatch(showToastEvent); - } - if (moveGroupData) { - const { moveGroup } = moveGroupData; - if (isErrorPayload(moveGroup)) { - const { message } = moveGroup; - const showToastEvent: ShowToastEvent = { type: 'SHOW_TOAST', message }; - dispatch(showToastEvent); - } - } - } - }, [moveGroupLoading, moveGroupData, moveGroupError, dispatch]); - useEffect(() => { if (error) { const message: string = 'An error has occurred while trying to retrieve the form description editor'; @@ -260,57 +198,19 @@ export const FormDescriptionEditorRepresentation = ({ } }, [formDescriptionEditorRepresentation, dispatch]); - const handleDragStart: React.DragEventHandler = (event) => { - event.dataTransfer.setData('text/plain', event.currentTarget.id); - }; - const handleDragEnter: React.DragEventHandler = (event) => { - event.preventDefault(); - event.currentTarget.classList.add(classes.dragOver); + const handleDragStartPage: React.DragEventHandler = (event) => { + event.dataTransfer.setData('draggedElementId', event.currentTarget.id); + event.dataTransfer.setData('draggedElementType', 'Page'); }; - const handleDragOver: React.DragEventHandler = (event) => { - event.preventDefault(); - event.currentTarget.classList.add(classes.dragOver); - }; - const handleDragLeave: React.DragEventHandler = (event) => { - event.preventDefault(); - event.currentTarget.classList.remove(classes.dragOver); - }; - const handleDrop: React.DragEventHandler = (event) => { - event.preventDefault(); - event.currentTarget.classList.remove(classes.dragOver); - const id: string = event.dataTransfer.getData('text/plain'); - let index = formDescriptionEditor.groups.length; + const handleDragStartGroup: React.DragEventHandler = (event) => { + event.dataTransfer.setData('draggedElementId', event.currentTarget.id); + event.dataTransfer.setData('draggedElementType', 'Group'); + }; - if (id === 'Group') { - const addGroupInput: GQLAddGroupInput = { - id: crypto.randomUUID(), - editingContextId, - representationId, - index, - }; - const addGroupVariables: GQLAddGroupMutationVariables = { input: addGroupInput }; - addGroup({ variables: addGroupVariables }); - } else if (isKind(id)) { - // forbid to drag and drop new widgets into groups area - return; - } else { - if (formDescriptionEditor.groups.find((g) => g.id === id)) { - index--; - } else { - // forbid to drag and drop existing widgets or toolbarActions into groups area - return; - } - const moveGroupInput: GQLMoveGroupInput = { - id: crypto.randomUUID(), - editingContextId, - representationId, - groupId: id, - index, - }; - const moveGroupVariables: GQLMoveGroupMutationVariables = { input: moveGroupInput }; - moveGroup({ variables: moveGroupVariables }); - } + const handleDragStartWidget: React.DragEventHandler = (event) => { + event.dataTransfer.setData('draggedElementId', event.currentTarget.id); + event.dataTransfer.setData('draggedElementType', 'Widget'); }; let content: JSX.Element | null = null; @@ -319,13 +219,25 @@ export const FormDescriptionEditorRepresentation = ({ content = (
+ Pages +
+ + + Page + +
Groups
+ onDragStart={handleDragStartGroup}> Group @@ -337,7 +249,7 @@ export const FormDescriptionEditorRepresentation = ({ data-testid="FormDescriptionEditor-BarChart" draggable="true" className={classes.widgetKind} - onDragStart={handleDragStart}> + onDragStart={handleDragStartWidget}> BarChart @@ -348,7 +260,7 @@ export const FormDescriptionEditorRepresentation = ({ data-testid="FormDescriptionEditor-Button" draggable="true" className={classes.widgetKind} - onDragStart={handleDragStart}> + onDragStart={handleDragStartWidget}>
- {formDescriptionEditor.groups.map((group) => ( - - ))} -
- {'Drag and drop a group here'} -
+
diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.tsx index 5fd1dad858..3b02b07d66 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.tsx @@ -12,7 +12,7 @@ *******************************************************************************/ import { useMutation } from '@apollo/client'; import { Selection } from '@eclipse-sirius/sirius-components-core'; -import { GQLGroup, GQLToolbarAction, GQLWidget } from '@eclipse-sirius/sirius-components-forms'; +import { GQLWidget } from '@eclipse-sirius/sirius-components-forms'; import IconButton from '@material-ui/core/IconButton'; import Snackbar from '@material-ui/core/Snackbar'; import { makeStyles, Theme, withStyles } from '@material-ui/core/styles'; @@ -54,7 +54,7 @@ import { import { GroupProps, GroupState } from './Group.types'; import { ToolbarActions } from './ToolbarActions'; import { WidgetEntry } from './WidgetEntry'; -import { getAllToolbarActions, isKind } from './WidgetOperations'; +import { isKind } from './WidgetOperations'; const useGroupEntryStyles = makeStyles((theme) => ({ group: { @@ -143,6 +143,7 @@ export const Group = ({ editingContextId, representationId, formDescriptionEditor, + page, group, selection, setSelection, @@ -313,7 +314,8 @@ export const Group = ({ }; const handleDragStart: React.DragEventHandler = (event: React.DragEvent) => { - event.dataTransfer.setData('text/plain', group.id); + event.dataTransfer.setData('draggedElementId', group.id); + event.dataTransfer.setData('draggedElementType', 'Group'); }; const handleDragEnter: React.DragEventHandler = (event: React.DragEvent) => { event.preventDefault(); @@ -331,12 +333,15 @@ export const Group = ({ event.preventDefault(); event.currentTarget.classList.remove(classes.dragOver); - const id: string = event.dataTransfer.getData('text/plain'); + const id: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); - if (isKind(id)) { + if (type !== 'Group') { return; - } else if (id === 'Group') { - let newGroupIndex: number = formDescriptionEditor.groups.indexOf(group); + } + + if (id === 'Group') { + let newGroupIndex: number = page.groups.indexOf(group); if (newGroupIndex <= 0) { newGroupIndex = 0; } @@ -344,16 +349,17 @@ export const Group = ({ id: crypto.randomUUID(), editingContextId, representationId, + pageId: page.id, index: newGroupIndex, }; const addGroupVariables: GQLAddGroupMutationVariables = { input: addGroupInput }; addGroup({ variables: addGroupVariables }); - } else if (formDescriptionEditor.groups.find((g) => g.id === id)) { - let groupNewIndex: number = formDescriptionEditor.groups.indexOf(group); + } else if (page.groups.find((g) => g.id === id)) { + let groupNewIndex: number = page.groups.indexOf(group); if (groupNewIndex <= 0) { groupNewIndex = 0; } - const movedGroupIndex = formDescriptionEditor.groups.findIndex((g) => g.id === id); + const movedGroupIndex = page.groups.findIndex((g) => g.id === id); if (movedGroupIndex > -1 && movedGroupIndex < groupNewIndex) { groupNewIndex--; } @@ -361,6 +367,7 @@ export const Group = ({ id: crypto.randomUUID(), editingContextId, representationId, + pageId: page.id, groupId: id, index: groupNewIndex, }; @@ -372,16 +379,16 @@ export const Group = ({ event.preventDefault(); event.currentTarget.classList.remove(classes.dragOver); - const id: string = event.dataTransfer.getData('text/plain'); - let widgetIndex = group.widgets.length; + const id: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); - if (id === 'Group') { - return; - } else if (formDescriptionEditor.groups.find((g: GQLGroup) => g.id === id)) { + if (type !== 'Widget') { return; - } else if (getAllToolbarActions(formDescriptionEditor).find((tba: GQLToolbarAction) => tba.id === id)) { - return; - } else if (isKind(id)) { + } + + let widgetIndex = group.widgets.length; + + if (isKind(id)) { const addWidgetInput: GQLAddWidgetInput = { id: crypto.randomUUID(), editingContextId, @@ -494,6 +501,7 @@ export const Group = ({ editingContextId={editingContextId} representationId={representationId} formDescriptionEditor={formDescriptionEditor} + page={page} container={group} widget={widget} selection={selection} diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.types.ts b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.types.ts index 5690a14dcb..2eb95c341f 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.types.ts +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Group.types.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -11,13 +11,14 @@ * Obeo - initial API and implementation *******************************************************************************/ import { Selection } from '@eclipse-sirius/sirius-components-core'; -import { GQLGroup } from '@eclipse-sirius/sirius-components-forms'; +import { GQLGroup, GQLPage } from '@eclipse-sirius/sirius-components-forms'; import { GQLFormDescriptionEditor } from './FormDescriptionEditorEventFragment.types'; export interface GroupProps { editingContextId: string; representationId: string; formDescriptionEditor: GQLFormDescriptionEditor; + page: GQLPage; group: GQLGroup; selection: Selection; setSelection: (newSelection: Selection) => void; diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.tsx new file mode 100644 index 0000000000..f45471d170 --- /dev/null +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.tsx @@ -0,0 +1,251 @@ +/******************************************************************************* + * Copyright (c) 2023 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 + *******************************************************************************/ +import { useMutation } from '@apollo/client'; +import { makeStyles } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; +import CloseIcon from '@material-ui/icons/Close'; +import IconButton from '@material-ui/core/IconButton'; +import Snackbar from '@material-ui/core/Snackbar'; +import { Group } from './Group'; +import { PageProps, PageState } from './Page.types'; +import { + GQLAddGroupInput, + GQLAddGroupMutationData, + GQLAddGroupMutationVariables, + GQLAddPagePayload, + GQLErrorPayload, + GQLMoveGroupInput, + GQLMoveGroupMutationData, + GQLMoveGroupMutationVariables, + GQLMovePagePayload, +} from './FormDescriptionEditorEventFragment.types'; +import { addGroupMutation, moveGroupMutation } from './FormDescriptionEditorEventFragment'; +import React, { useEffect, useRef, useState } from 'react'; + +const isErrorPayload = (payload: GQLAddPagePayload | GQLMovePagePayload): payload is GQLErrorPayload => + payload.__typename === 'ErrorPayload'; + +const usePageStyles = makeStyles((theme) => ({ + page: { + display: 'flex', + flexDirection: 'column', + '& > *': { + marginBottom: theme.spacing(2), + }, + overflowY: 'auto', + }, + preview: { + width: '100%', + padding: '4px 8px 4px 8px', + overflowY: 'auto', + }, + bottomDropArea: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'whitesmoke', + borderRadius: '10px', + color: 'gray', + height: '60px', + }, + dragOver: { + borderWidth: '1px', + borderStyle: 'dashed', + borderColor: theme.palette.primary.main, + }, +})); + +export const Page = ({ + editingContextId, + representationId, + formDescriptionEditor, + page, + selection, + setSelection, +}: PageProps) => { + const classes = usePageStyles(); + + const initialState: PageState = { message: null, selected: false }; + const [state, setState] = useState(initialState); + const { message } = state; + + const ref = useRef(null); + + useEffect(() => { + if (ref.current && selection.entries.find((entry) => entry.id === page.id)) { + ref.current.focus(); + setState((prevState) => { + return { ...prevState, selected: true }; + }); + } else { + setState((prevState) => { + return { ...prevState, selected: false }; + }); + } + }, [selection, page]); + + const [addGroup, { loading: addGroupLoading, data: addGroupData, error: addGroupError }] = useMutation< + GQLAddGroupMutationData, + GQLAddGroupMutationVariables + >(addGroupMutation); + + useEffect(() => { + if (!addGroupLoading) { + if (addGroupError) { + setState((prevState) => { + return { ...prevState, message: addGroupError.message }; + }); + } + if (addGroupData) { + const { addGroup } = addGroupData; + if (isErrorPayload(addGroup)) { + setState((prevState) => { + return { ...prevState, message: addGroup.message }; + }); + } + } + } + }, [addGroupLoading, addGroupData, addGroupError]); + + const [moveGroup, { loading: moveGroupLoading, data: moveGroupData, error: moveGroupError }] = useMutation< + GQLMoveGroupMutationData, + GQLMoveGroupMutationVariables + >(moveGroupMutation); + + useEffect(() => { + if (!moveGroupLoading) { + if (moveGroupError) { + setState((prevState) => { + return { ...prevState, message: moveGroupError.message }; + }); + } + if (moveGroupData) { + const { moveGroup } = moveGroupData; + if (isErrorPayload(moveGroup)) { + setState((prevState) => { + return { ...prevState, message: moveGroup.message }; + }); + } + } + } + }, [moveGroupLoading, moveGroupData, moveGroupError]); + + const handleDragEnter: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.add(classes.dragOver); + }; + const handleDragOver: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.add(classes.dragOver); + }; + const handleDragLeave: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.remove(classes.dragOver); + }; + const handleDrop: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.remove(classes.dragOver); + + const id: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); + + if (type !== 'Group') { + return; + } + + let index = page.groups.length; + + if (id === 'Group') { + const addGroupInput: GQLAddGroupInput = { + id: crypto.randomUUID(), + editingContextId, + pageId: page.id, + representationId, + index, + }; + const addGroupVariables: GQLAddGroupMutationVariables = { input: addGroupInput }; + addGroup({ variables: addGroupVariables }); + } else if (page.groups.find((g) => g.id === id)) { + index--; + const moveGroupInput: GQLMoveGroupInput = { + id: crypto.randomUUID(), + editingContextId, + representationId, + pageId: page.id, + groupId: id, + index, + }; + const moveGroupVariables: GQLMoveGroupMutationVariables = { input: moveGroupInput }; + moveGroup({ variables: moveGroupVariables }); + } + }; + + return ( +
+
+ {page.groups.map((group) => { + return ( + + ); + })} +
+
+ {'Drag and drop a group here'} +
+ + setState((prevState) => { + return { ...prevState, message: null }; + }) + } + message={message} + action={ + + setState((prevState) => { + return { ...prevState, message: null }; + }) + }> + + + } + data-testid="error" + /> +
+ ); +}; diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.types.ts b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.types.ts new file mode 100644 index 0000000000..c091d7d932 --- /dev/null +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/Page.types.ts @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2023 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 + *******************************************************************************/ +import { Selection } from '@eclipse-sirius/sirius-components-core'; +import { GQLPage } from '@eclipse-sirius/sirius-components-forms/src'; +import { GQLFormDescriptionEditor } from './FormDescriptionEditorEventFragment.types'; + +export interface PageProps { + editingContextId: string; + representationId: string; + formDescriptionEditor: GQLFormDescriptionEditor; + page: GQLPage; + selection: Selection; + setSelection: (selection: Selection) => void; +} + +export interface PageState { + message: string | null; + selected: boolean; +} diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.tsx new file mode 100644 index 0000000000..c04b4e52d4 --- /dev/null +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.tsx @@ -0,0 +1,406 @@ +/******************************************************************************* + * Copyright (c) 2023 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 + *******************************************************************************/ +import { useMutation } from '@apollo/client'; +import { Selection } from '@eclipse-sirius/sirius-components-core'; +import { makeStyles } from '@material-ui/core/styles'; +import { PageListProps, PageListState } from './PageList.types'; +import { Page } from './Page'; +import Tab from '@material-ui/core/Tab'; +import Tabs from '@material-ui/core/Tabs'; +import Snackbar from '@material-ui/core/Snackbar'; +import CloseIcon from '@material-ui/icons/Close'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import React, { useEffect, useState } from 'react'; +import { + GQLAddPageInput, + GQLAddPageMutationData, + GQLAddPageMutationVariables, + GQLAddPagePayload, + GQLDeletePageInput, + GQLDeletePageMutationData, + GQLDeletePageMutationVariables, + GQLErrorPayload, + GQLMovePageInput, + GQLMovePageMutationData, + GQLMovePageMutationVariables, + GQLMovePagePayload, +} from './FormDescriptionEditorEventFragment.types'; +import { addPageMutation, deletePageMutation, movePageMutation } from './FormDescriptionEditorEventFragment'; + +const isErrorPayload = (payload: GQLAddPagePayload | GQLMovePagePayload): payload is GQLErrorPayload => + payload.__typename === 'ErrorPayload'; + +const usePageListStyles = makeStyles((theme) => ({ + rightDropArea: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'whitesmoke', + borderRadius: '10px', + color: 'gray', + height: '40px', + width: '50%', + }, + dragOver: { + borderWidth: '1px', + borderStyle: 'dashed', + borderColor: theme.palette.primary.main, + }, + pagesList: { + display: 'flex', + justifyContent: 'left', + }, + tabsRoot: { + minHeight: theme.spacing(4), + borderBottomColor: theme.palette.divider, + borderBottomWidth: '1px', + borderBottomStyle: 'solid', + }, + tabRoot: { + minHeight: theme.spacing(4), + textTransform: 'none', + }, + tabLabel: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + width: 'inherit', + }, + tabLabelText: { + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + }, +})); + +const a11yProps = (id: string) => { + return { + id: `simple-tab-${id}`, + 'aria-controls': `simple-tabpanel-${id}`, + }; +}; + +export const PageList = ({ + editingContextId, + representationId, + formDescriptionEditor, + selection, + setSelection, +}: PageListProps) => { + const classes = usePageListStyles(); + + const { pages } = formDescriptionEditor; + + const [state, setState] = useState({ message: null, selectedPage: pages[0], pages }); + const { message } = state; + + useEffect(() => { + setState((prevState) => { + const selectedPage = pages.find((page) => page.id === state.selectedPage.id); + if (selectedPage) { + return { ...prevState, selectedPage, pages }; + } + return { ...prevState, selectedPage: pages[0], pages }; + }); + }, [pages, state.selectedPage.id]); + + const onChangeTab = (_: React.ChangeEvent<{}>, value: string) => { + const selectedPage = pages.find((page) => page.id === value); + setState((prevState) => { + return { ...prevState, selectedPage }; + }); + }; + + const [addPage, { loading: addPageLoading, data: addPageData, error: addPageError }] = useMutation< + GQLAddPageMutationData, + GQLAddPageMutationVariables + >(addPageMutation); + + useEffect(() => { + if (!addPageLoading) { + if (addPageError) { + setState((prevState) => { + return { ...prevState, message: addPageError.message }; + }); + } + if (addPageData) { + const { addPage } = addPageData; + if (isErrorPayload(addPage)) { + setState((prevState) => { + return { ...prevState, message: addPage.message }; + }); + } + } + } + }, [addPageLoading, addPageData, addPageError]); + + const [movePage, { loading: movePageLoading, data: movePageData, error: movePageError }] = useMutation< + GQLMovePageMutationData, + GQLMovePageMutationVariables + >(movePageMutation); + + useEffect(() => { + if (!movePageLoading) { + if (movePageError) { + setState((prevState) => { + return { ...prevState, message: movePageError.message }; + }); + } + if (movePageData) { + const { movePage } = movePageData; + if (isErrorPayload(movePage)) { + setState((prevState) => { + return { ...prevState, message: movePage.message }; + }); + } + } + } + }, [movePageLoading, movePageData, movePageError]); + + const [deletePage, { loading: deletePageLoading, data: deletePageData, error: deletePageError }] = useMutation< + GQLDeletePageMutationData, + GQLDeletePageMutationVariables + >(deletePageMutation); + + useEffect(() => { + if (!deletePageLoading) { + if (deletePageError) { + setState((prevState) => { + return { ...prevState, message: deletePageError.message }; + }); + } + if (deletePageData) { + const { deletePage } = deletePageData; + if (isErrorPayload(deletePage)) { + setState((prevState) => { + return { ...prevState, message: deletePage.message }; + }); + } + } + } + }, [deletePageLoading, deletePageData, deletePageError]); + + const handleClick: React.MouseEventHandler = (event) => { + const currentPage = pages.find((page) => page.id === event.currentTarget.id); + if (currentPage) { + const newSelection: Selection = { + entries: [ + { + id: currentPage.id, + label: currentPage.label, + kind: `siriusComponents://semantic?domain=view&entity=PageDescription`, + }, + ], + }; + setSelection(newSelection); + } + event.stopPropagation(); + }; + + const handleDelete: React.KeyboardEventHandler = (event) => { + event.preventDefault(); + if (event.key === 'Delete') { + const deletePageInput: GQLDeletePageInput = { + id: crypto.randomUUID(), + editingContextId, + representationId, + pageId: state.selectedPage.id, + }; + const deletePageVariables: GQLDeletePageMutationVariables = { input: deletePageInput }; + deletePage({ variables: deletePageVariables }); + event.stopPropagation(); + } + }; + + const handleDragStart: React.DragEventHandler = (event) => { + event.dataTransfer.setData('draggedElementId', event.currentTarget.id); + event.dataTransfer.setData('draggedElementType', 'Page'); + }; + + const handleDragEnter: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.add(classes.dragOver); + }; + const handleDragOver: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.add(classes.dragOver); + }; + const handleDragLeave: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.remove(classes.dragOver); + }; + const handleDropTab: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.remove(classes.dragOver); + + const draggedElementId: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); + + if (type !== 'Page') { + return; + } + + const dropLocationId: string = event.currentTarget.id; + const index: number = pages.findIndex((p) => p.id === dropLocationId); + + if (index < 0) { + //Drop location invalids + return; + } + + if (draggedElementId === 'Page') { + const addPageInput: GQLAddPageInput = { + id: crypto.randomUUID(), + editingContextId, + representationId, + index, + }; + const addPageVariables: GQLAddPageMutationVariables = { input: addPageInput }; + addPage({ variables: addPageVariables }); + } else if (formDescriptionEditor.pages.find((g) => g.id === draggedElementId)) { + const movePageInput: GQLMovePageInput = { + id: crypto.randomUUID(), + editingContextId, + representationId, + pageId: draggedElementId, + index, + }; + const movePageVariables: GQLMovePageMutationVariables = { input: movePageInput }; + movePage({ variables: movePageVariables }); + } + }; + + const handleDropArea: React.DragEventHandler = (event) => { + event.preventDefault(); + event.currentTarget.classList.remove(classes.dragOver); + + const id: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); + + if (type !== 'Page') { + return; + } + + let index = formDescriptionEditor.pages.length; + + if (id === 'Page') { + const addPageInput: GQLAddPageInput = { + id: crypto.randomUUID(), + editingContextId, + representationId, + index, + }; + const addPageVariables: GQLAddPageMutationVariables = { input: addPageInput }; + addPage({ variables: addPageVariables }); + } else if (pages.find((g) => g.id === id)) { + index--; + const movePageInput: GQLMovePageInput = { + id: crypto.randomUUID(), + editingContextId, + representationId, + pageId: id, + index, + }; + const movePageVariables: GQLMovePageMutationVariables = { input: movePageInput }; + movePage({ variables: movePageVariables }); + } + }; + + return ( +
+
+ + {state.pages.map((page) => { + return ( + +
{page.label}
+
+ } + key={page.id} + onClick={handleClick} + onKeyDown={handleDelete} + draggable={true} + onDragStart={handleDragStart} + onDragEnter={handleDragEnter} + onDragOver={handleDragOver} + onDragLeave={handleDragLeave} + onDrop={handleDropTab} + /> + ); + })} + +
+ {'Drag and drop a page here'} +
+
+ + + setState((prevState) => { + return { ...prevState, message: null }; + }) + } + message={message} + action={ + + setState((prevState) => { + return { ...prevState, message: null }; + }) + }> + + + } + data-testid="error" + /> +
+ ); +}; diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.types.ts b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.types.ts new file mode 100644 index 0000000000..f21a6d4266 --- /dev/null +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/PageList.types.ts @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2023 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 + *******************************************************************************/ +import { Selection } from '@eclipse-sirius/sirius-components-core'; +import { GQLFormDescriptionEditor } from './FormDescriptionEditorEventFragment.types'; +import { GQLPage } from '@eclipse-sirius/sirius-components-forms/src'; + +export interface PageListProps { + editingContextId: string; + representationId: string; + formDescriptionEditor: GQLFormDescriptionEditor; + selection: Selection; + setSelection: (selection: Selection) => void; +} + +export interface PageListState { + message: string | null; + selectedPage: GQLPage; + pages: GQLPage[]; +} diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActionWidget.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActionWidget.tsx index 807ce80960..83e4c4eed6 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActionWidget.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActionWidget.tsx @@ -16,9 +16,7 @@ import { ButtonStyleProps, getTextDecorationLineValue, GQLButton, - GQLGroup, GQLToolbarAction, - GQLWidget, } from '@eclipse-sirius/sirius-components-forms'; import Button from '@material-ui/core/Button'; import IconButton from '@material-ui/core/IconButton'; @@ -38,7 +36,6 @@ import { GQLMoveToolbarActionMutationVariables, } from './FormDescriptionEditorEventFragment.types'; import { ToolbarActionProps, ToolbarActionState } from './ToolbarActionWidget.types'; -import { getAllWidgets, isKind } from './WidgetOperations'; const useStyles = makeStyles((theme) => ({ style: { @@ -109,7 +106,6 @@ const isErrorPayload = (payload: GQLDeleteToolbarActionPayload): payload is GQLE export const ToolbarActionWidget = ({ editingContextId, representationId, - formDescriptionEditor, group, toolbarAction, selection, @@ -261,7 +257,8 @@ export const ToolbarActionWidget = ({ }, [moveToolbarActionLoading, moveToolbarActionData, moveToolbarActionError]); const handleDragStart: React.DragEventHandler = (event: React.DragEvent) => { - event.dataTransfer.setData('text/plain', toolbarAction.id); + event.dataTransfer.setData('draggedElementId', toolbarAction.id); + event.dataTransfer.setData('draggedElementType', 'ToolbarActionWidget'); event.stopPropagation(); }; const handleDragEnter: React.DragEventHandler = (event: React.DragEvent) => { @@ -283,15 +280,10 @@ export const ToolbarActionWidget = ({ }; const onDropBefore = (event: React.DragEvent, toolbarAction: GQLButton) => { - const id: string = event.dataTransfer.getData('text/plain'); - // We only accept drop of ToolbarAction, no Widget or Group allowed - if (isKind(id)) { - return; - } else if (id === 'Group') { - return; - } else if (getAllWidgets(formDescriptionEditor).find((w: GQLWidget) => w.id === id)) { - return; - } else if (formDescriptionEditor.groups.find((g: GQLGroup) => g.id === id)) { + const id: string = event.dataTransfer.getData('draggedElementId'); + // We only accept a drop of ToolbarAction + const type: string = event.dataTransfer.getData('draggedElementType'); + if (type !== 'ToolbarActionWidget') { return; } diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActions.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActions.tsx index 365593e06e..745635558c 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActions.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/ToolbarActions.tsx @@ -12,7 +12,7 @@ *******************************************************************************/ import { useMutation } from '@apollo/client'; -import { GQLGroup, GQLToolbarAction, GQLWidget } from '@eclipse-sirius/sirius-components-forms'; +import { GQLToolbarAction } from '@eclipse-sirius/sirius-components-forms'; import IconButton from '@material-ui/core/IconButton'; import Snackbar from '@material-ui/core/Snackbar'; import { makeStyles, Theme } from '@material-ui/core/styles'; @@ -34,7 +34,6 @@ import { } from './FormDescriptionEditorEventFragment.types'; import { ToolbarActionsProps } from './ToolbarActions.types'; import { ToolbarActionWidget } from './ToolbarActionWidget'; -import { getAllWidgets, isKind } from './WidgetOperations'; const useToolbarActionsStyles = makeStyles((theme: Theme) => ({ toolbar: { @@ -147,15 +146,10 @@ export const ToolbarActions = ({ event.preventDefault(); event.currentTarget.classList.remove(classes.dragOver); - const id: string = event.dataTransfer.getData('text/plain'); + const id: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); - if (isKind(id)) { - return; - } else if (id === 'Group') { - return; - } else if (getAllWidgets(formDescriptionEditor).find((w: GQLWidget) => w.id === id)) { - return; - } else if (formDescriptionEditor.groups.find((g: GQLGroup) => g.id === id)) { + if (type !== 'ToolbarActionWidget') { return; } diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.tsx index 36d0e6f074..923ff5ef43 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.tsx @@ -28,7 +28,6 @@ import { GQLSelect, GQLTextarea, GQLTextfield, - GQLToolbarAction, GQLWidget, } from '@eclipse-sirius/sirius-components-forms'; import IconButton from '@material-ui/core/IconButton'; @@ -69,7 +68,7 @@ import { SelectWidget } from './SelectWidget'; import { TextAreaWidget } from './TextAreaWidget'; import { TextfieldWidget } from './TextfieldWidget'; import { WidgetEntryProps, WidgetEntryState, WidgetEntryStyleProps } from './WidgetEntry.types'; -import { getAllToolbarActions, isFlexboxContainer, isGroup, isKind } from './WidgetOperations'; +import { isFlexboxContainer, isGroup, isKind } from './WidgetOperations'; const useWidgetEntryStyles = makeStyles((theme) => ({ widget: { @@ -122,6 +121,7 @@ export const WidgetEntry = ({ editingContextId, representationId, formDescriptionEditor, + page, container, widget, selection, @@ -232,7 +232,8 @@ export const WidgetEntry = ({ }; const handleDragStart: React.DragEventHandler = (event: React.DragEvent) => { - event.dataTransfer.setData('text/plain', widget.id); + event.dataTransfer.setData('draggedElementId', widget.id); + event.dataTransfer.setData('draggedElementType', 'Widget'); event.stopPropagation(); }; const handleDragEnter: React.DragEventHandler = (event: React.DragEvent) => { @@ -254,13 +255,10 @@ export const WidgetEntry = ({ }; const onDropBefore = (event: React.DragEvent, widget: GQLWidget) => { - const id: string = event.dataTransfer.getData('text/plain'); - // We only accept drop of Widgets, no ToolbarAction or Group allowed - if (id === 'Group') { - return; - } else if (getAllToolbarActions(formDescriptionEditor).find((tba: GQLToolbarAction) => tba.id === id)) { - return; - } else if (formDescriptionEditor.groups.find((g: GQLGroup) => g.id === id)) { + const id: string = event.dataTransfer.getData('draggedElementId'); + const type: string = event.dataTransfer.getData('draggedElementType'); + + if (type !== 'Widget') { return; } @@ -333,6 +331,7 @@ export const WidgetEntry = ({ editingContextId={editingContextId} representationId={representationId} formDescriptionEditor={formDescriptionEditor} + page={page} container={container} widget={widget as GQLFlexboxContainer} selection={selection} diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.types.ts b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.types.ts index a712493832..b59467e4cc 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.types.ts +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetEntry.types.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -23,6 +23,7 @@ import { GQLLink, GQLList, GQLMultiSelect, + GQLPage, GQLRadio, GQLRichText, GQLSelect, @@ -37,6 +38,7 @@ export interface WidgetEntryProps { editingContextId: string; representationId: string; formDescriptionEditor: GQLFormDescriptionEditor; + page: GQLPage; container: GQLGroup | GQLFlexboxContainer; widget: GQLWidget; selection: Selection; @@ -60,6 +62,7 @@ export interface FlexboxContainerWidgetProps { editingContextId: string; representationId: string; formDescriptionEditor: GQLFormDescriptionEditor; + page: GQLPage; container: GQLGroup | GQLFlexboxContainer; widget: GQLFlexboxContainer; selection: Selection; diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetOperations.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetOperations.tsx index 3d291804bf..e03d1a4f3a 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetOperations.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/WidgetOperations.tsx @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -10,8 +10,7 @@ * Contributors: * Obeo - initial API and implementation *******************************************************************************/ -import { GQLFlexboxContainer, GQLGroup, GQLToolbarAction, GQLWidget } from '@eclipse-sirius/sirius-components-forms'; -import { GQLFormDescriptionEditor } from './FormDescriptionEditorEventFragment.types'; +import { GQLGroup, GQLWidget } from '@eclipse-sirius/sirius-components-forms'; import { Kind } from './FormDescriptionEditorRepresentation.types'; export const isKind = (value: string): value is Kind => { @@ -41,31 +40,3 @@ export const isGroup = (element: GQLWidget | GQLGroup): boolean => { export const isFlexboxContainer = (element: GQLWidget | GQLGroup): boolean => { return element.__typename === 'FlexboxContainer'; }; - -export const getAllWidgets = (formDescriptionEditor: GQLFormDescriptionEditor): GQLWidget[] => { - let allWidgets: GQLWidget[] = []; - formDescriptionEditor.groups.forEach((group: GQLGroup) => { - group.widgets.forEach((widget: GQLWidget) => { - if (isFlexboxContainer(widget)) { - allWidgets = allWidgets.concat(getAllFlexboxContainerWidgets(widget as GQLFlexboxContainer)); - } - allWidgets.push(widget); - }); - }); - return allWidgets; -}; - -const getAllFlexboxContainerWidgets = (flexboxContainer: GQLFlexboxContainer): GQLWidget[] => { - let allWidgets: GQLWidget[] = []; - flexboxContainer.children.forEach((widget: GQLWidget) => { - if (isFlexboxContainer(widget)) { - allWidgets = allWidgets.concat(getAllFlexboxContainerWidgets(widget as GQLFlexboxContainer)); - } - allWidgets.push(widget); - }); - return allWidgets; -}; - -export const getAllToolbarActions = (formDescriptionEditor: GQLFormDescriptionEditor): GQLToolbarAction[] => { - return formDescriptionEditor.groups.flatMap((g: GQLGroup) => g.toolbarActions); -}; diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Group.test.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Group.test.tsx index 48e16aac7f..43642bdc00 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Group.test.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Group.test.tsx @@ -12,7 +12,7 @@ *******************************************************************************/ import { MockedProvider, MockedResponse } from '@apollo/client/testing'; import { Selection } from '@eclipse-sirius/sirius-components-core'; -import { GQLGroup } from '@eclipse-sirius/sirius-components-forms'; +import { GQLGroup, GQLPage } from '@eclipse-sirius/sirius-components-forms'; import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { afterEach, expect, test, vi } from 'vitest'; import { addGroupMutation, deleteGroupMutation, moveGroupMutation } from '../FormDescriptionEditorEventFragment'; @@ -49,6 +49,7 @@ const addGroupVariables: GQLAddGroupMutationVariables = { id: '48be95fc-3422-45d3-b1f9-d590e847e9e1', editingContextId: 'editingContextId', representationId: 'formDescriptionEditorId', + pageId: 'Page1', index: 0, }, }; @@ -75,6 +76,7 @@ const moveGroupVariables: GQLMoveGroupMutationVariables = { id: '48be95fc-3422-45d3-b1f9-d590e847e9e1', editingContextId: 'editingContextId', representationId: 'formDescriptionEditorId', + pageId: 'Page1', groupId: 'Group2', index: 0, }, @@ -94,9 +96,16 @@ test('should drop the Group in the drop area', async () => { toolbarActions: [], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'FormDescriptionEditor1', - groups: [group], + pages: [page], }; let addGroupCalled: boolean = false; @@ -119,6 +128,7 @@ test('should drop the Group in the drop area', async () => { editingContextId="editingContextId" representationId="formDescriptionEditorId" formDescriptionEditor={formDescriptionEditor} + page={page} group={group} selection={emptySelection} setSelection={emptySetSelection} @@ -129,7 +139,8 @@ test('should drop the Group in the drop area', async () => { const element: HTMLElement = screen.getByTestId(`Group-DropArea-${group.id}`); const dataTransfer: DataTransfer = new DataTransfer(); - dataTransfer.setData('text/plain', 'Group'); + dataTransfer.setData('draggedElementId', 'Group'); + dataTransfer.setData('draggedElementType', 'Group'); fireEvent.drop(element, { dataTransfer }); await act(async () => { @@ -150,9 +161,16 @@ test('should delete the Group from the drop area', async () => { toolbarActions: [], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'formDescriptionEditorId', - groups: [group], + pages: [page], }; let deleteGroupCalled: boolean = false; @@ -175,6 +193,7 @@ test('should delete the Group from the drop area', async () => { editingContextId="editingContextId" representationId="formDescriptionEditorId" formDescriptionEditor={formDescriptionEditor} + page={page} group={group} selection={emptySelection} setSelection={emptySetSelection} @@ -214,9 +233,16 @@ test('should move the existing Group from/into the drop area', async () => { toolbarActions: [], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group1, group2], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'formDescriptionEditorId', - groups: [group1, group2], + pages: [page], }; let moveGroupCalled: boolean = false; @@ -239,6 +265,7 @@ test('should move the existing Group from/into the drop area', async () => { editingContextId="editingContextId" representationId="formDescriptionEditorId" formDescriptionEditor={formDescriptionEditor} + page={page} group={group1} selection={emptySelection} setSelection={emptySetSelection} @@ -249,7 +276,8 @@ test('should move the existing Group from/into the drop area', async () => { const element: HTMLElement = screen.getByTestId(`Group-DropArea-${group1.id}`); const dataTransfer: DataTransfer = new DataTransfer(); - dataTransfer.setData('text/plain', group2.id); + dataTransfer.setData('draggedElementId', group2.id); + dataTransfer.setData('draggedElementType', 'Group'); fireEvent.drop(element, { dataTransfer }); await act(async () => { diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Page.test.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Page.test.tsx new file mode 100644 index 0000000000..29dfa1d15b --- /dev/null +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/Page.test.tsx @@ -0,0 +1,253 @@ +/******************************************************************************* + * Copyright (c) 2023 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 + *******************************************************************************/ +import { MockedProvider, MockedResponse } from '@apollo/client/testing'; +import { Selection } from '@eclipse-sirius/sirius-components-core'; +import { GQLPage } from '@eclipse-sirius/sirius-components-forms'; +import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { afterEach, expect, test, vi } from 'vitest'; + +import { + GQLAddPageMutationData, + GQLAddPageMutationVariables, + GQLDeletePageMutationData, + GQLDeletePageMutationVariables, + GQLFormDescriptionEditor, + GQLMovePageMutationData, + GQLMovePageMutationVariables, + GQLSuccessPayload, +} from '../FormDescriptionEditorEventFragment.types'; +import { addPageMutation, deletePageMutation, movePageMutation } from '../FormDescriptionEditorEventFragment'; +import { DataTransfer } from './DataTransfer'; +import { PageList } from '../PageList'; + +crypto.randomUUID = vi.fn(() => '48be95fc-3422-45d3-b1f9-d590e847e9e1'); + +afterEach(() => cleanup()); + +const emptySelection: Selection = { + entries: [], +}; + +const emptySetSelection = (_: Selection) => {}; + +const successPayload: GQLSuccessPayload = { + __typename: 'SuccessPayload', + id: '48be95fc-3422-45d3-b1f9-d590e847e9e1', +}; + +const addPageVariables: GQLAddPageMutationVariables = { + input: { + id: '48be95fc-3422-45d3-b1f9-d590e847e9e1', + editingContextId: 'editingContextId', + representationId: 'formDescriptionEditorId', + index: 1, + }, +}; + +const addPageSuccessData: GQLAddPageMutationData = { + addPage: successPayload, +}; + +const deletePageVariables: GQLDeletePageMutationVariables = { + input: { + id: '48be95fc-3422-45d3-b1f9-d590e847e9e1', + editingContextId: 'editingContextId', + representationId: 'formDescriptionEditorId', + pageId: 'Page1', + }, +}; + +const deletePageSuccessData: GQLDeletePageMutationData = { + deletePage: successPayload, +}; + +const movePageVariables: GQLMovePageMutationVariables = { + input: { + id: '48be95fc-3422-45d3-b1f9-d590e847e9e1', + editingContextId: 'editingContextId', + representationId: 'formDescriptionEditorId', + pageId: 'Page2', + index: 0, + }, +}; + +const movePageSuccessData: GQLMovePageMutationData = { + movePage: successPayload, +}; + +test('should drop the Page in the drop area', async () => { + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [], + }; + + const formDescriptionEditor: GQLFormDescriptionEditor = { + id: 'FormDescriptionEditor1', + pages: [page], + }; + + let addPageCalled: boolean = false; + const addPageSuccessMock: MockedResponse> = { + request: { + query: addPageMutation, + variables: addPageVariables, + }, + result: () => { + addPageCalled = true; + return { data: addPageSuccessData }; + }, + }; + + const mocks: MockedResponse>[] = [addPageSuccessMock]; + + render( + + + + ); + + const element: HTMLElement = screen.getByTestId(`PageList-DropArea`); + + const dataTransfer: DataTransfer = new DataTransfer(); + dataTransfer.setData('draggedElementId', 'Page'); + dataTransfer.setData('draggedElementType', 'Page'); + fireEvent.drop(element, { dataTransfer }); + + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 0)); + await waitFor(() => { + expect(addPageCalled).toBeTruthy(); + }); + }); +}); + +test('should delete the Page', async () => { + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [], + }; + + const formDescriptionEditor: GQLFormDescriptionEditor = { + id: 'formDescriptionEditorId', + pages: [page], + }; + + let deletePageCalled: boolean = false; + const deletePageSuccessMock: MockedResponse> = { + request: { + query: deletePageMutation, + variables: deletePageVariables, + }, + result: () => { + deletePageCalled = true; + return { data: deletePageSuccessData }; + }, + }; + + const mocks: MockedResponse>[] = [deletePageSuccessMock]; + + render( + + + + ); + + const page1: HTMLElement = screen.getByTestId('Page-Page1'); + expect(page1).not.toBeUndefined(); + + await act(async () => { + page1.focus(); + fireEvent.keyDown(page1, { key: 'Delete', code: 'NumpadDecimal' }); + await new Promise((resolve) => setTimeout(resolve, 0)); + await waitFor(() => { + expect(deletePageCalled).toBeTruthy(); + }); + }); +}); + +test('should move the existing Page into the drop area', async () => { + const page1: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [], + }; + + const page2: GQLPage = { + id: 'Page2', + label: 'Page2', + toolbarActions: [], + groups: [], + }; + + const formDescriptionEditor: GQLFormDescriptionEditor = { + id: 'formDescriptionEditorId', + pages: [page1, page2], + }; + + let movePageCalled: boolean = false; + const movePageSuccessMock: MockedResponse> = { + request: { + query: movePageMutation, + variables: movePageVariables, + }, + result: () => { + movePageCalled = true; + return { data: movePageSuccessData }; + }, + }; + + const mocks: MockedResponse>[] = [movePageSuccessMock]; + + render( + + + + ); + + const element: HTMLElement = screen.getByTestId(`Page-${page1.id}`); + + const dataTransfer: DataTransfer = new DataTransfer(); + dataTransfer.setData('draggedElementId', page2.id); + dataTransfer.setData('draggedElementType', 'Page'); + fireEvent.drop(element, { dataTransfer }); + + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 0)); + await waitFor(() => { + expect(movePageCalled).toBeTruthy(); + }); + }); +}); diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/ToolbarActions.test.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/ToolbarActions.test.tsx index 1ee9ad6da4..afa9bdc75e 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/ToolbarActions.test.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/ToolbarActions.test.tsx @@ -12,7 +12,7 @@ *******************************************************************************/ import { MockedProvider, MockedResponse } from '@apollo/client/testing'; import { Selection } from '@eclipse-sirius/sirius-components-core'; -import { GQLGroup, GQLToolbarAction } from '@eclipse-sirius/sirius-components-forms'; +import { GQLGroup, GQLPage, GQLToolbarAction } from '@eclipse-sirius/sirius-components-forms'; import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { afterEach, expect, test, vi } from 'vitest'; import { @@ -133,9 +133,16 @@ test('add ToolbarAction by clicking on the Add Toolbar Action button', async () toolbarActions: [toolbarAction], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'FormDescriptionEditor1', - groups: [group], + pages: [page], }; let addToolbarActionCalled: boolean = false; @@ -223,9 +230,16 @@ test('delete the ToolbarAction from the ToolbarActions', async () => { toolbarActions: [toolbarAction1, toolbarAction2], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'FormDescriptionEditor1', - groups: [group], + pages: [page], }; let deleteToolbarActionCalled: boolean = false; @@ -315,9 +329,16 @@ test('move the existing ToolbarAction from/into the drop area', async () => { toolbarActions: [toolbarAction1, toolbarAction2], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'FormDescriptionEditor1', - groups: [group], + pages: [page], }; let moveToolbarActionCalled: boolean = false; @@ -350,7 +371,8 @@ test('move the existing ToolbarAction from/into the drop area', async () => { const element: HTMLElement = screen.getByTestId('ToolbarAction-DropArea-ToolbarAction1'); const dataTransfer: DataTransfer = new DataTransfer(); - dataTransfer.setData('text/plain', 'ToolbarAction2'); + dataTransfer.setData('draggedElementId', 'ToolbarAction2'); + dataTransfer.setData('draggedElementType', 'ToolbarActionWidget'); fireEvent.drop(element, { dataTransfer }); await act(async () => { @@ -408,9 +430,16 @@ test('move the existing ToolbarAction from/into the drop area located at the end toolbarActions: [toolbarAction1, toolbarAction2], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'FormDescriptionEditor1', - groups: [group], + pages: [page], }; let moveToolbarActionAtTheEndCalled: boolean = false; @@ -443,7 +472,8 @@ test('move the existing ToolbarAction from/into the drop area located at the end const element: HTMLElement = screen.getByTestId(`Group-ToolbarActions-DropArea-${group.id}`); const dataTransfer: DataTransfer = new DataTransfer(); - dataTransfer.setData('text/plain', 'ToolbarAction2'); + dataTransfer.setData('draggedElementId', 'ToolbarAction2'); + dataTransfer.setData('draggedElementType', 'ToolbarActionWidget'); fireEvent.drop(element, { dataTransfer }); await act(async () => { diff --git a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/WidgetEntry.test.tsx b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/WidgetEntry.test.tsx index 569baf0644..eb72f48f44 100644 --- a/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/WidgetEntry.test.tsx +++ b/packages/formdescriptioneditors/frontend/sirius-components-formdescriptioneditors/src/__tests__/WidgetEntry.test.tsx @@ -12,7 +12,7 @@ *******************************************************************************/ import { MockedProvider, MockedResponse } from '@apollo/client/testing'; import { Selection } from '@eclipse-sirius/sirius-components-core'; -import { GQLChartWidget, GQLGroup, GQLPieChart, GQLTextfield } from '@eclipse-sirius/sirius-components-forms'; +import { GQLChartWidget, GQLGroup, GQLPage, GQLPieChart, GQLTextfield } from '@eclipse-sirius/sirius-components-forms'; import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { afterEach, expect, test, vi } from 'vitest'; import { addWidgetMutation, deleteWidgetMutation, moveWidgetMutation } from '../FormDescriptionEditorEventFragment'; @@ -118,9 +118,16 @@ test('should drop the Textfield in the drop area', async () => { toolbarActions: [], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'formDescriptionEditorId', - groups: [group], + pages: [page], }; let addWidgetCalled: boolean = false; @@ -143,6 +150,7 @@ test('should drop the Textfield in the drop area', async () => { editingContextId="editingContextId" representationId="formDescriptionEditorId" formDescriptionEditor={formDescriptionEditor} + page={page} container={group} flexDirection={'row'} flexGrow={0} @@ -156,7 +164,8 @@ test('should drop the Textfield in the drop area', async () => { const element: HTMLElement = screen.getByTestId(`WidgetEntry-DropArea-${textfieldWidget.id}`); const dataTransfer: DataTransfer = new DataTransfer(); - dataTransfer.setData('text/plain', 'Textfield'); + dataTransfer.setData('draggedElementId', 'Textfield'); + dataTransfer.setData('draggedElementType', 'Widget'); fireEvent.drop(element, { dataTransfer }); await act(async () => { @@ -196,9 +205,16 @@ test('should delete the Textfield from the drop area', async () => { toolbarActions: [], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'formDescriptionEditorId', - groups: [group], + pages: [page], }; let deleteWidgetCalled: boolean = false; @@ -221,6 +237,7 @@ test('should delete the Textfield from the drop area', async () => { editingContextId="editingContextId" representationId="formDescriptionEditorId" formDescriptionEditor={formDescriptionEditor} + page={page} container={group} flexDirection={'row'} flexGrow={0} @@ -283,9 +300,16 @@ test('should delete the PieChart from the drop area', async () => { toolbarActions: [], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'formDescriptionEditorId', - groups: [group], + pages: [page], }; let deleteWidgetCalled: boolean = false; @@ -308,6 +332,7 @@ test('should delete the PieChart from the drop area', async () => { editingContextId="editingContextId" representationId="formDescriptionEditorId" formDescriptionEditor={formDescriptionEditor} + page={page} container={group} flexDirection={'row'} flexGrow={0} @@ -359,9 +384,16 @@ test('should move the existing Textfield from/into the drop area', async () => { toolbarActions: [], }; + const page: GQLPage = { + id: 'Page1', + label: 'Page1', + toolbarActions: [], + groups: [group], + }; + const formDescriptionEditor: GQLFormDescriptionEditor = { id: 'formDescriptionEditorId', - groups: [group], + pages: [page], }; let moveWidgetCalled: boolean = false; @@ -384,6 +416,7 @@ test('should move the existing Textfield from/into the drop area', async () => { editingContextId="editingContextId" representationId="formDescriptionEditorId" formDescriptionEditor={formDescriptionEditor} + page={page} container={group} flexDirection={'row'} flexGrow={0} @@ -397,7 +430,8 @@ test('should move the existing Textfield from/into the drop area', async () => { const element: HTMLElement = screen.getByTestId(`WidgetEntry-DropArea-${textfieldWidget.id}`); const dataTransfer: DataTransfer = new DataTransfer(); - dataTransfer.setData('text/plain', 'Textfield2'); + dataTransfer.setData('draggedElementId', 'Textfield2'); + dataTransfer.setData('draggedElementType', 'Widget'); fireEvent.drop(element, { dataTransfer }); await act(async () => { diff --git a/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregator.java b/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregator.java index 5bce202afb..5615096d15 100644 --- a/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregator.java +++ b/packages/forms/backend/sirius-components-collaborative-forms/src/main/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregator.java @@ -15,11 +15,9 @@ import java.util.List; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Collectors; import org.eclipse.sirius.components.core.api.IObjectService; import org.eclipse.sirius.components.forms.description.FormDescription; -import org.eclipse.sirius.components.forms.description.GroupDescription; import org.eclipse.sirius.components.forms.description.PageDescription; import org.eclipse.sirius.components.representations.GetOrCreateRandomIdProvider; import org.eclipse.sirius.components.representations.VariableManager; @@ -36,31 +34,22 @@ public Optional aggregate(List formDescription VariableManager pageVariableManager = new VariableManager(); pageVariableManager.put(VariableManager.SELF, objects); - // @formatter:off List pageDescriptions = formDescriptions.stream() .flatMap(formDescription -> formDescription.getPageDescriptions().stream()) .filter(pageDescription -> pageDescription.getCanCreatePredicate().test(pageVariableManager)) .toList(); - // @formatter:on if (pageDescriptions.isEmpty()) { return Optional.empty(); } - // @formatter:off - List groupDescriptions = pageDescriptions.stream() - .flatMap(pageDescription -> pageDescription.getGroupDescriptions().stream()) - .collect(Collectors.toUnmodifiableList()); - Function labelProvider = variableManager -> variableManager.get(VariableManager.SELF, Object.class) .filter(self -> self instanceof List) .map(self -> (List) self) .flatMap(self -> self.stream().findFirst()) .map(objectService::getFullLabel) .orElse("Properties"); - // @formatter:on - // @formatter:off Function targetObjectIdProvider = variableManager -> variableManager.get(VariableManager.SELF, Object.class) .filter(self -> self instanceof List) .map(self -> (List) self) @@ -75,8 +64,6 @@ public Optional aggregate(List formDescription .targetObjectIdProvider(targetObjectIdProvider) .canCreatePredicate(variableManager -> false) .pageDescriptions(pageDescriptions) - .groupDescriptions(groupDescriptions) .build()); - // @formatter:on } } diff --git a/packages/forms/backend/sirius-components-collaborative-forms/src/main/resources/schema/form.graphqls b/packages/forms/backend/sirius-components-collaborative-forms/src/main/resources/schema/form.graphqls index 9a808685c7..1b43e27809 100644 --- a/packages/forms/backend/sirius-components-collaborative-forms/src/main/resources/schema/form.graphqls +++ b/packages/forms/backend/sirius-components-collaborative-forms/src/main/resources/schema/form.graphqls @@ -54,6 +54,7 @@ type Form implements Representation { type Page { id: ID! label: String! + toolbarActions: [ToolbarAction!]! groups: [Group!]! } diff --git a/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregatorTests.java b/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregatorTests.java index e0275083ad..334128ad89 100644 --- a/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregatorTests.java +++ b/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormDescriptionAggregatorTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -51,7 +51,6 @@ public void testAggregatorWithMatchingPages() { assertThat(optional).isPresent(); assertThat(optional.get().getPageDescriptions()).hasSize(3); - assertThat(optional.get().getGroupDescriptions()).hasSize(3); } @Test @@ -73,7 +72,6 @@ public void testAggregatorWithNoMatchingPages() { private FormDescription createForm(Object object, int numberOfPages, int numberOfCanCreate) { List pageDescriptions = new ArrayList<>(); - List groupDescriptions = new ArrayList<>(); int initialCount = numberOfCanCreate; for (int i = 0; i < numberOfPages; i++) { @@ -81,14 +79,12 @@ private FormDescription createForm(Object object, int numberOfPages, int numberO GroupDescription groupDescription = this.createGroup(); PageDescription pageDescription = this.createPage(object, groupDescription, canCreate); pageDescriptions.add(pageDescription); - groupDescriptions.add(groupDescription); } // @formatter:off return FormDescription.newFormDescription(UUID.randomUUID().toString()) .targetObjectIdProvider(targetObjectIdProvider -> "targetObjectId") .canCreatePredicate(variableManager -> true) - .groupDescriptions(groupDescriptions) .pageDescriptions(pageDescriptions) .idProvider(variableManager -> UUID.randomUUID().toString()) .labelProvider(variableManager -> LABEL) diff --git a/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormEventProcessorTests.java b/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormEventProcessorTests.java index 781a5140b1..19bb59da63 100644 --- a/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormEventProcessorTests.java +++ b/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/FormEventProcessorTests.java @@ -48,7 +48,6 @@ private FormDescription getFormDescription() { .idProvider(variableManager -> UUID.randomUUID().toString()) .label("formLabel") .labelProvider(variableManager -> "label") - .groupDescriptions(List.of()) .pageDescriptions(List.of()) .build(); // @formatter:on diff --git a/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/handlers/CreateFormEventHandlerTests.java b/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/handlers/CreateFormEventHandlerTests.java index 4e7779d995..5375cb6c02 100644 --- a/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/handlers/CreateFormEventHandlerTests.java +++ b/packages/forms/backend/sirius-components-collaborative-forms/src/test/java/org/eclipse/sirius/components/collaborative/forms/handlers/CreateFormEventHandlerTests.java @@ -45,6 +45,7 @@ * @author sbegaudeau */ public class CreateFormEventHandlerTests { + @Test public void testFormCreation() { // @formatter:off @@ -52,7 +53,6 @@ public void testFormCreation() { .label("label") .canCreatePredicate(variableManager -> true) .pageDescriptions(List.of()) - .groupDescriptions(List.of()) .idProvider(variableManager -> "id") .labelProvider(variableManager -> "label") .targetObjectIdProvider(variableManager -> "targetObjectId") diff --git a/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Page.java b/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Page.java index b4e9a8c90d..692774b618 100644 --- a/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Page.java +++ b/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/Page.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2022 Obeo. + * Copyright (c) 2019, 2023 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 @@ -25,10 +25,13 @@ */ @Immutable public final class Page { + private String id; private String label; + private List toolbarActions; + private List groups; private Page() { @@ -43,6 +46,10 @@ public String getLabel() { return this.label; } + public List getToolbarActions() { + return this.toolbarActions; + } + public List getGroups() { return this.groups; } @@ -64,10 +71,13 @@ public String toString() { */ @SuppressWarnings("checkstyle:HiddenField") public static final class Builder { + private String id; private String label; + private List toolbarActions = List.of(); + private List groups; private Builder(String id) { @@ -79,6 +89,11 @@ public Builder label(String label) { return this; } + public Builder toolbarActions(List toolbarActions) { + this.toolbarActions = Objects.requireNonNull(toolbarActions); + return this; + } + public Builder groups(List groups) { this.groups = Objects.requireNonNull(groups); return this; @@ -88,6 +103,7 @@ public Page build() { Page page = new Page(); page.id = Objects.requireNonNull(this.id); page.label = Objects.requireNonNull(this.label); + page.toolbarActions = Objects.requireNonNull(this.toolbarActions); page.groups = Objects.requireNonNull(this.groups); return page; } diff --git a/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/description/FormDescription.java b/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/description/FormDescription.java index ee0e484aa9..28532f57de 100644 --- a/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/description/FormDescription.java +++ b/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/description/FormDescription.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2022 Obeo. + * Copyright (c) 2019, 2023 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 @@ -32,6 +32,7 @@ @PublicApi @Immutable public final class FormDescription implements IRepresentationDescription { + private String id; private String label; @@ -46,8 +47,6 @@ public final class FormDescription implements IRepresentationDescription { private List pageDescriptions; - private List groupDescriptions; - private FormDescription() { // Prevent instantiation } @@ -83,10 +82,6 @@ public List getPageDescriptions() { return this.pageDescriptions; } - public List getGroupDescriptions() { - return this.groupDescriptions; - } - public static Builder newFormDescription(String id) { return new Builder(id); } @@ -104,6 +99,7 @@ public String toString() { */ @SuppressWarnings("checkstyle:HiddenField") public static final class Builder { + private String id; private String label; @@ -118,8 +114,6 @@ public static final class Builder { private List pageDescriptions; - private List groupDescriptions; - private Builder(String id) { this.id = Objects.requireNonNull(id); } @@ -154,11 +148,6 @@ public Builder pageDescriptions(List pageDescriptions) { return this; } - public Builder groupDescriptions(List groupDescriptions) { - this.groupDescriptions = Objects.requireNonNull(groupDescriptions); - return this; - } - public FormDescription build() { FormDescription formDescription = new FormDescription(); formDescription.id = Objects.requireNonNull(this.id); @@ -168,7 +157,6 @@ public FormDescription build() { formDescription.labelProvider = Objects.requireNonNull(this.labelProvider); formDescription.targetObjectIdProvider = Objects.requireNonNull(this.targetObjectIdProvider); formDescription.pageDescriptions = Objects.requireNonNull(this.pageDescriptions); - formDescription.groupDescriptions = Objects.requireNonNull(this.groupDescriptions); return formDescription; } } diff --git a/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java b/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java index 42b49a078b..b8dd4d1367 100644 --- a/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java +++ b/packages/forms/backend/sirius-components-forms/src/main/java/org/eclipse/sirius/components/forms/renderer/FormElementFactory.java @@ -199,7 +199,11 @@ private Form instantiateForm(FormElementProps props, List children) { } private Page instantiatePage(PageElementProps props, List children) { - // @formatter:off + List toolbarActions = children.stream() + .filter(ToolbarAction.class::isInstance) + .map(ToolbarAction.class::cast) + .toList(); + List groups = children.stream() .filter(Group.class::isInstance) .map(Group.class::cast) @@ -207,9 +211,9 @@ private Page instantiatePage(PageElementProps props, List children) { return Page.newPage(props.getId()) .label(props.getLabel()) + .toolbarActions(toolbarActions) .groups(groups) .build(); - //@formatter:on } private Group instantiateGroup(GroupElementProps props, List children) { diff --git a/packages/forms/backend/sirius-components-forms/src/test/java/org/eclipse/sirius/components/forms/render/RenderTextfieldTest.java b/packages/forms/backend/sirius-components-forms/src/test/java/org/eclipse/sirius/components/forms/render/RenderTextfieldTest.java index 1b9758079e..d2a87f9dde 100644 --- a/packages/forms/backend/sirius-components-forms/src/test/java/org/eclipse/sirius/components/forms/render/RenderTextfieldTest.java +++ b/packages/forms/backend/sirius-components-forms/src/test/java/org/eclipse/sirius/components/forms/render/RenderTextfieldTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 Obeo. + * Copyright (c) 2022, 2023 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 @@ -148,7 +148,6 @@ private FormDescription createSingleWidgetForm(TextfieldDescription textDescript .idProvider(this.constantProvider("formId")) .labelProvider(this.constantProvider("formLabel")) .canCreatePredicate(variableManager -> true) - .groupDescriptions(List.of(groupDescription)) .pageDescriptions(List.of(pageDescription)) .targetObjectIdProvider(this.constantProvider("selfId")) .build(); diff --git a/packages/forms/frontend/sirius-components-forms/src/form/FormEventFragments.types.ts b/packages/forms/frontend/sirius-components-forms/src/form/FormEventFragments.types.ts index 8a3189f1c6..b5e0bac34e 100644 --- a/packages/forms/frontend/sirius-components-forms/src/form/FormEventFragments.types.ts +++ b/packages/forms/frontend/sirius-components-forms/src/form/FormEventFragments.types.ts @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2022 Obeo. + * Copyright (c) 2021, 2023 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 @@ -101,6 +101,7 @@ export interface GQLForm { export interface GQLPage { id: string; label: string; + toolbarActions: GQLToolbarAction[]; groups: GQLGroup[]; } diff --git a/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/datafetchers/representation/RepresentationMetadataDescriptionDataFetcher.java b/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/datafetchers/representation/RepresentationMetadataDescriptionDataFetcher.java index 0b4cc9b95e..d1051fe8d3 100644 --- a/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/datafetchers/representation/RepresentationMetadataDescriptionDataFetcher.java +++ b/packages/sirius-web/backend/sirius-web-graphql/src/main/java/org/eclipse/sirius/web/graphql/datafetchers/representation/RepresentationMetadataDescriptionDataFetcher.java @@ -49,7 +49,6 @@ public class RepresentationMetadataDescriptionDataFetcher implements IDataFetche .labelProvider(variableManager -> PropertiesEventProcessorFactory.DETAILS_VIEW_ID) .targetObjectIdProvider(variableManager -> PropertiesEventProcessorFactory.DETAILS_VIEW_ID) .canCreatePredicate(variableManager -> true) - .groupDescriptions(List.of()) .pageDescriptions(List.of()) .build(); // @formatter:on @@ -62,7 +61,7 @@ public RepresentationMetadataDescriptionDataFetcher(IEditingContextEventProcesso @Override public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { - CompletableFuture result = Mono. empty().toFuture(); + CompletableFuture result = Mono.empty().toFuture(); RepresentationMetadata representationMetadata = environment.getSource(); if (Objects.equals(PropertiesEventProcessorFactory.DETAILS_VIEW_ID, representationMetadata.getDescriptionId())) { diff --git a/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/configuration/StereotypeDescriptionRegistryConfigurer.java b/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/configuration/StereotypeDescriptionRegistryConfigurer.java index 8851b1c9b4..6e56f151f9 100644 --- a/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/configuration/StereotypeDescriptionRegistryConfigurer.java +++ b/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/configuration/StereotypeDescriptionRegistryConfigurer.java @@ -13,8 +13,10 @@ package org.eclipse.sirius.web.sample.configuration; import fr.obeo.dsl.designer.sample.flow.FlowFactory; + import java.util.List; import java.util.UUID; + import org.eclipse.sirius.components.core.configuration.IStereotypeDescriptionRegistry; import org.eclipse.sirius.components.core.configuration.IStereotypeDescriptionRegistryConfigurer; import org.eclipse.sirius.components.core.configuration.StereotypeDescription; @@ -55,6 +57,10 @@ public class StereotypeDescriptionRegistryConfigurer implements IStereotypeDescr public static final String BIG_GUY_FLOW_LABEL = "Big Guy Flow (17k elements)"; + public static final UUID EMPTY_VIEW_ID = UUID.nameUUIDFromBytes("empty_view".getBytes()); + + public static final String EMPTY_VIEW_LABEL = "View"; + private static final UUID EMPTY_DOMAIN_ID = UUID.nameUUIDFromBytes("empty_domain".getBytes()); private static final String EMPTY_DOMAIN_LABEL = "Domain"; @@ -63,10 +69,6 @@ public class StereotypeDescriptionRegistryConfigurer implements IStereotypeDescr private static final String PAPAYA_DOMAIN_LABEL = "Papaya Domain"; - private static final UUID EMPTY_VIEW_ID = UUID.nameUUIDFromBytes("empty_view".getBytes()); - - private static final String EMPTY_VIEW_LABEL = "View"; - private static final UUID PAPAYA_VIEW_ID = UUID.nameUUIDFromBytes("papaya_view".getBytes()); private static final String PAPAYA_VIEW_LABEL = "Papaya View"; diff --git a/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/papaya/view/overviewform/OverviewFormProvider.java b/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/papaya/view/overviewform/OverviewFormProvider.java index f9b91e0f15..ac7df977c0 100644 --- a/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/papaya/view/overviewform/OverviewFormProvider.java +++ b/packages/sirius-web/backend/sirius-web-sample-application/src/main/java/org/eclipse/sirius/web/sample/papaya/view/overviewform/OverviewFormProvider.java @@ -29,12 +29,17 @@ public RepresentationDescription create(IColorProvider colorProvider) { formDescription.setDomainType("papaya_core::Root"); formDescription.setName("Overview Form"); + var pageDescription = ViewFactory.eINSTANCE.createPageDescription(); + pageDescription.setName("Page"); + pageDescription.setSemanticCandidatesExpression("aql:self"); + var groupDescription = ViewFactory.eINSTANCE.createGroupDescription(); groupDescription.setName("Group"); groupDescription.setSemanticCandidatesExpression("aql:self"); groupDescription.setLabelExpression("Root"); - formDescription.getGroups().add(groupDescription); + pageDescription.getGroups().add(groupDescription); + formDescription.getPages().add(pageDescription); return formDescription; } diff --git a/packages/sirius-web/backend/sirius-web-sample-application/src/test/java/org/eclipse/sirius/web/sample/tests/integration/formdescritpioneditors/FormDescriptionEditorPageIntegrationTests.java b/packages/sirius-web/backend/sirius-web-sample-application/src/test/java/org/eclipse/sirius/web/sample/tests/integration/formdescritpioneditors/FormDescriptionEditorPageIntegrationTests.java new file mode 100644 index 0000000000..615ff7ae22 --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-sample-application/src/test/java/org/eclipse/sirius/web/sample/tests/integration/formdescritpioneditors/FormDescriptionEditorPageIntegrationTests.java @@ -0,0 +1,466 @@ +/******************************************************************************* + * Copyright (c) 2023 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.web.sample.tests.integration.formdescritpioneditors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; + +import java.time.Duration; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; + +import org.eclipse.sirius.components.collaborative.dto.CreateChildInput; +import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput; +import org.eclipse.sirius.components.collaborative.dto.CreateRootObjectInput; +import org.eclipse.sirius.components.collaborative.editingcontext.EditingContextEventProcessorRegistry; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.FormDescriptionEditorConfiguration; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorEventProcessor; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.AddPageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.DeletePageInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.FormDescriptionEditorEventInput; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.FormDescriptionEditorRefreshedEventPayload; +import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.MovePageInput; +import org.eclipse.sirius.components.core.api.IPayload; +import org.eclipse.sirius.components.forms.Page; +import org.eclipse.sirius.components.graphql.api.IEventProcessorSubscriptionProvider; +import org.eclipse.sirius.web.persistence.repositories.IProjectRepository; +import org.eclipse.sirius.web.sample.configuration.StereotypeDescriptionRegistryConfigurer; +import org.eclipse.sirius.web.sample.tests.integration.AbstractIntegrationTests; +import org.eclipse.sirius.web.services.api.document.CreateDocumentInput; +import org.eclipse.sirius.web.services.api.projects.CreateProjectInput; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import graphql.ExecutionInput; +import graphql.GraphQL; +import reactor.test.StepVerifier; + +/** + * Integration tests of the page concept in form description editor. + * + * @author frouene + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@SuppressWarnings("checkstyle:MultipleStringLiterals") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class FormDescriptionEditorPageIntegrationTests extends AbstractIntegrationTests { + + @Autowired + private GraphQL graphQL; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private IProjectRepository projectRepository; + + @Autowired + private EditingContextEventProcessorRegistry editingContextEventProcessorRegistry; + + @Autowired + private IEventProcessorSubscriptionProvider eventProcessorSubscriptionProvider; + + private UUID projectId; + + private UUID rootObjectId; + + private UUID formDescriptionObjectId; + + private UUID representationId; + + @BeforeEach + public void setup() { + this.createProject(); + this.createProjectContent(); + this.createFormDescriptor(); + this.createFormDescriptionEditor(); + } + + @AfterEach + public void teardown() { + this.editingContextEventProcessorRegistry.dispose(); + this.projectRepository.deleteAll(); + } + + + private void createProject() { + var query = """ + mutation createProject($input: CreateProjectInput!) { + createProject(input: $input) { + __typename + ... on CreateProjectSuccessPayload { + project { + id + } + } + } + } + """; + + var input = new CreateProjectInput(UUID.randomUUID(), "Instance"); + + var executionInput = ExecutionInput.newExecutionInput() + .query(query) + .variables(Map.of("input", this.objectMapper.convertValue(input, new TypeReference>() { + }))) + .build(); + var executionResult = this.graphQL.execute(executionInput); + assertThat(executionResult.getErrors()).isEmpty(); + + try { + var jsonResult = this.objectMapper.writeValueAsString(executionResult.toSpecification()); + String responseTypeName = JsonPath.read(jsonResult, "$.data.createProject.__typename"); + assertThat(responseTypeName).isEqualTo("CreateProjectSuccessPayload"); + + String rawProjectId = JsonPath.read(jsonResult, "$.data.createProject.project.id"); + this.projectId = UUID.fromString(rawProjectId); + } catch (JsonProcessingException | IllegalArgumentException exception) { + fail(exception.getMessage()); + } + + assertThat(this.projectRepository.existsById(this.projectId)).isTrue(); + } + + private void createProjectContent() { + var createDocumentQuery = """ + mutation createDocument($input: CreateDocumentInput!) { + createDocument(input: $input) { + __typename + ... on CreateDocumentSuccessPayload { + document { + id + } + } + } + } + """; + + assertThat(this.projectRepository.existsById(this.projectId)).isTrue(); + + var createDocumentInput = new CreateDocumentInput(UUID.randomUUID(), this.projectId.toString(), StereotypeDescriptionRegistryConfigurer.EMPTY_VIEW_LABEL, StereotypeDescriptionRegistryConfigurer.EMPTY_VIEW_ID); + + var createDocumentExecutionInput = ExecutionInput.newExecutionInput() + .query(createDocumentQuery) + .variables(Map.of("input", this.objectMapper.convertValue(createDocumentInput, new TypeReference>() { + }))) + .build(); + var createDocumentExecutionResult = this.graphQL.execute(createDocumentExecutionInput); + assertThat(createDocumentExecutionResult.getErrors()).isEmpty(); + + UUID documentId = null; + try { + var jsonResult = this.objectMapper.writeValueAsString(createDocumentExecutionResult.toSpecification()); + String responseTypeName = JsonPath.read(jsonResult, "$.data.createDocument.__typename"); + assertThat(responseTypeName).isEqualTo("CreateDocumentSuccessPayload"); + + String rawDocumentId = JsonPath.read(jsonResult, "$.data.createDocument.document.id"); + documentId = UUID.fromString(rawDocumentId); + } catch (JsonProcessingException | IllegalArgumentException exception) { + fail(exception.getMessage()); + } + + var createRootObjectQuery = """ + mutation createRootObject($input: CreateRootObjectInput!) { + createRootObject(input: $input) { + __typename + ... on CreateRootObjectSuccessPayload { + object { + id + } + } + } + } + """; + + var createRootObjectInput = new CreateRootObjectInput(UUID.randomUUID(), this.projectId.toString(), documentId, "http://www.eclipse.org/sirius-web/view", "View"); + + var createRootObjectExecutionInput = ExecutionInput.newExecutionInput() + .query(createRootObjectQuery) + .variables(Map.of("input", this.objectMapper.convertValue(createRootObjectInput, new TypeReference>() { + }))) + .build(); + var createRootObjectExecutionResult = this.graphQL.execute(createRootObjectExecutionInput); + assertThat(createRootObjectExecutionResult.getErrors()).isEmpty(); + + try { + var jsonResult = this.objectMapper.writeValueAsString(createRootObjectExecutionResult.toSpecification()); + String responseTypeName = JsonPath.read(jsonResult, "$.data.createRootObject.__typename"); + assertThat(responseTypeName).isEqualTo("CreateRootObjectSuccessPayload"); + + String rawObjectId = JsonPath.read(jsonResult, "$.data.createRootObject.object.id"); + this.rootObjectId = UUID.fromString(rawObjectId); + } catch (JsonProcessingException exception) { + fail(exception.getMessage()); + } + + } + + private void createFormDescriptor() { + var createChildQuery = """ + mutation createChild($input: CreateChildInput!) { + createChild(input: $input) { + __typename + ... on CreateChildSuccessPayload { + object { + id + } + } + ... on ErrorPayload { message __typename } + } + } + """; + + var createChildInput = new CreateChildInput(UUID.randomUUID(), this.projectId.toString(), rootObjectId.toString(), "Form Description"); + + var createChildExecutionInput = ExecutionInput.newExecutionInput() + .query(createChildQuery) + .variables(Map.of("input", this.objectMapper.convertValue(createChildInput, new TypeReference>() { + }))) + .build(); + var createChildExecutionResult = this.graphQL.execute(createChildExecutionInput); + assertThat(createChildExecutionResult.getErrors()).isEmpty(); + + try { + var jsonResult = this.objectMapper.writeValueAsString(createChildExecutionResult.toSpecification()); + String responseTypeName = JsonPath.read(jsonResult, "$.data.createChild.__typename"); + assertThat(responseTypeName).isEqualTo("CreateChildSuccessPayload"); + + String rawObjectId = JsonPath.read(jsonResult, "$.data.createChild.object.id"); + this.formDescriptionObjectId = UUID.fromString(rawObjectId); + } catch (JsonProcessingException exception) { + fail(exception.getMessage()); + } + } + + private void createFormDescriptionEditor() { + var getRepresentationDescriptionsQuery = """ + query getRepresentationDescriptions($editingContextId: ID!, $objectId: ID!) { + viewer { + editingContext(editingContextId: $editingContextId) { + representationDescriptions(objectId: $objectId) { + edges { + node { + id + } + } + } + } + } + } + """; + + var getRepresentationDescriptionsExecutionInput = ExecutionInput.newExecutionInput() + .query(getRepresentationDescriptionsQuery) + .variables(Map.of("editingContextId", this.projectId.toString(), "objectId", this.formDescriptionObjectId.toString())) + .build(); + var getRepresentationDescriptionsExecutionResult = this.graphQL.execute(getRepresentationDescriptionsExecutionInput); + assertThat(getRepresentationDescriptionsExecutionResult.getErrors()).isEmpty(); + + String representationDescriptionId = null; + try { + var jsonResult = this.objectMapper.writeValueAsString(getRepresentationDescriptionsExecutionResult.toSpecification()); + representationDescriptionId = JsonPath.read(jsonResult, "$.data.viewer.editingContext.representationDescriptions.edges[0].node.id"); + } catch (JsonProcessingException exception) { + fail(exception.getMessage()); + } + + var query = """ + mutation createRepresentation($input: CreateRepresentationInput!) { + createRepresentation(input: $input) { + __typename + ... on CreateRepresentationSuccessPayload { + representation { + id + } + } + } + } + """; + + var input = new CreateRepresentationInput(UUID.randomUUID(), this.projectId.toString(), representationDescriptionId, this.formDescriptionObjectId.toString(), + "FormDescriptionEditor"); + var executionInput = ExecutionInput.newExecutionInput() + .query(query) + .variables(Map.of("input", this.objectMapper.convertValue(input, new TypeReference>() { + }))) + .build(); + var executionResult = this.graphQL.execute(executionInput); + assertThat(executionResult.getErrors()).isEmpty(); + + try { + var jsonResult = this.objectMapper.writeValueAsString(executionResult.toSpecification()); + String rawRepresentationId = JsonPath.read(jsonResult, "$.data.createRepresentation.representation.id"); + this.representationId = UUID.fromString(rawRepresentationId); + } catch (JsonProcessingException | IllegalArgumentException exception) { + fail(exception.getMessage()); + } + } + + @Test + public void testPageMutations() { + var configuration = new FormDescriptionEditorConfiguration(this.representationId.toString()); + var input = new FormDescriptionEditorEventInput(UUID.randomUUID(), this.projectId.toString(), this.representationId.toString()); + var payloadFlux = this.eventProcessorSubscriptionProvider.getSubscription(this.projectId.toString(), IFormDescriptionEditorEventProcessor.class, configuration, input); + AtomicReference defaultPageId = new AtomicReference<>(); + AtomicReference newPageId = new AtomicReference<>(); + + Predicate isInitiatedWithOnePageFormDescriptionEditorRefreshedEventPayload = payload -> { + if (payload instanceof FormDescriptionEditorRefreshedEventPayload formDescriptionEditorRefreshedEventPayload) { + var formDescriptionEditor = formDescriptionEditorRefreshedEventPayload.formDescriptionEditor(); + defaultPageId.set(formDescriptionEditor.getPages().get(0).getId()); + return formDescriptionEditor.getPages().size() == 1; + } + return false; + }; + + Predicate afterAddPageFormDescriptionEditorRefreshedEventPayload = payload -> { + if (payload instanceof FormDescriptionEditorRefreshedEventPayload formDescriptionEditorRefreshedEventPayload) { + var formDescriptionEditor = formDescriptionEditorRefreshedEventPayload.formDescriptionEditor(); + newPageId.set(formDescriptionEditor.getPages().get(1).getId()); + return formDescriptionEditor.getPages().size() == 2 && formDescriptionEditor.getPages().stream().map(Page::getId).toList().indexOf(defaultPageId.get()) == 0; + } + return false; + }; + + Predicate afterMovePageFormDescriptionEditorRefreshedEventPayload = payload -> { + if (payload instanceof FormDescriptionEditorRefreshedEventPayload formDescriptionEditorRefreshedEventPayload) { + var formDescriptionEditor = formDescriptionEditorRefreshedEventPayload.formDescriptionEditor(); + return formDescriptionEditor.getPages().size() == 2 && formDescriptionEditor.getPages().stream().map(Page::getId).toList().indexOf(newPageId.get()) == 0; + } + return false; + }; + + Predicate afterDeletePageFormDescriptionEditorRefreshedEventPayload = payload -> { + if (payload instanceof FormDescriptionEditorRefreshedEventPayload formDescriptionEditorRefreshedEventPayload) { + var formDescriptionEditor = formDescriptionEditorRefreshedEventPayload.formDescriptionEditor(); + return formDescriptionEditor.getPages().size() == 1 && !formDescriptionEditor.getPages().stream().map(Page::getId).toList().contains(newPageId.get()); + } + return false; + }; + + + StepVerifier.create(payloadFlux) + .expectNextMatches(isInitiatedWithOnePageFormDescriptionEditorRefreshedEventPayload) + .then(this::addPageMutation) + .expectNextMatches(afterAddPageFormDescriptionEditorRefreshedEventPayload) + .then(() -> movePageMutation(newPageId.get())) + .expectNextMatches(afterMovePageFormDescriptionEditorRefreshedEventPayload) + .then(() -> deletePageMutation(newPageId.get())) + .expectNextMatches(afterDeletePageFormDescriptionEditorRefreshedEventPayload) + .thenCancel() + .verify(Duration.ofSeconds(10)); + + } + + private void addPageMutation() { + var query = """ + mutation addPage($input: AddPageInput!) { + addPage(input: $input) { + __typename + ... on SuccessPayload { + __typename + } + } + } + """; + + var input = new AddPageInput(UUID.randomUUID(), this.projectId.toString(), this.representationId.toString(), 1); + var executionInput = ExecutionInput.newExecutionInput() + .query(query) + .variables(Map.of("input", this.objectMapper.convertValue(input, new TypeReference>() { + }))) + .build(); + var executionResult = this.graphQL.execute(executionInput); + assertThat(executionResult.getErrors()).isEmpty(); + + try { + var jsonResult = this.objectMapper.writeValueAsString(executionResult.toSpecification()); + String responseTypeName = JsonPath.read(jsonResult, "$.data.addPage.__typename"); + assertThat(responseTypeName).isEqualTo("SuccessPayload"); + } catch (JsonProcessingException | IllegalArgumentException exception) { + fail(exception.getMessage()); + } + + } + + private void movePageMutation(String pageId) { + var query = """ + mutation movePage($input: MovePageInput!) { + movePage(input: $input) { + __typename + ... on SuccessPayload { + __typename + } + } + } + """; + + var input = new MovePageInput(UUID.randomUUID(), this.projectId.toString(), this.representationId.toString(), pageId, 0); + var executionInput = ExecutionInput.newExecutionInput() + .query(query) + .variables(Map.of("input", this.objectMapper.convertValue(input, new TypeReference>() { + }))) + .build(); + var executionResult = this.graphQL.execute(executionInput); + assertThat(executionResult.getErrors()).isEmpty(); + + try { + var jsonResult = this.objectMapper.writeValueAsString(executionResult.toSpecification()); + String responseTypeName = JsonPath.read(jsonResult, "$.data.movePage.__typename"); + assertThat(responseTypeName).isEqualTo("SuccessPayload"); + } catch (JsonProcessingException | IllegalArgumentException exception) { + fail(exception.getMessage()); + } + } + + private void deletePageMutation(String pageId) { + var query = """ + mutation deletePage($input: DeletePageInput!) { + deletePage(input: $input) { + __typename + ... on SuccessPayload { + __typename + } + } + } + """; + + var input = new DeletePageInput(UUID.randomUUID(), this.projectId.toString(), this.representationId.toString(), pageId); + var executionInput = ExecutionInput.newExecutionInput() + .query(query) + .variables(Map.of("input", this.objectMapper.convertValue(input, new TypeReference>() { + }))) + .build(); + var executionResult = this.graphQL.execute(executionInput); + assertThat(executionResult.getErrors()).isEmpty(); + + try { + var jsonResult = this.objectMapper.writeValueAsString(executionResult.toSpecification()); + String responseTypeName = JsonPath.read(jsonResult, "$.data.deletePage.__typename"); + assertThat(responseTypeName).isEqualTo("SuccessPayload"); + } catch (JsonProcessingException | IllegalArgumentException exception) { + fail(exception.getMessage()); + } + } +} diff --git a/packages/sirius-web/backend/sirius-web-sample-application/src/test/resources/ViewCompletionFixture.xmi b/packages/sirius-web/backend/sirius-web-sample-application/src/test/resources/ViewCompletionFixture.xmi index 143d38e571..49e5b13101 100644 --- a/packages/sirius-web/backend/sirius-web-sample-application/src/test/resources/ViewCompletionFixture.xmi +++ b/packages/sirius-web/backend/sirius-web-sample-application/src/test/resources/ViewCompletionFixture.xmi @@ -37,51 +37,53 @@ - - -