[Notice] Announcing the End of Demo Server [Read me]

Merge pull request #184 from npcode/yobi refs/heads/fix/comment-on-noChangeBetween
@5ee54bb8f4932308ae006cb6cbb9afa5803678b1
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
... | ... | @@ -2734,7 +2734,6 @@ |
2734 | 2734 |
|
2735 | 2735 |
.yobicon-paperclip {vertical-align:middle;margin-top: 4px;} |
2736 | 2736 |
|
2737 |
- |
|
2738 | 2737 |
} |
2739 | 2738 |
.comment-body { |
2740 | 2739 |
font-size: 12px; |
... | ... | @@ -2749,6 +2748,7 @@ |
2749 | 2748 |
.border-radius(2px); |
2750 | 2749 |
} |
2751 | 2750 |
} |
2751 |
+ |
|
2752 | 2752 |
} |
2753 | 2753 |
.attach-preview-wrap { |
2754 | 2754 |
margin-top: 10px; |
... | ... | @@ -2762,8 +2762,32 @@ |
2762 | 2762 |
.meta-info { background-color:#f8f8f8; } |
2763 | 2763 |
|
2764 | 2764 |
.attach { background-color:#f8f8f8; } |
2765 |
- } |
|
2765 |
+ } |
|
2766 |
+ } |
|
2766 | 2767 |
|
2768 |
+ .reply { |
|
2769 |
+ padding:0 20px; |
|
2770 |
+ .media-body { |
|
2771 |
+ border-top:0px; |
|
2772 |
+ .border-radius(0 0 0 0); |
|
2773 |
+ &:before { |
|
2774 |
+ content:none; |
|
2775 |
+ } |
|
2776 |
+ } |
|
2777 |
+ } |
|
2778 |
+ |
|
2779 |
+ .hasReply { |
|
2780 |
+ padding-bottom:0px; |
|
2781 |
+ .media-body { |
|
2782 |
+ .border-radius(3px 3px 0 0); |
|
2783 |
+ } |
|
2784 |
+ } |
|
2785 |
+ |
|
2786 |
+ .last { |
|
2787 |
+ padding-bottom:10px; |
|
2788 |
+ .media-body { |
|
2789 |
+ .border-radius(0 0 3px 3px); |
|
2790 |
+ } |
|
2767 | 2791 |
} |
2768 | 2792 |
|
2769 | 2793 |
.event { |
... | ... | @@ -2771,7 +2795,6 @@ |
2771 | 2795 |
padding:15px 0 15px 75px; |
2772 | 2796 |
font-size:14px; |
2773 | 2797 |
line-height:14px; |
2774 |
- |
|
2775 | 2798 |
.state { |
2776 | 2799 |
color:#FFF; |
2777 | 2800 |
padding: 6px 0; |
... | ... | @@ -4585,4 +4608,4 @@ |
4585 | 4608 |
|
4586 | 4609 |
div.diff-body[data-outdated="true"] tr:hover .icon-comment { |
4587 | 4610 |
visibility: hidden; |
4588 |
-}(No newline at end of file) |
|
4611 |
+} |
--- app/controllers/CodeApp.java
+++ app/controllers/CodeApp.java
... | ... | @@ -70,8 +70,8 @@ |
70 | 70 |
* @param branch 브랜치 이름 |
71 | 71 |
* @param path 파일 경로 |
72 | 72 |
*/ |
73 |
- public static Result codeBrowserWithBranch(String userName, String projectName, String branch, String path) |
|
74 |
- throws UnsupportedOperationException, IOException, SVNException, GitAPIException, ServletException, Exception { |
|
73 |
+ public static Result codeBrowserWithBranch(String userName, String projectName, String branch, String path) |
|
74 |
+ throws UnsupportedOperationException, IOException, SVNException, GitAPIException, ServletException, Exception { |
|
75 | 75 |
Project project = ProjectApp.getProject(userName, projectName); |
76 | 76 |
|
77 | 77 |
if (!RepositoryService.VCS_GIT.equals(project.vcs) && !RepositoryService.VCS_SUBVERSION.equals(project.vcs)) { |
... | ... | @@ -93,14 +93,14 @@ |
93 | 93 |
|
94 | 94 |
return ok(view.render(project, branches, recursiveData, branch, path)); |
95 | 95 |
} |
96 |
- |
|
97 |
- /** |
|
98 |
- * AJAX 호출로 지정한 프로젝트 지정한 경로의 정보를 얻고자 할 때 사용된다 |
|
99 |
- * |
|
100 |
- * @param userName 프로젝트 소유자 이름 |
|
101 |
- * @param projectName 프로젝트 이름 |
|
102 |
- * @param path 파일 또는 폴더의 경로 |
|
103 |
- */ |
|
96 |
+ |
|
97 |
+ /** |
|
98 |
+ * AJAX 호출로 지정한 프로젝트 지정한 경로의 정보를 얻고자 할 때 사용된다 |
|
99 |
+ * |
|
100 |
+ * @param userName 프로젝트 소유자 이름 |
|
101 |
+ * @param projectName 프로젝트 이름 |
|
102 |
+ * @param path 파일 또는 폴더의 경로 |
|
103 |
+ */ |
|
104 | 104 |
public static Result ajaxRequest(String userName, String projectName, String path) throws Exception{ |
105 | 105 |
PlayRepository repository = RepositoryService.getRepository(userName, projectName); |
106 | 106 |
ObjectNode fileInfo = repository.getMetaDataFromPath(path); |
--- app/controllers/HelpApp.java
+++ app/controllers/HelpApp.java
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 |
import views.html.help.*; |
6 | 6 |
|
7 | 7 |
public class HelpApp extends Controller { |
8 |
- public static Result help() { |
|
9 |
- return ok(toc.render("title.help")); |
|
10 |
- } |
|
8 |
+ public static Result help() { |
|
9 |
+ return ok(toc.render("title.help")); |
|
10 |
+ } |
|
11 | 11 |
} |
--- app/controllers/ProjectApp.java
+++ app/controllers/ProjectApp.java
... | ... | @@ -44,21 +44,21 @@ |
44 | 44 |
*/ |
45 | 45 |
public class ProjectApp extends Controller { |
46 | 46 |
|
47 |
- private static final int LOGO_FILE_LIMIT_SIZE = 1024*1000*5; //5M |
|
47 |
+ private static final int LOGO_FILE_LIMIT_SIZE = 1024*1000*5; //5M |
|
48 | 48 |
|
49 |
- /** 프로젝트 로고로 사용할 수 있는 이미지 확장자 */ |
|
49 |
+ /** 프로젝트 로고로 사용할 수 있는 이미지 확장자 */ |
|
50 | 50 |
public static final String[] LOGO_TYPE = {"jpg", "jpeg", "png", "gif", "bmp"}; |
51 | 51 |
|
52 | 52 |
/** 자동완성에서 보여줄 최대 프로젝트 개수 */ |
53 | 53 |
private static final int MAX_FETCH_PROJECTS = 1000; |
54 | 54 |
|
55 |
- private static final int COMMIT_HISTORY_PAGE = 0; |
|
55 |
+ private static final int COMMIT_HISTORY_PAGE = 0; |
|
56 | 56 |
|
57 |
- private static final int COMMIT_HISTORY_SHOW_LIMIT = 10; |
|
57 |
+ private static final int COMMIT_HISTORY_SHOW_LIMIT = 10; |
|
58 | 58 |
|
59 |
- private static final int RECENLTY_ISSUE_SHOW_LIMIT = 10; |
|
59 |
+ private static final int RECENLTY_ISSUE_SHOW_LIMIT = 10; |
|
60 | 60 |
|
61 |
- private static final int RECENLTY_POSTING_SHOW_LIMIT = 10; |
|
61 |
+ private static final int RECENLTY_POSTING_SHOW_LIMIT = 10; |
|
62 | 62 |
|
63 | 63 |
private static final int RECENT_PULL_REQUEST_SHOW_LIMIT = 10; |
64 | 64 |
|
... | ... | @@ -100,7 +100,7 @@ |
100 | 100 |
|
101 | 101 |
if (project == null) { |
102 | 102 |
return notFound(ErrorViews.NotFound.render("error.notfound")); |
103 |
- // No project matches given parameters'" + loginId + "' and project_name '" + projectName + "'")); |
|
103 |
+ // No project matches given parameters'" + loginId + "' and project_name '" + projectName + "'")); |
|
104 | 104 |
} |
105 | 105 |
|
106 | 106 |
project.fixInvalidForkData(); |
... | ... | @@ -113,9 +113,9 @@ |
113 | 113 |
|
114 | 114 |
List<Commit> commits = null; |
115 | 115 |
try { |
116 |
- commits = repository.getHistory(COMMIT_HISTORY_PAGE, COMMIT_HISTORY_SHOW_LIMIT, null, null); |
|
116 |
+ commits = repository.getHistory(COMMIT_HISTORY_PAGE, COMMIT_HISTORY_SHOW_LIMIT, null, null); |
|
117 | 117 |
} catch (NoHeadException e) { |
118 |
- // NOOP |
|
118 |
+ // NOOP |
|
119 | 119 |
} |
120 | 120 |
|
121 | 121 |
List<Issue> issues = Issue.findRecentlyCreated(project, RECENLTY_ISSUE_SHOW_LIMIT); |
... | ... | @@ -127,7 +127,7 @@ |
127 | 127 |
return ok(overview.render("title.projectHome", project, histories)); |
128 | 128 |
} |
129 | 129 |
|
130 |
- /** |
|
130 |
+ /** |
|
131 | 131 |
* 신규 프로젝트 생성 페이지로 이동한다.<p /> |
132 | 132 |
* |
133 | 133 |
* 비로그인 상태({@link models.User#anonymous})이면 로그인 경고메세지와 함께 로그인페이지로 redirect 된다.<br /> |
... | ... | @@ -273,9 +273,9 @@ |
273 | 273 |
* @param filePart |
274 | 274 |
* @return {@code filePart}가 null이면 true, {@code filename}이 null이면 true, {@code fileLength}가 0 이하이면 true |
275 | 275 |
*/ |
276 |
- private static boolean isEmptyFilePart(FilePart filePart) { |
|
277 |
- return filePart == null || filePart.getFilename() == null || filePart.getFilename().length() <= 0; |
|
278 |
- } |
|
276 |
+ private static boolean isEmptyFilePart(FilePart filePart) { |
|
277 |
+ return filePart == null || filePart.getFilename() == null || filePart.getFilename().length() <= 0; |
|
278 |
+ } |
|
279 | 279 |
|
280 | 280 |
/** |
281 | 281 |
* {@code filename}의 확장자를 체크하여 이미지인지 확인한다.<p /> |
... | ... | @@ -321,7 +321,7 @@ |
321 | 321 |
/** |
322 | 322 |
* 프로젝트를 삭제한다.<p /> |
323 | 323 |
* |
324 |
- * {@code loginId}와 {@code projectName}으로 프로젝트 정보를 가져온다.<br /> |
|
324 |
+ * {@code loginId}와 {@code projectName}으로 프로젝트 정보를 가져온다.<br /> |
|
325 | 325 |
* 삭제 권한이 없을 경우는 경고 메시지와 함께 설정페이지로 redirect된다. <br /> |
326 | 326 |
* |
327 | 327 |
* @param loginId the user login id |
--- app/controllers/PullRequestApp.java
+++ app/controllers/PullRequestApp.java
... | ... | @@ -174,11 +174,11 @@ |
174 | 174 |
|
175 | 175 |
/** |
176 | 176 |
* {@code userName}과 {@code projectName}에 해당하는 프로젝트의 원본 프로젝트로 코드를 보낼 수 있는 코드 보내기 폼을 보여준다. |
177 |
- * |
|
177 |
+ * |
|
178 | 178 |
* 코드 보내기 폼에서 보내려는 브랜치과 코드를 받을 브랜치를 선택할 수 있도록 브랜치 목록을 보여준다. |
179 | 179 |
* 보내는 브랜치(fromBranch)와 받는 브랜치(toBranch) 파라미터가 있을 경우 두개의 브랜치를 merge해보고 결과를 반환한다. |
180 | 180 |
* ajax 요청일 경우 partial로 렌더링한다. |
181 |
- * |
|
181 |
+ * |
|
182 | 182 |
* @param userName |
183 | 183 |
* @param projectName |
184 | 184 |
* @return |
... | ... | @@ -195,29 +195,29 @@ |
195 | 195 |
|
196 | 196 |
List<String> fromBranches = RepositoryService.getRepository(project).getBranches(); |
197 | 197 |
List<String> toBranches = RepositoryService.getRepository(project.originalProject).getBranches(); |
198 |
- |
|
198 |
+ |
|
199 | 199 |
PullRequest pullRequest = new PullRequest(); |
200 | 200 |
pullRequest.toProject = project.originalProject; |
201 | 201 |
pullRequest.fromProject = project; |
202 | 202 |
pullRequest.fromBranch = request().getQueryString("fromBranch"); |
203 | 203 |
pullRequest.toBranch = request().getQueryString("toBranch"); |
204 |
- |
|
204 |
+ |
|
205 | 205 |
PullRequestMergeResult mergeResult = null; |
206 |
- |
|
206 |
+ |
|
207 | 207 |
if (!StringUtils.isEmpty(pullRequest.fromBranch) && !StringUtils.isEmpty(pullRequest.toBranch)) { |
208 | 208 |
mergeResult = pullRequest.attemptMerge(); |
209 | 209 |
Map<String, String> suggestText = suggestTitleAndBodyFromDiffCommit(mergeResult.getGitCommits()); |
210 | 210 |
pullRequest.title = suggestText.get("title"); |
211 | 211 |
pullRequest.body = suggestText.get("body"); |
212 |
- } |
|
213 |
- |
|
212 |
+ } |
|
213 |
+ |
|
214 | 214 |
String xRequested = request().getHeader("X-Requested-With"); |
215 |
- |
|
215 |
+ |
|
216 | 216 |
if (!StringUtils.isEmpty(xRequested)) { |
217 | 217 |
response().setHeader("Cache-Control", "no-cache, no-store"); |
218 | 218 |
return ok(partial_diff.render(new Form<>(PullRequest.class).fill(pullRequest), project, mergeResult, pullRequest)); |
219 |
- } |
|
220 |
- |
|
219 |
+ } |
|
220 |
+ |
|
221 | 221 |
return ok(create.render("title.newPullRequest", new Form<>(PullRequest.class).fill(pullRequest), project, fromBranches, toBranches, mergeResult, pullRequest)); |
222 | 222 |
} |
223 | 223 |
|
... | ... | @@ -271,24 +271,24 @@ |
271 | 271 |
Attachment.moveAll(UserApp.currentUser().asResource(), pullRequest.asResource()); |
272 | 272 |
|
273 | 273 |
Call pullRequestCall = routes.PullRequestApp.pullRequest(originalProject.owner, originalProject.name, pullRequest.number); |
274 |
- |
|
274 |
+ |
|
275 | 275 |
NotificationEvent notiEvent = NotificationEvent.addNewPullRequest(pullRequestCall, request(), pullRequest); |
276 | 276 |
PullRequestEvent.addEvent(notiEvent, pullRequest); |
277 |
- |
|
277 |
+ |
|
278 | 278 |
PullRequestEventMessage message = new PullRequestEventMessage( |
279 | 279 |
UserApp.currentUser(), request(), pullRequest.toProject, pullRequest.toBranch); |
280 | 280 |
Akka.system().actorOf(new Props(PullRequestEventActor.class)).tell(message, null); |
281 |
- |
|
281 |
+ |
|
282 | 282 |
return redirect(pullRequestCall); |
283 | 283 |
} |
284 |
- |
|
284 |
+ |
|
285 | 285 |
/** |
286 | 286 |
* diff commit message로 pull request의 title과 body를 채운다.<br> |
287 | 287 |
* <br> |
288 | 288 |
* case 1 : commit이 한개이고 message가 한줄일 경우 title에 추가한다.<br> |
289 | 289 |
* case 2 : commit이 한개이고 message가 여러줄일 경우 첫번째줄 mesage는 title 나머지 message는 body에 추가<br> |
290 | 290 |
* case 3 : commit이 여러개일 경우 각 commit의 첫번째줄 message들을 모아서 body에 추가 <br> |
291 |
- * |
|
291 |
+ * |
|
292 | 292 |
* @param commits |
293 | 293 |
* @return |
294 | 294 |
*/ |
... | ... | @@ -299,21 +299,21 @@ |
299 | 299 |
|
300 | 300 |
if (commits.isEmpty()) { |
301 | 301 |
return messageMap; |
302 |
- |
|
302 |
+ |
|
303 | 303 |
} else if (commits.size() == 1) { |
304 |
- message = commits.get(0).getMessage(); |
|
304 |
+ message = commits.get(0).getMessage(); |
|
305 | 305 |
String[] messages = message.split(NEW_LINE_DELIMETER); |
306 | 306 |
|
307 | 307 |
if (messages.length > 1) { |
308 | 308 |
String[] msgs = Arrays.copyOfRange(messages, 1, messages.length); |
309 | 309 |
messageMap.put("title", messages[0]); |
310 | 310 |
messageMap.put("body", StringUtils.join(msgs, NEW_LINE_DELIMETER)); |
311 |
- |
|
311 |
+ |
|
312 | 312 |
} else { |
313 | 313 |
messageMap.put("title", messages[0]); |
314 | 314 |
messageMap.put("body", StringUtils.EMPTY); |
315 | 315 |
} |
316 |
- |
|
316 |
+ |
|
317 | 317 |
} else { |
318 | 318 |
String[] firstMessages = new String[commits.size()]; |
319 | 319 |
for (int i = 0; i < commits.size(); i++) { |
... | ... | @@ -321,13 +321,13 @@ |
321 | 321 |
firstMessages[i] = messages[0]; |
322 | 322 |
} |
323 | 323 |
messageMap.put("body", StringUtils.join(firstMessages, NEW_LINE_DELIMETER)); |
324 |
- |
|
324 |
+ |
|
325 | 325 |
} |
326 | 326 |
|
327 | 327 |
return messageMap; |
328 | 328 |
} |
329 |
- |
|
330 |
- |
|
329 |
+ |
|
330 |
+ |
|
331 | 331 |
private static void validateForm(Form<PullRequest> form) { |
332 | 332 |
Map<String, String> data = form.data(); |
333 | 333 |
ValidationUtils.rejectIfEmpty(flash(), data.get("fromBranch"), "pullRequest.fromBranch.required"); |
... | ... | @@ -424,10 +424,10 @@ |
424 | 424 |
if(activeTab == null && !isValid(activeTab)) { |
425 | 425 |
activeTab = "info"; |
426 | 426 |
} |
427 |
- |
|
427 |
+ |
|
428 | 428 |
boolean canDeleteBranch = false; |
429 | 429 |
boolean canRestoreBranch = false; |
430 |
- |
|
430 |
+ |
|
431 | 431 |
if (pullRequest.isClosed()) { |
432 | 432 |
canDeleteBranch = GitRepository.canDeleteFromBranch(pullRequest); |
433 | 433 |
canRestoreBranch = GitRepository.canRestoreBranch(pullRequest); |
... | ... | @@ -470,8 +470,39 @@ |
470 | 470 |
return result; |
471 | 471 |
} |
472 | 472 |
|
473 |
- List<GitCommit> commits = GitRepository.getPullingCommits(pullRequest); |
|
474 |
- return ok(viewCommits.render(project, pullRequest, commits)); |
|
473 |
+ return ok(viewCommits.render(project, pullRequest)); |
|
474 |
+ } |
|
475 |
+ |
|
476 |
+ /** |
|
477 |
+ * {@code userName}과 {@code projectName}에 해당하는 프로젝트로 들어온 |
|
478 |
+ * {@code pullRequestId}에 해당하는 코드 요청의 변경내역을 조회한다. |
|
479 |
+ * |
|
480 |
+ * @param userName |
|
481 |
+ * @param projectName |
|
482 |
+ * @param pullRequestNumber |
|
483 |
+ * @return |
|
484 |
+ */ |
|
485 |
+ public static Result pullRequestChanges(String userName, String projectName, long pullRequestNumber) { |
|
486 |
+ Project project = Project.findByOwnerAndProjectName(userName, projectName); |
|
487 |
+ PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
|
488 |
+ |
|
489 |
+ Result result = validatePullRequest(project, pullRequest, userName, projectName, pullRequestNumber); |
|
490 |
+ if(result != null) { |
|
491 |
+ return result; |
|
492 |
+ } |
|
493 |
+ |
|
494 |
+ List<PullRequestComment> comments = new ArrayList<>(); |
|
495 |
+ |
|
496 |
+ for (PullRequestComment comment : pullRequest.comments) { |
|
497 |
+ if (comment.hasValidCommitId()) { |
|
498 |
+ if (comment.commitId == null) { |
|
499 |
+ comment.commitId = comment.commitB; |
|
500 |
+ } |
|
501 |
+ comments.add(comment); |
|
502 |
+ } |
|
503 |
+ } |
|
504 |
+ |
|
505 |
+ return ok(viewChanges.render(project, pullRequest, comments)); |
|
475 | 506 |
} |
476 | 507 |
|
477 | 508 |
/** |
... | ... | @@ -494,7 +525,7 @@ |
494 | 525 |
} |
495 | 526 |
|
496 | 527 |
pullRequest.merge(); |
497 |
- |
|
528 |
+ |
|
498 | 529 |
// merge이후 관련 pullRequest의 상태를 체크한다. |
499 | 530 |
PullRequestEventMessage message = new PullRequestEventMessage( |
500 | 531 |
UserApp.currentUser(), request(), project, pullRequest.toBranch); |
--- app/controllers/StatisticsApp.java
+++ app/controllers/StatisticsApp.java
... | ... | @@ -7,11 +7,11 @@ |
7 | 7 |
import views.html.project.statistics; |
8 | 8 |
|
9 | 9 |
public class StatisticsApp extends Controller { |
10 |
- public static Result statistics(String userName, String projectName) { |
|
11 |
- Project project = Project.findByOwnerAndProjectName(userName, projectName); |
|
12 |
- if (project == null) { |
|
13 |
- return notFound(ErrorViews.NotFound.render("error.notfound")); |
|
14 |
- } |
|
15 |
- return ok(statistics.render("statistics", project)); |
|
16 |
- } |
|
10 |
+ public static Result statistics(String userName, String projectName) { |
|
11 |
+ Project project = Project.findByOwnerAndProjectName(userName, projectName); |
|
12 |
+ if (project == null) { |
|
13 |
+ return notFound(ErrorViews.NotFound.render("error.notfound")); |
|
14 |
+ } |
|
15 |
+ return ok(statistics.render("statistics", project)); |
|
16 |
+ } |
|
17 | 17 |
} |
--- app/models/AbstractPosting.java
+++ app/models/AbstractPosting.java
... | ... | @@ -161,26 +161,26 @@ |
161 | 161 |
|
162 | 162 |
public Resource asResource(final ResourceType type) { |
163 | 163 |
return new Resource() { |
164 |
- @Override |
|
165 |
- public String getId() { |
|
166 |
- return id.toString(); |
|
167 |
- } |
|
164 |
+ @Override |
|
165 |
+ public String getId() { |
|
166 |
+ return id.toString(); |
|
167 |
+ } |
|
168 | 168 |
|
169 |
- @Override |
|
170 |
- public Project getProject() { |
|
171 |
- return project; |
|
172 |
- } |
|
169 |
+ @Override |
|
170 |
+ public Project getProject() { |
|
171 |
+ return project; |
|
172 |
+ } |
|
173 | 173 |
|
174 |
- @Override |
|
175 |
- public ResourceType getType() { |
|
174 |
+ @Override |
|
175 |
+ public ResourceType getType() { |
|
176 | 176 |
return type; |
177 |
- } |
|
177 |
+ } |
|
178 | 178 |
|
179 | 179 |
@Override |
180 | 180 |
public Long getAuthorId() { |
181 | 181 |
return authorId; |
182 | 182 |
} |
183 |
- }; |
|
183 |
+ }; |
|
184 | 184 |
} |
185 | 185 |
|
186 | 186 |
/** |
--- app/models/CommitComment.java
+++ app/models/CommitComment.java
... | ... | @@ -14,6 +14,8 @@ |
14 | 14 |
private static final long serialVersionUID = 1L; |
15 | 15 |
public static final Finder<Long, CommitComment> find = new Finder<>(Long.class, CommitComment.class); |
16 | 16 |
|
17 |
+ public List<CommitComment> replies = new ArrayList<>(); |
|
18 |
+ |
|
17 | 19 |
public CommitComment() { |
18 | 20 |
super(); |
19 | 21 |
} |
... | ... | @@ -80,4 +82,16 @@ |
80 | 82 |
} |
81 | 83 |
return list; |
82 | 84 |
} |
85 |
+ |
|
86 |
+ /** |
|
87 |
+ * CommitComment의 groupKey를 반환한다. |
|
88 |
+ * commitId, path, line정보를 조한한 키가 일치할 경우 동일한 내용에 대한 |
|
89 |
+ * 코멘트로 간주한다. |
|
90 |
+ * |
|
91 |
+ * @return |
|
92 |
+ */ |
|
93 |
+ public String groupKey() { |
|
94 |
+ return new StringBuilder().append(this.commitId) |
|
95 |
+ .append(this.path).append(this.line).toString(); |
|
96 |
+ } |
|
83 | 97 |
} |
--- app/models/Issue.java
+++ app/models/Issue.java
... | ... | @@ -253,13 +253,13 @@ |
253 | 253 |
// FIXME 이것이 없이 테스트는 잘 작동하나, view에서 댓글이 달린 이슈들을 필터링하는 라디오버튼을 작동시에 이 메쏘드에서 |
254 | 254 |
// 시행하는 동기화 작업 없이는 작동을 하지 않는다. |
255 | 255 |
|
256 |
- public boolean isOpen() { |
|
257 |
- return this.state == State.OPEN; |
|
258 |
- } |
|
256 |
+ public boolean isOpen() { |
|
257 |
+ return this.state == State.OPEN; |
|
258 |
+ } |
|
259 | 259 |
|
260 |
- public boolean isClosed() { |
|
261 |
- return this.state == State.CLOSED; |
|
262 |
- } |
|
260 |
+ public boolean isClosed() { |
|
261 |
+ return this.state == State.CLOSED; |
|
262 |
+ } |
|
263 | 263 |
|
264 | 264 |
@Override |
265 | 265 |
public Resource asResource() { |
--- app/models/Milestone.java
+++ app/models/Milestone.java
... | ... | @@ -65,11 +65,11 @@ |
65 | 65 |
} |
66 | 66 |
|
67 | 67 |
public int getNumClosedIssues() { |
68 |
- return Issue.finder.where().eq("milestone", this).eq("state", State.CLOSED).findRowCount(); |
|
68 |
+ return Issue.finder.where().eq("milestone", this).eq("state", State.CLOSED).findRowCount(); |
|
69 | 69 |
} |
70 | 70 |
|
71 | 71 |
public int getNumOpenIssues() { |
72 |
- return Issue.finder.where().eq("milestone", this).eq("state", State.OPEN).findRowCount(); |
|
72 |
+ return Issue.finder.where().eq("milestone", this).eq("state", State.OPEN).findRowCount(); |
|
73 | 73 |
} |
74 | 74 |
|
75 | 75 |
public List<Issue> sortedByNumberOfIssue(){ |
... | ... | @@ -182,11 +182,11 @@ |
182 | 182 |
public static List<Milestone> findMilestones(Long projectId, |
183 | 183 |
State state, String sort, final Direction direction) { |
184 | 184 |
|
185 |
- OrderParams orderParams = new OrderParams(); |
|
185 |
+ OrderParams orderParams = new OrderParams(); |
|
186 | 186 |
|
187 |
- if(!"completionRate".equals(sort)) { |
|
188 |
- orderParams.add(sort, direction); |
|
189 |
- } |
|
187 |
+ if(!"completionRate".equals(sort)) { |
|
188 |
+ orderParams.add(sort, direction); |
|
189 |
+ } |
|
190 | 190 |
|
191 | 191 |
SearchParams searchParams = new SearchParams().add("project.id", projectId, Matching.EQUALS); |
192 | 192 |
if(state != null && state != State.ALL) { |
... | ... | @@ -196,19 +196,19 @@ |
196 | 196 |
List<Milestone> milestones = FinderTemplate.findBy(orderParams, searchParams, find); |
197 | 197 |
|
198 | 198 |
if("completionRate".equals(sort)) { |
199 |
- Collections.sort(milestones, new Comparator<Milestone>() { |
|
200 |
- @Override |
|
201 |
- public int compare(Milestone o1, Milestone o2) { |
|
202 |
- int o1CompletionRate = o1.getCompletionRate(); |
|
203 |
- int o2CompletionRate = o2.getCompletionRate(); |
|
199 |
+ Collections.sort(milestones, new Comparator<Milestone>() { |
|
200 |
+ @Override |
|
201 |
+ public int compare(Milestone o1, Milestone o2) { |
|
202 |
+ int o1CompletionRate = o1.getCompletionRate(); |
|
203 |
+ int o2CompletionRate = o2.getCompletionRate(); |
|
204 | 204 |
|
205 |
- if(direction == Direction.ASC) { |
|
206 |
- return (o1CompletionRate < o2CompletionRate ? -1 : (o1CompletionRate == o2CompletionRate ? 0 : 1)); |
|
207 |
- } else { |
|
208 |
- return (o1CompletionRate < o2CompletionRate ? 1 : (o1CompletionRate == o2CompletionRate ? 0 : -1)); |
|
209 |
- } |
|
210 |
- } |
|
211 |
- }); |
|
205 |
+ if(direction == Direction.ASC) { |
|
206 |
+ return (o1CompletionRate < o2CompletionRate ? -1 : (o1CompletionRate == o2CompletionRate ? 0 : 1)); |
|
207 |
+ } else { |
|
208 |
+ return (o1CompletionRate < o2CompletionRate ? 1 : (o1CompletionRate == o2CompletionRate ? 0 : -1)); |
|
209 |
+ } |
|
210 |
+ } |
|
211 |
+ }); |
|
212 | 212 |
} |
213 | 213 |
|
214 | 214 |
return milestones; |
--- app/models/PullRequest.java
+++ app/models/PullRequest.java
... | ... | @@ -11,31 +11,15 @@ |
11 | 11 |
import models.resource.Resource; |
12 | 12 |
import models.resource.ResourceConvertible; |
13 | 13 |
|
14 |
-import org.apache.commons.lang.ArrayUtils; |
|
15 | 14 |
import org.apache.commons.lang3.StringUtils; |
16 | 15 |
import org.eclipse.jgit.api.MergeResult; |
17 | 16 |
import org.eclipse.jgit.api.errors.GitAPIException; |
18 |
-import org.eclipse.jgit.lib.ObjectId; |
|
19 | 17 |
import org.eclipse.jgit.lib.Repository; |
20 | 18 |
import org.eclipse.jgit.lib.RepositoryBuilder; |
21 | 19 |
|
22 |
-import org.joda.time.DateTimeConstants; |
|
23 |
-import org.eclipse.jgit.diff.*; |
|
24 |
-import org.eclipse.jgit.lib.ConfigConstants; |
|
25 |
-import org.eclipse.jgit.lib.ObjectId; |
|
26 |
-import org.eclipse.jgit.lib.Repository; |
|
27 |
-import org.eclipse.jgit.revwalk.RevTree; |
|
28 |
-import org.eclipse.jgit.revwalk.RevWalk; |
|
29 |
-import org.eclipse.jgit.treewalk.TreeWalk; |
|
30 |
-import org.eclipse.jgit.util.io.NullOutputStream; |
|
31 | 20 |
import org.joda.time.Duration; |
32 | 21 |
|
33 |
-import com.avaje.ebean.Ebean; |
|
34 | 22 |
import com.avaje.ebean.Expr; |
35 |
-import com.avaje.ebean.RawSql; |
|
36 |
-import com.avaje.ebean.RawSqlBuilder; |
|
37 |
-import com.avaje.ebean.SqlQuery; |
|
38 |
-import com.avaje.ebean.SqlRow; |
|
39 | 23 |
|
40 | 24 |
import play.data.validation.Constraints; |
41 | 25 |
import play.db.ebean.Model; |
... | ... | @@ -48,29 +32,14 @@ |
48 | 32 |
import playRepository.GitRepository.CloneAndFetch; |
49 | 33 |
import utils.AccessControl; |
50 | 34 |
import utils.Constants; |
51 |
-import utils.GravatarUtil; |
|
52 | 35 |
import utils.JodaDateUtil; |
53 | 36 |
import utils.WatchService; |
54 | 37 |
|
55 | 38 |
import javax.persistence.*; |
56 | 39 |
import javax.validation.constraints.Size; |
57 | 40 |
|
41 |
+import java.io.IOException; |
|
58 | 42 |
import java.util.*; |
59 |
-import java.util.regex.Matcher; |
|
60 |
- |
|
61 |
-import java.io.IOException; |
|
62 |
-import java.util.ArrayList; |
|
63 |
-import java.util.Arrays; |
|
64 |
-import java.util.Collections; |
|
65 |
-import java.util.Comparator; |
|
66 |
-import java.util.Date; |
|
67 |
-import java.util.HashMap; |
|
68 |
-import java.util.HashSet; |
|
69 |
-import java.util.List; |
|
70 |
-import java.util.Map; |
|
71 |
-import java.util.Set; |
|
72 |
-import java.io.IOException; |
|
73 |
-import java.io.OutputStream; |
|
74 | 43 |
import java.io.File; |
75 | 44 |
|
76 | 45 |
@Entity |
... | ... | @@ -610,7 +579,7 @@ |
610 | 579 |
* @return |
611 | 580 |
*/ |
612 | 581 |
@Transient |
613 |
- public List<CommitComment> getCodeComments() { |
|
582 |
+ public List<CommitComment> getCommitComments() { |
|
614 | 583 |
return CommitComment.findByCommits(fromProject, pullRequestCommits); |
615 | 584 |
} |
616 | 585 |
|
... | ... | @@ -625,15 +594,17 @@ |
625 | 594 |
|
626 | 595 |
/** |
627 | 596 |
* pull request의 모든 코멘트 정보를 가져오고 시간순으로 정렬 후 반환한다. (코멘트 + 코드코멘트 + 이벤트 ) |
597 |
+ * |
|
628 | 598 |
* @return |
629 | 599 |
*/ |
630 | 600 |
@Transient |
631 | 601 |
public List<TimelineItem> getTimelineComments() { |
632 |
- List<CommitComment> codeComments = getCodeComments(); |
|
633 |
- |
|
602 |
+ List<CommitComment> commitComment |
|
603 |
+ = computeCommitCommentReplies(getCommitComments()); |
|
604 |
+ |
|
634 | 605 |
List<TimelineItem> timelineComments = new ArrayList<>(); |
635 | 606 |
timelineComments.addAll(comments); |
636 |
- timelineComments.addAll(codeComments); |
|
607 |
+ timelineComments.addAll(commitComment); |
|
637 | 608 |
timelineComments.addAll(pullRequestEvents); |
638 | 609 |
|
639 | 610 |
Collections.sort(timelineComments, new Comparator<TimelineItem>() { |
... | ... | @@ -641,12 +612,97 @@ |
641 | 612 |
public int compare(TimelineItem o1, TimelineItem o2) { |
642 | 613 |
return o1.getDate().compareTo(o2.getDate()); |
643 | 614 |
} |
644 |
- |
|
615 |
+ |
|
645 | 616 |
}); |
646 |
- |
|
617 |
+ |
|
647 | 618 |
return timelineComments; |
648 | 619 |
} |
649 | 620 |
|
621 |
+ /** |
|
622 |
+ * 전체 코멘트중 부모글과 답글 정보를 재할당한다. |
|
623 |
+ * @param commitComments |
|
624 |
+ * @return |
|
625 |
+ */ |
|
626 |
+ private List<CommitComment> computeCommitCommentReplies( |
|
627 |
+ List<CommitComment> commitComments) { |
|
628 |
+ return reAssignReplyComments(sameTopicCommentGroups(commitComments)); |
|
629 |
+ } |
|
630 |
+ |
|
631 |
+ /** |
|
632 |
+ * 답글목록을 부모글의 필드로 재할당한다. |
|
633 |
+ * |
|
634 |
+ * commentGroup은 등록일순으로 오름차순 정렬되어 있는 상태이며 |
|
635 |
+ * 목록의 첫번째 코멘트를 부모글로 판단한다. |
|
636 |
+ * |
|
637 |
+ * @param commentGroup |
|
638 |
+ * @return |
|
639 |
+ */ |
|
640 |
+ private List<CommitComment> reAssignReplyComments( |
|
641 |
+ Map<String, List<CommitComment>> commentGroup) { |
|
642 |
+ List<CommitComment> parentCommitComments = new ArrayList<>(); |
|
643 |
+ |
|
644 |
+ for (List<CommitComment> commitComments : commentGroup.values()) { |
|
645 |
+ CommitComment parentComment = commitComments.get(0); |
|
646 |
+ if (hasReply(commitComments)) { |
|
647 |
+ parentComment.replies = replies(commitComments); |
|
648 |
+ } |
|
649 |
+ parentCommitComments.add(parentComment); |
|
650 |
+ } |
|
651 |
+ return parentCommitComments; |
|
652 |
+ } |
|
653 |
+ |
|
654 |
+ /** |
|
655 |
+ * 답글 목록을 반환한다. |
|
656 |
+ * @param commitComments |
|
657 |
+ * @return |
|
658 |
+ */ |
|
659 |
+ private List<CommitComment> replies(List<CommitComment> commitComments) { |
|
660 |
+ return commitComments.subList(1, commitComments.size()); |
|
661 |
+ } |
|
662 |
+ |
|
663 |
+ /** |
|
664 |
+ * 답글 유무를 체크한다. |
|
665 |
+ * @param commitComments |
|
666 |
+ * @return |
|
667 |
+ */ |
|
668 |
+ private boolean hasReply(List<CommitComment> commitComments) { |
|
669 |
+ return commitComments.size() > 1; |
|
670 |
+ } |
|
671 |
+ |
|
672 |
+ /** |
|
673 |
+ * groupKey를 통해 같은 코멘트그룹 목록을 반환한다. |
|
674 |
+ * (같은 커밋, 같은 파일, 같은 라인의 덧글들) |
|
675 |
+ * @param commitComments |
|
676 |
+ * @return |
|
677 |
+ */ |
|
678 |
+ private Map<String, List<CommitComment>> sameTopicCommentGroups( |
|
679 |
+ List<CommitComment> commitComments) { |
|
680 |
+ Map<String, List<CommitComment>> commentGroup = new HashMap<>(); |
|
681 |
+ for (CommitComment commitComment : commitComments) { |
|
682 |
+ commentGroup.put( |
|
683 |
+ commitComment.groupKey(), |
|
684 |
+ commitCommentsGroupByKey(commitComment.groupKey(), |
|
685 |
+ commitComments)); |
|
686 |
+ } |
|
687 |
+ return commentGroup; |
|
688 |
+ } |
|
689 |
+ |
|
690 |
+ /** |
|
691 |
+ * groupKey를 통해 같은 코멘트그룹을 반환한다. |
|
692 |
+ * @param groupKey |
|
693 |
+ * @param codeComments |
|
694 |
+ * @return |
|
695 |
+ */ |
|
696 |
+ private List<CommitComment> commitCommentsGroupByKey(String groupKey, |
|
697 |
+ List<CommitComment> codeComments) { |
|
698 |
+ List<CommitComment> commitCommentGroups = new ArrayList<CommitComment>(); |
|
699 |
+ for (CommitComment commitComment : codeComments) { |
|
700 |
+ if (commitComment.groupKey().equals(groupKey)) { |
|
701 |
+ commitCommentGroups.add(commitComment); |
|
702 |
+ } |
|
703 |
+ } |
|
704 |
+ return commitCommentGroups; |
|
705 |
+ } |
|
650 | 706 |
|
651 | 707 |
/** |
652 | 708 |
* 보낸 코드를 병합해보고 결과 정보를 반환한다. |
--- app/models/support/Options.java
+++ app/models/support/Options.java
... | ... | @@ -3,11 +3,11 @@ |
3 | 3 |
import java.util.*; |
4 | 4 |
|
5 | 5 |
public class Options extends LinkedHashMap<String, String> { |
6 |
- private static final long serialVersionUID = 1L; |
|
6 |
+ private static final long serialVersionUID = 1L; |
|
7 | 7 |
|
8 |
- public Options(String... args) { |
|
9 |
- for (int idx = 0; idx < args.length; idx++) { |
|
10 |
- this.put(String.valueOf(idx + 1), args[idx]); |
|
11 |
- } |
|
12 |
- } |
|
8 |
+ public Options(String... args) { |
|
9 |
+ for (int idx = 0; idx < args.length; idx++) { |
|
10 |
+ this.put(String.valueOf(idx + 1), args[idx]); |
|
11 |
+ } |
|
12 |
+ } |
|
13 | 13 |
} |
--- app/playRepository/FileDiff.java
+++ app/playRepository/FileDiff.java
... | ... | @@ -29,81 +29,81 @@ |
29 | 29 |
/** |
30 | 30 |
* Get list of hunks |
31 | 31 |
* |
32 |
- * @throws java.io.IOException |
|
33 |
- */ |
|
34 |
- public List<Hunk> getHunks() |
|
35 |
- throws IOException { |
|
32 |
+ * @throws java.io.IOException |
|
33 |
+ */ |
|
34 |
+ public List<Hunk> getHunks() |
|
35 |
+ throws IOException { |
|
36 | 36 |
|
37 | 37 |
List<Hunk> hunks = new ArrayList<>(); |
38 | 38 |
|
39 |
- for (int curIdx = 0; curIdx < editList.size();) { |
|
39 |
+ for (int curIdx = 0; curIdx < editList.size();) { |
|
40 | 40 |
Hunk hunk = new Hunk(); |
41 |
- Edit curEdit = editList.get(curIdx); |
|
42 |
- final int endIdx = findCombinedEnd(editList, curIdx); |
|
43 |
- final Edit endEdit = editList.get(endIdx); |
|
41 |
+ Edit curEdit = editList.get(curIdx); |
|
42 |
+ final int endIdx = findCombinedEnd(editList, curIdx); |
|
43 |
+ final Edit endEdit = editList.get(endIdx); |
|
44 | 44 |
|
45 |
- int aCur = Math.max(0, curEdit.getBeginA() - context); |
|
46 |
- int bCur = Math.max(0, curEdit.getBeginB() - context); |
|
47 |
- final int aEnd = Math.min(a.size(), endEdit.getEndA() + context); |
|
48 |
- final int bEnd = Math.min(b.size(), endEdit.getEndB() + context); |
|
45 |
+ int aCur = Math.max(0, curEdit.getBeginA() - context); |
|
46 |
+ int bCur = Math.max(0, curEdit.getBeginB() - context); |
|
47 |
+ final int aEnd = Math.min(a.size(), endEdit.getEndA() + context); |
|
48 |
+ final int bEnd = Math.min(b.size(), endEdit.getEndB() + context); |
|
49 | 49 |
|
50 | 50 |
hunk.beginA = aCur; |
51 | 51 |
hunk.endA = aEnd; |
52 | 52 |
hunk.beginB = bCur; |
53 | 53 |
hunk.endB = bEnd; |
54 | 54 |
|
55 |
- while (aCur < aEnd || bCur < bEnd) { |
|
56 |
- if (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) { |
|
55 |
+ while (aCur < aEnd || bCur < bEnd) { |
|
56 |
+ if (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) { |
|
57 | 57 |
hunk.lines.add(new DiffLine(this, DiffLineType.CONTEXT, aCur, bCur, |
58 | 58 |
a.getString(aCur))); |
59 |
- isEndOfLineMissing = checkEndOfLineMissing(a, aCur); |
|
60 |
- aCur++; |
|
61 |
- bCur++; |
|
62 |
- } else if (aCur < curEdit.getEndA()) { |
|
59 |
+ isEndOfLineMissing = checkEndOfLineMissing(a, aCur); |
|
60 |
+ aCur++; |
|
61 |
+ bCur++; |
|
62 |
+ } else if (aCur < curEdit.getEndA()) { |
|
63 | 63 |
hunk.lines.add(new DiffLine(this, DiffLineType.REMOVE, aCur, bCur, |
64 | 64 |
a.getString(aCur))); |
65 | 65 |
isEndOfLineMissing = checkEndOfLineMissing(a, aCur); |
66 |
- aCur++; |
|
67 |
- } else if (bCur < curEdit.getEndB()) { |
|
66 |
+ aCur++; |
|
67 |
+ } else if (bCur < curEdit.getEndB()) { |
|
68 | 68 |
hunk.lines.add(new DiffLine(this, DiffLineType.ADD, aCur, bCur, |
69 | 69 |
b.getString(bCur))); |
70 | 70 |
isEndOfLineMissing = checkEndOfLineMissing(a, aCur); |
71 |
- bCur++; |
|
72 |
- } |
|
71 |
+ bCur++; |
|
72 |
+ } |
|
73 | 73 |
|
74 |
- if (end(curEdit, aCur, bCur) && ++curIdx < editList.size()) |
|
75 |
- curEdit = editList.get(curIdx); |
|
76 |
- } |
|
74 |
+ if (end(curEdit, aCur, bCur) && ++curIdx < editList.size()) |
|
75 |
+ curEdit = editList.get(curIdx); |
|
76 |
+ } |
|
77 | 77 |
|
78 | 78 |
hunks.add(hunk); |
79 |
- } |
|
79 |
+ } |
|
80 | 80 |
|
81 | 81 |
return hunks; |
82 |
- } |
|
82 |
+ } |
|
83 | 83 |
|
84 | 84 |
private int findCombinedEnd(final List<Edit> edits, final int i) { |
85 |
- int end = i + 1; |
|
86 |
- while (end < edits.size() |
|
87 |
- && (combineA(edits, end) || combineB(edits, end))) |
|
88 |
- end++; |
|
89 |
- return end - 1; |
|
90 |
- } |
|
85 |
+ int end = i + 1; |
|
86 |
+ while (end < edits.size() |
|
87 |
+ && (combineA(edits, end) || combineB(edits, end))) |
|
88 |
+ end++; |
|
89 |
+ return end - 1; |
|
90 |
+ } |
|
91 | 91 |
|
92 | 92 |
private boolean combineA(final List<Edit> e, final int i) { |
93 |
- return e.get(i).getBeginA() - e.get(i - 1).getEndA() <= 2 * context; |
|
94 |
- } |
|
93 |
+ return e.get(i).getBeginA() - e.get(i - 1).getEndA() <= 2 * context; |
|
94 |
+ } |
|
95 | 95 |
|
96 |
- private boolean combineB(final List<Edit> e, final int i) { |
|
97 |
- return e.get(i).getBeginB() - e.get(i - 1).getEndB() <= 2 * context; |
|
98 |
- } |
|
96 |
+ private boolean combineB(final List<Edit> e, final int i) { |
|
97 |
+ return e.get(i).getBeginB() - e.get(i - 1).getEndB() <= 2 * context; |
|
98 |
+ } |
|
99 | 99 |
|
100 |
- private static boolean end(final Edit edit, final int a, final int b) { |
|
101 |
- return edit.getEndA() <= a && edit.getEndB() <= b; |
|
102 |
- } |
|
100 |
+ private static boolean end(final Edit edit, final int a, final int b) { |
|
101 |
+ return edit.getEndA() <= a && edit.getEndB() <= b; |
|
102 |
+ } |
|
103 | 103 |
|
104 | 104 |
private boolean checkEndOfLineMissing(final RawText text, final int line) { |
105 |
- return line + 1 == text.size() && text.isMissingNewlineAtEnd(); |
|
106 |
- } |
|
105 |
+ return line + 1 == text.size() && text.isMissingNewlineAtEnd(); |
|
106 |
+ } |
|
107 | 107 |
|
108 | 108 |
/** |
109 | 109 |
* 주어진 줄 번호와 관련된 diff만 남기고 나머지는 모두 버린다. |
--- app/utils/Constants.java
+++ app/utils/Constants.java
... | ... | @@ -1,9 +1,9 @@ |
1 | 1 |
package utils; |
2 | 2 |
|
3 | 3 |
public class Constants { |
4 |
- public static final String WARNING = "warning"; |
|
5 |
- public static final String INFO = "info"; |
|
6 |
- public static final String SUCCESS = "success"; |
|
4 |
+ public static final String WARNING = "warning"; |
|
5 |
+ public static final String INFO = "info"; |
|
6 |
+ public static final String SUCCESS = "success"; |
|
7 | 7 |
|
8 | 8 |
public static final String DEFAULT_LOGO_PATH = "public/uploadFiles/"; |
9 | 9 |
|
--- app/utils/MenuType.java
+++ app/utils/MenuType.java
... | ... | @@ -1,7 +1,7 @@ |
1 | 1 |
package utils; |
2 | 2 |
|
3 | 3 |
public enum MenuType { |
4 |
- SITE_HOME(1), NEW_PROJECT(2), PROJECTS(3), HELP(4), SITE_SETTING(5), USER(6), |
|
4 |
+ SITE_HOME(1), NEW_PROJECT(2), PROJECTS(3), HELP(4), SITE_SETTING(5), USER(6), |
|
5 | 5 |
PROJECT_HOME(100), BOARD(101), CODE(102), ISSUE(103), TASK(104), PROJECT_SETTING(105), MILESTONE(106), PULL_REQUEST(107), NONE(0); |
6 | 6 |
|
7 | 7 |
private int type; |
--- app/utils/TemplateHelper.scala
+++ app/utils/TemplateHelper.scala
... | ... | @@ -80,7 +80,7 @@ |
80 | 80 |
} |
81 | 81 |
|
82 | 82 |
def getJSPath(): String = { |
83 |
- routes.Assets.at("javascripts/").toString |
|
83 |
+ routes.Assets.at("javascripts/").toString |
|
84 | 84 |
} |
85 | 85 |
|
86 | 86 |
def nullOrEquals(a: String, b: String) = (a == null || b == null) || a.equals(b) |
--- app/views/code/history.scala.html
+++ app/views/code/history.scala.html
... | ... | @@ -165,7 +165,7 @@ |
165 | 165 |
case (user: User, _, _) if !user.isAnonymous => { |
166 | 166 |
|
167 | 167 |
<a href="@routes.UserApp.userInfo(commit.getAuthor.loginId)" class="avatar-wrap"> |
168 |
- @if( user.avatarUrl == UserApp.DEFAULT_AVATAR_URL ){ |
|
168 |
+ @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){ |
|
169 | 169 |
@if(commit.getAuthorEmail != null) { |
170 | 170 |
<img src="@urlToPicture(commit.getAuthorEmail, 32)"> |
171 | 171 |
} else { |
--- app/views/git/create.scala.html
+++ app/views/git/create.scala.html
... | ... | @@ -57,67 +57,67 @@ |
57 | 57 |
</div> |
58 | 58 |
</div> |
59 | 59 |
<div class="pull-request-wrap"> |
60 |
- <div class="option request-from"> |
|
61 |
- <div class="option-label">@Messages("pullRequest.from"): |
|
60 |
+ <div class="option request-from"> |
|
61 |
+ <div class="option-label">@Messages("pullRequest.from"): |
|
62 | 62 |
<code>@project.owner/@project.name</code> |
63 | 63 |
</div> |
64 |
- <div class="option-desc mt5"> |
|
65 |
- <div class="btn-group branches" data-name="fromBranch"> |
|
66 |
- <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
67 |
- <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
68 |
- <span class="d-caret"><span class="caret"></span></span> |
|
69 |
- </button> |
|
70 |
- <ul class="dropdown-menu"> |
|
71 |
- @for(branch <- fromBranches) { |
|
72 |
- @if(!branch.equals("HEAD") && !branch.contains("refs/remotes/")) { |
|
73 |
- @makeBranchItem(branch, pullRequest.fromBranch) |
|
74 |
- } |
|
75 |
- } |
|
76 |
- </ul> |
|
77 |
- </div> |
|
78 |
- </div> |
|
79 |
- </div> |
|
80 |
- |
|
81 |
- <div class="arrow"> |
|
82 |
- <i class="yobicon-right"></i> |
|
64 |
+ <div class="option-desc mt5"> |
|
65 |
+ <div class="btn-group branches" data-name="fromBranch"> |
|
66 |
+ <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
67 |
+ <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
68 |
+ <span class="d-caret"><span class="caret"></span></span> |
|
69 |
+ </button> |
|
70 |
+ <ul class="dropdown-menu"> |
|
71 |
+ @for(branch <- fromBranches) { |
|
72 |
+ @if(!branch.equals("HEAD") && !branch.contains("refs/remotes/")) { |
|
73 |
+ @makeBranchItem(branch, pullRequest.fromBranch) |
|
74 |
+ } |
|
75 |
+ } |
|
76 |
+ </ul> |
|
77 |
+ </div> |
|
78 |
+ </div> |
|
83 | 79 |
</div> |
84 | 80 |
|
85 |
- <div class="option request-to"> |
|
86 |
- <div class="option-label">@Messages("pullRequest.to"): |
|
81 |
+ <div class="arrow"> |
|
82 |
+ <i class="yobicon-right"></i> |
|
83 |
+ </div> |
|
84 |
+ |
|
85 |
+ <div class="option request-to"> |
|
86 |
+ <div class="option-label">@Messages("pullRequest.to"): |
|
87 | 87 |
<code>@project.originalProject.owner/@project.originalProject.name</code> |
88 | 88 |
</div> |
89 |
- <div class="option-desc mt5"> |
|
90 |
- <div class="btn-group branches" data-name="toBranch"> |
|
91 |
- <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
92 |
- <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
93 |
- <span class="d-caret"><span class="caret"></span></span> |
|
94 |
- </button> |
|
95 |
- <ul class="dropdown-menu"> |
|
96 |
- @for(branch <- toBranches) { |
|
97 |
- @if(!branch.equals("HEAD") && !branch.contains("refs/remotes/")) { |
|
98 |
- @makeBranchItem(branch, pullRequest.toBranch) |
|
99 |
- } |
|
100 |
- } |
|
101 |
- </ul> |
|
102 |
- </div> |
|
103 |
- </div> |
|
104 |
- </div> |
|
89 |
+ <div class="option-desc mt5"> |
|
90 |
+ <div class="btn-group branches" data-name="toBranch"> |
|
91 |
+ <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
92 |
+ <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
93 |
+ <span class="d-caret"><span class="caret"></span></span> |
|
94 |
+ </button> |
|
95 |
+ <ul class="dropdown-menu"> |
|
96 |
+ @for(branch <- toBranches) { |
|
97 |
+ @if(!branch.equals("HEAD") && !branch.contains("refs/remotes/")) { |
|
98 |
+ @makeBranchItem(branch, pullRequest.toBranch) |
|
99 |
+ } |
|
100 |
+ } |
|
101 |
+ </ul> |
|
102 |
+ </div> |
|
103 |
+ </div> |
|
104 |
+ </div> |
|
105 | 105 |
</div> |
106 | 106 |
|
107 | 107 |
<div id="frmWrap"> |
108 |
- @views.html.git.partial_diff(form, project, mergeResult, pullRequest) |
|
109 |
- </div> |
|
110 |
- <div id="compare" class="modal hide compare-wrap" tabindex="-1" role="dialog"> |
|
111 |
- <h4 class="path"> |
|
112 |
- <span></span> |
|
113 |
- <button type="button" class="ybtn pull-right" data-dismiss="modal" style="margin-right:20px;">@Messages("button.confirm")</button> |
|
114 |
- </h4> |
|
115 |
- <div class="row-fluid"> |
|
116 |
- <div class="span6 compare-from"></div> |
|
117 |
- <div class="span6 compare-to"></div> |
|
118 |
- </div> |
|
119 |
- <div id="mergely" class="mergely-wrap"></div> |
|
120 |
- </div> |
|
108 |
+ @views.html.git.partial_diff(form, project, mergeResult, pullRequest) |
|
109 |
+ </div> |
|
110 |
+ <div id="compare" class="modal hide compare-wrap" tabindex="-1" role="dialog"> |
|
111 |
+ <h4 class="path"> |
|
112 |
+ <span></span> |
|
113 |
+ <button type="button" class="ybtn pull-right" data-dismiss="modal" style="margin-right:20px;">@Messages("button.confirm")</button> |
|
114 |
+ </h4> |
|
115 |
+ <div class="row-fluid"> |
|
116 |
+ <div class="span6 compare-from"></div> |
|
117 |
+ <div class="span6 compare-to"></div> |
|
118 |
+ </div> |
|
119 |
+ <div id="mergely" class="mergely-wrap"></div> |
|
120 |
+ </div> |
|
121 | 121 |
} |
122 | 122 |
</div> |
123 | 123 |
</div> |
... | ... | @@ -131,9 +131,9 @@ |
131 | 131 |
<script type="text/javascript"> |
132 | 132 |
$(document).ready(function() { |
133 | 133 |
$yobi.loadModule("git.Write", { |
134 |
- "sFormURL" : "@routes.PullRequestApp.newPullRequestForm(project.owner, project.name)", |
|
135 |
- "welFromBranch": $("div[data-name='fromBranch']"), |
|
136 |
- "welToBranch" : $("div[data-name='toBranch']") |
|
134 |
+ "sFormURL" : "@routes.PullRequestApp.newPullRequestForm(project.owner, project.name)", |
|
135 |
+ "welFromBranch" : $("div[data-name='fromBranch']"), |
|
136 |
+ "welToBranch" : $("div[data-name='toBranch']") |
|
137 | 137 |
}); |
138 | 138 |
}); |
139 | 139 |
</script> |
--- app/views/git/diff.scala.html
+++ app/views/git/diff.scala.html
... | ... | @@ -31,10 +31,10 @@ |
31 | 31 |
<div class="page"> |
32 | 32 |
<div class="code-browse-wrap"> |
33 | 33 |
<div class="actrow"> |
34 |
- <a href="@routes.PullRequestApp.pullRequest(pull.toProject.owner, pull.toProject.name, pull.number)?activeTab=commits" class="ybtn"> |
|
34 |
+ <a href="@routes.PullRequestApp.pullRequestCommits(pull.toProject.owner, pull.toProject.name, pull.number)" class="ybtn"> |
|
35 | 35 |
<i class="yobicon-arrow-right"></i> @Messages("pullRequest.back.to.the.pullrequest") |
36 | 36 |
</a> |
37 |
- |
|
37 |
+ |
|
38 | 38 |
<div class="pull-right"> |
39 | 39 |
<button id="watch-button" type="button" class="ybtn ybtn-info @if(commit.getWatchers(pull.fromProject).contains(UserApp.currentUser())) { active }" data-toggle="button">@Messages("notification.watch")</button> |
40 | 40 |
</div> |
... | ... | @@ -100,11 +100,11 @@ |
100 | 100 |
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> |
101 | 101 |
<img src="@User.findByLoginId(comment.authorLoginId).avatarUrl" width="32" height="32" alt="@comment.authorLoginId"> |
102 | 102 |
</a> |
103 |
- </div> |
|
103 |
+ </div> |
|
104 | 104 |
<div class="media-body"> |
105 | 105 |
<div class="meta-info"> |
106 | 106 |
<span class="comment_author pull-left"> |
107 |
- <i class="yobicon-comment"></i> |
|
107 |
+ <i class="yobicon-comment"></i> |
|
108 | 108 |
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> |
109 | 109 |
<strong>@comment.authorLoginId </strong> |
110 | 110 |
</a> |
... | ... | @@ -116,9 +116,9 @@ |
116 | 116 |
</span> |
117 | 117 |
} |
118 | 118 |
</div> |
119 |
- |
|
119 |
+ |
|
120 | 120 |
<div class="comment-body markdown-wrap markdown-before" markdown="true">@comment.contents</div> |
121 |
- |
|
121 |
+ |
|
122 | 122 |
<div class="attachments" data-resourceType="@ResourceType.COMMIT_COMMENT" data-resourceId="@comment.id"></div> |
123 | 123 |
</div> |
124 | 124 |
</li> |
... | ... | @@ -126,11 +126,11 @@ |
126 | 126 |
</ul> |
127 | 127 |
} |
128 | 128 |
} |
129 |
- |
|
129 |
+ |
|
130 | 130 |
@common.commentForm(pull.fromProject, ResourceType.COMMIT_COMMENT, routes.CodeHistoryApp.newComment(pull.fromProject.owner, pull.fromProject.name, commit.getId).toString()) |
131 | 131 |
</div> |
132 | 132 |
@** // Comment **@ |
133 |
- |
|
133 |
+ |
|
134 | 134 |
<div id="minimap" class="minimap-outer"> |
135 | 135 |
<div class="minimap-wrap"> |
136 | 136 |
<div class="minimap-curr"></div> |
--- app/views/git/edit.scala.html
+++ app/views/git/edit.scala.html
... | ... | @@ -13,17 +13,17 @@ |
13 | 13 |
} |
14 | 14 |
} |
15 | 15 |
|
16 |
-@makeBranchItem(branch:String, selectedBranch:String) = { |
|
16 |
+@makeBranchItem(branch:String) = { |
|
17 | 17 |
@defining(branch.split('/')){ names => |
18 | 18 |
@if(names(0).equals("refs")){ |
19 |
- <li data-value="@branch" @if(branch.equals(selectedBranch)){data-selected="true" class="active"}> |
|
19 |
+ <li data-value="@branch" data-selected="true" class="active"> |
|
20 | 20 |
<a href="#"> |
21 | 21 |
<span class="label @branchItemType(names(1))">@branchItemType(names(1))</span> |
22 | 22 |
@branch.replace("refs/" + names(1) + "/", "") |
23 | 23 |
</a> |
24 | 24 |
</li> |
25 | 25 |
} else { |
26 |
- <li data-value="@branch" @if(branch.equals(selectedBranch)){data-selected="true" class="active"}><a href="#">@branch</a></li> |
|
26 |
+ <li data-value="@branch" data-selected="true" class="active"><a href="#">@branch</a></li> |
|
27 | 27 |
} |
28 | 28 |
} |
29 | 29 |
} |
... | ... | @@ -55,51 +55,43 @@ |
55 | 55 |
</div> |
56 | 56 |
</div> |
57 | 57 |
<div class="pull-request-wrap"> |
58 |
- <div class="option request-from"> |
|
59 |
- <div class="option-label">@Messages("pullRequest.from"): |
|
58 |
+ <div class="option request-from"> |
|
59 |
+ <div class="option-label">@Messages("pullRequest.from"): |
|
60 | 60 |
<code>@project.owner/@project.name</code> |
61 | 61 |
</div> |
62 |
- <div class="option-desc"> |
|
63 |
- <div class="btn-group branches" data-name="fromBranch"> |
|
64 |
- <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
65 |
- <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
66 |
- <span class="d-caret"><span class="caret"></span></span> |
|
67 |
- </button> |
|
68 |
- <ul class="dropdown-menu"> |
|
69 |
- @for(branch <- fromBranches) { |
|
70 |
- @if(!branch.equals("HEAD") && !branch.contains("refs/remotes/")) { |
|
71 |
- @makeBranchItem(branch, form("fromBranch").value()) |
|
72 |
- } |
|
73 |
- } |
|
74 |
- </ul> |
|
75 |
- </div> |
|
76 |
- </div> |
|
77 |
- </div> |
|
78 |
- |
|
79 |
- <div class="arrow"> |
|
80 |
- <i class="yobicon-right"></i> |
|
62 |
+ <div class="option-desc"> |
|
63 |
+ <div class="btn-group branches" data-name="fromBranch"> |
|
64 |
+ <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
65 |
+ <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
66 |
+ <span class="d-caret"><span class="caret"></span></span> |
|
67 |
+ </button> |
|
68 |
+ <ul class="dropdown-menu"> |
|
69 |
+ @makeBranchItem(form("fromBranch").value()) |
|
70 |
+ </ul> |
|
71 |
+ </div> |
|
72 |
+ </div> |
|
81 | 73 |
</div> |
82 | 74 |
|
83 |
- <div class="option request-to"> |
|
84 |
- <div class="option-label">@Messages("pullRequest.to"): |
|
75 |
+ <div class="arrow"> |
|
76 |
+ <i class="yobicon-right"></i> |
|
77 |
+ </div> |
|
78 |
+ |
|
79 |
+ <div class="option request-to"> |
|
80 |
+ <div class="option-label">@Messages("pullRequest.to"): |
|
85 | 81 |
<code>@project.originalProject.owner/@project.originalProject.name</code> |
86 | 82 |
</div> |
87 |
- <div class="option-desc"> |
|
88 |
- <div class="btn-group branches" data-name="toBranch"> |
|
89 |
- <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
90 |
- <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
91 |
- <span class="d-caret"><span class="caret"></span></span> |
|
92 |
- </button> |
|
93 |
- <ul class="dropdown-menu"> |
|
94 |
- @for(branch <- toBranches) { |
|
95 |
- @if(!branch.equals("HEAD") && !branch.contains("refs/remotes/")) { |
|
96 |
- @makeBranchItem(branch, form("toBranch").value()) |
|
97 |
- } |
|
98 |
- } |
|
99 |
- </ul> |
|
100 |
- </div> |
|
101 |
- </div> |
|
102 |
- </div> |
|
83 |
+ <div class="option-desc"> |
|
84 |
+ <div class="btn-group branches" data-name="toBranch"> |
|
85 |
+ <button class="btn dropdown-toggle auto" data-toggle="dropdown"> |
|
86 |
+ <span class="d-label">@Messages("pullRequest.select.branch")</span> |
|
87 |
+ <span class="d-caret"><span class="caret"></span></span> |
|
88 |
+ </button> |
|
89 |
+ <ul class="dropdown-menu"> |
|
90 |
+ @makeBranchItem(form("toBranch").value()) |
|
91 |
+ </ul> |
|
92 |
+ </div> |
|
93 |
+ </div> |
|
94 |
+ </div> |
|
103 | 95 |
</div> |
104 | 96 |
|
105 | 97 |
@helper.inputText(form("title"), 'class->"text title", 'maxlength -> "250", 'tabindex -> 1, 'placeholder->"Title") |
--- app/views/git/partial_comments.scala.html
+++ app/views/git/partial_comments.scala.html
... | ... | @@ -122,7 +122,7 @@ |
122 | 122 |
@renderCommitComment(comment: CommitComment) = { |
123 | 123 |
@defining(PullRequestCommit.getStateByCommitId(pull, comment.commitId)) { state => |
124 | 124 |
@if(state != null) { |
125 |
- <li class="comment @isAuthorComment(comment.authorLoginId)" id="comment-@comment.id"> |
|
125 |
+ <li class="comment @isAuthorComment(comment.authorLoginId) @if(!comment.replies.isEmpty) {hasReply}" id="comment-@comment.id"> |
|
126 | 126 |
<div class="comment-avatar"> |
127 | 127 |
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> |
128 | 128 |
<img src="@User.findByLoginId(comment.authorLoginId).avatarUrl" width="32" height="32" alt="@comment.authorLoginId"> |
... | ... | @@ -133,7 +133,7 @@ |
133 | 133 |
<span class="comment_author pull-left"> |
134 | 134 |
<i class="yobicon-comment"></i> |
135 | 135 |
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> |
136 |
- <strong>@comment.authorLoginId </strong> |
|
136 |
+ <strong>@comment.authorLoginId</strong> |
|
137 | 137 |
</a> |
138 | 138 |
</span> |
139 | 139 |
<span class="ago"> |
... | ... | @@ -155,6 +155,36 @@ |
155 | 155 |
<div class="attachments pull-right" data-resourceType="@ResourceType.COMMIT_COMMENT" data-resourceId="@comment.id"></div> |
156 | 156 |
</div> |
157 | 157 |
</li> |
158 |
+ @for((reply, index) <- comment.replies.zipWithIndex) { |
|
159 |
+ <li class="comment @isAuthorComment(reply.authorLoginId) reply @if(index == (comment.replies.size - 1)) {last}" id="comment-@reply.id"> |
|
160 |
+ <div class="media-body"> |
|
161 |
+ <div class="meta-info"> |
|
162 |
+ <span class="comment_author pull-left"> |
|
163 |
+ <i class="yobicon-comment"></i> |
|
164 |
+ <a href="@routes.UserApp.userInfo(reply.authorLoginId)" data-toggle="tooltip" data-placement="top" title="@reply.authorName"> |
|
165 |
+ <strong>@reply.authorLoginId</strong> |
|
166 |
+ </a> |
|
167 |
+ </span> |
|
168 |
+ <span class="ago"> |
|
169 |
+ @if(PullRequestCommit.State.PRIOR == state) { |
|
170 |
+ @utils.TemplateHelper.agoString(ago(reply.createdDate)) - <strike>@Messages("pullRequest.code.replied")</strike> |
|
171 |
+ } else { |
|
172 |
+ @utils.TemplateHelper.agoString(ago(reply.createdDate)) - @Messages("pullRequest.code.replied") |
|
173 |
+ } |
|
174 |
+ </span> |
|
175 |
+ @if(isAllowed(UserApp.currentUser(), reply.asResource(), Operation.DELETE)){ |
|
176 |
+ <span class="edit pull-right"> |
|
177 |
+ <button type="button" class="btn-transparent close" data-request-method="delete" data-request-uri="@routes.CodeHistoryApp.deleteComment(pull.fromProject.owner, pull.fromProject.name, reply.commitId, reply.id)"><i class="yobicon-trash"></i></button> |
|
178 |
+ </span> |
|
179 |
+ } |
|
180 |
+ </div> |
|
181 |
+ |
|
182 |
+ <div class="comment-body markdown-wrap markdown-before" markdown="true">@reply.contents</div> |
|
183 |
+ |
|
184 |
+ <div class="attachments pull-right" data-resourceType="@ResourceType.COMMIT_COMMENT" data-resourceId="@reply.id"></div> |
|
185 |
+ </div> |
|
186 |
+ </li> |
|
187 |
+ } |
|
158 | 188 |
} |
159 | 189 |
} |
160 | 190 |
} |
+++ app/views/git/partial_conflict_message.scala.html
... | ... | @@ -0,0 +1,52 @@ |
1 | +@(project: Project, pull: PullRequest) | |
2 | + | |
3 | +@import utils.JodaDateUtil._ | |
4 | +@import utils.TemplateHelper._ | |
5 | +@import utils.AccessControl._ | |
6 | +@import models.enumeration | |
7 | +@import scala.collection.JavaConversions._ | |
8 | + | |
9 | +@branchName(branch:String) = @{ | |
10 | + branch.replace("refs/heads/", "") | |
11 | +} | |
12 | + | |
13 | +@getCodeURL(project: Project) = @{ | |
14 | + if(session == null){ | |
15 | + CodeApp.getURL(project.owner, project.name) | |
16 | + } else { | |
17 | + defining(ProjectUser.roleOf(session.get("loginId"), project)) { role => | |
18 | + if(role == "manager" || role == "member"){ | |
19 | + CodeApp.getURL(project.owner, project.name).replace("://", "://" + session.get("loginId") + "@") | |
20 | + } else { | |
21 | + CodeApp.getURL(project.owner, project.name) | |
22 | + } | |
23 | + } | |
24 | + } | |
25 | +} | |
26 | + | |
27 | +<div class="alert alert-error"> | |
28 | + <h5>@Messages("pullRequest.is.not.safe")</h5> | |
29 | + <div> | |
30 | + <h5>@Messages("pullRequest.conflict.files")</h5> | |
31 | + <ul class="unstyled conflict-files"> | |
32 | + @for(file <- pull.getConflictFiles) { | |
33 | + <li><i class="yobicon-file"></i> @file</li> | |
34 | + } | |
35 | + </ul> | |
36 | + </div> | |
37 | + <div> | |
38 | + <h5>@Messages("pullRequest.resolve.conflict")</h5> | |
39 | + <ol> | |
40 | + <li>@Messages("pullRequest.resolver.step1") <code>git checkout @branchName(pull.fromBranch)</code></li> | |
41 | + <li>@Messages("pullRequest.resolver.step2") <code>git remote add upstream @getCodeURL(pull.toProject)</code></li> | |
42 | + <li>@Messages("pullRequest.resolver.step3") <code>git fetch upstream</code></li> | |
43 | + <li>@Messages("pullRequest.resolver.step4") <code>git rebase upstream/@branchName(pull.toBranch)</code></li> | |
44 | + <li>@Messages("pullRequest.resolver.step5") </li> | |
45 | + <li>@Messages("pullRequest.resolver.step6") <code>git add 충돌을_해결한_파일</code></li> | |
46 | + <li>@Messages("pullRequest.resolver.step7") <code>git rebase --continue</code></li> | |
47 | + <li>@Messages("pullRequest.resolver.step8") </li> | |
48 | + <li>@Messages("pullRequest.resolver.step9") <code>git push -f origin @branchName(pull.fromBranch)</code></li> | |
49 | + <li>@Messages("pullRequest.resolver.step10") <a href="@routes.PullRequestApp.pullRequest(project.owner, project.name, pull.number)" class="ybtn ybtn-info ybtn-small">@Messages("button.page.refresh")</a>@Messages("pullRequest.resolver.step11")</li> | |
50 | + </ol> | |
51 | + </div> | |
52 | +</div>(No newline at end of file) |
--- app/views/git/partial_diff.scala.html
+++ app/views/git/partial_diff.scala.html
... | ... | @@ -54,12 +54,12 @@ |
54 | 54 |
</div> |
55 | 55 |
} |
56 | 56 |
</div> |
57 |
- |
|
57 |
+ |
|
58 | 58 |
<ul class="nav nav-tabs nm"> |
59 | 59 |
<li class="active"><a href="#__commits" data-toggle="tab">@Messages("pullRequest.menu.commit")</a></li> |
60 | 60 |
<li><a href="#__changes" data-toggle="tab">@Messages("pullRequest.menu.changes")</a></li> |
61 | 61 |
</ul> |
62 |
- <div class="tab-content"> |
|
62 |
+ <div class="tab-content"> |
|
63 | 63 |
<div id="__commits" class="code-browse-wrap tab-pane active"> |
64 | 64 |
<div id="history" class="commit-wrap mt20"> |
65 | 65 |
<table class="code-table commits"> |
... | ... | @@ -80,14 +80,12 @@ |
80 | 80 |
<i class="yobicon-right"></i> |
81 | 81 |
</a> |
82 | 82 |
</td> |
83 |
- |
|
84 | 83 |
<td class="messages"> |
85 | 84 |
@defining(CommitComment.count(pullRequest.fromProject, commit.getId, null)){ numOfComment => |
86 | 85 |
@if(numOfComment > 0) { |
87 | 86 |
<span class="number-of-comments"><i class="yobicon-comments"></i> @numOfComment</span> |
88 | 87 |
} |
89 | 88 |
} |
90 |
- |
|
91 | 89 |
@defining(commit.getMessage()){ commitMsg => |
92 | 90 |
<a href="@routes.CodeHistoryApp.show(pullRequest.fromProject.owner, pullRequest.fromProject.name, commit.getId())"> |
93 | 91 |
@commitMsg.split("\n")(0) |
... | ... | @@ -118,10 +116,11 @@ |
118 | 116 |
</table> |
119 | 117 |
</div> |
120 | 118 |
</div> |
121 |
- |
|
122 | 119 |
<div id="__changes" class="tab-pane"> |
123 | 120 |
<div class="diff-body"> |
121 |
+ @if(result.getGitConflicts() == null) { |
|
124 | 122 |
@views.html.partial_diff(pullRequest.getDiff) |
123 |
+ } |
|
125 | 124 |
</div> |
126 | 125 |
</div> |
127 | 126 |
</div> |
... | ... | @@ -141,4 +140,4 @@ |
141 | 140 |
"sTplRawURLB" : "@routes.CodeApp.showRawFile(pullRequest.fromProject.owner, pullRequest.fromProject.name, "${commitId}", "${path}")" |
142 | 141 |
}); |
143 | 142 |
}); |
144 |
-</script>(No newline at end of file) |
|
143 |
+</script> |
+++ app/views/git/partial_info.scala.html
... | ... | @@ -0,0 +1,61 @@ |
1 | +@(project: Project, pull: PullRequest) | |
2 | + | |
3 | +@import utils.JodaDateUtil._ | |
4 | +@import utils.TemplateHelper._ | |
5 | +@import utils.AccessControl._ | |
6 | +@import models.enumeration | |
7 | +@import scala.collection.JavaConversions._ | |
8 | + | |
9 | +@branchName(branch:String) = @{ | |
10 | + branch.replace("refs/heads/", "") | |
11 | +} | |
12 | + | |
13 | +<div class="pullreq-info"> | |
14 | + <div class="pull-right"> | |
15 | + <button id="helpBtn" class="ybtn ybtn-inverse ybtn-mini mt5"> | |
16 | + <i class="yobicon-question-sign yobicon-large"></i> @Messages("title.help") | |
17 | + </button> | |
18 | + </div> | |
19 | + <div> | |
20 | + <a href="@routes.UserApp.userInfo(pull.contributor.loginId)" class="avatar-wrap"> | |
21 | + <img src="@pull.contributor.avatarUrl" width="32" height="32"> | |
22 | + </a> | |
23 | + <a href="@routes.UserApp.userInfo(pull.contributor.loginId)"> | |
24 | + <strong>@pull.contributor.name (@pull.contributor.loginId)</strong> | |
25 | + </a> | |
26 | + @Messages("pullRequest.merge.requested") | |
27 | + | |
28 | + <div class="pullRequest-branch ml10"> | |
29 | + <span data-toggle="tooltip" data-original-title="@Messages("pullRequest.from")"> | |
30 | + <code class="from"> | |
31 | + <i class="yobicon-branch"></i> | |
32 | + <a href="@routes.UserApp.userInfo(pull.fromProject.owner)">@pull.fromProject.owner</a>/<!-- | |
33 | + --><a href="@routes.ProjectApp.project(pull.fromProject.owner, pull.fromProject.name)">@pull.fromProject.name</a>: | |
34 | + @branchName(pull.fromBranch) | |
35 | + </code> | |
36 | + </span> | |
37 | + <i class="yobicon-right ml10"></i> | |
38 | + <span class="ml10" data-toggle="tooltip" data-original-title="@Messages("pullRequest.to")"> | |
39 | + <code class="to"> | |
40 | + <i class="yobicon-branch"></i> | |
41 | + <a href="@routes.UserApp.userInfo(pull.toProject.owner)">@pull.toProject.owner</a>/<!-- | |
42 | + --><a href="@routes.ProjectApp.project(pull.toProject.owner, pull.toProject.name)">@pull.toProject.name</a>: | |
43 | + @branchName(pull.toBranch) | |
44 | + </code> | |
45 | + </span> | |
46 | + </div> | |
47 | + </div> | |
48 | + <div id="helpMessage" class="well" style="display:none;"> | |
49 | + <div class="row-fluid"> | |
50 | + <div class="pull-left"> | |
51 | + <img class="img-polaroid" src="@routes.Assets.at("images/fork-pull/merge.jpg")"><br> | |
52 | + </div> | |
53 | + <div class="pull-left help-messages"> | |
54 | + <p class="lead">@Messages("pullRequest.merge.help.1")</p> | |
55 | + <p>@Messages("pullRequest.merge.help.2")</p> | |
56 | + <p>@Messages("pullRequest.merge.help.3")</p> | |
57 | + <p>@Messages("pullRequest.merge.help.4")</p> | |
58 | + </div> | |
59 | + </div> | |
60 | + </div> | |
61 | +</div>(No newline at end of file) |
--- app/views/git/view.scala.html
+++ app/views/git/view.scala.html
... | ... | @@ -6,287 +6,103 @@ |
6 | 6 |
@import models.enumeration |
7 | 7 |
@import scala.collection.JavaConversions._ |
8 | 8 |
|
9 |
-@branchName(branch:String) = @{ |
|
10 |
- branch.replace("refs/heads/", "") |
|
11 |
-} |
|
12 |
- |
|
13 |
-@getCodeURL(project: Project) = @{ |
|
14 |
- if(session == null){ |
|
15 |
- CodeApp.getURL(project.owner, project.name) |
|
16 |
- } else { |
|
17 |
- defining(ProjectUser.roleOf(session.get("loginId"), project)) { role => |
|
18 |
- if(role == "manager" || role == "member"){ |
|
19 |
- CodeApp.getURL(project.owner, project.name).replace("://", "://" + session.get("loginId") + "@") |
|
20 |
- } else { |
|
21 |
- CodeApp.getURL(project.owner, project.name) |
|
22 |
- } |
|
23 |
- } |
|
24 |
- } |
|
25 |
-} |
|
26 |
- |
|
27 |
-@conflictMessage = { |
|
28 |
- <div class="alert alert-error"> |
|
29 |
- <h5>@Messages("pullRequest.is.not.safe")</h5> |
|
30 |
- <div> |
|
31 |
- <h5>@Messages("pullRequest.conflict.files")</h5> |
|
32 |
- <ul class="unstyled conflict-files"> |
|
33 |
- @for(file <- pull.getConflictFiles) { |
|
34 |
- <li><i class="yobicon-file"></i> @file</li> |
|
35 |
- } |
|
36 |
- </ul> |
|
37 |
- </div> |
|
38 |
- <div> |
|
39 |
- <h5>@Messages("pullRequest.resolve.conflict")</h5> |
|
40 |
- <ol> |
|
41 |
- <li>@Messages("pullRequest.resolver.step1") <code>git checkout @branchName(pull.fromBranch)</code></li> |
|
42 |
- <li>@Messages("pullRequest.resolver.step2") <code>git remote add upstream @getCodeURL(pull.toProject)</code></li> |
|
43 |
- <li>@Messages("pullRequest.resolver.step3") <code>git fetch upstream</code></li> |
|
44 |
- <li>@Messages("pullRequest.resolver.step4") <code>git rebase upstream/@branchName(pull.toBranch)</code></li> |
|
45 |
- <li>@Messages("pullRequest.resolver.step5") </li> |
|
46 |
- <li>@Messages("pullRequest.resolver.step6") <code>git add 충돌을_해결한_파일</code></li> |
|
47 |
- <li>@Messages("pullRequest.resolver.step7") <code>git rebase --continue</code></li> |
|
48 |
- <li>@Messages("pullRequest.resolver.step8") </li> |
|
49 |
- <li>@Messages("pullRequest.resolver.step9") <code>git push -f origin @branchName(pull.fromBranch)</code></li> |
|
50 |
- <li>@Messages("pullRequest.resolver.step10") <a href="@routes.PullRequestApp.pullRequest(project.owner, project.name, pull.number)" class="ybtn ybtn-info ybtn-small">@Messages("button.page.refresh")</a>@Messages("pullRequest.resolver.step11")</li> |
|
51 |
- </ol> |
|
52 |
- </div> |
|
53 |
- </div> |
|
54 |
-} |
|
55 |
- |
|
56 | 9 |
@projectLayout(Messages("menu.pullRequest"), project, utils.MenuType.PULL_REQUEST) { |
57 | 10 |
<div class="page"> |
58 | 11 |
@projectMenu(project, utils.MenuType.PULL_REQUEST, "main-menu-only") |
59 | 12 |
|
60 |
- <div class="pullreq-info"> |
|
61 |
- <div class="pull-right"> |
|
62 |
- <button id="helpBtn" class="ybtn ybtn-inverse ybtn-mini mt5"> |
|
63 |
- <i class="yobicon-question-sign yobicon-large"></i> @Messages("title.help") |
|
64 |
- </button> |
|
65 |
- </div> |
|
66 |
- <div> |
|
67 |
- <a href="@routes.UserApp.userInfo(pull.contributor.loginId)" class="avatar-wrap"> |
|
68 |
- <img src="@pull.contributor.avatarUrl" width="32" height="32"> |
|
69 |
- </a> |
|
70 |
- <a href="@routes.UserApp.userInfo(pull.contributor.loginId)"> |
|
71 |
- <strong>@pull.contributor.name (@pull.contributor.loginId)</strong> |
|
72 |
- </a> |
|
73 |
- @Messages("pullRequest.merge.requested") |
|
74 |
- |
|
75 |
- <div class="pullRequest-branch ml10"> |
|
76 |
- <span data-toggle="tooltip" data-original-title="@Messages("pullRequest.from")"> |
|
77 |
- <code class="from"> |
|
78 |
- <i class="yobicon-branch"></i> |
|
79 |
- <a href="@routes.UserApp.userInfo(pull.fromProject.owner)">@pull.fromProject.owner</a>/<!-- |
|
80 |
- --><a href="@routes.ProjectApp.project(pull.fromProject.owner, pull.fromProject.name)">@pull.fromProject.name</a>: |
|
81 |
- @branchName(pull.fromBranch) |
|
82 |
- </code> |
|
83 |
- </span> |
|
84 |
- <i class="yobicon-right ml10"></i> |
|
85 |
- <span class="ml10" data-toggle="tooltip" data-original-title="@Messages("pullRequest.to")"> |
|
86 |
- <code class="to"> |
|
87 |
- <i class="yobicon-branch"></i> |
|
88 |
- <a href="@routes.UserApp.userInfo(pull.toProject.owner)">@pull.toProject.owner</a>/<!-- |
|
89 |
- --><a href="@routes.ProjectApp.project(pull.toProject.owner, pull.toProject.name)">@pull.toProject.name</a>: |
|
90 |
- @branchName(pull.toBranch) |
|
91 |
- </code> |
|
92 |
- </span> |
|
93 |
- </div> |
|
94 |
- </div> |
|
95 |
- <div id="helpMessage" class="well" style="display:none;"> |
|
96 |
- <div class="row-fluid"> |
|
97 |
- <div class="pull-left"> |
|
98 |
- <img class="img-polaroid" src="@routes.Assets.at("images/fork-pull/merge.jpg")"><br> |
|
99 |
- </div> |
|
100 |
- <div class="pull-left help-messages"> |
|
101 |
- <p class="lead">@Messages("pullRequest.merge.help.1")</p> |
|
102 |
- <p>@Messages("pullRequest.merge.help.2")</p> |
|
103 |
- <p>@Messages("pullRequest.merge.help.3")</p> |
|
104 |
- <p>@Messages("pullRequest.merge.help.4")</p> |
|
105 |
- </div> |
|
106 |
- </div> |
|
107 |
- </div> |
|
108 |
- </div> |
|
13 |
+ @partial_info(project, pull) |
|
109 | 14 |
|
110 | 15 |
<ul class="nav nav-tabs nm"> |
111 |
- <li @if(activeTab == "info"){ class="active" }><a href="#__info" data-toggle="tab">@Messages("pullRequest.menu.overview")</a></li> |
|
112 |
- <li @if(activeTab == "commits"){ class="active" }><a href="#__commits" data-toggle="tab">@Messages("pullRequest.menu.commit")</a></li> |
|
113 |
- <li @if(activeTab == "changes"){ class="active" }><a href="#__changes" data-toggle="tab">@Messages("pullRequest.menu.changes")</a></li> |
|
16 |
+ <li class="active"><a href="@routes.PullRequestApp.pullRequest(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.overview")</a></li> |
|
17 |
+ <li><a href="@routes.PullRequestApp.pullRequestCommits(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.commit")</a></li> |
|
18 |
+ <li><a href="@routes.PullRequestApp.pullRequestChanges(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.changes")</a></li> |
|
114 | 19 |
</ul> |
115 |
- <div class="tab-content"> |
|
116 |
- <div id="__info" class="tab-pane @if(activeTab == "info"){ active }"> |
|
117 |
- @**<!-- Pull Request Info -->**@ |
|
118 |
- <div class="board-header issue" style="border-top:none;"> |
|
119 |
- <div class="title pull-left"> |
|
120 |
- <strong class="board-id">#@pull.number</strong> @pull.title |
|
121 |
- </div> |
|
122 |
- <div class="pull-right"> |
|
123 |
- <div class="date">@agoString(pull.createdAgo)</div> |
|
124 |
- <span class="badge badge-issue-@pull.state.state.toLowerCase">@Messages("issue.state." + pull.state.state)</span> |
|
125 |
- </div> |
|
126 |
- </div> |
|
127 | 20 |
|
128 |
- <div class="board-body"> |
|
129 |
- <div class="content markdown-wrap markdown-before" markdown="true">@pull.body</div> |
|
21 |
+ <div id="__info"> |
|
22 |
+ @**<!-- Pull Request Info -->**@ |
|
23 |
+ <div class="board-header issue" style="border-top:none;"> |
|
24 |
+ <div class="title pull-left"> |
|
25 |
+ <strong class="board-id">#@pull.number</strong> @pull.title |
|
130 | 26 |
</div> |
27 |
+ <div class="pull-right"> |
|
28 |
+ <div class="date">@agoString(pull.createdAgo)</div> |
|
29 |
+ <span class="badge badge-issue-@pull.state.state.toLowerCase">@Messages("issue.state." + pull.state.state)</span> |
|
30 |
+ </div> |
|
31 |
+ </div> |
|
131 | 32 |
|
33 |
+ <div class="board-body"> |
|
34 |
+ <div class="content markdown-wrap markdown-before" markdown="true">@pull.body</div> |
|
35 |
+ </div> |
|
36 |
+ |
|
37 |
+ @if(!pull.isMerging && pull.isOpen()){ |
|
38 |
+ @if(!pull.isConflict){ |
|
39 |
+ <div class="alert alert-success"> |
|
40 |
+ <h5>@Messages("pullRequest.is.safe")</h5> |
|
41 |
+ </div> |
|
42 |
+ } else { |
|
43 |
+ @partial_conflict_message(project, pull) |
|
44 |
+ } |
|
45 |
+ } |
|
46 |
+ |
|
47 |
+ @if(pull.isMerging) { |
|
48 |
+ <div class="alert alert-warnning"> |
|
49 |
+ <h5>@Messages("pullRequest.is.merging")</h5> |
|
50 |
+ </div> |
|
51 |
+ } |
|
52 |
+ |
|
53 |
+ <div id="attachments" class="attachments" data-resourceType="@ResourceType.PULL_REQUEST" data-resourceId="@pull.id"></div> |
|
54 |
+ |
|
55 |
+ <div class="board-footer board-actrow"> |
|
56 |
+ <button id="watch-button" type="button" class="ybtn @if(pull.getWatchers.contains(UserApp.currentUser())) { active }" data-toggle="button"> |
|
57 |
+ @if(pull.getWatchers.contains(UserApp.currentUser())) { |
|
58 |
+ @Messages("project.unwatch") |
|
59 |
+ } else { |
|
60 |
+ @Messages("project.watch") |
|
61 |
+ } |
|
62 |
+ </button> |
|
132 | 63 |
@if(!pull.isMerging && pull.isOpen()){ |
133 |
- @if(!pull.isConflict){ |
|
134 |
- <div class="alert alert-success"> |
|
135 |
- <h5>@Messages("pullRequest.is.safe")</h5> |
|
136 |
- </div> |
|
137 |
- } else { |
|
138 |
- @conflictMessage |
|
64 |
+ @if(!pull.isConflict && isAllowed(UserApp.currentUser(), pull.asResource(), Operation.ACCEPT)){ |
|
65 |
+ <a href="@routes.PullRequestApp.accept(project.owner, project.name, pull.number)" class="ybtn ybtn-success">@Messages("pullRequest.accept")</a> |
|
66 |
+ } |
|
67 |
+ @if(isAllowed(UserApp.currentUser(), pull.asResource(), Operation.REJECT)) { |
|
68 |
+ <a href="@routes.PullRequestApp.reject(project.owner, project.name, pull.number)" class="ybtn">@Messages("pullRequest.reject")</a> |
|
69 |
+ } |
|
70 |
+ @if(isAllowed(UserApp.currentUser(), pull.asResource(), Operation.UPDATE)) { |
|
71 |
+ <a href="@routes.PullRequestApp.editPullRequestForm(pull.toProject.owner, pull.toProject.name, pull.number)" class="ybtn">@Messages("button.edit")</a> |
|
139 | 72 |
} |
140 | 73 |
} |
141 |
- |
|
142 |
- @if(pull.isMerging) { |
|
143 |
- <div class="alert alert-warnning"> |
|
144 |
- <h5>@Messages("pullRequest.is.merging")</h5> |
|
145 |
- </div> |
|
146 |
- } |
|
147 | 74 |
|
148 |
- <div id="attachments" class="attachments" data-resourceType="@ResourceType.PULL_REQUEST" data-resourceId="@pull.id"></div> |
|
149 |
- |
|
150 |
- <div class="board-footer board-actrow"> |
|
151 |
- <button id="watch-button" type="button" class="ybtn @if(pull.getWatchers.contains(UserApp.currentUser())) { active }" data-toggle="button"> |
|
152 |
- @if(pull.getWatchers.contains(UserApp.currentUser())) { |
|
153 |
- @Messages("project.unwatch") |
|
154 |
- } else { |
|
155 |
- @Messages("project.watch") |
|
156 |
- } |
|
157 |
- </button> |
|
158 |
- @if(!pull.isMerging && pull.isOpen()){ |
|
159 |
- @if(!pull.isConflict && isAllowed(UserApp.currentUser(), pull.asResource(), Operation.ACCEPT)){ |
|
160 |
- <a href="@routes.PullRequestApp.accept(project.owner, project.name, pull.number)" class="ybtn ybtn-success">@Messages("pullRequest.accept")</a> |
|
161 |
- } |
|
162 |
- @if(isAllowed(UserApp.currentUser(), pull.asResource(), Operation.REJECT)) { |
|
163 |
- <a href="@routes.PullRequestApp.reject(project.owner, project.name, pull.number)" class="ybtn">@Messages("pullRequest.reject")</a> |
|
164 |
- } |
|
165 |
- @if(isAllowed(UserApp.currentUser(), pull.asResource(), Operation.UPDATE)) { |
|
166 |
- <a href="@routes.PullRequestApp.editPullRequestForm(pull.toProject.owner, pull.toProject.name, pull.number)" class="ybtn">@Messages("button.edit")</a> |
|
167 |
- } |
|
168 |
- } |
|
169 |
- |
|
170 |
- @if(!pull.isMerging && pull.isRejected()){ |
|
171 |
- @if(isAllowed(UserApp.currentUser(), pull.asResource(), Operation.REOPEN)) { |
|
172 |
- <a href="@routes.PullRequestApp.open(project.owner, project.name, pull.number)" class="ybtn">@Messages("pullRequest.reopen")</a> |
|
173 |
- } |
|
174 |
- } |
|
175 |
- </div> |
|
176 |
- @if(pull.isClosed()) { |
|
177 |
- <div class="alert alert-info"> |
|
178 |
- <a href="@routes.UserApp.userInfo(pull.receiver.loginId)"><img src="@pull.receiver.avatarUrl" width="25" height="25" class="img-rounded"></a> |
|
179 |
- <a href="@routes.UserApp.userInfo(pull.receiver.loginId)">@pull.receiver.name</a>@Messages("pullRequest.merged.the.pullrequest") |
|
180 |
- @if(UserApp.currentUser().equals(pull.contributor)) { |
|
181 |
- @if(canDeleteBranch) { |
|
182 |
- <code>@pull.fromBranch</code> @Messages("pullRequest.delete.frombranch.message") |
|
183 |
- <button class="ybtn ybtn-danger ybtn-mini pull-right" data-request-method="delete" data-request-uri="@routes.PullRequestApp.deleteFromBranch(project.owner, project.name, pull.number)">@Messages("pullRequest.delete.branch")</button> |
|
184 |
- } |
|
185 |
- @if(canRestoreBranch) { |
|
186 |
- <code>@pull.fromBranch</code> @Messages("pullRequest.restore.frombranch.message") |
|
187 |
- <a href="@routes.PullRequestApp.restoreFromBranch(project.owner, project.name, pull.id)" class="ybtn ybtn-info ybtn-mini pull-right">@Messages("pullRequest.restore.branch")</a> |
|
188 |
- } |
|
189 |
- } |
|
190 |
- </div> |
|
191 |
- } |
|
192 |
- <div class="board-comment-wrap"> |
|
193 |
- <div class="comment-header"><i class="yobicon-comments"></i><strong>@Messages("common.comment")</strong> <strong class="num">@{pull.comments.size() + pull.getCodeComments.size()}</strong></div> |
|
194 |
- |
|
195 |
- @if(pull.getTimelineComments.size > 0) { |
|
196 |
- <ul class="comments" id="comments"> |
|
197 |
- @partial_comments(pull, pull.getTimelineComments.toList) |
|
198 |
- </ul> |
|
199 |
- } |
|
200 |
- @common.commentForm(project, ResourceType.PULL_REQUEST_COMMENT, routes.PullRequestCommentApp.newComment(project.owner, project.name, pull.id).toString()) |
|
201 |
- </div> |
|
202 |
- </div> |
|
203 |
- |
|
204 |
- <div id="__commits" class="code-browse-wrap tab-pane @if(activeTab == "commits"){ active }"> |
|
205 |
- <div id="history" class="commit-wrap mt20"> |
|
206 |
- <table class="code-table commits"> |
|
207 |
- <thead class="thead"> |
|
208 |
- <tr> |
|
209 |
- <td class="commit-id"><strong>@{"@"}</strong></td> |
|
210 |
- <td class="messages"><strong>@Messages("code.commitMsg")</strong></td> |
|
211 |
- <td class="date"><strong>@Messages("code.commitDate")</strong></td> |
|
212 |
- <td class="author"><strong>@Messages("code.author")</strong></td> |
|
213 |
- </tr> |
|
214 |
- </thead> |
|
215 |
- <tbody class="tbody"> |
|
216 |
- @for(commit <- pull.getCurrentCommits) { |
|
217 |
- <tr> |
|
218 |
- <td class="commit-id"> |
|
219 |
- <a href="@routes.PullRequestApp.commitView(pull.toProject.owner, pull.toProject.name, pull.number, commit.getCommitId())"> |
|
220 |
- @commit.getCommitShortId() |
|
221 |
- <i class="yobicon-right"></i> |
|
222 |
- </a> |
|
223 |
- </td> |
|
224 |
- |
|
225 |
- <td class="messages"> |
|
226 |
- |
|
227 |
- @defining(CommitComment.count(pull.fromProject, commit.getCommitId, null)){ numOfComment => |
|
228 |
- @if(numOfComment > 0) { |
|
229 |
- <span class="number-of-comments"><i class="yobicon-comments"></i> @numOfComment</span> |
|
230 |
- } |
|
231 |
- } |
|
232 |
- |
|
233 |
- @defining(commit.getCommitMessage()){ commitMsg => |
|
234 |
- <a href="@routes.PullRequestApp.commitView(pull.toProject.owner, pull.toProject.name, pull.number, commit.getCommitId())"> |
|
235 |
- @commitMsg.split("\n")(0) |
|
236 |
- </a> |
|
237 |
- |
|
238 |
- @if(commitMsg.split("\n").length > 1){ |
|
239 |
- <button type="button" class="more">…</button> |
|
240 |
- <pre class="hidden">@commitMsg.replace(commitMsg.split("\n")(0)+"\n", "")</pre> |
|
241 |
- } |
|
242 |
- } |
|
243 |
- </td> |
|
244 |
- <td class="date">@agoString(ago(commit.getAuthorDate()))</td> |
|
245 |
- <td class="author @commit.getAuthorEmail"> |
|
246 |
- @defining(User.find.where.eq("email", commit.getAuthorEmail).findUnique) { user => |
|
247 |
- @if(user != null) { |
|
248 |
- <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap"> |
|
249 |
- <img src="@user.avatarUrl" alt="@user.name" width="32" height="32"/> |
|
250 |
- </a> |
|
251 |
- } else { |
|
252 |
- <div class="avatar-wrap"> |
|
253 |
- <img src="@urlToPicture(commit.getAuthorEmail(), 32)" width="32" height="32"/> |
|
254 |
- </div> |
|
255 |
- } |
|
256 |
- } |
|
257 |
- </td> |
|
258 |
- </tr> |
|
259 |
- } |
|
260 |
- </tbody> |
|
261 |
- </table> |
|
262 |
- </div> |
|
263 |
- </div> |
|
264 |
- |
|
265 |
- <div id="__changes" class="tab-pane @if(activeTab == "changes"){ active }"> |
|
266 |
- <div class="diff-body"> |
|
267 |
- @if(pull.isMerging) { |
|
268 |
- <div class="alert alert-warnning"> |
|
269 |
- <h5>@Messages("pullRequest.is.merging")</h5> |
|
270 |
- </div> |
|
271 |
- } else { |
|
272 |
- @if(pull.isConflict) { |
|
273 |
- @conflictMessage |
|
274 |
- } else { |
|
275 |
- @views.html.partial_diff(pull.getDiff, comments.filter(v => !v.isOutdated)) |
|
276 |
- } |
|
75 |
+ @if(!pull.isMerging && pull.isRejected()){ |
|
76 |
+ @if(isAllowed(UserApp.currentUser(), pull.asResource(), Operation.REOPEN)) { |
|
77 |
+ <a href="@routes.PullRequestApp.open(project.owner, project.name, pull.number)" class="ybtn">@Messages("pullRequest.reopen")</a> |
|
277 | 78 |
} |
278 |
- </div> |
|
279 |
- <div id="compare" class="modal hide compare-wrap" tabindex="-1" role="dialog"> |
|
280 |
- <h4 class="path"> |
|
281 |
- <span></span> |
|
282 |
- <button type="button" class="ybtn pull-right" data-dismiss="modal" style="margin-right:20px;">@Messages("button.confirm")</button> |
|
283 |
- </h4> |
|
284 |
- <div class="row-fluid"> |
|
285 |
- <div class="span6 compare-from"></div> |
|
286 |
- <div class="span6 compare-to"></div> |
|
287 |
- </div> |
|
288 |
- <div id="mergely" class="mergely-wrap"></div> |
|
289 |
- </div> |
|
79 |
+ } |
|
80 |
+ </div> |
|
81 |
+ @if(pull.isClosed()) { |
|
82 |
+ <div class="alert alert-info"> |
|
83 |
+ <a href="@routes.UserApp.userInfo(pull.receiver.loginId)"><img src="@pull.receiver.avatarUrl" width="25" height="25" class="img-rounded"></a> |
|
84 |
+ <a href="@routes.UserApp.userInfo(pull.receiver.loginId)">@pull.receiver.name</a>@Messages("pullRequest.merged.the.pullrequest") |
|
85 |
+ @if(UserApp.currentUser().equals(pull.contributor)) { |
|
86 |
+ @if(canDeleteBranch) { |
|
87 |
+ <code>@pull.fromBranch</code> @Messages("pullRequest.delete.frombranch.message") |
|
88 |
+ <button class="ybtn ybtn-danger ybtn-mini pull-right" data-request-method="delete" data-request-uri="@routes.PullRequestApp.deleteFromBranch(project.owner, project.name, pull.number)">@Messages("pullRequest.delete.branch")</button> |
|
89 |
+ } |
|
90 |
+ @if(canRestoreBranch) { |
|
91 |
+ <code>@pull.fromBranch</code> @Messages("pullRequest.restore.frombranch.message") |
|
92 |
+ <a href="@routes.PullRequestApp.restoreFromBranch(project.owner, project.name, pull.id)" class="ybtn ybtn-info ybtn-mini pull-right">@Messages("pullRequest.restore.branch")</a> |
|
93 |
+ } |
|
94 |
+ } |
|
95 |
+ </div> |
|
96 |
+ } |
|
97 |
+ <div class="board-comment-wrap"> |
|
98 |
+ <div class="comment-header"><i class="yobicon-comments"></i><strong>@Messages("common.comment")</strong> <strong class="num">@{pull.comments.size() + pull.getCommitComments.size()}</strong></div> |
|
99 |
+ |
|
100 |
+ @if(pull.getTimelineComments.size > 0) { |
|
101 |
+ <ul class="comments" id="comments"> |
|
102 |
+ @partial_comments(pull, pull.getTimelineComments.toList) |
|
103 |
+ </ul> |
|
104 |
+ } |
|
105 |
+ @common.commentForm(project, ResourceType.PULL_REQUEST_COMMENT, routes.PullRequestCommentApp.newComment(project.owner, project.name, pull.id).toString()) |
|
290 | 106 |
</div> |
291 | 107 |
</div> |
292 | 108 |
</div> |
... | ... | @@ -314,15 +130,6 @@ |
314 | 130 |
} else { |
315 | 131 |
url : "@Html(routes.ProjectApp.mentionListAtPullRequest(pull.toProject.owner, pull.toProject.name, pull.getCurrentCommits.get(0).getCommitId, pull.id).toString)" |
316 | 132 |
} |
317 |
- }); |
|
318 |
- |
|
319 |
- $yobi.loadModule("code.Diff", { |
|
320 |
- "welDiff" : $("#pull-request-changes"), |
|
321 |
- "bCommentable" : "@isProjectResourceCreatable(UserApp.currentUser, project, ResourceType.PULL_REQUEST_COMMENT)", |
|
322 |
- "sTplFileURLA" : "@routes.CodeApp.codeBrowserWithBranch(pull.toProject.owner, pull.toProject.name, "${commitId}", "${path}")", |
|
323 |
- "sTplFileURLB" : "@routes.CodeApp.codeBrowserWithBranch(pull.fromProject.owner, pull.fromProject.name, "${commitId}", "${path}")", |
|
324 |
- "sTplRawURLA" : "@routes.CodeApp.showRawFile(pull.toProject.owner, pull.toProject.name, "${commitId}", "${path}")", |
|
325 |
- "sTplRawURLB" : "@routes.CodeApp.showRawFile(pull.fromProject.owner, pull.fromProject.name, "${commitId}", "${path}")" |
|
326 | 133 |
}); |
327 | 134 |
}); |
328 | 135 |
</script> |
+++ app/views/git/viewChanges.scala.html
... | ... | @@ -0,0 +1,80 @@ |
1 | +@(project: Project, pull: PullRequest, comments: List[PullRequestComment]) | |
2 | + | |
3 | +@import utils.JodaDateUtil._ | |
4 | +@import utils.TemplateHelper._ | |
5 | +@import utils.AccessControl._ | |
6 | +@import models.enumeration | |
7 | +@import scala.collection.JavaConversions._ | |
8 | + | |
9 | +@projectLayout(Messages("menu.pullRequest"), project, utils.MenuType.PULL_REQUEST) { | |
10 | + <div class="page"> | |
11 | + @projectMenu(project, utils.MenuType.PULL_REQUEST, "main-menu-only") | |
12 | + | |
13 | + @partial_info(project, pull) | |
14 | + | |
15 | + <ul class="nav nav-tabs nm"> | |
16 | + <li><a href="@routes.PullRequestApp.pullRequest(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.overview")</a></li> | |
17 | + <li><a href="@routes.PullRequestApp.pullRequestCommits(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.commit")</a></li> | |
18 | + <li class="active"><a href="@routes.PullRequestApp.pullRequestChanges(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.changes")</a></li> | |
19 | + </ul> | |
20 | + | |
21 | + <div id="__changes"> | |
22 | + <div class="diff-body"> | |
23 | + @if(pull.isMerging) { | |
24 | + <div class="alert alert-warnning"> | |
25 | + <h5>@Messages("pullRequest.is.merging")</h5> | |
26 | + </div> | |
27 | + } else { | |
28 | + @if(pull.isConflict) { | |
29 | + @partial_conflict_message(project, pull) | |
30 | + } else { | |
31 | + @views.html.partial_diff(pull.getDiff, comments.filter(v => !v.isOutdated)) | |
32 | + } | |
33 | + } | |
34 | + </div> | |
35 | + <div id="compare" class="modal hide compare-wrap" tabindex="-1" role="dialog"> | |
36 | + <h4 class="path"> | |
37 | + <span></span> | |
38 | + <button type="button" class="ybtn pull-right" data-dismiss="modal" style="margin-right:20px;">@Messages("button.confirm")</button> | |
39 | + </h4> | |
40 | + <div class="row-fluid"> | |
41 | + <div class="span6 compare-from"></div> | |
42 | + <div class="span6 compare-to"></div> | |
43 | + </div> | |
44 | + <div id="mergely" class="mergely-wrap"></div> | |
45 | + </div> | |
46 | + </div> | |
47 | + @common.commentForm(project, ResourceType.PULL_REQUEST_COMMENT, routes.PullRequestCommentApp.newComment(project.owner, project.name, pull.id).toString()) | |
48 | + </div> | |
49 | + | |
50 | +@common.markdown(project) | |
51 | + | |
52 | +<link rel="stylesheet" type="text/css" media="screen" href="@routes.Assets.at("javascripts/lib/mergely/codemirror.css")"> | |
53 | +<link rel="stylesheet" type="text/css" media="screen" href="@routes.Assets.at("javascripts/lib/mergely/mergely.css")"> | |
54 | +<link rel="stylesheet" type="text/css" media="screen" href="@getCSSLink("mention")"> | |
55 | +<script type="text/javascript" src="@getJSLink("lib/mentionjs/mention")"></script> | |
56 | +<script type="text/javascript" src="@getJSLink("lib/diff")"></script> | |
57 | +<script type="text/javascript" src="@getJSLink("lib/mergely/codemirror.min")"></script> | |
58 | +<script type="text/javascript" src="@getJSLink("lib/mergely/mergely")"></script> | |
59 | +<script type="text/javascript"> | |
60 | + $(document).ready(function() { | |
61 | + yobi.Mention({ | |
62 | + target:'comment-editor', | |
63 | + @if(pull.getCurrentCommits.isEmpty()) { | |
64 | + url : "@Html(routes.ProjectApp.mentionListAtPullRequest(pull.toProject.owner, pull.toProject.name, "", pull.id).toString)" | |
65 | + } else { | |
66 | + url : "@Html(routes.ProjectApp.mentionListAtPullRequest(pull.toProject.owner, pull.toProject.name, pull.getCurrentCommits.get(0).getCommitId, pull.id).toString)" | |
67 | + } | |
68 | + }); | |
69 | + | |
70 | + $yobi.loadModule("code.Diff", { | |
71 | + "welDiff" : $("#pull-request-changes"), | |
72 | + "bCommentable" : "@isProjectResourceCreatable(UserApp.currentUser, project, ResourceType.PULL_REQUEST_COMMENT)", | |
73 | + "sTplFileURLA" : "@routes.CodeApp.codeBrowserWithBranch(pull.toProject.owner, pull.toProject.name, "${commitId}", "${path}")", | |
74 | + "sTplFileURLB" : "@routes.CodeApp.codeBrowserWithBranch(pull.fromProject.owner, pull.fromProject.name, "${commitId}", "${path}")", | |
75 | + "sTplRawURLA" : "@routes.CodeApp.showRawFile(pull.toProject.owner, pull.toProject.name, "${commitId}", "${path}")", | |
76 | + "sTplRawURLB" : "@routes.CodeApp.showRawFile(pull.fromProject.owner, pull.fromProject.name, "${commitId}", "${path}")" | |
77 | + }); | |
78 | + }); | |
79 | +</script> | |
80 | +} |
--- app/views/git/viewCommits.scala.html
+++ app/views/git/viewCommits.scala.html
... | ... | @@ -1,44 +1,25 @@ |
1 |
-@(project: Project, pull: PullRequest, commits: List[playRepository.GitCommit]) |
|
1 |
+@(project: Project, pull: PullRequest) |
|
2 | 2 |
|
3 | 3 |
@import utils.JodaDateUtil._ |
4 | 4 |
@import utils.TemplateHelper._ |
5 |
-@import java.net.URLEncoder |
|
5 |
+@import utils.AccessControl._ |
|
6 |
+@import models.enumeration |
|
7 |
+@import scala.collection.JavaConversions._ |
|
6 | 8 |
|
7 | 9 |
@projectLayout(Messages("menu.pullRequest"), project, utils.MenuType.PULL_REQUEST) { |
8 | 10 |
<div class="page"> |
9 | 11 |
@projectMenu(project, utils.MenuType.PULL_REQUEST, "main-menu-only") |
10 | 12 |
|
11 |
- <p> |
|
12 |
- @Messages("pullRequest.from") |
|
13 |
- <span class="label label-info"> |
|
14 |
- <a href="@routes.UserApp.userInfo(pull.fromProject.owner)">@pull.fromProject.owner</a> / |
|
15 |
- <a href="@routes.ProjectApp.project(pull.fromProject.owner, pull.fromProject.name)">@pull.fromProject.name</a> |
|
16 |
- </span> |
|
17 |
- <a href="@routes.CodeApp.codeBrowserWithBranch(pull.fromProject.owner, pull.fromProject.name, pull.fromBranch, "")" class="label label-success">@pull.fromBranch</a> |
|
13 |
+ @partial_info(project, pull) |
|
18 | 14 |
|
19 |
- @Messages("pullRequest.to") |
|
20 |
- <span class="label label-info"> |
|
21 |
- <a href="@routes.UserApp.userInfo(pull.toProject.owner)">@pull.toProject.owner</a> / |
|
22 |
- <a href="@routes.ProjectApp.project(pull.toProject.owner, pull.toProject.name)">@pull.toProject.name</a> |
|
23 |
- </span> |
|
24 |
- <a href="@routes.CodeApp.codeBrowserWithBranch(pull.toProject.owner, pull.toProject.name, pull.toBranch, "")" class="label label-success">@pull.toBranch</a> |
|
25 |
- </p> |
|
26 |
- |
|
27 |
- <ul class="nav nav-tabs yobi-tabs"> |
|
28 |
- <li> |
|
29 |
- <a href="@routes.PullRequestApp.pullRequest(project.owner, project.name, pull.id)"> |
|
30 |
- @Messages("pullRequest.menu.overview") |
|
31 |
- </a> |
|
32 |
- </li> |
|
33 |
- <li class="active"> |
|
34 |
- <a href="@routes.PullRequestApp.pullRequestCommits(project.owner, project.name, pull.id)"> |
|
35 |
- @Messages("pullRequest.menu.commit") |
|
36 |
- </a> |
|
37 |
- </li> |
|
15 |
+ <ul class="nav nav-tabs nm"> |
|
16 |
+ <li><a href="@routes.PullRequestApp.pullRequest(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.overview")</a></li> |
|
17 |
+ <li class="active"><a href="@routes.PullRequestApp.pullRequestCommits(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.commit")</a></li> |
|
18 |
+ <li><a href="@routes.PullRequestApp.pullRequestChanges(project.owner, project.name, pull.number)">@Messages("pullRequest.menu.changes")</a></li> |
|
38 | 19 |
</ul> |
39 | 20 |
|
40 |
- <div class="code-browse-wrap"> |
|
41 |
- <div id="history" class="commit-wrap"> |
|
21 |
+ <div id="__commits" class="code-browse-wrap"> |
|
22 |
+ <div id="history" class="commit-wrap mt20"> |
|
42 | 23 |
<table class="code-table commits"> |
43 | 24 |
<thead class="thead"> |
44 | 25 |
<tr> |
... | ... | @@ -49,18 +30,37 @@ |
49 | 30 |
</tr> |
50 | 31 |
</thead> |
51 | 32 |
<tbody class="tbody"> |
52 |
- @for(commit <- commits.iterator()) { |
|
33 |
+ @for(commit <- pull.getCurrentCommits) { |
|
53 | 34 |
<tr> |
54 | 35 |
<td class="commit-id"> |
55 |
- <a href="@routes.CodeHistoryApp.show(pull.fromProject.owner, pull.fromProject.name, commit.getId())?branch=@URLEncoder.encode(pull.fromBranch, "UTF-8")"> |
|
56 |
- @commit.getShortId() |
|
36 |
+ <a href="@routes.PullRequestApp.commitView(pull.toProject.owner, pull.toProject.name, pull.number, commit.getCommitId())"> |
|
37 |
+ @commit.getCommitShortId() |
|
57 | 38 |
<i class="yobicon-right"></i> |
58 | 39 |
</a> |
59 | 40 |
</td> |
60 |
- <td class="messages">@commit.getMessage()</td> |
|
41 |
+ |
|
42 |
+ <td class="messages"> |
|
43 |
+ |
|
44 |
+ @defining(CommitComment.count(pull.fromProject, commit.getCommitId, null)){ numOfComment => |
|
45 |
+ @if(numOfComment > 0) { |
|
46 |
+ <span class="number-of-comments"><i class="yobicon-comments"></i> @numOfComment</span> |
|
47 |
+ } |
|
48 |
+ } |
|
49 |
+ |
|
50 |
+ @defining(commit.getCommitMessage()){ commitMsg => |
|
51 |
+ <a href="@routes.PullRequestApp.commitView(pull.toProject.owner, pull.toProject.name, pull.number, commit.getCommitId())"> |
|
52 |
+ @commitMsg.split("\n")(0) |
|
53 |
+ </a> |
|
54 |
+ |
|
55 |
+ @if(commitMsg.split("\n").length > 1){ |
|
56 |
+ <button type="button" class="more">…</button> |
|
57 |
+ <pre class="hidden">@commitMsg.replace(commitMsg.split("\n")(0)+"\n", "")</pre> |
|