Fri, 23 Oct 2020 13:29:33 +0200
adds issue detail view - fixes #24
1.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Fri Oct 23 12:38:20 2020 +0200 1.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Fri Oct 23 13:29:33 2020 +0200 1.3 @@ -422,16 +422,39 @@ 1.4 1.5 private void configureIssueEditor(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException { 1.6 final var project = viewModel.getProjectInfo().getProject(); 1.7 - issue.setProject(project); 1.8 + issue.setProject(project); // automatically set current project for new issues 1.9 viewModel.setIssue(issue); 1.10 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions()); 1.11 viewModel.setUsers(dao.getUserDao().list()); 1.12 viewModel.setComponents(dao.getComponentDao().list(project)); 1.13 - if (issue.getId() >= 0) { 1.14 - viewModel.setComments(dao.getIssueDao().listComments(issue)); 1.15 - } 1.16 } 1.17 1.18 + @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET) 1.19 + public ResponseType viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { 1.20 + final var viewModel = new IssueDetailView(); 1.21 + populate(viewModel, pathParameters, dao); 1.22 + 1.23 + final var projectInfo = viewModel.getProjectInfo(); 1.24 + if (projectInfo == null) { 1.25 + resp.sendError(HttpServletResponse.SC_NOT_FOUND); 1.26 + return ResponseType.NONE; 1.27 + } 1.28 + 1.29 + final var issueDao = dao.getIssueDao(); 1.30 + final var issue = issueDao.find(Functions.parseIntOrZero(pathParameters.get("issue"))); 1.31 + if (issue == null) { 1.32 + resp.sendError(HttpServletResponse.SC_NOT_FOUND); 1.33 + return ResponseType.NONE; 1.34 + } 1.35 + 1.36 + issueDao.joinVersionInformation(issue); 1.37 + viewModel.setIssue(issue); 1.38 + viewModel.setComments(issueDao.listComments(issue)); 1.39 + 1.40 + return forwardView(req, viewModel, "issue-view"); 1.41 + } 1.42 + 1.43 + // TODO: why should the issue editor be child of $project? 1.44 @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET) 1.45 public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { 1.46 final var viewModel = new IssueEditView(); 1.47 @@ -522,8 +545,8 @@ 1.48 1.49 dao.getIssueDao().saveOrUpdate(issue, issue.getProject()); 1.50 1.51 - // TODO: fix issue #14 1.52 - setRedirectLocation(req, "./projects/" + issue.getProject().getNode() + "/all-components/all-versions/issues/"); 1.53 + // TODO: fix redirect location 1.54 + setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view"); 1.55 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 1.56 1.57 return ResponseType.HTML; 1.58 @@ -561,8 +584,8 @@ 1.59 1.60 dao.getIssueDao().saveComment(issueComment); 1.61 1.62 - // TODO: fix redirect location (e.g. after fixing #24) 1.63 - setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/edit"); 1.64 + // TODO: fix redirect location 1.65 + setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view"); 1.66 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 1.67 1.68 return ResponseType.HTML;
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/IssueDetailView.java Fri Oct 23 13:29:33 2020 +0200 2.3 @@ -0,0 +1,28 @@ 2.4 +package de.uapcore.lightpit.viewmodel; 2.5 + 2.6 +import de.uapcore.lightpit.entities.Issue; 2.7 +import de.uapcore.lightpit.entities.IssueComment; 2.8 + 2.9 +import java.util.List; 2.10 + 2.11 +public class IssueDetailView extends ProjectView { 2.12 + private Issue issue; 2.13 + 2.14 + private List<IssueComment> comments; 2.15 + 2.16 + public void setIssue(Issue issue) { 2.17 + this.issue = issue; 2.18 + } 2.19 + 2.20 + public Issue getIssue() { 2.21 + return issue; 2.22 + } 2.23 + 2.24 + public List<IssueComment> getComments() { 2.25 + return comments; 2.26 + } 2.27 + 2.28 + public void setComments(List<IssueComment> comments) { 2.29 + this.comments = comments; 2.30 + } 2.31 +}
3.1 --- a/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java Fri Oct 23 12:38:20 2020 +0200 3.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java Fri Oct 23 13:29:33 2020 +0200 3.3 @@ -4,23 +4,12 @@ 3.4 3.5 import java.util.*; 3.6 3.7 -public class IssueEditView extends ProjectView { 3.8 - private Issue issue; 3.9 - 3.10 +public class IssueEditView extends IssueDetailView { 3.11 private List<Project> projects = Collections.emptyList(); 3.12 private Set<Version> versionsUpcoming = new HashSet<>(); 3.13 private Set<Version> versionsRecent = new HashSet<>(); 3.14 private List<User> users; 3.15 private List<Component> components; 3.16 - private List<IssueComment> comments; 3.17 - 3.18 - public void setIssue(Issue issue) { 3.19 - this.issue = issue; 3.20 - } 3.21 - 3.22 - public Issue getIssue() { 3.23 - return issue; 3.24 - } 3.25 3.26 public List<Project> getProjects() { 3.27 return projects; 3.28 @@ -42,8 +31,8 @@ 3.29 versionsRecent.clear(); 3.30 versionsUpcoming.clear(); 3.31 // keep the current selection, if any 3.32 - versionsRecent.addAll(issue.getAffectedVersions()); 3.33 - versionsUpcoming.addAll(issue.getResolvedVersions()); 3.34 + versionsRecent.addAll(getIssue().getAffectedVersions()); 3.35 + versionsUpcoming.addAll(getIssue().getResolvedVersions()); 3.36 for (var v : versions) { 3.37 if (v.getStatus().isReleased()) { 3.38 if (!v.getStatus().equals(VersionStatus.Deprecated)) 3.39 @@ -77,12 +66,4 @@ 3.40 public IssueCategory[] getIssueCategory() { 3.41 return IssueCategory.values(); 3.42 } 3.43 - 3.44 - public List<IssueComment> getComments() { 3.45 - return comments; 3.46 - } 3.47 - 3.48 - public void setComments(List<IssueComment> comments) { 3.49 - this.comments = comments; 3.50 - } 3.51 }
4.1 --- a/src/main/resources/localization/projects.properties Fri Oct 23 12:38:20 2020 +0200 4.2 +++ b/src/main/resources/localization/projects.properties Fri Oct 23 13:29:33 2020 +0200 4.3 @@ -29,6 +29,7 @@ 4.4 button.version.create=New Version 4.5 button.version.edit=Edit Version 4.6 button.issue.create=New Issue 4.7 +button.issue.edit=Edit Issue 4.8 button.issue.all=All Issues 4.9 button.comment=Comment 4.10
5.1 --- a/src/main/resources/localization/projects_de.properties Fri Oct 23 12:38:20 2020 +0200 5.2 +++ b/src/main/resources/localization/projects_de.properties Fri Oct 23 13:29:33 2020 +0200 5.3 @@ -29,6 +29,7 @@ 5.4 button.version.create=Neue Version 5.5 button.version.edit=Version Bearbeiten 5.6 button.issue.create=Neuer Vorgang 5.7 +button.issue.edit=Vorgang Bearbeiten 5.8 button.issue.all=Alle Vorg\u00e4nge 5.9 button.comment=Kommentieren 5.10
6.1 --- a/src/main/webapp/WEB-INF/jsp/issue-form.jsp Fri Oct 23 12:38:20 2020 +0200 6.2 +++ b/src/main/webapp/WEB-INF/jsp/issue-form.jsp Fri Oct 23 13:29:33 2020 +0200 6.3 @@ -169,56 +169,20 @@ 6.4 <tr> 6.5 <td colspan="2"> 6.6 <input type="hidden" name="id" value="${issue.id}"/> 6.7 - <%-- TODO: fix #14 --%> 6.8 - <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button"> 6.9 + <c:if test="${issue.id ge 0}"> 6.10 + <a href="./projects/${issue.project.node}/issues/${issue.id}/view" class="button"> 6.11 <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> 6.12 </a> 6.13 + </c:if> 6.14 + <c:if test="${issue.id lt 0}"> 6.15 + <%-- TODO: fix #14 --%> 6.16 + <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button"> 6.17 + <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> 6.18 + </a> 6.19 + </c:if> 6.20 <button type="submit"><fmt:message bundle="${lightpit_bundle}" key="button.okay"/></button> 6.21 </td> 6.22 </tr> 6.23 </tfoot> 6.24 </table> 6.25 </form> 6.26 -<hr class="comments-separator"/> 6.27 -<h2><fmt:message key="issue.comments"/></h2> 6.28 -<c:if test="${viewmodel.issue.id ge 0}"> 6.29 -<form id="comment-form" action="./projects/commit-issue-comment" method="post"> 6.30 - <table class="formtable fullwidth"> 6.31 - <tbody> 6.32 - <tr> 6.33 - <td><textarea rows="5" name="comment" required></textarea></td> 6.34 - </tr> 6.35 - </tbody> 6.36 - <tfoot> 6.37 - <tr> 6.38 - <td> 6.39 - <input type="hidden" name="issueid" value="${issue.id}"/> 6.40 - <button type="submit"><fmt:message key="button.comment"/></button> 6.41 - </td> 6.42 - </tr> 6.43 - </tfoot> 6.44 - </table> 6.45 -</form> 6.46 - <c:forEach var="comment" items="${viewmodel.comments}"> 6.47 - <div class="comment"> 6.48 - <div class="caption"> 6.49 - <c:if test="${not empty comment.author}"> 6.50 - <c:out value="${comment.author.displayname}"/> 6.51 - </c:if> 6.52 - <c:if test="${empty comment.author}"> 6.53 - <fmt:message key="issue.comments.anonauthor"/> 6.54 - </c:if> 6.55 - </div> 6.56 - <div class="smalltext"> 6.57 - <fmt:formatDate type="BOTH" value="${comment.created}" /> 6.58 - <c:if test="${comment.updateCount gt 0}"> 6.59 - <!-- TODO: update count --> 6.60 - </c:if> 6.61 - </div> 6.62 - <div class="medskip"> 6.63 - <c:out value="${comment.comment}"/> 6.64 - </div> 6.65 - </div> 6.66 - </c:forEach> 6.67 -</c:if> 6.68 -
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/main/webapp/WEB-INF/jsp/issue-view.jsp Fri Oct 23 13:29:33 2020 +0200 7.3 @@ -0,0 +1,186 @@ 7.4 +<%-- 7.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 7.6 + 7.7 +Copyright 2018 Mike Becker. All rights reserved. 7.8 + 7.9 +Redistribution and use in source and binary forms, with or without 7.10 +modification, are permitted provided that the following conditions are met: 7.11 + 7.12 +1. Redistributions of source code must retain the above copyright 7.13 +notice, this list of conditions and the following disclaimer. 7.14 + 7.15 +2. Redistributions in binary form must reproduce the above copyright 7.16 +notice, this list of conditions and the following disclaimer in the 7.17 +documentation and/or other materials provided with the distribution. 7.18 + 7.19 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 7.20 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7.21 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 7.22 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 7.23 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 7.24 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 7.25 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 7.26 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 7.27 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 7.28 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 7.29 +--%> 7.30 +<%@page pageEncoding="UTF-8" %> 7.31 +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 7.32 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 7.33 + 7.34 +<jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.IssueDetailView" scope="request"/> 7.35 +<c:set var="issue" scope="page" value="${viewmodel.issue}" /> 7.36 + 7.37 +<table class="formtable fullwidth"> 7.38 + <colgroup> 7.39 + <col> 7.40 + <col style="width: 100%"> 7.41 + </colgroup> 7.42 + <tbody> 7.43 + <c:if test="${viewmodel.issue.id ge 0}"> 7.44 + <tr> 7.45 + <th><fmt:message key="issue.id"/></th> 7.46 + <td>${issue.id}</td> 7.47 + </tr> 7.48 + </c:if> 7.49 + <tr> 7.50 + <th><fmt:message key="issue.project"/></th> 7.51 + <td> 7.52 + <c:out value="${issue.project.name}" /> 7.53 + </td> 7.54 + </tr> 7.55 + <tr> 7.56 + <th><fmt:message key="issue.created"/></th> 7.57 + <td><fmt:formatDate value="${issue.created}" /></td> 7.58 + </tr> 7.59 + <tr> 7.60 + <th><fmt:message key="issue.updated"/></th> 7.61 + <td><fmt:formatDate value="${issue.updated}" /></td> 7.62 + </tr> 7.63 + <tr> 7.64 + <th><fmt:message key="issue.component"/></th> 7.65 + <td> 7.66 + <c:if test="${not empty issue.component}"> 7.67 + <c:out value="${issue.component.name}"/> 7.68 + </c:if> 7.69 + <c:if test="${empty issue.component}"> 7.70 + <fmt:message key="placeholder.null-component"/> 7.71 + </c:if> 7.72 + </td> 7.73 + </tr> 7.74 + <tr> 7.75 + <th><fmt:message key="issue.category"/></th> 7.76 + <td> 7.77 + <div class="issue-tag ${issue.category}" style="width: auto"> 7.78 + <fmt:message key="issue.category.${issue.category}" /> 7.79 + </div> 7.80 + </td> 7.81 + </tr> 7.82 + <tr> 7.83 + <th><fmt:message key="issue.status"/></th> 7.84 + <td> 7.85 + <div class="issue-tag phase-${issue.status.phase}" style="width: auto"> 7.86 + <fmt:message key="issue.status.${issue.status}" /> 7.87 + </div> 7.88 + </td> 7.89 + </tr> 7.90 + <tr> 7.91 + <th><fmt:message key="issue.subject"/></th> 7.92 + <td><c:out value="${issue.subject}"/></td> 7.93 + </tr> 7.94 + <tr> 7.95 + <th class="vtop"><fmt:message key="issue.description"/></th> 7.96 + <td> 7.97 + <textarea readonly rows="10"><c:out value="${issue.description}"/></textarea> 7.98 + </td> 7.99 + </tr> 7.100 + <tr> 7.101 + <th><fmt:message key="issue.assignee"/></th> 7.102 + <td> 7.103 + <c:if test="${not empty issue.assignee}"> 7.104 + <c:out value="${issue.assignee.displayname}"/> 7.105 + </c:if> 7.106 + <c:if test="${empty issue.assignee}"> 7.107 + <fmt:message key="placeholder.null-assignee" /> 7.108 + </c:if> 7.109 + </td> 7.110 + </tr> 7.111 + <tr> 7.112 + <th class="vtop"><fmt:message key="issue.affected-versions"/></th> 7.113 + <td> 7.114 + <c:forEach var="version" items="${issue.affectedVersions}"> 7.115 + <c:out value="${version.name}"/> 7.116 + </c:forEach> 7.117 + </td> 7.118 + </tr> 7.119 + <tr> 7.120 + <th class="vtop"><fmt:message key="issue.resolved-versions"/></th> 7.121 + <td> 7.122 + <c:forEach var="version" items="${issue.resolvedVersions}"> 7.123 + <c:out value="${version.name}"/> 7.124 + </c:forEach> 7.125 + </td> 7.126 + </tr> 7.127 + <tr> 7.128 + <th><fmt:message key="issue.eta"/></th> 7.129 + <td><fmt:formatDate value="${issue.eta}" /></td> 7.130 + </tr> 7.131 + </tbody> 7.132 + <tfoot> 7.133 + <tr> 7.134 + <td colspan="2"> 7.135 + <%-- TODO: fix #14 --%> 7.136 + <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button"> 7.137 + <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> 7.138 + </a> 7.139 + <a href="./projects/${issue.project.node}/issues/${issue.id}/edit" class="button submit"> 7.140 + <fmt:message key="button.issue.edit"/> 7.141 + </a> 7.142 + </td> 7.143 + </tr> 7.144 + </tfoot> 7.145 +</table> 7.146 + 7.147 +<hr class="comments-separator"/> 7.148 +<h2><fmt:message key="issue.comments"/></h2> 7.149 +<c:if test="${viewmodel.issue.id ge 0}"> 7.150 +<form id="comment-form" action="./projects/commit-issue-comment" method="post"> 7.151 + <table class="formtable fullwidth"> 7.152 + <tbody> 7.153 + <tr> 7.154 + <td><textarea rows="5" name="comment" required></textarea></td> 7.155 + </tr> 7.156 + </tbody> 7.157 + <tfoot> 7.158 + <tr> 7.159 + <td> 7.160 + <input type="hidden" name="issueid" value="${issue.id}"/> 7.161 + <button type="submit"><fmt:message key="button.comment"/></button> 7.162 + </td> 7.163 + </tr> 7.164 + </tfoot> 7.165 + </table> 7.166 +</form> 7.167 + <c:forEach var="comment" items="${viewmodel.comments}"> 7.168 + <div class="comment"> 7.169 + <div class="caption"> 7.170 + <c:if test="${not empty comment.author}"> 7.171 + <c:out value="${comment.author.displayname}"/> 7.172 + </c:if> 7.173 + <c:if test="${empty comment.author}"> 7.174 + <fmt:message key="issue.comments.anonauthor"/> 7.175 + </c:if> 7.176 + </div> 7.177 + <div class="smalltext"> 7.178 + <fmt:formatDate type="BOTH" value="${comment.created}" /> 7.179 + <c:if test="${comment.updateCount gt 0}"> 7.180 + <!-- TODO: update count --> 7.181 + </c:if> 7.182 + </div> 7.183 + <div class="medskip"> 7.184 + <c:out value="${comment.comment}"/> 7.185 + </div> 7.186 + </div> 7.187 + </c:forEach> 7.188 +</c:if> 7.189 +
8.1 --- a/src/main/webapp/WEB-INF/jspf/issue-list.jspf Fri Oct 23 12:38:20 2020 +0200 8.2 +++ b/src/main/webapp/WEB-INF/jspf/issue-list.jspf Fri Oct 23 13:29:33 2020 +0200 8.3 @@ -17,7 +17,7 @@ 8.4 <tr> 8.5 <td> 8.6 <span class="phase-${issue.status.phase}"> 8.7 - <a href="./projects/${issue.project.node}/issues/${issue.id}/edit"> 8.8 + <a href="./projects/${issue.project.node}/issues/${issue.id}/view"> 8.9 #${issue.id} - <c:out value="${issue.subject}" /> 8.10 </a> 8.11 </span>
9.1 --- a/src/main/webapp/lightpit.css Fri Oct 23 12:38:20 2020 +0200 9.2 +++ b/src/main/webapp/lightpit.css Fri Oct 23 13:29:33 2020 +0200 9.3 @@ -145,12 +145,12 @@ 9.4 background: #f0f0ff; 9.5 } 9.6 9.7 -button[type=submit] { 9.8 +button[type=submit], a.button.submit { 9.9 background: #20a0ff; 9.10 color: white; 9.11 } 9.12 9.13 -button[type=submit]:hover { 9.14 +button[type=submit]:hover, a.button.submit:hover { 9.15 background: #1090cf; 9.16 } 9.17