Skip to content

Commit

Permalink
[3655] Support "Delete Task Dependency" tool in gantt
Browse files Browse the repository at this point in the history
Bug: #3655
Signed-off-by: Laurent Fasani <[email protected]>
  • Loading branch information
lfasani committed Jun 21, 2024
1 parent 822adbe commit 6b92aa0
Show file tree
Hide file tree
Showing 55 changed files with 1,275 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ This dialog presents diagram elements in a tree and allows to select them and up
+
image:doc/screenshots/diagramFilterView.png[Diagram Filter View, 70%]
- https://github.com/eclipse-sirius/sirius-web/issues/3523[#3523] [gantt] Support rounding dates when changing dates from gantt
- https://github.com/eclipse-sirius/sirius-web/issues/3655[#3655] [gantt] Support "Delete Task Dependency" tool in gantt

=== Improvements

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/specifier/images/gantt-task-handlers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 9 additions & 2 deletions doc/specifier/representation-gantt.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Available variables:
** `newStartTime`: The new value of the start time.
** `newEndTime`: The new value of the end time.
** `newDescription`: The new value of the description.
** `newProgress`: The new value of the progress.
** `newProgress`: The new value of the progress.
image::images/gantt-task-handlers.png[Task handlers]

Expand All @@ -121,7 +121,14 @@ index=0 means first position.
This tool defines the behavior when creating a task dependency by dragging the dependency handler from one task to another.
Available variables:
** `sourceObject`: The semantic element associated with the task from which the dependency link is initiated.
** `targetObject`: The semantic element associated with the target task where the dependency finishes.
** `targetObject`: The semantic element associated with the dependant task where the dependency finishes.
image::images/gantt-task-relation-tool.png[Create Task Dependency Tool]
* `Delete Task Dependency Tool`:
This tool defines the behavior when deleting a task dependency using the button in the task dependency contextual palette in Gantt.
Available variables:
** `sourceObject`: The semantic element associated with the task from which the dependency link is initiated.
** `targetObject`: The semantic element associated with the dependant task where the dependency finishes.

image:images/gantt-task-dependency-palette.png[Task Dependency Contextual Palette]

Binary file added doc/user/images/gantt-task-dependency-palette.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/user/images/gantt-task-handlers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/user/images/gantt-task-palette.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 16 additions & 1 deletion doc/user/representation-gantt.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ When selecting a `Task` in Gantt or in the Table, the associated semantic elemen
Using handlers on the task, it is possible to change the start/end dates and the progress.
Clicking on the task and moving it left or right, allows to shift the date keeping the same duration.

image:images/gantt-task-handlers.png[Show/Hide Cards]
image:images/gantt-task-handlers.png[Task handlers]

When changing a date, the date is rounded accordingly to the `Date Rounding Expression` define in the `GanttDescription`.
Holiday is set as Saturday and Sunday. If the rounded date is part of the holiday, it is moved to the next or previous working date.
Expand All @@ -78,6 +78,21 @@ image:images/gantt-task-dependency-tool.png[Task Dependency Tool]
image:images/gantt-task-dependency.png[Task Dependency]


### Task dependency relation

Clicking on a task displays a contextual menu.

* `Create Task`: It will invoke `Create Task Tool`
* `Delete Task`: It will invoke `Delete Task Tool`
image:images/gantt-task-palette.png[Task Contextual Palette]

Clicking on a task dependency displays a contextual menu.

* `Delete Task Dependency`: It will invoke `Create Task Dependency Tool`
image:images/gantt-task-dependency-palette.png[Task Dependency Contextual Palette]

### Task reordering

From the table, it is possible to drag and drop a Task to reorder the task or change its container.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.eclipse.sirius.components.collaborative.gantt.dto.input.ChangeTaskCollapseStateInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.CreateGanttTaskDependencyInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.CreateGanttTaskInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.DeleteGanttTaskDependencyInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.DeleteGanttTaskInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.DropGanttTaskInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.EditGanttTaskInput;
Expand Down Expand Up @@ -55,6 +56,11 @@ public interface IGanttTaskService {
*/
IPayload createTaskDependency(CreateGanttTaskDependencyInput createTaskDependencyInput, IEditingContext editingContext, Gantt gantt);

/**
* Delete a dependency between two tasks.
*/
IPayload deleteTaskDependency(DeleteGanttTaskDependencyInput createTaskDependencyInput, IEditingContext editingContext, Gantt gantt);

/**
* Change the state collapse of a task.
*/
Expand Down Expand Up @@ -97,6 +103,11 @@ public IPayload createTaskDependency(CreateGanttTaskDependencyInput createTaskDe
return null;
}

@Override
public IPayload deleteTaskDependency(DeleteGanttTaskDependencyInput createTaskDependencyInput, IEditingContext editingContext, Gantt gantt) {
return null;
}

@Override
public IPayload changeTaskCollapseState(ChangeTaskCollapseStateInput changeTaskCollapseStateInput, IEditingContext editingContext, IGanttContext ganttContext) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.gantt.dto.input;

import java.util.Objects;
import java.util.UUID;

import org.eclipse.sirius.components.collaborative.gantt.api.IGanttInput;

/**
* The input of the "Delete task dependency" mutation.
*
* @author lfasani
*/
public record DeleteGanttTaskDependencyInput(UUID id, String editingContextId, String representationId, String sourceTaskId, String targetTaskId) implements IGanttInput {
public DeleteGanttTaskDependencyInput {
Objects.requireNonNull(id);
Objects.requireNonNull(editingContextId);
Objects.requireNonNull(representationId);
Objects.requireNonNull(sourceTaskId);
Objects.requireNonNull(targetTaskId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.collaborative.gantt.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.gantt.api.IGanttContext;
import org.eclipse.sirius.components.collaborative.gantt.api.IGanttEventHandler;
import org.eclipse.sirius.components.collaborative.gantt.api.IGanttInput;
import org.eclipse.sirius.components.collaborative.gantt.api.IGanttTaskService;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.DeleteGanttTaskDependencyInput;
import org.eclipse.sirius.components.collaborative.gantt.message.ICollaborativeGanttMessageService;
import org.eclipse.sirius.components.core.api.ErrorPayload;
import org.eclipse.sirius.components.core.api.IEditingContext;
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 "Delete Task Dependency" events.
*
* @author lfasani
*/
@Service
public class DeleteTaskDependencyEventHandler implements IGanttEventHandler {

private final IGanttTaskService ganttTaskService;

private final ICollaborativeGanttMessageService messageService;

private final Counter counter;

public DeleteTaskDependencyEventHandler(IGanttTaskService ganttTaskService, ICollaborativeGanttMessageService messageService, MeterRegistry meterRegistry) {
this.ganttTaskService = Objects.requireNonNull(ganttTaskService);
this.messageService = Objects.requireNonNull(messageService);

this.counter = Counter.builder(Monitoring.EVENT_HANDLER).tag(Monitoring.NAME, this.getClass().getSimpleName()).register(meterRegistry);
}

@Override
public boolean canHandle(IGanttInput ganttInput) {
return ganttInput instanceof DeleteGanttTaskDependencyInput;
}

@Override
public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDescriptionSink, IEditingContext editingContext, IGanttContext ganttContext, IGanttInput ganttInput) {
this.counter.increment();

String message = this.messageService.invalidInput(ganttInput.getClass().getSimpleName(), DeleteGanttTaskDependencyInput.class.getSimpleName());
IPayload payload = new ErrorPayload(ganttInput.id(), message);
ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, ganttInput.representationId(), ganttInput);

if (ganttInput instanceof DeleteGanttTaskDependencyInput input) {
payload = this.ganttTaskService.deleteTaskDependency(input, editingContext, ganttContext.getGantt());

changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, ganttInput.representationId(), ganttInput);
}

payloadSink.tryEmitValue(payload);
changeDescriptionSink.tryEmitNext(changeDescription);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.eclipse.sirius.components.collaborative.gantt.dto.input.ChangeTaskCollapseStateInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.CreateGanttTaskDependencyInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.CreateGanttTaskInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.DeleteGanttTaskDependencyInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.DeleteGanttTaskInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.DropGanttTaskInput;
import org.eclipse.sirius.components.collaborative.gantt.dto.input.EditGanttTaskInput;
Expand Down Expand Up @@ -228,6 +229,34 @@ public IPayload createTaskDependency(CreateGanttTaskDependencyInput createTaskDe
return payload;
}

@Override
public IPayload deleteTaskDependency(DeleteGanttTaskDependencyInput deleteTaskDependencyInput, IEditingContext editingContext, Gantt gantt) {
IPayload payload = new ErrorPayload(deleteTaskDependencyInput.id(), "Delete task dependency failed");

Optional<GanttDescription> ganttDescriptionOpt = this.findGanttDescription(gantt.descriptionId(), editingContext);

if (ganttDescriptionOpt.isPresent()) {
VariableManager variableManager = new VariableManager();
variableManager.put(IEditingContext.EDITING_CONTEXT, editingContext);

Optional<Object> sourceObjectOpt = Optional.of(deleteTaskDependencyInput.sourceTaskId())
.flatMap(taskId -> this.getTaskSemanticObject(taskId, gantt, editingContext));

Optional<Object> targetObjectOpt = Optional.of(deleteTaskDependencyInput.targetTaskId())
.flatMap(taskId -> this.getTaskSemanticObject(taskId, gantt, editingContext));

if (sourceObjectOpt.isPresent() && targetObjectOpt.isPresent()) {
variableManager.put(GanttDescription.SOURCE_OBJECT, sourceObjectOpt.get());
variableManager.put(GanttDescription.TARGET_OBJECT, targetObjectOpt.get());
ganttDescriptionOpt.get().deleteTaskDependencyProvider().accept(variableManager);
}

payload = this.getPayload(deleteTaskDependencyInput.id());
}

return payload;
}

private Optional<Object> getTaskSemanticObject(String taskId, Gantt gantt, IEditingContext editingContext) {
Optional<Object> targetObjectOpt = this.findTask(task -> Objects.equals(task.id(), taskId), gantt.tasks())
.map(task -> this.objectService.getObject(editingContext, task.targetObjectId()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ extend type Mutation {
editGanttTask(input: EditGanttTaskInput!): EditGanttTaskPayload
dropGanttTask(input: DropGanttTaskInput!): DropGanttTaskPayload
createGanttTaskDependency(input: CreateGanttTaskDependencyInput!): CreateGanttTaskDependencyPayload
deleteGanttTaskDependency(input: DeleteGanttTaskDependencyInput!): DeleteGanttTaskDependencyPayload
changeGanttTaskCollapseState(input: ChangeGanttTaskCollapseStateInput!): ChangeGanttTaskCollapseStatePayload
changeGanttColumn(input: ChangeGanttColumnInput!): ChangeGanttColumnPayload
}
Expand Down Expand Up @@ -143,6 +144,15 @@ input CreateGanttTaskDependencyInput {
}
union CreateGanttTaskDependencyPayload = SuccessPayload | ErrorPayload

input DeleteGanttTaskDependencyInput {
id: ID!
editingContextId: ID!
representationId: ID!
sourceTaskId: ID!
targetTaskId: ID!
}
union DeleteGanttTaskDependencyPayload = SuccessPayload | ErrorPayload

input ChangeGanttTaskCollapseStateInput {
id: ID!
editingContextId: ID!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.gantt.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.gantt.dto.input.DeleteGanttTaskDependencyInput;
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 gantt task dependency.
*
* @author lfasani
*/
@MutationDataFetcher(type = "Mutation", field = "deleteGanttTaskDependency")
public class MutationDeleteTaskDependencyDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<IPayload>> {

private static final String INPUT_ARGUMENT = "input";

private final ObjectMapper objectMapper;

private final IExceptionWrapper exceptionWrapper;

private final IEditingContextDispatcher editingContextDispatcher;

public MutationDeleteTaskDependencyDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) {
this.objectMapper = Objects.requireNonNull(objectMapper);
this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper);
this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher);
}

@Override
public CompletableFuture<IPayload> get(DataFetchingEnvironment environment) throws Exception {
Object argument = environment.getArgument(INPUT_ARGUMENT);
var input = this.objectMapper.convertValue(argument, DeleteGanttTaskDependencyInput.class);

return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input), input).toFuture();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.gantt.tests.graphql;

import java.util.Objects;

import org.eclipse.sirius.components.collaborative.gantt.dto.input.CreateGanttTaskDependencyInput;
import org.eclipse.sirius.components.graphql.tests.api.IGraphQLRequestor;
import org.eclipse.sirius.components.graphql.tests.api.IMutationRunner;
import org.springframework.stereotype.Service;

/**
* Used to create a Task Dependency with the GraphQL API.
*
* @author lfasani
*/
@Service
public class CreateTaskDependencyMutationRunner implements IMutationRunner<CreateGanttTaskDependencyInput> {

private static final String CREATE_TASK_DEPENDENCY_MUTATION = """
mutation createGanttTaskDependency($input: CreateGanttTaskDependencyInput!) {
createGanttTaskDependency(input: $input) {
__typename
... on ErrorPayload {
messages {
body
level
}
}
... on SuccessPayload {
messages {
body
level
}
}
}
}
""";

private final IGraphQLRequestor graphQLRequestor;

public CreateTaskDependencyMutationRunner(IGraphQLRequestor graphQLRequestor) {
this.graphQLRequestor = Objects.requireNonNull(graphQLRequestor);
}

@Override
public String run(CreateGanttTaskDependencyInput input) {
return this.graphQLRequestor.execute(CREATE_TASK_DEPENDENCY_MUTATION, input);
}
}
Loading

0 comments on commit 6b92aa0

Please sign in to comment.