Allows admins to manage grading report templates #14

Merged
niat8586 merged 41 commits from 3482-new-grading-criteria into develop 2024-10-30 10:05:23 +01:00
6 changed files with 344 additions and 1 deletions
Showing only changes of commit ffcd880384 - Show all commits

View File

@ -14,6 +14,7 @@ import org.apache.wicket.util.convert.converter.LocalDateConverter;
import org.apache.wicket.util.convert.converter.LocalDateTimeConverter;
import se.su.dsv.scipro.activityplan.*;
import se.su.dsv.scipro.admin.pages.*;
import se.su.dsv.scipro.admin.pages.grading.AdminGradingTemplateEditPage;
import se.su.dsv.scipro.admin.pages.grading.AdminGradingTemplatePage;
import se.su.dsv.scipro.admin.pages.grading.AdminGradingTemplatesOverviewPage;
import se.su.dsv.scipro.admin.pages.settings.*;
@ -286,6 +287,7 @@ public class SciProApplication extends LifecycleManagedWebApplication {
mountPage("admin/project/reviewer/capacity", AdminReviewerCapacityManagementPage.class);
mountPage("admin/project/grading/template", AdminGradingTemplatesOverviewPage.class);
mountPage("admin/project/grading/template/view", AdminGradingTemplatePage.class);
mountPage("admin/project/grading/template/edit", AdminGradingTemplateEditPage.class);
mountPage("admin/edit", AdminEditProjectPage.class);
mountPage("admin/finalseminars", AdminFinalSeminarPage.class);
mountPage("admin/finalseminars/exemptions", AdminFinalSeminarExemptionPage.class);

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:extend>
<form wicket:id="form">
<div wicket:id="editing" class="mb-3"></div>
<div class="position-sticky bottom-0 bg-white p-3 border line-length-limit">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</wicket:extend>
</body>
</html>

View File

@ -1,13 +1,38 @@
package se.su.dsv.scipro.admin.pages.grading;
import jakarta.inject.Inject;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import se.su.dsv.scipro.admin.pages.AbstractAdminProjectPage;
import se.su.dsv.scipro.grading.GradingReportTemplateService;
import se.su.dsv.scipro.report.GradingReportTemplate;
public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage implements MenuHighlightGradingTemplates {
private static final String GRADING_REPORT_TEMPLATE_ID_PARAMETER = "id";
public AdminGradingTemplateEditPage() {
@Inject
GradingReportTemplateService gradingReportTemplateService;
private EditingGradingTemplate editingGradingTemplate;
public AdminGradingTemplateEditPage(PageParameters pageParameters) {
long id = pageParameters.get(GRADING_REPORT_TEMPLATE_ID_PARAMETER).toLong();
GradingReportTemplate template = gradingReportTemplateService.getTemplate(id);
editingGradingTemplate = new EditingGradingTemplate(template);
Form<EditingGradingTemplate> form = new Form<>("form") {
@Override
protected void onSubmit() {
super.onSubmit();
System.out.println(editingGradingTemplate);
}
};
form.add(new EditingGradingTemplateComponentPanel("editing", Model.of(editingGradingTemplate)));
add(form);
}
public static PageParameters getPageParameters(GradingReportTemplate gradingReportTemplate) {

View File

@ -0,0 +1,107 @@
package se.su.dsv.scipro.admin.pages.grading;
import se.su.dsv.scipro.report.GradingCriterionPointTemplate;
import se.su.dsv.scipro.report.GradingCriterionTemplate;
import se.su.dsv.scipro.report.GradingReportTemplate;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
class EditingGradingTemplate implements Serializable {
private String note;
private List<Criteria> criteria;
EditingGradingTemplate(GradingReportTemplate template) {
this.note = "";
this.criteria = new ArrayList<>();
for (var criteria : template.getCriteria()) {
Criteria editingCriteria = new Criteria(criteria);
this.criteria.add(editingCriteria);
}
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public List<Criteria> getCriteria() {
return criteria;
}
class Criteria implements Serializable {
private String titleSv;
private String titleEn;
private List<Point> points;
Criteria(GradingCriterionTemplate criteria) {
this.titleSv = criteria.getTitle();
this.titleEn = criteria.getTitleEn();
this.points = new ArrayList<>();
for (var point : criteria.getGradingCriterionPointTemplates()) {
if (point.getPoint() == 0) continue;;
Point editingPoint = new Point(point);
this.points.add(editingPoint);
}
}
public String getTitleSv() {
return titleSv;
}
public void setTitleSv(String titleSv) {
this.titleSv = titleSv;
}
public String getTitleEn() {
return titleEn;
}
public void setTitleEn(String titleEn) {
this.titleEn = titleEn;
}
public List<Point> getPoints() {
return points;
}
public void setPoints(List<Point> points) {
this.points = points;
}
class Point implements Serializable {
private String requirementEn;
private String requirementSv;
Point() {
this.requirementEn = "";
this.requirementSv = "";
}
Point(GradingCriterionPointTemplate point) {
this.requirementEn = point.getDescriptionEn();
this.requirementSv = point.getDescription();
}
public String getRequirementEn() {
return requirementEn;
}
public void setRequirementEn(String requirement) {
this.requirementEn = requirement;
}
public String getRequirementSv() {
return requirementSv;
}
public void setRequirementSv(String requirementSv) {
this.requirementSv = requirementSv;
}
}
}
}

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
<head>
<wicket:remove>
<link rel="stylesheet" type="text/css" href="../../../../../../../../webapp/css/scipro_m.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</wicket:remove>
</head>
<body>
<wicket:panel>
<div class="mb-3 line-length-limit">
<label class="form-label" wicket:for="note">
Note
</label>
<textarea class="form-control" wicket:id="note" rows="3"></textarea>
<small class="text-muted">
This note can be used to describe the template, for example, what changes have been made from the previous version.
It is purely an aid for administrators if necessary.
</small>
</div>
<div class="mb-3 line-length-limit card" wicket:id="criteria">
<div class="card-header text-bg-info text-white">
<h3 class="text-white mb-0">Criteria 1</h3>
</div>
<div wicket:id="criteria" class="card-body">
<div class="row mb-3">
<div class="col">
<label class="form-label" wicket:for="title_en">
Title (english)
</label>
<input class="form-control" wicket:id="title_en" type="text">
</div>
<div class="col">
<label class="form-label" wicket:for="title_sv">
Title (swedish)
</label>
<input class="form-control" wicket:id="title_sv" type="text">
</div>
</div>
<fieldset>
<legend>Points</legend>
<ol class="list-unstyled">
<li wicket:id="points">
<fieldset wicket:id="point" class="card mb-3">
<legend class="card-header hstack justify-content-between">
<span wicket:id="point"></span>
<button class="btn btn-sm btn-outline-danger" wicket:id="remove">Remove</button>
</legend>
<div class="card-body">
<div class="mb-3">
<label wicket:for="requirement_en">
Requirement (english)
</label>
<textarea rows="4" class="form-control" wicket:id="requirement_en"></textarea>
</div>
<div>
<label wicket:for="requirement_sv">
Requirement (swedish)
</label>
<textarea rows="4" class="form-control" wicket:id="requirement_sv"></textarea>
</div>
</div>
</fieldset>
</li>
<li>
<div class="row align-items-center" wicket:id="new_point_form">
<label class="col-auto">
<wicket:container wicket:id="new_point"/>
</label>
<div class="col-auto">
<div class="btn-group">
<button class="btn btn-sm btn-outline-success" wicket:id="add_new_point">Add</button>
</div>
</div>
</div>
</li>
</ol>
</fieldset>
</div>
</div>
</wicket:panel>
</body>
</html>

View File

@ -0,0 +1,109 @@
package se.su.dsv.scipro.admin.pages.grading;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.markup.html.GenericWebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.GenericPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LambdaModel;
import org.apache.wicket.model.Model;
class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTemplate> {
EditingGradingTemplateComponentPanel(
String id,
IModel<EditingGradingTemplate> editingGradingTemplateModel)
{
super(id, editingGradingTemplateModel);
add(new TextArea<>("note", LambdaModel.of(
editingGradingTemplateModel,
EditingGradingTemplate::getNote,
EditingGradingTemplate::setNote)));
add(new ListView<>("criteria", editingGradingTemplateModel.map(EditingGradingTemplate::getCriteria)) {
{
setReuseItems(true);
}
@Override
protected void populateItem(ListItem<EditingGradingTemplate.Criteria> item) {
item.add(new CriteriaEditingPanel("criteria", item.getModel()));
}
});
}
class CriteriaEditingPanel extends GenericWebMarkupContainer<EditingGradingTemplate.Criteria> {
CriteriaEditingPanel(String id, IModel<EditingGradingTemplate.Criteria> model) {
super(id, model);
setOutputMarkupId(true);
add(new TextField<>("title_sv", LambdaModel.of(
model,
EditingGradingTemplate.Criteria::getTitleSv,
EditingGradingTemplate.Criteria::setTitleSv)));
add(new TextField<>("title_en", LambdaModel.of(
model,
EditingGradingTemplate.Criteria::getTitleEn,
EditingGradingTemplate.Criteria::setTitleEn)));
add(new ListView<>("points", model.map(EditingGradingTemplate.Criteria::getPoints)) {
@Override
protected void populateItem(ListItem<EditingGradingTemplate.Criteria.Point> item) {
item.add(new PointEditingPanel("point", item.getModel()));
}
});
Form<Object> newPointForm = new Form<>("new_point_form");
add(newPointForm);
newPointForm.add(new Label("new_point", model
.map(criteria -> criteria.getPoints().size())
.map(size -> "Requirement for " + size + " points")));
newPointForm.add(new AjaxSubmitLink("add_new_point", newPointForm) {
@Override
public void onSubmit(AjaxRequestTarget target) {
EditingGradingTemplate.Criteria criteria = model.getObject();
EditingGradingTemplate.Criteria.Point newPoint = criteria.new Point();
criteria.getPoints().add(newPoint);
target.add(CriteriaEditingPanel.this);
}
});
}
private class PointEditingPanel extends GenericWebMarkupContainer<EditingGradingTemplate.Criteria.Point> {
public PointEditingPanel(String id, IModel<EditingGradingTemplate.Criteria.Point> model) {
super(id, model);
add(new Label("point", "Requirement for 1 point"));
add(new TextArea<>("requirement_en", LambdaModel.of(
model,
EditingGradingTemplate.Criteria.Point::getRequirementEn,
EditingGradingTemplate.Criteria.Point::setRequirementEn)));
add(new TextArea<>("requirement_sv", LambdaModel.of(
model,
EditingGradingTemplate.Criteria.Point::getRequirementSv,
EditingGradingTemplate.Criteria.Point::setRequirementSv)));
add(new AjaxLink<>("remove") {
@Override
public void onClick(AjaxRequestTarget target) {
EditingGradingTemplate.Criteria criteria = CriteriaEditingPanel.this.getModelObject();
criteria.getPoints().remove(model.getObject());
target.add(CriteriaEditingPanel.this);
}
});
}
}
}
}