mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
chore: Improve link mutiple issues UI
This commit is contained in:
parent
f87ceb0d13
commit
53e91f8520
@ -0,0 +1,41 @@
|
|||||||
|
package io.onedev.server.web.component.issue.choice;
|
||||||
|
|
||||||
|
import static io.onedev.server.web.translation.Translation._T;
|
||||||
|
|
||||||
|
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.Issue;
|
||||||
|
import io.onedev.server.web.component.select2.Select2MultiChoice;
|
||||||
|
|
||||||
|
public class IssueMultiChoice extends Select2MultiChoice<Issue> {
|
||||||
|
|
||||||
|
public IssueMultiChoice(String id, IModel<Collection<Issue>> model, IssueChoiceProvider choiceProvider) {
|
||||||
|
super(id, model, choiceProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInitialize() {
|
||||||
|
super.onInitialize();
|
||||||
|
getSettings().setAllowClear(!isRequired());
|
||||||
|
if (isRequired())
|
||||||
|
getSettings().setPlaceholder(_T("Choose issues..."));
|
||||||
|
else
|
||||||
|
getSettings().setPlaceholder(_T("Not specified"));
|
||||||
|
getSettings().setFormatResult("onedev.server.issueChoiceFormatter.formatResult");
|
||||||
|
getSettings().setFormatSelection("onedev.server.issueChoiceFormatter.formatSelection");
|
||||||
|
getSettings().setEscapeMarkup("onedev.server.issueChoiceFormatter.escapeMarkup");
|
||||||
|
setConvertEmptyInputStringToNull(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderHead(IHeaderResponse response) {
|
||||||
|
super.renderHead(response);
|
||||||
|
|
||||||
|
response.render(JavaScriptHeaderItem.forReference(new IssueChoiceResourceReference()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,9 +9,9 @@ import org.apache.wicket.model.IModel;
|
|||||||
import io.onedev.server.model.Issue;
|
import io.onedev.server.model.Issue;
|
||||||
import io.onedev.server.web.component.select2.Select2Choice;
|
import io.onedev.server.web.component.select2.Select2Choice;
|
||||||
|
|
||||||
public class IssueChoice extends Select2Choice<Issue> {
|
public class IssueSingleChoice extends Select2Choice<Issue> {
|
||||||
|
|
||||||
public IssueChoice(String id, IModel<Issue> model, IssueChoiceProvider choiceProvider) {
|
public IssueSingleChoice(String id, IModel<Issue> model, IssueChoiceProvider choiceProvider) {
|
||||||
super(id, model, choiceProvider);
|
super(id, model, choiceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,11 +416,7 @@ public abstract class IssuePrimaryPanel extends Panel {
|
|||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FormComponent<Issue> newLinkExistingPanel(String componentId) {
|
private IssueChoiceProvider getIssueChoiceProvider() {
|
||||||
return new SelectIssuePanel(componentId) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IssueChoiceProvider getChoiceProvider() {
|
|
||||||
return new IssueChoiceProvider() {
|
return new IssueChoiceProvider() {
|
||||||
@Override
|
@Override
|
||||||
protected Project getProject() {
|
protected Project getProject() {
|
||||||
@ -438,10 +434,28 @@ public abstract class IssuePrimaryPanel extends Panel {
|
|||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FormComponent<?> newLinkExistingPanel(String componentId) {
|
||||||
|
LinkSpec spec = getLinkSpecManager().load(specId);
|
||||||
|
if (!opposite && spec.isMultiple() || opposite && spec.getOpposite().isMultiple()) {
|
||||||
|
return new SelectIssuesPanel(componentId) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IssueChoiceProvider getChoiceProvider() {
|
||||||
|
return getIssueChoiceProvider();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return new SelectIssuePanel(componentId) {
|
||||||
|
@Override
|
||||||
|
protected IssueChoiceProvider getChoiceProvider() {
|
||||||
|
return getIssueChoiceProvider();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private FormComponent<Issue> issuePopulator;
|
private FormComponent<?> issuePopulator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Component newContent(String id) {
|
protected Component newContent(String id) {
|
||||||
@ -511,30 +525,50 @@ public abstract class IssuePrimaryPanel extends Panel {
|
|||||||
form.add(new Label("title", MessageFormat.format(_T("Add {0}"), linkName)));
|
form.add(new Label("title", MessageFormat.format(_T("Add {0}"), linkName)));
|
||||||
|
|
||||||
form.add(new AjaxButton("save") {
|
form.add(new AjaxButton("save") {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
|
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
|
||||||
var linkIssue = issuePopulator.getConvertedInput();
|
var convertedInput = issuePopulator.getConvertedInput();
|
||||||
|
if (convertedInput instanceof Issue) {
|
||||||
|
var linkIssue = (Issue) convertedInput;
|
||||||
if (linkIssue.isNew()) {
|
if (linkIssue.isNew()) {
|
||||||
getIssueManager().open(linkIssue);
|
getIssueManager().open(linkIssue);
|
||||||
notifyIssueChange(target, linkIssue);
|
notifyIssueChange(target, linkIssue);
|
||||||
var spec = getLinkSpecManager().load(specId);
|
addLink(target, linkIssue);
|
||||||
getIssueChangeManager().addLink(spec, getIssue(), linkIssue, opposite);
|
|
||||||
notifyIssueChange(target, getIssue());
|
|
||||||
close();
|
close();
|
||||||
|
} else if (checkLink(target, linkIssue)) {
|
||||||
|
addLink(target, linkIssue);
|
||||||
|
close();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
var linkIssues = (List<Issue>) convertedInput;
|
||||||
|
if (linkIssues.stream().noneMatch(it->!checkLink(target, it))) {
|
||||||
|
for (var linkIssue: linkIssues)
|
||||||
|
addLink(target, linkIssue);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkLink(AjaxRequestTarget target, Issue linkIssue) {
|
||||||
LinkSpec spec = getLinkSpecManager().load(specId);
|
LinkSpec spec = getLinkSpecManager().load(specId);
|
||||||
if (getIssue().getId().equals(linkIssue.getId())) {
|
if (getIssue().getId().equals(linkIssue.getId())) {
|
||||||
form.error(_T("Can not link to self"));
|
form.error(_T("Can not link to self: " + linkIssue.getReference().toString(getProject())));
|
||||||
target.add(form);
|
target.add(form);
|
||||||
|
return false;
|
||||||
} else if (getIssue().findLinkedIssues(spec, opposite).contains(linkIssue)) {
|
} else if (getIssue().findLinkedIssues(spec, opposite).contains(linkIssue)) {
|
||||||
form.error(_T("Issue already linked"));
|
form.error(_T("Issue already linked: " + linkIssue.getReference().toString(getProject())));
|
||||||
target.add(form);
|
target.add(form);
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLink(AjaxRequestTarget target, Issue linkIssue) {
|
||||||
|
LinkSpec spec = getLinkSpecManager().load(specId);
|
||||||
getIssueChangeManager().addLink(spec, getIssue(), linkIssue, opposite);
|
getIssueChangeManager().addLink(spec, getIssue(), linkIssue, opposite);
|
||||||
notifyIssueChange(target, getIssue());
|
notifyIssueChange(target, getIssue());
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -8,14 +8,14 @@ import org.apache.wicket.model.Model;
|
|||||||
import io.onedev.server.OneDev;
|
import io.onedev.server.OneDev;
|
||||||
import io.onedev.server.entitymanager.IssueManager;
|
import io.onedev.server.entitymanager.IssueManager;
|
||||||
import io.onedev.server.model.Issue;
|
import io.onedev.server.model.Issue;
|
||||||
import io.onedev.server.web.component.issue.choice.IssueChoice;
|
|
||||||
import io.onedev.server.web.component.issue.choice.IssueChoiceProvider;
|
import io.onedev.server.web.component.issue.choice.IssueChoiceProvider;
|
||||||
|
import io.onedev.server.web.component.issue.choice.IssueSingleChoice;
|
||||||
|
|
||||||
abstract class SelectIssuePanel extends FormComponentPanel<Issue> {
|
abstract class SelectIssuePanel extends FormComponentPanel<Issue> {
|
||||||
|
|
||||||
private Long issueId;
|
private Long issueId;
|
||||||
|
|
||||||
private IssueChoice choice;
|
private IssueSingleChoice choice;
|
||||||
|
|
||||||
public SelectIssuePanel(String id) {
|
public SelectIssuePanel(String id) {
|
||||||
super(id, Model.of((Issue)null));
|
super(id, Model.of((Issue)null));
|
||||||
@ -26,7 +26,7 @@ abstract class SelectIssuePanel extends FormComponentPanel<Issue> {
|
|||||||
super.onInitialize();
|
super.onInitialize();
|
||||||
|
|
||||||
add(new FencedFeedbackPanel("feedback"));
|
add(new FencedFeedbackPanel("feedback"));
|
||||||
choice = new IssueChoice("choice", new IModel<Issue>() {
|
choice = new IssueSingleChoice("choice", new IModel<Issue>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void detach() {
|
public void detach() {
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
<wicket:panel>
|
||||||
|
<div wicket:id="feedback"></div>
|
||||||
|
<input wicket:id="choice" type="hidden" class="form-control">
|
||||||
|
</wicket:panel>
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
package io.onedev.server.web.component.issue.primary;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.wicket.feedback.FencedFeedbackPanel;
|
||||||
|
import org.apache.wicket.markup.html.form.FormComponentPanel;
|
||||||
|
import org.apache.wicket.model.IModel;
|
||||||
|
|
||||||
|
import io.onedev.server.OneDev;
|
||||||
|
import io.onedev.server.entitymanager.IssueManager;
|
||||||
|
import io.onedev.server.model.Issue;
|
||||||
|
import io.onedev.server.web.component.issue.choice.IssueChoiceProvider;
|
||||||
|
import io.onedev.server.web.component.issue.choice.IssueMultiChoice;
|
||||||
|
|
||||||
|
abstract class SelectIssuesPanel extends FormComponentPanel<Collection<Issue>> {
|
||||||
|
|
||||||
|
private Collection<Long> issueIds = new ArrayList<>();
|
||||||
|
|
||||||
|
private IssueMultiChoice choice;
|
||||||
|
|
||||||
|
public SelectIssuesPanel(String id) {
|
||||||
|
super(id, new IModel<Collection<Issue>>() {
|
||||||
|
|
||||||
|
private Collection<Issue> collection = new ArrayList<Issue>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void detach() {
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Collection<Issue> getObject() {
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setObject(Collection<Issue> object) {
|
||||||
|
collection = object;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInitialize() {
|
||||||
|
super.onInitialize();
|
||||||
|
|
||||||
|
add(new FencedFeedbackPanel("feedback"));
|
||||||
|
choice = new IssueMultiChoice("choice", new IModel<Collection<Issue>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void detach() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Issue> getObject() {
|
||||||
|
return issueIds.stream().map(it->getIssueManager().load(it)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObject(Collection<Issue> object) {
|
||||||
|
issueIds = object.stream().map(it->it.getId()).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}, getChoiceProvider());
|
||||||
|
|
||||||
|
choice.setRequired(true);
|
||||||
|
add(choice);
|
||||||
|
|
||||||
|
setOutputMarkupId(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void convertInput() {
|
||||||
|
super.convertInput();
|
||||||
|
setConvertedInput(choice.getConvertedInput());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract IssueChoiceProvider getChoiceProvider();
|
||||||
|
|
||||||
|
private IssueManager getIssueManager() {
|
||||||
|
return OneDev.getInstance(IssueManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@ import io.onedev.server.entitymanager.IssueManager;
|
|||||||
import io.onedev.server.model.Issue;
|
import io.onedev.server.model.Issue;
|
||||||
import io.onedev.server.model.Project;
|
import io.onedev.server.model.Project;
|
||||||
import io.onedev.server.search.entity.issue.IssueQuery;
|
import io.onedev.server.search.entity.issue.IssueQuery;
|
||||||
import io.onedev.server.web.component.issue.choice.IssueChoice;
|
import io.onedev.server.web.component.issue.choice.IssueSingleChoice;
|
||||||
import io.onedev.server.web.component.issue.choice.IssueChoiceProvider;
|
import io.onedev.server.web.component.issue.choice.IssueChoiceProvider;
|
||||||
import io.onedev.server.web.editable.PropertyDescriptor;
|
import io.onedev.server.web.editable.PropertyDescriptor;
|
||||||
import io.onedev.server.web.editable.PropertyEditor;
|
import io.onedev.server.web.editable.PropertyEditor;
|
||||||
@ -22,7 +22,7 @@ import io.onedev.server.web.util.ProjectAware;
|
|||||||
|
|
||||||
public class IssueChoiceEditor extends PropertyEditor<Long> {
|
public class IssueChoiceEditor extends PropertyEditor<Long> {
|
||||||
|
|
||||||
private IssueChoice input;
|
private IssueSingleChoice input;
|
||||||
|
|
||||||
public IssueChoiceEditor(String id, PropertyDescriptor propertyDescriptor,
|
public IssueChoiceEditor(String id, PropertyDescriptor propertyDescriptor,
|
||||||
IModel<Long> propertyModel) {
|
IModel<Long> propertyModel) {
|
||||||
@ -64,7 +64,7 @@ public class IssueChoiceEditor extends PropertyEditor<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
input = new IssueChoice("input", Model.of(issue), choiceProvider) {
|
input = new IssueSingleChoice("input", Model.of(issue), choiceProvider) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onInitialize() {
|
protected void onInitialize() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user