1.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Sat May 23 14:13:09 2020 +0200 1.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Sun May 24 15:30:43 2020 +0200 1.3 @@ -57,9 +57,10 @@ 1.4 1.5 private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class); 1.6 1.7 - public static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected-project"); 1.8 - public static final String SESSION_ATTR_SELECTED_ISSUE = fqn(ProjectsModule.class, "selected-issue"); 1.9 - public static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected-version"); 1.10 + public static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected_project"); 1.11 + public static final String SESSION_ATTR_SELECTED_ISSUE = fqn(ProjectsModule.class, "selected_issue"); 1.12 + public static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version"); 1.13 + public static final String SESSION_ATTR_HIDE_ZEROS = fqn(ProjectsModule.class, "stats_hide_zeros"); 1.14 1.15 private class SessionSelection { 1.16 final HttpSession session; 1.17 @@ -128,15 +129,40 @@ 1.18 } 1.19 } 1.20 1.21 + private void setAttributeHideZeros(HttpServletRequest req) { 1.22 + final Boolean value; 1.23 + final var param = getParameter(req, Boolean.class, "reduced"); 1.24 + if (param.isPresent()) { 1.25 + value = param.get(); 1.26 + req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); 1.27 + } else { 1.28 + final var sessionValue = req.getSession().getAttribute(SESSION_ATTR_HIDE_ZEROS); 1.29 + if (sessionValue != null) { 1.30 + value = (Boolean) sessionValue; 1.31 + } else { 1.32 + value = false; 1.33 + req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); 1.34 + } 1.35 + } 1.36 + req.setAttribute("statsHideZeros", value); 1.37 + } 1.38 + 1.39 @Override 1.40 protected String getResourceBundleName() { 1.41 return "localization.projects"; 1.42 } 1.43 1.44 + 1.45 + private static final int BREADCRUMB_LEVEL_ROOT = 0; 1.46 + private static final int BREADCRUMB_LEVEL_PROJECT = 1; 1.47 + private static final int BREADCRUMB_LEVEL_VERSION = 2; 1.48 + private static final int BREADCRUMB_LEVEL_ISSUE_LIST = 3; 1.49 + private static final int BREADCRUMB_LEVEL_ISSUE = 4; 1.50 + 1.51 /** 1.52 * Creates the breadcrumb menu. 1.53 * 1.54 - * @param level the current active level (0: root, 1: project, 2: version, 3: issue) 1.55 + * @param level the current active level (0: root, 1: project, 2: version, 3: issue list, 4: issue) 1.56 * @param sessionSelection the currently selected objects 1.57 * @return a dynamic breadcrumb menu trying to display as many levels as possible 1.58 */ 1.59 @@ -147,7 +173,7 @@ 1.60 entry = new MenuEntry(new ResourceKey("localization.lightpit", "menu.projects"), 1.61 "projects/"); 1.62 breadcrumbs.add(entry); 1.63 - if (level == 0) entry.setActive(true); 1.64 + if (level == BREADCRUMB_LEVEL_ROOT) entry.setActive(true); 1.65 1.66 if (sessionSelection.project != null) { 1.67 if (sessionSelection.project.getId() < 0) { 1.68 @@ -157,7 +183,7 @@ 1.69 entry = new MenuEntry(sessionSelection.project.getName(), 1.70 "projects/view?pid=" + sessionSelection.project.getId()); 1.71 } 1.72 - if (level == 1) entry.setActive(true); 1.73 + if (level == BREADCRUMB_LEVEL_PROJECT) entry.setActive(true); 1.74 breadcrumbs.add(entry); 1.75 } 1.76 1.77 @@ -170,15 +196,19 @@ 1.78 // TODO: change link to issue overview for that version 1.79 "projects/versions/edit?id=" + sessionSelection.version.getId()); 1.80 } 1.81 - if (level == 2) entry.setActive(true); 1.82 + if (level == BREADCRUMB_LEVEL_VERSION) entry.setActive(true); 1.83 + breadcrumbs.add(entry); 1.84 + } 1.85 + 1.86 + if (sessionSelection.project != null) { 1.87 + entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"), 1.88 + // TODO: maybe also add selected version 1.89 + "projects/issues/?pid=" + sessionSelection.project.getId()); 1.90 + if (level == BREADCRUMB_LEVEL_ISSUE_LIST) entry.setActive(true); 1.91 breadcrumbs.add(entry); 1.92 } 1.93 1.94 if (sessionSelection.issue != null) { 1.95 - entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"), 1.96 - // TODO: change link to a separate issue view (maybe depending on the selected version) 1.97 - "projects/view?pid=" + sessionSelection.issue.getProject().getId()); 1.98 - breadcrumbs.add(entry); 1.99 if (sessionSelection.issue.getId() < 0) { 1.100 entry = new MenuEntry(new ResourceKey("localization.projects", "button.issue.create"), 1.101 "projects/issues/edit"); 1.102 @@ -187,7 +217,7 @@ 1.103 // TODO: maybe change link to a view rather than directly opening the editor 1.104 "projects/issues/edit?id=" + sessionSelection.issue.getId()); 1.105 } 1.106 - if (level == 3) entry.setActive(true); 1.107 + if (level == BREADCRUMB_LEVEL_ISSUE) entry.setActive(true); 1.108 breadcrumbs.add(entry); 1.109 } 1.110 1.111 @@ -202,7 +232,7 @@ 1.112 setContentPage(req, "projects"); 1.113 setStylesheet(req, "projects"); 1.114 1.115 - setBreadcrumbs(req, getBreadcrumbs(0, sessionSelection)); 1.116 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ROOT, sessionSelection)); 1.117 1.118 return ResponseType.HTML; 1.119 } 1.120 @@ -211,7 +241,7 @@ 1.121 req.setAttribute("project", selection.project); 1.122 req.setAttribute("users", dao.getUserDao().list()); 1.123 setContentPage(req, "project-form"); 1.124 - setBreadcrumbs(req, getBreadcrumbs(1, selection)); 1.125 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, selection)); 1.126 } 1.127 1.128 @RequestMapping(requestPath = "edit", method = HttpMethod.GET) 1.129 @@ -253,29 +283,60 @@ 1.130 } 1.131 1.132 @RequestMapping(requestPath = "view", method = HttpMethod.GET) 1.133 - public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { 1.134 + public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { 1.135 final var sessionSelection = new SessionSelection(req, dao); 1.136 + if (sessionSelection.project == null) { 1.137 + resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); 1.138 + return ResponseType.NONE; 1.139 + } 1.140 1.141 - req.setAttribute("versions", dao.getVersionDao().list(sessionSelection.project)); 1.142 - req.setAttribute("issues", dao.getIssueDao().list(sessionSelection.project)); 1.143 + final var versionDao = dao.getVersionDao(); 1.144 + final var versions = versionDao.list(sessionSelection.project); 1.145 + final var statsAffected = new ArrayList<VersionStatistics>(); 1.146 + final var statsScheduled = new ArrayList<VersionStatistics>(); 1.147 + final var statsResolved = new ArrayList<VersionStatistics>(); 1.148 + for (Version version : versions) { 1.149 + statsAffected.add(versionDao.statsOpenedIssues(version)); 1.150 + statsScheduled.add(versionDao.statsScheduledIssues(version)); 1.151 + statsResolved.add(versionDao.statsResolvedIssues(version)); 1.152 + } 1.153 1.154 - setBreadcrumbs(req, getBreadcrumbs(1, sessionSelection)); 1.155 + setAttributeHideZeros(req); 1.156 + 1.157 + req.setAttribute("versions", versions); 1.158 + req.setAttribute("statsAffected", statsAffected); 1.159 + req.setAttribute("statsScheduled", statsScheduled); 1.160 + req.setAttribute("statsResolved", statsResolved); 1.161 + 1.162 + req.setAttribute("issueStatusEnum", IssueStatus.values()); 1.163 + req.setAttribute("issueCategoryEnum", IssueCategory.values()); 1.164 + 1.165 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, sessionSelection)); 1.166 setContentPage(req, "project-details"); 1.167 + setStylesheet(req, "projects"); 1.168 1.169 return ResponseType.HTML; 1.170 } 1.171 1.172 private void configureEditVersionForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 1.173 + final var versionDao = dao.getVersionDao(); 1.174 req.setAttribute("projects", dao.getProjectDao().list()); 1.175 req.setAttribute("version", selection.version); 1.176 req.setAttribute("versionStatusEnum", VersionStatus.values()); 1.177 1.178 + req.setAttribute("issueStatusEnum", IssueStatus.values()); 1.179 + req.setAttribute("issueCategoryEnum", IssueCategory.values()); 1.180 + req.setAttribute("statsAffected", versionDao.statsOpenedIssues(selection.version)); 1.181 + req.setAttribute("statsScheduled", versionDao.statsScheduledIssues(selection.version)); 1.182 + req.setAttribute("statsResolved", versionDao.statsResolvedIssues(selection.version)); 1.183 + setAttributeHideZeros(req); 1.184 + 1.185 setContentPage(req, "version-form"); 1.186 - setBreadcrumbs(req, getBreadcrumbs(2, selection)); 1.187 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_VERSION, selection)); 1.188 } 1.189 1.190 @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET) 1.191 - public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { 1.192 + public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.193 final var sessionSelection = new SessionSelection(req, dao); 1.194 1.195 sessionSelection.selectVersion(findByParameter(req, Integer.class, "id", dao.getVersionDao()::find) 1.196 @@ -286,7 +347,7 @@ 1.197 } 1.198 1.199 @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST) 1.200 - public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { 1.201 + public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.202 final var sessionSelection = new SessionSelection(req, dao); 1.203 1.204 var version = new Version(-1, sessionSelection.project); 1.205 @@ -320,11 +381,28 @@ 1.206 req.setAttribute("users", dao.getUserDao().list()); 1.207 1.208 setContentPage(req, "issue-form"); 1.209 - setBreadcrumbs(req, getBreadcrumbs(3, selection)); 1.210 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE, selection)); 1.211 + } 1.212 + 1.213 + @RequestMapping(requestPath = "issues/", method = HttpMethod.GET) 1.214 + public ResponseType issues(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { 1.215 + final var sessionSelection = new SessionSelection(req, dao); 1.216 + if (sessionSelection.project == null) { 1.217 + resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); 1.218 + return ResponseType.NONE; 1.219 + } 1.220 + 1.221 + req.setAttribute("issues", dao.getIssueDao().list(sessionSelection.project)); 1.222 + 1.223 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE_LIST, sessionSelection)); 1.224 + setContentPage(req, "issues"); 1.225 + setStylesheet(req, "projects"); 1.226 + 1.227 + return ResponseType.HTML; 1.228 } 1.229 1.230 @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET) 1.231 - public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { 1.232 + public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.233 final var sessionSelection = new SessionSelection(req, dao); 1.234 1.235 sessionSelection.selectIssue(findByParameter(req, Integer.class, "id", 1.236 @@ -335,7 +413,7 @@ 1.237 } 1.238 1.239 @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST) 1.240 - public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { 1.241 + public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.242 final var sessionSelection = new SessionSelection(req, dao); 1.243 1.244 Issue issue = new Issue(-1, sessionSelection.project);