mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
feat: Add description/permission list to role selector (OD-2335)
This commit is contained in:
parent
3ff5e40419
commit
8951b29ad8
@ -41,6 +41,8 @@ public class Role extends AbstractEntity implements BasePermission {
|
||||
|
||||
@Column(nullable=false, unique=true)
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
private boolean manageProject;
|
||||
|
||||
@ -104,6 +106,15 @@ public class Role extends AbstractEntity implements BasePermission {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Editable(order=110)
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isOwner() {
|
||||
return getId().equals(OWNER_ID);
|
||||
}
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
package io.onedev.server.web.component.rolechoice;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONWriter;
|
||||
import org.unbescape.html.HtmlEscape;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.RoleManager;
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.web.component.select2.ChoiceProvider;
|
||||
|
||||
public abstract class AbstractRoleChoiceProvider extends ChoiceProvider<Role> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void toJson(Role choice, JSONWriter writer) throws JSONException {
|
||||
writer.key("id").value(choice.getId()).key("name").value(HtmlEscape.escapeHtml5(choice.getName()));
|
||||
if (choice.getDescription() != null)
|
||||
writer.key("description").value(HtmlEscape.escapeHtml5(choice.getDescription()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Role> toChoices(Collection<String> ids) {
|
||||
List<Role> roles = Lists.newArrayList();
|
||||
RoleManager roleManager = OneDev.getInstance(RoleManager.class);
|
||||
for (String each : ids) {
|
||||
Role role = roleManager.load(Long.valueOf(each));
|
||||
Hibernate.initialize(role);
|
||||
roles.add(role);
|
||||
}
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package io.onedev.server.web.component.rolechoice;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.wicket.model.IModel;
|
||||
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.util.Similarities;
|
||||
import io.onedev.server.web.WebConstants;
|
||||
import io.onedev.server.web.component.select2.Response;
|
||||
import io.onedev.server.web.component.select2.ResponseFiller;
|
||||
|
||||
public class RoleChoiceProvider extends AbstractRoleChoiceProvider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final IModel<Collection<Role>> choicesModel;
|
||||
|
||||
public RoleChoiceProvider(IModel<Collection<Role>> choicesModel) {
|
||||
this.choicesModel = choicesModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
choicesModel.detach();
|
||||
super.detach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void query(String term, int page, Response<Role> response) {
|
||||
List<Role> similarities = new Similarities<Role>(choicesModel.getObject()) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public double getSimilarScore(Role object) {
|
||||
return Similarities.getSimilarScore(object.getName(), term);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
new ResponseFiller<Role>(response).fill(similarities, page, WebConstants.PAGE_SIZE);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package io.onedev.server.web.component.rolechoice;
|
||||
|
||||
import io.onedev.server.web.page.base.BaseDependentResourceReference;
|
||||
|
||||
public class RoleChoiceResourceReference extends BaseDependentResourceReference {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RoleChoiceResourceReference() {
|
||||
super(RoleChoiceResourceReference.class, "role-choice.js");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package io.onedev.server.web.component.rolechoice;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
|
||||
import org.apache.wicket.model.IModel;
|
||||
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.web.component.select2.Select2MultiChoice;
|
||||
|
||||
public class RoleMultiChoice extends Select2MultiChoice<Role> {
|
||||
|
||||
public RoleMultiChoice(String id, IModel<Collection<Role>> selectionsModel, IModel<Collection<Role>> choicesModel) {
|
||||
super(id, selectionsModel, new RoleChoiceProvider(choicesModel));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
if (isRequired())
|
||||
getSettings().setPlaceholder("Choose roles...");
|
||||
else
|
||||
getSettings().setPlaceholder("Not specified");
|
||||
getSettings().setFormatResult("onedev.server.roleChoiceFormatter.formatResult");
|
||||
getSettings().setFormatSelection("onedev.server.roleChoiceFormatter.formatSelection");
|
||||
getSettings().setEscapeMarkup("onedev.server.roleChoiceFormatter.escapeMarkup");
|
||||
setConvertEmptyInputStringToNull(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderHead(IHeaderResponse response) {
|
||||
super.renderHead(response);
|
||||
|
||||
response.render(JavaScriptHeaderItem.forReference(new RoleChoiceResourceReference()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package io.onedev.server.web.component.rolechoice;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
|
||||
import org.apache.wicket.model.IModel;
|
||||
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.web.component.select2.Select2Choice;
|
||||
|
||||
public class RoleSingleChoice extends Select2Choice<Role> {
|
||||
|
||||
public RoleSingleChoice(String id, IModel<Role> selectionModel, IModel<Collection<Role>> choicesModel) {
|
||||
super(id, selectionModel, new RoleChoiceProvider(choicesModel));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
getSettings().setAllowClear(!isRequired());
|
||||
if (isRequired())
|
||||
getSettings().setPlaceholder("Choose role...");
|
||||
else
|
||||
getSettings().setPlaceholder("Not specified");
|
||||
getSettings().setFormatResult("onedev.server.roleChoiceFormatter.formatResult");
|
||||
getSettings().setFormatSelection("onedev.server.roleChoiceFormatter.formatSelection");
|
||||
getSettings().setEscapeMarkup("onedev.server.roleChoiceFormatter.escapeMarkup");
|
||||
setConvertEmptyInputStringToNull(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderHead(IHeaderResponse response) {
|
||||
super.renderHead(response);
|
||||
|
||||
response.render(JavaScriptHeaderItem.forReference(new RoleChoiceResourceReference()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
onedev.server.roleChoiceFormatter = {
|
||||
formatSelection: function(role) {
|
||||
return role.name;
|
||||
},
|
||||
|
||||
formatResult: function(role) {
|
||||
return role.name + (role.description ? " <span class='text-muted font-size-sm'>" + role.description + "</span>" : "");
|
||||
},
|
||||
|
||||
escapeMarkup: function(m) {
|
||||
return m;
|
||||
}
|
||||
};
|
||||
@ -2,7 +2,7 @@ package io.onedev.server.web.editable.rolechoice;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
@ -22,22 +22,21 @@ public class RoleChoiceEditSupport implements EditSupport {
|
||||
|
||||
@Override
|
||||
public PropertyContext<?> getEditContext(PropertyDescriptor descriptor) {
|
||||
Method propertyGetter = descriptor.getPropertyGetter();
|
||||
RoleChoice roleChoice = propertyGetter.getAnnotation(RoleChoice.class);
|
||||
if (roleChoice != null) {
|
||||
if (List.class.isAssignableFrom(propertyGetter.getReturnType())
|
||||
Method propertyGetter = descriptor.getPropertyGetter();
|
||||
if (propertyGetter.getAnnotation(RoleChoice.class) != null) {
|
||||
if (Collection.class.isAssignableFrom(propertyGetter.getReturnType())
|
||||
&& ReflectionUtils.getCollectionElementClass(propertyGetter.getGenericReturnType()) == String.class) {
|
||||
return new PropertyContext<List<String>>(descriptor) {
|
||||
return new PropertyContext<Collection<String>>(descriptor) {
|
||||
|
||||
@Override
|
||||
public PropertyViewer renderForView(String componentId, final IModel<List<String>> model) {
|
||||
public PropertyViewer renderForView(String componentId, final IModel<Collection<String>> model) {
|
||||
return new PropertyViewer(componentId, descriptor) {
|
||||
|
||||
@Override
|
||||
protected Component newContent(String id, PropertyDescriptor propertyDescriptor) {
|
||||
List<String> roleNames = model.getObject();
|
||||
if (roleNames != null && !roleNames.isEmpty()) {
|
||||
return new Label(id, StringUtils.join(roleNames, ", " ));
|
||||
Collection<String> teamNames = model.getObject();
|
||||
if (teamNames != null && !teamNames.isEmpty()) {
|
||||
return new Label(id, StringUtils.join(teamNames, ", " ));
|
||||
} else {
|
||||
return new EmptyValueLabel(id) {
|
||||
|
||||
@ -54,7 +53,7 @@ public class RoleChoiceEditSupport implements EditSupport {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyEditor<List<String>> renderForEdit(String componentId, IModel<List<String>> model) {
|
||||
public PropertyEditor<Collection<String>> renderForEdit(String componentId, IModel<Collection<String>> model) {
|
||||
return new RoleMultiChoiceEditor(componentId, descriptor, model);
|
||||
}
|
||||
|
||||
@ -68,8 +67,9 @@ public class RoleChoiceEditSupport implements EditSupport {
|
||||
|
||||
@Override
|
||||
protected Component newContent(String id, PropertyDescriptor propertyDescriptor) {
|
||||
if (model.getObject() != null) {
|
||||
return new Label(id, model.getObject());
|
||||
String teamName = model.getObject();
|
||||
if (teamName != null) {
|
||||
return new Label(id, teamName);
|
||||
} else {
|
||||
return new EmptyValueLabel(id) {
|
||||
|
||||
@ -92,7 +92,7 @@ public class RoleChoiceEditSupport implements EditSupport {
|
||||
|
||||
};
|
||||
} else {
|
||||
throw new RuntimeException("Annotation 'RoleChoice' should be applied to property with type 'String' or 'List<String>'.");
|
||||
throw new RuntimeException("Annotation 'TeamChoice' should be applied to property with type String or Collection<String>");
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<wicket:panel>
|
||||
<input wicket:id="input" type="hidden"></input>
|
||||
<input wicket:id="input" type="hidden">
|
||||
</wicket:panel>
|
||||
@ -2,9 +2,8 @@ package io.onedev.server.web.editable.rolechoice;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
|
||||
@ -12,37 +11,53 @@ import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.Model;
|
||||
import org.apache.wicket.util.convert.ConversionException;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.annotation.RoleChoice;
|
||||
import io.onedev.server.entitymanager.RoleManager;
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.web.component.stringchoice.StringMultiChoice;
|
||||
import io.onedev.server.util.ComponentContext;
|
||||
import io.onedev.server.web.component.rolechoice.RoleMultiChoice;
|
||||
import io.onedev.server.web.editable.PropertyDescriptor;
|
||||
import io.onedev.server.web.editable.PropertyEditor;
|
||||
|
||||
public class RoleMultiChoiceEditor extends PropertyEditor<List<String>> {
|
||||
public class RoleMultiChoiceEditor extends PropertyEditor<Collection<String>> {
|
||||
|
||||
private StringMultiChoice input;
|
||||
private RoleMultiChoice input;
|
||||
|
||||
public RoleMultiChoiceEditor(String id, PropertyDescriptor propertyDescriptor,
|
||||
IModel<List<String>> propertyModel) {
|
||||
public RoleMultiChoiceEditor(String id, PropertyDescriptor propertyDescriptor, IModel<Collection<String>> propertyModel) {
|
||||
super(id, propertyDescriptor, propertyModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
List<Role> choices = new ArrayList<>();
|
||||
|
||||
Map<String, String> roleNames = new LinkedHashMap<>();
|
||||
for (Role role: OneDev.getInstance(RoleManager.class).query())
|
||||
roleNames.put(role.getName(), role.getName());
|
||||
ComponentContext componentContext = new ComponentContext(this);
|
||||
ComponentContext.push(componentContext);
|
||||
try {
|
||||
RoleChoice roleChoice = descriptor.getPropertyGetter().getAnnotation(RoleChoice.class);
|
||||
Preconditions.checkNotNull(roleChoice);
|
||||
choices.addAll(OneDev.getInstance(RoleManager.class).query());
|
||||
choices.sort(Comparator.comparing(Role::getName));
|
||||
} finally {
|
||||
ComponentContext.pop();
|
||||
}
|
||||
|
||||
List<Role> selections = new ArrayList<>();
|
||||
if (getModelObject() != null) {
|
||||
RoleManager roleManager = OneDev.getInstance(RoleManager.class);
|
||||
for (String roleName: getModelObject()) {
|
||||
Role role = roleManager.find(roleName);
|
||||
if (role != null && choices.contains(role))
|
||||
selections.add(role);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<String> selections = new ArrayList<>();
|
||||
if (getModelObject() != null)
|
||||
selections.addAll(getModelObject());
|
||||
|
||||
selections.retainAll(roleNames.keySet());
|
||||
|
||||
input = new StringMultiChoice("input", Model.of(selections), Model.ofMap(roleNames), false) {
|
||||
input = new RoleMultiChoice("input", Model.of(selections), Model.of(choices)) {
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
@ -51,7 +66,6 @@ public class RoleMultiChoiceEditor extends PropertyEditor<List<String>> {
|
||||
}
|
||||
|
||||
};
|
||||
input.setConvertEmptyInputStringToNull(true);
|
||||
|
||||
input.setLabel(Model.of(getDescriptor().getDisplayName()));
|
||||
|
||||
@ -69,11 +83,13 @@ public class RoleMultiChoiceEditor extends PropertyEditor<List<String>> {
|
||||
|
||||
@Override
|
||||
protected List<String> convertInputToValue() throws ConversionException {
|
||||
Collection<String> roleNames = input.getConvertedInput();
|
||||
if (roleNames != null)
|
||||
return new ArrayList<>(roleNames);
|
||||
else
|
||||
return new ArrayList<>();
|
||||
List<String> roleNames = new ArrayList<>();
|
||||
Collection<Role> roles = input.getConvertedInput();
|
||||
if (roles != null) {
|
||||
for (Role role: roles)
|
||||
roleNames.add(role.getName());
|
||||
}
|
||||
return roleNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<wicket:panel>
|
||||
<input wicket:id="input" type="hidden"></input>
|
||||
<input wicket:id="input" type="hidden" class="select2"></input>
|
||||
</wicket:panel>
|
||||
@ -1,29 +1,31 @@
|
||||
package io.onedev.server.web.editable.rolechoice;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.Model;
|
||||
import org.apache.wicket.util.convert.ConversionException;
|
||||
import org.hibernate.criterion.Order;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.annotation.RoleChoice;
|
||||
import io.onedev.server.entitymanager.RoleManager;
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.persistence.dao.EntityCriteria;
|
||||
import io.onedev.server.web.component.stringchoice.StringSingleChoice;
|
||||
import io.onedev.server.util.ComponentContext;
|
||||
import io.onedev.server.web.component.rolechoice.RoleSingleChoice;
|
||||
import io.onedev.server.web.editable.PropertyDescriptor;
|
||||
import io.onedev.server.web.editable.PropertyEditor;
|
||||
|
||||
public class RoleSingleChoiceEditor extends PropertyEditor<String> {
|
||||
|
||||
private StringSingleChoice input;
|
||||
|
||||
public RoleSingleChoiceEditor(String id, PropertyDescriptor propertyDescriptor,
|
||||
IModel<String> propertyModel) {
|
||||
private RoleSingleChoice input;
|
||||
|
||||
public RoleSingleChoiceEditor(String id, PropertyDescriptor propertyDescriptor, IModel<String> propertyModel) {
|
||||
super(id, propertyDescriptor, propertyModel);
|
||||
}
|
||||
|
||||
@ -31,20 +33,30 @@ public class RoleSingleChoiceEditor extends PropertyEditor<String> {
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
Map<String, String> roleNames = new LinkedHashMap<>();
|
||||
List<Role> choices = new ArrayList<>();
|
||||
|
||||
var criteria = EntityCriteria.of(Role.class);
|
||||
criteria.addOrder(Order.asc(Role.PROP_NAME));
|
||||
for (Role role: OneDev.getInstance(RoleManager.class).query(criteria))
|
||||
roleNames.put(role.getName(), role.getName());
|
||||
ComponentContext componentContext = new ComponentContext(this);
|
||||
ComponentContext.push(componentContext);
|
||||
try {
|
||||
RoleChoice roleChoice = descriptor.getPropertyGetter().getAnnotation(RoleChoice.class);
|
||||
Preconditions.checkNotNull(roleChoice);
|
||||
choices.addAll(OneDev.getInstance(RoleManager.class).query());
|
||||
choices.sort(Comparator.comparing(Role::getName));
|
||||
} finally {
|
||||
ComponentContext.pop();
|
||||
}
|
||||
Role role;
|
||||
if (getModelObject() != null)
|
||||
role = OneDev.getInstance(RoleManager.class).find(getModelObject());
|
||||
else
|
||||
role = null;
|
||||
|
||||
String selection = getModelObject();
|
||||
if (!roleNames.containsKey(selection))
|
||||
selection = null;
|
||||
|
||||
input = new StringSingleChoice("input", Model.of(selection), Model.ofMap(roleNames), false) {
|
||||
if (role != null && !choices.contains(role))
|
||||
role = null;
|
||||
|
||||
@Override
|
||||
input = new RoleSingleChoice("input", Model.of(role), Model.of(choices)) {
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
getSettings().configurePlaceholder(descriptor);
|
||||
@ -52,9 +64,8 @@ public class RoleSingleChoiceEditor extends PropertyEditor<String> {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
input.setLabel(Model.of(getDescriptor().getDisplayName()));
|
||||
|
||||
input.add(new AjaxFormComponentUpdatingBehavior("change"){
|
||||
|
||||
@Override
|
||||
@ -63,12 +74,17 @@ public class RoleSingleChoiceEditor extends PropertyEditor<String> {
|
||||
}
|
||||
|
||||
});
|
||||
add(input);
|
||||
|
||||
add(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertInputToValue() throws ConversionException {
|
||||
return input.getConvertedInput();
|
||||
Role role = input.getConvertedInput();
|
||||
if (role != null)
|
||||
return role.getName();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -163,6 +163,15 @@ public class RoleListPage extends AdministrationPage {
|
||||
cellItem.add(fragment);
|
||||
}
|
||||
});
|
||||
|
||||
columns.add(new AbstractColumn<Role, Void>(Model.of("Description")) {
|
||||
|
||||
@Override
|
||||
public void populateItem(Item<ICellPopulator<Role>> cellItem, String componentId, IModel<Role> rowModel) {
|
||||
cellItem.add(new Label(componentId, rowModel.getObject().getDescription()));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
columns.add(new AbstractColumn<Role, Void>(Model.of("")) {
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user