Sun, 08 Jan 2023 19:32:11 +0100
#15 add sort options
--- a/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt Sun Jan 08 19:32:11 2023 +0100 @@ -191,13 +191,7 @@ val relationsMap = if (needRelationsMap) dao.getIssueRelationMap(project, filter.includeDone) else emptyMap() val issues = dao.listIssues(project, filter.includeDone, version, component) - .sortedWith( - IssueSorter( - IssueSorter.Criteria(IssueSorter.Field.DONE), - IssueSorter.Criteria(IssueSorter.Field.ETA), - IssueSorter.Criteria(IssueSorter.Field.UPDATED, false) - ) - ) + .sortedWith(IssueSorter(filter.sortPrimary, filter.sortSecondary, filter.sortTertiary)) .filter { (!filter.onlyMine || (it.assignee?.username ?: "") == (http.remoteUser ?: "<Anonymous>")) && (!filter.onlyBlocker || (relationsMap[it.id]?.any { (_,type) -> type.blocking }?:false)) &&
--- a/src/main/kotlin/de/uapcore/lightpit/types/IssueCategory.kt Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/kotlin/de/uapcore/lightpit/types/IssueCategory.kt Sun Jan 08 19:32:11 2023 +0100 @@ -26,5 +26,5 @@ package de.uapcore.lightpit.types enum class IssueCategory { - Feature, Improvement, Bug, Task, Test + Bug, Feature, Improvement, Task, Test } \ No newline at end of file
--- a/src/main/kotlin/de/uapcore/lightpit/viewmodel/Issues.kt Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/kotlin/de/uapcore/lightpit/viewmodel/Issues.kt Sun Jan 08 19:32:11 2023 +0100 @@ -38,10 +38,20 @@ class IssueSorter(private vararg val criteria: Criteria) : Comparator<Issue> { enum class Field { - DONE, PHASE, STATUS, CATEGORY, ETA, UPDATED, CREATED + DONE, PHASE, STATUS, CATEGORY, ETA, UPDATED, CREATED; + + val resourceKey: String by lazy { + if (this == DONE) "issue.filter.sort.done" + else if (this == PHASE) "issue.filter.sort.phase" + else "issue.${this.name.lowercase()}" + } } - data class Criteria(val field: Field, val asc: Boolean = true) + data class Criteria(val field: Field, val asc: Boolean = true) { + override fun toString(): String { + return "$field.$asc" + } + } override fun compare(left: Issue, right: Issue): Int { if (left == right) { @@ -170,6 +180,7 @@ val issueStatus = IssueStatus.values() val issueCategory = IssueCategory.values() + val sortCriteria = IssueSorter.Field.values().flatMap { listOf(IssueSorter.Criteria(it, true), IssueSorter.Criteria(it, false)) } val flagIncludeDone = "f.0" val flagMine = "f.1" val flagBlocker = "f.2" @@ -180,6 +191,26 @@ val status: List<IssueStatus> = evalEnum(http, "s") val category: List<IssueCategory> = evalEnum(http, "c") + val sortPrimary: IssueSorter.Criteria = evalSort(http, "primary", IssueSorter.Criteria(IssueSorter.Field.DONE)) + val sortSecondary: IssueSorter.Criteria = evalSort(http, "secondary", IssueSorter.Criteria(IssueSorter.Field.ETA)) + val sortTertiary: IssueSorter.Criteria = evalSort(http, "tertiary", IssueSorter.Criteria(IssueSorter.Field.UPDATED, false)) + + private fun evalSort(http: HttpRequest, prio: String, defaultValue: IssueSorter.Criteria): IssueSorter.Criteria { + val param = http.param("sort_$prio") + if (param != null) { + http.session.removeAttribute("sort_$prio") + val p = param.split(".") + if (p.size > 1) { + try { + http.session.setAttribute("sort_$prio", IssueSorter.Criteria(enumValueOf(p[0]), p[1].toBoolean())) + } catch (_:IllegalArgumentException) { + // ignore malfored values + } + } + } + return http.session.getAttribute("sort_$prio") as IssueSorter.Criteria? ?: defaultValue + } + private fun evalFlag(http: HttpRequest, name: String): Boolean { val param = http.paramArray("filter") if (param.isNotEmpty()) {
--- a/src/main/resources/localization/strings.properties Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/resources/localization/strings.properties Sun Jan 08 19:32:11 2023 +0100 @@ -86,11 +86,11 @@ issue.created=Created issue.description=Description issue.eta=ETA -issue.filter=Filter +issue.filter=Filter and Sorting issue.filter.blocking=show only blocking issue.filter.done=show resolved issue.filter.mine=only assigned to me -issue.filter.more=more filters +issue.filter.more=more filter and sort options issue.id=Issue ID issue.relations=Relations issue.relations.issue=Issue @@ -177,4 +177,9 @@ version.status=Status version=Version issue.relations.type.DefectOf=defect of -issue.relations.type.DefectOf.rev=defect \ No newline at end of file +issue.relations.type.DefectOf.rev=defect +issue.filter.sort.primary=Primary Order +issue.filter.sort.secondary=Secondary Order +issue.filter.sort.tertiary=Tertiary Order +issue.filter.sort.done=resolved +issue.filter.sort.phase=Phase \ No newline at end of file
--- a/src/main/resources/localization/strings_de.properties Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/resources/localization/strings_de.properties Sun Jan 08 19:32:11 2023 +0100 @@ -86,11 +86,11 @@ issue.created=Erstellt issue.description=Beschreibung issue.eta=Zieldatum -issue.filter=Filter +issue.filter=Filter und Sortierung issue.filter.blocking=zeige nur blockierende issue.filter.done=zeige erledigte issue.filter.mine=nur mir zugewiesene -issue.filter.more=mehr Filter +issue.filter.more=mehr Filter und Sortieroptionen issue.id=Vorgangs-ID issue.relations=Beziehungen issue.relations.issue=Vorgang @@ -178,3 +178,8 @@ version=Version issue.relations.type.DefectOf.rev=Fehler issue.relations.type.DefectOf=Fehler von +issue.filter.sort.primary=Prim\u00e4re Sortierung +issue.filter.sort.secondary=Sekund\u00e4re Sortierung +issue.filter.sort.tertiary=Terti\u00e4re Sortierung +issue.filter.sort.done=erledigt +issue.filter.sort.phase=Phase
--- a/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf Sun Jan 08 19:32:11 2023 +0100 @@ -32,7 +32,7 @@ <li>Mehrfachauswahl für Versionen im Vorgang entfernt.</li> <li>RSS Feeds für Projekte hinzugefügt.</li> <li>Vorgangsansicht vereinfacht.</li> - <li>Filteroptionen hinzugefügt.</li> + <li>Filter- und Sortieroptionen hinzugefügt.</li> <li>Möglichkeit zum Deaktivieren einer Komponente hinzugefügt.</li> <li>Datum der Veröffentlichung und des Supportendes zu Versionen hinzugefügt.</li> <li>Gesamtanzahl der Kommentare wird nun angezeigt.</li>
--- a/src/main/webapp/WEB-INF/changelogs/changelog.jspf Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/webapp/WEB-INF/changelogs/changelog.jspf Sun Jan 08 19:32:11 2023 +0100 @@ -32,7 +32,7 @@ <li>Remove multi selection of versions within an issue.</li> <li>Add RSS feeds for projects.</li> <li>Simplify issue view.</li> - <li>Add filtering options.</li> + <li>Add filtering and sorting options.</li> <li>Add possibility to deactivate a component.</li> <li>Add release and end of life dates to versions.</li> <li>Add the total number of comments to the caption.</li>
--- a/src/main/webapp/WEB-INF/jspf/issue-filter.jspf Sun Jan 08 17:57:05 2023 +0100 +++ b/src/main/webapp/WEB-INF/jspf/issue-filter.jspf Sun Jan 08 19:32:11 2023 +0100 @@ -1,6 +1,3 @@ -<%-- - ---%> <form method="GET" id="filter-form"> <div> <label> @@ -53,6 +50,15 @@ </c:forEach> </select> </div> + <c:set var="sortPriority" value="primary"/> + <c:set var="currentSort" value="${viewmodel.filter.sortPrimary}"/> + <%@include file="sort-box.jspf"%> + <c:set var="sortPriority" value="secondary"/> + <c:set var="currentSort" value="${viewmodel.filter.sortSecondary}"/> + <%@include file="sort-box.jspf"%> + <c:set var="sortPriority" value="tertiary"/> + <c:set var="currentSort" value="${viewmodel.filter.sortTertiary}"/> + <%@include file="sort-box.jspf"%> </div> <div class="medskip"> <button name="filter" type="submit"><fmt:message key="button.apply"/></button>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/webapp/WEB-INF/jspf/sort-box.jspf Sun Jan 08 19:32:11 2023 +0100 @@ -0,0 +1,17 @@ +<%-- +Page attribute: + sortPriority: String + currentSort: IssueSorter.Criteria +--%> +<div style="display: inline-block"> + <label class="caption" style="display:block;" for="sort_${sortPriority}"><fmt:message key="issue.filter.sort.${sortPriority}"/></label> + <select id="sort_${sortPriority}" name="sort_${sortPriority}"> + <c:forEach var="criteria" items="${viewmodel.filter.sortCriteria}"> + <option value="${criteria}" <c:if test="${currentSort eq criteria}">selected</c:if> > + <fmt:message key="${criteria.field.resourceKey}"/> + <c:if test="${criteria.asc}">↑</c:if> + <c:if test="${not criteria.asc}">↓</c:if> + </option> + </c:forEach> + </select> +</div>