diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebPrismUtil.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebPrismUtil.java index 4bbd68c7669..20767a96c78 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebPrismUtil.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebPrismUtil.java @@ -682,9 +682,7 @@ public static String createMappingTypeDescription(MappingType mapping, boolean s if (showExpression) { ExpressionUtil.ExpressionEvaluatorType evaluatorType = null; if (expressionBean != null) { - String expression = ExpressionUtil.loadExpression(expressionBean, PrismContext.get(), LOGGER); - evaluatorType = ExpressionUtil.getExpressionType(expression); - + evaluatorType = ExpressionUtil.getExpressionType(expressionBean); } if (evaluatorType == null) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/AssociationFromLinkPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/AssociationFromLinkPanel.java index ba4bbfe7771..ff27d984135 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/AssociationFromLinkPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/AssociationFromLinkPanel.java @@ -14,6 +14,8 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AssociationFromLinkExpressionEvaluatorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; +import javax.xml.namespace.QName; + import org.apache.wicket.MarkupContainer; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -23,7 +25,11 @@ public class AssociationFromLinkPanel extends EvaluatorExpressionPanel { private static final Trace LOGGER = TraceManager.getTrace(AssociationFromLinkPanel.class); public AssociationFromLinkPanel(String id, IModel model) { - super(id, model); + this(id, model, null); + } + + public AssociationFromLinkPanel(String id, IModel model, IModel expressionTargetTypeModel) { + super(id, model, expressionTargetTypeModel); updateEvaluatorValue(); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/EvaluatorExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/EvaluatorExpressionPanel.java index a193c5e4e3b..dcffa541748 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/EvaluatorExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/EvaluatorExpressionPanel.java @@ -6,6 +6,8 @@ package com.evolveum.midpoint.gui.impl.component.input.expression; +import javax.xml.namespace.QName; + import com.evolveum.midpoint.gui.api.component.BasePanel; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.impl.component.message.FeedbackLabels; @@ -24,8 +26,29 @@ public abstract class EvaluatorExpressionPanel extends BasePanel private static final String ID_VALUE_CONTAINER = "valueContainer"; private static final String ID_FEEDBACK = "feedback"; + /** + * Type of the object the expression is evaluated against. Null when the context does not tell us. + */ + private final IModel expressionTargetTypeModel; + public EvaluatorExpressionPanel(String id, IModel model) { + this(id, model, null); + } + + public EvaluatorExpressionPanel(String id, IModel model, IModel expressionTargetTypeModel) { super(id, model); + this.expressionTargetTypeModel = expressionTargetTypeModel; + } + + /** + * Type of the object the expression is evaluated against, for panels that need to know the + * schema they work with. + * + * @return the type, or null when the context does not tell us and the panel has to manage + * without it. + */ + protected QName getExpressionTargetType() { + return expressionTargetTypeModel != null ? expressionTargetTypeModel.getObject() : null; } @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ExpressionPanel.java index 53d110f0774..000a56930db 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ExpressionPanel.java @@ -53,6 +53,8 @@ import com.evolveum.midpoint.web.util.ExpressionUtil.ExpressionEvaluatorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; +import javax.xml.namespace.QName; + import org.apache.wicket.model.StringResourceModel; import org.jetbrains.annotations.NotNull; @@ -97,6 +99,9 @@ public enum RecognizedEvaluator { PATH(ExpressionEvaluatorType.PATH, PathExpressionPanel.class, "ExpressionEvaluatorType.PATH.show.button"), + FILTER(ExpressionEvaluatorType.FILTER, + FilterExpressionPanel.class, + "ExpressionEvaluatorType.FILTER.show.button"), NULL(ExpressionEvaluatorType.NULL, null, null); @@ -159,9 +164,7 @@ private void initTypeModels() { typeModel = new LoadableModel<>(false) { @Override protected RecognizedEvaluator load() { - String expression = ExpressionUtil.loadExpression(getModelObject(), PrismContext.get(), LOGGER); - - ExpressionEvaluatorType type = ExpressionUtil.getExpressionType(expression); + ExpressionEvaluatorType type = ExpressionUtil.getExpressionType(getModelObject()); return recognizeEvaluator(type); } @@ -435,6 +438,28 @@ public void onClick(AjaxRequestTarget target) { return typeButton; } + /** + * Returns type of the object the expression is evaluated against, taken from the schema context of the item. + * + * @return target object type of expression or null while the schema context is not defined for the expression. + */ + private QName resolveExpressionTargetType() { + PrismPropertyWrapper wrapper = parent != null ? parent.getObject() : null; + if (wrapper == null) { + return null; + } + + var item = wrapper.getItem(); + if (item == null || item.getValue() == null) { + return null; + } + var schemaContext = item.getValue().getSchemaContext(); + if (schemaContext == null || schemaContext.getItemDefinition() == null) { + return null; + } + return schemaContext.getItemDefinition().getTypeName(); + } + private WebMarkupContainer createEvaluatorPanel() { return createEvaluatorPanel(ExpressionPanel.ID_EVALUATOR_PANEL, false); } @@ -443,8 +468,10 @@ private WebMarkupContainer createEvaluatorPanel(String id, boolean isInPopup) { RecognizedEvaluator type = typeModel.getObject(); if (type != null && type.evaluatorPanel != null) { try { - Constructor> constructor = type.evaluatorPanel.getConstructor(String.class, IModel.class); - BasePanel evaluatorPanel = constructor.newInstance(id, getModel()); + Constructor> constructor = + type.evaluatorPanel.getConstructor(String.class, IModel.class, IModel.class); + BasePanel evaluatorPanel = + constructor.newInstance(id, getModel(), (IModel) this::resolveExpressionTargetType); evaluatorPanel.setOutputMarkupId(true); evaluatorPanel.add(new VisibleBehaviour(() -> isInPopup || isEvaluatorPanelExpanded())); if (!isInTable()) { @@ -453,7 +480,7 @@ private WebMarkupContainer createEvaluatorPanel(String id, boolean isInPopup) { return evaluatorPanel; } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { LOGGER.error("Couldn't create panel for expression evaluator by constructor for class {} with parameters type: " - + "String, IModel", type.evaluatorPanel.getSimpleName()); + + "String, IModel, IModel", type.evaluatorPanel.getSimpleName()); } } WebMarkupContainer invisiblePanel = new WebMarkupContainer(id); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/FilterExpressionPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/FilterExpressionPanel.html new file mode 100644 index 00000000000..ab59ee4adc2 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/FilterExpressionPanel.html @@ -0,0 +1,17 @@ + + + + + +
+
+ +
+
+
+ + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/FilterExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/FilterExpressionPanel.java new file mode 100644 index 00000000000..ac4388eb1c8 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/FilterExpressionPanel.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2026 Evolveum and contributors + * + * Licensed under the EUPL-1.2 or later. + */ + +package com.evolveum.midpoint.gui.impl.component.input.expression; + +import javax.xml.namespace.QName; + +import org.apache.wicket.MarkupContainer; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.LambdaModel; +import org.apache.wicket.model.StringResourceModel; + +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.page.admin.reports.component.SearchFilterConfigurationPanel; +import com.evolveum.midpoint.web.util.ExpressionUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FilterExpressionEvaluatorType; +import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; + +public class FilterExpressionPanel extends EvaluatorExpressionPanel { + + private static final Trace LOGGER = TraceManager.getTrace(FilterExpressionPanel.class); + + private static final String ID_FILTER_INPUT = "filterInput"; + + public FilterExpressionPanel(String id, IModel model, IModel expressionTargetTypeModel) { + super(id, model, expressionTargetTypeModel); + } + + @Override + public IModel getValueContainerLabelModel(PageBase pageBase) { + return pageBase.createStringResource("FilterExpressionPanel.label"); + } + + @Override + protected void initLayout(MarkupContainer parent) { + parent.add(new SearchFilterConfigurationPanel<>( + ID_FILTER_INPUT, null, createFilterModel(), this::getExpressionTargetType) { + + @Override + protected StringResourceModel getConfigPanelTitle() { + return createStringResource("FilterExpressionPanel.configureFilter"); + } + + @Override + protected boolean addEmptyBlumBehaviourToTextField() { + return true; + } + }); + } + + /** + * Model of the filter of the expression. {@link LambdaModel} skips the setter when its target + * object is null, and the expression of an empty condition is null, so the target falls back to + * a fresh expression. Without it the first filter the user configures is silently dropped. + */ + private IModel createFilterModel() { + return LambdaModel.of( + getModel().orElseGet(ExpressionType::new), FilterExpressionPanel::readFilter, this::writeFilter); + } + + private static SearchFilterType readFilter(ExpressionType expression) { + FilterExpressionEvaluatorType evaluator = ExpressionUtil.getFilterExpressionValue(expression); + return evaluator != null ? evaluator.getFilter() : null; + } + + private void writeFilter(ExpressionType expression, SearchFilterType filter) { + try { + FilterExpressionEvaluatorType evaluator = filter == null + ? null + : new FilterExpressionEvaluatorType().filter(filter); + getModel().setObject( + ExpressionUtil.updateFilterExpressionValue(expression, evaluator)); + } catch (SchemaException ex) { + LOGGER.error("Couldn't update filter expression value: {}", ex.getLocalizedMessage()); + getPageBase().error("Couldn't update filter expression value: " + ex.getLocalizedMessage()); + } + } + + /** + * Description of the filter shown in the tooltip of the collapsed expression. Looked up by class + * and method name from {@link ExpressionPanel}, do not remove. + * + * @param expression expression the filter belongs to. + * @param pageBase page the description is created for. + * @return the query text of the filter, or an empty string when there is none. + */ + public static String getInfoDescription(ExpressionType expression, PageBase pageBase) { + FilterExpressionEvaluatorType evaluator = ExpressionUtil.getFilterExpressionValue(expression); + if (evaluator == null || evaluator.getFilter() == null) { + return ""; + } + String text = evaluator.getFilter().getText(); + return text != null ? text : ""; + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/GenerateExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/GenerateExpressionPanel.java index dcc106185c8..ff2abc8de70 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/GenerateExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/GenerateExpressionPanel.java @@ -36,7 +36,11 @@ public class GenerateExpressionPanel extends EvaluatorExpressionPanel { private static final String ID_VALUE_POLICY = "valuePolicy"; public GenerateExpressionPanel(String id, IModel model) { - super(id, model); + this(id, model, null); + } + + public GenerateExpressionPanel(String id, IModel model, IModel expressionTargetTypeModel) { + super(id, model, expressionTargetTypeModel); GenerateExpressionWrapper wrapper = getEvaluatorValue(); if (wrapper == null || wrapper.isEmpty()) { updateEvaluatorValue((GenerateExpressionEvaluatorModeType) null); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/PathExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/PathExpressionPanel.java index cf7955cee07..71324b7b1df 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/PathExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/PathExpressionPanel.java @@ -17,6 +17,8 @@ import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; +import javax.xml.namespace.QName; + import org.apache.wicket.Component; import org.apache.wicket.MarkupContainer; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -33,7 +35,11 @@ public class PathExpressionPanel extends EvaluatorExpressionPanel { private static final String ID_PATH_LABEL = "pathLabel"; public PathExpressionPanel(String id, IModel model) { - super(id, model); + this(id, model, null); + } + + public PathExpressionPanel(String id, IModel model, IModel expressionTargetTypeModel) { + super(id, model, expressionTargetTypeModel); } @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ScriptExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ScriptExpressionPanel.java index 880e7b7cdf9..e3e0a1e4e0d 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ScriptExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ScriptExpressionPanel.java @@ -17,6 +17,8 @@ import com.evolveum.midpoint.web.page.admin.reports.component.SimpleAceEditorPanel; import com.evolveum.midpoint.web.util.ExpressionUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; + +import javax.xml.namespace.QName; import com.evolveum.midpoint.xml.ns._public.common.common_3.ScriptExpressionEvaluatorType; import org.apache.commons.lang3.StringUtils; @@ -47,7 +49,11 @@ public class ScriptExpressionPanel extends EvaluatorExpressionPanel { private static final String C_DATA_SUFFIX = "]]>"; public ScriptExpressionPanel(String id, IModel model) { - super(id, model); + this(id, model, null); + } + + public ScriptExpressionPanel(String id, IModel model, IModel expressionTargetTypeModel) { + super(id, model, expressionTargetTypeModel); } @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ShadowOwnerReferenceSearchExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ShadowOwnerReferenceSearchExpressionPanel.java index c772966e970..195dce0ad53 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ShadowOwnerReferenceSearchExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/ShadowOwnerReferenceSearchExpressionPanel.java @@ -42,7 +42,12 @@ public class ShadowOwnerReferenceSearchExpressionPanel extends EvaluatorExpressi private static final String ID_RELATION_EXPRESSION_LABEL = "relationExpressionLabel"; public ShadowOwnerReferenceSearchExpressionPanel(String id, IModel model) { - super(id, model); + this(id, model, null); + } + + public ShadowOwnerReferenceSearchExpressionPanel( + String id, IModel model, IModel expressionTargetTypeModel) { + super(id, model, expressionTargetTypeModel); updateEvaluatorValue(); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/SimpleValueExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/SimpleValueExpressionPanel.java index bcb3e705b1d..e56767279d3 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/SimpleValueExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/component/input/expression/SimpleValueExpressionPanel.java @@ -32,6 +32,8 @@ import com.evolveum.midpoint.web.util.ExpressionUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; +import javax.xml.namespace.QName; + import org.jetbrains.annotations.NotNull; public class SimpleValueExpressionPanel extends EvaluatorExpressionPanel { @@ -46,7 +48,11 @@ public class SimpleValueExpressionPanel extends EvaluatorExpressionPanel { private static final String ID_REMOVE_BUTTON = "remove"; public SimpleValueExpressionPanel(String id, IModel model) { - super(id, model); + this(id, model, null); + } + + public SimpleValueExpressionPanel(String id, IModel model, IModel expressionTargetTypeModel) { + super(id, model, expressionTargetTypeModel); if (getEvaluatorValues().isEmpty()) { updateEvaluatorValue(List.of()); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/expression/ConditionPanelFactory.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/expression/ConditionPanelFactory.java index 71b88bf3d46..dbaf199cda4 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/expression/ConditionPanelFactory.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/expression/ConditionPanelFactory.java @@ -7,10 +7,12 @@ package com.evolveum.midpoint.gui.impl.factory.panel.expression; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import com.evolveum.midpoint.gui.api.prism.wrapper.PrismValueWrapper; -import com.evolveum.midpoint.gui.impl.component.input.expression.ScriptExpressionPanel; +import com.evolveum.midpoint.gui.impl.component.input.expression.ExpressionPanel; import com.evolveum.midpoint.gui.impl.factory.panel.PrismPropertyPanelContext; import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; @@ -33,7 +35,14 @@ public void register() { @Override protected Panel getPanel(PrismPropertyPanelContext panelCtx) { - return new ScriptExpressionPanel(panelCtx.getComponentId(), panelCtx.getRealValueModel()); + return new ExpressionPanel( + panelCtx.getComponentId(), panelCtx.getItemWrapperModel(), panelCtx.getRealValueModel()) { + + @Override + protected List getChoices() { + return new ArrayList<>(List.of(RecognizedEvaluator.SCRIPT, RecognizedEvaluator.FILTER)); + } + }; } @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/searchfilter/SearchFilterPanelFactory.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/searchfilter/SearchFilterPanelFactory.java index be8f6a66bf7..ccf57123e17 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/searchfilter/SearchFilterPanelFactory.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/panel/searchfilter/SearchFilterPanelFactory.java @@ -32,6 +32,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.wicket.feedback.ComponentFeedbackMessageFilter; +import org.apache.wicket.model.Model; import org.springframework.stereotype.Component; @Component @@ -77,7 +78,8 @@ public void configure(PrismPropertyPanelContext panelCtx, org. @Override protected InputPanel getPanel(PrismPropertyPanelContext panelCtx) { return new SearchFilterConfigurationPanel( - panelCtx.getComponentId(), panelCtx.getItemWrapperModel(), panelCtx.getRealValueModel(), getFilterObjectType(panelCtx) + panelCtx.getComponentId(), panelCtx.getItemWrapperModel(), panelCtx.getRealValueModel(), + Model.of(getFilterObjectType(panelCtx)) ); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/FilterExpressionPreviewDetailsPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/FilterExpressionPreviewDetailsPanel.html new file mode 100644 index 00000000000..9efb5a7c4ae --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/FilterExpressionPreviewDetailsPanel.html @@ -0,0 +1,12 @@ + + + + + +
+
+ diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/FilterExpressionPreviewDetailsPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/FilterExpressionPreviewDetailsPanel.java new file mode 100644 index 00000000000..4d655b43a70 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/FilterExpressionPreviewDetailsPanel.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010-2026 Evolveum and contributors + * + * Licensed under the EUPL-1.2 or later. + */ +package com.evolveum.midpoint.gui.impl.page.admin.resource.component.wizard.schemaHandling.objectType.attribute.mapping.preview.expression; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.IModel; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.web.util.ExpressionUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FilterExpressionEvaluatorType; +import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; + +/** + * Preview panel for filter expressions. + */ +public class FilterExpressionPreviewDetailsPanel extends BasePanel { + + private static final String ID_QUERY = "query"; + + public FilterExpressionPreviewDetailsPanel(String id, IModel model) { + super(id, model); + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + add(new Label(ID_QUERY, getModel().map(FilterExpressionPreviewDetailsPanel::extractQuery))); + } + + private static String extractQuery(ExpressionType expression) { + FilterExpressionEvaluatorType evaluator = ExpressionUtil.getFilterExpressionValue(expression); + if (evaluator == null || evaluator.getFilter() == null) { + return null; + } + return evaluator.getFilter().getText(); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/PreviewExpressionPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/PreviewExpressionPanel.java index cde2aa97799..95a2a6d372a 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/PreviewExpressionPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/page/admin/resource/component/wizard/schemaHandling/objectType/attribute/mapping/preview/expression/PreviewExpressionPanel.java @@ -20,9 +20,6 @@ import org.jetbrains.annotations.NotNull; import com.evolveum.midpoint.gui.api.component.BasePanel; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.util.VisibleBehaviour; import com.evolveum.midpoint.web.util.ExpressionUtil; import com.evolveum.midpoint.web.util.ExpressionUtil.ExpressionEvaluatorType; @@ -33,8 +30,6 @@ */ public class PreviewExpressionPanel extends BasePanel { - private static final Trace LOGGER = TraceManager.getTrace(PreviewExpressionPanel.class); - private static final String ID_EXPRESSION_LABEL = "expressionLabel"; private static final String ID_TYPE_BADGE = "typeBadge"; private static final String ID_DESCRIPTION = "description"; @@ -55,6 +50,8 @@ public enum RecognizedEvaluator { "ExpressionEvaluatorType.SHADOW_OWNER_REFERENCE_SEARCH"), PATH(ExpressionEvaluatorType.PATH, "ExpressionEvaluatorType.PATH"), + FILTER(ExpressionEvaluatorType.FILTER, + "ExpressionEvaluatorType.FILTER"), NULL(ExpressionEvaluatorType.NULL, "ExpressionEvaluatorType.NULL"); @@ -127,8 +124,7 @@ private String getDescription() { } private RecognizedEvaluator resolveEvaluator() { - String expression = ExpressionUtil.loadExpression(getModelObject(), PrismContext.get(), LOGGER); - ExpressionEvaluatorType type = ExpressionUtil.getExpressionType(expression); + ExpressionEvaluatorType type = ExpressionUtil.getExpressionType(getModelObject()); return recognizeEvaluator(type); } @@ -142,6 +138,7 @@ private RecognizedEvaluator resolveEvaluator() { case LITERAL -> new LiteralExpressionPreviewDetailsPanel(PreviewExpressionPanel.ID_DETAILS, getModel()); case PATH -> new PathExpressionPreviewDetailsPanel(PreviewExpressionPanel.ID_DETAILS, getModel()); case GENERATE -> new GenerateExpressionPreviewDetailsPanel(PreviewExpressionPanel.ID_DETAILS, getModel()); + case FILTER -> new FilterExpressionPreviewDetailsPanel(PreviewExpressionPanel.ID_DETAILS, getModel()); default -> invisiblePanel(); }; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.html index 93dce79ae3a..79e87fc3d22 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.html @@ -12,10 +12,10 @@ diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.java index f9135ae3c31..2d9924150ae 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/component/SearchFilterConfigurationPanel.java @@ -22,6 +22,7 @@ import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.FormComponent; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.StringResourceModel; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; @@ -64,7 +65,7 @@ private enum FieldType { private LoadableModel> filterTypeModel; - private QName filterObjectType; + private final IModel filterObjectTypeModel; private FieldType fieldType; @@ -72,11 +73,11 @@ private enum FieldType { private final IModel beanModel; public SearchFilterConfigurationPanel(String id, IModel> itemModel, - IModel model, QName filterObjectType) { + IModel model, IModel filterObjectTypeModel) { super(id); this.beanModel = model; this.itemModel = itemModel; - this.filterObjectType = filterObjectType; + this.filterObjectTypeModel = filterObjectTypeModel; // todo why resolving model in constructor? if (model.getObject() == null || StringUtils.isNotBlank(model.getObject().getText())) { fieldType = FieldType.QUERY; @@ -88,10 +89,15 @@ public SearchFilterConfigurationPanel(String id, IModel() { @Serial private static final long serialVersionUID = 1L; @@ -99,8 +105,8 @@ private void initFilterTypeModel() { @Override public Class load() { QName filterType = null; - if (filterObjectType != null) { - filterType = filterObjectType; + if (getFilterObjectType() != null) { + filterType = getFilterObjectType(); } else if (itemModel != null && itemModel.getObject() != null ) { var item = itemModel.getObject().getItem(); if (item != null && item.getValue() != null) { @@ -125,7 +131,7 @@ private void initLayout() { aceEditorField.add(new VisibleBehaviour(() -> FieldType.XML.equals(fieldType))); container.add(aceEditorField); - SearchFilterTypeForQueryModel queryModel = createQueryModel(getModel(), filterTypeModel, filterObjectType != null); + SearchFilterTypeForQueryModel queryModel = createQueryModel(getModel(), filterTypeModel, getFilterObjectType() != null); TextPanel textPanel = new TextPanel(ID_TEXT_FIELD, queryModel); textPanel.add(new VisibleBehaviour(() -> FieldType.QUERY.equals(fieldType))); if (addEmptyBlumBehaviourToTextField()) { @@ -142,7 +148,7 @@ public void onClick(AjaxRequestTarget target) { searchConfigurationPerformed(target); } }; - searchConfigurationButton.add(new VisibleBehaviour(() -> filterObjectType != null)); + searchConfigurationButton.add(new VisibleBehaviour(() -> getFilterObjectType() != null)); add(searchConfigurationButton); IModel labelModel = () -> { @@ -216,12 +222,28 @@ protected void filterConfiguredPerformed(ObjectFilter configuredFilter, AjaxRequ LoggingUtils.logUnexpectedException(LOGGER, "Cannot serialize filter", e); } } + + @Override + public StringResourceModel getTitle() { + StringResourceModel title = getConfigPanelTitle(); + return title != null ? title : super.getTitle(); + } }; getPageBase().showMainPopup(configPanel, target); } + + /** + * Title of the query builder popup. Null keeps the default one. + * + * @return the {@code StringResourceModel} representing the title of the configuration panel. + */ + protected StringResourceModel getConfigPanelTitle() { + return null; + } + private void updateModelToMidpointQuery() { - if (filterObjectType == null || getModel().getObject() == null) { + if (getFilterObjectType() == null || getModel().getObject() == null) { return; } SearchFilterTypeForQueryModel queryModel = createQueryModel(getModel(), filterTypeModel, true); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java index 76302844481..21faf5b63e3 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionUtil.java @@ -56,6 +56,7 @@ public enum ExpressionEvaluatorType { GENERATE, ASSOCIATION_FROM_LINK, SHADOW_OWNER_REFERENCE_SEARCH, + FILTER, NULL } @@ -162,6 +163,21 @@ public static String getExpressionString(ExpressionEvaluatorType type) { } } + /** + * + * Recognizes the evaluator from the bean. Preferred over the text based variant - search evaluators + * contain a nested {@code filter} element, so the serialized form cannot tell them apart. + * + * @param expression expression in which we are looking for the evaluator. + * @return expression evaluator type. + */ + public static ExpressionEvaluatorType getExpressionType(ExpressionType expression) { + if (!findAllEvaluatorsByName(expression, SchemaConstantsGenerated.C_FILTER).isEmpty()) { + return ExpressionEvaluatorType.FILTER; + } + return getExpressionType(loadExpression(expression, PrismContext.get(), LOGGER)); + } + public static ExpressionEvaluatorType getExpressionType(String expression) { if (expression.contains(ELEMENT_SHADOW_OWNER_REFERENCE_SEARCH) || expression.contains(ELEMENT_SHADOW_OWNER_REFERENCE_SEARCH_WITH_NS)) { return ExpressionEvaluatorType.SHADOW_OWNER_REFERENCE_SEARCH; @@ -586,6 +602,22 @@ public static ScriptExpressionEvaluatorType getScriptExpressionValue(ExpressionT return null; } + /** + * Returns the filter evaluator of the expression. + * + * @param expression in which we are looking for the evaluator. + * @return the filter evaluator, or null when the expression has none. + */ + public static FilterExpressionEvaluatorType getFilterExpressionValue(ExpressionType expression) { + List> elements = ExpressionUtil.findAllEvaluatorsByName(expression, SchemaConstantsGenerated.C_FILTER); + for (JAXBElement element : elements) { + if (element.getValue() instanceof FilterExpressionEvaluatorType evaluator) { + return evaluator; + } + } + return null; + } + public static ItemPathType getPathExpressionValue(ExpressionType expression) throws SchemaException { List> elements = ExpressionUtil.findAllEvaluatorsByName(expression, SchemaConstantsGenerated.C_PATH); for (JAXBElement element : elements) { @@ -665,6 +697,19 @@ public static ExpressionType updateScriptExpressionValue( expression, evaluator, ScriptExpressionEvaluatorType.class, SchemaConstantsGenerated.C_SCRIPT); } + /** + * Makes the filter evaluator the only evaluator of the expression. A null evaluator removes it. + * + * @param expression to update, created when null. + * @param evaluator filter evaluator to store. + * @return the updated expression, or null when the evaluator was null. + */ + public static ExpressionType updateFilterExpressionValue( + ExpressionType expression, FilterExpressionEvaluatorType evaluator) throws SchemaException { + return updateExpressionEvaluator( + expression, evaluator, FilterExpressionEvaluatorType.class, SchemaConstantsGenerated.C_FILTER); + } + public static ExpressionType updatePathEvaluator(ExpressionType expression, ItemPathType path) throws SchemaException { return updateExpressionEvaluator( expression, path, ItemPathType.class, SchemaConstantsGenerated.C_PATH);