From 4b113715d64b19427226a854ac878a1452a96bca Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Wed, 13 Nov 2024 14:30:22 +0100
Subject: [PATCH 1/8] User alert on unsaved changes in grading template

Grading template did not have any way to alert the user that changes had been made when editing a template.

Added a way to detect and alert the user when changes have been made on the grading template they are editing. If the user removes his changes, so the template is in the same state as it was when the user started editing the template the alert will disappear.
---
 .../grading/AdminGradingTemplateEditPage.html |  5 +-
 .../grading/AdminGradingTemplateEditPage.java | 28 +++++++--
 .../pages/grading/EditingGradingTemplate.java | 58 +++++++++++++++++++
 .../EditingGradingTemplateComponentPanel.java | 17 +++++-
 .../admin/pages/grading/GradeLimits.java      | 26 +++++++++
 .../grading/wicket-package.utf8.properties    |  1 +
 6 files changed, 128 insertions(+), 7 deletions(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
index 9e28766880..626408b739 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
@@ -5,8 +5,11 @@
     <div wicket:id="feedback"></div>
     <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">
+        <div class="position-sticky bottom-0 bg-white p-3 border line-length-limit hstack">
             <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>
     </form>
 </wicket:extend>
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
index da4a0b42a7..c255d1be51 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
@@ -2,9 +2,10 @@ package se.su.dsv.scipro.admin.pages.grading;
 
 import jakarta.inject.Inject;
 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.panel.FeedbackPanel;
-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;
@@ -12,9 +13,9 @@ import se.su.dsv.scipro.grading.GradingReportTemplateUpdate;
 import se.su.dsv.scipro.grading.LocalizedString;
 import se.su.dsv.scipro.report.DuplicateDateException;
 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.TemplateLockedException;
+import se.su.dsv.scipro.report.ValidDateMustBeInTheFutureException;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -25,6 +26,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
             0,
             new LocalizedString("", ""));
 
+    private final WebMarkupContainer unsavedChangesAlert;
+
     @Inject
     GradingReportTemplateService gradingReportTemplateService;
 
@@ -47,7 +50,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
                     GradingReportTemplateUpdate update = toUpdate(
                             editingGradingTemplate);
 
-                    gradingReportTemplateService.update(id, update);
+                    GradingReportTemplate newTemplate = gradingReportTemplateService.update(id, update);
+                    editingGradingTemplate = new EditingGradingTemplate(newTemplate);
                     success(getString("template_updated"));
                 } catch (ValidDateMustBeInTheFutureException 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);
     }
 
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
index 7e4e935ad5..04f6402920 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
@@ -8,8 +8,10 @@ import java.io.Serializable;
 import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 class EditingGradingTemplate implements Serializable {
+    private EditingGradingTemplate original;
     private String note;
     private LocalDate validFrom;
     private List<Criteria> criteria;
@@ -21,6 +23,16 @@ class EditingGradingTemplate implements Serializable {
     }
 
     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.validFrom = template.getValidFrom();
         this.gradeLimits = new GradeLimits(template);
@@ -61,10 +73,28 @@ class EditingGradingTemplate implements Serializable {
                 .sum();
     }
 
+    public Boolean hasChanges() {
+        return !Objects.equals(original, this);
+    }
+
     public void addCriteria() {
         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 {
         enum Flag {
             OPPOSITION, REFLECTION
@@ -150,6 +180,22 @@ class EditingGradingTemplate implements Serializable {
             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 {
             private String requirementEn;
             private String requirementSv;
@@ -179,6 +225,18 @@ class EditingGradingTemplate implements Serializable {
             public void setRequirementSv(String 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);
+            }
         }
     }
 }
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
index fb6b0af006..5980e6834c 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
@@ -64,6 +64,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                     public void onClick(AjaxRequestTarget target) {
                         editingGradingTemplateModel.getObject().getCriteria().remove(item.getModelObject());
                         target.add(EditingGradingTemplateComponentPanel.this);
+                        onTemplateChanged(target);
                     }
                 });
                 item.add(new CriteriaEditingPanel("criteria", item.getModel()));
@@ -75,6 +76,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
             public void onClick(AjaxRequestTarget target) {
                 editingGradingTemplateModel.getObject().addCriteria();
                 target.add(EditingGradingTemplateComponentPanel.this);
+                onTemplateChanged(target);
             }
         });
     }
@@ -117,6 +119,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate.Criteria.Type objectSelected)
                 {
                     // auto save
+                    onTemplateChanged(target);
                 }
             };
             typeChoice.setRequired(true);
@@ -149,6 +152,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate.Criteria.Flag objectSelected)
                 {
                     // auto save
+                    onTemplateChanged(target);
                 }
             };
             flagChoice.setNullValid(true);
@@ -176,6 +180,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                     EditingGradingTemplate.Criteria.Point newPoint = criteria.new Point();
                     criteria.getPoints().add(newPoint);
                     target.add(CriteriaEditingPanel.this);
+                    onTemplateChanged(target);
                 }
             });
         }
@@ -210,13 +215,14 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate.Criteria criteria = CriteriaEditingPanel.this.getModelObject();
                         criteria.getPoints().remove(model.getObject());
                         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) {
             super(id, model);
 
@@ -248,6 +254,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                     GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
                     gradeLimits.addNewLimit();
                     target.add(GradeLimitsPanel.this);
+                    onTemplateChanged(target);
                 }
             });
         }
@@ -278,13 +285,14 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         GradeLimits gradeLimits = GradeLimitsPanel.this.getModelObject();
                         gradeLimits.getGradeLimits().remove(model.getObject());
                         target.add(GradeLimitsPanel.this);
+                        onTemplateChanged(target);
                     }
                 });
             }
         }
     }
 
-    private static class AutoSave extends AjaxFormComponentUpdatingBehavior {
+    private class AutoSave extends AjaxFormComponentUpdatingBehavior {
         public AutoSave() {
             super("input");
         }
@@ -292,6 +300,11 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
         @Override
         protected void onUpdate(AjaxRequestTarget target) {
             // just trigger the ajax call is enough to update the model object
+            onTemplateChanged(target);
         }
     }
+
+    protected void onTemplateChanged(AjaxRequestTarget target) {
+        // do nothing
+    }
 }
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java
index 29bd5877d2..dae5812f7a 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java
@@ -5,6 +5,7 @@ import se.su.dsv.scipro.report.GradingReportTemplate;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 class GradeLimits implements Serializable {
     private List<GradeLimit> gradeLimits;
@@ -41,6 +42,19 @@ class GradeLimits implements Serializable {
         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 {
         private String grade;
         private int lowerLimit;
@@ -60,5 +74,17 @@ class GradeLimits implements Serializable {
         public void setLowerLimit(int 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);
+        }
     }
 }
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
index f761f20e4e..25726d2d64 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
@@ -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.
 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.
+unsaved_changes=The grading template has been changed, unsaved changes will be lost if you do not save.

From ea54958e71bc50134df39dcefdf5d50f87a8a7cd Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Tue, 19 Nov 2024 07:10:18 +0100
Subject: [PATCH 2/8] Added project type title when viewing or editing

When you chose to edit a template you could not see what type the template is.
For example if it was a bachelor or master type template.

Now when you choose to edit a grading template the type will be shown as a heading,
so you can more easily see what type of template you are currently editing.
The heading will read:
`You are editing a <type> grading template.`
The <type> will display the correct type of the grading template you are editing.

Open to change of what exactly the heading will display if anyone has a better idea for it.
---
 .../admin/pages/grading/EditingGradingTemplate.java      | 9 ++++++++-
 .../grading/EditingGradingTemplateComponentPanel.html    | 6 ++++++
 .../grading/EditingGradingTemplateComponentPanel.java    | 1 +
 .../EditingGradingTemplateComponentPanel.utf8.properties | 1 +
 4 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
index 04f6402920..1202d83137 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
@@ -16,6 +16,7 @@ class EditingGradingTemplate implements Serializable {
     private LocalDate validFrom;
     private List<Criteria> criteria;
     private GradeLimits gradeLimits;
+    private String projectType;
 
     public EditingGradingTemplate() {
         this.gradeLimits = new GradeLimits();
@@ -41,6 +42,7 @@ class EditingGradingTemplate implements Serializable {
             Criteria editingCriteria = new Criteria(criteria);
             this.criteria.add(editingCriteria);
         }
+        this.projectType = template.getProjectType().getName();
     }
 
     public String getNote() {
@@ -81,13 +83,18 @@ class EditingGradingTemplate implements Serializable {
         this.criteria.add(new Criteria());
     }
 
+    public String getProjectType() {
+        return projectType;
+    }
+
     @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);
+                && Objects.equals(gradeLimits, that.gradeLimits)
+                && Objects.equals(projectType, that.projectType);
     }
 
     @Override
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html
index 80952a8f02..f4ea4e67dc 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html
@@ -9,6 +9,12 @@
 </head>
 <body>
 <wicket:panel>
+    <div class="mb-3 lead">
+        <wicket:message key="project_type_name_editing">
+            <span wicket:id="project_type_name"></span>
+        </wicket:message>
+    </div>
+
     <div class="mb-3 line-length-limit">
         <label class="form-label" wicket:for="valid_from">
             Valid from
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
index 5980e6834c..6c28a46bde 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
@@ -30,6 +30,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
 
         setOutputMarkupId(true);
 
+        add(new Label("project_type_name", editingGradingTemplateModel.map(EditingGradingTemplate::getProjectType)));
         TextField<LocalDate> validFromField = new RequiredTextField<>("valid_from",
                 LambdaModel.of(editingGradingTemplateModel,
                         EditingGradingTemplate::getValidFrom,
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties
index 6315499c53..db27aba41e 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties
@@ -11,3 +11,4 @@ Type.INDIVIDUAL=Individually for each author
 minimum.Required=You must set the minimum number of points for each grade
 grade.Required=You must set the letter for each grade
 flag.nullValid=None
+project_type_name_editing=You are editing a ${project_type_name} grading template. 

From c538f95950c8e4f9e2f0bff5e955e4b1d315104d Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Tue, 19 Nov 2024 07:47:45 +0100
Subject: [PATCH 3/8] Changed default value of `Points required to pass`

When adding a new criteria to a template the default value of `Points required to pass` was `0` (zero).
Now when you add a new criterion to a template the `Points required to pass` default to `1` (one).
---
 .../scipro/admin/pages/grading/EditingGradingTemplate.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
index 1202d83137..b6bc971b88 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
@@ -116,14 +116,14 @@ class EditingGradingTemplate implements Serializable {
         private List<Point> points = new ArrayList<>();
         private Flag flag;
         private Type type = Type.PROJECT;
-        private int pointsRequiredToPass;
+        private int pointsRequiredToPass = 1;
 
         Criteria(GradingCriterionTemplate criteria) {
             this.titleSv = criteria.getTitle();
             this.titleEn = criteria.getTitleEn();
             this.pointsRequiredToPass = criteria.getPointsRequiredToPass();
             for (var point : criteria.getGradingCriterionPointTemplates()) {
-                if (point.getPoint() == 0) continue;
+                if (point.getPoint() == 1) continue;
                 Point editingPoint = new Point(point);
                 this.points.add(editingPoint);
             }

From 00994e6cf7fe8f709046e4cf930665e3634c76e1 Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Tue, 19 Nov 2024 10:06:43 +0100
Subject: [PATCH 4/8] Fixed behavior of valid from date when creating new
 template

Previously if you created a new grading template chose a date for `Valid from` field and then added a criterion.
The valid from date would reset to null. This would create a validation error on save.
This creates unnecessary confusion for the user.

Now when you have chosen a date and then choose to add a criterion to the template the date does not reset.

The reason for this was that the AutoSave() added to the field was using the wrong event to trigger the setValidFrom().
Since we use bootstraps date picker we have to trigger on "changeDate" event.
---
 .../pages/grading/EditingGradingTemplateComponentPanel.java | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
index 6c28a46bde..47afb417b1 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
@@ -37,7 +37,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                         EditingGradingTemplate::setValidFrom),
                 LocalDate.class);
         validFromField.add(new BootstrapDatePicker());
-        validFromField.add(new AutoSave());
+        validFromField.add(new AutoSave("changeDate"));
         add(validFromField);
 
         add(new TextArea<>("note", LambdaModel.of(
@@ -298,6 +298,10 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
             super("input");
         }
 
+        public AutoSave(String event) {
+            super(event);
+        }
+
         @Override
         protected void onUpdate(AjaxRequestTarget target) {
             // just trigger the ajax call is enough to update the model object

From f79f66c182740c91b9abb71b4068925df8f04bfb Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Tue, 19 Nov 2024 10:13:14 +0100
Subject: [PATCH 5/8] Fix adding new criteria should add point requirements

When you added new criteria you only got to set the criterion title, type, flag and point but you had to manually add the requirements for the first criterion.

Now when you add a new criterion the new criterion will by default add the requirement for the points.

reverted a previous change in the for loop the correct condition was to check against 0, I accidently turned that to 1 in a previous commit. Also added a comment to try and explain what that condition checks for.
---
 .../scipro/admin/pages/grading/EditingGradingTemplate.java | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
index b6bc971b88..a56af9d4eb 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java
@@ -80,7 +80,10 @@ class EditingGradingTemplate implements Serializable {
     }
 
     public void addCriteria() {
-        this.criteria.add(new Criteria());
+        Criteria newCriteria = new Criteria();
+        newCriteria.points.add(newCriteria.new Point());
+        this.criteria.add(newCriteria);
+
     }
 
     public String getProjectType() {
@@ -123,7 +126,7 @@ class EditingGradingTemplate implements Serializable {
             this.titleEn = criteria.getTitleEn();
             this.pointsRequiredToPass = criteria.getPointsRequiredToPass();
             for (var point : criteria.getGradingCriterionPointTemplates()) {
-                if (point.getPoint() == 1) continue;
+                if (point.getPoint() == 0) continue; // This is to hide zero point requirements that never have any text
                 Point editingPoint = new Point(point);
                 this.points.add(editingPoint);
             }

From 433ef4ed871a26ceedd906fec52e3436d55488b6 Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Wed, 20 Nov 2024 10:34:40 +0100
Subject: [PATCH 6/8] Create button should not be visible until user has
 selected project type

Previously a user could click on the create button before they had chosen a
grading template project type from the Project type dropdown.
This would result in a runtime exception, and possibly in an unhappy user.

To protect the user from "jumping the gun", the Create button will only become visible
after the user has selected a Project type from the dropdown menu.
---
 .../grading/AdminGradingTemplateCreationPage.html      |  2 +-
 .../grading/AdminGradingTemplateCreationPage.java      | 10 +++++++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html
index 8fd44e66ab..d300cde333 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html
@@ -17,7 +17,7 @@
 
         <div wicket:id="grading_template_component_panel"></div>
 
-        <div class="position-sticky bottom-0 bg-white p-3 border line-length-limit">
+        <div wicket:id="button_container" class="position-sticky bottom-0 bg-white p-3 border line-length-limit">
             <button type="submit" class="btn btn-primary">Create</button>
         </div>
     </form>
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java
index c14d4925db..0338617189 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java
@@ -3,6 +3,7 @@ package se.su.dsv.scipro.admin.pages.grading;
 import jakarta.inject.Inject;
 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.LambdaChoiceRenderer;
 import org.apache.wicket.markup.html.panel.FeedbackPanel;
@@ -29,6 +30,7 @@ public class AdminGradingTemplateCreationPage extends AbstractAdminProjectPage i
 
     private final IModel<ProjectType> projectTypeModel;
     private EditingGradingTemplate editingGradingTemplateModel;
+    private final WebMarkupContainer buttonContainer;
 
     public AdminGradingTemplateCreationPage() {
         projectTypeModel = new DetachableServiceModel<>(projectTypeService);
@@ -57,6 +59,11 @@ public class AdminGradingTemplateCreationPage extends AbstractAdminProjectPage i
         form.setOutputMarkupId(true);
         add(form);
 
+        buttonContainer = new WebMarkupContainer("button_container");
+        buttonContainer.setOutputMarkupPlaceholderTag(true);
+        buttonContainer.setVisible(false);
+        form.add(buttonContainer);
+
         form.add(new AjaxDropDownChoice<>(
                 "project_type",
                 projectTypeModel,
@@ -64,7 +71,8 @@ public class AdminGradingTemplateCreationPage extends AbstractAdminProjectPage i
                 new LambdaChoiceRenderer<>(ProjectType::getName, ProjectType::getId)) {
             @Override
             public void onNewSelection(AjaxRequestTarget target, ProjectType objectSelected) {
-                target.add(form);
+                buttonContainer.setVisible(true);
+                target.add(form, buttonContainer);
             }
         });
 

From 3c5934863600651af81f0c21cdc94e62ac379a9a Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Wed, 20 Nov 2024 10:37:42 +0100
Subject: [PATCH 7/8] Max available points should be updated when adding new
 points to criterion

Previously max available points where only updated when you added a new criterion.

It is beneficial that the user can see the max available points as they have completed editing the
template without having to click on the create button or add a new criterion.
---
 .../grading/EditingGradingTemplateComponentPanel.java    | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
index 47afb417b1..dfe427faf7 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
@@ -22,6 +22,9 @@ import java.time.LocalDate;
 import java.util.List;
 
 class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTemplate> {
+
+    private final Label maxPointsAvailable;
+
     EditingGradingTemplateComponentPanel(
             String id,
             IModel<EditingGradingTemplate> editingGradingTemplateModel)
@@ -51,7 +54,10 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
 
         add(new GradeLimitsPanel("grade_limits", editingGradingTemplateModel.map(EditingGradingTemplate::getGradeLimits)));
 
-        add(new Label("max_points_available", editingGradingTemplateModel.map(EditingGradingTemplate::getMaxPointsAvailable)));
+        maxPointsAvailable = new Label("max_points_available", editingGradingTemplateModel.map(EditingGradingTemplate::getMaxPointsAvailable));
+        maxPointsAvailable.setOutputMarkupId(true);
+        add(maxPointsAvailable);
+
 
         add(new ListView<>("criteria", editingGradingTemplateModel.map(EditingGradingTemplate::getCriteria)) {
             {
@@ -181,6 +187,7 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
                     EditingGradingTemplate.Criteria.Point newPoint = criteria.new Point();
                     criteria.getPoints().add(newPoint);
                     target.add(CriteriaEditingPanel.this);
+                    target.add(maxPointsAvailable);
                     onTemplateChanged(target);
                 }
             });

From 774f1e9d7a5e3c27794a4fe945bc4e128117a71b Mon Sep 17 00:00:00 2001
From: Nico Athanassiadis <nico@dsv.su.se>
Date: Wed, 20 Nov 2024 11:07:07 +0100
Subject: [PATCH 8/8] Fix for project title commit
 90604b8ef1f82343e913319c54802dbd09278027

The project title was added to the wrong panel which caused side effect of showing a title when
creating a new template. Moved the previous code it is only shown when editing a template.

Also changed it to read the title from the database using the LoadableDetachableModel pattern.

Now the project title should only be shown when editing an existing template.
---
 .../admin/pages/grading/AdminGradingTemplateEditPage.html   | 5 +++++
 .../admin/pages/grading/AdminGradingTemplateEditPage.java   | 6 ++++++
 .../pages/grading/EditingGradingTemplateComponentPanel.html | 6 ------
 .../pages/grading/EditingGradingTemplateComponentPanel.java | 1 -
 .../EditingGradingTemplateComponentPanel.utf8.properties    | 1 -
 .../admin/pages/grading/wicket-package.utf8.properties      | 1 +
 6 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
index 626408b739..cd7a505d25 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.html
@@ -3,6 +3,11 @@
 <body>
 <wicket:extend>
     <div wicket:id="feedback"></div>
+    <div class="mb-3 lead">
+        <wicket:message key="project_type_name_editing">
+            <span wicket:id="project_type_name"></span>
+        </wicket:message>
+    </div>
     <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 hstack">
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
index c255d1be51..d2ad546e0f 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java
@@ -4,8 +4,11 @@ import jakarta.inject.Inject;
 import org.apache.wicket.RestartResponseException;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import se.su.dsv.scipro.admin.pages.AbstractAdminProjectPage;
 import se.su.dsv.scipro.grading.GradingReportTemplateService;
@@ -16,6 +19,7 @@ import se.su.dsv.scipro.report.GradingReportTemplate;
 import se.su.dsv.scipro.report.NoSuchTemplateException;
 import se.su.dsv.scipro.report.TemplateLockedException;
 import se.su.dsv.scipro.report.ValidDateMustBeInTheFutureException;
+import se.su.dsv.scipro.system.ProjectType;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -41,6 +45,8 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple
         editingGradingTemplate = new EditingGradingTemplate(template);
 
         add(new FeedbackPanel("feedback"));
+        IModel<GradingReportTemplate> model = LoadableDetachableModel.of(() -> gradingReportTemplateService.getTemplate(id));
+        add(new Label("project_type_name", model.map(GradingReportTemplate::getProjectType).map(ProjectType::getName)));
 
         Form<EditingGradingTemplate> form = new Form<>("form") {
             @Override
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html
index f4ea4e67dc..80952a8f02 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.html
@@ -9,12 +9,6 @@
 </head>
 <body>
 <wicket:panel>
-    <div class="mb-3 lead">
-        <wicket:message key="project_type_name_editing">
-            <span wicket:id="project_type_name"></span>
-        </wicket:message>
-    </div>
-
     <div class="mb-3 line-length-limit">
         <label class="form-label" wicket:for="valid_from">
             Valid from
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
index dfe427faf7..6a59cfa2f5 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.java
@@ -33,7 +33,6 @@ class EditingGradingTemplateComponentPanel extends GenericPanel<EditingGradingTe
 
         setOutputMarkupId(true);
 
-        add(new Label("project_type_name", editingGradingTemplateModel.map(EditingGradingTemplate::getProjectType)));
         TextField<LocalDate> validFromField = new RequiredTextField<>("valid_from",
                 LambdaModel.of(editingGradingTemplateModel,
                         EditingGradingTemplate::getValidFrom,
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties
index db27aba41e..6315499c53 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplateComponentPanel.utf8.properties
@@ -11,4 +11,3 @@ Type.INDIVIDUAL=Individually for each author
 minimum.Required=You must set the minimum number of points for each grade
 grade.Required=You must set the letter for each grade
 flag.nullValid=None
-project_type_name_editing=You are editing a ${project_type_name} grading template. 
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
index 25726d2d64..defb43b968 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties
@@ -4,3 +4,4 @@ another_template_exists_for_the_given_date_date=There is already another ${proje
 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.
 unsaved_changes=The grading template has been changed, unsaved changes will be lost if you do not save.
+project_type_name_editing=You are editing a ${project_type_name} grading template.