Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
- https://github.com/eclipse-syson/syson/issues/2116[#2116] [explorer] In the _Explorer_ view, the items corresponding to the internals of `Expression` elements (syntax tree) are now hidden by default.
Disabling the _Hide expression internals_ filter in the _Explorer_ view allows to display them if needed.
- https://github.com/eclipse-syson/syson/issues/2112[#2112] [diagrams] Add tools to create _Start_ and _Done_ `StateUsages`, available on `StateUsage` and `StateDefinition` graphical nodes.
- https://github.com/eclipse-syson/syson/issues/2097[#2097] [explorer] Add support for creating and editing exressions through their textual representation.
This is currently supported on `Features` (e.g. `Attribute`), `Constraints` and `Transitions` (guard conditions) view new context menu actions (_Create expression_ and _Edit expression_) on the corresponding elements in the _Explorer_.

== v2026.5.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.syson.sysml.Element;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory.Descriptor;
import org.eclipse.sirius.components.collaborative.forms.services.api.IPropertiesDescriptionRegistry;
import org.eclipse.sirius.components.collaborative.forms.services.api.IPropertiesDescriptionRegistryConfigurer;
Expand Down Expand Up @@ -63,8 +62,9 @@
import org.eclipse.syson.model.services.ModelMutationElementService;
import org.eclipse.syson.model.services.aql.ModelMutationAQLService;
import org.eclipse.syson.model.services.aql.ModelQueryAQLService;
import org.eclipse.syson.services.UtilService;
import org.eclipse.syson.sysml.Element;
import org.eclipse.syson.sysml.SysmlPackage;
import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService;
import org.eclipse.syson.util.AQLConstants;
import org.eclipse.syson.util.AQLUtils;
import org.eclipse.syson.util.ServiceMethod;
Expand Down Expand Up @@ -119,10 +119,10 @@ public class SysMLv2PropertiesConfigurer implements IPropertiesDescriptionRegist

private final ILabelService labelService;

private final UtilService utilService;

private final IReadOnlyObjectPredicate readOnlyObjectPredicate;

private final MetamodelQueryElementService metamodelQueryElementService;

private final List<IDetailsViewHelpTextProvider> detailViewHelpTextProviders;

public SysMLv2PropertiesConfigurer(List<Descriptor> composedAdapterFactoryDescriptors, ViewFormDescriptionConverter converter, IFeedbackMessageService feedbackMessageService,
Expand All @@ -133,7 +133,7 @@ public SysMLv2PropertiesConfigurer(List<Descriptor> composedAdapterFactoryDescri
this.labelService = Objects.requireNonNull(labelService);
this.readOnlyObjectPredicate = Objects.requireNonNull(readOnlyObjectPredicate);
this.detailViewHelpTextProviders = Objects.requireNonNull(detailViewHelpTextProviders);
this.utilService = new UtilService();
this.metamodelQueryElementService = new MetamodelQueryElementService();
}

@Override
Expand All @@ -155,7 +155,8 @@ public void addPropertiesDescriptions(IPropertiesDescriptionRegistry registry) {

// Convert the View-based FormDescription and register the result into the system
AQLInterpreter interpreter = new AQLInterpreter(List.of(),
List.of(new DetailsViewService(this.composedAdapterFactoryDescriptors, this.feedbackMessageService, this.readOnlyObjectPredicate, this.detailViewHelpTextProviders), this.labelService, this.utilService,
List.of(new DetailsViewService(this.composedAdapterFactoryDescriptors, this.feedbackMessageService, this.readOnlyObjectPredicate, this.metamodelQueryElementService,
this.detailViewHelpTextProviders), this.labelService,
new ModelMutationAQLService(new ModelMutationElementService()), new ModelQueryAQLService(), new FormMutationAQLService(), new FormQueryAQLService()),
List.of(SysmlPackage.eINSTANCE));
ViewConverterResult converterResult = this.converter.convert(viewFormDescription, List.of(), interpreter);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* Copyright (c) 2026 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.syson.application.expressions.dto;

import java.util.UUID;

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

/**
* The input object for the {@code deleteExpression} mutation.
*
* @author pcdavid
*/
public record DeleteExpressionInput(UUID id, String editingContextId, String parentElementId) implements IInput {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* Copyright (c) 2026 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.syson.application.expressions.dto;

import java.util.UUID;

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

/**
* Input for the {@code expressionTextualRepresentation} query field on EditingContext.
*
* @author pcdavid
*/
public record ExpressionTextualRepresentationInput(UUID id, String editingContextId, String elementId) implements IInput {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2026 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.syson.application.expressions.dto;

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

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

/**
* Payload for the {@code expressionTextualRepresentation} query field on EditingContext.
*
* @author pcdavid
*/
public record ExpressionTextualRepresentationPayload(UUID id, String textualRepresentation) implements IPayload {
public ExpressionTextualRepresentationPayload {
Objects.requireNonNull(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2026 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.syson.application.expressions.graphql;

import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher;
import org.eclipse.syson.application.expressions.dto.ExpressionTextualRepresentationInput;
import org.eclipse.syson.application.expressions.dto.ExpressionTextualRepresentationPayload;

import graphql.schema.DataFetchingEnvironment;

/**
* Data fetcher for the field {@code EditingContext#expressionTextualRepresentation} to fetch the textual representation
* of a SysMLv2 expression.
*
* @author pcdavid
*/
@QueryDataFetcher(type = "EditingContext", field = "expressionTextualRepresentation")
public class EditingContextExpressionTextualRepresentationDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<String>> {

private static final String ELEMENT_ID_ARGUMENT = "elementId";

private final IEditingContextDispatcher editingContextDispatcher;

public EditingContextExpressionTextualRepresentationDataFetcher(IEditingContextDispatcher editingContextDispatcher) {
this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher);
}

@Override
public CompletableFuture<String> get(DataFetchingEnvironment environment) throws Exception {
String editingContextId = environment.getSource();
String elementId = environment.getArgument(ELEMENT_ID_ARGUMENT);

ExpressionTextualRepresentationInput input = new ExpressionTextualRepresentationInput(UUID.randomUUID(), editingContextId, elementId);
return this.editingContextDispatcher.dispatchQuery(input.editingContextId(), input)
.filter(ExpressionTextualRepresentationPayload.class::isInstance)
.map(ExpressionTextualRepresentationPayload.class::cast)
.map(ExpressionTextualRepresentationPayload::textualRepresentation)
.toFuture();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2026 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.syson.application.expressions.graphql;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;

import org.eclipse.sirius.components.annotations.spring.graphql.MutationDataFetcher;
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 org.eclipse.syson.application.expressions.dto.DeleteExpressionInput;

import graphql.schema.DataFetchingEnvironment;
import tools.jackson.databind.ObjectMapper;

/**
* The GraphQL data-fetcher for the {@code deleteExpression} mutation to delete the expression associated to a SysMLv2
* element.
*
* @author pcdavid
*/
@MutationDataFetcher(type = "Mutation", field = "deleteExpression")
public class MutationDeleteExpressionDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<IPayload>> {

private static final String INPUT_ARGUMENT = "input";

private final ObjectMapper objectMapper;

private final IExceptionWrapper exceptionWrapper;

private final IEditingContextDispatcher editingContextDispatcher;

public MutationDeleteExpressionDataFetcher(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, DeleteExpressionInput.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,86 @@
/*******************************************************************************
* Copyright (c) 2026 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.syson.application.expressions.services;

import java.util.Objects;
import java.util.Optional;

import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
import org.eclipse.sirius.components.collaborative.api.ChangeKind;
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventHandler;
import org.eclipse.sirius.components.collaborative.messages.ICollaborativeMessageService;
import org.eclipse.sirius.components.core.api.ErrorPayload;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IInput;
import org.eclipse.sirius.components.core.api.IObjectSearchService;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.core.api.SuccessPayload;
import org.eclipse.syson.application.expressions.dto.DeleteExpressionInput;
import org.eclipse.syson.services.DeleteService;
import org.eclipse.syson.sysml.Element;
import org.eclipse.syson.sysml.Expression;
import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService;
import org.springframework.stereotype.Service;

import reactor.core.publisher.Sinks;

/**
* Event handler for the {@code deleteExpression} mutation.
*
* @author pcdavid
*/
@Service
public class DeleteExpressionEventHandler implements IEditingContextEventHandler {

private final IObjectSearchService objectSearchService;

private final MetamodelQueryElementService metamodelQueryElementService;

private final ICollaborativeMessageService messageService;

private final DeleteService deleteService;

public DeleteExpressionEventHandler(IObjectSearchService objectSearchService, ICollaborativeMessageService messageService) {
this.objectSearchService = Objects.requireNonNull(objectSearchService);
this.metamodelQueryElementService = new MetamodelQueryElementService();
this.messageService = Objects.requireNonNull(messageService);
this.deleteService = new DeleteService();
}

@Override
public boolean canHandle(IEditingContext editingContext, IInput input) {
return input instanceof DeleteExpressionInput;
}

@Override
public void handle(Sinks.One<IPayload> payloadSink, Sinks.Many<ChangeDescription> changeDescriptionSink, IEditingContext editingContext, IInput input) {
IPayload payload;
if (input instanceof DeleteExpressionInput deleteExpressionInput) {
Optional<Expression> optionalExpression = this.objectSearchService.getObject(editingContext, deleteExpressionInput.parentElementId())
.filter(Element.class::isInstance)
.map(Element.class::cast)
.flatMap(element -> this.metamodelQueryElementService.findSingleExpressionDefinition(element));
if (optionalExpression.isPresent()) {
this.deleteService.deleteFromModel(optionalExpression.get());
var changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, editingContext.getId(), input);
changeDescriptionSink.tryEmitNext(changeDescription);
payload = new SuccessPayload(input.id());
} else {
payload = new ErrorPayload(input.id(), this.messageService.notFound());
}
} else {
payload = new ErrorPayload(input.id(), this.messageService.invalidInput(DeleteExpressionInput.class.getName(), input.getClass().getName()));
}
payloadSink.tryEmitValue(payload);
}
}
Loading
Loading