[Notice] Announcing the End of Demo Server [Read me]
issue: Suppor issue creation at any page
@5dfac4deeb095a07db077579f410c56ed474889e
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
... | ... | @@ -6708,6 +6708,11 @@ |
6708 | 6708 |
display: inline-block; |
6709 | 6709 |
} |
6710 | 6710 |
|
6711 |
+.width25px { |
|
6712 |
+ width: 25px; |
|
6713 |
+ display: inline-block; |
|
6714 |
+} |
|
6715 |
+ |
|
6711 | 6716 |
#simple-issue-list { |
6712 | 6717 |
.state-label { |
6713 | 6718 |
font-size: 13px; |
... | ... | @@ -6921,3 +6926,7 @@ |
6921 | 6926 |
color: rgba(0, 0, 0, 0.7); |
6922 | 6927 |
padding: 0 2px; |
6923 | 6928 |
} |
6929 |
+ |
|
6930 |
+.no-margin { |
|
6931 |
+ margin: 0; |
|
6932 |
+} |
--- app/controllers/IssueApp.java
+++ app/controllers/IssueApp.java
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 |
import models.enumeration.Operation; |
18 | 18 |
import models.enumeration.ResourceType; |
19 | 19 |
import models.enumeration.State; |
20 |
+import org.apache.commons.collections.CollectionUtils; |
|
20 | 21 |
import org.apache.commons.lang3.StringUtils; |
21 | 22 |
import org.apache.tika.Tika; |
22 | 23 |
import com.fasterxml.jackson.databind.node.ObjectNode; |
... | ... | @@ -162,6 +163,7 @@ |
162 | 163 |
if(project == null){ |
163 | 164 |
return ok(my_list.render("title.issueList", issues, searchCondition, project)); |
164 | 165 |
} else { |
166 |
+ UserApp.currentUser().visits(project); |
|
165 | 167 |
return ok(list.render("title.issueList", issues, searchCondition, project)); |
166 | 168 |
} |
167 | 169 |
|
... | ... | @@ -281,6 +283,54 @@ |
281 | 283 |
return ok(partial_comments.render(project, issueInfo)); |
282 | 284 |
} |
283 | 285 |
|
286 |
+ public static Result newDirectIssueForm() { |
|
287 |
+ User current = UserApp.currentUser(); |
|
288 |
+ |
|
289 |
+ Project project = null; |
|
290 |
+ // Fallback #1: Favorite projects 1st if exists |
|
291 |
+ if(!CollectionUtils.isEmpty(current.favoriteProjects)) { |
|
292 |
+ project = current.favoriteProjects.get(current.favoriteProjects.size() - 1).project; |
|
293 |
+ } |
|
294 |
+ |
|
295 |
+ // Fallback #2: Last visited project |
|
296 |
+ List<Project> visitedProjects = current.getVisitedProjects(); |
|
297 |
+ if (project == null && !CollectionUtils.isEmpty(visitedProjects)) { |
|
298 |
+ project = visitedProjects.get(0); |
|
299 |
+ } |
|
300 |
+ |
|
301 |
+ if(project != null){ |
|
302 |
+ return newIssueForm(project.owner, project.name); |
|
303 |
+ } else { |
|
304 |
+ flash(Constants.WARNING, Messages.get("project.is.empty")); |
|
305 |
+ return Application.index(); |
|
306 |
+ } |
|
307 |
+ } |
|
308 |
+ |
|
309 |
+ public static Result newDirectMyIssueForm() { |
|
310 |
+ User current = UserApp.currentUser(); |
|
311 |
+ |
|
312 |
+ // Prefixed project. inbox or _private |
|
313 |
+ Project project = Project.findByOwnerAndProjectName(current.loginId, "inbox"); |
|
314 |
+ if( project == null ) { |
|
315 |
+ project = Project.findByOwnerAndProjectName(current.loginId, "_private"); |
|
316 |
+ } |
|
317 |
+ |
|
318 |
+ // Fallback to any other project |
|
319 |
+ if( project == null ) { |
|
320 |
+ List<Project> projects = Project.findProjectsByMember(current.id); |
|
321 |
+ if(!CollectionUtils.isEmpty(projects)) { |
|
322 |
+ project = projects.get(0); |
|
323 |
+ } |
|
324 |
+ } |
|
325 |
+ |
|
326 |
+ if(project != null){ |
|
327 |
+ return newIssueForm(project.owner, project.name); |
|
328 |
+ } else { |
|
329 |
+ flash(Constants.WARNING, Messages.get("project.is.empty")); |
|
330 |
+ return Application.index(); |
|
331 |
+ } |
|
332 |
+ } |
|
333 |
+ |
|
284 | 334 |
@AnonymousCheck(requiresLogin = true, displaysFlashMessage = true) |
285 | 335 |
@IsCreatable(ResourceType.ISSUE_POST) |
286 | 336 |
public static Result newIssueForm(String ownerName, String projectName) { |
--- app/models/RecentProject.java
+++ app/models/RecentProject.java
... | ... | @@ -84,7 +84,6 @@ |
84 | 84 |
if(existed != null){ |
85 | 85 |
existed.delete(); |
86 | 86 |
} |
87 |
- |
|
88 | 87 |
} |
89 | 88 |
|
90 | 89 |
private static void deleteOldestIfOverflow(User user) { |
--- app/models/User.java
+++ app/models/User.java
... | ... | @@ -976,6 +976,15 @@ |
976 | 976 |
projects.addAll(Project.findProjectsByMember(id)); |
977 | 977 |
List<Project> list = new ArrayList<>(); |
978 | 978 |
list.addAll(projects); |
979 |
+ Collections.sort(list, new Comparator<Project>() { |
|
980 |
+ @Override |
|
981 |
+ public int compare(Project lhs, Project rhs) { |
|
982 |
+ if(lhs.owner.compareToIgnoreCase(rhs.owner) == 0) { |
|
983 |
+ return lhs.name.compareToIgnoreCase(rhs.name); |
|
984 |
+ } |
|
985 |
+ return lhs.owner.compareToIgnoreCase(rhs.owner); |
|
986 |
+ } |
|
987 |
+ }); |
|
979 | 988 |
return list; |
980 | 989 |
} |
981 | 990 |
|
--- app/views/common/select2.scala.html
+++ app/views/common/select2.scala.html
... | ... | @@ -34,12 +34,14 @@ |
34 | 34 |
<script id="tplSelect2Projects" type="text/x-jquery-tmpl"> |
35 | 35 |
<div class="usf-group" title="${name}"> |
36 | 36 |
<span class="avatar-wrap smaller"><img src="${avatarURL}" width="16" height="16"></span> |
37 |
+ <span class="loginid">${owner}</span> |
|
37 | 38 |
<span class="name">${name}</span> |
38 | 39 |
</div> |
39 | 40 |
</script> |
40 | 41 |
<script id="tplSelect2ProjectsWithoutAvatar" type="text/x-jquery-tmpl"> |
41 | 42 |
<div class="usf-group" title="${name}"> |
42 |
- <span class="width16px"></span> |
|
43 |
+ <span class="width25px"></span> |
|
44 |
+ <span class="loginid">${owner}</span> |
|
43 | 45 |
<span class="name">${name}</span> |
44 | 46 |
</div> |
45 | 47 |
</script> |
--- app/views/issue/create.scala.html
+++ app/views/issue/create.scala.html
... | ... | @@ -19,6 +19,11 @@ |
19 | 19 |
play.mvc.Http.Context.current().request().getQueryString("parentIssueId") |
20 | 20 |
} |
21 | 21 |
|
22 |
+@isFromGlobalMenuNew = @{ |
|
23 |
+ routes.IssueApp.newDirectIssueForm.toString().equals(requestHeader.path) || |
|
24 |
+ routes.IssueApp.newDirectMyIssueForm.toString().equals(requestHeader.path) |
|
25 |
+} |
|
26 |
+ |
|
22 | 27 |
@projectLayout(Messages(title), project, utils.MenuType.ISSUE) { |
23 | 28 |
@projectMenu(project, utils.MenuType.ISSUE, "main-menu-only") |
24 | 29 |
<div class="page-wrap-outer"> |
... | ... | @@ -157,6 +162,10 @@ |
157 | 162 |
"target": 'textarea[id^=editor-]', |
158 | 163 |
"url" : "@routes.ProjectApp.mentionList(project.owner, project.name)" |
159 | 164 |
}); |
165 |
+ |
|
166 |
+ if(@isFromGlobalMenuNew) { |
|
167 |
+ $(".subtask-message").trigger("click"); |
|
168 |
+ } |
|
160 | 169 |
}); |
161 | 170 |
</script> |
162 | 171 |
} |
--- app/views/issue/partial_select_subtask.scala.html
+++ app/views/issue/partial_select_subtask.scala.html
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 |
<option value="@project.id" data-avatar-url="@urlToProjectLogo(project)">@project.name</option> |
17 | 17 |
@for(movableProject <- UserApp.currentUser().getIssueMovableProject) { |
18 | 18 |
@if(movableProject.id != project.id) { |
19 |
- <option value="@movableProject.id" data-avatar-url="@urlToProjectLogo(movableProject)">@movableProject.name</option> |
|
19 |
+ <option value="@movableProject.id" data-owner="@movableProject.owner /" data-avatar-url="@urlToProjectLogo(movableProject)">@movableProject.name</option> |
|
20 | 20 |
} |
21 | 21 |
} |
22 | 22 |
</select> |
--- conf/messages
+++ conf/messages
... | ... | @@ -289,6 +289,7 @@ |
289 | 289 |
issue.list.commentedByMe = Commented |
290 | 290 |
issue.list.mentionedOfMe = Mentioned |
291 | 291 |
issue.menu.new = New issue |
292 |
+issue.menu.new.mine = New issue - personal |
|
292 | 293 |
issue.myIssue = My issues |
293 | 294 |
issue.new.result = Results |
294 | 295 |
issue.noAssignee = No assignee |
--- conf/messages.ko-KR
+++ conf/messages.ko-KR
... | ... | @@ -290,6 +290,7 @@ |
290 | 290 |
issue.list.commentedByMe = 댓글 남긴 이슈 |
291 | 291 |
issue.list.mentionedOfMe = 나를 언급한 이슈 |
292 | 292 |
issue.menu.new = 새 이슈 |
293 |
+issue.menu.new.mine = 새 이슈 - 개인 |
|
293 | 294 |
issue.myIssue = 내 이슈 |
294 | 295 |
issue.new.result = 확인결과 |
295 | 296 |
issue.noAssignee = 담당자 없음 |
--- conf/routes
+++ conf/routes
... | ... | @@ -95,6 +95,8 @@ |
95 | 95 |
# User |
96 | 96 |
GET /user/issues controllers.IssueApp.userIssuesPage() |
97 | 97 |
GET /user/issues controllers.IssueApp.userIssues(state:String ?= "", format:String ?= "html", pageNum: Int ?= 1) |
98 |
+GET /user/issues/new controllers.IssueApp.newDirectIssueForm() |
|
99 |
+GET /user/issues/new/mine controllers.IssueApp.newDirectMyIssueForm() |
|
98 | 100 |
GET /user/files controllers.UserApp.userFiles() |
99 | 101 |
GET /users/loginform controllers.UserApp.loginForm() |
100 | 102 |
GET /users/login controllers.Application.index() |
--- public/javascripts/common/yobi.ui.Select2.js
+++ public/javascripts/common/yobi.ui.Select2.js
... | ... | @@ -50,14 +50,17 @@ |
50 | 50 |
return !avatarURL || avatarURL.indexOf("project_default_logo.png") !== -1; |
51 | 51 |
} |
52 | 52 |
|
53 |
+ var owner = itemElement.data("owner") ? itemElement.data("owner") : ""; |
|
53 | 54 |
if(_doesntHaveProjectAvatar()){ |
54 | 55 |
return $.tmpl($("#tplSelect2ProjectsWithoutAvatar").text(), { |
55 |
- "name" : itemObject.text |
|
56 |
+ "name" : itemObject.text, |
|
57 |
+ "owner" : owner |
|
56 | 58 |
}); |
57 | 59 |
} else { |
58 | 60 |
return $.tmpl($("#tplSelect2Projects").text(), { |
59 | 61 |
"avatarURL": avatarURL, |
60 |
- "name" : itemObject.text.trim() |
|
62 |
+ "name" : itemObject.text.trim(), |
|
63 |
+ "owner" : owner |
|
61 | 64 |
}); |
62 | 65 |
} |
63 | 66 |
}, |
... | ... | @@ -176,6 +179,15 @@ |
176 | 179 |
loginId = (typeof loginId !== "undefined") ? loginId.toLowerCase() : ""; |
177 | 180 |
|
178 | 181 |
return (loginId.indexOf(term) > -1) || (formattedResult.indexOf(term) > -1); |
182 |
+ }, |
|
183 |
+ "projects": function(term, formattedResult, itemElement){ |
|
184 |
+ term = term.toLowerCase(); |
|
185 |
+ formattedResult = formattedResult.toLowerCase(); |
|
186 |
+ |
|
187 |
+ var owner = itemElement.data("owner") + ""; |
|
188 |
+ owner = (typeof owner !== "undefined") ? owner.toLowerCase() : ""; |
|
189 |
+ |
|
190 |
+ return (owner.indexOf(term) > -1) || (formattedResult.indexOf(term) > -1); |
|
179 | 191 |
} |
180 | 192 |
}; |
181 | 193 |
|
--- public/javascripts/common/yona.Subtask.js
+++ public/javascripts/common/yona.Subtask.js
... | ... | @@ -20,10 +20,12 @@ |
20 | 20 |
var targetProjectName = selected.target.selectedOptions[0].innerText; |
21 | 21 |
if(selected.val === initialProjectId){ |
22 | 22 |
parentId.prop("disabled", false); |
23 |
+ $('#s2id_parentId').show(); |
|
23 | 24 |
parentId.trigger('change.select2'); |
24 | 25 |
} else { |
25 | 26 |
parentId.val(parentId.find("option:first").val()); |
26 | 27 |
parentId.prop("disabled", true); |
28 |
+ $('#s2id_parentId').hide(); |
|
27 | 29 |
parentId.trigger('change.select2'); |
28 | 30 |
$yobi.notify("Issue will be move/write to '" + targetProjectName + "'", 3000); |
29 | 31 |
} |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?