3321 PO 4) Show current reviewer and allow un-assigning
This commit is contained in:
parent
b4edcf50c7
commit
36d3ab35ad
core/src/main/java/se/su/dsv/scipro
project
reviewing
view/src/main/java/se/su/dsv/scipro
@ -0,0 +1,4 @@
|
||||
package se.su.dsv.scipro.project;
|
||||
|
||||
public record ReviewerUnassignedEvent(Project project) {
|
||||
}
|
@ -10,6 +10,8 @@ public interface ReviewerAssignmentService {
|
||||
|
||||
ReviewerAssignment assignReviewer(Project project, User reviewer);
|
||||
|
||||
void unassignReviewer(Project project);
|
||||
|
||||
enum ReviewerAssignment {
|
||||
OK, ERROR_IS_SUPERVISOR, ERROR_IS_NOT_REVIEWER
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package se.su.dsv.scipro.reviewing;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.project.ProjectService;
|
||||
import se.su.dsv.scipro.project.ReviewerAssignedEvent;
|
||||
import se.su.dsv.scipro.project.ReviewerUnassignedEvent;
|
||||
import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||
import se.su.dsv.scipro.system.Language;
|
||||
import se.su.dsv.scipro.system.Unit;
|
||||
@ -20,6 +22,7 @@ import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAssignmentService {
|
||||
@ -194,6 +197,14 @@ class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAs
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void unassignReviewer(Project project) {
|
||||
project.setReviewers(Set.of());
|
||||
projectService.save(project);
|
||||
eventBus.post(new ReviewerUnassignedEvent(project));
|
||||
}
|
||||
|
||||
private int countAssignedReviews(User reviewer, LocalDate fromDate) {
|
||||
if (fromDate.getMonthValue() <= Month.JUNE.getValue()) {
|
||||
return decisionRepository.countDecisions(reviewer,
|
||||
|
@ -25,6 +25,44 @@
|
||||
|
||||
<div class="col-12 col-xl-4 col-md-6" wicket:id="reviewers">
|
||||
<div wicket:id="feedback"></div>
|
||||
<wicket:enclosure child="current_reviewer">
|
||||
<h3>Current reviewer</h3>
|
||||
<div class="card mb-3 bg-info bg-opacity-25" wicket:id="current_reviewer">
|
||||
<div class="row g-0">
|
||||
<div class="col-auto">
|
||||
<img class="img-fluid rounded-start" wicket:id="image">
|
||||
</div>
|
||||
<div class="col my-auto">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title" wicket:id="name"></h4>
|
||||
<div>
|
||||
Research areas:
|
||||
<ul>
|
||||
<li wicket:id="research_areas">
|
||||
<wicket:container wicket:id="research_area"></wicket:container>
|
||||
</li>
|
||||
<li wicket:id="none">None specified</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
Languages:
|
||||
<ul class="mb-0">
|
||||
<li wicket:id="languages">
|
||||
<wicket:container wicket:id="language"></wicket:container>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto my-auto">
|
||||
<div class="card-body">
|
||||
<button class="btn btn-success" wicket:id="unassign">Un-assign</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</wicket:enclosure>
|
||||
|
||||
<wicket:enclosure child="good_candidates">
|
||||
<h3>Suitable candidates</h3>
|
||||
<p>
|
||||
|
@ -31,6 +31,9 @@ import javax.inject.Inject;
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class AdminAssignReviewerPage extends AbstractAdminProjectPage {
|
||||
@Inject
|
||||
@ -88,6 +91,8 @@ public class AdminAssignReviewerPage extends AbstractAdminProjectPage {
|
||||
reviewerCandidates = LoadableDetachableModel.of(() ->
|
||||
reviewerAssignmentService.getCandidatesToReview(projectModel.getObject(), LocalDate.now(clock)));
|
||||
|
||||
add(new CurrentReviewerCard("current_reviewer", projectModel.map(Project::getReviewer)));
|
||||
|
||||
add(new AutoHidingListView<>("good_candidates", reviewerCandidates.map(ReviewerCandidates::good)) {
|
||||
@Override
|
||||
protected void populateItem(ListItem<ReviewerCandidates.Candidate> item) {
|
||||
@ -127,6 +132,46 @@ public class AdminAssignReviewerPage extends AbstractAdminProjectPage {
|
||||
});
|
||||
}
|
||||
|
||||
private class CurrentReviewerCard extends GenericWebMarkupContainer<User> {
|
||||
public CurrentReviewerCard(String id, IModel<User> reviewer) {
|
||||
super(id, reviewer);
|
||||
add(new UserProfileImage("image", reviewer, UserProfileImage.Size.MEDIUM));
|
||||
add(new UserLabel("name", reviewer));
|
||||
add(new AutoHidingListView<>("research_areas", reviewer.map(User::getResearchAreas).map(ArrayList::new)) {
|
||||
@Override
|
||||
protected void populateItem(ListItem<ResearchArea> item) {
|
||||
item.add(new Label("research_area", item.getModel().map(ResearchArea::getTitle)));
|
||||
}
|
||||
});
|
||||
add(new WebMarkupContainer("none") {
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisible(reviewer.getObject().getResearchAreas().isEmpty());
|
||||
}
|
||||
});
|
||||
add(new AutoHidingListView<>("languages", reviewer.map(User::getLanguages).map(ArrayList::new)) {
|
||||
@Override
|
||||
protected void populateItem(ListItem<Language> item) {
|
||||
item.add(new EnumLabel<>("language", item.getModel()));
|
||||
}
|
||||
});
|
||||
add(new Link<>("unassign", reviewer) {
|
||||
@Override
|
||||
public void onClick() {
|
||||
reviewerAssignmentService.unassignReviewer(AvailableReviewersPanel.this.getModelObject());
|
||||
AvailableReviewersPanel.this.success(getString("reviewer_unassigned"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisible(getModelObject() != null);
|
||||
}
|
||||
}
|
||||
|
||||
private class ReviewerCard extends Fragment {
|
||||
public ReviewerCard(String id, IModel<ReviewerCandidates.Candidate> candidate) {
|
||||
super(id, "reviewer_details", AvailableReviewersPanel.this, candidate);
|
||||
|
@ -1,3 +1,4 @@
|
||||
reviewer_assigned=Reviewer assigned
|
||||
error_reviewer_is_supervisor=The selected reviewer is the supervisor of the project
|
||||
error_reviewer_is_not_reviewer=The selected reviewer does not have the reviewer role
|
||||
reviewer_unassigned=Reviewer un-assigned
|
||||
|
@ -4,6 +4,7 @@ import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import se.su.dsv.scipro.misc.DaysService;
|
||||
import se.su.dsv.scipro.project.ReviewerAssignedEvent;
|
||||
import se.su.dsv.scipro.project.ReviewerUnassignedEvent;
|
||||
import se.su.dsv.scipro.reviewing.*;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -11,7 +12,6 @@ import javax.inject.Singleton;
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Date;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Singleton
|
||||
public class ReviewerAssignedDeadline {
|
||||
@ -73,6 +73,27 @@ public class ReviewerAssignedDeadline {
|
||||
});
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void reviewerUnassigned(ReviewerUnassignedEvent event) {
|
||||
roughDraftApprovalService.findBy(event.project())
|
||||
.filter(rda -> !rda.isDecided())
|
||||
.map(ReviewerApproval::getCurrentDecision)
|
||||
.ifPresent(currentDecision -> {
|
||||
currentDecision.setDeadline(null);
|
||||
currentDecision.setAssignedReviewer(null);
|
||||
currentDecision.setReviewerAssignedAt(null);
|
||||
});
|
||||
|
||||
finalSeminarApprovalService.findBy(event.project())
|
||||
.filter(fsa -> !fsa.isDecided())
|
||||
.map(ReviewerApproval::getCurrentDecision)
|
||||
.ifPresent(currentDecision -> {
|
||||
currentDecision.setDeadline(null);
|
||||
currentDecision.setAssignedReviewer(null);
|
||||
currentDecision.setReviewerAssignedAt(null);
|
||||
});
|
||||
}
|
||||
|
||||
protected Date getDeadline(int days) {
|
||||
return daysService.workDaysAfter(new Date(), days);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user