Skip to content

Commit

Permalink
MID-8907 improved configuration for request access ui - autocomplete …
Browse files Browse the repository at this point in the history
…search and result display.
  • Loading branch information
1azyman committed Jul 11, 2023
1 parent 44e334d commit dbd06c4
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 128 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2010-2023 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.gui.api.component.autocomplete;

import java.util.Collection;
import java.util.function.Function;

import com.evolveum.midpoint.util.logging.TraceManager;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.util.ModelServiceLocator;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.repo.common.expression.Expression;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.repo.common.expression.ExpressionFactory;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.expression.VariablesMap;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.MiscSchemaUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

public interface AutocompleteConfigurationMixin {

Trace LOGGER = TraceManager.getTrace(AutocompleteConfigurationMixin.class);

default <O extends ObjectType> String getDisplayNameFromExpression(
String contextDesc, @Nullable ExpressionType expressionType,
@NotNull Function<PrismObject<O>, String> defaultDisplayNameFunction,
@NotNull PrismObject<O> object, @NotNull BasePanel<?> panel) {

if (expressionType == null) {
return defaultDisplayNameFunction.apply(object);
}

ModelServiceLocator locator = panel.getPageBase();

Task task = panel.getPageBase().getPageTask();
OperationResult result = task.getResult();

try {
ExpressionFactory factory = locator.getExpressionFactory();
PrismContext ctx = object.getPrismContext();
PrismPropertyDefinition<String> outputDefinition = ctx.definitionFactory().createPropertyDefinition(
ExpressionConstants.OUTPUT_ELEMENT_NAME, DOMUtil.XSD_STRING);

Expression<PrismPropertyValue<String>, PrismPropertyDefinition<String>> expression =
factory.makeExpression(expressionType, outputDefinition, MiscSchemaUtil.getExpressionProfile(), contextDesc, task, result);

VariablesMap variables = new VariablesMap();
variables.put(ExpressionConstants.VAR_OBJECT, object, object.getDefinition());

ExpressionEvaluationContext context = new ExpressionEvaluationContext(null, variables, contextDesc, task);
context.setExpressionFactory(factory);
PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = expression.evaluate(context, result);
if (outputTriple == null) {
return null;
}
Collection<PrismPropertyValue<String>> outputValues = outputTriple.getNonNegativeValues();
if (outputValues.isEmpty()) {
return null;
}
if (outputValues.size() > 1) {
return null;
}
return outputValues.iterator().next().getRealValue();
} catch (Exception ex) {
result.recordFatalError(ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't evaluate expression for group selection and user display name", ex);
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,18 @@

package com.evolveum.midpoint.gui.impl.page.self.requestAccess;

import java.util.Collection;
import java.util.function.Function;

import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.Page;

import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.ModelServiceLocator;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.model.api.authentication.CompiledGuiProfile;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.repo.common.expression.Expression;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.repo.common.expression.ExpressionFactory;
import com.evolveum.midpoint.repo.common.expression.ExpressionUtil;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.expression.VariablesMap;
Expand All @@ -37,7 +30,6 @@
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessRequestType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType;

Expand Down Expand Up @@ -81,43 +73,10 @@ default ObjectFilter createAutocompleteFilter(String text, SearchFilterType filt
return defaultFilterFunction.apply(text);
}

default String getDisplayNameFromExpression(String contextDesc, ExpressionType expressionType, PrismObject<?> object, BasePanel<?> panel) {
ModelServiceLocator locator = panel.getPageBase();
default String getDefaultUserDisplayName(PrismObject<UserType> o) {
String name = WebComponentUtil.getOrigStringFromPoly(o.getName());
String fullName = WebComponentUtil.getOrigStringFromPoly(o.asObjectable().getFullName());

Task task = panel.getPageBase().getPageTask();
OperationResult result = task.getResult();

try {
ExpressionFactory factory = locator.getExpressionFactory();
PrismContext ctx = object.getPrismContext();
PrismPropertyDefinition<String> outputDefinition = ctx.definitionFactory().createPropertyDefinition(
ExpressionConstants.OUTPUT_ELEMENT_NAME, DOMUtil.XSD_STRING);

Expression<PrismPropertyValue<String>, PrismPropertyDefinition<String>> expression =
factory.makeExpression(expressionType, outputDefinition, MiscSchemaUtil.getExpressionProfile(), contextDesc, task, result);

VariablesMap variables = new VariablesMap();
variables.put(ExpressionConstants.VAR_OBJECT, object, object.getDefinition());

ExpressionEvaluationContext context = new ExpressionEvaluationContext(null, variables, contextDesc, task);
context.setExpressionFactory(factory);
PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = expression.evaluate(context, result);
if (outputTriple == null) {
return null;
}
Collection<PrismPropertyValue<String>> outputValues = outputTriple.getNonNegativeValues();
if (outputValues.isEmpty()) {
return null;
}
if (outputValues.size() > 1) {
return null;
}
return outputValues.iterator().next().getRealValue();
} catch (Exception ex) {
result.recordFatalError(ex);
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't evaluate expression for group selection and user display name", ex);
}

return null;
return StringUtils.isNotEmpty(fullName) ? fullName + " (" + name + ")" : name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
import org.wicketstuff.select2.Select2MultiChoice;

import com.evolveum.midpoint.gui.api.component.ObjectBrowserPanel;
import com.evolveum.midpoint.gui.api.component.autocomplete.AutocompleteConfigurationMixin;
import com.evolveum.midpoint.gui.api.component.wizard.BasicWizardStepPanel;
import com.evolveum.midpoint.gui.api.component.wizard.WizardModel;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.LocalizationUtil;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils;
import com.evolveum.midpoint.gui.impl.component.tile.Tile;
Expand Down Expand Up @@ -71,6 +73,8 @@ public class PersonOfInterestPanel extends BasicWizardStepPanel<RequestAccess> i

private static final String DEFAULT_TILE_ICON = "fas fa-user-friends";

private static final int AUTOCOMPLETE_MIN_CHARS = 2;

private enum TileType {

MYSELF("fas fa-user-circle"),
Expand All @@ -88,16 +92,8 @@ public String getIcon() {
}
}

private static class PersonOfInterest implements Serializable {

private final String groupIdentifier;
private record PersonOfInterest(String groupIdentifier, TileType type) implements Serializable {

private final TileType type;

public PersonOfInterest(String groupIdentifier, TileType type) {
this.groupIdentifier = groupIdentifier;
this.type = type;
}
}

private enum SelectionState {
Expand Down Expand Up @@ -233,7 +229,7 @@ private Tile<PersonOfInterest> createTile(GroupSelectionType selection) {

String label = getString(TileType.GROUP_OTHERS);
if (display.getLabel() != null) {
label = WebComponentUtil.getTranslatedPolyString(display.getLabel());
label = LocalizationUtil.translatePolyString(display.getLabel());
}

Tile<PersonOfInterest> tile = new Tile<>(icon, label);
Expand Down Expand Up @@ -289,12 +285,8 @@ protected void populateItem(ListItem<Tile<PersonOfInterest>> item) {
protected void onClick(AjaxRequestTarget target) {
Tile<PersonOfInterest> tile = item.getModelObject();
switch (tile.getValue().type) {
case MYSELF:
myselfPerformed(target, tile);
break;
case GROUP_OTHERS:
groupOthersPerformed(target, tile);
break;
case MYSELF -> myselfPerformed(target, tile);
case GROUP_OTHERS -> groupOthersPerformed(target, tile);
}
}
};
Expand All @@ -306,6 +298,25 @@ protected void onClick(AjaxRequestTarget target) {
return fragment;
}

private AutocompleteSearchConfigurationType getAutocompleteConfiguration() {
GroupSelectionType group = getSelectedGroupSelection();
if (group == null) {
return new AutocompleteSearchConfigurationType();
}

AutocompleteSearchConfigurationType config = group.getAutoCompleteConfiguration();
if (config != null) {
return config;
}

config = new AutocompleteSearchConfigurationType();
config.setAutocompleteMinChars(group.getAutocompleteMinChars());
config.setDisplayExpression(group.getUserDisplayName());
config.setSearchFilterTemplate(group.getSearchFilterTemplate());

return config;
}

private Fragment initSelectionFragment() {
Fragment fragment = new Fragment(ID_FRAGMENTS, ID_SELECTION_FRAGMENT, this);

Expand All @@ -325,18 +336,10 @@ public void setObject(Collection<ObjectReferenceType> object) {
Select2MultiChoice<ObjectReferenceType> multiselect = new Select2MultiChoice<>(ID_MULTISELECT, multiselectModel,
new ObjectReferenceProvider(this));

GroupSelectionType group = getSelectedGroupSelection();
AutocompleteSearchConfigurationType autocompleteConfig = group.getAutoCompleteConfiguration();
if (autocompleteConfig == null) {
autocompleteConfig = new AutocompleteSearchConfigurationType();
}

int minLength = 2;
if (group != null && group.getAutocompleteMinChars() != null) {
minLength = group.getAutocompleteMinChars();
}
AutocompleteSearchConfigurationType config = getAutocompleteConfiguration();
int minLength = config.getAutocompleteMinChars() != null ? config.getAutocompleteMinChars() : AUTOCOMPLETE_MIN_CHARS;
if (minLength < 0) {
minLength = 2;
minLength = AUTOCOMPLETE_MIN_CHARS;
}
multiselect.getSettings()
.setMinimumInputLength(minLength);
Expand All @@ -352,7 +355,7 @@ protected void onUpdate(AjaxRequestTarget target) {
});
fragment.add(multiselect);

AjaxLink selectManually = new AjaxLink<>(ID_SELECT_MANUALLY) {
AjaxLink<?> selectManually = new AjaxLink<>(ID_SELECT_MANUALLY) {

@Override
public void onClick(AjaxRequestTarget target) {
Expand Down Expand Up @@ -425,15 +428,7 @@ public IModel<Boolean> isStepVisible() {

@Override
protected void onBeforeRender() {
Fragment fragment;
switch (selectionState.getObject()) {
case USERS:
fragment = initSelectionFragment();
break;
case TILES:
default:
fragment = initTileFragment();
}
Fragment fragment = selectionState.getObject() == SelectionState.USERS ? initSelectionFragment() : initTileFragment();
addOrReplace(fragment);

super.onBeforeRender();
Expand Down Expand Up @@ -663,33 +658,21 @@ private TargetSelectionType getTargetSelectionConfiguration() {
return result != null ? result : new TargetSelectionType();
}

private SearchFilterType getSearchFilterTemplate() {
GroupSelectionType group = getSelectedGroupSelection();
if (group == null || group.getAutoCompleteConfiguration() == null) {
return null;
}

if (group.getAutoCompleteConfiguration() != null) {
return group.getAutoCompleteConfiguration().getSearchFilterTemplate();
}

return group.getSearchFilterTemplate();
}

private ObjectFilter getAutocompleteFilter(String text) {
return createAutocompleteFilter(text, getSearchFilterTemplate(), (t) -> createDefaultFilter(t), page);
return createAutocompleteFilter(
text, getAutocompleteConfiguration().getSearchFilterTemplate(), (t) -> createDefaultFilter(t), page);
}

private ObjectFilter createDefaultFilter(String text) {
return getPrismContext().queryFor(UserType.class)
.item(UserType.F_NAME).containsPoly(text).matchingNorm().buildFilter();
}

public static class ObjectReferenceProvider extends ChoiceProvider<ObjectReferenceType> {
public static class ObjectReferenceProvider extends ChoiceProvider<ObjectReferenceType> implements AutocompleteConfigurationMixin {

@Serial private static final long serialVersionUID = 1L;

private PersonOfInterestPanel panel;
private final PersonOfInterestPanel panel;

public ObjectReferenceProvider(PersonOfInterestPanel panel) {
this.panel = panel;
Expand Down Expand Up @@ -750,26 +733,15 @@ private String getDisplayName(PrismObject<UserType> o) {
}

if (identifier == null) {
return getDefaultUserDisplayName(o);
}

GroupSelectionType group = panel.getSelectedGroupSelection();
if (group == null || group.getUserDisplayName() == null) {
return getDefaultUserDisplayName(o);
return panel.getDefaultUserDisplayName(o);
}

String displayName = panel.getDisplayNameFromExpression(
AutocompleteSearchConfigurationType config = panel.getAutocompleteConfiguration();
String displayName = getDisplayNameFromExpression(
"User display name for group selection '" + identifier + "' expression",
group.getUserDisplayName(), o, panel);

return StringUtils.isNotEmpty(displayName) ? displayName : getDefaultUserDisplayName(o);
}

private String getDefaultUserDisplayName(PrismObject<UserType> o) {
String name = WebComponentUtil.getOrigStringFromPoly(o.getName());
String fullName = WebComponentUtil.getOrigStringFromPoly(o.asObjectable().getFullName());
config.getDisplayExpression(), obj -> panel.getDefaultUserDisplayName(obj), o, panel);

return StringUtils.isNotEmpty(fullName) ? fullName + " (" + name + ")" : name;
return StringUtils.isNotEmpty(displayName) ? displayName : panel.getDefaultUserDisplayName(o);
}

@Override
Expand Down

0 comments on commit dbd06c4

Please sign in to comment.