Sat, 22 Aug 2020 18:17:06 +0200
first part of navigation redesign
1.1 --- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sat Aug 22 16:25:03 2020 +0200 1.2 +++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sat Aug 22 18:17:06 2020 +0200 1.3 @@ -234,7 +234,7 @@ 1.4 * @param navigationItems the menu entries for the navigation menu 1.5 * @see Constants#REQ_ATTR_NAVIGATION 1.6 */ 1.7 - protected void setNavItems(HttpServletRequest req, List<MenuEntry> navigationItems) { 1.8 + protected void setNavigationMenu(HttpServletRequest req, List<MenuEntry> navigationItems) { 1.9 req.setAttribute(Constants.REQ_ATTR_NAVIGATION, navigationItems); 1.10 } 1.11
2.1 --- a/src/main/java/de/uapcore/lightpit/MenuEntry.java Sat Aug 22 16:25:03 2020 +0200 2.2 +++ b/src/main/java/de/uapcore/lightpit/MenuEntry.java Sat Aug 22 18:17:06 2020 +0200 2.3 @@ -50,13 +50,28 @@ 2.4 */ 2.5 private boolean active = false; 2.6 2.7 + /** 2.8 + * The menu level. 2.9 + */ 2.10 + private int level; 2.11 + 2.12 public MenuEntry(ResourceKey resourceKey, String pathName) { 2.13 + this(0, resourceKey, pathName); 2.14 + } 2.15 + 2.16 + public MenuEntry(String text, String pathName) { 2.17 + this(0, text, pathName); 2.18 + } 2.19 + 2.20 + public MenuEntry(int level, ResourceKey resourceKey, String pathName) { 2.21 + this.level = level; 2.22 this.text = null; 2.23 this.resourceKey = resourceKey; 2.24 this.pathName = pathName; 2.25 } 2.26 2.27 - public MenuEntry(String text, String pathName) { 2.28 + public MenuEntry(int level, String text, String pathName) { 2.29 + this.level = level; 2.30 this.text = text; 2.31 this.resourceKey = null; 2.32 this.pathName = pathName; 2.33 @@ -82,4 +97,11 @@ 2.34 this.active = true; 2.35 } 2.36 2.37 + public int getLevel() { 2.38 + return level; 2.39 + } 2.40 + 2.41 + public void setLevel(int level) { 2.42 + this.level = level; 2.43 + } 2.44 }
3.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Sat Aug 22 16:25:03 2020 +0200 3.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Sat Aug 22 18:17:06 2020 +0200 3.3 @@ -64,6 +64,7 @@ 3.4 public static final String SESSION_ATTR_SELECTED_ISSUE = fqn(ProjectsModule.class, "selected_issue"); 3.5 public static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version"); 3.6 3.7 + // TODO: try to get rid of this shit 3.8 private class SessionSelection { 3.9 final HttpSession session; 3.10 final HttpServletRequest req; 3.11 @@ -169,9 +170,13 @@ 3.12 void syncIssue() throws SQLException { 3.13 final var issueSelection = getParameter(req, Integer.class, "issue"); 3.14 if (issueSelection.isPresent()) { 3.15 - final var selectedIssue = dao.getIssueDao().find(issueSelection.get()); 3.16 - dao.getIssueDao().joinVersionInformation(selectedIssue); 3.17 - selectIssue(selectedIssue); 3.18 + if (issueSelection.get() < 0) { 3.19 + issue = null; 3.20 + } else { 3.21 + final var selectedIssue = dao.getIssueDao().find(issueSelection.get()); 3.22 + dao.getIssueDao().joinVersionInformation(selectedIssue); 3.23 + selectIssue(selectedIssue); 3.24 + } 3.25 } else { 3.26 issue = issue == null ? null : dao.getIssueDao().find(issue.getId()); 3.27 } 3.28 @@ -201,75 +206,67 @@ 3.29 return "localization.projects"; 3.30 } 3.31 3.32 - 3.33 - private static final int NAV_LEVEL_ROOT = 0; 3.34 - private static final int NAV_LEVEL_PROJECT = 1; 3.35 - private static final int NAV_LEVEL_VERSION = 2; 3.36 - private static final int NAV_LEVEL_ISSUE_LIST = 3; 3.37 - private static final int NAV_LEVEL_ISSUE = 4; 3.38 + private String queryParams(Project p, Version v, Issue i) { 3.39 + return String.format("pid=%d&vid=%d&issue=%d", 3.40 + p == null ? -1 : p.getId(), 3.41 + v == null ? -1 : v.getId(), 3.42 + i == null ? -1 : i.getId() 3.43 + ); 3.44 + } 3.45 3.46 /** 3.47 * Creates the navigation menu. 3.48 * 3.49 - * @param level the current active level (0: root, 1: project, 2: version, 3: issue list, 4: issue) 3.50 + * @param projects the list of projects 3.51 * @param selection the currently selected objects 3.52 + * @param projInfo info about the currently selected project or null 3.53 * @return a dynamic navigation menu trying to display as many levels as possible 3.54 */ 3.55 - private List<MenuEntry> getNavMenu(int level, SessionSelection selection) { 3.56 - MenuEntry entry; 3.57 + private List<MenuEntry> getNavMenu(List<Project> projects, SessionSelection selection, ProjectInfo projInfo) { 3.58 + final var navigation = new ArrayList<MenuEntry>(); 3.59 3.60 - final var navigation = new ArrayList<MenuEntry>(); 3.61 - entry = new MenuEntry(new ResourceKey("localization.lightpit", "menu.projects"), 3.62 - "projects/"); 3.63 - navigation.add(entry); 3.64 - if (level == NAV_LEVEL_ROOT) entry.setActive(true); 3.65 + for (Project proj : projects) { 3.66 + final var projEntry = new MenuEntry( 3.67 + proj.getName(), 3.68 + "projects/view?pid=" + proj.getId() 3.69 + ); 3.70 + navigation.add(projEntry); 3.71 + if (proj.equals(selection.project)) { 3.72 + projEntry.setActive(true); 3.73 3.74 - if (selection.project != null) { 3.75 - if (selection.project.getId() < 0) { 3.76 - entry = new MenuEntry(new ResourceKey("localization.projects", "button.create"), 3.77 - "projects/edit"); 3.78 - } else { 3.79 - entry = new MenuEntry(selection.project.getName(), 3.80 - "projects/view?pid=" + selection.project.getId()); 3.81 + // **************** 3.82 + // Versions Section 3.83 + // **************** 3.84 + { 3.85 + final var entry = new MenuEntry(1, 3.86 + new ResourceKey("localization.projects", "menu.versions"), 3.87 + "projects/view?" + queryParams(proj, null, null) 3.88 + ); 3.89 + navigation.add(entry); 3.90 + } 3.91 + 3.92 + final var level2 = new ArrayList<MenuEntry>(); 3.93 + { 3.94 + final var entry = new MenuEntry( 3.95 + new ResourceKey("localization.projects", "filter.all"), 3.96 + "projects/view?" + queryParams(proj, null, null) 3.97 + ); 3.98 + if (selection.version == null) entry.setActive(true); 3.99 + level2.add(entry); 3.100 + } 3.101 + 3.102 + for (Version version : projInfo.getVersions()) { 3.103 + final var entry = new MenuEntry( 3.104 + version.getName(), 3.105 + "projects/versions/view?" + queryParams(proj, version, null) 3.106 + ); 3.107 + if (version.equals(selection.version)) entry.setActive(true); 3.108 + level2.add(entry); 3.109 + } 3.110 + 3.111 + level2.forEach(e -> e.setLevel(2)); 3.112 + navigation.addAll(level2); 3.113 } 3.114 - if (level == NAV_LEVEL_PROJECT) entry.setActive(true); 3.115 - navigation.add(entry); 3.116 - } 3.117 - 3.118 - if (selection.version != null) { 3.119 - if (selection.version.getId() < 0) { 3.120 - entry = new MenuEntry(new ResourceKey("localization.projects", "button.version.create"), 3.121 - "projects/versions/edit"); 3.122 - } else { 3.123 - entry = new MenuEntry(selection.version.getName(), 3.124 - "projects/versions/view?vid=" + selection.version.getId()); 3.125 - } 3.126 - if (level == NAV_LEVEL_VERSION) entry.setActive(true); 3.127 - navigation.add(entry); 3.128 - } 3.129 - 3.130 - if (selection.project != null) { 3.131 - String path = "projects/issues/?pid=" + selection.project.getId(); 3.132 - if (selection.version != null) { 3.133 - path += "&vid=" + selection.version.getId(); 3.134 - } 3.135 - entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"), 3.136 - path); 3.137 - if (level == NAV_LEVEL_ISSUE_LIST) entry.setActive(true); 3.138 - navigation.add(entry); 3.139 - } 3.140 - 3.141 - if (selection.issue != null) { 3.142 - if (selection.issue.getId() < 0) { 3.143 - entry = new MenuEntry(new ResourceKey("localization.projects", "button.issue.create"), 3.144 - "projects/issues/edit"); 3.145 - } else { 3.146 - entry = new MenuEntry("#" + selection.issue.getId(), 3.147 - // TODO: maybe change link to a view rather than directly opening the editor 3.148 - "projects/issues/edit?issue=" + selection.issue.getId()); 3.149 - } 3.150 - if (level == NAV_LEVEL_ISSUE) entry.setActive(true); 3.151 - navigation.add(entry); 3.152 } 3.153 3.154 return navigation; 3.155 @@ -297,18 +294,29 @@ 3.156 setContentPage(req, "projects"); 3.157 setStylesheet(req, "projects"); 3.158 3.159 - setNavItems(req, getNavMenu(NAV_LEVEL_ROOT, sessionSelection)); 3.160 + setNavigationMenu(req, getNavMenu(projectList, sessionSelection, currentProjectInfo(dao, sessionSelection.project))); 3.161 3.162 return ResponseType.HTML; 3.163 } 3.164 3.165 + private ProjectInfo currentProjectInfo(DataAccessObjects dao, Project project) throws SQLException { 3.166 + if (project == null) return null; 3.167 + final var projectDao = dao.getProjectDao(); 3.168 + final var versionDao = dao.getVersionDao(); 3.169 + 3.170 + final var info = new ProjectInfo(project); 3.171 + info.setVersions(versionDao.list(project)); 3.172 + info.setIssueSummary(projectDao.getIssueSummary(project)); 3.173 + return info; 3.174 + } 3.175 + 3.176 private ProjectEditView configureEditForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 3.177 final var viewModel = new ProjectEditView(); 3.178 viewModel.setProject(selection.project); 3.179 viewModel.setUsers(dao.getUserDao().list()); 3.180 + setNavigationMenu(req, getNavMenu(dao.getProjectDao().list(), selection, currentProjectInfo(dao, selection.project))); 3.181 setViewModel(req, viewModel); 3.182 setContentPage(req, "project-form"); 3.183 - setNavItems(req, getNavMenu(NAV_LEVEL_PROJECT, selection)); 3.184 return viewModel; 3.185 } 3.186 3.187 @@ -366,6 +374,7 @@ 3.188 return ResponseType.NONE; 3.189 } 3.190 3.191 + final var projectDao = dao.getProjectDao(); 3.192 final var versionDao = dao.getVersionDao(); 3.193 final var issueDao = dao.getIssueDao(); 3.194 3.195 @@ -373,11 +382,12 @@ 3.196 final var issues = issueDao.list(selection.project); 3.197 for (var issue : issues) issueDao.joinVersionInformation(issue); 3.198 viewModel.setIssues(issues); 3.199 + // TODO: fix duplicated selection of versions (projectInfo also contains these infos) 3.200 viewModel.setVersions(versionDao.list(selection.project)); 3.201 viewModel.updateVersionInfo(); 3.202 setViewModel(req, viewModel); 3.203 3.204 - setNavItems(req, getNavMenu(NAV_LEVEL_PROJECT, selection)); 3.205 + setNavigationMenu(req, getNavMenu(projectDao.list(), selection, currentProjectInfo(dao, selection.project))); 3.206 setContentPage(req, "project-details"); 3.207 setStylesheet(req, "projects"); 3.208 3.209 @@ -393,14 +403,16 @@ 3.210 return ResponseType.NONE; 3.211 } 3.212 3.213 + final var projectDao = dao.getProjectDao(); 3.214 final var issueDao = dao.getIssueDao(); 3.215 + 3.216 final var viewModel = new VersionView(selection.version); 3.217 final var issues = issueDao.list(selection.version); 3.218 for (var issue : issues) issueDao.joinVersionInformation(issue); 3.219 viewModel.setIssues(issues); 3.220 setViewModel(req, viewModel); 3.221 3.222 - setNavItems(req, getNavMenu(NAV_LEVEL_VERSION, selection)); 3.223 + setNavigationMenu(req, getNavMenu(projectDao.list(), selection, currentProjectInfo(dao, selection.project))); 3.224 setContentPage(req, "version"); 3.225 setStylesheet(req, "projects"); 3.226 3.227 @@ -414,7 +426,7 @@ 3.228 } 3.229 setViewModel(req, viewModel); 3.230 setContentPage(req, "version-form"); 3.231 - setNavItems(req, getNavMenu(NAV_LEVEL_VERSION, selection)); 3.232 + setNavigationMenu(req, getNavMenu(dao.getProjectDao().list(), selection, currentProjectInfo(dao, selection.project))); 3.233 return viewModel; 3.234 } 3.235 3.236 @@ -471,7 +483,7 @@ 3.237 setViewModel(req, viewModel); 3.238 3.239 setContentPage(req, "issue-form"); 3.240 - setNavItems(req, getNavMenu(NAV_LEVEL_ISSUE, selection)); 3.241 + setNavigationMenu(req, getNavMenu(dao.getProjectDao().list(), selection, currentProjectInfo(dao, selection.project))); 3.242 return viewModel; 3.243 } 3.244 3.245 @@ -484,17 +496,20 @@ 3.246 return ResponseType.NONE; 3.247 } 3.248 3.249 + final var projectDao = dao.getProjectDao(); 3.250 + final var issueDao = dao.getIssueDao(); 3.251 + 3.252 final var viewModel = new IssuesView(); 3.253 viewModel.setProject(selection.project); 3.254 if (selection.version == null) { 3.255 - viewModel.setIssues(dao.getIssueDao().list(selection.project)); 3.256 + viewModel.setIssues(issueDao.list(selection.project)); 3.257 } else { 3.258 viewModel.setVersion(selection.version); 3.259 - viewModel.setIssues(dao.getIssueDao().list(selection.version)); 3.260 + viewModel.setIssues(issueDao.list(selection.version)); 3.261 } 3.262 setViewModel(req, viewModel); 3.263 3.264 - setNavItems(req, getNavMenu(NAV_LEVEL_ISSUE_LIST, selection)); 3.265 + setNavigationMenu(req, getNavMenu(projectDao.list(), selection, currentProjectInfo(dao, selection.project))); 3.266 setContentPage(req, "issues"); 3.267 setStylesheet(req, "projects"); 3.268
4.1 --- a/src/main/resources/localization/projects.properties Sat Aug 22 16:25:03 2020 +0200 4.2 +++ b/src/main/resources/localization/projects.properties Sat Aug 22 18:17:06 2020 +0200 4.3 @@ -31,6 +31,9 @@ 4.4 4.5 no-projects=Welcome to LightPIT. Start off by creating a new project! 4.6 4.7 +filter.all=all 4.8 + 4.9 +menu.versions=Versions 4.10 menu.issues=Issues 4.11 4.12 name=Name
5.1 --- a/src/main/resources/localization/projects_de.properties Sat Aug 22 16:25:03 2020 +0200 5.2 +++ b/src/main/resources/localization/projects_de.properties Sat Aug 22 18:17:06 2020 +0200 5.3 @@ -31,6 +31,9 @@ 5.4 5.5 no-projects=Wilkommen bei LightPIT. Beginnen Sie mit der Erstellung eines Projektes! 5.6 5.7 +filter.all=alle 5.8 + 5.9 +menu.versions=Versionen 5.10 menu.issues=Vorg\u00e4nge 5.11 5.12 name=Name
6.1 --- a/src/main/webapp/WEB-INF/jsp/project-form.jsp Sat Aug 22 16:25:03 2020 +0200 6.2 +++ b/src/main/webapp/WEB-INF/jsp/project-form.jsp Sat Aug 22 18:17:06 2020 +0200 6.3 @@ -28,8 +28,8 @@ 6.4 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 6.5 <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 6.6 6.7 -<jsp:useBean id="project" type="de.uapcore.lightpit.entities.Project" scope="request"/> 6.8 -<jsp:useBean id="users" type="java.util.List<de.uapcore.lightpit.entities.User>" scope="request"/> 6.9 +<jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.ProjectEditView" scope="request" /> 6.10 +<c:set var="project" scope="page" value="${viewmodel.project}"/> 6.11 6.12 <form action="./projects/commit" method="post"> 6.13 <table class="formtable"> 6.14 @@ -55,7 +55,7 @@ 6.15 <td> 6.16 <select name="owner"> 6.17 <option value="-1"><fmt:message key="placeholder.null-owner"/></option> 6.18 - <c:forEach var="user" items="${users}"> 6.19 + <c:forEach var="user" items="${viewmodel.users}"> 6.20 <option 6.21 <c:if test="${not empty project.owner and user eq project.owner}">selected</c:if> 6.22 value="${user.id}"><c:out value="${user.displayname}"/></option>
7.1 --- a/src/main/webapp/WEB-INF/jspf/menu-entry.jsp Sat Aug 22 16:25:03 2020 +0200 7.2 +++ b/src/main/webapp/WEB-INF/jspf/menu-entry.jsp Sat Aug 22 18:17:06 2020 +0200 7.3 @@ -1,4 +1,4 @@ 7.4 -<div class="menuEntry" 7.5 +<div class="menuEntry level-${menu.level}" 7.6 <c:if test="${menu.active}">data-active</c:if> > 7.7 <a href="${menu.pathName}"> 7.8 <c:if test="${empty menu.resourceKey}">
8.1 --- a/src/main/webapp/lightpit.css Sat Aug 22 16:25:03 2020 +0200 8.2 +++ b/src/main/webapp/lightpit.css Sat Aug 22 18:17:06 2020 +0200 8.3 @@ -61,7 +61,7 @@ 8.4 flex-flow: column; 8.5 position: fixed; 8.6 height: 100%; 8.7 - width: 20ch; 8.8 + width: 30ch; 8.9 border-image-source: linear-gradient(to bottom, #606060, rgba(60, 60, 60, .25)); 8.10 border-image-slice: 1; 8.11 border-right-style: solid; 8.12 @@ -69,7 +69,7 @@ 8.13 } 8.14 8.15 #content-area.sidebar-spacing { 8.16 - margin-left: 20ch; 8.17 + margin-left: 30ch; 8.18 } 8.19 8.20 #mainMenu { 8.21 @@ -79,6 +79,7 @@ 8.22 8.23 #sideMenu { 8.24 background: #f7f7ff; 8.25 + overflow-x: scroll; 8.26 } 8.27 8.28 #mainMenu .menuEntry { 8.29 @@ -88,6 +89,14 @@ 8.30 border-right-color: #9095a1; 8.31 } 8.32 8.33 +#sideMenu .menuEntry { 8.34 + padding-top: .25em; 8.35 + padding-bottom: .25em; 8.36 + border-bottom-style: solid; 8.37 + border-bottom-width: 1pt; 8.38 + border-bottom-color: #d7d7df; 8.39 +} 8.40 + 8.41 #mainMenu .menuEntry[data-active] { 8.42 background: #d0d0d5; 8.43 } 8.44 @@ -96,6 +105,18 @@ 8.45 background: #e7e7ef 8.46 } 8.47 8.48 +#sideMenu .level-0 { 8.49 + padding-left: .25em; 8.50 +} 8.51 + 8.52 +#sideMenu .level-1 { 8.53 + padding-left: .75em; 8.54 +} 8.55 + 8.56 +#sideMenu .level-2 { 8.57 + padding-left: 2em; 8.58 +} 8.59 + 8.60 #content-area { 8.61 padding: 1em; 8.62 }