You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by md...@apache.org on 2020/02/05 22:40:35 UTC
[syncope] branch 2_1_X updated: [SYNCOPE-1538] Replaced DropDown
with a search field
This is an automated email from the ASF dual-hosted git repository.
mdisabatino pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/2_1_X by this push:
new b553278 [SYNCOPE-1538] Replaced DropDown with a search field
b553278 is described below
commit b55327827004d7ab2a0d75d19315206bc738d803
Author: Marco Di Sabatino Di Diodoro <ma...@tirasa.net>
AuthorDate: Wed Feb 5 23:40:11 2020 +0100
[SYNCOPE-1538] Replaced DropDown with a search field
---
.../client/console/commons/RealmsUtils.java | 51 ++++++
.../client/console/panels/RealmChoicePanel.java | 176 ++++++++++++++-------
.../client/console/rest/RealmRestClient.java | 8 +-
.../client/console/status/ReconTaskPanel.java | 35 +++-
.../console/tasks/SchedTaskWizardBuilder.java | 66 ++++++--
.../syncope/client/console/topology/Topology.java | 16 +-
.../markup/html/WebMarkupContainerNoVeil.java | 42 +++++
.../markup/html/form/AjaxSearchFieldPanel.java | 133 ++++++++++++++++
.../client/console/wizards/any/Details.java | 53 +++++--
.../wizards/resources/ConnectorDetailsPanel.java | 45 +++++-
.../META-INF/resources/css/syncopeConsole.css | 19 +--
.../client/console/panels/RealmChoicePanel.html | 11 +-
.../console/panels/RealmChoicePanel.properties | 17 ++
.../panels/RealmChoicePanel_fr_CA.properties | 17 ++
.../console/panels/RealmChoicePanel_it.properties | 17 ++
.../console/panels/RealmChoicePanel_ja.properties | 17 ++
.../panels/RealmChoicePanel_pt_BR.properties | 17 ++
.../console/panels/RealmChoicePanel_ru.properties | 17 ++
.../markup/html/form/AjaxCharacterFieldPanel.html | 4 +-
...erFieldPanel.html => AjaxSearchFieldPanel.html} | 1 -
.../client/console/wizards/any/Details.html | 8 +-
21 files changed, 631 insertions(+), 139 deletions(-)
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/RealmsUtils.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/RealmsUtils.java
new file mode 100644
index 0000000..2564012
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/RealmsUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.commons;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.rest.RealmRestClient;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.rest.api.beans.RealmQuery;
+
+public final class RealmsUtils {
+
+ public static final int REALMS_VIEW_SIZE = 20;
+
+ private RealmsUtils() {
+ // private constructor for static utility class
+ }
+
+ public static boolean enableSearchRealm() {
+ return new RealmRestClient().search(
+ new RealmQuery.Builder().keyword(
+ SyncopeConsoleSession.get().getAuthRealms().contains(SyncopeConstants.ROOT_REALM)
+ ? SyncopeConstants.ROOT_REALM
+ : SyncopeConsoleSession.get().getAuthRealms().iterator().next()).build()).
+ getTotalCount() > REALMS_VIEW_SIZE;
+ }
+
+ public static boolean checkInput(final String input) {
+ return StringUtils.isNotBlank(input) && !"*".equals(input);
+ }
+
+ public static RealmQuery buildQuery(final String input) {
+ return new RealmQuery.Builder().keyword(input.contains("*") ? input : "*" + input + "*").build();
+ }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
index a20fbfd..1bac74f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
@@ -25,14 +25,12 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
import de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.DropDownButton;
import de.agilecoders.wicket.core.markup.html.bootstrap.image.GlyphIconType;
import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;
-import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.select.BootstrapSelect;
-import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.select.BootstrapSelectConfig;
-import de.agilecoders.wicket.jquery.Key;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -41,33 +39,39 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.RealmsUtils;
import org.apache.syncope.client.console.rest.RealmRestClient;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.console.wicket.markup.html.WebMarkupContainerNoVeil;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.DynRealmTO;
import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.syncope.common.rest.api.beans.RealmQuery;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AbstractAutoCompleteRenderer;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.IAutoCompleteRenderer;
import org.apache.wicket.markup.ComponentTag;
-import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.Response;
public class RealmChoicePanel extends Panel {
private static final long serialVersionUID = -1100228004207271270L;
- private static final int REALMS_VIEW_SIZE = 15;
+ private static final String SEARCH_REALMS = "searchRealms";
private final RealmRestClient realmRestClient = new RealmRestClient();
@@ -77,7 +81,7 @@ public class RealmChoicePanel extends Panel {
private final LoadableDetachableModel<List<DynRealmTO>> dynRealmTree;
- private final WebMarkupContainer container;
+ private final WebMarkupContainerNoVeil container;
private Model<RealmTO> model;
@@ -87,11 +91,18 @@ public class RealmChoicePanel extends Panel {
private final List<AbstractLink> links = new ArrayList<>();
+ private String searchQuery;
+
+ private List<RealmTO> realmsChoices;
+
+ private boolean isSearchEnabled;
+
public RealmChoicePanel(final String id, final PageReference pageRef) {
super(id);
this.pageRef = pageRef;
availableRealms = SyncopeConsoleSession.get().getAuthRealms();
tree = new HashMap<>();
+ isSearchEnabled = RealmsUtils.enableSearchRealm();
realmTree = new LoadableDetachableModel<List<Pair<String, RealmTO>>>() {
@@ -114,9 +125,14 @@ public class RealmChoicePanel extends Panel {
@Override
protected List<Pair<String, RealmTO>> load() {
- Map<String, Pair<RealmTO, List<RealmTO>>> map = reloadRealmParentMap();
+ Map<String, Pair<RealmTO, List<RealmTO>>> map = reloadRealmParentMap(isSearchEnabled);
List<Pair<String, RealmTO>> full = new ArrayList<>();
- getChildren(full, null, map, StringUtils.EMPTY);
+ if (isSearchEnabled) {
+ full = map.entrySet().stream().map(
+ el -> Pair.of(el.getKey(), el.getValue().getKey())).collect(Collectors.toList());
+ } else {
+ getChildren(full, null, map, StringUtils.EMPTY);
+ }
return full.stream().filter(realm -> availableRealms.stream().anyMatch(
availableRealm -> realm.getValue().getFullPath().startsWith(availableRealm))).
collect(Collectors.toList());
@@ -146,8 +162,13 @@ public class RealmChoicePanel extends Panel {
}
};
- model = Model.of(realmTree.getObject().stream().findFirst().get().getValue());
- container = new WebMarkupContainer("container", realmTree);
+ RealmTO realmTO = realmRestClient.search(
+ new RealmQuery.Builder().keyword("*" + availableRealms.stream().findFirst().get() + "*").build()).
+ getResult().stream().findFirst().get();
+
+ model = Model.of(realmTO);
+ searchQuery = realmTO.getName();
+ container = new WebMarkupContainerNoVeil("container", realmTree);
container.setOutputMarkupId(true);
add(container);
reloadRealmTree();
@@ -169,63 +190,71 @@ public class RealmChoicePanel extends Panel {
label.setOutputMarkupId(true);
container.addOrReplace(label);
- if ((realmTree.getObject().size() + dynRealmTree.getObject().size()) > REALMS_VIEW_SIZE) {
- List<Pair<String, RealmTO>> realms = Stream.of(
- realmTree.getObject(),
- dynRealmTree.getObject().stream().map(
- item -> {
- final RealmTO realmTO = new RealmTO();
- realmTO.setKey(item.getKey());
- realmTO.setName(item.getKey());
- realmTO.setFullPath(item.getKey());
- return Pair.of(item.getKey(), realmTO);
- }).collect(Collectors.toList())).flatMap(Collection::stream).collect(Collectors.toList());
-
- BootstrapSelectConfig config = new BootstrapSelectConfig().withLiveSearch(true);
- config.put(new Key<>("styleBase", "btn"), "btn glyphicon glyphicon-folder-open");
- BootstrapSelect<Pair<String, RealmTO>> select =
- new BootstrapSelect<>("realmsLiveSearch", new Model<>(), realms);
- select.with(config);
- select.setOutputMarkupId(true);
- select.setChoiceRenderer(new IChoiceRenderer<Pair<String, RealmTO>>() {
-
- private static final long serialVersionUID = 5978544741356774985L;
+ if (isSearchEnabled) {
+ realmsChoices = buildRealmChoices();
+ final AutoCompleteSettings settings = new AutoCompleteSettings();
+ settings.setShowCompleteListOnFocusGain(false);
+ settings.setShowListOnEmptyInput(false);
- @Override
- public Object getDisplayValue(final Pair<String, RealmTO> object) {
- return object.getKey();
- }
+ final AutoCompleteTextField<String> searchRealms =
+ new AutoCompleteTextField<String>(SEARCH_REALMS, new Model<String>(), settings) {
+
+ private static final long serialVersionUID = -6635259975264955783L;
@Override
- public String getIdValue(final Pair<String, RealmTO> object, final int index) {
- return object.getKey();
+ protected Iterator<String> getChoices(final String input) {
+ searchQuery = input;
+ realmsChoices = RealmsUtils.checkInput(input)
+ ? buildRealmChoices()
+ : Collections.<RealmTO>emptyList();
+ return realmsChoices.stream().
+ map(item -> item.getFullPath()).sorted().collect(Collectors.toList()).iterator();
}
@Override
- public Pair<String, RealmTO> getObject(final String id,
- final IModel<? extends List<? extends Pair<String, RealmTO>>> choices) {
-
- return choices.getObject().stream().
- filter(object -> object.getKey().equals(id)).findFirst().orElse(null);
+ protected AutoCompleteBehavior<String> newAutoCompleteBehavior(
+ final IAutoCompleteRenderer<String> renderer,
+ final AutoCompleteSettings settings) {
+ return super.newAutoCompleteBehavior(new AbstractAutoCompleteRenderer<String>() {
+
+ private static final long serialVersionUID = -4789925973199139157L;
+
+ @Override
+ protected void renderChoice(
+ final String object,
+ final Response response,
+ final String criteria) {
+ response.write(object);
+ }
+
+ @Override
+ protected String getTextValue(final String object) {
+ return object;
+ }
+ }, settings);
}
- });
- select.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+ };
+
+ searchRealms.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
private static final long serialVersionUID = -6139318907146065915L;
@Override
protected void onUpdate(final AjaxRequestTarget target) {
- model.setObject(select.getModelObject().getValue());
- label.setDefaultModelObject(model.getObject().getFullPath());
- realmLabel.setDefaultModel(new ResourceModel("realmLabel", "Realm"));
- target.add(label);
- send(pageRef.getPage(), Broadcast.EXACT,
- new ChosenRealm<>(select.getModelObject().getValue(), target));
+ realmsChoices.stream().filter(
+ item -> item.getFullPath().equals(searchRealms.getModelObject())).
+ findFirst().ifPresent(realm -> {
+ model.setObject(realm);
+ label.setDefaultModelObject(model.getObject().getFullPath());
+ realmLabel.setDefaultModel(new ResourceModel("realmLabel", "Realm"));
+ target.add(label);
+ send(pageRef.getPage(), Broadcast.EXACT, new ChosenRealm<>(realm, target));
+ });
}
});
- buildRealmLinks(label, realmLabel);
+
Fragment fragment = new Fragment("realmsFragment", "realmsSearchFragment", container);
- fragment.addOrReplace(select);
+ fragment.addOrReplace(searchRealms);
container.addOrReplace(fragment);
} else {
final DropDownButton realms = new DropDownButton(
@@ -362,15 +391,26 @@ public class RealmChoicePanel extends Panel {
return this;
}
- private Map<String, Pair<RealmTO, List<RealmTO>>> reloadRealmParentMap() {
- return reloadRealmParentMap(realmRestClient.list().stream().
+ private Map<String, Pair<RealmTO, List<RealmTO>>> reloadRealmParentMap(final boolean enableSearch) {
+ List<RealmTO> realmsToList = enableSearch
+ ? realmRestClient.search(new RealmQuery.Builder().
+ keyword(searchQuery.contains("*")
+ ? searchQuery
+ : "*" + searchQuery + "*").build()).getResult()
+ : realmRestClient.list();
+
+ return reloadRealmParentMap(realmsToList.stream().
sorted(Comparator.comparing(RealmTO::getName)).
- collect(Collectors.toList()));
+ collect(Collectors.toList()), enableSearch);
}
- private Map<String, Pair<RealmTO, List<RealmTO>>> reloadRealmParentMap(final List<RealmTO> realms) {
+ private Map<String, Pair<RealmTO, List<RealmTO>>> reloadRealmParentMap(
+ final List<RealmTO> realms,
+ final boolean enableSearch) {
tree.clear();
- tree.put(null, Pair.<RealmTO, List<RealmTO>>of(realms.get(0), new ArrayList<>()));
+ if (!enableSearch) {
+ tree.put(null, Pair.<RealmTO, List<RealmTO>>of(realms.get(0), new ArrayList<>()));
+ }
final Map<String, List<RealmTO>> cache = new HashMap<>();
@@ -391,10 +431,23 @@ public class RealmChoicePanel extends Panel {
cache.put(realm.getParent(), new ArrayList<>(Collections.singleton(realm)));
}
});
-
return tree;
}
+ private List<RealmTO> buildRealmChoices() {
+ return Stream.of(
+ realmTree.getObject().stream().map(item -> item.getValue()).collect(Collectors.toList()),
+ dynRealmTree.getObject().stream().map(
+ item -> {
+ final RealmTO realmTO = new RealmTO();
+ realmTO.setKey(item.getKey());
+ realmTO.setName(item.getKey());
+ realmTO.setFullPath(item.getKey());
+ return realmTO;
+ }).collect(Collectors.toList())).flatMap(Collection::stream).
+ collect(Collectors.toList());
+ }
+
/**
* Gets current selected realm.
*
@@ -418,6 +471,7 @@ public class RealmChoicePanel extends Panel {
}
}
return null;
+
}
public static class ChosenRealm<T> {
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/RealmRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/RealmRestClient.java
index 6a96b20..25a7cac 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/RealmRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/RealmRestClient.java
@@ -23,8 +23,10 @@ import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.DynRealmTO;
+import org.apache.syncope.common.lib.to.PagedResult;
import org.apache.syncope.common.lib.to.ProvisioningResult;
import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.syncope.common.rest.api.beans.RealmQuery;
import org.apache.syncope.common.rest.api.service.DynRealmService;
import org.apache.syncope.common.rest.api.service.RealmService;
@@ -34,7 +36,11 @@ import org.apache.syncope.common.rest.api.service.RealmService;
public class RealmRestClient extends BaseRestClient {
private static final long serialVersionUID = -8549081557283519638L;
-
+
+ public PagedResult<RealmTO> search(final RealmQuery query) {
+ return getService(RealmService.class).search(query);
+ }
+
public List<RealmTO> list() {
return getService(RealmService.class).list(SyncopeConstants.ROOT_REALM);
}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
index 3ba1a8a..261edba 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
@@ -19,11 +19,14 @@
package org.apache.syncope.client.console.status;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.RealmsUtils;
import org.apache.syncope.client.console.pages.BasePage;
import org.apache.syncope.client.console.panels.MultilevelPanel;
import org.apache.syncope.client.console.rest.ImplementationRestClient;
@@ -32,6 +35,7 @@ import org.apache.syncope.client.console.rest.ReconciliationRestClient;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
@@ -45,6 +49,7 @@ import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.CompoundPropertyModel;
@@ -116,8 +121,29 @@ public class ReconTaskPanel extends MultilevelPanel.SecondLevel {
if (taskTO instanceof PushTaskTO) {
form.add(new Label("realm", ""));
} else {
- AjaxDropDownChoicePanel<String> realm = new AjaxDropDownChoicePanel<>(
- "realm", "destinationRealm", new PropertyModel<>(taskTO, "destinationRealm"), false);
+ boolean isSearchEnabled = RealmsUtils.enableSearchRealm();
+ final AutoCompleteSettings settings = new AutoCompleteSettings();
+ settings.setShowCompleteListOnFocusGain(!isSearchEnabled);
+ settings.setShowListOnEmptyInput(!isSearchEnabled);
+
+ final AjaxSearchFieldPanel realm =
+ new AjaxSearchFieldPanel("realm", "destinationRealm",
+ new PropertyModel<String>(taskTO, "destinationRealm"), settings) {
+
+ private static final long serialVersionUID = -6390474600233486704L;
+
+ @Override
+ protected Iterator<String> getChoices(final String input) {
+ return (RealmsUtils.checkInput(input)
+ ? (isSearchEnabled
+ ? realmRestClient.search(RealmsUtils.buildQuery(input)).getResult()
+ : realmRestClient.list())
+ : Collections.<RealmTO>emptyList()).stream().
+ sorted(Comparator.comparing(RealmTO::getName)).
+ map(RealmTO::getFullPath).collect(Collectors.toList()).iterator();
+ }
+ };
+
form.add(realm);
realm.addRequiredLabel();
realm.setOutputMarkupId(true);
@@ -125,11 +151,6 @@ public class ReconTaskPanel extends MultilevelPanel.SecondLevel {
if (isOnSyncope) {
realm.getField().setModelObject(SyncopeConstants.ROOT_REALM);
realm.setVisible(false);
- } else {
- realm.setChoices(realmRestClient.list().stream().
- sorted(Comparator.comparing(RealmTO::getName)).
- map(RealmTO::getFullPath).
- collect(Collectors.toList()));
}
}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
index a23f39b..3e4dab0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskWizardBuilder.java
@@ -21,9 +21,11 @@ package org.apache.syncope.client.console.tasks;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.RealmsUtils;
import org.apache.syncope.client.console.rest.ImplementationRestClient;
import org.apache.syncope.client.console.rest.RealmRestClient;
import org.apache.syncope.client.console.rest.TaskRestClient;
@@ -31,6 +33,7 @@ import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormCompo
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
import org.apache.syncope.common.lib.to.EntityTO;
@@ -46,6 +49,7 @@ import org.apache.syncope.common.lib.types.TaskType;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
import org.apache.wicket.extensions.wizard.WizardModel;
import org.apache.wicket.extensions.wizard.WizardStep;
import org.apache.wicket.markup.html.WebMarkupContainer;
@@ -60,6 +64,8 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends AjaxWizardBui
private final TaskRestClient taskRestClient = new TaskRestClient();
+ private final RealmRestClient realmRestClient = new RealmRestClient();
+
private final ImplementationRestClient implRestClient = new ImplementationRestClient();
private final TaskType type;
@@ -68,17 +74,17 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends AjaxWizardBui
private CrontabPanel crontabPanel;
+ private String realmQuery;
+
+ private boolean isSearchEnabled;
+
private final LoadableDetachableModel<List<String>> realms = new LoadableDetachableModel<List<String>>() {
private static final long serialVersionUID = 5275935387613157437L;
@Override
protected List<String> load() {
- List<String> result = new RealmRestClient().list().stream().
- map(RealmTO::getFullPath).collect(Collectors.toList());
- Collections.sort(result);
-
- return result;
+ return searchRealms().stream().map(RealmTO::getFullPath).sorted().collect(Collectors.toList());
}
};
@@ -113,6 +119,12 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends AjaxWizardBui
return wizardModel;
}
+ private List<RealmTO> searchRealms() {
+ return isSearchEnabled
+ ? realmRestClient.search(RealmsUtils.buildQuery(realmQuery)).getResult()
+ : realmRestClient.list();
+ }
+
public class Profile extends WizardStep {
private static final long serialVersionUID = -3043839139187792810L;
@@ -162,6 +174,7 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends AjaxWizardBui
};
public Profile(final SchedTaskTO taskTO) {
+ isSearchEnabled = RealmsUtils.enableSearchRealm();
AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name", new PropertyModel<>(taskTO, "name"),
false);
name.addRequiredLabel();
@@ -230,14 +243,28 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends AjaxWizardBui
}
});
- AjaxDropDownChoicePanel<String> destinationRealm = new AjaxDropDownChoicePanel<>(
- "destinationRealm", "destinationRealm",
- new PropertyModel<String>(taskTO, "destinationRealm"), false).
- setChoices(realms);
+ final AutoCompleteSettings settings = new AutoCompleteSettings();
+ settings.setShowCompleteListOnFocusGain(!isSearchEnabled);
+ settings.setShowListOnEmptyInput(!isSearchEnabled);
+
+ final AjaxSearchFieldPanel destinationRealm =
+ new AjaxSearchFieldPanel("destinationRealm", "destinationRealm",
+ new PropertyModel<String>(taskTO, "destinationRealm"), settings) {
+
+ private static final long serialVersionUID = -6390474600233486704L;
+
+ @Override
+ protected Iterator<String> getChoices(final String input) {
+ realmQuery = input;
+ return (RealmsUtils.checkInput(input)
+ ? searchRealms().stream().map(RealmTO::getFullPath).collect(Collectors.toList())
+ : Collections.<String>emptyList()).iterator();
+ }
+ };
+
if (taskTO instanceof PullTaskTO) {
destinationRealm.addRequiredLabel();
}
- destinationRealm.setNullValid(!(taskTO instanceof PullTaskTO));
pullTaskSpecifics.add(destinationRealm);
AjaxCheckBoxPanel remediation = new AjaxCheckBoxPanel(
@@ -254,14 +281,23 @@ public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends AjaxWizardBui
pushTaskSpecifics.setEnabled(false).setVisible(false);
}
- AjaxDropDownChoicePanel<String> sourceRealm = new AjaxDropDownChoicePanel<>(
- "sourceRealm", "sourceRealm",
- new PropertyModel<String>(taskTO, "sourceRealm"), false).
- setChoices(realms);
+ final AjaxSearchFieldPanel sourceRealm = new AjaxSearchFieldPanel("sourceRealm", "sourceRealm",
+ new PropertyModel<String>(taskTO, "sourceRealm"), settings) {
+
+ private static final long serialVersionUID = -6390474600233486704L;
+
+ @Override
+ protected Iterator<String> getChoices(final String input) {
+ realmQuery = input;
+ return (RealmsUtils.checkInput(input)
+ ? searchRealms().stream().map(RealmTO::getFullPath).collect(Collectors.toList())
+ : Collections.<String>emptyList()).iterator();
+ }
+ };
+
if (taskTO instanceof PushTaskTO) {
sourceRealm.addRequiredLabel();
}
- sourceRealm.setNullValid(!(taskTO instanceof PushTaskTO));
pushTaskSpecifics.add(sourceRealm);
// ------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
index b586966..29b4c35 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
@@ -40,6 +40,7 @@ import org.apache.syncope.client.console.wizards.resources.AbstractResourceWizar
import org.apache.syncope.client.console.rest.BaseRestClient;
import org.apache.syncope.client.console.rest.ConnectorRestClient;
import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.WebMarkupContainerNoVeil;
import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
@@ -51,7 +52,6 @@ import org.apache.wicket.Component;
import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.IAjaxIndicatorAware;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
@@ -609,18 +609,4 @@ public class Topology extends BasePage {
resourceCreateEvent.getKind()));
}
}
-
- private static class WebMarkupContainerNoVeil extends WebMarkupContainer implements IAjaxIndicatorAware {
-
- private static final long serialVersionUID = 6883930486048460708L;
-
- WebMarkupContainerNoVeil(final String id) {
- super(id);
- }
-
- @Override
- public String getAjaxIndicatorMarkupId() {
- return StringUtils.EMPTY;
- }
- }
}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/WebMarkupContainerNoVeil.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/WebMarkupContainerNoVeil.java
new file mode 100644
index 0000000..9faf87e
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/WebMarkupContainerNoVeil.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.markup.html;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.wicket.ajax.IAjaxIndicatorAware;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.model.IModel;
+
+public class WebMarkupContainerNoVeil extends WebMarkupContainer implements IAjaxIndicatorAware {
+
+ private static final long serialVersionUID = 6883930486048460708L;
+
+ public WebMarkupContainerNoVeil(final String id) {
+ super(id);
+ }
+
+ public WebMarkupContainerNoVeil(final String id, final IModel<?> model) {
+ super(id, model);
+ }
+
+ @Override
+ public String getAjaxIndicatorMarkupId() {
+ return StringUtils.EMPTY;
+ }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxSearchFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxSearchFieldPanel.java
new file mode 100644
index 0000000..a6943af
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxSearchFieldPanel.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.markup.html.form;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAutoCompleteBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.IAutoCompleteRenderer;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.validation.IValidator;
+
+public class AjaxSearchFieldPanel extends FieldPanel<String> implements Cloneable {
+
+ private static final long serialVersionUID = 6890905510177974519L;
+
+ private List<String> choices = Collections.emptyList();
+
+ private final IAutoCompleteRenderer<String> renderer;
+
+ private final AutoCompleteSettings settings;
+
+ public AjaxSearchFieldPanel(final String id, final String name, final IModel<String> model) {
+ this(id, name, model, null, null);
+ }
+
+ public AjaxSearchFieldPanel(
+ final String id, final String name,
+ final IModel<String> model,
+ final AutoCompleteSettings settings) {
+ this(id, name, model, null, settings);
+ }
+
+ public AjaxSearchFieldPanel(
+ final String id, final String name,
+ final IModel<String> model,
+ final IAutoCompleteRenderer<String> renderer,
+ final AutoCompleteSettings settings) {
+ super(id, name, model);
+
+ this.settings = settings;
+ this.renderer = renderer;
+
+ field = new AutoCompleteTextField<String>("textField", model, settings) {
+
+ private static final long serialVersionUID = -6648767303091874219L;
+
+ @Override
+ protected Iterator<String> getChoices(final String input) {
+ return AjaxSearchFieldPanel.this.getChoices(input);
+ }
+
+ @Override
+ protected AutoCompleteBehavior<String> newAutoCompleteBehavior(
+ final IAutoCompleteRenderer<String> renderer, final AutoCompleteSettings settings) {
+
+ return new IndicatorAutoCompleteBehavior<String>(
+ AjaxSearchFieldPanel.this.renderer != null ? AjaxSearchFieldPanel.this.renderer : renderer,
+ AjaxSearchFieldPanel.this.settings != null ? AjaxSearchFieldPanel.this.settings : settings) {
+
+ private static final long serialVersionUID = 1070808433195962931L;
+
+ @Override
+ protected Iterator<String> getChoices(final String input) {
+ return AjaxSearchFieldPanel.this.getChoices(input);
+ }
+ };
+ }
+ };
+ add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true));
+
+ if (!isReadOnly()) {
+ field.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+ private static final long serialVersionUID = -6139318907146065915L;
+
+ @Override
+ protected void onUpdate(final AjaxRequestTarget target) {
+ AjaxSearchFieldPanel.this.onUpdateBehavior();
+ }
+ });
+ }
+ }
+
+ @Override
+ public FieldPanel<String> setRequired(final boolean required) {
+ return super.setRequired(required);
+ }
+
+ public List<String> getChoices() {
+ return choices;
+ }
+
+ public void addValidator(final IValidator<String> validator) {
+ this.field.add(validator);
+ }
+
+ public void onUpdateBehavior() {
+ }
+
+ protected Iterator<String> getChoices(final String input) {
+ return choices.iterator();
+ }
+
+ @Override
+ public FieldPanel<String> clone() {
+ final AjaxSearchFieldPanel panel = (AjaxSearchFieldPanel) super.clone();
+ return panel;
+ }
+}
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
index 5016e7d..8d11492 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
@@ -19,18 +19,23 @@
package org.apache.syncope.client.console.wizards.any;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.RealmsUtils;
import org.apache.syncope.client.console.pages.Realms;
import org.apache.syncope.client.console.rest.RealmRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
import org.apache.wicket.extensions.wizard.WizardStep;
import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.PropertyModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,6 +46,8 @@ public class Details<T extends AnyTO> extends WizardStep {
protected static final Logger LOG = LoggerFactory.getLogger(Details.class);
+ private final RealmRestClient realmRestClient = new RealmRestClient();
+
protected final PageReference pageRef;
private final FieldPanel<String> realm;
@@ -52,27 +59,47 @@ public class Details<T extends AnyTO> extends WizardStep {
final PageReference pageRef) {
this.pageRef = pageRef;
-
+ final List<String> authRealms = SyncopeConsoleSession.get().getAuthRealms();
final T inner = wrapper.getInnerObject();
-
+ final Fragment fragment;
+
if (templateMode) {
realm = new AjaxTextFieldPanel(
"destinationRealm", "destinationRealm", new PropertyModel<>(inner, "realm"), false);
AjaxTextFieldPanel.class.cast(realm).enableJexlHelp();
- } else {
- final List<RealmTO> realms = pageRef.getPage() instanceof Realms
- ? getRealmsFromLinks(Realms.class.cast(pageRef.getPage()).getRealmChoicePanel().getLinks())
- : new RealmRestClient().list();
+ fragment = new Fragment("realmsFragment", "realmsTemplateFragment", this);
- realm = new AjaxDropDownChoicePanel<>(
- "destinationRealm", "destinationRealm", new PropertyModel<>(inner, "realm"), false);
-
- ((AjaxDropDownChoicePanel<String>) realm).setChoices(
- realms.stream().map(RealmTO::getFullPath).collect(Collectors.toList()));
+ } else {
+ boolean isSearchEnabled = RealmsUtils.enableSearchRealm();
+ final AutoCompleteSettings settings = new AutoCompleteSettings();
+ settings.setShowCompleteListOnFocusGain(!isSearchEnabled);
+ settings.setShowListOnEmptyInput(!isSearchEnabled);
+
+ realm = new AjaxSearchFieldPanel("destinationRealm", "destinationRealm",
+ new PropertyModel<>(inner, "realm"), settings) {
+
+ private static final long serialVersionUID = -6390474600233486704L;
+
+ @Override
+ protected Iterator<String> getChoices(final String input) {
+ return (isSearchEnabled
+ ? realmRestClient.search(RealmsUtils.buildQuery(input)).getResult()
+ : pageRef.getPage() instanceof Realms
+ ? getRealmsFromLinks(Realms.class.cast(pageRef.getPage()).getRealmChoicePanel().getLinks())
+ : realmRestClient.list()).
+ stream().filter(realm -> authRealms.stream().anyMatch(
+ authRealm -> realm.getFullPath().startsWith(authRealm))).
+ map(item -> item.getFullPath()).collect(Collectors.toList()).iterator();
+ }
+ };
+
+ fragment = new Fragment("realmsFragment", "realmsSearchFragment", this);
}
- add(realm);
+ fragment.addOrReplace(realm);
+ addOrReplace(fragment);
add(getGeneralStatusInformation("generalStatusInformation", inner).
setEnabled(includeStatusPanel).setVisible(includeStatusPanel).setRenderBodyOnly(true));
+
}
public Details<T> disableRealmSpecification() {
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
index d69b7d3..877b3aa 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java
@@ -19,13 +19,16 @@
package org.apache.syncope.client.console.wizards.resources;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.syncope.client.console.SyncopeConsoleSession;
import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.RealmsUtils;
import org.apache.syncope.client.console.rest.RealmRestClient;
import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSpinnerFieldPanel;
import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.common.lib.to.ConnBundleTO;
@@ -33,6 +36,7 @@ import org.apache.syncope.common.lib.to.ConnInstanceTO;
import org.apache.syncope.common.lib.to.ConnPoolConfTO;
import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
import org.apache.wicket.extensions.wizard.WizardStep;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.model.LoadableDetachableModel;
@@ -42,6 +46,12 @@ public class ConnectorDetailsPanel extends WizardStep {
private static final long serialVersionUID = -2435937897614232137L;
+ private final RealmRestClient realmRestClient = new RealmRestClient();
+
+ private String realmQuery;
+
+ private boolean isSearchEnabled;
+
private final LoadableDetachableModel<List<String>> realms;
public ConnectorDetailsPanel(final ConnInstanceTO connInstanceTO, final List<ConnBundleTO> bundles) {
@@ -49,13 +59,16 @@ public class ConnectorDetailsPanel extends WizardStep {
setOutputMarkupId(true);
final List<String> authRealms = SyncopeConsoleSession.get().getAuthRealms();
+ isSearchEnabled = RealmsUtils.enableSearchRealm();
+
realms = new LoadableDetachableModel<List<String>>() {
private static final long serialVersionUID = 5275935387613157437L;
@Override
protected List<String> load() {
- return new RealmRestClient().list().stream().
+ List<RealmTO> realmList = searchRealms();
+ return realmList.stream().
filter(realm -> authRealms.stream().
anyMatch(authRealm -> realm.getFullPath().startsWith(authRealm))).
map(RealmTO::getFullPath).
@@ -64,9 +77,27 @@ public class ConnectorDetailsPanel extends WizardStep {
}
};
- AjaxDropDownChoicePanel<String> realm = new AjaxDropDownChoicePanel<>(
- "adminRealm", "adminRealm", new PropertyModel<>(connInstanceTO, "adminRealm"), false);
- realm.setChoices(realms);
+ final AutoCompleteSettings settings = new AutoCompleteSettings();
+ settings.setShowCompleteListOnFocusGain(!isSearchEnabled);
+ settings.setShowListOnEmptyInput(!isSearchEnabled);
+
+ AjaxSearchFieldPanel realm = new AjaxSearchFieldPanel("adminRealm", "adminRealm",
+ new PropertyModel<>(connInstanceTO, "adminRealm"), settings) {
+
+ private static final long serialVersionUID = -6390474600233486704L;
+
+ @Override
+ protected Iterator<String> getChoices(final String input) {
+ realmQuery = input;
+ return (isSearchEnabled
+ ? searchRealms()
+ : realmRestClient.list()).
+ stream().filter(realm -> authRealms.stream().anyMatch(
+ authRealm -> realm.getFullPath().startsWith(authRealm))).
+ map(item -> item.getFullPath()).collect(Collectors.toList()).iterator();
+ }
+ };
+
realm.setOutputMarkupId(true);
realm.addRequiredLabel();
add(realm);
@@ -168,4 +199,10 @@ public class ConnectorDetailsPanel extends WizardStep {
&& object.getBundleName().equals(connInstanceTO.getBundleName())).
map(ConnBundleTO::getVersion).collect(Collectors.toList());
}
+
+ private List<RealmTO> searchRealms() {
+ return isSearchEnabled
+ ? realmRestClient.search(RealmsUtils.buildQuery(realmQuery)).getResult()
+ : realmRestClient.list();
+ }
}
diff --git a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
index c1758ae..78bef15 100644
--- a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
+++ b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
@@ -1167,21 +1167,10 @@ div#tablehandling ul.menu li a {
padding: 0px !important;
}
-.realm-live-search .dropdown-menu li a {
- height: 22px;
-}
-
-.realm-live-search #bs-select-1-0 {
- display: none;
+.realm-choice #realm-choice-field {
+ padding-right: 20px;
}
-.realm-live-search.dropdown.bootstrap-select .bs-caret {
- display: none;
-}
-.realm-live-search.bootstrap-select>.dropdown-toggle {
- width: 50px;
- background: transparent;
- border: none;
- color: #3c8dbc;
- float: right;
+.realm-choice #realm-choice-folder {
+ color: #3c8dbc;
}
\ No newline at end of file
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html
index a6271bb..3d015ed 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html
@@ -20,13 +20,18 @@ under the License.
<wicket:panel>
<div wicket:id="container" class="realm-header">
<div class="realm-label">
- <label wicket:id="realmLabel"/>: <label wicket:id="realm"/>
+ <label wicket:id="realmLabel"/>: <label wicket:id="realm"/>
</div>
<span wicket:id="realmsFragment"></span>
- <wicket:fragment wicket:id="realmsSearchFragment">
+ <wicket:fragment wicket:id="realmsSearchFragment">
<div class="realm-choice">
- <select wicket:id="realmsLiveSearch" class="realm-live-search"></select>
+ <div id="realm-choice-field" class="input-group">
+ <span class="input-group-addon">
+ <i id="realm-choice-folder" class="glyphicon glyphicon-folder-open"></i>
+ </span>
+ <input type="text" class="form-control" wicket:id="searchRealms" wicket:message="placeholder:search"/>
+ </div>
</div>
</wicket:fragment>
<wicket:fragment wicket:id="realmsListFragment">
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.properties
new file mode 100644
index 0000000..ccd697f
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+search=Search
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_fr_CA.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_fr_CA.properties
new file mode 100644
index 0000000..60881c2
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_fr_CA.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+search=Recherche
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_it.properties
new file mode 100644
index 0000000..1522846
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_it.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+search=Cerca
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_ja.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_ja.properties
new file mode 100644
index 0000000..6c85ab8
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_ja.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+search=\u691c\u7d22
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_pt_BR.properties
new file mode 100644
index 0000000..0ead5fe
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_pt_BR.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+search=Pesquisa
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_ru.properties
new file mode 100644
index 0000000..2164746
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel_ru.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+search=\u041f\u043e\u0438\u0441\u043a \u0434\u043b\u044f
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html
index 2c1b7bb..e9123ef 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html
@@ -20,11 +20,9 @@ under the License.
<wicket:extend>
<wicket:enclosure child="field-label">
<label wicket:id="field-label">[LABEL]</label><span wicket:id="required"/>
- <span wicket:id="jexlInfo" class="glyphicon glyphicon-info-sign" style="cursor: pointer"></span>
- <span wicket:id="externalAction"/>
</wicket:enclosure>
<fieldset class="input-group">
- <input type="text" class="form-control" wicket:id="textField" placeholder=""/>
+ <input type="text" class="form-control" wicket:id="searchField" placeholder=""/>
</fieldset>
</wicket:extend>
</html>
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxSearchFieldPanel.html
similarity index 92%
copy from client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html
copy to client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxSearchFieldPanel.html
index 2c1b7bb..78d702b 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxCharacterFieldPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/AjaxSearchFieldPanel.html
@@ -20,7 +20,6 @@ under the License.
<wicket:extend>
<wicket:enclosure child="field-label">
<label wicket:id="field-label">[LABEL]</label><span wicket:id="required"/>
- <span wicket:id="jexlInfo" class="glyphicon glyphicon-info-sign" style="cursor: pointer"></span>
<span wicket:id="externalAction"/>
</wicket:enclosure>
<fieldset class="input-group">
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Details.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Details.html
index a6773aa..aff6e32 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Details.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/Details.html
@@ -20,7 +20,13 @@ under the License.
<wicket:panel>
<div class="details">
<div class="form-group">
- <span wicket:id="destinationRealm">[DESTINATION REALM]</span>
+ <span wicket:id="realmsFragment"></span>
+ <wicket:fragment wicket:id="realmsSearchFragment">
+ <span wicket:id="destinationRealm">[DESTINATION REALM]</span>
+ </wicket:fragment>
+ <wicket:fragment wicket:id="realmsTemplateFragment">
+ <span wicket:id="destinationRealm">[DESTINATION REALM]</span>
+ </wicket:fragment>
</div>
<wicket:child/>
</div>