diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index a15ebbb42e..0cc8c3f761 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -117,6 +117,7 @@ To illustrate this new feature, we contribute a new tool on the _Papaya Diagram_ - https://github.com/eclipse-sirius/sirius-web/issues/2343[#2343] [emf] Add icon for type selection in new object modal. - https://github.com/eclipse-sirius/sirius-web/issues/2365[#2365] [diagram] Support key down and F2 to enable direct edit on edges on react-flow diagrams. +- https://github.com/eclipse-sirius/sirius-web/issues/2358[#2358] [form] Adds diagnostic messages to the reference widget. == v2023.8.0 diff --git a/integration-tests/cypress/e2e/project/edit/widget-reference.cy.js b/integration-tests/cypress/e2e/project/edit/widget-reference.cy.js index ef3bb51a9c..3df25ef395 100644 --- a/integration-tests/cypress/e2e/project/edit/widget-reference.cy.js +++ b/integration-tests/cypress/e2e/project/edit/widget-reference.cy.js @@ -322,4 +322,19 @@ describe('/projects/:projectId/edit - FormDescriptionEditor', () => { cy.getByTestId('reference-value-unused').should('exist'); cy.getByTestId('unused').should('exist'); }); + + it('check diagnostic messages are display on widget reference', () => { + cy.createProjectFromTemplate('flow-template').then((res) => { + const projectId = res.body.data.createProjectFromTemplate.project.id; + cy.visit(`/projects/${projectId}/edit`); + }); + + cy.getByTestId('explorer://').findByTestId('FlowNewModel').dblclick(); + cy.getByTestId('explorer://').findByTestId('NewSystem').dblclick(); + cy.getByTestId('explorer://').findByTestId('DataSource1').dblclick(); + cy.getByTestId('explorer://').findByTestId('standard').click(); + cy.getByTestId('Target').find('p[class*="Mui-error"]').should('not.exist'); + cy.getByTestId('Target-clear').click(); + cy.getByTestId('Target').find('p[class*="Mui-error"]').should('exist'); + }); }); diff --git a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/NonContainmentReferenceIfDescriptionProvider.java b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/NonContainmentReferenceIfDescriptionProvider.java index c7c9338022..078d12eeba 100644 --- a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/NonContainmentReferenceIfDescriptionProvider.java +++ b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/NonContainmentReferenceIfDescriptionProvider.java @@ -22,6 +22,7 @@ import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.sirius.components.compatibility.emf.properties.api.IPropertiesValidationProvider; import org.eclipse.sirius.components.compatibility.forms.WidgetIdProvider; import org.eclipse.sirius.components.core.api.IObjectService; import org.eclipse.sirius.components.forms.description.IfDescription; @@ -44,11 +45,14 @@ public class NonContainmentReferenceIfDescriptionProvider { private final IObjectService objectService; + private final IPropertiesValidationProvider propertiesValidationProvider; + private final Function semanticTargetIdProvider; - public NonContainmentReferenceIfDescriptionProvider(ComposedAdapterFactory composedAdapterFactory, IObjectService objectService, Function semanticTargetIdProvider) { + public NonContainmentReferenceIfDescriptionProvider(ComposedAdapterFactory composedAdapterFactory, IObjectService objectService, IPropertiesValidationProvider propertiesValidationProvider, Function semanticTargetIdProvider) { this.composedAdapterFactory = Objects.requireNonNull(composedAdapterFactory); this.objectService = Objects.requireNonNull(objectService); + this.propertiesValidationProvider = Objects.requireNonNull(propertiesValidationProvider); this.semanticTargetIdProvider = Objects.requireNonNull(semanticTargetIdProvider); } @@ -82,9 +86,9 @@ private ReferenceWidgetDescription getReferenceWidgetDescription() { .settingProvider(this::resolveSetting) .styleProvider(variableManager -> null) .ownerIdProvider(this::getOwnerId) - .diagnosticsProvider(variableManager -> List.of()) - .kindProvider(object -> "") - .messageProvider(object -> "") + .diagnosticsProvider(this.propertiesValidationProvider.getDiagnosticsProvider()) + .kindProvider(this.propertiesValidationProvider.getKindProvider()) + .messageProvider(this.propertiesValidationProvider.getMessageProvider()) .build(); } diff --git a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java index 39a4693637..89b6b63658 100644 --- a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java +++ b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesDefaultDescriptionProvider.java @@ -161,7 +161,7 @@ private GroupDescription getGroupDescription() { ifDescriptions.add(new EBooleanIfDescriptionProvider(this.composedAdapterFactory, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription()); ifDescriptions.add(new EEnumIfDescriptionProvider(this.composedAdapterFactory, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription()); - ifDescriptions.add(new NonContainmentReferenceIfDescriptionProvider(this.composedAdapterFactory, this.objectService, this.semanticTargetIdProvider).getIfDescription()); + ifDescriptions.add(new NonContainmentReferenceIfDescriptionProvider(this.composedAdapterFactory, this.objectService, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription()); // @formatter:off var numericDataTypes = List.of( diff --git a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesValidationProvider.java b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesValidationProvider.java index 3f290ad832..83300e4392 100644 --- a/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesValidationProvider.java +++ b/packages/compatibility/backend/sirius-components-compatibility-emf/src/main/java/org/eclipse/sirius/components/compatibility/emf/properties/PropertiesValidationProvider.java @@ -17,8 +17,8 @@ import java.util.function.Function; import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.sirius.components.collaborative.validation.api.IValidationService; import org.eclipse.sirius.components.compatibility.emf.properties.api.IPropertiesValidationProvider; import org.eclipse.sirius.components.representations.VariableManager; @@ -42,7 +42,7 @@ public PropertiesValidationProvider(IValidationService validationService) { public Function> getDiagnosticsProvider() { return variableManager -> { var optionalEObject = variableManager.get(VariableManager.SELF, EObject.class); - var optionalEAttribute = variableManager.get(PropertiesDefaultDescriptionProvider.ESTRUCTURAL_FEATURE, EAttribute.class); + var optionalEAttribute = variableManager.get(PropertiesDefaultDescriptionProvider.ESTRUCTURAL_FEATURE, EStructuralFeature.class); if (optionalEObject.isPresent() && optionalEAttribute.isPresent()) { return this.validationService.validate(optionalEObject.get(), optionalEAttribute.get()); } @@ -55,8 +55,7 @@ public Function> getDiagnosticsProvider() { public Function getKindProvider() { return object -> { String kind = "Unknown"; - if (object instanceof Diagnostic) { - Diagnostic diagnostic = (Diagnostic) object; + if (object instanceof Diagnostic diagnostic) { switch (diagnostic.getSeverity()) { case org.eclipse.emf.common.util.Diagnostic.ERROR: kind = "Error"; @@ -79,8 +78,7 @@ public Function getKindProvider() { @Override public Function getMessageProvider() { return object -> { - if (object instanceof Diagnostic) { - Diagnostic diagnostic = (Diagnostic) object; + if (object instanceof Diagnostic diagnostic) { return diagnostic.getMessage(); } return ""; diff --git a/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceElementProps.java b/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceElementProps.java index d23a2d7bd4..06412ea503 100644 --- a/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceElementProps.java +++ b/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceElementProps.java @@ -19,7 +19,7 @@ import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.sirius.components.annotations.Immutable; -import org.eclipse.sirius.components.forms.validation.Diagnostic; +import org.eclipse.sirius.components.representations.Element; import org.eclipse.sirius.components.representations.IProps; /** @@ -38,8 +38,6 @@ public final class ReferenceElementProps implements IProps { private String iconURL; - private List diagnostics; - private Supplier helpTextProvider; private boolean readOnly; @@ -54,6 +52,8 @@ public final class ReferenceElementProps implements IProps { private String ownerId; + private List children; + private ReferenceElementProps() { // Prevent instantiation } @@ -74,10 +74,6 @@ public String getIconURL() { return this.iconURL; } - public List getDiagnostics() { - return this.diagnostics; - } - public Supplier getHelpTextProvider() { return this.helpTextProvider; } @@ -106,6 +102,11 @@ public String getOwnerId() { return this.ownerId; } + @Override + public List getChildren() { + return this.children; + } + @Override public String toString() { String pattern = "{0} '{'id: {1}, label: {2}'}'"; @@ -128,8 +129,6 @@ public static final class Builder { private boolean readOnly; private Supplier helpTextProvider; - private List diagnostics; - private List values; private List options; @@ -140,6 +139,8 @@ public static final class Builder { private String ownerId; + private List children; + private Builder(String id) { this.id = Objects.requireNonNull(id); } @@ -164,11 +165,6 @@ public Builder readOnly(boolean readOnly) { return this; } - public Builder diagnostics(List diagnostics) { - this.diagnostics = Objects.requireNonNull(diagnostics); - return this; - } - public Builder values(List values) { this.values = Objects.requireNonNull(values); return this; @@ -194,12 +190,16 @@ public Builder ownerId(String ownerId) { return this; } + public Builder children(List children) { + this.children = Objects.requireNonNull(children); + return this; + } + public ReferenceElementProps build() { ReferenceElementProps referenceElementProps = new ReferenceElementProps(); referenceElementProps.id = Objects.requireNonNull(this.id); referenceElementProps.label = Objects.requireNonNull(this.label); referenceElementProps.iconURL = this.iconURL; - referenceElementProps.diagnostics = this.diagnostics; referenceElementProps.readOnly = this.readOnly; referenceElementProps.values = Objects.requireNonNull(this.values); referenceElementProps.options = Objects.requireNonNull(this.options); @@ -207,6 +207,7 @@ public ReferenceElementProps build() { referenceElementProps.helpTextProvider = this.helpTextProvider; // Optional on purpose referenceElementProps.style = this.style; // Optional on purpose referenceElementProps.ownerId = Objects.requireNonNull(this.ownerId); + referenceElementProps.children = Objects.requireNonNull(this.children); return referenceElementProps; } } diff --git a/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetComponent.java b/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetComponent.java index 5081f6c22c..271450d94a 100644 --- a/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetComponent.java +++ b/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetComponent.java @@ -19,6 +19,8 @@ import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.sirius.components.forms.ClickEventKind; import org.eclipse.sirius.components.forms.components.FormComponent; +import org.eclipse.sirius.components.forms.validation.DiagnosticComponent; +import org.eclipse.sirius.components.forms.validation.DiagnosticComponentProps; import org.eclipse.sirius.components.representations.Element; import org.eclipse.sirius.components.representations.IComponent; import org.eclipse.sirius.components.representations.IStatus; @@ -106,14 +108,16 @@ public Element render() { }) .toList(); + List children = List.of(new Element(DiagnosticComponent.class, new DiagnosticComponentProps(referenceDescription, variableManager))); + var builder = ReferenceElementProps.newReferenceElementProps(id) .label(label) .iconURL(iconURL) - .diagnostics(List.of()) .values(items) .options(options) .setting(setting) - .ownerId(ownerId); + .ownerId(ownerId) + .children(children); if (referenceDescription.getHelpTextProvider() != null) { builder.helpTextProvider(() -> referenceDescription.getHelpTextProvider().apply(variableManager)); } diff --git a/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetDescriptor.java b/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetDescriptor.java index 7b137a1d69..7564cff5fd 100644 --- a/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetDescriptor.java +++ b/packages/forms/backend/sirius-components-widget-reference/src/main/java/org/eclipse/sirius/components/widget/reference/ReferenceWidgetDescriptor.java @@ -18,6 +18,7 @@ import org.eclipse.sirius.components.forms.description.AbstractWidgetDescription; import org.eclipse.sirius.components.forms.renderer.IWidgetDescriptor; +import org.eclipse.sirius.components.forms.validation.Diagnostic; import org.eclipse.sirius.components.representations.Element; import org.eclipse.sirius.components.representations.IProps; import org.eclipse.sirius.components.representations.VariableManager; @@ -59,11 +60,17 @@ public Optional validateInstanceProps(String type, IProps props) { @Override public Optional instanciate(String type, IProps elementProps, List children) { Optional result = Optional.empty(); + + List diagnostics = children.stream() + .filter(Diagnostic.class::isInstance) + .map(Diagnostic.class::cast) + .toList(); + if (Objects.equals(type, ReferenceElementProps.TYPE) && elementProps instanceof ReferenceElementProps props) { var builder = ReferenceWidget.newReferenceWidget(props.getId()) .label(props.getLabel()) .iconURL(props.getIconURL()) - .diagnostics(props.getDiagnostics()) + .diagnostics(diagnostics) .readOnly(props.isReadOnly()) .setting(props.getSetting()) .referenceValues(props.getValues()) diff --git a/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx b/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx index cf7088ed08..65793979ea 100644 --- a/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx +++ b/packages/forms/frontend/sirius-components-widget-reference/src/components/ValuedReferenceAutocomplete.tsx @@ -138,6 +138,8 @@ export const ValuedReferenceAutocomplete = ({ {...params} variant="standard" placeholder={placeholder} + error={widget.diagnostics.length > 0} + helperText={widget.diagnostics[0]?.message} InputProps={{ ...params.InputProps, endAdornment: ( diff --git a/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/ViewPropertiesDescriptionRegistryConfigurer.java b/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/ViewPropertiesDescriptionRegistryConfigurer.java index c9dfef42a9..1f748dcbc7 100644 --- a/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/ViewPropertiesDescriptionRegistryConfigurer.java +++ b/packages/view/backend/sirius-components-view-emf/src/main/java/org/eclipse/sirius/components/view/emf/ViewPropertiesDescriptionRegistryConfigurer.java @@ -193,7 +193,7 @@ public boolean handles(EAttribute eAttribute) { ifDescriptions.add(new EBooleanIfDescriptionProvider(this.composedAdapterFactory, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription()); ifDescriptions.add(new EEnumIfDescriptionProvider(this.composedAdapterFactory, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription()); - ifDescriptions.add(new NonContainmentReferenceIfDescriptionProvider(this.composedAdapterFactory, this.objectService, this.semanticTargetIdProvider).getIfDescription()); + ifDescriptions.add(new NonContainmentReferenceIfDescriptionProvider(this.composedAdapterFactory, this.objectService, this.propertiesValidationProvider, this.semanticTargetIdProvider).getIfDescription()); var numericDataTypes = List.of( EcorePackage.Literals.EINT,