From 7516a52ce30328575529b51b355078087c7d88e7 Mon Sep 17 00:00:00 2001 From: Axel RICHARD Date: Fri, 3 Jul 2026 15:09:30 +0200 Subject: [PATCH 1/3] [2325] Add default and initial options to expressions popup on frontend Bug: https://github.com/eclipse-syson/syson/issues/2325 Signed-off-by: Axel RICHARD --- CHANGELOG.adoc | 5 +- ...ssionDiagramToolOverriddenContribution.tsx | 5 ++ ...sionExplorerToolOverriddenContribution.tsx | 5 ++ .../EditSysMLExpressionMenuContribution.tsx | 5 ++ .../expressions/EditSysMLExpressionModal.tsx | 26 +++++++++ .../EditSysMLExpressionModal.types.ts | 3 + .../ExpressionFeatureValueProperties.tsx | 57 +++++++++++++++++++ .../expressions/ExpressionPropertySection.tsx | 5 ++ ...ssionDiagramToolOverriddenContribution.tsx | 5 ++ ...sionExplorerToolOverriddenContribution.tsx | 5 ++ .../NewSysMLExpressionMenuContribution.tsx | 5 ++ .../expressions/expressionProperties.types.ts | 31 ++++++++++ 12 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx create mode 100644 frontend/syson-components/src/extensions/expressions/expressionProperties.types.ts diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 35c209d95..86e85fc19 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -58,6 +58,7 @@ Users should use the dedicated tools to edit expressions instead, as they ensure It concerns, at least, _actions_ and _items_ compartments list items. - https://github.com/eclipse-syson/syson/issues/2284[#2284] [diagrams] The expression-related tools in diagram palette are now available in the default _Edit_ section. - https://github.com/eclipse-syson/syson/issues/2319[#2319] [diagrams] Remove the margins around the `Actor` image. +- https://github.com/eclipse-syson/syson/issues/2325[#2325] [syson] Add checkboxes in the new Expressions popup allowing to set the _isDefault_ and _isInitial_ properties of `FeatureValue` elements when the expression is `FeatureValue` related. === New features @@ -70,10 +71,10 @@ Disabling the _Hide expression internals_ filter in the _Explorer_ view allows t - https://github.com/eclipse-syson/syson/issues/2235[#2235] [diagrams] Leverage the selection dialog to improve the graphical node tool creating a _frame_ `ConcernUsage` from `RequirementUsage` and `RequirementDefinition` graphical nodes. - https://github.com/eclipse-syson/syson/issues/2242[#2242] [explorer] Add two options to the dialog creating a child element of `RequirementUsage` or `RequirementDefinition` tree items. One creates a `ConcernUsage` and another one creates `FramedConcernMembership`. -- https://github.com/eclipse-syson/syson/issues/2097[#2097] [explorer] Add support for creating and editing exressions through their textual representation. +- https://github.com/eclipse-syson/syson/issues/2097[#2097] [explorer] Add support for creating and editing expressions 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_. - https://github.com/eclipse-syson/syson/issues/2270[#2270] [diagram] Add dedicated tools to diagram elements palette to create/edit/delete expressions. -- https://github.com/eclipse-syson/syson/issues/2247[#2247] [diagrams] Add the support for creating _timeslices/snapshots_ from the different kind of `OccurrenceDefiniton` graphical nodes. +- https://github.com/eclipse-syson/syson/issues/2247[#2247] [diagrams] Add the support for creating _timeslices/snapshots_ from the different kind of `OccurrenceDefinition` graphical nodes. It leverages the selection dialog to either create an _occurrence timeslice/snapshot_, or the _usage timeslice/snapshot_ matching the `OccurrenceDefinition` on which the tool is applied. - https://github.com/eclipse-syson/syson/issues/2250[#2250] [diagrams] Leverage the selection dialog to improve the graphical node tools creating a _require_ `ConstraintUsage`, or an _assume_ `ConstraintUsage`, from `RequirementUsage` and `RequirementDefinition` graphical nodes. - https://github.com/eclipse-syson/syson/issues/2254[#2254] [diagrams] Add the support for _assume_ and _require_ graphical edges. diff --git a/frontend/syson-components/src/extensions/expressions/EditExpressionDiagramToolOverriddenContribution.tsx b/frontend/syson-components/src/extensions/expressions/EditExpressionDiagramToolOverriddenContribution.tsx index 2cc3a9c03..347be12fe 100644 --- a/frontend/syson-components/src/extensions/expressions/EditExpressionDiagramToolOverriddenContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/EditExpressionDiagramToolOverriddenContribution.tsx @@ -20,6 +20,7 @@ import { Edge, InternalNode, Node, useStoreApi } from '@xyflow/react'; import { Fragment, useContext, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; +import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; const useStyle = makeStyles()((theme) => ({ listItemText: { @@ -81,6 +82,10 @@ export const EditExpressionDiagramToolOverriddenContribution = ({ elementId={elementId} mode="edit" onClose={onClose} + expressionPropertiesContext={{ + supportsFeatureValueProperties: true, + featureValueProperties: defaultFeatureValueExpressionProperties, + }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx b/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx index 35aebbb98..d3935ed5e 100644 --- a/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx @@ -19,6 +19,7 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import React, { forwardRef, Fragment, useContext, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; +import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const EditExpressionExplorerToolOverriddenContribution = forwardRef( ({}: PaletteToolOverriddenContributionComponentProps, ref: React.ForwardedRef) => { @@ -43,6 +44,10 @@ export const EditExpressionExplorerToolOverriddenContribution = forwardRef( elementId={item.id} mode="edit" onClose={onCloseModal} + expressionPropertiesContext={{ + supportsFeatureValueProperties: true, + featureValueProperties: defaultFeatureValueExpressionProperties, + }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx index e65e30f92..175d3d832 100644 --- a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx @@ -18,6 +18,7 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import React, { forwardRef, Fragment, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; +import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const EditSysMLExpressionMenuContribution = forwardRef( ( @@ -43,6 +44,10 @@ export const EditSysMLExpressionMenuContribution = forwardRef( elementId={item.id} mode="edit" onClose={onCloseModal} + expressionPropertiesContext={{ + supportsFeatureValueProperties: true, + featureValueProperties: defaultFeatureValueExpressionProperties, + }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx index b176008da..c8b1e66d9 100644 --- a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx +++ b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx @@ -30,7 +30,12 @@ import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; import { useEffect, useRef, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; +import { ExpressionFeatureValueProperties } from './ExpressionFeatureValueProperties'; import { EditSysMLExpressionModalProps, EditSysMLExpressionModalState } from './EditSysMLExpressionModal.types'; +import { + defaultFeatureValueExpressionProperties, + FeatureValueExpressionProperties, +} from './expressionProperties.types'; import { useCreateExpression } from './useCreateExpression'; import { useDeleteExpression } from './useDeleteExpression'; import { useEditExpression } from './useEditExpression'; @@ -85,6 +90,7 @@ export const EditSysMLExpressionModal = ({ elementId, mode, onClose, + expressionPropertiesContext, }: EditSysMLExpressionModalProps) => { const { classes } = useEditSysMLExpressionModalStyles(); @@ -92,6 +98,9 @@ export const EditSysMLExpressionModal = ({ textualContent: null, operationInProgress: null, validationResult: null, + properties: { + featureValue: expressionPropertiesContext?.featureValueProperties ?? defaultFeatureValueExpressionProperties, + }, }); const validationStatus = computeValidationStatus(state.validationResult); const busy = state.operationInProgress !== null; @@ -112,6 +121,8 @@ export const EditSysMLExpressionModal = ({ } }, [textualRepresentation, loading]); + const supportsFeatureValueProperties = expressionPropertiesContext?.supportsFeatureValueProperties ?? false; + const fieldReady = !busy && state.textualContent !== null; useEffect(() => { if (fieldReady) { @@ -203,6 +214,21 @@ export const EditSysMLExpressionModal = ({ }, }} /> + {supportsFeatureValueProperties ? ( + + setState((prevState) => ({ + ...prevState, + properties: { + ...prevState.properties, + featureValue, + }, + })) + } + /> + ) : null}
{validationStatus === 'invalid' && state.validationResult ? ( diff --git a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts index 2d1754fbd..3fe67e2af 100644 --- a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts +++ b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts @@ -12,6 +12,7 @@ *******************************************************************************/ import { GQLMessage } from '@eclipse-sirius/sirius-components-core'; +import { ExpressionProperties, ExpressionPropertiesContext } from './expressionProperties.types'; export type Mode = 'create' | 'edit'; @@ -20,6 +21,7 @@ export interface EditSysMLExpressionModalProps { elementId: string; mode: Mode; onClose: () => void; + expressionPropertiesContext?: ExpressionPropertiesContext; } export type Operation = 'loading' | 'creating' | 'editing'; @@ -28,4 +30,5 @@ export interface EditSysMLExpressionModalState { operationInProgress: Operation | null; textualContent: string | null; validationResult: GQLMessage[] | null; + properties: ExpressionProperties; } diff --git a/frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx b/frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx new file mode 100644 index 000000000..c8f463088 --- /dev/null +++ b/frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx @@ -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 + *******************************************************************************/ +import Checkbox from '@mui/material/Checkbox'; +import FormLabel from '@mui/material/FormLabel'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import FormGroup from '@mui/material/FormGroup'; +import { FeatureValueExpressionProperties } from './expressionProperties.types'; + +export interface ExpressionFeatureValuePropertiesProps { + disabled: boolean; + properties: FeatureValueExpressionProperties; + onChange: (properties: FeatureValueExpressionProperties) => void; +} + +export const ExpressionFeatureValueProperties = ({ + disabled, + properties, + onChange, +}: ExpressionFeatureValuePropertiesProps) => { + return ( +
+ Properties + + onChange({ ...properties, isDefault: checked })} + /> + } + label="Default value" + /> + onChange({ ...properties, isInitial: checked })} + /> + } + label="Initial value" + /> + +
+ ); +}; diff --git a/frontend/syson-components/src/extensions/expressions/ExpressionPropertySection.tsx b/frontend/syson-components/src/extensions/expressions/ExpressionPropertySection.tsx index 866e2b5a9..89f7d541b 100644 --- a/frontend/syson-components/src/extensions/expressions/ExpressionPropertySection.tsx +++ b/frontend/syson-components/src/extensions/expressions/ExpressionPropertySection.tsx @@ -28,6 +28,7 @@ import Typography from '@mui/material/Typography'; import { useState } from 'react'; import { makeStyles } from 'tss-react/mui'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; +import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; const useStyle = makeStyles()( (theme, { color, fontSize, italic, bold, underline, strikeThrough }) => ({ @@ -95,6 +96,10 @@ export const ExpressionPropertySection: PropertySectionComponent mode={expressionPresent ? 'edit' : 'create'} elementId={targetObjectId} onClose={onCloseModal} + expressionPropertiesContext={{ + supportsFeatureValueProperties: true, + featureValueProperties: defaultFeatureValueExpressionProperties, + }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx b/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx index f91d6f53e..4d9ad1539 100644 --- a/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx @@ -20,6 +20,7 @@ import { Edge, InternalNode, Node, useStoreApi } from '@xyflow/react'; import { Fragment, useContext, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; +import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; const useStyle = makeStyles()((theme) => ({ listItemText: { @@ -81,6 +82,10 @@ export const NewExpressionDiagramToolOverriddenContribution = ({ elementId={elementId} mode="create" onClose={onClose} + expressionPropertiesContext={{ + supportsFeatureValueProperties: true, + featureValueProperties: defaultFeatureValueExpressionProperties, + }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx b/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx index 244ed051e..37234fef1 100644 --- a/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx @@ -18,6 +18,7 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import { forwardRef, Fragment, useContext, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; +import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const NewExpressionExplorerToolOverriddenContribution = forwardRef( ({}: PaletteToolOverriddenContributionComponentProps, ref: React.ForwardedRef) => { @@ -43,6 +44,10 @@ export const NewExpressionExplorerToolOverriddenContribution = forwardRef( elementId={item.id} mode="create" onClose={onCloseModal} + expressionPropertiesContext={{ + supportsFeatureValueProperties: true, + featureValueProperties: defaultFeatureValueExpressionProperties, + }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx b/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx index 0dbe6dc6c..2eaebb4b6 100644 --- a/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx @@ -18,6 +18,7 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import React, { forwardRef, Fragment, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; +import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const NewSysMLExpressionMenuContribution = forwardRef( ( @@ -43,6 +44,10 @@ export const NewSysMLExpressionMenuContribution = forwardRef( elementId={item.id} mode="create" onClose={onCloseModal} + expressionPropertiesContext={{ + supportsFeatureValueProperties: true, + featureValueProperties: defaultFeatureValueExpressionProperties, + }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/expressionProperties.types.ts b/frontend/syson-components/src/extensions/expressions/expressionProperties.types.ts new file mode 100644 index 000000000..7f73d3660 --- /dev/null +++ b/frontend/syson-components/src/extensions/expressions/expressionProperties.types.ts @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +export interface FeatureValueExpressionProperties { + isDefault: boolean; + isInitial: boolean; +} + +export interface ExpressionProperties { + featureValue: FeatureValueExpressionProperties; +} + +export interface ExpressionPropertiesContext { + supportsFeatureValueProperties: boolean; + featureValueProperties?: FeatureValueExpressionProperties | null; +} + +export const defaultFeatureValueExpressionProperties: FeatureValueExpressionProperties = { + isDefault: false, + isInitial: false, +}; From 249635f3f7a992a1eb59fcdabecc1c39475de8cc Mon Sep 17 00:00:00 2001 From: Axel RICHARD Date: Fri, 3 Jul 2026 15:24:45 +0200 Subject: [PATCH 2/3] [2325] Add default and initial options to expressions popup on backend Bug: https://github.com/eclipse-syson/syson/issues/2325 Signed-off-by: Axel RICHARD --- ...xpressionsControllersIntegrationTests.java | 221 +++++++++++++++++- .../sysml/dto/CreateExpressionInput.java | 27 ++- .../syson/sysml/dto/EditExpressionInput.java | 27 ++- .../sysml/dto/ExpressionPropertiesInput.java | 23 ++ ...FeatureValueExpressionPropertiesInput.java | 25 ++ .../CreateExpressionEventHandler.java | 3 +- .../services/EditExpressionEventHandler.java | 3 +- .../services/SysideExpressionEditor.java | 62 ++++- .../services/api/ISysMLExpressionEditor.java | 9 +- .../resources/schema/syson-import.graphqls | 13 +- 10 files changed, 398 insertions(+), 15 deletions(-) create mode 100644 backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/ExpressionPropertiesInput.java create mode 100644 backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/FeatureValueExpressionPropertiesInput.java diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java index a46a12f49..0988e03e8 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java @@ -73,6 +73,8 @@ import org.eclipse.syson.sysml.dto.CreateExpressionSuccessPayload; import org.eclipse.syson.sysml.dto.EditExpressionInput; import org.eclipse.syson.sysml.dto.EditExpressionSuccessPayload; +import org.eclipse.syson.sysml.dto.ExpressionPropertiesInput; +import org.eclipse.syson.sysml.dto.FeatureValueExpressionPropertiesInput; import org.eclipse.syson.sysml.metamodel.helper.LabelConstants; import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService; import org.eclipse.syson.tree.explorer.view.SysONTreeViewDescriptionProvider; @@ -203,6 +205,43 @@ public void canCreateExpressionInEmptyAttribute() { .verify(Duration.ofSeconds(10)); } + @DisplayName("GIVEN an empty SysML attribute, WHEN creating an expression with feature value properties THEN the created feature value stores them") + @GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH }) + @Test + public void canCreateExpressionInEmptyAttributeWithFeatureValueProperties() { + String editingContextId = ExpressionSamplesProjectData.EDITING_CONTEXT_ID; + + List defaultFilters = this.explorerDefaultFiltersSearchService.findTreeDefaultFilterIds(editingContextId, this.sysONExplorerTreeDescriptionId); + var explorerRepresentationId = this.representationIdBuilder.buildExplorerRepresentationId(this.sysONExplorerTreeDescriptionId, List.of(), defaultFilters); + var explorerInput = new ExplorerEventInput(UUID.randomUUID(), editingContextId, explorerRepresentationId); + var flux = this.explorerEventSubscriptionRunner.run(explorerInput).flux(); + + var treeId = new AtomicReference(); + Consumer initialTreeContentConsumer = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + treeId.set(tree.getId()); + }); + + Runnable createExpressionOnPressureAttribute = this.createExpression(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_PRESSURE_ATTRIBUTE_ID, "maxPressure / 2", + this.featureValueProperties(true, false)); + + Consumer treeRefreshed = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getId()).isEqualTo(treeId.get()); + }); + + Runnable checkPressureAttributeFeatureValueProperties = this.checkAttributeFeatureValue(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_PRESSURE_ATTRIBUTE_ID, + "maxPressure / 2", true, false); + + StepVerifier.create(flux) + .consumeNextWith(initialTreeContentConsumer) + .then(createExpressionOnPressureAttribute) + .consumeNextWith(treeRefreshed) + .then(checkPressureAttributeFeatureValueProperties) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + @DisplayName("GIVEN a SysML attribute which does have an existing expression, WHEN trying to create a new expression on it THEN the new expression is created with proper name resolution") @GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH }) @Test @@ -285,6 +324,110 @@ public void textEditAttributeExpression() { .verify(Duration.ofSeconds(10)); } + @DisplayName("GIVEN a SysML attribute with a value expression, WHEN editing it with feature value properties THEN the flags are updated together with the expression") + @GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH }) + @Test + public void textEditAttributeExpressionAndFeatureValueProperties() { + String editingContextId = ExpressionSamplesProjectData.EDITING_CONTEXT_ID; + + List defaultFilters = this.explorerDefaultFiltersSearchService.findTreeDefaultFilterIds(editingContextId, this.sysONExplorerTreeDescriptionId); + var explorerRepresentationId = this.representationIdBuilder.buildExplorerRepresentationId(this.sysONExplorerTreeDescriptionId, List.of(), defaultFilters); + var explorerInput = new ExplorerEventInput(UUID.randomUUID(), editingContextId, explorerRepresentationId); + var flux = this.explorerEventSubscriptionRunner.run(explorerInput).flux(); + + var treeId = new AtomicReference(); + Consumer initialTreeContentConsumer = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + treeId.set(tree.getId()); + }); + + var existingExpressionId = new AtomicReference(); + + Runnable checkInitialExpression = this.checkElementHasExpression(editingContextId, + ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, AttributeUsage.class, existingExpressionId, + "100.0 * minVolume"); + + Runnable editExpressionOnMaxVolumeAttribute = this.editExpression(editingContextId, existingExpressionId::get, "50 * minVolume", + this.featureValueProperties(true, true)); + + Consumer treeRefreshed = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getId()).isEqualTo(treeId.get()); + }); + + Runnable checkUpdatedFeatureValue = this.checkAttributeFeatureValue(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, + "50 * minVolume", true, true); + + StepVerifier.create(flux) + .consumeNextWith(initialTreeContentConsumer) + .then(checkInitialExpression) + .then(editExpressionOnMaxVolumeAttribute) + .consumeNextWith(treeRefreshed) + .then(checkUpdatedFeatureValue) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + + @DisplayName("GIVEN a SysML attribute with feature value flags, WHEN editing it with partial properties THEN omitted fields keep their previous value") + @GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH }) + @Test + public void textEditAttributeExpressionWithPartialFeatureValueProperties() { + String editingContextId = ExpressionSamplesProjectData.EDITING_CONTEXT_ID; + + List defaultFilters = this.explorerDefaultFiltersSearchService.findTreeDefaultFilterIds(editingContextId, this.sysONExplorerTreeDescriptionId); + var explorerRepresentationId = this.representationIdBuilder.buildExplorerRepresentationId(this.sysONExplorerTreeDescriptionId, List.of(), defaultFilters); + var explorerInput = new ExplorerEventInput(UUID.randomUUID(), editingContextId, explorerRepresentationId); + var flux = this.explorerEventSubscriptionRunner.run(explorerInput).flux(); + + var treeId = new AtomicReference(); + Consumer initialTreeContentConsumer = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + treeId.set(tree.getId()); + }); + + var existingExpressionId = new AtomicReference(); + + Runnable checkInitialExpression = this.checkElementHasExpression(editingContextId, + ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, AttributeUsage.class, existingExpressionId, + "100.0 * minVolume"); + + Runnable firstEdit = this.editExpression(editingContextId, existingExpressionId::get, "50 * minVolume", this.featureValueProperties(true, true)); + + Consumer firstTreeRefresh = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getId()).isEqualTo(treeId.get()); + }); + + Runnable checkIntermediateFeatureValue = this.checkAttributeFeatureValue(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, + "50 * minVolume", true, true); + + Runnable refreshExpressionId = this.checkElementHasExpression(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, + AttributeUsage.class, existingExpressionId, "50 * minVolume"); + + Runnable secondEdit = this.editExpression(editingContextId, existingExpressionId::get, "60 * minVolume", this.featureValueProperties(null, false)); + + Consumer secondTreeRefresh = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getId()).isEqualTo(treeId.get()); + }); + + Runnable checkFinalFeatureValue = this.checkAttributeFeatureValue(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, + "60 * minVolume", true, false); + + StepVerifier.create(flux) + .consumeNextWith(initialTreeContentConsumer) + .then(checkInitialExpression) + .then(firstEdit) + .consumeNextWith(firstTreeRefresh) + .then(checkIntermediateFeatureValue) + .then(refreshExpressionId) + .then(secondEdit) + .consumeNextWith(secondTreeRefresh) + .then(checkFinalFeatureValue) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + @DisplayName("GIVEN a SysML constraint which does not have a predicate expression, WHEN creating a new expression on it THEN the new expression is created with proper name resolution") @GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH }) @Test @@ -325,6 +468,43 @@ public void canCreateExpressionInEmptyConstraint() { .verify(Duration.ofSeconds(10)); } + @DisplayName("GIVEN a SysML constraint, WHEN creating an expression with feature value properties THEN the expression is created and the properties are ignored") + @GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH }) + @Test + public void canCreateExpressionInConstraintIgnoringFeatureValueProperties() { + String editingContextId = ExpressionSamplesProjectData.EDITING_CONTEXT_ID; + + List defaultFilters = this.explorerDefaultFiltersSearchService.findTreeDefaultFilterIds(editingContextId, this.sysONExplorerTreeDescriptionId); + var explorerRepresentationId = this.representationIdBuilder.buildExplorerRepresentationId(this.sysONExplorerTreeDescriptionId, List.of(), defaultFilters); + var explorerInput = new ExplorerEventInput(UUID.randomUUID(), editingContextId, explorerRepresentationId); + var flux = this.explorerEventSubscriptionRunner.run(explorerInput).flux(); + + var treeId = new AtomicReference(); + Consumer initialTreeContentConsumer = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + treeId.set(tree.getId()); + }); + + Runnable createExpression = this.createExpression(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_ASSUME_ID, "s.enabled == true", + this.featureValueProperties(true, true)); + + Consumer treeRefreshed = assertRefreshedTreeThat(tree -> { + assertThat(tree).isNotNull(); + assertThat(tree.getId()).isEqualTo(treeId.get()); + }); + + Runnable checkCreatedExpression = this.checkElementHasExpression(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_ASSUME_ID, ConstraintUsage.class, + new AtomicReference<>(), "s.enabled == true"); + + StepVerifier.create(flux) + .consumeNextWith(initialTreeContentConsumer) + .then(createExpression) + .consumeNextWith(treeRefreshed) + .then(checkCreatedExpression) + .thenCancel() + .verify(Duration.ofSeconds(10)); + } + @DisplayName("GIVEN a SysML transition which does not have a guard expression, WHEN creating a new expression on it THEN the new expression is created with proper name resolution") @GivenSysONServer({ ExpressionSamplesProjectData.SCRIPT_PATH }) @Test @@ -440,7 +620,8 @@ public void editAttributeExpressionWithInvalidNewValue() { }); Runnable editExpressionOnMaxVolumeAttributeWithInvalidValue = () -> { - var input = new EditExpressionInput(UUID.randomUUID(), editingContextId, existingExpressionId.get(), "50 * minVolumeTypo"); + var input = new EditExpressionInput(UUID.randomUUID(), editingContextId, existingExpressionId.get(), "50 * minVolumeTypo", + this.featureValueProperties(true, true)); var result = this.editExpressionMutationRunner.run(input); String typename = JsonPath.read(result.data(), "$.data.editExpression.__typename"); assertThat(typename).isEqualTo(ErrorPayload.class.getSimpleName()); @@ -463,6 +644,9 @@ public void editAttributeExpressionWithInvalidNewValue() { // Make sure we did not create an additional invalid FeatureValue and left it around. assertThat(maxVolumeAttribute.getOwnedRelationship().stream().filter(FeatureValue.class::isInstance)).hasSize(1); + FeatureValue featureValue = maxVolumeAttribute.getOwnedRelationship().stream().filter(FeatureValue.class::isInstance).map(FeatureValue.class::cast).findFirst().orElseThrow(); + assertThat(featureValue.isIsDefault()).isFalse(); + assertThat(featureValue.isIsInitial()).isFalse(); return new ExecuteEditingContextFunctionSuccessPayload(input.id(), optionalMaxVolumeAttribute.get()); }); @@ -850,8 +1034,12 @@ private Runnable semanticCheck(String editingContextId, BiFunction { - var input = new CreateExpressionInput(UUID.randomUUID(), editingContextId, parentElementId, expressionContent); + var input = new CreateExpressionInput(UUID.randomUUID(), editingContextId, parentElementId, expressionContent, properties); var result = this.createExpressionMutationRunner.run(input); String typename = JsonPath.read(result.data(), "$.data.createExpression.__typename"); assertThat(typename).isEqualTo(CreateExpressionSuccessPayload.class.getSimpleName()); @@ -859,8 +1047,12 @@ private Runnable createExpression(String editingContextId, String parentElementI } private Runnable editExpression(String editingContextId, Supplier elementId, String expressionContent) { + return this.editExpression(editingContextId, elementId, expressionContent, null); + } + + private Runnable editExpression(String editingContextId, Supplier elementId, String expressionContent, ExpressionPropertiesInput properties) { return () -> { - var input = new EditExpressionInput(UUID.randomUUID(), editingContextId, elementId.get(), expressionContent); + var input = new EditExpressionInput(UUID.randomUUID(), editingContextId, elementId.get(), expressionContent, properties); var result = this.editExpressionMutationRunner.run(input); String typename = JsonPath.read(result.data(), "$.data.editExpression.__typename"); assertThat(typename).isEqualTo(EditExpressionSuccessPayload.class.getSimpleName()); @@ -900,4 +1092,27 @@ private Runnable checkElementHasExpression(String editingCon return new ExecuteEditingContextFunctionSuccessPayload(input.id(), optionalElement.get()); }); } + + private Runnable checkAttributeFeatureValue(String editingContextId, String attributeId, String expectedExpressionTextualRepresentation, boolean expectedIsDefault, + boolean expectedIsInitial) { + return this.semanticCheck(editingContextId, (editingContext, input) -> { + var optionalElement = this.objectSearchService.getObject(editingContext, attributeId); + assertThat(optionalElement).containsInstanceOf(AttributeUsage.class); + AttributeUsage attributeUsage = (AttributeUsage) optionalElement.get(); + Optional optionalFeatureValue = attributeUsage.getOwnedRelationship().stream() + .filter(FeatureValue.class::isInstance) + .map(FeatureValue.class::cast) + .findFirst(); + assertThat(optionalFeatureValue).isPresent(); + assertThat(this.metamodelQueryElementService.getExpressionTextualRepresentation(optionalFeatureValue.get().getValue())) + .isEqualTo(expectedExpressionTextualRepresentation); + assertThat(optionalFeatureValue.get().isIsDefault()).isEqualTo(expectedIsDefault); + assertThat(optionalFeatureValue.get().isIsInitial()).isEqualTo(expectedIsInitial); + return new ExecuteEditingContextFunctionSuccessPayload(input.id(), optionalElement.get()); + }); + } + + private ExpressionPropertiesInput featureValueProperties(Boolean isDefault, Boolean isInitial) { + return new ExpressionPropertiesInput(new FeatureValueExpressionPropertiesInput(isDefault, isInitial)); + } } diff --git a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/CreateExpressionInput.java b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/CreateExpressionInput.java index 7cdddbc3c..e4c95d918 100644 --- a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/CreateExpressionInput.java +++ b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/CreateExpressionInput.java @@ -19,7 +19,32 @@ /** * The input object of the createExpression operation. * + * @param id + * the mutation identifier. + * @param editingContextId + * the editing context identifier. + * @param parentElementId + * the identifier of the element in which the expression should be created. + * @param expressionText + * the textual representation of the expression to create. + * @param properties + * the optional typed properties to apply once the expression is created successfully. * @author pcdavid */ -public record CreateExpressionInput(UUID id, String editingContextId, String parentElementId, String expressionText) implements IInput { +public record CreateExpressionInput(UUID id, String editingContextId, String parentElementId, String expressionText, ExpressionPropertiesInput properties) implements IInput { + /** + * Creates an input without optional properties. + * + * @param id + * the mutation identifier. + * @param editingContextId + * the editing context identifier. + * @param parentElementId + * the identifier of the element in which the expression should be created. + * @param expressionText + * the textual representation of the expression to create. + */ + public CreateExpressionInput(UUID id, String editingContextId, String parentElementId, String expressionText) { + this(id, editingContextId, parentElementId, expressionText, null); + } } diff --git a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/EditExpressionInput.java b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/EditExpressionInput.java index ca0d50bda..d0eef2c69 100644 --- a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/EditExpressionInput.java +++ b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/EditExpressionInput.java @@ -19,7 +19,32 @@ /** * The input object of the {@code editExpression} mutation. * + * @param id + * the mutation identifier. + * @param editingContextId + * the editing context identifier. + * @param elementId + * the identifier of the expression itself or of the parent element that owns a single expression. + * @param newExpressionText + * the textual representation of the replacement expression. + * @param properties + * the optional typed properties to apply once the expression is edited successfully. * @author pcdavid */ -public record EditExpressionInput(UUID id, String editingContextId, String elementId, String newExpressionText) implements IInput { +public record EditExpressionInput(UUID id, String editingContextId, String elementId, String newExpressionText, ExpressionPropertiesInput properties) implements IInput { + /** + * Creates an input without optional properties. + * + * @param id + * the mutation identifier. + * @param editingContextId + * the editing context identifier. + * @param elementId + * the identifier of the expression itself or of the parent element that owns a single expression. + * @param newExpressionText + * the textual representation of the replacement expression. + */ + public EditExpressionInput(UUID id, String editingContextId, String elementId, String newExpressionText) { + this(id, editingContextId, elementId, newExpressionText, null); + } } diff --git a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/ExpressionPropertiesInput.java b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/ExpressionPropertiesInput.java new file mode 100644 index 000000000..60bb4e15a --- /dev/null +++ b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/ExpressionPropertiesInput.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * 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.sysml.dto; + +/** + * Optional typed properties associated with an expression mutation. + * + * @param featureValue + * properties to apply when the expression belongs to a {@code FeatureValue}. + * @author arichard + */ +public record ExpressionPropertiesInput(FeatureValueExpressionPropertiesInput featureValue) { +} diff --git a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/FeatureValueExpressionPropertiesInput.java b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/FeatureValueExpressionPropertiesInput.java new file mode 100644 index 000000000..2d8d42881 --- /dev/null +++ b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/dto/FeatureValueExpressionPropertiesInput.java @@ -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.sysml.dto; + +/** + * Optional properties that can be applied to a {@code FeatureValue} expression owner. + * + * @param isDefault + * whether the feature value is marked as default. A {@code null} value leaves the current state unchanged. + * @param isInitial + * whether the feature value is marked as initial. A {@code null} value leaves the current state unchanged. + * @author arichard + */ +public record FeatureValueExpressionPropertiesInput(Boolean isDefault, Boolean isInitial) { +} diff --git a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/CreateExpressionEventHandler.java b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/CreateExpressionEventHandler.java index 15ce52584..26235594c 100644 --- a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/CreateExpressionEventHandler.java +++ b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/CreateExpressionEventHandler.java @@ -90,7 +90,8 @@ public void handle(One payloadSink, Many changeDesc if (this.metamodelQueryElementService.hasSingleExpressionDefinition(optionalParentElement.get())) { payload = new ErrorPayload(input.id(), "The parent element already has an expression"); } else { - var result = this.expressionEditor.createExpression(emfEditingContext, optionalParentElement.get(), createExpressionInput.expressionText()); + var result = this.expressionEditor.createExpression(emfEditingContext, optionalParentElement.get(), createExpressionInput.expressionText(), + createExpressionInput.properties()); if (result.createdExpression() != null) { var createdExpression = result.createdExpression(); var createdExpressionId = this.identityService.getId(createdExpression); diff --git a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/EditExpressionEventHandler.java b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/EditExpressionEventHandler.java index 2c11c5214..095e315e4 100644 --- a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/EditExpressionEventHandler.java +++ b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/EditExpressionEventHandler.java @@ -87,7 +87,8 @@ public void handle(Sinks.One payloadSink, Sinks.Manyreplace this one instead of just being added. * @param expressionText * the textual representation of the expression to create. + * @param properties + * the optional typed properties to apply after the expression is created or replaced. * @return the result of creating a new expression. It can either contain the actual expression created (on success) * or a list of messages on failure. */ - private ExpressionCreationResult createOrEditExpression(IEMFEditingContext emfEditingContext, Element parentElement, Optional expressionToReplace, String expressionText) { + private ExpressionCreationResult createOrEditExpression(IEMFEditingContext emfEditingContext, Element parentElement, Optional expressionToReplace, String expressionText, + ExpressionPropertiesInput properties) { List newObjects = List.of(); List messages = new ArrayList<>(); @@ -106,12 +113,57 @@ private ExpressionCreationResult createOrEditExpression(IEMFEditingContext emfEd if (expressionToReplace.isPresent()) { this.replace(expressionToReplace.get(), optionalResult.get()); } + this.applyProperties(optionalResult.get(), properties); return new ExpressionCreationResult(optionalResult.get(), messages); } else { return new ExpressionCreationResult(null, messages); } } + /** + * Applies supported properties to the owner of the created or edited expression. + * + * @param expression + * the created or edited expression. + * @param properties + * the optional properties to apply. + */ + private void applyProperties(Expression expression, ExpressionPropertiesInput properties) { + if (properties != null && properties.featureValue() != null) { + this.getOwningFeatureValue(expression).ifPresent(featureValue -> this.applyFeatureValueProperties(featureValue, properties.featureValue())); + } + } + + /** + * Gets the owning {@link FeatureValue} of the provided expression, if any. + * + * @param expression + * the expression whose owner should be inspected. + * @return the owning {@link FeatureValue}, if one exists. + */ + private Optional getOwningFeatureValue(Expression expression) { + return Optional.ofNullable(expression.getOwningRelationship()) + .filter(FeatureValue.class::isInstance) + .map(FeatureValue.class::cast); + } + + /** + * Applies optional {@link FeatureValue} properties while preserving existing values for omitted fields. + * + * @param featureValue + * the feature value to update. + * @param properties + * the optional properties to apply. + */ + private void applyFeatureValueProperties(FeatureValue featureValue, FeatureValueExpressionPropertiesInput properties) { + if (properties.isDefault() != null) { + featureValue.setIsDefault(properties.isDefault()); + } + if (properties.isInitial() != null) { + featureValue.setIsInitial(properties.isInitial()); + } + } + /** * Determines if the messages we received from the parser and converter indicate an error. We treat warnings as * errors here. diff --git a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/api/ISysMLExpressionEditor.java b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/api/ISysMLExpressionEditor.java index 939b5d561..a9191e2aa 100644 --- a/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/api/ISysMLExpressionEditor.java +++ b/backend/application/syson-sysml-import/src/main/java/org/eclipse/syson/sysml/services/api/ISysMLExpressionEditor.java @@ -18,6 +18,7 @@ import org.eclipse.syson.sysml.LiteralBoolean; import org.eclipse.syson.sysml.OperatorExpression; import org.eclipse.syson.sysml.Relationship; +import org.eclipse.syson.sysml.dto.ExpressionPropertiesInput; /** * Use to create of edit a SySMLv2 {@link Expression} in a given context from a given text fragment. @@ -35,10 +36,12 @@ public interface ISysMLExpressionEditor { * relationship} into which the expression is added will depend on the parent's type. * @param expressionText * the plain text representation of the expression to create. + * @param properties + * the optional typed properties to apply after creation succeeds. * @return the result of creating a new expression. It can either contain the actual expression created (on success) * or a list of messages on failure. */ - ExpressionCreationResult createExpression(IEMFEditingContext emfEditingContext, Element parentElement, String expressionText); + ExpressionCreationResult createExpression(IEMFEditingContext emfEditingContext, Element parentElement, String expressionText, ExpressionPropertiesInput properties); /** * "Edit" an existing {@link Expression expression} inside the specified parent element from a textual @@ -54,8 +57,10 @@ public interface ISysMLExpressionEditor { * which the expression is added will depend on the parent's type. * @param expressionText * the plain text representation of the expression to create as a replacement. + * @param properties + * the optional typed properties to apply after the replacement succeeds. * @return the result of editing the expression. It can either contain the actual new expression created as a * replacement (on success) or a list of messages on failure. */ - ExpressionCreationResult editExpression(IEMFEditingContext emfEditingContext, Element parentElement, Expression expression, String expressionText); + ExpressionCreationResult editExpression(IEMFEditingContext emfEditingContext, Element parentElement, Expression expression, String expressionText, ExpressionPropertiesInput properties); } diff --git a/backend/application/syson-sysml-import/src/main/resources/schema/syson-import.graphqls b/backend/application/syson-sysml-import/src/main/resources/schema/syson-import.graphqls index 3eb3b4ada..d33870d57 100644 --- a/backend/application/syson-sysml-import/src/main/resources/schema/syson-import.graphqls +++ b/backend/application/syson-sysml-import/src/main/resources/schema/syson-import.graphqls @@ -21,6 +21,7 @@ input CreateExpressionInput { editingContextId: ID! parentElementId: ID! expressionText: String! + properties: ExpressionPropertiesInput } union CreateExpressionPayload = ErrorPayload | CreateExpressionSuccessPayload @@ -36,6 +37,16 @@ input EditExpressionInput { editingContextId: ID! elementId: ID! newExpressionText: String! + properties: ExpressionPropertiesInput +} + +input ExpressionPropertiesInput { + featureValue: FeatureValueExpressionPropertiesInput +} + +input FeatureValueExpressionPropertiesInput { + isDefault: Boolean + isInitial: Boolean } union EditExpressionPayload = ErrorPayload | EditExpressionSuccessPayload @@ -44,4 +55,4 @@ type EditExpressionSuccessPayload { id: ID! newExpressionId: ID! messages: [Message]! -} \ No newline at end of file +} From b585334a64c0ac1817d19750e1149e4b0a360ea8 Mon Sep 17 00:00:00 2001 From: Axel RICHARD Date: Fri, 3 Jul 2026 15:42:36 +0200 Subject: [PATCH 3/3] [2325] Add default/initial options backend frontend wiring Bug: https://github.com/eclipse-syson/syson/issues/2325 Signed-off-by: Axel RICHARD --- ...xpressionTextualRepresentationPayload.java | 9 +- ...atureValueExpressionPropertiesPayload.java | 25 ++++ ...ssionTextualRepresentationDataFetcher.java | 5 +- ...sionTextualRepresentationEventHandler.java | 124 ++++++++++++++++-- .../resources/schema/expressions.graphqls | 12 +- ...xpressionsControllersIntegrationTests.java | 49 +++++-- ...ssionTextualRepresentationQueryRunner.java | 8 +- .../data/ExpressionSamplesProjectData.java | 3 + .../expression-feature-value-properties.png | Bin 0 -> 85128 bytes ...es-expression-feature-value-properties.png | Bin 0 -> 85128 bytes .../pages/features/expressions.adoc | 15 +++ .../pages/release-notes/2026.7.0.adoc | 13 ++ ...ssionDiagramToolOverriddenContribution.tsx | 5 - ...sionExplorerToolOverriddenContribution.tsx | 5 - .../EditSysMLExpressionMenuContribution.tsx | 5 - .../expressions/EditSysMLExpressionModal.tsx | 44 +++++-- .../EditSysMLExpressionModal.types.ts | 5 +- .../ExpressionFeatureValueProperties.tsx | 31 ++++- ...types.ts => ExpressionProperties.types.ts} | 7 +- .../expressions/ExpressionPropertySection.tsx | 5 - ...ssionDiagramToolOverriddenContribution.tsx | 5 - ...sionExplorerToolOverriddenContribution.tsx | 5 - .../NewSysMLExpressionMenuContribution.tsx | 5 - .../expressions/useCreateExpression.ts | 9 +- .../expressions/useCreateExpression.types.ts | 9 +- .../expressions/useEditExpression.ts | 9 +- .../expressions/useEditExpression.types.ts | 9 +- .../useExpressionTextualRepresentation.ts | 14 +- ...seExpressionTextualRepresentation.types.ts | 11 +- 29 files changed, 349 insertions(+), 97 deletions(-) create mode 100644 backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/FeatureValueExpressionPropertiesPayload.java create mode 100644 doc/content/modules/user-manual/assets/images/expression-feature-value-properties.png create mode 100644 doc/content/modules/user-manual/assets/images/release-notes-expression-feature-value-properties.png rename frontend/syson-components/src/extensions/expressions/{expressionProperties.types.ts => ExpressionProperties.types.ts} (80%) diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/ExpressionTextualRepresentationPayload.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/ExpressionTextualRepresentationPayload.java index 3afd3f2b7..ebe5e334d 100644 --- a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/ExpressionTextualRepresentationPayload.java +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/ExpressionTextualRepresentationPayload.java @@ -20,9 +20,16 @@ /** * Payload for the {@code expressionTextualRepresentation} query field on EditingContext. * + * @param id + * the query identifier. + * @param textualRepresentation + * the textual representation of the effective expression, or an empty string if none is available. + * @param featureValueProperties + * the current feature value properties when supported. * @author pcdavid */ -public record ExpressionTextualRepresentationPayload(UUID id, String textualRepresentation) implements IPayload { +public record ExpressionTextualRepresentationPayload(UUID id, String textualRepresentation, + FeatureValueExpressionPropertiesPayload featureValueProperties) implements IPayload { public ExpressionTextualRepresentationPayload { Objects.requireNonNull(id); } diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/FeatureValueExpressionPropertiesPayload.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/FeatureValueExpressionPropertiesPayload.java new file mode 100644 index 000000000..35a2e3e17 --- /dev/null +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/dto/FeatureValueExpressionPropertiesPayload.java @@ -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; + +/** + * Properties exposed by the expression editor for expressions owned by a SysML {@code FeatureValue}. + * + * @param isDefault + * whether the feature value is marked as default. + * @param isInitial + * whether the feature value is marked as initial. + * @author arichard + */ +public record FeatureValueExpressionPropertiesPayload(boolean isDefault, boolean isInitial) { +} diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/graphql/EditingContextExpressionTextualRepresentationDataFetcher.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/graphql/EditingContextExpressionTextualRepresentationDataFetcher.java index e1a53069a..5bd5f4fc7 100644 --- a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/graphql/EditingContextExpressionTextualRepresentationDataFetcher.java +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/graphql/EditingContextExpressionTextualRepresentationDataFetcher.java @@ -31,7 +31,7 @@ * @author pcdavid */ @QueryDataFetcher(type = "EditingContext", field = "expressionTextualRepresentation") -public class EditingContextExpressionTextualRepresentationDataFetcher implements IDataFetcherWithFieldCoordinates> { +public class EditingContextExpressionTextualRepresentationDataFetcher implements IDataFetcherWithFieldCoordinates> { private static final String ELEMENT_ID_ARGUMENT = "elementId"; @@ -42,7 +42,7 @@ public EditingContextExpressionTextualRepresentationDataFetcher(IEditingContextD } @Override - public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { + public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { String editingContextId = environment.getSource(); String elementId = environment.getArgument(ELEMENT_ID_ARGUMENT); @@ -50,7 +50,6 @@ public CompletableFuture get(DataFetchingEnvironment environment) throws return this.editingContextDispatcher.dispatchQuery(input.editingContextId(), input) .filter(ExpressionTextualRepresentationPayload.class::isInstance) .map(ExpressionTextualRepresentationPayload.class::cast) - .map(ExpressionTextualRepresentationPayload::textualRepresentation) .toFuture(); } } diff --git a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/services/ExpressionTextualRepresentationEventHandler.java b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/services/ExpressionTextualRepresentationEventHandler.java index ec8fe45fe..617962129 100644 --- a/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/services/ExpressionTextualRepresentationEventHandler.java +++ b/backend/application/syson-application-configuration/src/main/java/org/eclipse/syson/application/expressions/services/ExpressionTextualRepresentationEventHandler.java @@ -23,8 +23,14 @@ import org.eclipse.sirius.components.core.api.IPayload; import org.eclipse.syson.application.expressions.dto.ExpressionTextualRepresentationInput; import org.eclipse.syson.application.expressions.dto.ExpressionTextualRepresentationPayload; +import org.eclipse.syson.application.expressions.dto.FeatureValueExpressionPropertiesPayload; import org.eclipse.syson.sysml.Element; import org.eclipse.syson.sysml.Expression; +import org.eclipse.syson.sysml.Feature; +import org.eclipse.syson.sysml.FeatureValue; +import org.eclipse.syson.sysml.Function; +import org.eclipse.syson.sysml.Succession; +import org.eclipse.syson.sysml.TransitionUsage; import org.eclipse.syson.sysml.metamodel.services.MetamodelQueryElementService; import org.springframework.stereotype.Service; @@ -55,39 +61,133 @@ public boolean canHandle(IEditingContext editingContext, IInput input) { @Override public void handle(Sinks.One payloadSink, Sinks.Many changeDescriptionSink, IEditingContext editingContext, IInput input) { String textualRepresentation = ""; + FeatureValueExpressionPropertiesPayload featureValueProperties = null; if (input instanceof ExpressionTextualRepresentationInput expressionTextualRepresentationInput) { String elementId = expressionTextualRepresentationInput.elementId(); - Optional optionalExpression = this.getExpression(editingContext, elementId); + Optional optionalElement = this.getElement(editingContext, elementId); + Optional optionalExpression = optionalElement.flatMap(this::getExpression); if (optionalExpression.isPresent()) { textualRepresentation = this.metamodelQueryElementService.getExpressionTextualRepresentation(optionalExpression.get()); } + featureValueProperties = this.getFeatureValueProperties(optionalElement, optionalExpression); } - payloadSink.tryEmitValue(new ExpressionTextualRepresentationPayload(input.id(), textualRepresentation)); + payloadSink.tryEmitValue(new ExpressionTextualRepresentationPayload(input.id(), textualRepresentation, featureValueProperties)); } /** - * Finds the {@link Expression} element to consider given the provided {@code elementId}. + * Gets the target {@link Element} designated by the provided identifier. * * @param editingContext * the editing context. * @param elementId - * either to id of an actual {@link Expression} element, or of the parent {@link Element} of a single + * the identifier of the target element. + * @return the target {@link Element}, if it exists. + */ + private Optional getElement(IEditingContext editingContext, String elementId) { + return this.objectSearchService.getObject(editingContext, elementId) + .filter(Element.class::isInstance) + .map(Element.class::cast); + } + + /** + * Finds the {@link Expression} element to consider given the provided {@code elementId}. + * + * @param element + * either an actual {@link Expression} element, or the parent {@link Element} of a single * {@code Expression}. * @return the directly of indirectly designated {@link Expression}. */ - private Optional getExpression(IEditingContext editingContext, String elementId) { + private Optional getExpression(Element element) { Optional result = Optional.empty(); - Optional optionalElement = this.objectSearchService.getObject(editingContext, elementId) - .filter(Element.class::isInstance) - .map(Element.class::cast); + if (element instanceof Expression expression && this.metamodelQueryElementService.isTopLevelExpression(expression)) { + result = Optional.of(expression); + } else { + result = this.metamodelQueryElementService.findSingleExpressionDefinition(element); + } + return result; + } + + /** + * Gets the {@link FeatureValueExpressionPropertiesPayload} relevant for the expression editor context. + * + * @param optionalElement + * the selected element, if any. + * @param optionalExpression + * the effective expression, if any. + * @return the relevant {@link FeatureValueExpressionPropertiesPayload}, if any. + */ + private FeatureValueExpressionPropertiesPayload getFeatureValueProperties(Optional optionalElement, Optional optionalExpression) { + FeatureValueExpressionPropertiesPayload result = null; if (optionalElement.isPresent()) { Element element = optionalElement.get(); - if (element instanceof Expression expression && this.metamodelQueryElementService.isTopLevelExpression(expression)) { - result = optionalElement.map(Expression.class::cast); - } else { - result = this.metamodelQueryElementService.findSingleExpressionDefinition(element); + Optional optionalFeatureValue = Optional.empty(); + if (element instanceof Expression expression) { + optionalFeatureValue = this.getOwningFeatureValue(expression); + } else if (element instanceof FeatureValue featureValue) { + optionalFeatureValue = Optional.of(featureValue); + } else if (this.supportsFeatureValueProperties(element)) { + optionalFeatureValue = this.getOwnedFeatureValue(element, optionalExpression); + } + if (optionalFeatureValue.isPresent()) { + FeatureValue featureValue = optionalFeatureValue.get(); + result = new FeatureValueExpressionPropertiesPayload(featureValue.isIsDefault(), featureValue.isIsInitial()); + } else if (optionalElement.filter(this::supportsFeatureValueProperties).isPresent()) { + result = new FeatureValueExpressionPropertiesPayload(false, false); } } return result; } + + /** + * Gets the {@link FeatureValue} directly owned by the selected feature-like element or by the resolved expression. + * + * @param element + * the selected element. + * @param optionalExpression + * the effective expression, if any. + * @return the relevant {@link FeatureValue}, if any. + */ + private Optional getOwnedFeatureValue(Element element, Optional optionalExpression) { + Optional result = optionalExpression.flatMap(this::getOwningFeatureValue); + if (result.isEmpty() && element instanceof Feature feature) { + result = feature.getOwnedRelationship().stream() + .filter(FeatureValue.class::isInstance) + .map(FeatureValue.class::cast) + .findFirst(); + } + return result; + } + + /** + * Gets the owning {@link FeatureValue} of the provided expression, if it is one. + * + * @param expression + * the expression whose owner should be inspected. + * @return the owning {@link FeatureValue}, if any. + */ + private Optional getOwningFeatureValue(Expression expression) { + return Optional.ofNullable(expression.getOwningRelationship()) + .filter(FeatureValue.class::isInstance) + .map(FeatureValue.class::cast); + } + + /** + * Checks whether the selected element would own its expression through a {@link FeatureValue}, which is the only + * case where the expression editor should expose feature value properties in create mode. + * + * @param element + * the selected element. + * @return {@code true} if feature value properties should be exposed for a new expression on this element. + */ + private boolean supportsFeatureValueProperties(Element element) { + boolean result = false; + if (element instanceof TransitionUsage || element instanceof Succession) { + result = false; + } else if (element instanceof Function || element instanceof Expression) { + result = false; + } else { + result = element instanceof Feature; + } + return result; + } } diff --git a/backend/application/syson-application-configuration/src/main/resources/schema/expressions.graphqls b/backend/application/syson-application-configuration/src/main/resources/schema/expressions.graphqls index e02595d6d..7398a28c6 100644 --- a/backend/application/syson-application-configuration/src/main/resources/schema/expressions.graphqls +++ b/backend/application/syson-application-configuration/src/main/resources/schema/expressions.graphqls @@ -1,5 +1,15 @@ extend type EditingContext { - expressionTextualRepresentation(elementId: ID!): String + expressionTextualRepresentation(elementId: ID!): ExpressionEditorState +} + +type ExpressionEditorState { + textualRepresentation: String! + featureValueProperties: FeatureValueExpressionProperties +} + +type FeatureValueExpressionProperties { + isDefault: Boolean! + isInitial: Boolean! } extend type Mutation { diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java index 0988e03e8..f511fb788 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/ExpressionsControllersIntegrationTests.java @@ -771,34 +771,47 @@ public void topLevelExpressionTextualRepresentation() { treeId.set(tree.getId()); }); - // The Tank part is not an expression => "" - var checkTank = this.checkExpressiontTextualRepresentation(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_ID, ""); + // The Tank part definition is not an expression and does not expose feature value properties. + var checkTank = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_ID, "", null, null); // The Tank's attribute is not an expression itself either, but it owns a single, non-ambiguous expression to // can act as a "shortcut" to interact with id. - var checkTankAttribute = this.checkExpressiontTextualRepresentation(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, "100.0 * minVolume"); + var checkTankAttribute = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_ID, "100.0 * minVolume", + false, false); // The actual attribute default value expression however should be correctly represented - var checkTankAttributeValueExpression = this.checkExpressiontTextualRepresentation(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_VALUE_ID, - "100.0 * minVolume"); + var checkTankAttributeValueExpression = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_MAX_VOLUME_ATTRIBUTE_VALUE_ID, + "100.0 * minVolume", false, false); + // An empty attribute still supports feature value properties for expression creation. + var checkEmptyTankAttribute = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.TANK_PRESSURE_ATTRIBUTE_ID, "", false, false); - var checkPerformanceConcern = this.checkExpressiontTextualRepresentation(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_ID, ""); + var checkPerformanceConcern = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_ID, "", null, null); // A ConstaintUsage *is* an Expression from the point of view of SysML's type hierarchy, but not a top-level // Expression. However if it contains a single expression, it an act as a "shortcut" to it. - var checkPerformanceConcernAssumeConstraint = this.checkExpressiontTextualRepresentation(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_ASSUME_ID, ""); - var checkPerformanceConcernRequireConstraint = this.checkExpressiontTextualRepresentation(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_REQUIRE_ID, - "s.samplingRate >= 50.0 & s.currentValue != 0.0 | s.errorCount == 0"); + var checkPerformanceConcernAssumeConstraint = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_ASSUME_ID, "", null, + null); + var checkPerformanceConcernRequireConstraint = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_REQUIRE_ID, + "s.samplingRate >= 50.0 & s.currentValue != 0.0 | s.errorCount == 0", null, null); // require s.samplingRate >= 50.0 & s.currentValue != 0.0 | s.errorCount == 0 - var checkPerformanceConcernRequireConstraintExpression = this.checkExpressiontTextualRepresentation(editingContextId, - ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_REQUIRE_EXPRESSION_ID, "s.samplingRate >= 50.0 & s.currentValue != 0.0 | s.errorCount == 0"); + var checkPerformanceConcernRequireConstraintExpression = this.checkExpressionEditorState(editingContextId, + ExpressionSamplesProjectData.SemanticIds.PERFORMANCE_CONCERN_REQUIRE_EXPRESSION_ID, "s.samplingRate >= 50.0 & s.currentValue != 0.0 | s.errorCount == 0", null, null); + var checkHeatingTransition = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.THERMAL_CONTROL_TO_HEATING_TRANSITION_ID, "", null, null); + var checkHeatingSuccession = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.THERMAL_CONTROL_TO_HEATING_SUCCESSION_ID, "", null, + null); + var checkCoolingTransition = this.checkExpressionEditorState(editingContextId, ExpressionSamplesProjectData.SemanticIds.THERMAL_CONTROL_TO_COOLING_TRANSITION_ID, + "currentTemp > targetTemp + tolerance", null, null); StepVerifier.create(flux) .consumeNextWith(initialTreeContentConsumer) .then(checkTank) .then(checkTankAttribute) .then(checkTankAttributeValueExpression) + .then(checkEmptyTankAttribute) .then(checkPerformanceConcern) .then(checkPerformanceConcernAssumeConstraint) .then(checkPerformanceConcernRequireConstraint) .then(checkPerformanceConcernRequireConstraintExpression) + .then(checkHeatingTransition) + .then(checkHeatingSuccession) + .then(checkCoolingTransition) .thenCancel() .verify(Duration.ofSeconds(10)); } @@ -1059,12 +1072,22 @@ private Runnable editExpression(String editingContextId, Supplier elemen }; } - private Runnable checkExpressiontTextualRepresentation(String editingContextId, String elementId, String expectedTextualRepresentation) { + private Runnable checkExpressionEditorState(String editingContextId, String elementId, String expectedTextualRepresentation, Boolean expectedIsDefault, + Boolean expectedIsInitial) { return () -> { Map variables = Map.of("editingContextId", editingContextId, "elementId", elementId); var result = this.expressionTextualRepresentationQueryRunner.run(variables); - String textualRepresentation = JsonPath.read(result.data(), "$.data.viewer.editingContext.expressionTextualRepresentation"); + String textualRepresentation = JsonPath.read(result.data(), "$.data.viewer.editingContext.expressionTextualRepresentation.textualRepresentation"); assertThat(textualRepresentation).as("elementId: {}", elementId).isEqualTo(expectedTextualRepresentation); + if (expectedIsDefault == null && expectedIsInitial == null) { + Object featureValueProperties = JsonPath.read(result.data(), "$.data.viewer.editingContext.expressionTextualRepresentation.featureValueProperties"); + assertThat(featureValueProperties).as("elementId: {}", elementId).isNull(); + } else { + Boolean isDefault = JsonPath.read(result.data(), "$.data.viewer.editingContext.expressionTextualRepresentation.featureValueProperties.isDefault"); + Boolean isInitial = JsonPath.read(result.data(), "$.data.viewer.editingContext.expressionTextualRepresentation.featureValueProperties.isInitial"); + assertThat(isDefault).as("elementId: {}", elementId).isEqualTo(expectedIsDefault); + assertThat(isInitial).as("elementId: {}", elementId).isEqualTo(expectedIsInitial); + } }; } diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/graphql/ExpressionTextualRepresentationQueryRunner.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/graphql/ExpressionTextualRepresentationQueryRunner.java index c279d886b..ea225a101 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/graphql/ExpressionTextualRepresentationQueryRunner.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/controllers/expressions/graphql/ExpressionTextualRepresentationQueryRunner.java @@ -31,7 +31,13 @@ public class ExpressionTextualRepresentationQueryRunner implements IQueryRunner query getExpressionTextualRepresentation($editingContextId: ID!, $elementId: ID!) { viewer { editingContext(editingContextId: $editingContextId) { - expressionTextualRepresentation(elementId: $elementId) + expressionTextualRepresentation(elementId: $elementId) { + textualRepresentation + featureValueProperties { + isDefault + isInitial + } + } } } } diff --git a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ExpressionSamplesProjectData.java b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ExpressionSamplesProjectData.java index 6da4bfbf0..ec9d8c94e 100644 --- a/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ExpressionSamplesProjectData.java +++ b/backend/application/syson-application/src/test/java/org/eclipse/syson/application/data/ExpressionSamplesProjectData.java @@ -56,6 +56,8 @@ public static final class SemanticIds { public static final String THERMAL_CONTROL_TO_HEATING_TRANSITION_ID = "0b517687-ef3f-4057-9ce5-27e27f627a22"; + public static final String THERMAL_CONTROL_TO_HEATING_SUCCESSION_ID = "c59c0174-da0a-4972-a5ca-6743ab295651"; + public static final String THERMAL_CONTROL_TO_COOLING_TRANSITION_ID = "e1c27d0b-476e-42d4-9b81-b5f064d9cbbe"; public static final String THERMAL_CONTROL_TO_COOLING_TRANSITION_GUARD_EXPRESSION_ID = "ec67ead5-7739-4dd3-a82e-f1bb5ef34268"; @@ -81,6 +83,7 @@ public static final class SemanticIds { PERFORMANCE_CONCERN_REQUIRE_EXPRESSION_ID, THERMAL_CONTROL_STATE_DEFINITION_ID, THERMAL_CONTROL_TO_HEATING_TRANSITION_ID, + THERMAL_CONTROL_TO_HEATING_SUCCESSION_ID, THERMAL_CONTROL_TO_COOLING_TRANSITION_ID, THERMAL_CONTROL_TO_COOLING_TRANSITION_GUARD_EXPRESSION_ID); } diff --git a/doc/content/modules/user-manual/assets/images/expression-feature-value-properties.png b/doc/content/modules/user-manual/assets/images/expression-feature-value-properties.png new file mode 100644 index 0000000000000000000000000000000000000000..e7765f41ea0fbfd02907e78a49f46ba097251a3d GIT binary patch literal 85128 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

tGa|F-p@lB;gTSUQxgSDuS#WI|L2**&g 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

tGa|F-p@lB;gTSUQxgSDuS#WI|L2**&g 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

h? ({ listItemText: { @@ -82,10 +81,6 @@ export const EditExpressionDiagramToolOverriddenContribution = ({ elementId={elementId} mode="edit" onClose={onClose} - expressionPropertiesContext={{ - supportsFeatureValueProperties: true, - featureValueProperties: defaultFeatureValueExpressionProperties, - }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx b/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx index d3935ed5e..35aebbb98 100644 --- a/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/EditExpressionExplorerToolOverriddenContribution.tsx @@ -19,7 +19,6 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import React, { forwardRef, Fragment, useContext, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; -import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const EditExpressionExplorerToolOverriddenContribution = forwardRef( ({}: PaletteToolOverriddenContributionComponentProps, ref: React.ForwardedRef) => { @@ -44,10 +43,6 @@ export const EditExpressionExplorerToolOverriddenContribution = forwardRef( elementId={item.id} mode="edit" onClose={onCloseModal} - expressionPropertiesContext={{ - supportsFeatureValueProperties: true, - featureValueProperties: defaultFeatureValueExpressionProperties, - }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx index 175d3d832..e65e30f92 100644 --- a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionMenuContribution.tsx @@ -18,7 +18,6 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import React, { forwardRef, Fragment, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; -import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const EditSysMLExpressionMenuContribution = forwardRef( ( @@ -44,10 +43,6 @@ export const EditSysMLExpressionMenuContribution = forwardRef( elementId={item.id} mode="edit" onClose={onCloseModal} - expressionPropertiesContext={{ - supportsFeatureValueProperties: true, - featureValueProperties: defaultFeatureValueExpressionProperties, - }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx index c8b1e66d9..ea91a141d 100644 --- a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx +++ b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.tsx @@ -35,7 +35,8 @@ import { EditSysMLExpressionModalProps, EditSysMLExpressionModalState } from './ import { defaultFeatureValueExpressionProperties, FeatureValueExpressionProperties, -} from './expressionProperties.types'; + GQLExpressionProperties, +} from './ExpressionProperties.types'; import { useCreateExpression } from './useCreateExpression'; import { useDeleteExpression } from './useDeleteExpression'; import { useEditExpression } from './useEditExpression'; @@ -85,12 +86,24 @@ const computeValidationStatus = (validationResult: GQLMessage[] | null): Validat } }; +const sanitizeFeatureValueProperties = ( + featureValueProperties: FeatureValueExpressionProperties | null | undefined +): FeatureValueExpressionProperties => ({ + isDefault: featureValueProperties?.isDefault ?? false, + isInitial: featureValueProperties?.isInitial ?? false, +}); + +const toExpressionProperties = ( + featureValueProperties: FeatureValueExpressionProperties | null | undefined +): GQLExpressionProperties => ({ + featureValue: sanitizeFeatureValueProperties(featureValueProperties ?? defaultFeatureValueExpressionProperties), +}); + export const EditSysMLExpressionModal = ({ editingContextId, elementId, mode, onClose, - expressionPropertiesContext, }: EditSysMLExpressionModalProps) => { const { classes } = useEditSysMLExpressionModalStyles(); @@ -98,16 +111,14 @@ export const EditSysMLExpressionModal = ({ textualContent: null, operationInProgress: null, validationResult: null, - properties: { - featureValue: expressionPropertiesContext?.featureValueProperties ?? defaultFeatureValueExpressionProperties, - }, + properties: toExpressionProperties(null), }); const validationStatus = computeValidationStatus(state.validationResult); const busy = state.operationInProgress !== null; const inputRef = useRef(null); - const { textualRepresentation, loading } = useExpressionTextualRepresentation(editingContextId, elementId); + const { editorState, loading } = useExpressionTextualRepresentation(editingContextId, elementId); useEffect(() => { if (loading) { setState((prevState) => ({ ...prevState, operationInProgress: 'loading' })); @@ -115,13 +126,14 @@ export const EditSysMLExpressionModal = ({ setState((prevState) => ({ ...prevState, operationInProgress: null, - textualContent: textualRepresentation, + textualContent: editorState?.textualRepresentation ?? '', validationResult: null, + properties: toExpressionProperties(editorState?.featureValueProperties), })); } - }, [textualRepresentation, loading]); + }, [editorState, loading]); - const supportsFeatureValueProperties = expressionPropertiesContext?.supportsFeatureValueProperties ?? false; + const supportsFeatureValueProperties = editorState?.featureValueProperties != null; const fieldReady = !busy && state.textualContent !== null; useEffect(() => { @@ -141,14 +153,24 @@ export const EditSysMLExpressionModal = ({ if (state.textualContent !== null) { if (mode === 'create' && state.textualContent.trim() !== '') { setState((prevState) => ({ ...prevState, operationInProgress: 'creating' })); - createExpression(editingContextId, elementId, state.textualContent); + createExpression( + editingContextId, + elementId, + state.textualContent, + supportsFeatureValueProperties ? state.properties : null + ); } else if (mode === 'edit' && state.textualContent !== null) { if (state.textualContent.trim() === '') { deleteExpression(editingContextId, elementId); onClose(); } else { setState((prevState) => ({ ...prevState, operationInProgress: 'editing' })); - editExpression(editingContextId, elementId, state.textualContent); + editExpression( + editingContextId, + elementId, + state.textualContent, + supportsFeatureValueProperties ? state.properties : null + ); } } } diff --git a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts index 3fe67e2af..fced3f474 100644 --- a/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts +++ b/frontend/syson-components/src/extensions/expressions/EditSysMLExpressionModal.types.ts @@ -12,7 +12,7 @@ *******************************************************************************/ import { GQLMessage } from '@eclipse-sirius/sirius-components-core'; -import { ExpressionProperties, ExpressionPropertiesContext } from './expressionProperties.types'; +import { GQLExpressionProperties } from './ExpressionProperties.types'; export type Mode = 'create' | 'edit'; @@ -21,7 +21,6 @@ export interface EditSysMLExpressionModalProps { elementId: string; mode: Mode; onClose: () => void; - expressionPropertiesContext?: ExpressionPropertiesContext; } export type Operation = 'loading' | 'creating' | 'editing'; @@ -30,5 +29,5 @@ export interface EditSysMLExpressionModalState { operationInProgress: Operation | null; textualContent: string | null; validationResult: GQLMessage[] | null; - properties: ExpressionProperties; + properties: GQLExpressionProperties; } diff --git a/frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx b/frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx index c8f463088..fa2d62dd6 100644 --- a/frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx +++ b/frontend/syson-components/src/extensions/expressions/ExpressionFeatureValueProperties.tsx @@ -14,7 +14,30 @@ import Checkbox from '@mui/material/Checkbox'; import FormLabel from '@mui/material/FormLabel'; import FormControlLabel from '@mui/material/FormControlLabel'; import FormGroup from '@mui/material/FormGroup'; -import { FeatureValueExpressionProperties } from './expressionProperties.types'; +import { Theme } from '@mui/material/styles'; +import { FeatureValueExpressionProperties } from './ExpressionProperties.types'; +import { makeStyles } from 'tss-react/mui'; + +const useStyles = makeStyles()((theme: Theme) => ({ + label: { + fontFamily: theme.typography.body2.fontFamily, + fontSize: theme.typography.body2.fontSize, + fontWeight: theme.typography.body2.fontWeight, + lineHeight: theme.typography.body2.lineHeight, + letterSpacing: theme.typography.body2.letterSpacing, + color: theme.palette.text.secondary, + }, + checkboxLabel: { + '& .MuiFormControlLabel-label': { + fontFamily: theme.typography.body2.fontFamily, + fontSize: theme.typography.body2.fontSize, + fontWeight: theme.typography.body2.fontWeight, + lineHeight: theme.typography.body2.lineHeight, + letterSpacing: theme.typography.body2.letterSpacing, + color: theme.palette.text.secondary, + }, + }, +})); export interface ExpressionFeatureValuePropertiesProps { disabled: boolean; @@ -27,11 +50,14 @@ export const ExpressionFeatureValueProperties = ({ properties, onChange, }: ExpressionFeatureValuePropertiesProps) => { + const { classes } = useStyles(); + return (

- Properties + Properties ()( (theme, { color, fontSize, italic, bold, underline, strikeThrough }) => ({ @@ -96,10 +95,6 @@ export const ExpressionPropertySection: PropertySectionComponent mode={expressionPresent ? 'edit' : 'create'} elementId={targetObjectId} onClose={onCloseModal} - expressionPropertiesContext={{ - supportsFeatureValueProperties: true, - featureValueProperties: defaultFeatureValueExpressionProperties, - }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx b/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx index 4d9ad1539..f91d6f53e 100644 --- a/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/NewExpressionDiagramToolOverriddenContribution.tsx @@ -20,7 +20,6 @@ import { Edge, InternalNode, Node, useStoreApi } from '@xyflow/react'; import { Fragment, useContext, useState } from 'react'; import { makeStyles } from 'tss-react/mui'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; -import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; const useStyle = makeStyles()((theme) => ({ listItemText: { @@ -82,10 +81,6 @@ export const NewExpressionDiagramToolOverriddenContribution = ({ elementId={elementId} mode="create" onClose={onClose} - expressionPropertiesContext={{ - supportsFeatureValueProperties: true, - featureValueProperties: defaultFeatureValueExpressionProperties, - }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx b/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx index 37234fef1..244ed051e 100644 --- a/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/NewExpressionExplorerToolOverriddenContribution.tsx @@ -18,7 +18,6 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import { forwardRef, Fragment, useContext, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; -import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const NewExpressionExplorerToolOverriddenContribution = forwardRef( ({}: PaletteToolOverriddenContributionComponentProps, ref: React.ForwardedRef) => { @@ -44,10 +43,6 @@ export const NewExpressionExplorerToolOverriddenContribution = forwardRef( elementId={item.id} mode="create" onClose={onCloseModal} - expressionPropertiesContext={{ - supportsFeatureValueProperties: true, - featureValueProperties: defaultFeatureValueExpressionProperties, - }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx b/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx index 2eaebb4b6..0dbe6dc6c 100644 --- a/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx +++ b/frontend/syson-components/src/extensions/expressions/NewSysMLExpressionMenuContribution.tsx @@ -18,7 +18,6 @@ import ListItemText from '@mui/material/ListItemText'; import MenuItem from '@mui/material/MenuItem'; import React, { forwardRef, Fragment, useState } from 'react'; import { EditSysMLExpressionModal } from './EditSysMLExpressionModal'; -import { defaultFeatureValueExpressionProperties } from './expressionProperties.types'; export const NewSysMLExpressionMenuContribution = forwardRef( ( @@ -44,10 +43,6 @@ export const NewSysMLExpressionMenuContribution = forwardRef( elementId={item.id} mode="create" onClose={onCloseModal} - expressionPropertiesContext={{ - supportsFeatureValueProperties: true, - featureValueProperties: defaultFeatureValueExpressionProperties, - }} /> ); } diff --git a/frontend/syson-components/src/extensions/expressions/useCreateExpression.ts b/frontend/syson-components/src/extensions/expressions/useCreateExpression.ts index e41ef325c..0cd1df75e 100644 --- a/frontend/syson-components/src/extensions/expressions/useCreateExpression.ts +++ b/frontend/syson-components/src/extensions/expressions/useCreateExpression.ts @@ -12,6 +12,7 @@ *******************************************************************************/ import { gql, useMutation } from '@apollo/client'; import { GQLMessage } from '@eclipse-sirius/sirius-components-core'; +import { GQLExpressionProperties } from './ExpressionProperties.types'; import { GQLCreateExpressionData, GQLCreateExpressionInput, @@ -51,12 +52,18 @@ export const useCreateExpression = (): UseCreateExpressionValue => { GQLCreateExpressionVariables >(createExpressionMutation); - const createExpression = (editingContextId: string, parentElementId: string, expressionText: string) => { + const createExpression = ( + editingContextId: string, + parentElementId: string, + expressionText: string, + properties?: GQLExpressionProperties | null + ) => { const input: GQLCreateExpressionInput = { id: crypto.randomUUID(), editingContextId, parentElementId, expressionText, + properties, }; performCreateExpression({ variables: { input } }); }; diff --git a/frontend/syson-components/src/extensions/expressions/useCreateExpression.types.ts b/frontend/syson-components/src/extensions/expressions/useCreateExpression.types.ts index 77dec46af..ed6352cda 100644 --- a/frontend/syson-components/src/extensions/expressions/useCreateExpression.types.ts +++ b/frontend/syson-components/src/extensions/expressions/useCreateExpression.types.ts @@ -11,9 +11,15 @@ * Obeo - initial API and implementation *******************************************************************************/ import { GQLMessage } from '@eclipse-sirius/sirius-components-core'; +import { GQLExpressionProperties } from './ExpressionProperties.types'; export interface UseCreateExpressionValue { - createExpression: (editingContextId: string, parentElementId: string, expressionText: string) => void; + createExpression: ( + editingContextId: string, + parentElementId: string, + expressionText: string, + properties?: GQLExpressionProperties | null + ) => void; messages: GQLMessage[] | null; newExpressionId: string | null; loading: boolean; @@ -28,6 +34,7 @@ export interface GQLCreateExpressionInput { editingContextId: string; parentElementId: string; expressionText: string; + properties?: GQLExpressionProperties | null; } export interface GQLCreateExpressionData { diff --git a/frontend/syson-components/src/extensions/expressions/useEditExpression.ts b/frontend/syson-components/src/extensions/expressions/useEditExpression.ts index 6cc80e48b..ee663177b 100644 --- a/frontend/syson-components/src/extensions/expressions/useEditExpression.ts +++ b/frontend/syson-components/src/extensions/expressions/useEditExpression.ts @@ -13,6 +13,7 @@ import { gql, useMutation } from '@apollo/client'; import { GQLMessage } from '@eclipse-sirius/sirius-components-core'; +import { GQLExpressionProperties } from './ExpressionProperties.types'; import { GQLEditExpressionData, GQLEditExpressionInput, @@ -52,12 +53,18 @@ export const useEditExpression = (): UseEditExpressionValue => { GQLEditExpressionVariables >(editExpressionMutation); - const editExpression = (editingContextId: string, elementId: string, newExpressionText: string) => { + const editExpression = ( + editingContextId: string, + elementId: string, + newExpressionText: string, + properties?: GQLExpressionProperties | null + ) => { const input: GQLEditExpressionInput = { id: crypto.randomUUID(), editingContextId, elementId: elementId, newExpressionText, + properties, }; performEditExpression({ variables: { input } }); diff --git a/frontend/syson-components/src/extensions/expressions/useEditExpression.types.ts b/frontend/syson-components/src/extensions/expressions/useEditExpression.types.ts index a7fbd4be3..30afc8954 100644 --- a/frontend/syson-components/src/extensions/expressions/useEditExpression.types.ts +++ b/frontend/syson-components/src/extensions/expressions/useEditExpression.types.ts @@ -12,9 +12,15 @@ *******************************************************************************/ import { GQLMessage } from '@eclipse-sirius/sirius-components-core'; +import { GQLExpressionProperties } from './ExpressionProperties.types'; export interface UseEditExpressionValue { - editExpression: (editingContextId: string, elementId: string, newValue: string) => void; + editExpression: ( + editingContextId: string, + elementId: string, + newValue: string, + properties?: GQLExpressionProperties | null + ) => void; loading: boolean; newExpressionId: string | null; messages: GQLMessage[] | null; @@ -29,6 +35,7 @@ export interface GQLEditExpressionInput { editingContextId: string; elementId: string; newExpressionText: string; + properties?: GQLExpressionProperties | null; } export interface GQLEditExpressionData { diff --git a/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.ts b/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.ts index 6c3884b82..47675f766 100644 --- a/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.ts +++ b/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.ts @@ -15,6 +15,7 @@ import { gql, useQuery } from '@apollo/client'; import { useMultiToast } from '@eclipse-sirius/sirius-components-core'; import { useEffect } from 'react'; import { + GQLExpressionEditorState, GQLGetExpressionTextualRepresentationData, GQLGetExpressionTextualRepresentationVariables, UseExpressionTextualRepresentationValue, @@ -24,7 +25,13 @@ const getExpressionTextualRepresentationQuery = gql` query getExpressionTextualRepresentation($editingContextId: ID!, $elementId: ID!) { viewer { editingContext(editingContextId: $editingContextId) { - expressionTextualRepresentation(elementId: $elementId) + expressionTextualRepresentation(elementId: $elementId) { + textualRepresentation + featureValueProperties { + isDefault + isInitial + } + } } } } @@ -50,7 +57,8 @@ export const useExpressionTextualRepresentation = ( } }, [error]); - const textualRepresentation: string | null = data?.viewer.editingContext.expressionTextualRepresentation ?? null; + const editorState: GQLExpressionEditorState | null = + data?.viewer.editingContext.expressionTextualRepresentation ?? null; - return { textualRepresentation, loading }; + return { editorState, loading }; }; diff --git a/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.types.ts b/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.types.ts index 988871091..d531f14f4 100644 --- a/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.types.ts +++ b/frontend/syson-components/src/extensions/expressions/useExpressionTextualRepresentation.types.ts @@ -11,8 +11,10 @@ * Obeo - initial API and implementation *******************************************************************************/ +import { FeatureValueExpressionProperties } from './ExpressionProperties.types'; + export interface UseExpressionTextualRepresentationValue { - textualRepresentation: string | null; + editorState: GQLExpressionEditorState | null; loading: boolean; } @@ -30,5 +32,10 @@ export interface GQLGetExpressionTextualRepresentationViewer { } export interface GQLGetExpressionTextualRepresentationEditingContext { - expressionTextualRepresentation: string | null; + expressionTextualRepresentation: GQLExpressionEditorState | null; +} + +export interface GQLExpressionEditorState { + textualRepresentation: string; + featureValueProperties: FeatureValueExpressionProperties | null; }