diff -r 3d16ad54b3dc -r 0a658e53177c src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Sat May 30 18:12:38 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Mon Jun 01 14:46:58 2020 +0200 @@ -32,6 +32,7 @@ import de.uapcore.lightpit.*; import de.uapcore.lightpit.dao.DataAccessObjects; import de.uapcore.lightpit.entities.*; +import de.uapcore.lightpit.viewmodel.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +43,10 @@ import java.io.IOException; import java.sql.Date; import java.sql.SQLException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -59,41 +63,81 @@ public static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected_project"); public static final String SESSION_ATTR_SELECTED_ISSUE = fqn(ProjectsModule.class, "selected_issue"); public static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version"); - public static final String SESSION_ATTR_HIDE_ZEROS = fqn(ProjectsModule.class, "stats_hide_zeros"); private class SessionSelection { final HttpSession session; + final HttpServletRequest req; + final DataAccessObjects dao; Project project; Version version; Issue issue; - SessionSelection(HttpServletRequest req, Project project) { - this.session = req.getSession(); - this.project = project; + SessionSelection(HttpServletRequest req, DataAccessObjects dao) { + this.req = req; + this.dao = dao; + session = req.getSession(); + } + + void newProject() { + project = null; version = null; issue = null; updateAttributes(); + project = new Project(-1); + updateAttributes(); } - SessionSelection(HttpServletRequest req, DataAccessObjects dao) throws SQLException { - this.session = req.getSession(); - final var issueDao = dao.getIssueDao(); - final var projectDao = dao.getProjectDao(); - final var issueSelection = getParameter(req, Integer.class, "issue"); - if (issueSelection.isPresent()) { - issue = issueDao.find(issueSelection.get()); - } else { - final var issue = (Issue) session.getAttribute(SESSION_ATTR_SELECTED_ISSUE); - this.issue = issue == null ? null : issueDao.find(issue.getId()); + void newVersion() throws SQLException { + project = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); + syncProject(); + version = null; + issue = null; + updateAttributes(); + version = new Version(-1); + version.setProject(project); + updateAttributes(); + } + + void newIssue() throws SQLException { + project = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); + syncProject(); + version = null; + issue = null; + updateAttributes(); + issue = new Issue(-1); + issue.setProject(project); + updateAttributes(); + } + + void selectVersion(Version selectedVersion) throws SQLException { + issue = null; + version = selectedVersion; + if (!version.getProject().equals(project)) { + project = dao.getProjectDao().find(version.getProject().getId()); } - if (issue != null) { - version = null; // show the issue globally - project = projectDao.find(issue.getProject().getId()); + // our object contains more details + version.setProject(project); + updateAttributes(); + } + + void selectIssue(Issue selectedIssue) throws SQLException { + issue = selectedIssue; + if (!issue.getProject().equals(project)) { + project = dao.getProjectDao().find(issue.getProject().getId()); } + // our object contains more details + issue.setProject(project); + if (!issue.getResolvedVersions().contains(version) && !issue.getScheduledVersions().contains(version) + && !issue.getAffectedVersions().contains(version)) { + version = null; + } + updateAttributes(); + } + void syncProject() throws SQLException { final var projectSelection = getParameter(req, Integer.class, "pid"); if (projectSelection.isPresent()) { - final var selectedProject = projectDao.find(projectSelection.get()); + final var selectedProject = dao.getProjectDao().find(projectSelection.get()); if (!Objects.equals(selectedProject, project)) { // reset version and issue if project changed version = null; @@ -101,51 +145,57 @@ } project = selectedProject; } else { - final var sessionProject = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); - project = sessionProject == null ? null : projectDao.find(sessionProject.getId()); + project = project == null ? null : dao.getProjectDao().find(project.getId()); } + } + + void syncVersion() throws SQLException { + final var versionSelection = getParameter(req, Integer.class, "vid"); + if (versionSelection.isPresent()) { + if (versionSelection.get() < 0) { + version = null; + } else { + final var selectedVersion = dao.getVersionDao().find(versionSelection.get()); + if (!Objects.equals(selectedVersion, version)) { + issue = null; + } + selectVersion(selectedVersion); + } + } else { + version = version == null ? null : dao.getVersionDao().find(version.getId()); + } + } + + void syncIssue() throws SQLException { + final var issueSelection = getParameter(req, Integer.class, "issue"); + if (issueSelection.isPresent()) { + final var selectedIssue = dao.getIssueDao().find(issueSelection.get()); + dao.getIssueDao().joinVersionInformation(selectedIssue); + selectIssue(selectedIssue); + } else { + issue = issue == null ? null : dao.getIssueDao().find(issue.getId()); + } + } + + void sync() throws SQLException { + project = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); + version = (Version) session.getAttribute(SESSION_ATTR_SELECTED_VERSION); + issue = (Issue) session.getAttribute(SESSION_ATTR_SELECTED_ISSUE); + + syncProject(); + syncVersion(); + syncIssue(); + updateAttributes(); } - void selectVersion(Version version) { - this.project = version.getProject(); - this.version = version; - this.issue = null; - updateAttributes(); - } - - void selectIssue(Issue issue) { - this.project = issue.getProject(); - this.issue = issue; - this.version = null; - updateAttributes(); - } - - void updateAttributes() { + private void updateAttributes() { session.setAttribute(SESSION_ATTR_SELECTED_PROJECT, project); session.setAttribute(SESSION_ATTR_SELECTED_VERSION, version); session.setAttribute(SESSION_ATTR_SELECTED_ISSUE, issue); } } - private void setAttributeHideZeros(HttpServletRequest req) { - final Boolean value; - final var param = getParameter(req, Boolean.class, "reduced"); - if (param.isPresent()) { - value = param.get(); - req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); - } else { - final var sessionValue = req.getSession().getAttribute(SESSION_ATTR_HIDE_ZEROS); - if (sessionValue != null) { - value = (Boolean) sessionValue; - } else { - value = false; - req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); - } - } - req.setAttribute("statsHideZeros", value); - } - @Override protected String getResourceBundleName() { return "localization.projects"; @@ -162,10 +212,10 @@ * Creates the breadcrumb menu. * * @param level the current active level (0: root, 1: project, 2: version, 3: issue list, 4: issue) - * @param sessionSelection the currently selected objects + * @param selection the currently selected objects * @return a dynamic breadcrumb menu trying to display as many levels as possible */ - private List getBreadcrumbs(int level, SessionSelection sessionSelection) { + private List getBreadcrumbs(int level, SessionSelection selection) { MenuEntry entry; final var breadcrumbs = new ArrayList(); @@ -174,47 +224,49 @@ breadcrumbs.add(entry); if (level == BREADCRUMB_LEVEL_ROOT) entry.setActive(true); - if (sessionSelection.project != null) { - if (sessionSelection.project.getId() < 0) { + if (selection.project != null) { + if (selection.project.getId() < 0) { entry = new MenuEntry(new ResourceKey("localization.projects", "button.create"), "projects/edit"); } else { - entry = new MenuEntry(sessionSelection.project.getName(), - "projects/view?pid=" + sessionSelection.project.getId()); + entry = new MenuEntry(selection.project.getName(), + "projects/view?pid=" + selection.project.getId()); } if (level == BREADCRUMB_LEVEL_PROJECT) entry.setActive(true); breadcrumbs.add(entry); } - if (sessionSelection.version != null) { - if (sessionSelection.version.getId() < 0) { + if (selection.version != null) { + if (selection.version.getId() < 0) { entry = new MenuEntry(new ResourceKey("localization.projects", "button.version.create"), "projects/versions/edit"); } else { - entry = new MenuEntry(sessionSelection.version.getName(), - // TODO: change link to issue overview for that version - "projects/versions/edit?id=" + sessionSelection.version.getId()); + entry = new MenuEntry(selection.version.getName(), + "projects/versions/view?vid=" + selection.version.getId()); } if (level == BREADCRUMB_LEVEL_VERSION) entry.setActive(true); breadcrumbs.add(entry); } - if (sessionSelection.project != null) { + if (selection.project != null) { + String path = "projects/issues/?pid=" + selection.project.getId(); + if (selection.version != null) { + path += "&vid="+selection.version.getId(); + } entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"), - // TODO: maybe also add selected version - "projects/issues/?pid=" + sessionSelection.project.getId()); + path); if (level == BREADCRUMB_LEVEL_ISSUE_LIST) entry.setActive(true); breadcrumbs.add(entry); } - if (sessionSelection.issue != null) { - if (sessionSelection.issue.getId() < 0) { + if (selection.issue != null) { + if (selection.issue.getId() < 0) { entry = new MenuEntry(new ResourceKey("localization.projects", "button.issue.create"), "projects/issues/edit"); } else { - entry = new MenuEntry("#" + sessionSelection.issue.getId(), + entry = new MenuEntry("#" + selection.issue.getId(), // TODO: maybe change link to a view rather than directly opening the editor - "projects/issues/edit?id=" + sessionSelection.issue.getId()); + "projects/issues/edit?issue=" + selection.issue.getId()); } if (level == BREADCRUMB_LEVEL_ISSUE) entry.setActive(true); breadcrumbs.add(entry); @@ -226,8 +278,22 @@ @RequestMapping(method = HttpMethod.GET) public ResponseType index(HttpServletRequest req, DataAccessObjects dao) throws SQLException { final var sessionSelection = new SessionSelection(req, dao); - final var projectList = dao.getProjectDao().list(); - req.setAttribute("projects", projectList); + sessionSelection.sync(); + + final var projectDao = dao.getProjectDao(); + final var versionDao = dao.getVersionDao(); + + final var projectList = projectDao.list(); + + final var viewModel = new ProjectIndexView(); + for (var project : projectList) { + final var info = new ProjectInfo(project); + info.setVersions(versionDao.list(project)); + info.setIssueSummary(projectDao.getIssueSummary(project)); + viewModel.getProjects().add(info); + } + + setViewModel(req, viewModel); setContentPage(req, "projects"); setStylesheet(req, "projects"); @@ -236,17 +302,24 @@ return ResponseType.HTML; } - private void configureEditForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { - req.setAttribute("project", selection.project); - req.setAttribute("users", dao.getUserDao().list()); + private ProjectEditView configureEditForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { + final var viewModel = new ProjectEditView(); + viewModel.setProject(selection.project); + viewModel.setUsers(dao.getUserDao().list()); + setViewModel(req, viewModel); setContentPage(req, "project-form"); setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, selection)); + return viewModel; } @RequestMapping(requestPath = "edit", method = HttpMethod.GET) public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException { - final var selection = new SessionSelection(req, findByParameter(req, Integer.class, "id", - dao.getProjectDao()::find).orElse(new Project(-1))); + final var selection = new SessionSelection(req, dao); + if (getParameter(req, Integer.class, "pid").isEmpty()) { + selection.newProject(); + } else { + selection.sync(); + } configureEditForm(req, dao, selection); @@ -272,10 +345,12 @@ setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); LOG.debug("Successfully updated project {}", project.getName()); } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { - // TODO: set request attribute with error text LOG.warn("Form validation failure: {}", ex.getMessage()); LOG.debug("Details:", ex); - configureEditForm(req, dao, new SessionSelection(req, project)); + final var selection = new SessionSelection(req, dao); + selection.project = project; + final var vm = configureEditForm(req, dao, selection); + vm.setErrorText(ex.getMessage()); // TODO: error text } return ResponseType.HTML; @@ -283,127 +358,143 @@ @RequestMapping(requestPath = "view", method = HttpMethod.GET) public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { - final var sessionSelection = new SessionSelection(req, dao); - if (sessionSelection.project == null) { + final var selection = new SessionSelection(req, dao); + selection.sync(); + + if (selection.project == null) { resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); return ResponseType.NONE; } final var versionDao = dao.getVersionDao(); - final var versions = versionDao.list(sessionSelection.project); - final var statsAffected = new ArrayList(); - final var statsScheduled = new ArrayList(); - final var statsResolved = new ArrayList(); - for (Version version : versions) { - statsAffected.add(versionDao.statsOpenedIssues(version)); - statsScheduled.add(versionDao.statsScheduledIssues(version)); - statsResolved.add(versionDao.statsResolvedIssues(version)); - } + final var issueDao = dao.getIssueDao(); - setAttributeHideZeros(req); + final var viewModel = new ProjectView(selection.project); + final var issues = issueDao.list(selection.project); + for (var issue : issues) issueDao.joinVersionInformation(issue); + viewModel.setIssues(issues); + viewModel.setVersions(versionDao.list(selection.project)); + viewModel.updateVersionInfo(); + setViewModel(req, viewModel); - req.setAttribute("project", sessionSelection.project); - req.setAttribute("versions", versions); - req.setAttribute("statsAffected", statsAffected); - req.setAttribute("statsScheduled", statsScheduled); - req.setAttribute("statsResolved", statsResolved); - - req.setAttribute("issueStatusEnum", IssueStatus.values()); - req.setAttribute("issueCategoryEnum", IssueCategory.values()); - - setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, sessionSelection)); + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, selection)); setContentPage(req, "project-details"); setStylesheet(req, "projects"); return ResponseType.HTML; } - private void configureEditVersionForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { - final var versionDao = dao.getVersionDao(); - req.setAttribute("projects", dao.getProjectDao().list()); - req.setAttribute("version", selection.version); - req.setAttribute("versionStatusEnum", VersionStatus.values()); + @RequestMapping(requestPath = "versions/view", method = HttpMethod.GET) + public ResponseType viewVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { + final var selection = new SessionSelection(req, dao); + selection.sync(); + if (selection.version == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; + } - req.setAttribute("issueStatusEnum", IssueStatus.values()); - req.setAttribute("issueCategoryEnum", IssueCategory.values()); - req.setAttribute("statsAffected", versionDao.statsOpenedIssues(selection.version)); - req.setAttribute("statsScheduled", versionDao.statsScheduledIssues(selection.version)); - req.setAttribute("statsResolved", versionDao.statsResolvedIssues(selection.version)); - setAttributeHideZeros(req); + final var issueDao = dao.getIssueDao(); + final var viewModel = new VersionView(selection.version); + final var issues = issueDao.list(selection.version); + for (var issue : issues) issueDao.joinVersionInformation(issue); + viewModel.setIssues(issues); + setViewModel(req, viewModel); + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_VERSION, selection)); + setContentPage(req, "version"); + setStylesheet(req, "projects"); + + return ResponseType.HTML; + } + + private VersionEditView configureEditVersionForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { + final var viewModel = new VersionEditView(selection.version); + if (selection.version.getProject() == null) { + viewModel.setProjects(dao.getProjectDao().list()); + } + setViewModel(req, viewModel); setContentPage(req, "version-form"); setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_VERSION, selection)); + return viewModel; } @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET) - public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { - final var sessionSelection = new SessionSelection(req, dao); + public ResponseType editVersion(HttpServletRequest req, DataAccessObjects dao) throws SQLException { + final var selection = new SessionSelection(req, dao); + if (getParameter(req, Integer.class, "vid").isEmpty()) { + selection.newVersion(); + } else { + selection.sync(); + } - sessionSelection.selectVersion(findByParameter(req, Integer.class, "id", dao.getVersionDao()::find) - .orElse(new Version(-1, sessionSelection.project))); - configureEditVersionForm(req, dao, sessionSelection); + configureEditVersionForm(req, dao, selection); return ResponseType.HTML; } @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST) public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { - final var sessionSelection = new SessionSelection(req, dao); - var version = new Version(-1, sessionSelection.project); + var version = new Version(-1); try { - version = new Version(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); + version = new Version(getParameter(req, Integer.class, "id").orElseThrow()); + version.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow())); version.setName(getParameter(req, String.class, "name").orElseThrow()); getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal); version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow())); dao.getVersionDao().saveOrUpdate(version); // specifying the pid parameter will purposely reset the session selected version! - setRedirectLocation(req, "./projects/view?pid="+sessionSelection.project.getId()); + setRedirectLocation(req, "./projects/view?pid="+version.getProject().getId()); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); - LOG.debug("Successfully updated version {} for project {}", version.getName(), sessionSelection.project.getName()); } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { - // TODO: set request attribute with error text LOG.warn("Form validation failure: {}", ex.getMessage()); LOG.debug("Details:", ex); - sessionSelection.selectVersion(version); - configureEditVersionForm(req, dao, sessionSelection); + final var selection = new SessionSelection(req, dao); + selection.selectVersion(version); + final var viewModel = configureEditVersionForm(req, dao, selection); + // TODO: set Error Text } return ResponseType.HTML; } - private void configureEditIssueForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { + private IssueEditView configureEditIssueForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { + final var viewModel = new IssueEditView(selection.issue); - if (selection.issue.getProject() == null || selection.issue.getProject().getId() < 0) { - req.setAttribute("projects", dao.getProjectDao().list()); - req.setAttribute("versions", Collections.emptyList()); + if (selection.issue.getProject() == null) { + viewModel.setProjects(dao.getProjectDao().list()); } else { - req.setAttribute("projects", Collections.emptyList()); - req.setAttribute("versions", dao.getVersionDao().list(selection.issue.getProject())); + viewModel.setVersions(dao.getVersionDao().list(selection.issue.getProject())); } - - dao.getIssueDao().joinVersionInformation(selection.issue); - req.setAttribute("issue", selection.issue); - req.setAttribute("issueStatusEnum", IssueStatus.values()); - req.setAttribute("issueCategoryEnum", IssueCategory.values()); - req.setAttribute("users", dao.getUserDao().list()); + viewModel.setUsers(dao.getUserDao().list()); + setViewModel(req, viewModel); setContentPage(req, "issue-form"); setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE, selection)); + return viewModel; } @RequestMapping(requestPath = "issues/", method = HttpMethod.GET) public ResponseType issues(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { - final var sessionSelection = new SessionSelection(req, dao); - if (sessionSelection.project == null) { + final var selection = new SessionSelection(req, dao); + selection.sync(); + if (selection.project == null) { resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); return ResponseType.NONE; } - req.setAttribute("issues", dao.getIssueDao().list(sessionSelection.project)); + final var viewModel = new IssuesView(); + viewModel.setProject(selection.project); + if (selection.version == null) { + viewModel.setIssues(dao.getIssueDao().list(selection.project)); + } else { + viewModel.setVersion(selection.version); + viewModel.setIssues(dao.getIssueDao().list(selection.version)); + } + setViewModel(req, viewModel); - setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE_LIST, sessionSelection)); + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE_LIST, selection)); setContentPage(req, "issues"); setStylesheet(req, "projects"); @@ -412,22 +503,25 @@ @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET) public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { - final var sessionSelection = new SessionSelection(req, dao); + final var selection = new SessionSelection(req, dao); + if (getParameter(req, Integer.class, "issue").isEmpty()) { + selection.newIssue(); + } else { + selection.sync(); + } - sessionSelection.selectIssue(findByParameter(req, Integer.class, "id", - dao.getIssueDao()::find).orElse(new Issue(-1, sessionSelection.project))); - configureEditIssueForm(req, dao, sessionSelection); + configureEditIssueForm(req, dao, selection); return ResponseType.HTML; } @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST) public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { - final var sessionSelection = new SessionSelection(req, dao); - Issue issue = new Issue(-1, sessionSelection.project); + Issue issue = new Issue(-1); try { - issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); + issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow()); + issue.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow())); getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory); getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus); issue.setSubject(getParameter(req, String.class, "subject").orElseThrow()); @@ -440,17 +534,17 @@ getParameter(req, Integer[].class, "affected") .map(Stream::of) .map(stream -> - stream.map(id -> new Version(id, sessionSelection.project)).collect(Collectors.toList()) + stream.map(Version::new).collect(Collectors.toList()) ).ifPresent(issue::setAffectedVersions); getParameter(req, Integer[].class, "scheduled") .map(Stream::of) .map(stream -> - stream.map(id -> new Version(id, sessionSelection.project)).collect(Collectors.toList()) + stream.map(Version::new).collect(Collectors.toList()) ).ifPresent(issue::setScheduledVersions); getParameter(req, Integer[].class, "resolved") .map(Stream::of) .map(stream -> - stream.map(id -> new Version(id, sessionSelection.project)).collect(Collectors.toList()) + stream.map(Version::new).collect(Collectors.toList()) ).ifPresent(issue::setResolvedVersions); dao.getIssueDao().saveOrUpdate(issue); @@ -458,13 +552,14 @@ // specifying the issue parameter keeps the edited issue as breadcrumb setRedirectLocation(req, "./projects/issues/?issue="+issue.getId()); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); - LOG.debug("Successfully updated issue {} for project {}", issue.getId(), sessionSelection.project.getName()); } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { // TODO: set request attribute with error text LOG.warn("Form validation failure: {}", ex.getMessage()); LOG.debug("Details:", ex); - sessionSelection.selectIssue(issue); - configureEditIssueForm(req, dao, sessionSelection); + final var selection = new SessionSelection(req, dao); + selection.selectIssue(issue); + final var viewModel = configureEditIssueForm(req, dao, selection); + // TODO: set Error Text } return ResponseType.HTML;