126 session.setAttribute(SESSION_ATTR_SELECTED_VERSION, version); |
127 session.setAttribute(SESSION_ATTR_SELECTED_VERSION, version); |
127 session.setAttribute(SESSION_ATTR_SELECTED_ISSUE, issue); |
128 session.setAttribute(SESSION_ATTR_SELECTED_ISSUE, issue); |
128 } |
129 } |
129 } |
130 } |
130 |
131 |
|
132 private void setAttributeHideZeros(HttpServletRequest req) { |
|
133 final Boolean value; |
|
134 final var param = getParameter(req, Boolean.class, "reduced"); |
|
135 if (param.isPresent()) { |
|
136 value = param.get(); |
|
137 req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); |
|
138 } else { |
|
139 final var sessionValue = req.getSession().getAttribute(SESSION_ATTR_HIDE_ZEROS); |
|
140 if (sessionValue != null) { |
|
141 value = (Boolean) sessionValue; |
|
142 } else { |
|
143 value = false; |
|
144 req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); |
|
145 } |
|
146 } |
|
147 req.setAttribute("statsHideZeros", value); |
|
148 } |
|
149 |
131 @Override |
150 @Override |
132 protected String getResourceBundleName() { |
151 protected String getResourceBundleName() { |
133 return "localization.projects"; |
152 return "localization.projects"; |
134 } |
153 } |
135 |
154 |
|
155 |
|
156 private static final int BREADCRUMB_LEVEL_ROOT = 0; |
|
157 private static final int BREADCRUMB_LEVEL_PROJECT = 1; |
|
158 private static final int BREADCRUMB_LEVEL_VERSION = 2; |
|
159 private static final int BREADCRUMB_LEVEL_ISSUE_LIST = 3; |
|
160 private static final int BREADCRUMB_LEVEL_ISSUE = 4; |
|
161 |
136 /** |
162 /** |
137 * Creates the breadcrumb menu. |
163 * Creates the breadcrumb menu. |
138 * |
164 * |
139 * @param level the current active level (0: root, 1: project, 2: version, 3: issue) |
165 * @param level the current active level (0: root, 1: project, 2: version, 3: issue list, 4: issue) |
140 * @param sessionSelection the currently selected objects |
166 * @param sessionSelection the currently selected objects |
141 * @return a dynamic breadcrumb menu trying to display as many levels as possible |
167 * @return a dynamic breadcrumb menu trying to display as many levels as possible |
142 */ |
168 */ |
143 private List<MenuEntry> getBreadcrumbs(int level, SessionSelection sessionSelection) { |
169 private List<MenuEntry> getBreadcrumbs(int level, SessionSelection sessionSelection) { |
144 MenuEntry entry; |
170 MenuEntry entry; |
145 |
171 |
146 final var breadcrumbs = new ArrayList<MenuEntry>(); |
172 final var breadcrumbs = new ArrayList<MenuEntry>(); |
147 entry = new MenuEntry(new ResourceKey("localization.lightpit", "menu.projects"), |
173 entry = new MenuEntry(new ResourceKey("localization.lightpit", "menu.projects"), |
148 "projects/"); |
174 "projects/"); |
149 breadcrumbs.add(entry); |
175 breadcrumbs.add(entry); |
150 if (level == 0) entry.setActive(true); |
176 if (level == BREADCRUMB_LEVEL_ROOT) entry.setActive(true); |
151 |
177 |
152 if (sessionSelection.project != null) { |
178 if (sessionSelection.project != null) { |
153 if (sessionSelection.project.getId() < 0) { |
179 if (sessionSelection.project.getId() < 0) { |
154 entry = new MenuEntry(new ResourceKey("localization.projects", "button.create"), |
180 entry = new MenuEntry(new ResourceKey("localization.projects", "button.create"), |
155 "projects/edit"); |
181 "projects/edit"); |
156 } else { |
182 } else { |
157 entry = new MenuEntry(sessionSelection.project.getName(), |
183 entry = new MenuEntry(sessionSelection.project.getName(), |
158 "projects/view?pid=" + sessionSelection.project.getId()); |
184 "projects/view?pid=" + sessionSelection.project.getId()); |
159 } |
185 } |
160 if (level == 1) entry.setActive(true); |
186 if (level == BREADCRUMB_LEVEL_PROJECT) entry.setActive(true); |
161 breadcrumbs.add(entry); |
187 breadcrumbs.add(entry); |
162 } |
188 } |
163 |
189 |
164 if (sessionSelection.version != null) { |
190 if (sessionSelection.version != null) { |
165 if (sessionSelection.version.getId() < 0) { |
191 if (sessionSelection.version.getId() < 0) { |
168 } else { |
194 } else { |
169 entry = new MenuEntry(sessionSelection.version.getName(), |
195 entry = new MenuEntry(sessionSelection.version.getName(), |
170 // TODO: change link to issue overview for that version |
196 // TODO: change link to issue overview for that version |
171 "projects/versions/edit?id=" + sessionSelection.version.getId()); |
197 "projects/versions/edit?id=" + sessionSelection.version.getId()); |
172 } |
198 } |
173 if (level == 2) entry.setActive(true); |
199 if (level == BREADCRUMB_LEVEL_VERSION) entry.setActive(true); |
174 breadcrumbs.add(entry); |
200 breadcrumbs.add(entry); |
175 } |
201 } |
176 |
202 |
|
203 if (sessionSelection.project != null) { |
|
204 entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"), |
|
205 // TODO: maybe also add selected version |
|
206 "projects/issues/?pid=" + sessionSelection.project.getId()); |
|
207 if (level == BREADCRUMB_LEVEL_ISSUE_LIST) entry.setActive(true); |
|
208 breadcrumbs.add(entry); |
|
209 } |
|
210 |
177 if (sessionSelection.issue != null) { |
211 if (sessionSelection.issue != null) { |
178 entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"), |
|
179 // TODO: change link to a separate issue view (maybe depending on the selected version) |
|
180 "projects/view?pid=" + sessionSelection.issue.getProject().getId()); |
|
181 breadcrumbs.add(entry); |
|
182 if (sessionSelection.issue.getId() < 0) { |
212 if (sessionSelection.issue.getId() < 0) { |
183 entry = new MenuEntry(new ResourceKey("localization.projects", "button.issue.create"), |
213 entry = new MenuEntry(new ResourceKey("localization.projects", "button.issue.create"), |
184 "projects/issues/edit"); |
214 "projects/issues/edit"); |
185 } else { |
215 } else { |
186 entry = new MenuEntry("#" + sessionSelection.issue.getId(), |
216 entry = new MenuEntry("#" + sessionSelection.issue.getId(), |
187 // TODO: maybe change link to a view rather than directly opening the editor |
217 // TODO: maybe change link to a view rather than directly opening the editor |
188 "projects/issues/edit?id=" + sessionSelection.issue.getId()); |
218 "projects/issues/edit?id=" + sessionSelection.issue.getId()); |
189 } |
219 } |
190 if (level == 3) entry.setActive(true); |
220 if (level == BREADCRUMB_LEVEL_ISSUE) entry.setActive(true); |
191 breadcrumbs.add(entry); |
221 breadcrumbs.add(entry); |
192 } |
222 } |
193 |
223 |
194 return breadcrumbs; |
224 return breadcrumbs; |
195 } |
225 } |
200 final var projectList = dao.getProjectDao().list(); |
230 final var projectList = dao.getProjectDao().list(); |
201 req.setAttribute("projects", projectList); |
231 req.setAttribute("projects", projectList); |
202 setContentPage(req, "projects"); |
232 setContentPage(req, "projects"); |
203 setStylesheet(req, "projects"); |
233 setStylesheet(req, "projects"); |
204 |
234 |
205 setBreadcrumbs(req, getBreadcrumbs(0, sessionSelection)); |
235 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ROOT, sessionSelection)); |
206 |
236 |
207 return ResponseType.HTML; |
237 return ResponseType.HTML; |
208 } |
238 } |
209 |
239 |
210 private void configureEditForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { |
240 private void configureEditForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { |
211 req.setAttribute("project", selection.project); |
241 req.setAttribute("project", selection.project); |
212 req.setAttribute("users", dao.getUserDao().list()); |
242 req.setAttribute("users", dao.getUserDao().list()); |
213 setContentPage(req, "project-form"); |
243 setContentPage(req, "project-form"); |
214 setBreadcrumbs(req, getBreadcrumbs(1, selection)); |
244 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, selection)); |
215 } |
245 } |
216 |
246 |
217 @RequestMapping(requestPath = "edit", method = HttpMethod.GET) |
247 @RequestMapping(requestPath = "edit", method = HttpMethod.GET) |
218 public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException { |
248 public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException { |
219 final var selection = new SessionSelection(req, findByParameter(req, Integer.class, "id", |
249 final var selection = new SessionSelection(req, findByParameter(req, Integer.class, "id", |
251 |
281 |
252 return ResponseType.HTML; |
282 return ResponseType.HTML; |
253 } |
283 } |
254 |
284 |
255 @RequestMapping(requestPath = "view", method = HttpMethod.GET) |
285 @RequestMapping(requestPath = "view", method = HttpMethod.GET) |
256 public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { |
286 public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { |
257 final var sessionSelection = new SessionSelection(req, dao); |
287 final var sessionSelection = new SessionSelection(req, dao); |
258 |
288 if (sessionSelection.project == null) { |
259 req.setAttribute("versions", dao.getVersionDao().list(sessionSelection.project)); |
289 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); |
260 req.setAttribute("issues", dao.getIssueDao().list(sessionSelection.project)); |
290 return ResponseType.NONE; |
261 |
291 } |
262 setBreadcrumbs(req, getBreadcrumbs(1, sessionSelection)); |
292 |
|
293 final var versionDao = dao.getVersionDao(); |
|
294 final var versions = versionDao.list(sessionSelection.project); |
|
295 final var statsAffected = new ArrayList<VersionStatistics>(); |
|
296 final var statsScheduled = new ArrayList<VersionStatistics>(); |
|
297 final var statsResolved = new ArrayList<VersionStatistics>(); |
|
298 for (Version version : versions) { |
|
299 statsAffected.add(versionDao.statsOpenedIssues(version)); |
|
300 statsScheduled.add(versionDao.statsScheduledIssues(version)); |
|
301 statsResolved.add(versionDao.statsResolvedIssues(version)); |
|
302 } |
|
303 |
|
304 setAttributeHideZeros(req); |
|
305 |
|
306 req.setAttribute("versions", versions); |
|
307 req.setAttribute("statsAffected", statsAffected); |
|
308 req.setAttribute("statsScheduled", statsScheduled); |
|
309 req.setAttribute("statsResolved", statsResolved); |
|
310 |
|
311 req.setAttribute("issueStatusEnum", IssueStatus.values()); |
|
312 req.setAttribute("issueCategoryEnum", IssueCategory.values()); |
|
313 |
|
314 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, sessionSelection)); |
263 setContentPage(req, "project-details"); |
315 setContentPage(req, "project-details"); |
|
316 setStylesheet(req, "projects"); |
264 |
317 |
265 return ResponseType.HTML; |
318 return ResponseType.HTML; |
266 } |
319 } |
267 |
320 |
268 private void configureEditVersionForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { |
321 private void configureEditVersionForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { |
|
322 final var versionDao = dao.getVersionDao(); |
269 req.setAttribute("projects", dao.getProjectDao().list()); |
323 req.setAttribute("projects", dao.getProjectDao().list()); |
270 req.setAttribute("version", selection.version); |
324 req.setAttribute("version", selection.version); |
271 req.setAttribute("versionStatusEnum", VersionStatus.values()); |
325 req.setAttribute("versionStatusEnum", VersionStatus.values()); |
272 |
326 |
|
327 req.setAttribute("issueStatusEnum", IssueStatus.values()); |
|
328 req.setAttribute("issueCategoryEnum", IssueCategory.values()); |
|
329 req.setAttribute("statsAffected", versionDao.statsOpenedIssues(selection.version)); |
|
330 req.setAttribute("statsScheduled", versionDao.statsScheduledIssues(selection.version)); |
|
331 req.setAttribute("statsResolved", versionDao.statsResolvedIssues(selection.version)); |
|
332 setAttributeHideZeros(req); |
|
333 |
273 setContentPage(req, "version-form"); |
334 setContentPage(req, "version-form"); |
274 setBreadcrumbs(req, getBreadcrumbs(2, selection)); |
335 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_VERSION, selection)); |
275 } |
336 } |
276 |
337 |
277 @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET) |
338 @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET) |
278 public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { |
339 public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { |
279 final var sessionSelection = new SessionSelection(req, dao); |
340 final var sessionSelection = new SessionSelection(req, dao); |
280 |
341 |
281 sessionSelection.selectVersion(findByParameter(req, Integer.class, "id", dao.getVersionDao()::find) |
342 sessionSelection.selectVersion(findByParameter(req, Integer.class, "id", dao.getVersionDao()::find) |
282 .orElse(new Version(-1, sessionSelection.project))); |
343 .orElse(new Version(-1, sessionSelection.project))); |
283 configureEditVersionForm(req, dao, sessionSelection); |
344 configureEditVersionForm(req, dao, sessionSelection); |
284 |
345 |
285 return ResponseType.HTML; |
346 return ResponseType.HTML; |
286 } |
347 } |
287 |
348 |
288 @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST) |
349 @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST) |
289 public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { |
350 public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { |
290 final var sessionSelection = new SessionSelection(req, dao); |
351 final var sessionSelection = new SessionSelection(req, dao); |
291 |
352 |
292 var version = new Version(-1, sessionSelection.project); |
353 var version = new Version(-1, sessionSelection.project); |
293 try { |
354 try { |
294 version = new Version(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); |
355 version = new Version(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); |
318 req.setAttribute("issueStatusEnum", IssueStatus.values()); |
379 req.setAttribute("issueStatusEnum", IssueStatus.values()); |
319 req.setAttribute("issueCategoryEnum", IssueCategory.values()); |
380 req.setAttribute("issueCategoryEnum", IssueCategory.values()); |
320 req.setAttribute("users", dao.getUserDao().list()); |
381 req.setAttribute("users", dao.getUserDao().list()); |
321 |
382 |
322 setContentPage(req, "issue-form"); |
383 setContentPage(req, "issue-form"); |
323 setBreadcrumbs(req, getBreadcrumbs(3, selection)); |
384 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE, selection)); |
|
385 } |
|
386 |
|
387 @RequestMapping(requestPath = "issues/", method = HttpMethod.GET) |
|
388 public ResponseType issues(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { |
|
389 final var sessionSelection = new SessionSelection(req, dao); |
|
390 if (sessionSelection.project == null) { |
|
391 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); |
|
392 return ResponseType.NONE; |
|
393 } |
|
394 |
|
395 req.setAttribute("issues", dao.getIssueDao().list(sessionSelection.project)); |
|
396 |
|
397 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE_LIST, sessionSelection)); |
|
398 setContentPage(req, "issues"); |
|
399 setStylesheet(req, "projects"); |
|
400 |
|
401 return ResponseType.HTML; |
324 } |
402 } |
325 |
403 |
326 @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET) |
404 @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET) |
327 public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { |
405 public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { |
328 final var sessionSelection = new SessionSelection(req, dao); |
406 final var sessionSelection = new SessionSelection(req, dao); |
329 |
407 |
330 sessionSelection.selectIssue(findByParameter(req, Integer.class, "id", |
408 sessionSelection.selectIssue(findByParameter(req, Integer.class, "id", |
331 dao.getIssueDao()::find).orElse(new Issue(-1, sessionSelection.project))); |
409 dao.getIssueDao()::find).orElse(new Issue(-1, sessionSelection.project))); |
332 configureEditIssueForm(req, dao, sessionSelection); |
410 configureEditIssueForm(req, dao, sessionSelection); |
333 |
411 |
334 return ResponseType.HTML; |
412 return ResponseType.HTML; |
335 } |
413 } |
336 |
414 |
337 @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST) |
415 @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST) |
338 public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { |
416 public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { |
339 final var sessionSelection = new SessionSelection(req, dao); |
417 final var sessionSelection = new SessionSelection(req, dao); |
340 |
418 |
341 Issue issue = new Issue(-1, sessionSelection.project); |
419 Issue issue = new Issue(-1, sessionSelection.project); |
342 try { |
420 try { |
343 issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); |
421 issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); |