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.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);
|
||||
}
|
||||
|
||||
@ -416,32 +416,46 @@ public abstract class IssuePrimaryPanel extends Panel {
|
||||
return editor;
|
||||
}
|
||||
|
||||
private FormComponent<Issue> newLinkExistingPanel(String componentId) {
|
||||
return new SelectIssuePanel(componentId) {
|
||||
|
||||
private IssueChoiceProvider getIssueChoiceProvider() {
|
||||
return new IssueChoiceProvider() {
|
||||
@Override
|
||||
protected IssueChoiceProvider getChoiceProvider() {
|
||||
return new IssueChoiceProvider() {
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return getIssue().getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IssueQuery getBaseQuery() {
|
||||
LinkSpec spec = getLinkSpecManager().load(specId);
|
||||
if (opposite)
|
||||
return spec.getOpposite().getParsedIssueQuery(getProject());
|
||||
else
|
||||
return spec.getParsedIssueQuery(getProject());
|
||||
}
|
||||
|
||||
};
|
||||
protected Project getProject() {
|
||||
return getIssue().getProject();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected IssueQuery getBaseQuery() {
|
||||
LinkSpec spec = getLinkSpecManager().load(specId);
|
||||
if (opposite)
|
||||
return spec.getOpposite().getParsedIssueQuery(getProject());
|
||||
else
|
||||
return spec.getParsedIssueQuery(getProject());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private FormComponent<Issue> issuePopulator;
|
||||
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<?> issuePopulator;
|
||||
|
||||
@Override
|
||||
protected Component newContent(String id) {
|
||||
@ -511,32 +525,52 @@ public abstract class IssuePrimaryPanel extends Panel {
|
||||
form.add(new Label("title", MessageFormat.format(_T("Add {0}"), linkName)));
|
||||
|
||||
form.add(new AjaxButton("save") {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
|
||||
var linkIssue = issuePopulator.getConvertedInput();
|
||||
if (linkIssue.isNew()) {
|
||||
getIssueManager().open(linkIssue);
|
||||
notifyIssueChange(target, linkIssue);
|
||||
var spec = getLinkSpecManager().load(specId);
|
||||
getIssueChangeManager().addLink(spec, getIssue(), linkIssue, opposite);
|
||||
notifyIssueChange(target, getIssue());
|
||||
close();
|
||||
} else {
|
||||
LinkSpec spec = getLinkSpecManager().load(specId);
|
||||
if (getIssue().getId().equals(linkIssue.getId())) {
|
||||
form.error(_T("Can not link to self"));
|
||||
target.add(form);
|
||||
} else if (getIssue().findLinkedIssues(spec, opposite).contains(linkIssue)) {
|
||||
form.error(_T("Issue already linked"));
|
||||
target.add(form);
|
||||
} else {
|
||||
getIssueChangeManager().addLink(spec, getIssue(), linkIssue, opposite);
|
||||
notifyIssueChange(target, getIssue());
|
||||
var convertedInput = issuePopulator.getConvertedInput();
|
||||
if (convertedInput instanceof Issue) {
|
||||
var linkIssue = (Issue) convertedInput;
|
||||
if (linkIssue.isNew()) {
|
||||
getIssueManager().open(linkIssue);
|
||||
notifyIssueChange(target, linkIssue);
|
||||
addLink(target, linkIssue);
|
||||
close();
|
||||
}
|
||||
} else if (checkLink(target, linkIssue)) {
|
||||
addLink(target, linkIssue);
|
||||
close();
|
||||
}
|
||||
} 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);
|
||||
if (getIssue().getId().equals(linkIssue.getId())) {
|
||||
form.error(_T("Can not link to self: " + linkIssue.getReference().toString(getProject())));
|
||||
target.add(form);
|
||||
return false;
|
||||
} else if (getIssue().findLinkedIssues(spec, opposite).contains(linkIssue)) {
|
||||
form.error(_T("Issue already linked: " + linkIssue.getReference().toString(getProject())));
|
||||
target.add(form);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void addLink(AjaxRequestTarget target, Issue linkIssue) {
|
||||
LinkSpec spec = getLinkSpecManager().load(specId);
|
||||
getIssueChangeManager().addLink(spec, getIssue(), linkIssue, opposite);
|
||||
notifyIssueChange(target, getIssue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onError(AjaxRequestTarget target, Form<?> form) {
|
||||
target.add(form);
|
||||
|
||||
@ -8,14 +8,14 @@ import org.apache.wicket.model.Model;
|
||||
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.IssueChoice;
|
||||
import io.onedev.server.web.component.issue.choice.IssueChoiceProvider;
|
||||
import io.onedev.server.web.component.issue.choice.IssueSingleChoice;
|
||||
|
||||
abstract class SelectIssuePanel extends FormComponentPanel<Issue> {
|
||||
|
||||
private Long issueId;
|
||||
|
||||
private IssueChoice choice;
|
||||
private IssueSingleChoice choice;
|
||||
|
||||
public SelectIssuePanel(String id) {
|
||||
super(id, Model.of((Issue)null));
|
||||
@ -26,7 +26,7 @@ abstract class SelectIssuePanel extends FormComponentPanel<Issue> {
|
||||
super.onInitialize();
|
||||
|
||||
add(new FencedFeedbackPanel("feedback"));
|
||||
choice = new IssueChoice("choice", new IModel<Issue>() {
|
||||
choice = new IssueSingleChoice("choice", new IModel<Issue>() {
|
||||
|
||||
@Override
|
||||
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.Project;
|
||||
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.editable.PropertyDescriptor;
|
||||
import io.onedev.server.web.editable.PropertyEditor;
|
||||
@ -22,7 +22,7 @@ import io.onedev.server.web.util.ProjectAware;
|
||||
|
||||
public class IssueChoiceEditor extends PropertyEditor<Long> {
|
||||
|
||||
private IssueChoice input;
|
||||
private IssueSingleChoice input;
|
||||
|
||||
public IssueChoiceEditor(String id, PropertyDescriptor propertyDescriptor,
|
||||
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
|
||||
protected void onInitialize() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user