3494-UI-improvements-grading-templates #21
@ -5,8 +5,11 @@
|
|||||||
<div wicket:id="feedback"></div>
|
<div wicket:id="feedback"></div>
|
||||||
<form wicket:id="form">
|
<form wicket:id="form">
|
||||||
<div wicket:id="editing" class="mb-3"></div>
|
<div wicket:id="editing" class="mb-3"></div>
|
||||||
<div class="position-sticky bottom-0 bg-white p-3 border line-length-limit">
|
<div class="position-sticky bottom-0 bg-white p-3 border line-length-limit hstack">
|
||||||
<button type="submit" class="btn btn-primary">Save</button>
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
|
<span wicket:id="unsaved_changes_alert" class="text-danger flex-grow-1 text-center" role="alert">
|
||||||
|
<wicket:message key="unsaved_changes"/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</wicket:extend>
|
</wicket:extend>
|
||||||
|
@ -2,9 +2,10 @@ package se.su.dsv.scipro.admin.pages.grading;
|
|||||||
|
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import org.apache.wicket.RestartResponseException;
|
import org.apache.wicket.RestartResponseException;
|
||||||
|
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||||
|
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||||
import org.apache.wicket.markup.html.form.Form;
|
import org.apache.wicket.markup.html.form.Form;
|
||||||
import org.apache.wicket.markup.html.panel.FeedbackPanel;
|
import org.apache.wicket.markup.html.panel.FeedbackPanel;
|
||||||
import org.apache.wicket.model.Model;
|
|
||||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||||
import se.su.dsv.scipro.admin.pages.AbstractAdminProjectPage;
|
import se.su.dsv.scipro.admin.pages.AbstractAdminProjectPage;
|
||||||
import se.su.dsv.scipro.grading.GradingReportTemplateService;
|
import se.su.dsv.scipro.grading.GradingReportTemplateService;
|
||||||
@ -12,9 +13,9 @@ import se.su.dsv.scipro.grading.GradingReportTemplateUpdate;
|
|||||||
import se.su.dsv.scipro.grading.LocalizedString;
|
import se.su.dsv.scipro.grading.LocalizedString;
|
||||||
import se.su.dsv.scipro.report.DuplicateDateException;
|
import se.su.dsv.scipro.report.DuplicateDateException;
|
||||||
import se.su.dsv.scipro.report.GradingReportTemplate;
|
import se.su.dsv.scipro.report.GradingReportTemplate;
|
||||||
import se.su.dsv.scipro.report.ValidDateMustBeInTheFutureException;
|
|
||||||
import se.su.dsv.scipro.report.NoSuchTemplateException;
|
import se.su.dsv.scipro.report.NoSuchTemplateException;
|
||||||
import se.su.dsv.scipro.report.TemplateLockedException;
|
import se.su.dsv.scipro.report.TemplateLockedException;
|
||||||
|
import se.su.dsv.scipro.report.ValidDateMustBeInTheFutureException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -25,6 +26,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
|
|||||||
0,
|
0,
|
||||||
new LocalizedString("", ""));
|
new LocalizedString("", ""));
|
||||||
|
|
||||||
|
private final WebMarkupContainer unsavedChangesAlert;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
GradingReportTemplateService gradingReportTemplateService;
|
GradingReportTemplateService gradingReportTemplateService;
|
||||||
|
|
||||||
@ -47,7 +50,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
|
|||||||
GradingReportTemplateUpdate update = toUpdate(
|
GradingReportTemplateUpdate update = toUpdate(
|
||||||
editingGradingTemplate);
|
editingGradingTemplate);
|
||||||
|
|
||||||
gradingReportTemplateService.update(id, update);
|
GradingReportTemplate newTemplate = gradingReportTemplateService.update(id, update);
|
||||||
|
editingGradingTemplate = new EditingGradingTemplate(newTemplate);
|
||||||
success(getString("template_updated"));
|
success(getString("template_updated"));
|
||||||
} catch (ValidDateMustBeInTheFutureException e) {
|
} catch (ValidDateMustBeInTheFutureException e) {
|
||||||
error(getString("valid_from_must_be_in_the_future", () -> e));
|
error(getString("valid_from_must_be_in_the_future", () -> e));
|
||||||
@ -61,7 +65,23 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
form.add(new EditingGradingTemplateComponentPanel("editing", Model.of(editingGradingTemplate)));
|
unsavedChangesAlert = new WebMarkupContainer("unsaved_changes_alert") {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(editingGradingTemplate.hasChanges());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
form.add(unsavedChangesAlert);
|
||||||
|
unsavedChangesAlert.setOutputMarkupPlaceholderTag(true);
|
||||||
|
|
||||||
|
form.add(new EditingGradingTemplateComponentPanel("editing", () -> editingGradingTemplate) {
|
||||||
|
@Override
|
||||||
|
protected void onTemplateChanged(AjaxRequestTarget target) {
|
||||||
|
super.onTemplateChanged(target);
|
||||||
|
target.add(unsavedChangesAlert);
|
||||||
|
}
|
||||||
|
});
|
||||||
add(form);
|
add(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,8 +8,10 @@ import java.io.Serializable;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
class EditingGradingTemplate implements Serializable {
|
class EditingGradingTemplate implements Serializable {
|
||||||
|
private EditingGradingTemplate original;
|
||||||
private String note;
|
private String note;
|
||||||
private LocalDate validFrom;
|
private LocalDate validFrom;
|
||||||
private List<Criteria> criteria;
|
private List<Criteria> criteria;
|
||||||
@ -21,6 +23,16 @@ class EditingGradingTemplate implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EditingGradingTemplate(GradingReportTemplate template) {
|
EditingGradingTemplate(GradingReportTemplate template) {
|
||||||
|
this(template, null);
|
||||||
|
this.original = new EditingGradingTemplate(template, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor for creating a new instance of EditingGradingTemplate
|
||||||
|
* to be able to track changes made.
|
||||||
|
* @param doNotCreateOriginal Only exists to differentiate the signature from the public constructor
|
||||||
|
*/
|
||||||
|
private EditingGradingTemplate(GradingReportTemplate template, @SuppressWarnings("unused") Void doNotCreateOriginal) {
|
||||||
this.note = template.getNote();
|
this.note = template.getNote();
|
||||||
this.validFrom = template.getValidFrom();
|
this.validFrom = template.getValidFrom();
|
||||||
this.gradeLimits = new GradeLimits(template);
|
this.gradeLimits = new GradeLimits(template);
|
||||||
@ -61,10 +73,28 @@ class EditingGradingTemplate implements Serializable {
|
|||||||
.sum();
|
.sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean hasChanges() {
|
||||||
|
return !Objects.equals(original, this);
|
||||||
|
}
|
||||||
|
|
||||||
public void addCriteria() {
|
public void addCriteria() {
|
||||||
this.criteria.add(new Criteria());
|
this.criteria.add(new Criteria());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof EditingGradingTemplate that
|
||||||
|
&& Objects.equals(note, that.note)
|
||||||
|
&& Objects.equals(validFrom, that.validFrom)
|
||||||
|
&& Objects.equals(criteria, that.criteria)
|
||||||
|
&& Objects.equals(gradeLimits, that.gradeLimits);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(note, validFrom, criteria, gradeLimits);
|
||||||
|
}
|
||||||
|
|
||||||
class Criteria implements Serializable {
|
class Criteria implements Serializable {
|
||||||
enum Flag {
|
enum Flag {
|
||||||
OPPOSITION, REFLECTION
|
OPPOSITION, REFLECTION
|
||||||
@ -150,6 +180,22 @@ class EditingGradingTemplate implements Serializable {
|
|||||||
this.pointsRequiredToPass = pointsRequiredToPass;
|
this.pointsRequiredToPass = pointsRequiredToPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof Criteria criterion
|
||||||
|
&& pointsRequiredToPass == criterion.pointsRequiredToPass
|
||||||
|
&& Objects.equals(titleSv, criterion.titleSv)
|
||||||
|
&& Objects.equals(titleEn, criterion.titleEn)
|
||||||
|
&& Objects.equals(points, criterion.points)
|
||||||
|
&& flag == criterion.flag
|
||||||
|
&& type == criterion.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(titleSv, titleEn, points, flag, type, pointsRequiredToPass);
|
||||||
|
}
|
||||||
|
|
||||||
class Point implements Serializable {
|
class Point implements Serializable {
|
||||||
private String requirementEn;
|
private String requirementEn;
|
||||||
private String requirementSv;
|
private String requirementSv;
|
||||||
@ -179,6 +225,18 @@ class EditingGradingTemplate implements Serializable {
|
|||||||
public void setRequirementSv(String requirementSv) {
|
public void setRequirementSv(String requirementSv) {
|
||||||
this.requirementSv = requirementSv;
|
this.requirementSv = requirementSv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof Point point
|
||||||
|
&& Objects.equals(requirementEn, point.requirementEn)
|
||||||
|
&& Objects.equals(requirementSv, point.requirementSv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(requirementEn, requirementSv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
public void onClick(AjaxRequestTarget target) {
|
public void onClick(AjaxRequestTarget target) {
|
||||||
editingGradingTemplateModel.getObject().getCriteria().remove(item.getModelObject());
|
editingGradingTemplateModel.getObject().getCriteria().remove(item.getModelObject());
|
||||||
target.add(EditingGradingTemplateComponentPanel.this);
|
target.add(EditingGradingTemplateComponentPanel.this);
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
item.add(new CriteriaEditingPanel("criteria", item.getModel()));
|
item.add(new CriteriaEditingPanel("criteria", item.getModel()));
|
||||||
@ -75,6 +76,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
public void onClick(AjaxRequestTarget target) {
|
public void onClick(AjaxRequestTarget target) {
|
||||||
editingGradingTemplateModel.getObject().addCriteria();
|
editingGradingTemplateModel.getObject().addCriteria();
|
||||||
target.add(EditingGradingTemplateComponentPanel.this);
|
target.add(EditingGradingTemplateComponentPanel.this);
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -117,6 +119,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
EditingGradingTemplate.Criteria.Type objectSelected)
|
EditingGradingTemplate.Criteria.Type objectSelected)
|
||||||
{
|
{
|
||||||
// auto save
|
// auto save
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typeChoice.setRequired(true);
|
typeChoice.setRequired(true);
|
||||||
@ -149,6 +152,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
EditingGradingTemplate.Criteria.Flag objectSelected)
|
EditingGradingTemplate.Criteria.Flag objectSelected)
|
||||||
{
|
{
|
||||||
// auto save
|
// auto save
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
flagChoice.setNullValid(true);
|
flagChoice.setNullValid(true);
|
||||||
@ -176,6 +180,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
EditingGradingTemplate.Criteria.Point newPoint = criteria.new Point();
|
EditingGradingTemplate.Criteria.Point newPoint = criteria.new Point();
|
||||||
criteria.getPoints().add(newPoint);
|
criteria.getPoints().add(newPoint);
|
||||||
target.add(CriteriaEditingPanel.this);
|
target.add(CriteriaEditingPanel.this);
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -210,13 +215,14 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
EditingGradingTemplate.Criteria criteria = CriteriaEditingPanel.this.getModelObject();
|
EditingGradingTemplate.Criteria criteria = CriteriaEditingPanel.this.getModelObject();
|
||||||
criteria.getPoints().remove(model.getObject());
|
criteria.getPoints().remove(model.getObject());
|
||||||
target.add(CriteriaEditingPanel.this);
|
target.add(CriteriaEditingPanel.this);
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GradeLimitsPanel extends GenericWebMarkupContainer<GradeLimits> {
|
private class GradeLimitsPanel extends GenericWebMarkupContainer<GradeLimits> {
|
||||||
public GradeLimitsPanel(String id, IModel<GradeLimits> model) {
|
public GradeLimitsPanel(String id, IModel<GradeLimits> model) {
|
||||||
super(id, model);
|
super(id, model);
|
||||||
|
|
||||||
@ -248,6 +254,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
|
GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
|
||||||
gradeLimits.addNewLimit();
|
gradeLimits.addNewLimit();
|
||||||
target.add(GradeLimitsPanel.this);
|
target.add(GradeLimitsPanel.this);
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -278,13 +285,14 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
|
GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
|
||||||
gradeLimits.getGradeLimits().remove(model.getObject());
|
gradeLimits.getGradeLimits().remove(model.getObject());
|
||||||
target.add(GradeLimitsPanel.this);
|
target.add(GradeLimitsPanel.this);
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class AutoSave extends AjaxFormComponentUpdatingBehavior {
|
private class AutoSave extends AjaxFormComponentUpdatingBehavior {
|
||||||
public AutoSave() {
|
public AutoSave() {
|
||||||
super("input");
|
super("input");
|
||||||
}
|
}
|
||||||
@ -292,6 +300,11 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
|
|||||||
@Override
|
@Override
|
||||||
protected void onUpdate(AjaxRequestTarget target) {
|
protected void onUpdate(AjaxRequestTarget target) {
|
||||||
// just trigger the ajax call is enough to update the model object
|
// just trigger the ajax call is enough to update the model object
|
||||||
|
onTemplateChanged(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void onTemplateChanged(AjaxRequestTarget target) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import se.su.dsv.scipro.report.GradingReportTemplate;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
class GradeLimits implements Serializable {
|
class GradeLimits implements Serializable {
|
||||||
private List<GradeLimit> gradeLimits;
|
private List<GradeLimit> gradeLimits;
|
||||||
@ -41,6 +42,19 @@ class GradeLimits implements Serializable {
|
|||||||
return gradeLimits;
|
return gradeLimits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
|
||||||
|
return o instanceof GradeLimits that
|
||||||
|
&& Objects.equals(gradeLimits, that.gradeLimits)
|
||||||
|
&& Objects.equals(failingGrade, that.failingGrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(gradeLimits, failingGrade);
|
||||||
|
}
|
||||||
|
|
||||||
class GradeLimit implements Serializable {
|
class GradeLimit implements Serializable {
|
||||||
private String grade;
|
private String grade;
|
||||||
private int lowerLimit;
|
private int lowerLimit;
|
||||||
@ -60,5 +74,17 @@ class GradeLimits implements Serializable {
|
|||||||
public void setLowerLimit(int lowerLimit) {
|
public void setLowerLimit(int lowerLimit) {
|
||||||
this.lowerLimit = lowerLimit;
|
this.lowerLimit = lowerLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof GradeLimit that
|
||||||
|
&& lowerLimit == that.lowerLimit
|
||||||
|
&& Objects.equals(grade, that.grade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(grade, lowerLimit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,3 +3,4 @@ valid_from_must_be_in_the_future=The templates valid date must be in the future.
|
|||||||
another_template_exists_for_the_given_date_date=There is already another ${projectType.name} template that becomes valid at ${validFrom}, please pick another date.
|
another_template_exists_for_the_given_date_date=There is already another ${projectType.name} template that becomes valid at ${validFrom}, please pick another date.
|
||||||
template_is_locked=You can not edit templates that have become current. The template you are trying to edit became current at ${validFrom}.
|
template_is_locked=You can not edit templates that have become current. The template you are trying to edit became current at ${validFrom}.
|
||||||
template_created=New template for ${name} created.
|
template_created=New template for ${name} created.
|
||||||
|
unsaved_changes=The grading template has been changed, unsaved changes will be lost if you do not save.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user