From 949de4a26041cdfca9e0b7dc9ec1485a2a5d4a5c Mon Sep 17 00:00:00 2001 From: ansv7779 <andreass@dsv.su.se> Date: Wed, 10 Jul 2024 13:43:27 +0200 Subject: [PATCH] Allow supervisors to write a note associated with their projects (#8) There is a need among supervisors to maintain some work notes for each project. Where they are in the process, what students need to do, and other such things. This PR gives the supervisors the ability to write a note for each project on their overview page. Card 3399 Reviewed-on: https://gitea.dsv.su.se/DSV/scipro/pulls/8 Reviewed-by: niat8586 <nico@dsv.su.se> --- core/src/main/java/modules/CoreModule.java | 2 + .../se/su/dsv/scipro/project/Project.java | 15 ++ .../scipro/project/ProjectNoteService.java | 9 ++ .../se/su/dsv/scipro/project/ProjectRepo.java | 4 + .../dsv/scipro/project/ProjectRepoImpl.java | 13 ++ .../scipro/project/ProjectServiceImpl.java | 12 +- .../SupervisorProjectNoteDisplay.java | 5 + .../settings/dataobjects/UserProfile.java | 13 ++ .../V388__user_notes_for_projects.sql | 11 ++ .../dsv/scipro/components/MaxLengthLabel.java | 37 +++++ .../scipro/components/ModalWindowPlus.java | 11 ++ ...ctNoteColumn$ViewAndEditNoteCellPanel.html | 11 ++ ...n$ViewAndEditNoteCellPanel.utf8.properties | 2 + ...ProjectNoteColumn$ViewAndEditNoteForm.html | 15 ++ .../supervisor/panels/ProjectNoteColumn.java | 129 ++++++++++++++++++ .../panels/SupervisorMyProjectsPanel.html | 4 + .../panels/SupervisorMyProjectsPanel.java | 20 +++ .../SupervisorMyProjectsPanel.utf8.properties | 3 + .../java/se/su/dsv/scipro/SciProTest.java | 3 + 19 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/se/su/dsv/scipro/project/ProjectNoteService.java create mode 100644 core/src/main/java/se/su/dsv/scipro/settings/dataobjects/SupervisorProjectNoteDisplay.java create mode 100644 core/src/main/resources/db/migration/V388__user_notes_for_projects.sql create mode 100644 view/src/main/java/se/su/dsv/scipro/components/MaxLengthLabel.java create mode 100644 view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.html create mode 100644 view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.utf8.properties create mode 100644 view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html create mode 100644 view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java diff --git a/core/src/main/java/modules/CoreModule.java b/core/src/main/java/modules/CoreModule.java index cb2c500685..075c6e9ed8 100644 --- a/core/src/main/java/modules/CoreModule.java +++ b/core/src/main/java/modules/CoreModule.java @@ -48,6 +48,7 @@ import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServ import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServiceImpl; import se.su.dsv.scipro.peer.*; import se.su.dsv.scipro.plagiarism.*; +import se.su.dsv.scipro.project.ProjectNoteService; import se.su.dsv.scipro.project.ProjectPeopleStatisticsService; import se.su.dsv.scipro.project.ProjectPeopleStatisticsServiceImpl; import se.su.dsv.scipro.project.ProjectService; @@ -139,6 +140,7 @@ public class CoreModule extends AbstractModule { bind(FirstMeetingService.class).to(FirstMeetingServiceImpl.class); bind(FinalSeminarCreationSubscribers.class).asEagerSingleton(); bind(ProjectPartnerRepository.class).to(ProjectPartnerRepositoryImpl.class); + bind(ProjectNoteService.class).to(ProjectServiceImpl.class); install(new PlagiarismModule()); install(new NotificationModule()); diff --git a/core/src/main/java/se/su/dsv/scipro/project/Project.java b/core/src/main/java/se/su/dsv/scipro/project/Project.java index 92c82a9014..9429d2cbfc 100755 --- a/core/src/main/java/se/su/dsv/scipro/project/Project.java +++ b/core/src/main/java/se/su/dsv/scipro/project/Project.java @@ -85,6 +85,13 @@ public class Project extends DomainObject { @Enumerated(EnumType.STRING) private Language language; + @ElementCollection(fetch = FetchType.LAZY) + @CollectionTable(name = "project_user_note", joinColumns = @JoinColumn(name = "project_id")) + @Column(name = "note") + @SuppressWarnings("JpaDataSourceORMInspection") // false warning from IntelliJ for the @MapKeyJoinColumn + @MapKeyJoinColumn(name = "user_id") + private Map<User, String> userNotes = new HashMap<>(); + @PrePersist @PreUpdate void cleanTitle() { @@ -94,6 +101,14 @@ public class Project extends DomainObject { title = title.trim(); } + public Map<User, String> getUserNotes() { + return userNotes; + } + + public void setUserNotes(Map<User, String> userNotes) { + this.userNotes = userNotes; + } + public boolean isFinalSeminarRuleExempted() { return finalSeminarRuleExempted; } diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectNoteService.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectNoteService.java new file mode 100644 index 0000000000..7ff1657d63 --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectNoteService.java @@ -0,0 +1,9 @@ +package se.su.dsv.scipro.project; + +import se.su.dsv.scipro.system.User; + +public interface ProjectNoteService { + String getUserNote(Project project, User user); + + void setUserNote(Project project, User user, String note); +} diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java index 69dcda672d..f27da7b94a 100755 --- a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java @@ -11,4 +11,8 @@ import java.util.List; @Transactional public interface ProjectRepo extends JpaRepository<Project, Long>, QueryDslPredicateExecutor<Project> { List<User> findMultipleAuthors(Collection<Project> projects); + + String getUserNoteForProject(Project project, User user); + + void setUserNoteForProject(Project project, User user, String note); } \ No newline at end of file diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java index 627af554ec..f8dfb462bd 100644 --- a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.project; +import com.google.inject.persist.Transactional; import se.su.dsv.scipro.system.GenericRepo; import se.su.dsv.scipro.system.User; @@ -30,4 +31,16 @@ public class ProjectRepoImpl extends GenericRepo<Project, Long> implements Proje query.setParameter("projects", projects); return query.getResultList(); } + + @Override + public String getUserNoteForProject(Project project, User user) { + return project.getUserNotes().get(user); + } + + @Override + @Transactional + public void setUserNoteForProject(Project project, User user, String note) { + project.getUserNotes().put(user, note); + save(project); + } } diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java index c2f8e83098..2ba2a6a436 100755 --- a/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java @@ -22,7 +22,7 @@ import java.time.Duration; import java.time.Instant; import java.util.*; -public class ProjectServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectService { +public class ProjectServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectService, ProjectNoteService { public static final int MIN_TITLE_LENGTH = 3; private final ProjectRepo projectRepo; @@ -175,6 +175,16 @@ public class ProjectServiceImpl extends AbstractServiceImpl<Project, Long> imple return completed; } + @Override + public String getUserNote(Project project, User user) { + return projectRepo.getUserNoteForProject(project, user); + } + + @Override + public void setUserNote(Project project, User user, String note) { + projectRepo.setUserNoteForProject(project, user, note); + } + @Override public List<Project> findAll(Filter filter, Pageable pageable) { return findAll(toPredicate(filter), pageable); diff --git a/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/SupervisorProjectNoteDisplay.java b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/SupervisorProjectNoteDisplay.java new file mode 100644 index 0000000000..1a6c45d452 --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/SupervisorProjectNoteDisplay.java @@ -0,0 +1,5 @@ +package se.su.dsv.scipro.settings.dataobjects; + +public enum SupervisorProjectNoteDisplay { + COMPACT, FULL +} diff --git a/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java index 8cf7d44e31..ac863a2afa 100644 --- a/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java +++ b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java @@ -58,6 +58,11 @@ public class UserProfile extends DomainObject { @Enumerated(EnumType.STRING) private Roles selectedRole; + @Basic + @Enumerated(EnumType.STRING) + @Column(name = "supervisor_project_note_display") + private SupervisorProjectNoteDisplay supervisorProjectNoteDisplay = SupervisorProjectNoteDisplay.COMPACT; + @Override public Long getId() { return this.id; @@ -147,6 +152,14 @@ public class UserProfile extends DomainObject { this.selectedRole = selectedRole; } + public SupervisorProjectNoteDisplay getSupervisorProjectNoteDisplay() { + return supervisorProjectNoteDisplay; + } + + public void setSupervisorProjectNoteDisplay(SupervisorProjectNoteDisplay supervisorProjectNoteDisplay) { + this.supervisorProjectNoteDisplay = supervisorProjectNoteDisplay; + } + @Override public String toString() { return "UserProfile(id=" + this.getId() + ", user=" + this.getUser() + ", skypeId=" + this.getSkypeId() + ", phoneNumber=" + this.getPhoneNumber() + ", otherInfo=" + this.getOtherInfo() + ", mailCompilation=" + this.isMailCompilation() + ", defaultProjectStatusFilter=" + this.getDefaultProjectStatusFilter() + ", defaultProjectTeamMemberRolesFilter=" + this.getDefaultProjectTeamMemberRolesFilter() + ", defaultSupervisorFilter=" + this.isDefaultSupervisorFilter() + ", defaultProjectTypeFilter=" + this.getDefaultProjectTypeFilter() + ", selectedRole=" + this.getSelectedRole() + ")"; diff --git a/core/src/main/resources/db/migration/V388__user_notes_for_projects.sql b/core/src/main/resources/db/migration/V388__user_notes_for_projects.sql new file mode 100644 index 0000000000..334caad59b --- /dev/null +++ b/core/src/main/resources/db/migration/V388__user_notes_for_projects.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS `project_user_note` ( + `project_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `note` text NULL, + PRIMARY KEY (`project_id`, `user_id`), + CONSTRAINT `FK_project_user_note_project` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `FK_project_user_note_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +); + +ALTER TABLE `user_profile` + ADD COLUMN `supervisor_project_note_display` VARCHAR(15) NOT NULL DEFAULT 'COMPACT'; diff --git a/view/src/main/java/se/su/dsv/scipro/components/MaxLengthLabel.java b/view/src/main/java/se/su/dsv/scipro/components/MaxLengthLabel.java new file mode 100644 index 0000000000..edfdd48ab9 --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/components/MaxLengthLabel.java @@ -0,0 +1,37 @@ +package se.su.dsv.scipro.components; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.IModel; +import org.apache.wicket.util.convert.IConverter; + +import java.util.Locale; + +public class MaxLengthLabel extends Label { + private final IModel<Integer> maxLengthModel; + + public MaxLengthLabel(String id, IModel<String> dataModel, IModel<Integer> maxLength) { + super(id, dataModel); + this.maxLengthModel = maxLength; + } + + @Override + protected IConverter<?> createConverter(Class<?> type) { + return new MaxLengthConverter(); + } + + private class MaxLengthConverter implements IConverter<String> { + @Override + public String convertToObject(String s, Locale locale) { + return s; + } + + @Override + public String convertToString(String o, Locale locale) { + Integer maxLength = maxLengthModel.getObject(); + if (o.length() > maxLength) { + return o.substring(0, maxLength) + "..."; + } + return o; + } + } +} diff --git a/view/src/main/java/se/su/dsv/scipro/components/ModalWindowPlus.java b/view/src/main/java/se/su/dsv/scipro/components/ModalWindowPlus.java index 9faa92158d..0eca546462 100644 --- a/view/src/main/java/se/su/dsv/scipro/components/ModalWindowPlus.java +++ b/view/src/main/java/se/su/dsv/scipro/components/ModalWindowPlus.java @@ -1,6 +1,7 @@ package se.su.dsv.scipro.components; import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxEventBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.markup.ComponentTag; @@ -9,6 +10,7 @@ import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; +import org.danekja.java.util.function.serializable.SerializableConsumer; import java.util.function.Function; @@ -83,4 +85,13 @@ public class ModalWindowPlus extends Panel { component.setOutputMarkupPlaceholderTag(true); replace(component); } + + public void onClose(SerializableConsumer<AjaxRequestTarget> onClose) { + add(new AjaxEventBehavior("hidden.bs.modal") { + @Override + protected void onEvent(AjaxRequestTarget target) { + onClose.accept(target); + } + }); + } } diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.html b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.html new file mode 100644 index 0000000000..7a5e924096 --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.html @@ -0,0 +1,11 @@ +<?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:panel> + <div wicket:id="edit_note_modal"></div> + <span wicket:id="shortened_note"></span> + <wicket:container wicket:id="full_note"></wicket:container> + <a wicket:id="view_note"><wicket:message key="note.view.edit"/></a> +</wicket:panel> +</body> +</html> \ No newline at end of file diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.utf8.properties new file mode 100644 index 0000000000..5f31ea7d1c --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteCellPanel.utf8.properties @@ -0,0 +1,2 @@ +note.modal.title=View/edit note for ${title} +note.view.edit=View/edit note diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html new file mode 100644 index 0000000000..bf546f6a76 --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html @@ -0,0 +1,15 @@ +<?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:panel> + <form wicket:id="form"> + <div wicket:id="feedback"></div> + <div class="mb-3"> + <label wicket:for="note" class="sr-only">Note</label> + <textarea wicket:id="note" rows="20" class="form-control"></textarea> + </div> + <button wicket:id="save" type="submit" class="btn btn-primary">Save</button> + </form> +</wicket:panel> +</body> +</html> \ No newline at end of file diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java new file mode 100644 index 0000000000..b35962f891 --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java @@ -0,0 +1,129 @@ +package se.su.dsv.scipro.supervisor.panels; + +import jakarta.inject.Inject; +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.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.export.AbstractExportableColumn; +import org.apache.wicket.feedback.FencedFeedbackPanel; +import org.apache.wicket.injection.Injector; +import org.apache.wicket.markup.html.basic.MultiLineLabel; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.markup.html.panel.GenericPanel; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; +import se.su.dsv.scipro.components.LargeModalWindow; +import se.su.dsv.scipro.components.MaxLengthLabel; +import se.su.dsv.scipro.components.ModalWindowPlus; +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.project.ProjectNoteService; +import se.su.dsv.scipro.settings.dataobjects.SupervisorProjectNoteDisplay; +import se.su.dsv.scipro.system.User; + +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; + +public class ProjectNoteColumn extends AbstractExportableColumn<Project, String> { + @Inject + private ProjectNoteService projectNoteService; + + private final IModel<User> user; + private final IModel<SupervisorProjectNoteDisplay> supervisorProjectNoteDisplayModel; + + public ProjectNoteColumn(IModel<String> displayModel, IModel<User> user, + IModel<SupervisorProjectNoteDisplay> supervisorProjectNoteDisplayModel) { + super(displayModel); + Injector.get().inject(this); + this.supervisorProjectNoteDisplayModel = supervisorProjectNoteDisplayModel; + this.user = user; + } + + @Override + public IModel<String> getDataModel(IModel<Project> rowModel) { + return LoadableDetachableModel.of(() -> projectNoteService.getUserNote( + rowModel.getObject(), + user.getObject())); + } + + @Override + public void populateItem( + Item<ICellPopulator<Project>> cellItem, + String componentId, + IModel<Project> rowModel) + { + cellItem.add(new ViewAndEditNoteCellPanel(componentId, rowModel)); + } + + private class ViewAndEditNoteCellPanel extends GenericPanel<Project> { + public ViewAndEditNoteCellPanel(String id, IModel<Project> model) { + super(id, model); + + ModalWindowPlus modal = new LargeModalWindow("edit_note_modal"); + modal.setTitle(new StringResourceModel("note.modal.title", this, model)); + modal.setContent(componentId -> new ViewAndEditNoteForm(componentId, model)); + add(modal); + + setOutputMarkupId(true); + modal.onClose(target -> target.add(this)); + + add(new MaxLengthLabel("shortened_note", getDataModel(model), Model.of(100)) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisibilityAllowed(supervisorProjectNoteDisplayModel.getObject() == SupervisorProjectNoteDisplay.COMPACT); + } + }); + add(new MultiLineLabel("full_note", getDataModel(model)) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisibilityAllowed(supervisorProjectNoteDisplayModel.getObject() == SupervisorProjectNoteDisplay.FULL); + } + }); + + AjaxLink<Object> noteLink = new AjaxLink<>("view_note") { + @Override + public void onClick(AjaxRequestTarget target) { + modal.show(target); + } + }; + add(noteLink); + } + } + + private class ViewAndEditNoteForm extends GenericPanel<Project> { + public ViewAndEditNoteForm(String id, IModel<Project> project) { + super(id, project); + + IModel<String> note = getDataModel(project); + + Form<Project> form = new Form<>("form", project) { + @Override + protected void onSubmit() { + projectNoteService.setUserNote( + project.getObject(), + user.getObject(), + note.getObject() + ); + success("Note saved at " + LocalTime.now().truncatedTo(ChronoUnit.SECONDS)); + } + }; + add(form); + + form.add(new FencedFeedbackPanel("feedback", form)); + + form.add(new TextArea<>("note", note)); + form.add(new AjaxSubmitLink("save") { + @Override + protected void onAfterSubmit(AjaxRequestTarget target) { + target.add(form); + } + }); + } + } +} diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.html b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.html index 9b68bf8d79..73ab571f7f 100755 --- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.html +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.html @@ -31,6 +31,10 @@ </strong> <div wicket:id="projectTypes"></div> </div> + <fieldset class="col-6 col-md-3 col-lg-2"> + <legend>Note</legend> + <div wicket:id="note_display"></div> + </fieldset> </div> </form> </div> diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.java b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.java index e13137a359..e3cab053eb 100755 --- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.java @@ -1,6 +1,7 @@ package se.su.dsv.scipro.supervisor.panels; import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; @@ -15,6 +16,7 @@ import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LambdaModel; +import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import se.su.dsv.scipro.components.*; import se.su.dsv.scipro.components.datatables.MultipleUsersColumn; @@ -30,6 +32,7 @@ import se.su.dsv.scipro.project.ProjectService; import se.su.dsv.scipro.project.ProjectStatus; import se.su.dsv.scipro.project.ProjectTeamMemberRoles; import se.su.dsv.scipro.session.SciProSession; +import se.su.dsv.scipro.settings.dataobjects.SupervisorProjectNoteDisplay; import se.su.dsv.scipro.settings.dataobjects.UserProfile; import se.su.dsv.scipro.springdata.services.UserProfileService; import se.su.dsv.scipro.system.ProjectType; @@ -62,6 +65,7 @@ public class SupervisorMyProjectsPanel extends Panel { private ExportableDataPanel dataPanel; private ProjectService.Filter filter = new ProjectService.Filter(); + private IModel<SupervisorProjectNoteDisplay> supervisorProjectNoteDisplayModel = new Model<>(); public SupervisorMyProjectsPanel(String id) { super(id); @@ -90,6 +94,7 @@ public class SupervisorMyProjectsPanel extends Panel { return new ListAdapterModel<>(rowModel.map(Project::getProjectParticipants)); } }); + columns.add(new ProjectNoteColumn(Model.of("Note"), LoadableDetachableModel.of(this::currentUser), supervisorProjectNoteDisplayModel)); columns.add(new UserColumn<>(Model.of("Head supervisor"), "headSupervisor.fullName", Project::getHeadSupervisor)); return columns; } @@ -112,6 +117,7 @@ public class SupervisorMyProjectsPanel extends Panel { filter.setRoles(userProfile.getDefaultProjectTeamMemberRolesFilter()); filter.setFilterSupervisor(userProfile.isDefaultSupervisorFilter()); filter.setProjectTypes(userProfile.getDefaultProjectTypeFilter()); + supervisorProjectNoteDisplayModel.setObject(userProfile.getSupervisorProjectNoteDisplay()); } private User currentUser() { @@ -155,6 +161,19 @@ public class SupervisorMyProjectsPanel extends Panel { updateProfileWithCurrentFilter(); } }); + BootstrapRadioChoice<SupervisorProjectNoteDisplay> noteDisplay = new BootstrapRadioChoice<>( + "note_display", + supervisorProjectNoteDisplayModel, + List.of(SupervisorProjectNoteDisplay.values()), + new EnumChoiceRenderer<>(this)); + noteDisplay.add(new AjaxFormChoiceComponentUpdatingBehavior() { + @Override + public void onUpdate(AjaxRequestTarget target) { + target.add(dataPanel); + updateProfileWithCurrentFilter(); + } + }); + add(noteDisplay); } private void updateProfileWithCurrentFilter() { @@ -163,6 +182,7 @@ public class SupervisorMyProjectsPanel extends Panel { userProfile.setDefaultProjectTeamMemberRolesFilter(filter.getRoles()); userProfile.setDefaultSupervisorFilter(filter.isFilterSupervisor()); userProfile.setDefaultProjectTypeFilter(filter.getProjectTypes()); + userProfile.setSupervisorProjectNoteDisplay(supervisorProjectNoteDisplayModel.getObject()); profileService.save(userProfile); } } diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.utf8.properties index 8c2d03baf2..17f454ad8c 100644 --- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.utf8.properties +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorMyProjectsPanel.utf8.properties @@ -9,3 +9,6 @@ ProjectTeamMemberRoles.CO_SUPERVISOR= Co-Supervisor ProjectStatus.ACTIVE= Active ProjectStatus.INACTIVE= Inactive ProjectStatus.COMPLETED= Completed + +SupervisorProjectNoteDisplay.COMPACT=Compact +SupervisorProjectNoteDisplay.FULL=Full diff --git a/view/src/test/java/se/su/dsv/scipro/SciProTest.java b/view/src/test/java/se/su/dsv/scipro/SciProTest.java index 9a400e0086..ee39fc8b41 100755 --- a/view/src/test/java/se/su/dsv/scipro/SciProTest.java +++ b/view/src/test/java/se/su/dsv/scipro/SciProTest.java @@ -87,6 +87,7 @@ import se.su.dsv.scipro.peer.PerformReviewService; import se.su.dsv.scipro.plagiarism.PlagiarismControl; import se.su.dsv.scipro.plagiarism.urkund.UrkundService; import se.su.dsv.scipro.profiles.CurrentProfile; +import se.su.dsv.scipro.project.ProjectNoteService; import se.su.dsv.scipro.project.ProjectPeopleStatisticsService; import se.su.dsv.scipro.project.ProjectService; import se.su.dsv.scipro.project.pages.ProjectStartPage; @@ -355,6 +356,8 @@ public abstract class SciProTest { protected ExaminerTimelineService examinerTimelineService; @Mock protected NationalSubjectCategoryService nationalSubjectCategoryService; + @Mock + protected ProjectNoteService projectNoteService; protected WicketTester tester;