Basic GUI for assigning reviewers
This commit is contained in:
parent
a615f12238
commit
33e0e033b5
core/src/main/java/se/su/dsv/scipro/reviewing
ReviewerAssignmentService.javaReviewerCandidates.javaReviewerCapacityServiceImpl.javaReviewingModule.java
view/src/main/java/se/su/dsv/scipro
@ -0,0 +1,7 @@
|
||||
package se.su.dsv.scipro.reviewing;
|
||||
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
||||
public interface ReviewerAssignmentService {
|
||||
ReviewerCandidates getCandidatesToReview(Project project);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package se.su.dsv.scipro.reviewing;
|
||||
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ReviewerCandidates(List<Candidate> goodCandidates) {
|
||||
public record Candidate(User reviewer, int target, int assigned) {
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
package se.su.dsv.scipro.reviewing;
|
||||
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
class ReviewerCapacityServiceImpl implements ReviewerCapacityService {
|
||||
class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAssignmentService {
|
||||
private final ReviewerTargetRepository reviewerTargetRepository;
|
||||
|
||||
@Inject
|
||||
@ -31,4 +33,10 @@ class ReviewerCapacityServiceImpl implements ReviewerCapacityService {
|
||||
.max()
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReviewerCandidates getCandidatesToReview(Project project) {
|
||||
return new ReviewerCandidates(
|
||||
List.of(new ReviewerCandidates.Candidate(project.getHeadSupervisor(), 5, 2)));
|
||||
}
|
||||
}
|
||||
|
@ -20,5 +20,6 @@ public class ReviewingModule extends AbstractModule {
|
||||
bind(ReviewerDeadlineSettingsRepository.class).to(ReviewerDeadlineSettingsRepositoryImpl.class);
|
||||
bind(ReviewerDeadlineFollowupService.class).to(ReviewerDeadlineFollowupServiceImpl.class);
|
||||
bind(ReviewerCapacityService.class).to(ReviewerCapacityServiceImpl.class);
|
||||
bind(ReviewerAssignmentService.class).to(ReviewerCapacityServiceImpl.class);
|
||||
}
|
||||
}
|
||||
|
@ -273,6 +273,7 @@ public class SciProApplication extends LifecycleManagedWebApplication {
|
||||
mountPage("admin/project", ProjectManagementPage.class);
|
||||
mountPage("admin/project/create", AdminCreateProjectPage.class);
|
||||
mountPage("admin/project/survey", AdminSurveyPage.class);
|
||||
mountPage("admin/project/reviewer", AdminAssignReviewerPage.class);
|
||||
mountPage("admin/edit", AdminEditProjectPage.class);
|
||||
mountPage("admin/finalseminars", AdminFinalSeminarPage.class);
|
||||
mountPage("admin/finalseminars/exemptions", AdminFinalSeminarExemptionPage.class);
|
||||
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
|
||||
<body>
|
||||
<wicket:extend>
|
||||
<div class="row">
|
||||
<div class="col-12 col-xl-4" wicket:id="project_details">
|
||||
<dl>
|
||||
<dt>Project</dt>
|
||||
<dd wicket:id="title"></dd>
|
||||
|
||||
<dt>Supervisor</dt>
|
||||
<dd wicket:id="supervisor"></dd>
|
||||
|
||||
<dt>Research area</dt>
|
||||
<dd wicket:id="research_area"></dd>
|
||||
|
||||
<dt>Language</dt>
|
||||
<dd wicket:id="language"></dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-4 col-md-6" wicket:id="reviewers">
|
||||
<div class="card bg-success text-white bg-opacity-50" wicket:id="good_candidates">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<img class="img-fluid rounded-start" wicket:id="image">
|
||||
</div>
|
||||
<div class="col my-auto">
|
||||
<div class="card-body p-0">
|
||||
<h4 class="card-title text-white" wicket:id="user"></h4>
|
||||
<span wicket:id="assigned"></span> / <span wicket:id="target"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto my-auto">
|
||||
<div class="card-body py-0">
|
||||
<button class="btn btn-success">Assign</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wicket:extend>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,85 @@
|
||||
package se.su.dsv.scipro.admin.pages;
|
||||
|
||||
import org.apache.wicket.RestartResponseException;
|
||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||
import org.apache.wicket.markup.html.basic.EnumLabel;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.list.ListItem;
|
||||
import org.apache.wicket.markup.html.list.ListView;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
import org.apache.wicket.util.string.StringValueConversionException;
|
||||
import se.su.dsv.scipro.data.DetachableServiceModel;
|
||||
import se.su.dsv.scipro.profile.UserLabel;
|
||||
import se.su.dsv.scipro.profile.UserLinkPanel;
|
||||
import se.su.dsv.scipro.profile.UserProfileImage;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.project.ProjectService;
|
||||
import se.su.dsv.scipro.reviewing.ReviewerAssignmentService;
|
||||
import se.su.dsv.scipro.reviewing.ReviewerCandidates;
|
||||
import se.su.dsv.scipro.system.ResearchArea;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class AdminAssignReviewerPage extends AbstractAdminProjectPage {
|
||||
@Inject
|
||||
private ProjectService projectService;
|
||||
|
||||
public AdminAssignReviewerPage(PageParameters pp) {
|
||||
IModel<Project> projectModel = new DetachableServiceModel<>(projectService);
|
||||
try {
|
||||
long pid = pp.get("pid").toLong();
|
||||
Project project = projectService.findOne(pid);
|
||||
if (project == null) {
|
||||
throw new RestartResponseException(ProjectManagementPage.class);
|
||||
}
|
||||
projectModel.setObject(project);
|
||||
} catch (StringValueConversionException ignored) {
|
||||
throw new RestartResponseException(ProjectManagementPage.class);
|
||||
}
|
||||
|
||||
add(new ProjectDetailsPanel("project_details", projectModel));
|
||||
|
||||
add(new AvailableReviewersPanel("reviewers", projectModel));
|
||||
}
|
||||
|
||||
public static PageParameters pageParametersFor(Project project) {
|
||||
PageParameters pageParameters = new PageParameters();
|
||||
pageParameters.set("pid", project.getId());
|
||||
return pageParameters;
|
||||
}
|
||||
|
||||
private static class ProjectDetailsPanel extends WebMarkupContainer {
|
||||
public ProjectDetailsPanel(String id, IModel<Project> projectModel) {
|
||||
super(id, projectModel);
|
||||
|
||||
add(new Label("title", projectModel.map(Project::getTitle)));
|
||||
add(new Label("research_area", projectModel.map(Project::getResearchArea).map(ResearchArea::getTitle)));
|
||||
add(new UserLinkPanel("supervisor", projectModel.map(Project::getHeadSupervisor)));
|
||||
add(new EnumLabel<>("language", projectModel.map(Project::getLanguage)));
|
||||
}
|
||||
}
|
||||
|
||||
private static class AvailableReviewersPanel extends WebMarkupContainer {
|
||||
@Inject
|
||||
private ReviewerAssignmentService reviewerAssignmentService;
|
||||
|
||||
public AvailableReviewersPanel(String id, IModel<Project> projectModel) {
|
||||
super(id, projectModel);
|
||||
|
||||
IModel<ReviewerCandidates> reviewerCandidates = LoadableDetachableModel.of(() ->
|
||||
reviewerAssignmentService.getCandidatesToReview(projectModel.getObject()));
|
||||
|
||||
add(new ListView<>("good_candidates", reviewerCandidates.map(ReviewerCandidates::goodCandidates)) {
|
||||
@Override
|
||||
protected void populateItem(ListItem<ReviewerCandidates.Candidate> item) {
|
||||
item.add(new UserProfileImage("image", item.getModel().map(ReviewerCandidates.Candidate::reviewer), UserProfileImage.Size.MEDIUM));
|
||||
item.add(new UserLabel("user", item.getModel().map(ReviewerCandidates.Candidate::reviewer)));
|
||||
item.add(new Label("target", item.getModel().map(ReviewerCandidates.Candidate::target)));
|
||||
item.add(new Label("assigned", item.getModel().map(ReviewerCandidates.Candidate::assigned)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LambdaModel;
|
||||
import org.apache.wicket.model.Model;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
import se.su.dsv.scipro.admin.pages.AdminAssignReviewerPage;
|
||||
import se.su.dsv.scipro.admin.pages.AdminCreateProjectPage;
|
||||
import se.su.dsv.scipro.admin.pages.AdminEditProjectPage;
|
||||
import se.su.dsv.scipro.components.EmployeeAutoCompleteDivPanel;
|
||||
@ -159,32 +160,15 @@ public class ProjectDataPanel extends Panel {
|
||||
}
|
||||
|
||||
private AbstractColumn<Project, String> reviewerColumn() {
|
||||
return new UserColumn<>(Model.of("Reviewer"), Project::getReviewer) {
|
||||
return new LambdaColumn<>(Model.of("Reviewer"), Project::getReviewer) {
|
||||
@Override
|
||||
public void populateItem(final Item<ICellPopulator<Project>> cellItem, final String componentId, final IModel<Project> rowModel) {
|
||||
cellItem.add(new EmployeeAutoCompleteDivPanel(componentId, new DetachableServiceModel<>(userService, rowModel.getObject().getReviewer())) {
|
||||
@Override
|
||||
public void onNewEmployeeSelection(final AjaxRequestTarget target, final User newSelection) {
|
||||
Project project = rowModel.getObject();
|
||||
if (project.getHeadSupervisor().equals(newSelection)) {
|
||||
error(getString("supervisor.reviewer.error"));
|
||||
} else if (!newSelection.getRoles().contains(Roles.REVIEWER)) {
|
||||
error(getString("not.reviewer.error"));
|
||||
} else {
|
||||
for (User currentReviewer : project.getReviewers()) {
|
||||
project.removeReviewer(currentReviewer);
|
||||
}
|
||||
project.addReviewer(newSelection);
|
||||
notifyReviewersChanged(project);
|
||||
eventBus.post(new ReviewerAssignedEvent(project, newSelection));
|
||||
|
||||
projectService.save(project);
|
||||
info(getString("reviewer.updated"));
|
||||
}
|
||||
target.add(feedback);
|
||||
target.add(exportableDataPanel);
|
||||
}
|
||||
});
|
||||
cellItem.add(LinkWrapper.apply(componentId, id -> {
|
||||
PageParameters pp = AdminAssignReviewerPage.pageParametersFor(rowModel.getObject());
|
||||
final BookmarkablePageLink<Void> link = new BookmarkablePageLink<>(id, AdminAssignReviewerPage.class, pp);
|
||||
link.setBody(Model.of("Assign reviewer"));
|
||||
return link;
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user