Fri, 23 Oct 2020 13:29:33 +0200
adds issue detail view - fixes #24
--- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Fri Oct 23 12:38:20 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Fri Oct 23 13:29:33 2020 +0200 @@ -422,16 +422,39 @@ private void configureIssueEditor(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException { final var project = viewModel.getProjectInfo().getProject(); - issue.setProject(project); + issue.setProject(project); // automatically set current project for new issues viewModel.setIssue(issue); viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions()); viewModel.setUsers(dao.getUserDao().list()); viewModel.setComponents(dao.getComponentDao().list(project)); - if (issue.getId() >= 0) { - viewModel.setComments(dao.getIssueDao().listComments(issue)); - } } + @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET) + public ResponseType viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { + final var viewModel = new IssueDetailView(); + populate(viewModel, pathParameters, dao); + + final var projectInfo = viewModel.getProjectInfo(); + if (projectInfo == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; + } + + final var issueDao = dao.getIssueDao(); + final var issue = issueDao.find(Functions.parseIntOrZero(pathParameters.get("issue"))); + if (issue == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; + } + + issueDao.joinVersionInformation(issue); + viewModel.setIssue(issue); + viewModel.setComments(issueDao.listComments(issue)); + + return forwardView(req, viewModel, "issue-view"); + } + + // TODO: why should the issue editor be child of $project? @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET) public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { final var viewModel = new IssueEditView(); @@ -522,8 +545,8 @@ dao.getIssueDao().saveOrUpdate(issue, issue.getProject()); - // TODO: fix issue #14 - setRedirectLocation(req, "./projects/" + issue.getProject().getNode() + "/all-components/all-versions/issues/"); + // TODO: fix redirect location + setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view"); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); return ResponseType.HTML; @@ -561,8 +584,8 @@ dao.getIssueDao().saveComment(issueComment); - // TODO: fix redirect location (e.g. after fixing #24) - setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/edit"); + // TODO: fix redirect location + setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view"); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); return ResponseType.HTML;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/IssueDetailView.java Fri Oct 23 13:29:33 2020 +0200 @@ -0,0 +1,28 @@ +package de.uapcore.lightpit.viewmodel; + +import de.uapcore.lightpit.entities.Issue; +import de.uapcore.lightpit.entities.IssueComment; + +import java.util.List; + +public class IssueDetailView extends ProjectView { + private Issue issue; + + private List<IssueComment> comments; + + public void setIssue(Issue issue) { + this.issue = issue; + } + + public Issue getIssue() { + return issue; + } + + public List<IssueComment> getComments() { + return comments; + } + + public void setComments(List<IssueComment> comments) { + this.comments = comments; + } +}
--- a/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java Fri Oct 23 12:38:20 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java Fri Oct 23 13:29:33 2020 +0200 @@ -4,23 +4,12 @@ import java.util.*; -public class IssueEditView extends ProjectView { - private Issue issue; - +public class IssueEditView extends IssueDetailView { private List<Project> projects = Collections.emptyList(); private Set<Version> versionsUpcoming = new HashSet<>(); private Set<Version> versionsRecent = new HashSet<>(); private List<User> users; private List<Component> components; - private List<IssueComment> comments; - - public void setIssue(Issue issue) { - this.issue = issue; - } - - public Issue getIssue() { - return issue; - } public List<Project> getProjects() { return projects; @@ -42,8 +31,8 @@ versionsRecent.clear(); versionsUpcoming.clear(); // keep the current selection, if any - versionsRecent.addAll(issue.getAffectedVersions()); - versionsUpcoming.addAll(issue.getResolvedVersions()); + versionsRecent.addAll(getIssue().getAffectedVersions()); + versionsUpcoming.addAll(getIssue().getResolvedVersions()); for (var v : versions) { if (v.getStatus().isReleased()) { if (!v.getStatus().equals(VersionStatus.Deprecated)) @@ -77,12 +66,4 @@ public IssueCategory[] getIssueCategory() { return IssueCategory.values(); } - - public List<IssueComment> getComments() { - return comments; - } - - public void setComments(List<IssueComment> comments) { - this.comments = comments; - } }
--- a/src/main/resources/localization/projects.properties Fri Oct 23 12:38:20 2020 +0200 +++ b/src/main/resources/localization/projects.properties Fri Oct 23 13:29:33 2020 +0200 @@ -29,6 +29,7 @@ button.version.create=New Version button.version.edit=Edit Version button.issue.create=New Issue +button.issue.edit=Edit Issue button.issue.all=All Issues button.comment=Comment
--- a/src/main/resources/localization/projects_de.properties Fri Oct 23 12:38:20 2020 +0200 +++ b/src/main/resources/localization/projects_de.properties Fri Oct 23 13:29:33 2020 +0200 @@ -29,6 +29,7 @@ button.version.create=Neue Version button.version.edit=Version Bearbeiten button.issue.create=Neuer Vorgang +button.issue.edit=Vorgang Bearbeiten button.issue.all=Alle Vorg\u00e4nge button.comment=Kommentieren
--- a/src/main/webapp/WEB-INF/jsp/issue-form.jsp Fri Oct 23 12:38:20 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/issue-form.jsp Fri Oct 23 13:29:33 2020 +0200 @@ -169,56 +169,20 @@ <tr> <td colspan="2"> <input type="hidden" name="id" value="${issue.id}"/> - <%-- TODO: fix #14 --%> - <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button"> + <c:if test="${issue.id ge 0}"> + <a href="./projects/${issue.project.node}/issues/${issue.id}/view" class="button"> <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> </a> + </c:if> + <c:if test="${issue.id lt 0}"> + <%-- TODO: fix #14 --%> + <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button"> + <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> + </a> + </c:if> <button type="submit"><fmt:message bundle="${lightpit_bundle}" key="button.okay"/></button> </td> </tr> </tfoot> </table> </form> -<hr class="comments-separator"/> -<h2><fmt:message key="issue.comments"/></h2> -<c:if test="${viewmodel.issue.id ge 0}"> -<form id="comment-form" action="./projects/commit-issue-comment" method="post"> - <table class="formtable fullwidth"> - <tbody> - <tr> - <td><textarea rows="5" name="comment" required></textarea></td> - </tr> - </tbody> - <tfoot> - <tr> - <td> - <input type="hidden" name="issueid" value="${issue.id}"/> - <button type="submit"><fmt:message key="button.comment"/></button> - </td> - </tr> - </tfoot> - </table> -</form> - <c:forEach var="comment" items="${viewmodel.comments}"> - <div class="comment"> - <div class="caption"> - <c:if test="${not empty comment.author}"> - <c:out value="${comment.author.displayname}"/> - </c:if> - <c:if test="${empty comment.author}"> - <fmt:message key="issue.comments.anonauthor"/> - </c:if> - </div> - <div class="smalltext"> - <fmt:formatDate type="BOTH" value="${comment.created}" /> - <c:if test="${comment.updateCount gt 0}"> - <!-- TODO: update count --> - </c:if> - </div> - <div class="medskip"> - <c:out value="${comment.comment}"/> - </div> - </div> - </c:forEach> -</c:if> -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/webapp/WEB-INF/jsp/issue-view.jsp Fri Oct 23 13:29:33 2020 +0200 @@ -0,0 +1,186 @@ +<%-- +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + +Copyright 2018 Mike Becker. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--%> +<%@page pageEncoding="UTF-8" %> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + +<jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.IssueDetailView" scope="request"/> +<c:set var="issue" scope="page" value="${viewmodel.issue}" /> + +<table class="formtable fullwidth"> + <colgroup> + <col> + <col style="width: 100%"> + </colgroup> + <tbody> + <c:if test="${viewmodel.issue.id ge 0}"> + <tr> + <th><fmt:message key="issue.id"/></th> + <td>${issue.id}</td> + </tr> + </c:if> + <tr> + <th><fmt:message key="issue.project"/></th> + <td> + <c:out value="${issue.project.name}" /> + </td> + </tr> + <tr> + <th><fmt:message key="issue.created"/></th> + <td><fmt:formatDate value="${issue.created}" /></td> + </tr> + <tr> + <th><fmt:message key="issue.updated"/></th> + <td><fmt:formatDate value="${issue.updated}" /></td> + </tr> + <tr> + <th><fmt:message key="issue.component"/></th> + <td> + <c:if test="${not empty issue.component}"> + <c:out value="${issue.component.name}"/> + </c:if> + <c:if test="${empty issue.component}"> + <fmt:message key="placeholder.null-component"/> + </c:if> + </td> + </tr> + <tr> + <th><fmt:message key="issue.category"/></th> + <td> + <div class="issue-tag ${issue.category}" style="width: auto"> + <fmt:message key="issue.category.${issue.category}" /> + </div> + </td> + </tr> + <tr> + <th><fmt:message key="issue.status"/></th> + <td> + <div class="issue-tag phase-${issue.status.phase}" style="width: auto"> + <fmt:message key="issue.status.${issue.status}" /> + </div> + </td> + </tr> + <tr> + <th><fmt:message key="issue.subject"/></th> + <td><c:out value="${issue.subject}"/></td> + </tr> + <tr> + <th class="vtop"><fmt:message key="issue.description"/></th> + <td> + <textarea readonly rows="10"><c:out value="${issue.description}"/></textarea> + </td> + </tr> + <tr> + <th><fmt:message key="issue.assignee"/></th> + <td> + <c:if test="${not empty issue.assignee}"> + <c:out value="${issue.assignee.displayname}"/> + </c:if> + <c:if test="${empty issue.assignee}"> + <fmt:message key="placeholder.null-assignee" /> + </c:if> + </td> + </tr> + <tr> + <th class="vtop"><fmt:message key="issue.affected-versions"/></th> + <td> + <c:forEach var="version" items="${issue.affectedVersions}"> + <c:out value="${version.name}"/> + </c:forEach> + </td> + </tr> + <tr> + <th class="vtop"><fmt:message key="issue.resolved-versions"/></th> + <td> + <c:forEach var="version" items="${issue.resolvedVersions}"> + <c:out value="${version.name}"/> + </c:forEach> + </td> + </tr> + <tr> + <th><fmt:message key="issue.eta"/></th> + <td><fmt:formatDate value="${issue.eta}" /></td> + </tr> + </tbody> + <tfoot> + <tr> + <td colspan="2"> + <%-- TODO: fix #14 --%> + <a href="./projects/${issue.project.node}/all-components/all-versions/issues/" class="button"> + <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> + </a> + <a href="./projects/${issue.project.node}/issues/${issue.id}/edit" class="button submit"> + <fmt:message key="button.issue.edit"/> + </a> + </td> + </tr> + </tfoot> +</table> + +<hr class="comments-separator"/> +<h2><fmt:message key="issue.comments"/></h2> +<c:if test="${viewmodel.issue.id ge 0}"> +<form id="comment-form" action="./projects/commit-issue-comment" method="post"> + <table class="formtable fullwidth"> + <tbody> + <tr> + <td><textarea rows="5" name="comment" required></textarea></td> + </tr> + </tbody> + <tfoot> + <tr> + <td> + <input type="hidden" name="issueid" value="${issue.id}"/> + <button type="submit"><fmt:message key="button.comment"/></button> + </td> + </tr> + </tfoot> + </table> +</form> + <c:forEach var="comment" items="${viewmodel.comments}"> + <div class="comment"> + <div class="caption"> + <c:if test="${not empty comment.author}"> + <c:out value="${comment.author.displayname}"/> + </c:if> + <c:if test="${empty comment.author}"> + <fmt:message key="issue.comments.anonauthor"/> + </c:if> + </div> + <div class="smalltext"> + <fmt:formatDate type="BOTH" value="${comment.created}" /> + <c:if test="${comment.updateCount gt 0}"> + <!-- TODO: update count --> + </c:if> + </div> + <div class="medskip"> + <c:out value="${comment.comment}"/> + </div> + </div> + </c:forEach> +</c:if> +
--- a/src/main/webapp/WEB-INF/jspf/issue-list.jspf Fri Oct 23 12:38:20 2020 +0200 +++ b/src/main/webapp/WEB-INF/jspf/issue-list.jspf Fri Oct 23 13:29:33 2020 +0200 @@ -17,7 +17,7 @@ <tr> <td> <span class="phase-${issue.status.phase}"> - <a href="./projects/${issue.project.node}/issues/${issue.id}/edit"> + <a href="./projects/${issue.project.node}/issues/${issue.id}/view"> #${issue.id} - <c:out value="${issue.subject}" /> </a> </span>
--- a/src/main/webapp/lightpit.css Fri Oct 23 12:38:20 2020 +0200 +++ b/src/main/webapp/lightpit.css Fri Oct 23 13:29:33 2020 +0200 @@ -145,12 +145,12 @@ background: #f0f0ff; } -button[type=submit] { +button[type=submit], a.button.submit { background: #20a0ff; color: white; } -button[type=submit]:hover { +button[type=submit]:hover, a.button.submit:hover { background: #1090cf; }