Skip to content

Commit

Permalink
[1169] Add support for deletion of widgets in FormDescriptionEditor
Browse files Browse the repository at this point in the history
Bug: #1169
Signed-off-by: Axel RICHARD <axel.richard@obeo.fr>
  • Loading branch information
AxelRICHARD authored and sbegaudeau committed May 16, 2022
1 parent 39a51ea commit 52a3465
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright (c) 2022 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.text.MessageFormat;
import java.util.Objects;
import java.util.UUID;

import org.eclipse.sirius.components.collaborative.formdescriptioneditors.api.IFormDescriptionEditorInput;

/**
* The input for the Form Description Editor delete widget mutation.
*
* @author arichard
*/
public class DeleteWidgetInput implements IFormDescriptionEditorInput {

private UUID id;

private String editingContextId;

private String representationId;

private String widgetId;

public DeleteWidgetInput() {
// Used by jackson
}

public DeleteWidgetInput(UUID id, String editingContextId, String representationId) {
this.id = Objects.requireNonNull(id);
this.editingContextId = Objects.requireNonNull(editingContextId);
this.representationId = Objects.requireNonNull(representationId);
}

@Override
public UUID getId() {
return this.id;
}

@Override
public String getRepresentationId() {
return this.representationId;
}

public String getEditingContextId() {
return this.editingContextId;
}

public String getWidgetId() {
return this.widgetId;
}

@Override
public String toString() {
String pattern = "{0} '{'id: {1}, editingContextId: {2}, representationId: {3}; widgetId: {4}}'"; //$NON-NLS-1$
return MessageFormat.format(pattern, this.getClass().getSimpleName(), this.id, this.editingContextId, this.representationId, this.widgetId);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2022 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.text.MessageFormat;
import java.util.Objects;
import java.util.UUID;

import org.eclipse.sirius.components.core.api.IPayload;

/**
* The payload of the Form Description Editor delete widget mutation.
*
* @author arichard
*/
public class DeleteWidgetSuccessPayload implements IPayload {
private final UUID id;

public DeleteWidgetSuccessPayload(UUID id) {
this.id = Objects.requireNonNull(id);
}

@Override
public UUID getId() {
return this.id;
}

@Override
public String toString() {
String pattern = "{0} '{'id: {1}'}'"; //$NON-NLS-1$
return MessageFormat.format(pattern, this.getClass().getSimpleName(), this.id);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import reactor.core.publisher.Sinks.One;

/**
* Handle the arrange all events.
* Handle the add widget event on Form Description Editor.
*
* @author arichard
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*******************************************************************************
* Copyright (c) 2022 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.DeleteWidgetInput;
import org.eclipse.sirius.components.collaborative.formdescriptioneditors.dto.DeleteWidgetSuccessPayload;
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.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 widget event on Form Description Editor.
*
* @author arichard
*/
@Service
public class DeleteWidgetEventHandler implements IFormDescriptionEditorEventHandler {

private final IObjectService objectService;

private final IEditService editService;

private final ICollaborativeFormDescriptionEditorMessageService messageService;

private final Counter counter;

public DeleteWidgetEventHandler(IObjectService objectService, IEditService editService, ICollaborativeFormDescriptionEditorMessageService messageService, MeterRegistry meterRegistry) {
this.objectService = Objects.requireNonNull(objectService);
this.editService = Objects.requireNonNull(editService);
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
public boolean canHandle(IFormDescriptionEditorInput formDescriptionEditorInput) {
return formDescriptionEditorInput instanceof DeleteWidgetInput;
}

@Override
public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDescriptionSink, IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext,
IFormDescriptionEditorInput formDescriptionEditorInput) {
this.counter.increment();

String message = this.messageService.invalidInput(formDescriptionEditorInput.getClass().getSimpleName(), DeleteWidgetInput.class.getSimpleName());
IPayload payload = new ErrorPayload(formDescriptionEditorInput.getId(), message);
ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, formDescriptionEditorInput.getRepresentationId(), formDescriptionEditorInput);

if (formDescriptionEditorInput instanceof DeleteWidgetInput) {
String widgetId = ((DeleteWidgetInput) formDescriptionEditorInput).getWidgetId();
boolean deleteWidget = this.deleteWidget(editingContext, formDescriptionEditorContext, widgetId);
if (deleteWidget) {
payload = new DeleteWidgetSuccessPayload(formDescriptionEditorInput.getId());
changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, formDescriptionEditorInput.getRepresentationId(), formDescriptionEditorInput);
}
}

payloadSink.tryEmitValue(payload);
changeDescriptionSink.tryEmitNext(changeDescription);
}

protected boolean deleteWidget(IEditingContext editingContext, IFormDescriptionEditorContext formDescriptionEditorContext, String widgetId) {
var optionalSelf = this.objectService.getObject(editingContext, widgetId);
if (optionalSelf.isPresent()) {
this.editService.delete(optionalSelf.get());
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type FormDescriptionEditorWidget {

extend type Mutation {
addWidget(input: AddWidgetInput!): AddWidgetPayload!
deleteWidget(input: DeleteWidgetInput!): DeleteWidgetPayload!
}

input AddWidgetInput {
Expand All @@ -48,4 +49,17 @@ union AddWidgetPayload = AddWidgetSuccessPayload | ErrorPayload

type AddWidgetSuccessPayload {
id: ID!
}

input DeleteWidgetInput {
id: ID!
editingContextId: ID!
representationId: ID!
widgetId: String!
}

union DeleteWidgetPayload = DeleteWidgetSuccessPayload | ErrorPayload

type DeleteWidgetSuccessPayload {
id: ID!
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,17 @@ export const addWidgetMutation = gql`
}
}
`;

export const deleteWidgetMutation = gql`
mutation deleteWidget($input: DeleteWidgetInput!) {
deleteWidget(input: $input) {
__typename
... on DeleteWidgetSuccessPayload {
id
}
... on ErrorPayload {
message
}
}
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,29 @@ export interface GQLAddWidgetSuccessPayload extends GQLAddWidgetPayload {
id: string;
}

export interface GQLErrorPayload extends GQLAddWidgetPayload {
export interface GQLDeleteWidgetInput {
id: string;
editingContextId: string;
representationId: string;
widgetId: string;
}

export interface GQLDeleteWidgetMutationVariables {
input: GQLDeleteWidgetInput;
}

export interface GQLDeleteWidgetMutationData {
deleteWidget: GQLDeleteWidgetPayload;
}

export interface GQLDeleteWidgetPayload {
__typename: string;
}

export interface GQLDeleteWidgetSuccessPayload extends GQLDeleteWidgetPayload {
id: string;
}

export interface GQLErrorPayload extends GQLAddWidgetPayload, GQLDeleteWidgetPayload {
message: string;
}
46 changes: 44 additions & 2 deletions frontend/src/formdescriptioneditor/WidgetEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ import React, { useEffect, useState } from 'react';
import { v4 as uuid } from 'uuid';
import { Selection } from 'workbench/Workbench.types';
import { CheckboxWidget } from './CheckboxWidget';
import { addWidgetMutation } from './FormDescriptionEditorEventFragment';
import { addWidgetMutation, deleteWidgetMutation } from './FormDescriptionEditorEventFragment';
import {
GQLAddWidgetInput,
GQLAddWidgetMutationData,
GQLAddWidgetMutationVariables,
GQLAddWidgetPayload,
GQLDeleteWidgetInput,
GQLDeleteWidgetMutationData,
GQLDeleteWidgetMutationVariables,
GQLErrorPayload,
GQLFormDescriptionEditorWidget,
} from './FormDescriptionEditorEventFragment.types';
Expand Down Expand Up @@ -105,6 +108,31 @@ export const WidgetEntry = ({
}
}, [addWidgetLoading, addWidgetData, addWidgetError]);

const [deleteWidget, { loading: deleteWidgetLoading, data: deleteWidgetData, error: deleteWidgetError }] =
useMutation<GQLDeleteWidgetMutationData, GQLDeleteWidgetMutationVariables>(deleteWidgetMutation);

useEffect(() => {
if (!deleteWidgetLoading) {
if (deleteWidgetError) {
setState((prevState) => {
const newState = { ...prevState };
newState.message = deleteWidgetError.message;
return newState;
});
}
if (deleteWidgetData) {
const { deleteWidget } = deleteWidgetData;
if (isErrorPayload(deleteWidget)) {
setState((prevState) => {
const newState = { ...prevState };
newState.message = deleteWidget.message;
return newState;
});
}
}
}
}, [deleteWidgetLoading, deleteWidgetData, deleteWidgetError]);

const handleClick: React.MouseEventHandler<HTMLDivElement> = (event) => {
const newSelection: Selection = {
entries: [
Expand All @@ -118,6 +146,20 @@ export const WidgetEntry = ({
setSelection(newSelection);
};

const handleDelete: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
event.preventDefault();
if (event.key === 'Delete') {
const deleteWidgetInput: GQLDeleteWidgetInput = {
id: uuid(),
editingContextId,
representationId,
widgetId: widget.id,
};
const deleteWidgetVariables: GQLDeleteWidgetMutationVariables = { input: deleteWidgetInput };
deleteWidget({ variables: deleteWidgetVariables });
}
};

const handleDragEnter: React.DragEventHandler<HTMLDivElement> = (event) => {
event.preventDefault();
event.currentTarget.classList.add(classes.dragOver);
Expand Down Expand Up @@ -217,7 +259,7 @@ export const WidgetEntry = ({
);
}
return (
<div className={classes.widget} onClick={handleClick}>
<div className={classes.widget} onClick={handleClick} onKeyDown={handleDelete}>
<div
data-testid="WidgetEntry-DropArea"
className={classes.placeholder}
Expand Down
Loading

0 comments on commit 52a3465

Please sign in to comment.