Improve the UX when creating groups as a supervisor (#123)
The main problem was that the supervisor did not get enough information about each project, mainly who the authors were, when selecting them in the dropdown. To remedy this, the dropdown has been completely replaced with a checkbox based approach showing the title as well as project type, authors, and start date for each project. The projects are sorted first by start date (descending) and then title, based on the assumptions that newly created projects are the most relevant when setting up groups. In addition extra "quick buttons" have been added in an effort to reduce the number of clicks required to accomplish varying tasks. Fixes #89 ## How to test 1. Log in as `evan@example.com` 2. Go to "My groups" 3. Click "Create new group" Co-authored-by: Nico Athanassiadis <nico@dsv.su.se> Reviewed-on: #123 Reviewed-by: Nico Athanassiadis <nico@dsv.su.se> Co-authored-by: Andreas Svanberg <andreass@dsv.su.se> Co-committed-by: Andreas Svanberg <andreass@dsv.su.se>
This commit is contained in:
parent
d008bec815
commit
1aa0a4e3ef
test-data/src/main/java/se/su/dsv/scipro/testdata/populators
view/src
main
test/java/se/su/dsv/scipro/group
65
test-data/src/main/java/se/su/dsv/scipro/testdata/populators/GroupCreationUXImprovement.java
vendored
Normal file
65
test-data/src/main/java/se/su/dsv/scipro/testdata/populators/GroupCreationUXImprovement.java
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package se.su.dsv.scipro.testdata.populators;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.project.ProjectService;
|
||||||
|
import se.su.dsv.scipro.system.ProjectType;
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
import se.su.dsv.scipro.testdata.BaseData;
|
||||||
|
import se.su.dsv.scipro.testdata.Factory;
|
||||||
|
import se.su.dsv.scipro.testdata.TestDataPopulator;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GroupCreationUXImprovement implements TestDataPopulator {
|
||||||
|
|
||||||
|
private static final String[] STUDENT_NAMES = { "Alice", "Bob", "Charlie", "David", "Emma" };
|
||||||
|
|
||||||
|
private final ProjectService projectService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public GroupCreationUXImprovement(ProjectService projectService) {
|
||||||
|
this.projectService = projectService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void populate(BaseData baseData, Factory factory) {
|
||||||
|
User supervisor = factory.createSupervisor("Evan");
|
||||||
|
List<User> students = createStudents(factory);
|
||||||
|
for (int i = 1; i <= 20; i++) {
|
||||||
|
projectService.save(createProject(baseData, i, supervisor, students));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<User> createStudents(Factory factory) {
|
||||||
|
return Arrays.stream(STUDENT_NAMES).map(factory::createAuthor).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Project createProject(BaseData baseData, int i, User supervisor, List<User> students) {
|
||||||
|
User author1 = students.get(i % students.size());
|
||||||
|
User author2 = students.get((i + 1) % students.size());
|
||||||
|
|
||||||
|
String title = "Test project " + i;
|
||||||
|
if (i % 6 == 0) {
|
||||||
|
title = title + " with a very long title that makes the project special";
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectType projectType =
|
||||||
|
switch (i % 3) {
|
||||||
|
case 1 -> baseData.magister();
|
||||||
|
case 2 -> baseData.master();
|
||||||
|
default -> baseData.bachelor();
|
||||||
|
};
|
||||||
|
return Project.builder()
|
||||||
|
.title(title)
|
||||||
|
.projectType(projectType)
|
||||||
|
.startDate(LocalDate.now())
|
||||||
|
.headSupervisor(supervisor)
|
||||||
|
.projectParticipants(Set.of(author1, author2))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -2,85 +2,50 @@
|
|||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
|
||||||
<body>
|
<body>
|
||||||
<wicket:panel>
|
<wicket:panel>
|
||||||
<div class="row">
|
<div class="line-length-limit">
|
||||||
<div class="col-lg-12">
|
<form wicket:id="form">
|
||||||
<form wicket:id="form">
|
|
||||||
|
|
||||||
<div class="row">
|
<div wicket:id="feedback"></div>
|
||||||
<div class="col-lg-12">
|
|
||||||
<div wicket:id="feedback"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="mb-3">
|
||||||
<div class="col-lg-5 col-md-10">
|
<label wicket:for="title" class="form-label">Title</label>
|
||||||
<label wicket:for="title">Title: </label>
|
<input type="text" wicket:id="title" class="form-control">
|
||||||
<input type="text" wicket:id="title" class="form-control">
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="mb-3">
|
||||||
<div class="col-lg-5 col-md-10">
|
<label wicket:for="description" class="form-label">Description</label>
|
||||||
<label wicket:for="description">Description: </label>
|
<textarea wicket:id="description" class="form-control"></textarea>
|
||||||
<textarea wicket:id="description" class="form-control"></textarea>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="form-check mb-3">
|
||||||
<div class="col-lg-5 col-md-10">
|
<input class="form-check-input" wicket:id="active" type="checkbox"/>
|
||||||
<div class="form-check">
|
<label class="form-check-label" wicket:for="active">Active</label>
|
||||||
<input class="form-check-input" wicket:id="active" type="checkbox"/>
|
</div>
|
||||||
<label class="form-check-label" wicket:for="active">Active</label>
|
|
||||||
|
<fieldset class="mb-3">
|
||||||
|
<legend>Projects</legend>
|
||||||
|
<div class="group-project-grid">
|
||||||
|
<label wicket:id="available_projects">
|
||||||
|
<div>
|
||||||
|
<input class="form-check-input mt-0" type="checkbox" wicket:id="selected">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
</div>
|
<h4 wicket:id="title"></h4>
|
||||||
|
<span wicket:id="type"></span>
|
||||||
<div class="row">
|
<br>
|
||||||
<div class="col-lg-12">
|
Started at <span wicket:id="start_date"></span>
|
||||||
<div wicket:id="wmc">
|
<div wicket:id="authors">
|
||||||
|
<span wicket:id="author"></span>
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-5 col-md-10">
|
|
||||||
<strong>Add projects to group: </strong>
|
|
||||||
<div wicket:id="projectTypes"></div>
|
|
||||||
<select class="form-select" wicket:id="addProjects"></select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<strong>Projects in group: </strong>
|
|
||||||
<table class="table table-striped table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Title</th>
|
|
||||||
<th>Authors</th>
|
|
||||||
<th>Remove</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr wicket:id="projects">
|
|
||||||
<td><span wicket:id="type"></span></td>
|
|
||||||
<td><span wicket:id="title"></span></td>
|
|
||||||
<td><div wicket:id="authors">
|
|
||||||
<div wicket:id="author"></div>
|
|
||||||
</div></td>
|
|
||||||
<td><a wicket:id="remove"><span class="fa fa-times"></span></a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div wicket:id="noProjects"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
</fieldset>
|
||||||
<button type="submit" class="btn btn-success" >Save</button>
|
<button type="submit" class="btn btn-success">Save</button>
|
||||||
</form>
|
<button type="submit" wicket:id="save_and_close" class="btn btn-success">Save and close</button>
|
||||||
</div>
|
<button type="submit" wicket:id="save_and_create" class="btn btn-success">Save and create another</button>
|
||||||
|
<a wicket:id="cancel" class="btn btn-outline-secondary">Cancel</a>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</wicket:panel>
|
</wicket:panel>
|
||||||
</body>
|
</body>
|
||||||
|
@ -2,11 +2,10 @@ package se.su.dsv.scipro.group;
|
|||||||
|
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
import org.apache.wicket.extensions.model.AbstractCheckBoxModel;
|
||||||
import org.apache.wicket.ajax.markup.html.AjaxLink;
|
|
||||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
|
||||||
import org.apache.wicket.markup.html.basic.Label;
|
import org.apache.wicket.markup.html.basic.Label;
|
||||||
import org.apache.wicket.markup.html.form.*;
|
import org.apache.wicket.markup.html.form.*;
|
||||||
|
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
||||||
import org.apache.wicket.markup.html.list.ListItem;
|
import org.apache.wicket.markup.html.list.ListItem;
|
||||||
import org.apache.wicket.markup.html.list.ListView;
|
import org.apache.wicket.markup.html.list.ListView;
|
||||||
import org.apache.wicket.markup.html.panel.FeedbackPanel;
|
import org.apache.wicket.markup.html.panel.FeedbackPanel;
|
||||||
@ -14,10 +13,6 @@ import org.apache.wicket.markup.html.panel.Panel;
|
|||||||
import org.apache.wicket.model.IModel;
|
import org.apache.wicket.model.IModel;
|
||||||
import org.apache.wicket.model.LambdaModel;
|
import org.apache.wicket.model.LambdaModel;
|
||||||
import org.apache.wicket.model.LoadableDetachableModel;
|
import org.apache.wicket.model.LoadableDetachableModel;
|
||||||
import org.apache.wicket.model.Model;
|
|
||||||
import org.apache.wicket.model.util.ListModel;
|
|
||||||
import se.su.dsv.scipro.components.AjaxCheckBoxMultipleChoice;
|
|
||||||
import se.su.dsv.scipro.components.AjaxDropDownChoice;
|
|
||||||
import se.su.dsv.scipro.components.ListAdapterModel;
|
import se.su.dsv.scipro.components.ListAdapterModel;
|
||||||
import se.su.dsv.scipro.profile.UserLinkPanel;
|
import se.su.dsv.scipro.profile.UserLinkPanel;
|
||||||
import se.su.dsv.scipro.project.Project;
|
import se.su.dsv.scipro.project.Project;
|
||||||
@ -25,8 +20,8 @@ import se.su.dsv.scipro.project.ProjectService;
|
|||||||
import se.su.dsv.scipro.project.ProjectStatus;
|
import se.su.dsv.scipro.project.ProjectStatus;
|
||||||
import se.su.dsv.scipro.project.ProjectTeamMemberRoles;
|
import se.su.dsv.scipro.project.ProjectTeamMemberRoles;
|
||||||
import se.su.dsv.scipro.session.SciProSession;
|
import se.su.dsv.scipro.session.SciProSession;
|
||||||
import se.su.dsv.scipro.system.ProjectType;
|
import se.su.dsv.scipro.supervisor.pages.SupervisorEditGroupPage;
|
||||||
import se.su.dsv.scipro.system.ProjectTypeService;
|
import se.su.dsv.scipro.supervisor.pages.SupervisorMyGroupsPage;
|
||||||
import se.su.dsv.scipro.system.User;
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
public class EditGroupPanel extends Panel {
|
public class EditGroupPanel extends Panel {
|
||||||
@ -37,9 +32,6 @@ public class EditGroupPanel extends Panel {
|
|||||||
@Inject
|
@Inject
|
||||||
private GroupService groupService;
|
private GroupService groupService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private ProjectTypeService projectTypeService;
|
|
||||||
|
|
||||||
public EditGroupPanel(String id, final IModel<Group> model) {
|
public EditGroupPanel(String id, final IModel<Group> model) {
|
||||||
super(id, model);
|
super(id, model);
|
||||||
add(new GroupForm("form", model));
|
add(new GroupForm("form", model));
|
||||||
@ -47,18 +39,46 @@ public class EditGroupPanel extends Panel {
|
|||||||
|
|
||||||
private class GroupForm extends Form<Group> {
|
private class GroupForm extends Form<Group> {
|
||||||
|
|
||||||
private final AjaxDropDownChoice<Project> addProjects;
|
|
||||||
private final ListView<Project> projects;
|
|
||||||
private final List<Project> currentProjects;
|
|
||||||
private final AjaxCheckBoxMultipleChoice<ProjectType> projectTypes;
|
|
||||||
|
|
||||||
public GroupForm(String form, final IModel<Group> model) {
|
public GroupForm(String form, final IModel<Group> model) {
|
||||||
super(form, model);
|
super(form, model);
|
||||||
final FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
|
final FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
|
||||||
feedbackPanel.setOutputMarkupId(true);
|
feedbackPanel.setOutputMarkupId(true);
|
||||||
add(feedbackPanel);
|
add(feedbackPanel);
|
||||||
|
|
||||||
currentProjects = new ArrayList<>(getModelObject().getProjects());
|
IModel<List<Project>> availableProjects = LoadableDetachableModel.of(() -> {
|
||||||
|
Set<Project> projects = new HashSet<>();
|
||||||
|
projects.addAll(getAllRelevantProjects());
|
||||||
|
// Have to add the projects that are already in the group to the list of available projects
|
||||||
|
// since they may not be included in the relevant projects if they're inactive or completed.
|
||||||
|
// To allow them to be removed from the group, it will not be possible to add them again.
|
||||||
|
projects.addAll(model.getObject().getProjects());
|
||||||
|
return projects
|
||||||
|
.stream()
|
||||||
|
.sorted(Comparator.comparing(Project::getStartDate).reversed().thenComparing(Project::getTitle))
|
||||||
|
.toList();
|
||||||
|
});
|
||||||
|
add(
|
||||||
|
new ListView<>("available_projects", availableProjects) {
|
||||||
|
@Override
|
||||||
|
protected void populateItem(ListItem<Project> item) {
|
||||||
|
CheckBox checkbox = new CheckBox("selected", new SelectProjectModel(model, item.getModel()));
|
||||||
|
checkbox.setOutputMarkupId(true);
|
||||||
|
item.add(checkbox);
|
||||||
|
item.add(new Label("title", item.getModel().map(Project::getTitle)));
|
||||||
|
item.add(new Label("type", item.getModel().map(Project::getProjectTypeName)));
|
||||||
|
item.add(new Label("start_date", item.getModel().map(Project::getStartDate)));
|
||||||
|
IModel<SortedSet<User>> authors = item.getModel().map(Project::getProjectParticipants);
|
||||||
|
item.add(
|
||||||
|
new ListView<>("authors", new ListAdapterModel<>(authors)) {
|
||||||
|
@Override
|
||||||
|
protected void populateItem(ListItem<User> item) {
|
||||||
|
item.add(new UserLinkPanel("author", item.getModel()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
add(new RequiredTextField<>("title", LambdaModel.of(model, Group::getTitle, Group::setTitle)));
|
add(new RequiredTextField<>("title", LambdaModel.of(model, Group::getTitle, Group::setTitle)));
|
||||||
add(new TextArea<>("description", LambdaModel.of(model, Group::getDescription, Group::setDescription)));
|
add(new TextArea<>("description", LambdaModel.of(model, Group::getDescription, Group::setDescription)));
|
||||||
@ -66,120 +86,64 @@ public class EditGroupPanel extends Panel {
|
|||||||
new CheckBox("active", LambdaModel.of(model, Group::isActive, Group::setActive)).setOutputMarkupId(true)
|
new CheckBox("active", LambdaModel.of(model, Group::isActive, Group::setActive)).setOutputMarkupId(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
final WebMarkupContainer wmc = new WebMarkupContainer("wmc");
|
add(
|
||||||
wmc.setOutputMarkupId(true);
|
new SubmitLink("save_and_close") {
|
||||||
|
|
||||||
projectTypes = projectTypeSelection(wmc);
|
|
||||||
wmc.add(projectTypes);
|
|
||||||
|
|
||||||
addProjects = new AjaxDropDownChoice<>(
|
|
||||||
"addProjects",
|
|
||||||
new Model<>(),
|
|
||||||
getSelectableProjects(currentProjects),
|
|
||||||
new LambdaChoiceRenderer<>(Project::getTitle, Project::getId)
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onNewSelection(AjaxRequestTarget target, Project objectSelected) {
|
|
||||||
if (objectSelected != null && !currentProjects.contains(objectSelected)) {
|
|
||||||
currentProjects.add(objectSelected);
|
|
||||||
projects.setList(currentProjects);
|
|
||||||
addProjects.setChoices(getSelectableProjects(currentProjects));
|
|
||||||
target.add(wmc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
addProjects.setRequired(false);
|
|
||||||
addProjects.setNullValid(true);
|
|
||||||
wmc.add(addProjects);
|
|
||||||
|
|
||||||
projects = new ListView<>("projects", new ArrayList<>(currentProjects)) {
|
|
||||||
@Override
|
|
||||||
protected void populateItem(final ListItem<Project> item) {
|
|
||||||
item.add(new Label("type", item.getModel().map(Project::getProjectTypeName)));
|
|
||||||
item.add(new Label("title", item.getModel().map(Project::getTitle)));
|
|
||||||
item.add(
|
|
||||||
new ListView<>(
|
|
||||||
"authors",
|
|
||||||
new ListAdapterModel<>(
|
|
||||||
getLoaded(item.getModelObject()).map(Project::getProjectParticipants)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void populateItem(ListItem<User> item) {
|
|
||||||
item.add(new UserLinkPanel("author", item.getModel()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
item.add(
|
|
||||||
new AjaxLink<>("remove", item.getModel()) {
|
|
||||||
@Override
|
|
||||||
public void onClick(AjaxRequestTarget target) {
|
|
||||||
currentProjects.remove(item.getModelObject());
|
|
||||||
projects.setList(currentProjects);
|
|
||||||
addProjects.setChoices(getSelectableProjects(currentProjects));
|
|
||||||
target.add(wmc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
wmc.add(projects);
|
|
||||||
|
|
||||||
wmc.add(
|
|
||||||
new Label("noProjects", "None") {
|
|
||||||
@Override
|
@Override
|
||||||
protected void onConfigure() {
|
public void onAfterSubmit() {
|
||||||
super.onConfigure();
|
setResponsePage(SupervisorMyGroupsPage.class);
|
||||||
setVisibilityAllowed(currentProjects.isEmpty());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
add(
|
||||||
add(wmc);
|
new SubmitLink("save_and_create") {
|
||||||
}
|
@Override
|
||||||
|
public void onAfterSubmit() {
|
||||||
private AjaxCheckBoxMultipleChoice<ProjectType> projectTypeSelection(final WebMarkupContainer wmc) {
|
setResponsePage(SupervisorEditGroupPage.class);
|
||||||
return new AjaxCheckBoxMultipleChoice<>(
|
}
|
||||||
"projectTypes",
|
|
||||||
projectTypeService.findAllActive(),
|
|
||||||
projectTypeService.findAllActive(),
|
|
||||||
new LambdaChoiceRenderer<>(ProjectType::getName, ProjectType::getId)
|
|
||||||
) {
|
|
||||||
@Override
|
|
||||||
public void onUpdate(AjaxRequestTarget target) {
|
|
||||||
addProjects.setChoices(getSelectableProjects(currentProjects));
|
|
||||||
target.add(wmc);
|
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
add(new BookmarkablePageLink<>("cancel", SupervisorMyGroupsPage.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSubmit() {
|
protected void onSubmit() {
|
||||||
Group group = getModelObject();
|
Group group = getModelObject();
|
||||||
group.setProjects(new HashSet<>(currentProjects));
|
|
||||||
groupService.save(group);
|
groupService.save(group);
|
||||||
info(getString("saved"));
|
info(getString("saved"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListModel<Project> getSelectableProjects(List<Project> currentProjects) {
|
private List<Project> getAllRelevantProjects() {
|
||||||
final ProjectService.Filter filter = new ProjectService.Filter();
|
final ProjectService.Filter filter = new ProjectService.Filter();
|
||||||
filter.setSupervisor(SciProSession.get().getUser());
|
filter.setSupervisor(SciProSession.get().getUser());
|
||||||
filter.setRoles(Collections.singleton(ProjectTeamMemberRoles.CO_SUPERVISOR));
|
filter.setRoles(Collections.singleton(ProjectTeamMemberRoles.CO_SUPERVISOR));
|
||||||
filter.setStatuses(Collections.singletonList(ProjectStatus.ACTIVE));
|
filter.setStatuses(Collections.singletonList(ProjectStatus.ACTIVE));
|
||||||
filter.setProjectTypes(projectTypes.getModelObject());
|
return projectService.findAll(filter);
|
||||||
List<Project> all = projectService.findAll(filter);
|
|
||||||
all.removeAll(currentProjects);
|
|
||||||
all.remove(null);
|
|
||||||
return new ListModel<>(all);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoadableDetachableModel<Project> getLoaded(final Project project) {
|
private static final class SelectProjectModel extends AbstractCheckBoxModel {
|
||||||
return new LoadableDetachableModel<>() {
|
|
||||||
@Override
|
private final IModel<Group> groupModel;
|
||||||
protected Project load() {
|
private final IModel<Project> projectModel;
|
||||||
return projectService.findOne(project.getId());
|
|
||||||
}
|
public SelectProjectModel(IModel<Group> groupModel, IModel<Project> projectModel) {
|
||||||
};
|
this.groupModel = groupModel;
|
||||||
|
this.projectModel = projectModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSelected() {
|
||||||
|
return groupModel.getObject().getProjects().contains(projectModel.getObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void select() {
|
||||||
|
groupModel.getObject().getProjects().add(projectModel.getObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unselect() {
|
||||||
|
groupModel.getObject().getProjects().remove(projectModel.getObject());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -607,3 +607,27 @@ th.wicket_orderUp, th.sorting_asc {
|
|||||||
.line-length-limit {
|
.line-length-limit {
|
||||||
max-width: 80em;
|
max-width: 80em;
|
||||||
}
|
}
|
||||||
|
.group-project-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1em;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(30em, 1fr));
|
||||||
|
}
|
||||||
|
.group-project-grid > * {
|
||||||
|
background: linear-gradient(to left, white 40%, var(--bs-success-bg-subtle) 60%) right;
|
||||||
|
background-size: 250% 100%;
|
||||||
|
transition: background 0.4s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.group-project-grid > *:has(:checked) {
|
||||||
|
background-position: left;
|
||||||
|
}
|
||||||
|
.group-project-grid label {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
@ -27,7 +27,6 @@ public class EditGroupPanelTest extends SciProTest {
|
|||||||
group.setId(1L);
|
group.setId(1L);
|
||||||
Project project = createProject();
|
Project project = createProject();
|
||||||
group.setProjects(new HashSet<>(Collections.singletonList(project)));
|
group.setProjects(new HashSet<>(Collections.singletonList(project)));
|
||||||
when(projectService.findOne(anyLong())).thenReturn(project);
|
|
||||||
startPanel();
|
startPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user