You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2019/11/29 07:50:35 UTC
[syncope] 02/03: [SYNCOPE-1515] Realm selector
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit af43767bfe1b0fa840abc0a58986350b69e2f719
Author: Marco Di Sabatino Di Diodoro <ma...@tirasa.net>
AuthorDate: Fri Nov 29 07:58:04 2019 +0100
[SYNCOPE-1515] Realm selector
---
.../resources/ui-commons/css/syncopeUI.scss | 19 +-
.../client/console/panels/RealmChoicePanel.java | 320 +++++++++++++--------
.../client/console/panels/RealmChoicePanel.html | 15 +-
.../apache/syncope/fit/console/RealmsITCase.java | 21 +-
4 files changed, 248 insertions(+), 127 deletions(-)
diff --git a/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss b/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss
index 656965f..a2623c3 100644
--- a/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss
+++ b/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss
@@ -1112,9 +1112,24 @@ 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-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;
+}
/* Form wrappers
============================================================================= */
@@ -1139,4 +1154,4 @@ div#tablehandling ul.menu li a {
.max_height {
height: 100% !important;
-}
\ No newline at end of file
+}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
index 8743ff8..738fafb 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmChoicePanel.java
@@ -25,6 +25,9 @@ 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.Comparator;
@@ -32,23 +35,31 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
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.rest.RealmRestClient;
+import org.apache.syncope.client.ui.commons.Constants;
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.IdRepoEntitlement;
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.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;
@@ -57,6 +68,8 @@ public class RealmChoicePanel extends Panel {
private static final long serialVersionUID = -1100228004207271270L;
+ private static final int REALMS_VIEW_SIZE = 15;
+
private final PageReference pageRef;
private final LoadableDetachableModel<List<Pair<String, RealmTO>>> realmTree;
@@ -65,14 +78,14 @@ public class RealmChoicePanel extends Panel {
private final WebMarkupContainer container;
+ private Model<RealmTO> model;
+
private final Collection<String> availableRealms;
private final Map<String, Pair<RealmTO, List<RealmTO>>> tree;
private final List<AbstractLink> links = new ArrayList<>();
- private Model<RealmTO> model;
-
public RealmChoicePanel(final String id, final PageReference pageRef) {
super(id);
this.pageRef = pageRef;
@@ -159,135 +172,218 @@ public class RealmChoicePanel extends Panel {
label.setOutputMarkupId(true);
container.addOrReplace(label);
- final DropDownButton realms = new DropDownButton(
- "realms", new ResourceModel("select", ""), new Model<IconType>(GlyphIconType.folderopen)) {
+ 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<Pair<String, RealmTO>>("realmsLiveSearch", new Model<>(), realms) {
+
+ private static final long serialVersionUID = -12358873583862012L;
+
+ @Override
+ protected boolean isDisabled(
+ final Pair<String, RealmTO> object,
+ final int index,
+ final String selected) {
+ return availableRealms.stream().anyMatch(availableRealm -> {
+ return !SyncopeConstants.ROOT_REALM.equals(availableRealm)
+ && !object.getValue().getFullPath().equals(availableRealm);
+ });
+ }
+ };
- private static final long serialVersionUID = -5560086780455361131L;
+ select.with(config);
+ select.setOutputMarkupId(true);
+ select.setChoiceRenderer(new IChoiceRenderer<Pair<String, RealmTO>>() {
- @Override
- protected List<AbstractLink> newSubMenuButtons(final String buttonMarkupId) {
- RealmChoicePanel.this.links.clear();
+ private static final long serialVersionUID = 5978544741356774985L;
- RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
- ButtonList.getButtonMarkupId(),
- new Model<RealmTO>(),
- Buttons.Type.Link,
- new ResourceModel("realms", "Realms")) {
+ @Override
+ public Object getDisplayValue(final Pair<String, RealmTO> object) {
+ return object.getKey();
+ }
- private static final long serialVersionUID = -7978723352517770744L;
+ @Override
+ public String getIdValue(final Pair<String, RealmTO> object, final int index) {
+ return object.getKey();
+ }
- @Override
- public void onClick(final AjaxRequestTarget target) {
- }
+ @Override
+ public Pair<String, RealmTO> getObject(final String id,
+ final IModel<? extends List<? extends Pair<String, RealmTO>>> choices) {
+ return IterableUtils.find(choices.getObject(), new Predicate<Pair<String, RealmTO>>() {
- @Override
- public boolean isEnabled() {
- return false;
- }
+ @Override
+ public boolean evaluate(final Pair<String, RealmTO> object) {
+ return object.getKey().equals(id);
+ }
+ });
+ }
+ });
+ select.add(new AjaxFormComponentUpdatingBehavior(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));
+ }
+ });
+ buildRealmLinks(label, realmLabel);
+ Fragment fragment = new Fragment("realmsFragment", "realmsSearchFragment", container);
+ fragment.addOrReplace(select);
+ container.addOrReplace(fragment);
+ } else {
+ final DropDownButton realms = new DropDownButton(
+ "realms", new ResourceModel("select", ""), new Model<IconType>(GlyphIconType.folderopen)) {
- @Override
- protected void onComponentTag(final ComponentTag tag) {
- tag.put("class", "panel box box-primary box-header with-border");
- tag.put("style", "margin: 20px 5px 0px 5px; width: 90%");
- }
- });
+ private static final long serialVersionUID = -5560086780455361131L;
- for (Pair<String, RealmTO> link : realmTree.getObject()) {
- final RealmTO realmTO = link.getValue();
- RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
- ButtonList.getButtonMarkupId(),
- Model.of(realmTO),
- Buttons.Type.Link,
- new Model<>(link.getKey())) {
+ @Override
+ protected List<AbstractLink> newSubMenuButtons(final String buttonMarkupId) {
+ buildRealmLinks(label, realmLabel);
+ return RealmChoicePanel.this.links;
+ }
+ };
+ realms.setOutputMarkupId(true);
+ realms.setAlignment(AlignmentBehavior.Alignment.RIGHT);
+ realms.setType(Buttons.Type.Menu);
+
+ MetaDataRoleAuthorizationStrategy.authorize(realms, ENABLE, IdRepoEntitlement.REALM_LIST);
+ Fragment fragment = new Fragment("realmsFragment", "realmsListFragment", container);
+ fragment.addOrReplace(realms);
+ container.addOrReplace(fragment);
+ }
+ }
- private static final long serialVersionUID = -7978723352517770644L;
+ private void buildRealmLinks(final Label label, final Label realmLabel) {
+ RealmChoicePanel.this.links.clear();
+ RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
+ ButtonList.getButtonMarkupId(),
+ new Model<RealmTO>(),
+ Buttons.Type.Link,
+ new ResourceModel("realms", "Realms")) {
- @Override
- public void onClick(final AjaxRequestTarget target) {
- model.setObject(realmTO);
- label.setDefaultModelObject(model.getObject().getFullPath());
- realmLabel.setDefaultModel(new ResourceModel("realmLabel", "Realm"));
- target.add(label);
- send(pageRef.getPage(), Broadcast.EXACT, new ChosenRealm<>(realmTO, target));
- }
+ private static final long serialVersionUID = -7978723352517770744L;
- @Override
- public boolean isEnabled() {
- return availableRealms.stream().
- anyMatch(availableRealm -> realmTO.getFullPath().startsWith(availableRealm));
- }
- });
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+
+ @Override
+ protected void onComponentTag(final ComponentTag tag) {
+ tag.put("class", "panel box box-primary box-header with-border");
+ tag.put("style", "margin: 20px 5px 0px 5px; width: 90%");
+ }
+ });
+
+ for (Pair<String, RealmTO> link : realmTree.getObject()) {
+ final RealmTO realmTO = link.getValue();
+ RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
+ ButtonList.getButtonMarkupId(),
+ Model.of(realmTO),
+ Buttons.Type.Link,
+ new Model<>(link.getKey())) {
+
+ private static final long serialVersionUID = -7978723352517770644L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ model.setObject(realmTO);
+ label.setDefaultModelObject(model.getObject().getFullPath());
+ realmLabel.setDefaultModel(new ResourceModel("realmLabel", "Realm"));
+ target.add(label);
+ send(pageRef.getPage(), Broadcast.EXACT, new ChosenRealm<>(realmTO, target));
}
- if (!dynRealmTree.getObject().isEmpty()) {
- RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
- ButtonList.getButtonMarkupId(),
- new Model<RealmTO>(),
- Buttons.Type.Link,
- new ResourceModel("dynrealms", "Dynamic Realms")) {
+ @Override
+ public boolean isEnabled() {
+ return availableRealms.stream().
+ anyMatch(availableRealm -> realmTO.getFullPath().startsWith(availableRealm));
+ }
+ });
+ }
- private static final long serialVersionUID = -7978723352517770744L;
+ if (!dynRealmTree.getObject().isEmpty()) {
+ RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
+ ButtonList.getButtonMarkupId(),
+ new Model<RealmTO>(),
+ Buttons.Type.Link,
+ new ResourceModel("dynrealms", "Dynamic Realms")) {
- @Override
- public void onClick(final AjaxRequestTarget target) {
+ private static final long serialVersionUID = -7978723352517770744L;
- }
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
- @Override
- public boolean isEnabled() {
- return false;
- }
+ }
- @Override
- protected void onComponentTag(final ComponentTag tag) {
- tag.put("class", "panel box box-primary box-header with-border");
- tag.put("style", "margin: 20px 5px 0px 5px; width: 90%");
- }
- });
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
- for (DynRealmTO dynRealmTO : dynRealmTree.getObject()) {
- final RealmTO realmTO = new RealmTO();
- realmTO.setKey(dynRealmTO.getKey());
- realmTO.setName(dynRealmTO.getKey());
- realmTO.setFullPath(dynRealmTO.getKey());
-
- RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
- ButtonList.getButtonMarkupId(),
- new Model<RealmTO>(),
- Buttons.Type.Link,
- new Model<>(realmTO.getKey())) {
-
- private static final long serialVersionUID = -7978723352517770644L;
-
- @Override
- public void onClick(final AjaxRequestTarget target) {
- model.setObject(realmTO);
- label.setDefaultModelObject(realmTO.getKey());
- realmLabel.setDefaultModel(new ResourceModel("dynRealmLabel", "Dynamic Realm"));
- target.add(label);
- send(pageRef.getPage(), Broadcast.EXACT, new ChosenRealm<>(realmTO, target));
- }
-
- @Override
- public boolean isEnabled() {
- return availableRealms.stream()
- .anyMatch(availableRealm -> SyncopeConstants.ROOT_REALM.equals(availableRealm)
- || realmTO.getKey().equals(availableRealm));
- }
- });
- }
+ @Override
+ protected void onComponentTag(final ComponentTag tag) {
+ tag.put("class", "panel box box-primary box-header with-border");
+ tag.put("style", "margin: 20px 5px 0px 5px; width: 90%");
}
+ });
- return RealmChoicePanel.this.links;
- }
- };
- realms.setOutputMarkupId(true);
- realms.setAlignment(AlignmentBehavior.Alignment.RIGHT);
- realms.setType(Buttons.Type.Menu);
+ for (DynRealmTO dynRealmTO : dynRealmTree.getObject()) {
+ final RealmTO realmTO = new RealmTO();
+ realmTO.setKey(dynRealmTO.getKey());
+ realmTO.setName(dynRealmTO.getKey());
+ realmTO.setFullPath(dynRealmTO.getKey());
- MetaDataRoleAuthorizationStrategy.authorize(realms, ENABLE, IdRepoEntitlement.REALM_LIST);
+ RealmChoicePanel.this.links.add(new BootstrapAjaxLink<RealmTO>(
+ ButtonList.getButtonMarkupId(),
+ new Model<RealmTO>(),
+ Buttons.Type.Link,
+ new Model<>(realmTO.getKey())) {
+
+ private static final long serialVersionUID = -7978723352517770644L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ model.setObject(realmTO);
+ label.setDefaultModelObject(realmTO.getKey());
+ realmLabel.setDefaultModel(new ResourceModel("dynRealmLabel", "Dynamic Realm"));
+ target.add(label);
+ send(pageRef.getPage(), Broadcast.EXACT, new ChosenRealm<>(realmTO, target));
+ }
- container.addOrReplace(realms);
+ @Override
+ public boolean isEnabled() {
+ return availableRealms.stream().anyMatch(availableRealm -> {
+ return SyncopeConstants.ROOT_REALM.equals(availableRealm)
+ || realmTO.getKey().equals(availableRealm);
+ });
+ }
+ });
+ }
+ }
}
public final RealmChoicePanel reloadRealmTree(final AjaxRequestTarget target) {
@@ -360,10 +456,6 @@ public class RealmChoicePanel extends Panel {
return null;
}
- public List<AbstractLink> getLinks() {
- return links;
- }
-
public static class ChosenRealm<T> {
private final AjaxRequestTarget target;
@@ -383,4 +475,8 @@ public class RealmChoicePanel extends Panel {
return target;
}
}
+
+ public List<AbstractLink> getLinks() {
+ return links;
+ }
}
diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html
index 9933477..a6271bb 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmChoicePanel.html
@@ -22,9 +22,18 @@ under the License.
<div class="realm-label">
<label wicket:id="realmLabel"/>: <label wicket:id="realm"/>
</div>
- <div class="realm-choice">
- <button wicket:id="realms"></button>
- </div>
+ <span wicket:id="realmsFragment"></span>
+
+ <wicket:fragment wicket:id="realmsSearchFragment">
+ <div class="realm-choice">
+ <select wicket:id="realmsLiveSearch" class="realm-live-search"></select>
+ </div>
+ </wicket:fragment>
+ <wicket:fragment wicket:id="realmsListFragment">
+ <div class="realm-choice">
+ <button wicket:id="realms"></button>
+ </div>
+ </wicket:fragment>
</div>
</wicket:panel>
</html>
\ No newline at end of file
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RealmsITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RealmsITCase.java
index 16b7068..ebdec1d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RealmsITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/RealmsITCase.java
@@ -67,10 +67,10 @@ public class RealmsITCase extends AbstractConsoleITCase {
// remove the new realm just created
UTILITY_UI.getTester().clickLink("body:realmsLI:realms");
- UTILITY_UI.getTester().
- executeAjaxEvent("body:content:realmChoicePanel:container:realms:btn", Constants.ON_CLICK);
UTILITY_UI.getTester().executeAjaxEvent(
- "body:content:realmChoicePanel:container:realms:dropdown-menu:buttons:5:button",
+ "body:content:realmChoicePanel:container:realmsFragment:realms:btn", Constants.ON_CLICK);
+ UTILITY_UI.getTester().executeAjaxEvent(
+ "body:content:realmChoicePanel:container:realmsFragment:realms:dropdown-menu:buttons:5:button",
Constants.ON_CLICK);
UTILITY_UI.getTester().assertLabel("body:content:realmChoicePanel:container:realm", "/testRealm");
@@ -109,10 +109,11 @@ public class RealmsITCase extends AbstractConsoleITCase {
@Test
public void addUserTemplate() {
- UTILITY_UI.getTester().
- executeAjaxEvent("body:content:realmChoicePanel:container:realms:btn", Constants.ON_CLICK);
UTILITY_UI.getTester().executeAjaxEvent(
- "body:content:realmChoicePanel:container:realms:dropdown-menu:buttons:4:button",
+ "body:content:realmChoicePanel:container:realmsFragment:realms:btn",
+ Constants.ON_CLICK);
+ UTILITY_UI.getTester().executeAjaxEvent(
+ "body:content:realmChoicePanel:container:realmsFragment:realms:dropdown-menu:buttons:4:button",
Constants.ON_CLICK);
UTILITY_UI.getTester().assertLabel("body:content:realmChoicePanel:container:realm", "/odd");
@@ -161,10 +162,10 @@ public class RealmsITCase extends AbstractConsoleITCase {
@Test
public void verifyPropagation() {
- UTILITY_UI.getTester().
- executeAjaxEvent("body:content:realmChoicePanel:container:realms:btn", Constants.ON_CLICK);
- UTILITY_UI.getTester().executeAjaxEvent(
- "body:content:realmChoicePanel:container:realms:dropdown-menu:buttons:2:button",
+ UTILITY_UI.getTester().executeAjaxEvent("body:content:realmChoicePanel:container"
+ + ":realmsFragment:realms:btn", Constants.ON_CLICK);
+ UTILITY_UI.getTester().executeAjaxEvent("body:content:realmChoicePanel:container"
+ + ":realmsFragment:realms:dropdown-menu:buttons:2:button",
Constants.ON_CLICK);
UTILITY_UI.getTester().clickLink(