30 import com.vladsch.flexmark.html.HtmlRenderer |
30 import com.vladsch.flexmark.html.HtmlRenderer |
31 import com.vladsch.flexmark.parser.Parser |
31 import com.vladsch.flexmark.parser.Parser |
32 import com.vladsch.flexmark.util.data.MutableDataSet |
32 import com.vladsch.flexmark.util.data.MutableDataSet |
33 import com.vladsch.flexmark.util.data.SharedDataKeys |
33 import com.vladsch.flexmark.util.data.SharedDataKeys |
34 import de.uapcore.lightpit.HttpRequest |
34 import de.uapcore.lightpit.HttpRequest |
|
35 import de.uapcore.lightpit.dao.DataAccessObject |
35 import de.uapcore.lightpit.entities.* |
36 import de.uapcore.lightpit.entities.* |
|
37 import de.uapcore.lightpit.logic.compareEtaTo |
36 import de.uapcore.lightpit.types.* |
38 import de.uapcore.lightpit.types.* |
37 import kotlin.math.roundToInt |
39 import kotlin.math.roundToInt |
38 |
40 |
39 class IssueSorter(private vararg val criteria: Criteria) : Comparator<Issue> { |
41 class IssueSorter(private vararg val criteria: Criteria) : Comparator<Issue> { |
40 enum class Field { |
42 enum class Field { |
99 } |
101 } |
100 } |
102 } |
101 |
103 |
102 data class CommitLink(val url: String, val hash: String, val message: String) |
104 data class CommitLink(val url: String, val hash: String, val message: String) |
103 |
105 |
|
106 class IssueOverview( |
|
107 val issues: List<Issue>, |
|
108 val filter: IssueFilter |
|
109 ) : View() { |
|
110 val issueSummary = IssueSummary() |
|
111 |
|
112 init { |
|
113 feedHref = "feed/-/issues.rss" |
|
114 issues.forEach(issueSummary::add) |
|
115 } |
|
116 } |
|
117 |
104 class IssueDetailView( |
118 class IssueDetailView( |
105 val pathInfos: PathInfos, |
|
106 val issue: Issue, |
119 val issue: Issue, |
107 val comments: List<IssueComment>, |
120 val comments: List<IssueComment>, |
108 val project: Project, |
|
109 projectIssues: List<Issue>, |
121 projectIssues: List<Issue>, |
110 val currentRelations: List<IssueRelation>, |
122 val currentRelations: List<IssueRelation>, |
|
123 commitRefs: List<CommitRef>, |
111 /** |
124 /** |
112 * Optional resource key to an error message for the relation editor. |
125 * Optional resource key to an error message for the relation editor. |
113 */ |
126 */ |
114 val relationError: String?, |
127 val relationError: String? = null, |
115 commitRefs: List<CommitRef> |
128 val pathInfos: PathInfos? = null |
116 ) : View() { |
129 ) : View() { |
117 val relationTypes = RelationType.entries |
130 val relationTypes = RelationType.entries |
118 val linkableIssues = projectIssues.filterNot { it.id == issue.id } |
131 val linkableIssues = projectIssues.filterNot { it.id == issue.id } |
119 val commitLinks: List<CommitLink> |
132 val commitLinks: List<CommitLink> |
120 |
133 |
133 issue.description = formatMarkdown(issue.description ?: "") |
146 issue.description = formatMarkdown(issue.description ?: "") |
134 for (comment in comments) { |
147 for (comment in comments) { |
135 comment.commentFormatted = formatMarkdown(comment.comment) |
148 comment.commentFormatted = formatMarkdown(comment.comment) |
136 } |
149 } |
137 |
150 |
138 val commitBaseUrl = project.repoUrl |
151 val commitBaseUrl = issue.project.repoUrl |
139 commitLinks = (if (commitBaseUrl == null || project.vcs == VcsType.None) emptyList() else commitRefs.map { |
152 commitLinks = (if (commitBaseUrl == null || issue.project.vcs == VcsType.None) emptyList() else commitRefs.map { |
140 CommitLink(buildCommitUrl(commitBaseUrl, project.vcs, it.hash), it.hash, it.message) |
153 CommitLink(buildCommitUrl(commitBaseUrl, issue.project.vcs, it.hash), it.hash, it.message) |
141 }) |
154 }) |
142 } |
155 } |
143 |
156 |
144 private fun buildCommitUrl(baseUrl: String, vcs: VcsType, hash: String): String = |
157 private fun buildCommitUrl(baseUrl: String, vcs: VcsType, hash: String): String = |
145 with (StringBuilder(baseUrl)) { |
158 with (StringBuilder(baseUrl)) { |
164 class IssueEditView( |
177 class IssueEditView( |
165 val issue: Issue, |
178 val issue: Issue, |
166 val versions: List<Version>, |
179 val versions: List<Version>, |
167 val components: List<Component>, |
180 val components: List<Component>, |
168 val users: List<User>, |
181 val users: List<User>, |
169 val project: Project, // TODO: allow null values to create issues from the IssuesServlet |
182 val project: Project, |
170 val pathInfos: PathInfos |
183 val pathInfos: PathInfos? = null |
171 ) : EditView() { |
184 ) : EditView() { |
172 |
185 |
173 val versionsUpcoming: List<Version> |
186 val versionsUpcoming: List<Version> |
174 val versionsRecent: List<Version> |
187 val versionsRecent: List<Version> |
175 |
188 |
192 versionsRecent = recent.distinct() |
205 versionsRecent = recent.distinct() |
193 versionsUpcoming = upcoming.distinct() |
206 versionsUpcoming = upcoming.distinct() |
194 } |
207 } |
195 } |
208 } |
196 |
209 |
197 class IssueFilter(http: HttpRequest) { |
210 class IssueFilter(http: HttpRequest, dao: DataAccessObject) { |
198 |
211 |
199 val issueStatus = IssueStatus.entries |
212 val issueStatus = IssueStatus.entries |
200 val issueCategory = IssueCategory.entries |
213 val issueCategory = IssueCategory.entries |
|
214 val users = dao.listUsers().sortedBy(User::shortDisplayname) |
201 val sortCriteria = IssueSorter.Field.entries.flatMap { listOf(IssueSorter.Criteria(it, true), IssueSorter.Criteria(it, false)) } |
215 val sortCriteria = IssueSorter.Field.entries.flatMap { listOf(IssueSorter.Criteria(it, true), IssueSorter.Criteria(it, false)) } |
202 val flagIncludeDone = "f.0" |
216 val flagIncludeDone = "f.0" |
203 val flagMine = "f.1" |
217 val flagMine = "f.1" |
204 val flagBlocker = "f.2" |
218 val flagBlocker = "f.2" |
205 |
219 |
291 ?.split(",") |
305 ?.split(",") |
292 ?.map(String::toInt) |
306 ?.map(String::toInt) |
293 ?: emptyList() |
307 ?: emptyList() |
294 } |
308 } |
295 } |
309 } |
|
310 |
|
311 fun issueFilterFunction( |
|
312 filter: IssueFilter, |
|
313 relationsMap: IssueRelationMap, |
|
314 currentUserName: String |
|
315 ): (issue: Issue) -> Boolean = |
|
316 { |
|
317 (!filter.onlyMine || (it.assignee?.username ?: "") == currentUserName) && |
|
318 (!filter.onlyBlocker || (relationsMap[it.id]?.any { (_, type) -> type.blocking } ?: false)) && |
|
319 (filter.status.isEmpty() || filter.status.contains(it.status)) && |
|
320 (filter.category.isEmpty() || filter.category.contains(it.category)) && |
|
321 (filter.onlyMine || filter.assignee.isEmpty() || filter.assignee.contains(it.assignee?.id ?: -1)) |
|
322 } |