##// END OF EJS Templates
diff-navigation: small improvements on text and display of navigation menu.
marcink -
r4446:e6192ffb default
parent child Browse files
Show More
@@ -1,302 +1,302 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%inherit file="/base/base.mako"/>
4 4 <%namespace name="base" file="/base/base.mako"/>
5 5 <%namespace name="diff_block" file="/changeset/diff_block.mako"/>
6 6 <%namespace name="file_base" file="/files/base.mako"/>
7 7
8 8 <%def name="title()">
9 9 ${_('{} Commit').format(c.repo_name)} - ${h.show_id(c.commit)}
10 10 %if c.rhodecode_name:
11 11 &middot; ${h.branding(c.rhodecode_name)}
12 12 %endif
13 13 </%def>
14 14
15 15 <%def name="menu_bar_nav()">
16 16 ${self.menu_items(active='repositories')}
17 17 </%def>
18 18
19 19 <%def name="menu_bar_subnav()">
20 20 ${self.repo_menu(active='commits')}
21 21 </%def>
22 22
23 23 <%def name="main()">
24 24 <script type="text/javascript">
25 25 // TODO: marcink switch this to pyroutes
26 26 AJAX_COMMENT_DELETE_URL = "${h.route_path('repo_commit_comment_delete',repo_name=c.repo_name,commit_id=c.commit.raw_id,comment_id='__COMMENT_ID__')}";
27 27 templateContext.commit_data.commit_id = "${c.commit.raw_id}";
28 28 </script>
29 29
30 30 <div class="box">
31 31
32 32 <div class="summary">
33 33
34 34 <div class="fieldset">
35 35 <div class="left-content">
36 36 <%
37 37 rc_user = h.discover_user(c.commit.author_email)
38 38 %>
39 39 <div class="left-content-avatar">
40 40 ${base.gravatar(c.commit.author_email, 30, tooltip=(True if rc_user else False), user=rc_user)}
41 41 </div>
42 42
43 43 <div class="left-content-message">
44 44 <div class="fieldset collapsable-content no-hide" data-toggle="summary-details">
45 45 <div class="commit truncate-wrap">${h.urlify_commit_message(h.chop_at_smart(c.commit.message, '\n', suffix_if_chopped='...'), c.repo_name)}</div>
46 46 </div>
47 47
48 48 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none">
49 49 <div class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
50 50 </div>
51 51
52 52 <div class="fieldset" data-toggle="summary-details">
53 53 <div class="">
54 54 <table>
55 55 <tr class="file_author">
56 56
57 57 <td>
58 58 <span class="user commit-author">${h.link_to_user(rc_user or c.commit.author)}</span>
59 59 <span class="commit-date">- ${h.age_component(c.commit.date)}</span>
60 60 </td>
61 61
62 62 <td>
63 63 ## second cell for consistency with files
64 64 </td>
65 65 </tr>
66 66 </table>
67 67 </div>
68 68 </div>
69 69
70 70 </div>
71 71 </div>
72 72
73 73 <div class="right-content">
74 74
75 75 <div data-toggle="summary-details">
76 76 <div class="tags tags-main">
77 77 <code><a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.commit.raw_id)}">${h.show_id(c.commit)}</a></code>
78 78 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${c.commit.raw_id}" title="${_('Copy the full commit id')}"></i>
79 79 ${file_base.refs(c.commit)}
80 80
81 81 ## phase
82 82 % if hasattr(c.commit, 'phase') and getattr(c.commit, 'phase') != 'public':
83 83 <span class="tag phase-${c.commit.phase} tooltip" title="${_('Commit phase')}">
84 84 <i class="icon-info"></i>${c.commit.phase}
85 85 </span>
86 86 % endif
87 87
88 88 ## obsolete commits
89 89 % if getattr(c.commit, 'obsolete', False):
90 90 <span class="tag obsolete-${c.commit.obsolete} tooltip" title="${_('Evolve State')}">
91 91 ${_('obsolete')}
92 92 </span>
93 93 % endif
94 94
95 95 ## hidden commits
96 96 % if getattr(c.commit, 'hidden', False):
97 97 <span class="tag hidden-${c.commit.hidden} tooltip" title="${_('Evolve State')}">
98 98 ${_('hidden')}
99 99 </span>
100 100 % endif
101 101 </div>
102 102
103 103 %if c.statuses:
104 104 <div class="tag status-tag-${c.statuses[0]} pull-right">
105 105 <i class="icon-circle review-status-${c.statuses[0]}"></i>
106 106 <div class="pull-right">${h.commit_status_lbl(c.statuses[0])}</div>
107 107 </div>
108 108 %endif
109 109
110 110 </div>
111 111
112 112 </div>
113 113 </div>
114 114
115 115 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
116 116 <div class="left-label-summary">
117 117 <p>${_('Commit navigation')}:</p>
118 118 <div class="right-label-summary">
119 119 <span id="parent_link" class="tag tagtag">
120 120 <a href="#parentCommit" title="${_('Parent Commit')}"><i class="icon-left icon-no-margin"></i>${_('parent')}</a>
121 121 </span>
122 122
123 123 <span id="child_link" class="tag tagtag">
124 124 <a href="#childCommit" title="${_('Child Commit')}">${_('child')}<i class="icon-right icon-no-margin"></i></a>
125 125 </span>
126 126 </div>
127 127 </div>
128 128 </div>
129 129
130 130 <div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
131 131 <div class="left-label-summary">
132 132 <p>${_('Diff options')}:</p>
133 133 <div class="right-label-summary">
134 134 <div class="diff-actions">
135 135 <a href="${h.route_path('repo_commit_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id)}">
136 136 ${_('Raw Diff')}
137 137 </a>
138 138 |
139 139 <a href="${h.route_path('repo_commit_patch',repo_name=c.repo_name,commit_id=c.commit.raw_id)}">
140 140 ${_('Patch Diff')}
141 141 </a>
142 142 |
143 143 <a href="${h.route_path('repo_commit_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,_query=dict(diff='download'))}">
144 144 ${_('Download Diff')}
145 145 </a>
146 146 </div>
147 147 </div>
148 148 </div>
149 149 </div>
150 150
151 151 <div class="clear-fix"></div>
152 152
153 153 <div class="btn-collapse" data-toggle="summary-details">
154 154 ${_('Show More')}
155 155 </div>
156 156
157 157 </div>
158 158
159 159 <div class="cs_files">
160 160 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
161 ${cbdiffs.render_diffset_menu(c.changes[c.commit.raw_id])}
161 ${cbdiffs.render_diffset_menu(c.changes[c.commit.raw_id], commit=c.commit)}
162 162 ${cbdiffs.render_diffset(
163 163 c.changes[c.commit.raw_id], commit=c.commit, use_comments=True,inline_comments=c.inline_comments )}
164 164 </div>
165 165
166 166 ## template for inline comment form
167 167 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
168 168
169 169 ## comments heading with count
170 170 <div class="comments-heading">
171 171 <i class="icon-comment"></i>
172 172 ${_('Comments')} ${len(c.comments)}
173 173 </div>
174 174
175 175 ## render comments
176 176 ${comment.generate_comments(c.comments)}
177 177
178 178 ## main comment form and it status
179 179 ${comment.comments(h.route_path('repo_commit_comment_create', repo_name=c.repo_name, commit_id=c.commit.raw_id),
180 180 h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
181 181 </div>
182 182
183 183 ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
184 184 <script type="text/javascript">
185 185
186 186 $(document).ready(function() {
187 187
188 188 var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10);
189 189 if($('#trimmed_message_box').height() === boxmax){
190 190 $('#message_expand').show();
191 191 }
192 192
193 193 $('#message_expand').on('click', function(e){
194 194 $('#trimmed_message_box').css('max-height', 'none');
195 195 $(this).hide();
196 196 });
197 197
198 198 $('.show-inline-comments').on('click', function(e){
199 199 var boxid = $(this).attr('data-comment-id');
200 200 var button = $(this);
201 201
202 202 if(button.hasClass("comments-visible")) {
203 203 $('#{0} .inline-comments'.format(boxid)).each(function(index){
204 204 $(this).hide();
205 205 });
206 206 button.removeClass("comments-visible");
207 207 } else {
208 208 $('#{0} .inline-comments'.format(boxid)).each(function(index){
209 209 $(this).show();
210 210 });
211 211 button.addClass("comments-visible");
212 212 }
213 213 });
214 214
215 215 // next links
216 216 $('#child_link').on('click', function(e){
217 217 // fetch via ajax what is going to be the next link, if we have
218 218 // >1 links show them to user to choose
219 219 if(!$('#child_link').hasClass('disabled')){
220 220 $.ajax({
221 221 url: '${h.route_path('repo_commit_children',repo_name=c.repo_name, commit_id=c.commit.raw_id)}',
222 222 success: function(data) {
223 223 if(data.results.length === 0){
224 224 $('#child_link').html("${_('No Child Commits')}").addClass('disabled');
225 225 }
226 226 if(data.results.length === 1){
227 227 var commit = data.results[0];
228 228 window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id});
229 229 }
230 230 else if(data.results.length === 2){
231 231 $('#child_link').addClass('disabled');
232 232 $('#child_link').addClass('double');
233 233
234 234 var _html = '';
235 235 _html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a> '
236 236 .replace('__branch__', data.results[0].branch)
237 237 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
238 238 .replace('__title__', data.results[0].message)
239 239 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id}));
240 240 _html +=' | ';
241 241 _html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a> '
242 242 .replace('__branch__', data.results[1].branch)
243 243 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
244 244 .replace('__title__', data.results[1].message)
245 245 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id}));
246 246 $('#child_link').html(_html);
247 247 }
248 248 }
249 249 });
250 250 e.preventDefault();
251 251 }
252 252 });
253 253
254 254 // prev links
255 255 $('#parent_link').on('click', function(e){
256 256 // fetch via ajax what is going to be the next link, if we have
257 257 // >1 links show them to user to choose
258 258 if(!$('#parent_link').hasClass('disabled')){
259 259 $.ajax({
260 260 url: '${h.route_path("repo_commit_parents",repo_name=c.repo_name, commit_id=c.commit.raw_id)}',
261 261 success: function(data) {
262 262 if(data.results.length === 0){
263 263 $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
264 264 }
265 265 if(data.results.length === 1){
266 266 var commit = data.results[0];
267 267 window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id});
268 268 }
269 269 else if(data.results.length === 2){
270 270 $('#parent_link').addClass('disabled');
271 271 $('#parent_link').addClass('double');
272 272
273 273 var _html = '';
274 274 _html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a>'
275 275 .replace('__branch__', data.results[0].branch)
276 276 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
277 277 .replace('__title__', data.results[0].message)
278 278 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id}));
279 279 _html +=' | ';
280 280 _html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a>'
281 281 .replace('__branch__', data.results[1].branch)
282 282 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
283 283 .replace('__title__', data.results[1].message)
284 284 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id}));
285 285 $('#parent_link').html(_html);
286 286 }
287 287 }
288 288 });
289 289 e.preventDefault();
290 290 }
291 291 });
292 292
293 293 // browse tree @ revision
294 294 $('#files_link').on('click', function(e){
295 295 window.location = '${h.route_path('repo_files:default_path',repo_name=c.repo_name, commit_id=c.commit.raw_id)}';
296 296 e.preventDefault();
297 297 });
298 298
299 299 })
300 300 </script>
301 301
302 302 </%def>
@@ -1,1355 +1,1369 b''
1 1 <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/>
2 2
3 3 <%def name="diff_line_anchor(commit, filename, line, type)"><%
4 4 return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
5 5 %></%def>
6 6
7 7 <%def name="action_class(action)">
8 8 <%
9 9 return {
10 10 '-': 'cb-deletion',
11 11 '+': 'cb-addition',
12 12 ' ': 'cb-context',
13 13 }.get(action, 'cb-empty')
14 14 %>
15 15 </%def>
16 16
17 17 <%def name="op_class(op_id)">
18 18 <%
19 19 return {
20 20 DEL_FILENODE: 'deletion', # file deleted
21 21 BIN_FILENODE: 'warning' # binary diff hidden
22 22 }.get(op_id, 'addition')
23 23 %>
24 24 </%def>
25 25
26 26
27 27
28 28 <%def name="render_diffset(diffset, commit=None,
29 29
30 30 # collapse all file diff entries when there are more than this amount of files in the diff
31 31 collapse_when_files_over=20,
32 32
33 33 # collapse lines in the diff when more than this amount of lines changed in the file diff
34 34 lines_changed_limit=500,
35 35
36 36 # add a ruler at to the output
37 37 ruler_at_chars=0,
38 38
39 39 # show inline comments
40 40 use_comments=False,
41 41
42 42 # disable new comments
43 43 disable_new_comments=False,
44 44
45 45 # special file-comments that were deleted in previous versions
46 46 # it's used for showing outdated comments for deleted files in a PR
47 47 deleted_files_comments=None,
48 48
49 49 # for cache purpose
50 50 inline_comments=None,
51 51
52 52 # additional menu for PRs
53 53 pull_request_menu=None,
54 54
55 55 # show/hide todo next to comments
56 56 show_todos=True,
57 57
58 58 )">
59 59
60 60 <%
61 61 diffset_container_id = h.md5(diffset.target_ref)
62 62 collapse_all = len(diffset.files) > collapse_when_files_over
63 63 active_pattern_entries = h.get_active_pattern_entries(getattr(c, 'repo_name', None))
64 64 %>
65 65
66 66 %if use_comments:
67 67
68 68 ## Template for injecting comments
69 69 <div id="cb-comments-inline-container-template" class="js-template">
70 70 ${inline_comments_container([])}
71 71 </div>
72 72
73 73 <div class="js-template" id="cb-comment-inline-form-template">
74 74 <div class="comment-inline-form ac">
75 75
76 76 %if c.rhodecode_user.username != h.DEFAULT_USER:
77 77 ## render template for inline comments
78 78 ${commentblock.comment_form(form_type='inline')}
79 79 %else:
80 80 ${h.form('', class_='inline-form comment-form-login', method='get')}
81 81 <div class="pull-left">
82 82 <div class="comment-help pull-right">
83 83 ${_('You need to be logged in to leave comments.')} <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a>
84 84 </div>
85 85 </div>
86 86 <div class="comment-button pull-right">
87 87 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
88 88 ${_('Cancel')}
89 89 </button>
90 90 </div>
91 91 <div class="clearfix"></div>
92 92 ${h.end_form()}
93 93 %endif
94 94 </div>
95 95 </div>
96 96
97 97 %endif
98 98
99 99 %if c.user_session_attrs["diffmode"] == 'sideside':
100 100 <style>
101 101 .wrapper {
102 102 max-width: 1600px !important;
103 103 }
104 104 </style>
105 105 %endif
106 106
107 107 %if ruler_at_chars:
108 108 <style>
109 109 .diff table.cb .cb-content:after {
110 110 content: "";
111 111 border-left: 1px solid blue;
112 112 position: absolute;
113 113 top: 0;
114 114 height: 18px;
115 115 opacity: .2;
116 116 z-index: 10;
117 117 //## +5 to account for diff action (+/-)
118 118 left: ${ruler_at_chars + 5}ch;
119 119 </style>
120 120 %endif
121 121
122 122 <div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}">
123 123
124 124 <div style="height: 20px; line-height: 20px">
125 125 ## expand/collapse action
126 126 <div class="pull-left">
127 127 <a class="${'collapsed' if collapse_all else ''}" href="#expand-files" onclick="toggleExpand(this, '${diffset_container_id}'); return false">
128 128 % if collapse_all:
129 129 <i class="icon-plus-squared-alt icon-no-margin"></i>${_('Expand all files')}
130 130 % else:
131 131 <i class="icon-minus-squared-alt icon-no-margin"></i>${_('Collapse all files')}
132 132 % endif
133 133 </a>
134 134
135 135 </div>
136 136
137 137 ## todos
138 138 % if show_todos and getattr(c, 'at_version', None):
139 139 <div class="pull-right">
140 140 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
141 141 ${_('not available in this view')}
142 142 </div>
143 143 % elif show_todos:
144 144 <div class="pull-right">
145 145 <div class="comments-number" style="padding-left: 10px">
146 146 % if hasattr(c, 'unresolved_comments') and hasattr(c, 'resolved_comments'):
147 147 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
148 148 % if c.unresolved_comments:
149 149 <a href="#show-todos" onclick="$('#todo-box').toggle(); return false">
150 150 ${_('{} unresolved').format(len(c.unresolved_comments))}
151 151 </a>
152 152 % else:
153 153 ${_('0 unresolved')}
154 154 % endif
155 155
156 156 ${_('{} Resolved').format(len(c.resolved_comments))}
157 157 % endif
158 158 </div>
159 159 </div>
160 160 % endif
161 161
162 162 ## comments
163 163 <div class="pull-right">
164 164 <div class="comments-number" style="padding-left: 10px">
165 165 % if hasattr(c, 'comments') and hasattr(c, 'inline_cnt'):
166 166 <i class="icon-comment" style="color: #949494">COMMENTS:</i>
167 167 % if c.comments:
168 168 <a href="#comments">${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))}</a>,
169 169 % else:
170 170 ${_('0 General')}
171 171 % endif
172 172
173 173 % if c.inline_cnt:
174 174 <a href="#" onclick="return Rhodecode.comments.nextComment();"
175 175 id="inline-comments-counter">${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(c.inline_cnt)}
176 176 </a>
177 177 % else:
178 178 ${_('0 Inline')}
179 179 % endif
180 180 % endif
181 181
182 182 % if pull_request_menu:
183 183 <%
184 184 outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver']
185 185 %>
186 186
187 187 % if outdated_comm_count_ver:
188 188 <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">
189 189 (${_("{} Outdated").format(outdated_comm_count_ver)})
190 190 </a>
191 191 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a>
192 192 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a>
193 193 % else:
194 194 (${_("{} Outdated").format(outdated_comm_count_ver)})
195 195 % endif
196 196
197 197 % endif
198 198
199 199 </div>
200 200 </div>
201 201
202 202 </div>
203 203
204 204 % if diffset.limited_diff:
205 205 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
206 206 <h2 class="clearinner">
207 207 ${_('The requested changes are too big and content was truncated.')}
208 208 <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
209 209 </h2>
210 210 </div>
211 211 ## commit range header for each individual diff
212 212 % elif commit and hasattr(c, 'commit_ranges') and len(c.commit_ranges) > 1:
213 213 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
214 214 <div class="clearinner">
215 215 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=diffset.repo_name,commit_id=commit.raw_id)}">${('r%s:%s' % (commit.idx,h.short_id(commit.raw_id)))}</a>
216 216 </div>
217 217 </div>
218 218 % endif
219 219
220 220 <div id="todo-box">
221 221 % if hasattr(c, 'unresolved_comments') and c.unresolved_comments:
222 222 % for co in c.unresolved_comments:
223 223 <a class="permalink" href="#comment-${co.comment_id}"
224 224 onclick="Rhodecode.comments.scrollToComment($('#comment-${co.comment_id}'))">
225 225 <i class="icon-flag-filled-red"></i>
226 226 ${co.comment_id}</a>${('' if loop.last else ',')}
227 227 % endfor
228 228 % endif
229 229 </div>
230 230 %if diffset.has_hidden_changes:
231 231 <p class="empty_data">${_('Some changes may be hidden')}</p>
232 232 %elif not diffset.files:
233 233 <p class="empty_data">${_('No files')}</p>
234 234 %endif
235 235
236 236 <div class="filediffs">
237 237
238 238 ## initial value could be marked as False later on
239 239 <% over_lines_changed_limit = False %>
240 240 %for i, filediff in enumerate(diffset.files):
241 241
242 242 <%
243 243 lines_changed = filediff.patch['stats']['added'] + filediff.patch['stats']['deleted']
244 244 over_lines_changed_limit = lines_changed > lines_changed_limit
245 245 %>
246 246 ## anchor with support of sticky header
247 247 <div class="anchor" id="a_${h.FID(filediff.raw_id, filediff.patch['filename'])}"></div>
248 248
249 249 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filediff)}" type="checkbox" onchange="updateSticky();">
250 250 <div
251 251 class="filediff"
252 252 data-f-path="${filediff.patch['filename']}"
253 253 data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}"
254 254 >
255 255 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
256 256 <%
257 257 file_comments = (get_inline_comments(inline_comments, filediff.patch['filename']) or {}).values()
258 258 total_file_comments = [_c for _c in h.itertools.chain.from_iterable(file_comments) if not _c.outdated]
259 259 %>
260 260 <div class="filediff-collapse-indicator icon-"></div>
261 261 <span class="pill-group pull-right" >
262 262 <span class="pill" op="comments">
263 263
264 264 <i class="icon-comment"></i> ${len(total_file_comments)}
265 265 </span>
266 266 </span>
267 267 ${diff_ops(filediff)}
268 268
269 269 </label>
270 270
271 271 ${diff_menu(filediff, use_comments=use_comments)}
272 272 <table data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
273 273
274 274 ## new/deleted/empty content case
275 275 % if not filediff.hunks:
276 276 ## Comment container, on "fakes" hunk that contains all data to render comments
277 277 ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], filediff.hunk_ops, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)}
278 278 % endif
279 279
280 280 %if filediff.limited_diff:
281 281 <tr class="cb-warning cb-collapser">
282 282 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
283 283 ${_('The requested commit or file is too big and content was truncated.')} <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
284 284 </td>
285 285 </tr>
286 286 %else:
287 287 %if over_lines_changed_limit:
288 288 <tr class="cb-warning cb-collapser">
289 289 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
290 290 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
291 291 <a href="#" class="cb-expand"
292 292 onclick="$(this).closest('table').removeClass('cb-collapsed'); updateSticky(); return false;">${_('Show them')}
293 293 </a>
294 294 <a href="#" class="cb-collapse"
295 295 onclick="$(this).closest('table').addClass('cb-collapsed'); updateSticky(); return false;">${_('Hide them')}
296 296 </a>
297 297 </td>
298 298 </tr>
299 299 %endif
300 300 %endif
301 301
302 302 % for hunk in filediff.hunks:
303 303 <tr class="cb-hunk">
304 304 <td ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=3' or '')}>
305 305 ## TODO: dan: add ajax loading of more context here
306 306 ## <a href="#">
307 307 <i class="icon-more"></i>
308 308 ## </a>
309 309 </td>
310 310 <td ${(c.user_session_attrs["diffmode"] == 'sideside' and 'colspan=5' or '')}>
311 311 @@
312 312 -${hunk.source_start},${hunk.source_length}
313 313 +${hunk.target_start},${hunk.target_length}
314 314 ${hunk.section_header}
315 315 </td>
316 316 </tr>
317 317
318 318 ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)}
319 319 % endfor
320 320
321 321 <% unmatched_comments = (inline_comments or {}).get(filediff.patch['filename'], {}) %>
322 322
323 323 ## outdated comments that do not fit into currently displayed lines
324 324 % for lineno, comments in unmatched_comments.items():
325 325
326 326 %if c.user_session_attrs["diffmode"] == 'unified':
327 327 % if loop.index == 0:
328 328 <tr class="cb-hunk">
329 329 <td colspan="3"></td>
330 330 <td>
331 331 <div>
332 332 ${_('Unmatched/outdated inline comments below')}
333 333 </div>
334 334 </td>
335 335 </tr>
336 336 % endif
337 337 <tr class="cb-line">
338 338 <td class="cb-data cb-context"></td>
339 339 <td class="cb-lineno cb-context"></td>
340 340 <td class="cb-lineno cb-context"></td>
341 341 <td class="cb-content cb-context">
342 342 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
343 343 </td>
344 344 </tr>
345 345 %elif c.user_session_attrs["diffmode"] == 'sideside':
346 346 % if loop.index == 0:
347 347 <tr class="cb-comment-info">
348 348 <td colspan="2"></td>
349 349 <td class="cb-line">
350 350 <div>
351 351 ${_('Unmatched/outdated inline comments below')}
352 352 </div>
353 353 </td>
354 354 <td colspan="2"></td>
355 355 <td class="cb-line">
356 356 <div>
357 357 ${_('Unmatched/outdated comments below')}
358 358 </div>
359 359 </td>
360 360 </tr>
361 361 % endif
362 362 <tr class="cb-line">
363 363 <td class="cb-data cb-context"></td>
364 364 <td class="cb-lineno cb-context"></td>
365 365 <td class="cb-content cb-context">
366 366 % if lineno.startswith('o'):
367 367 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
368 368 % endif
369 369 </td>
370 370
371 371 <td class="cb-data cb-context"></td>
372 372 <td class="cb-lineno cb-context"></td>
373 373 <td class="cb-content cb-context">
374 374 % if lineno.startswith('n'):
375 375 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
376 376 % endif
377 377 </td>
378 378 </tr>
379 379 %endif
380 380
381 381 % endfor
382 382
383 383 </table>
384 384 </div>
385 385 %endfor
386 386
387 387 ## outdated comments that are made for a file that has been deleted
388 388 % for filename, comments_dict in (deleted_files_comments or {}).items():
389 389
390 390 <%
391 391 display_state = 'display: none'
392 392 open_comments_in_file = [x for x in comments_dict['comments'] if x.outdated is False]
393 393 if open_comments_in_file:
394 394 display_state = ''
395 395 fid = str(id(filename))
396 396 %>
397 397 <div class="filediffs filediff-outdated" style="${display_state}">
398 398 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filename)}" type="checkbox" onchange="updateSticky();">
399 399 <div class="filediff" data-f-path="${filename}" id="a_${h.FID(fid, filename)}">
400 400 <label for="filediff-collapse-${id(filename)}" class="filediff-heading">
401 401 <div class="filediff-collapse-indicator icon-"></div>
402 402
403 403 <span class="pill">
404 404 ## file was deleted
405 405 ${filename}
406 406 </span>
407 407 <span class="pill-group pull-left" >
408 408 ## file op, doesn't need translation
409 409 <span class="pill" op="removed">unresolved comments</span>
410 410 </span>
411 411 <a class="pill filediff-anchor" href="#a_${h.FID(fid, filename)}">ΒΆ</a>
412 412 <span class="pill-group pull-right">
413 413 <span class="pill" op="deleted">
414 414 % if comments_dict['stats'] >0:
415 415 -${comments_dict['stats']}
416 416 % else:
417 417 ${comments_dict['stats']}
418 418 % endif
419 419 </span>
420 420 </span>
421 421 </label>
422 422
423 423 <table class="cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
424 424 <tr>
425 425 % if c.user_session_attrs["diffmode"] == 'unified':
426 426 <td></td>
427 427 %endif
428 428
429 429 <td></td>
430 430 <td class="cb-text cb-${op_class(BIN_FILENODE)}" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=5')}>
431 431 <strong>${_('This file was removed from diff during updates to this pull-request.')}</strong><br/>
432 432 ${_('There are still outdated/unresolved comments attached to it.')}
433 433 </td>
434 434 </tr>
435 435 %if c.user_session_attrs["diffmode"] == 'unified':
436 436 <tr class="cb-line">
437 437 <td class="cb-data cb-context"></td>
438 438 <td class="cb-lineno cb-context"></td>
439 439 <td class="cb-lineno cb-context"></td>
440 440 <td class="cb-content cb-context">
441 441 ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)}
442 442 </td>
443 443 </tr>
444 444 %elif c.user_session_attrs["diffmode"] == 'sideside':
445 445 <tr class="cb-line">
446 446 <td class="cb-data cb-context"></td>
447 447 <td class="cb-lineno cb-context"></td>
448 448 <td class="cb-content cb-context"></td>
449 449
450 450 <td class="cb-data cb-context"></td>
451 451 <td class="cb-lineno cb-context"></td>
452 452 <td class="cb-content cb-context">
453 453 ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)}
454 454 </td>
455 455 </tr>
456 456 %endif
457 457 </table>
458 458 </div>
459 459 </div>
460 460 % endfor
461 461
462 462 </div>
463 463 </div>
464 464 </%def>
465 465
466 466 <%def name="diff_ops(filediff)">
467 467 <%
468 468 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
469 469 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE
470 470 %>
471 471 <span class="pill">
472 472 <i class="icon-file-text"></i>
473 473 %if filediff.source_file_path and filediff.target_file_path:
474 474 %if filediff.source_file_path != filediff.target_file_path:
475 475 ## file was renamed, or copied
476 476 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
477 477 ${filediff.target_file_path} β¬… <del>${filediff.source_file_path}</del>
478 478 <% final_path = filediff.target_file_path %>
479 479 %elif COPIED_FILENODE in filediff.patch['stats']['ops']:
480 480 ${filediff.target_file_path} β¬… ${filediff.source_file_path}
481 481 <% final_path = filediff.target_file_path %>
482 482 %endif
483 483 %else:
484 484 ## file was modified
485 485 ${filediff.source_file_path}
486 486 <% final_path = filediff.source_file_path %>
487 487 %endif
488 488 %else:
489 489 %if filediff.source_file_path:
490 490 ## file was deleted
491 491 ${filediff.source_file_path}
492 492 <% final_path = filediff.source_file_path %>
493 493 %else:
494 494 ## file was added
495 495 ${filediff.target_file_path}
496 496 <% final_path = filediff.target_file_path %>
497 497 %endif
498 498 %endif
499 499 <i style="color: #aaa" class="on-hover-icon icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="${_('Copy file path')}" onclick="return false;"></i>
500 500 </span>
501 501 ## anchor link
502 502 <a class="pill filediff-anchor" href="#a_${h.FID(filediff.raw_id, filediff.patch['filename'])}">ΒΆ</a>
503 503
504 504 <span class="pill-group pull-right">
505 505
506 506 ## ops pills
507 507 %if filediff.limited_diff:
508 508 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
509 509 %endif
510 510
511 511 %if NEW_FILENODE in filediff.patch['stats']['ops']:
512 512 <span class="pill" op="created">created</span>
513 513 %if filediff['target_mode'].startswith('120'):
514 514 <span class="pill" op="symlink">symlink</span>
515 515 %else:
516 516 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
517 517 %endif
518 518 %endif
519 519
520 520 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
521 521 <span class="pill" op="renamed">renamed</span>
522 522 %endif
523 523
524 524 %if COPIED_FILENODE in filediff.patch['stats']['ops']:
525 525 <span class="pill" op="copied">copied</span>
526 526 %endif
527 527
528 528 %if DEL_FILENODE in filediff.patch['stats']['ops']:
529 529 <span class="pill" op="removed">removed</span>
530 530 %endif
531 531
532 532 %if CHMOD_FILENODE in filediff.patch['stats']['ops']:
533 533 <span class="pill" op="mode">
534 534 ${nice_mode(filediff['source_mode'])} ➑ ${nice_mode(filediff['target_mode'])}
535 535 </span>
536 536 %endif
537 537
538 538 %if BIN_FILENODE in filediff.patch['stats']['ops']:
539 539 <span class="pill" op="binary">binary</span>
540 540 %if MOD_FILENODE in filediff.patch['stats']['ops']:
541 541 <span class="pill" op="modified">modified</span>
542 542 %endif
543 543 %endif
544 544
545 545 <span class="pill" op="added">${('+' if filediff.patch['stats']['added'] else '')}${filediff.patch['stats']['added']}</span>
546 546 <span class="pill" op="deleted">${((h.safe_int(filediff.patch['stats']['deleted']) or 0) * -1)}</span>
547 547
548 548 </span>
549 549
550 550 </%def>
551 551
552 552 <%def name="nice_mode(filemode)">
553 553 ${(filemode.startswith('100') and filemode[3:] or filemode)}
554 554 </%def>
555 555
556 556 <%def name="diff_menu(filediff, use_comments=False)">
557 557 <div class="filediff-menu">
558 558
559 559 %if filediff.diffset.source_ref:
560 560
561 561 ## FILE BEFORE CHANGES
562 562 %if filediff.operation in ['D', 'M']:
563 563 <a
564 564 class="tooltip"
565 565 href="${h.route_path('repo_files',repo_name=filediff.diffset.target_repo_name,commit_id=filediff.diffset.source_ref,f_path=filediff.source_file_path)}"
566 566 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
567 567 >
568 568 ${_('Show file before')}
569 569 </a> |
570 570 %else:
571 571 <span
572 572 class="tooltip"
573 573 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
574 574 >
575 575 ${_('Show file before')}
576 576 </span> |
577 577 %endif
578 578
579 579 ## FILE AFTER CHANGES
580 580 %if filediff.operation in ['A', 'M']:
581 581 <a
582 582 class="tooltip"
583 583 href="${h.route_path('repo_files',repo_name=filediff.diffset.source_repo_name,commit_id=filediff.diffset.target_ref,f_path=filediff.target_file_path)}"
584 584 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
585 585 >
586 586 ${_('Show file after')}
587 587 </a>
588 588 %else:
589 589 <span
590 590 class="tooltip"
591 591 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
592 592 >
593 593 ${_('Show file after')}
594 594 </span>
595 595 %endif
596 596
597 597 % if use_comments:
598 598 |
599 599 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
600 600 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
601 601 </a>
602 602 % endif
603 603
604 604 %endif
605 605
606 606 </div>
607 607 </%def>
608 608
609 609
610 610 <%def name="inline_comments_container(comments, active_pattern_entries=None)">
611 611
612 612 <div class="inline-comments">
613 613 %for comment in comments:
614 614 ${commentblock.comment_block(comment, inline=True, active_pattern_entries=active_pattern_entries)}
615 615 %endfor
616 616 % if comments and comments[-1].outdated:
617 617 <span class="btn btn-secondary cb-comment-add-button comment-outdated}" style="display: none;}">
618 618 ${_('Add another comment')}
619 619 </span>
620 620 % else:
621 621 <span onclick="return Rhodecode.comments.createComment(this)" class="btn btn-secondary cb-comment-add-button">
622 622 ${_('Add another comment')}
623 623 </span>
624 624 % endif
625 625
626 626 </div>
627 627 </%def>
628 628
629 629 <%!
630 630
631 631 def get_inline_comments(comments, filename):
632 632 if hasattr(filename, 'unicode_path'):
633 633 filename = filename.unicode_path
634 634
635 635 if not isinstance(filename, (unicode, str)):
636 636 return None
637 637
638 638 if comments and filename in comments:
639 639 return comments[filename]
640 640
641 641 return None
642 642
643 643 def get_comments_for(diff_type, comments, filename, line_version, line_number):
644 644 if hasattr(filename, 'unicode_path'):
645 645 filename = filename.unicode_path
646 646
647 647 if not isinstance(filename, (unicode, str)):
648 648 return None
649 649
650 650 file_comments = get_inline_comments(comments, filename)
651 651 if file_comments is None:
652 652 return None
653 653
654 654 line_key = '{}{}'.format(line_version, line_number) ## e.g o37, n12
655 655 if line_key in file_comments:
656 656 data = file_comments.pop(line_key)
657 657 return data
658 658 %>
659 659
660 660 <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)">
661 661
662 662 <% chunk_count = 1 %>
663 663 %for loop_obj, item in h.looper(hunk.sideside):
664 664 <%
665 665 line = item
666 666 i = loop_obj.index
667 667 prev_line = loop_obj.previous
668 668 old_line_anchor, new_line_anchor = None, None
669 669
670 670 if line.original.lineno:
671 671 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, line.original.lineno, 'o')
672 672 if line.modified.lineno:
673 673 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, line.modified.lineno, 'n')
674 674
675 675 line_action = line.modified.action or line.original.action
676 676 prev_line_action = prev_line and (prev_line.modified.action or prev_line.original.action)
677 677 %>
678 678
679 679 <tr class="cb-line">
680 680 <td class="cb-data ${action_class(line.original.action)}"
681 681 data-line-no="${line.original.lineno}"
682 682 >
683 683
684 684 <% line_old_comments = None %>
685 685 %if line.original.get_comment_args:
686 686 <% line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args) %>
687 687 %endif
688 688 %if line_old_comments:
689 689 <% has_outdated = any([x.outdated for x in line_old_comments]) %>
690 690 % if has_outdated:
691 691 <i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(line_old_comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
692 692 % else:
693 693 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_old_comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
694 694 % endif
695 695 %endif
696 696 </td>
697 697 <td class="cb-lineno ${action_class(line.original.action)}"
698 698 data-line-no="${line.original.lineno}"
699 699 %if old_line_anchor:
700 700 id="${old_line_anchor}"
701 701 %endif
702 702 >
703 703 %if line.original.lineno:
704 704 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
705 705 %endif
706 706 </td>
707 707 <td class="cb-content ${action_class(line.original.action)}"
708 708 data-line-no="o${line.original.lineno}"
709 709 >
710 710 %if use_comments and line.original.lineno:
711 711 ${render_add_comment_button()}
712 712 %endif
713 713 <span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span>
714 714
715 715 %if use_comments and line.original.lineno and line_old_comments:
716 716 ${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries)}
717 717 %endif
718 718
719 719 </td>
720 720 <td class="cb-data ${action_class(line.modified.action)}"
721 721 data-line-no="${line.modified.lineno}"
722 722 >
723 723 <div>
724 724
725 725 %if line.modified.get_comment_args:
726 726 <% line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args) %>
727 727 %else:
728 728 <% line_new_comments = None%>
729 729 %endif
730 730 %if line_new_comments:
731 731
732 732 <% has_outdated = any([x.outdated for x in line_new_comments]) %>
733 733 % if has_outdated:
734 734 <i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(line_new_comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
735 735 % else:
736 736 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_new_comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
737 737 % endif
738 738 %endif
739 739 </div>
740 740 </td>
741 741 <td class="cb-lineno ${action_class(line.modified.action)}"
742 742 data-line-no="${line.modified.lineno}"
743 743 %if new_line_anchor:
744 744 id="${new_line_anchor}"
745 745 %endif
746 746 >
747 747 %if line.modified.lineno:
748 748 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
749 749 %endif
750 750 </td>
751 751 <td class="cb-content ${action_class(line.modified.action)}"
752 752 data-line-no="n${line.modified.lineno}"
753 753 >
754 754 %if use_comments and line.modified.lineno:
755 755 ${render_add_comment_button()}
756 756 %endif
757 757 <span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span>
758 758 %if use_comments and line.modified.lineno and line_new_comments:
759 759 ${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries)}
760 760 %endif
761 761 % if line_action in ['+', '-'] and prev_line_action not in ['+', '-']:
762 762 <div class="nav-chunk" style="visibility: hidden">
763 763 <i class="icon-eye" title="viewing diff hunk-${hunk.index}-${chunk_count}"></i>
764 764 </div>
765 765 <% chunk_count +=1 %>
766 766 % endif
767 767 </td>
768 768 </tr>
769 769 %endfor
770 770 </%def>
771 771
772 772
773 773 <%def name="render_hunk_lines_unified(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)">
774 774 %for old_line_no, new_line_no, action, content, comments_args in hunk.unified:
775 775
776 776 <%
777 777 old_line_anchor, new_line_anchor = None, None
778 778 if old_line_no:
779 779 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, old_line_no, 'o')
780 780 if new_line_no:
781 781 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, new_line_no, 'n')
782 782 %>
783 783 <tr class="cb-line">
784 784 <td class="cb-data ${action_class(action)}">
785 785 <div>
786 786
787 787 %if comments_args:
788 788 <% comments = get_comments_for('unified', inline_comments, *comments_args) %>
789 789 %else:
790 790 <% comments = None %>
791 791 %endif
792 792
793 793 % if comments:
794 794 <% has_outdated = any([x.outdated for x in comments]) %>
795 795 % if has_outdated:
796 796 <i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
797 797 % else:
798 798 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
799 799 % endif
800 800 % endif
801 801 </div>
802 802 </td>
803 803 <td class="cb-lineno ${action_class(action)}"
804 804 data-line-no="${old_line_no}"
805 805 %if old_line_anchor:
806 806 id="${old_line_anchor}"
807 807 %endif
808 808 >
809 809 %if old_line_anchor:
810 810 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
811 811 %endif
812 812 </td>
813 813 <td class="cb-lineno ${action_class(action)}"
814 814 data-line-no="${new_line_no}"
815 815 %if new_line_anchor:
816 816 id="${new_line_anchor}"
817 817 %endif
818 818 >
819 819 %if new_line_anchor:
820 820 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
821 821 %endif
822 822 </td>
823 823 <td class="cb-content ${action_class(action)}"
824 824 data-line-no="${(new_line_no and 'n' or 'o')}${(new_line_no or old_line_no)}"
825 825 >
826 826 %if use_comments:
827 827 ${render_add_comment_button()}
828 828 %endif
829 829 <span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span>
830 830 %if use_comments and comments:
831 831 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
832 832 %endif
833 833 </td>
834 834 </tr>
835 835 %endfor
836 836 </%def>
837 837
838 838
839 839 <%def name="render_hunk_lines(filediff, diff_mode, hunk, use_comments, inline_comments, active_pattern_entries)">
840 840 % if diff_mode == 'unified':
841 841 ${render_hunk_lines_unified(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)}
842 842 % elif diff_mode == 'sideside':
843 843 ${render_hunk_lines_sideside(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)}
844 844 % else:
845 845 <tr class="cb-line">
846 846 <td>unknown diff mode</td>
847 847 </tr>
848 848 % endif
849 849 </%def>file changes
850 850
851 851
852 852 <%def name="render_add_comment_button()">
853 853 <button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this)">
854 854 <span><i class="icon-comment"></i></span>
855 855 </button>
856 856 </%def>
857 857
858 <%def name="render_diffset_menu(diffset, range_diff_on=None)">
858 <%def name="render_diffset_menu(diffset, range_diff_on=None, commit=None, pull_request_menu=None)">
859 859 <% diffset_container_id = h.md5(diffset.target_ref) %>
860 860
861 861 <div id="diff-file-sticky" class="diffset-menu clearinner">
862 862 ## auto adjustable
863 863 <div class="sidebar__inner">
864 864 <div class="sidebar__bar">
865 865 <div class="pull-right">
866 866 <div class="btn-group">
867 867 <a class="btn tooltip toggle-wide-diff" href="#toggle-wide-diff" onclick="toggleWideDiff(this); return false" title="${h.tooltip(_('Toggle wide diff'))}">
868 868 <i class="icon-wide-mode"></i>
869 869 </a>
870 870 </div>
871 871 <div class="btn-group">
872 872
873 873 <a
874 874 class="btn ${(c.user_session_attrs["diffmode"] == 'sideside' and 'btn-active')} tooltip"
875 875 title="${h.tooltip(_('View diff as side by side'))}"
876 876 href="${h.current_route_path(request, diffmode='sideside')}">
877 877 <span>${_('Side by Side')}</span>
878 878 </a>
879 879
880 880 <a
881 881 class="btn ${(c.user_session_attrs["diffmode"] == 'unified' and 'btn-active')} tooltip"
882 882 title="${h.tooltip(_('View diff as unified'))}" href="${h.current_route_path(request, diffmode='unified')}">
883 883 <span>${_('Unified')}</span>
884 884 </a>
885 885
886 886 % if range_diff_on is True:
887 887 <a
888 888 title="${_('Turn off: Show the diff as commit range')}"
889 889 class="btn btn-primary"
890 890 href="${h.current_route_path(request, **{"range-diff":"0"})}">
891 891 <span>${_('Range Diff')}</span>
892 892 </a>
893 893 % elif range_diff_on is False:
894 894 <a
895 895 title="${_('Show the diff as commit range')}"
896 896 class="btn"
897 897 href="${h.current_route_path(request, **{"range-diff":"1"})}">
898 898 <span>${_('Range Diff')}</span>
899 899 </a>
900 900 % endif
901 901 </div>
902 902 <div class="btn-group">
903 903
904 904 <div class="pull-left">
905 905 ${h.hidden('diff_menu_{}'.format(diffset_container_id))}
906 906 </div>
907 907
908 908 </div>
909 909 </div>
910 910 <div class="pull-left">
911 911 <div class="btn-group">
912 912 <div class="pull-left">
913 913 ${h.hidden('file_filter_{}'.format(diffset_container_id))}
914 914 </div>
915 915
916 916 </div>
917 917 </div>
918 918 </div>
919 919 <div class="fpath-placeholder pull-left">
920 920 <i class="icon-file-text"></i>
921 921 <strong class="fpath-placeholder-text">
922 922 Context file:
923 923 </strong>
924 924 </div>
925 925 <div class="pull-right noselect">
926 <span id="diff_nav">Loading diff...:</span>
927 <span class="cursor-pointer" onclick="scrollToPrevChunk(); return false">
928 <i class="icon-angle-up"></i>
929 </span>
930 <span class="cursor-pointer" onclick="scrollToNextChunk(); return false">
931 <i class="icon-angle-down"></i>
932 </span>
926
927 %if commit:
928 <span>
929 <code>${h.show_id(commit)}</code>
930 </span>
931 %elif pull_request_menu and pull_request_menu.get('pull_request'):
932 <span>
933 <code>!${pull_request_menu['pull_request'].pull_request_id}</code>
934 </span>
935 %endif
936 % if commit or pull_request_menu:
937 <span id="diff_nav">Loading diff...:</span>
938 <span class="cursor-pointer" onclick="scrollToPrevChunk(); return false">
939 <i class="icon-angle-up"></i>
940 </span>
941 <span class="cursor-pointer" onclick="scrollToNextChunk(); return false">
942 <i class="icon-angle-down"></i>
943 </span>
944 % endif
933 945 </div>
934 946 <div class="sidebar_inner_shadow"></div>
935 947 </div>
936 948 </div>
937 949
938 950 % if diffset:
939 951 %if diffset.limited_diff:
940 952 <% file_placeholder = _ungettext('%(num)s file changed', '%(num)s files changed', diffset.changed_files) % {'num': diffset.changed_files} %>
941 953 %else:
942 954 <% file_placeholder = h.literal(_ungettext('%(num)s file changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>', '%(num)s files changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>',
943 955 diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}) %>
944 956
945 957 %endif
946 958 ## case on range-diff placeholder needs to be updated
947 959 % if range_diff_on is True:
948 960 <% file_placeholder = _('Disabled on range diff') %>
949 961 % endif
950 962
951 963 <script type="text/javascript">
952 964 var feedFilesOptions = function (query, initialData) {
953 965 var data = {results: []};
954 966 var isQuery = typeof query.term !== 'undefined';
955 967
956 968 var section = _gettext('Changed files');
957 969 var filteredData = [];
958 970
959 971 //filter results
960 972 $.each(initialData.results, function (idx, value) {
961 973
962 974 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
963 975 filteredData.push({
964 976 'id': this.id,
965 977 'text': this.text,
966 978 "ops": this.ops,
967 979 })
968 980 }
969 981
970 982 });
971 983
972 984 data.results = filteredData;
973 985
974 986 query.callback(data);
975 987 };
976 988
977 989 var selectionFormatter = function(data, escapeMarkup) {
978 990 var container = '<div class="filelist" style="padding-right:100px">{0}</div>';
979 991 var tmpl = '<div><strong>{0}</strong></div>'.format(escapeMarkup(data['text']));
980 992 var pill = '<div class="pill-group" style="position: absolute; top:7px; right: 0">' +
981 993 '<span class="pill" op="added">{0}</span>' +
982 994 '<span class="pill" op="deleted">{1}</span>' +
983 995 '</div>'
984 996 ;
985 997 var added = data['ops']['added'];
986 998 if (added === 0) {
987 999 // don't show +0
988 1000 added = 0;
989 1001 } else {
990 1002 added = '+' + added;
991 1003 }
992 1004
993 1005 var deleted = -1*data['ops']['deleted'];
994 1006
995 1007 tmpl += pill.format(added, deleted);
996 1008 return container.format(tmpl);
997 1009 };
998 1010 var formatFileResult = function(result, container, query, escapeMarkup) {
999 1011 return selectionFormatter(result, escapeMarkup);
1000 1012 };
1001 1013
1002 1014 var formatSelection = function (data, container) {
1003 1015 return '${file_placeholder}'
1004 1016 };
1005 1017
1006 1018 if (window.preloadFileFilterData === undefined) {
1007 1019 window.preloadFileFilterData = {}
1008 1020 }
1009 1021
1010 1022 preloadFileFilterData["${diffset_container_id}"] = {
1011 1023 results: [
1012 1024 % for filediff in diffset.files:
1013 1025 {id:"a_${h.FID(filediff.raw_id, filediff.patch['filename'])}",
1014 1026 text:"${filediff.patch['filename']}",
1015 1027 ops:${h.json.dumps(filediff.patch['stats'])|n}}${('' if loop.last else ',')}
1016 1028 % endfor
1017 1029 ]
1018 1030 };
1019 1031
1020 1032 var diffFileFilterId = "#file_filter_" + "${diffset_container_id}";
1021 1033 var diffFileFilter = $(diffFileFilterId).select2({
1022 1034 'dropdownAutoWidth': true,
1023 1035 'width': 'auto',
1024 1036
1025 1037 containerCssClass: "drop-menu",
1026 1038 dropdownCssClass: "drop-menu-dropdown",
1027 1039 data: preloadFileFilterData["${diffset_container_id}"],
1028 1040 query: function(query) {
1029 1041 feedFilesOptions(query, preloadFileFilterData["${diffset_container_id}"]);
1030 1042 },
1031 1043 initSelection: function(element, callback) {
1032 1044 callback({'init': true});
1033 1045 },
1034 1046 formatResult: formatFileResult,
1035 1047 formatSelection: formatSelection
1036 1048 });
1037 1049
1038 1050 % if range_diff_on is True:
1039 1051 diffFileFilter.select2("enable", false);
1040 1052 % endif
1041 1053
1042 1054 $(diffFileFilterId).on('select2-selecting', function (e) {
1043 1055 var idSelector = e.choice.id;
1044 1056
1045 1057 // expand the container if we quick-select the field
1046 1058 $('#'+idSelector).next().prop('checked', false);
1047 1059 // hide the mast as we later do preventDefault()
1048 1060 $("#select2-drop-mask").click();
1049 1061
1050 1062 window.location.hash = '#'+idSelector;
1051 1063 updateSticky();
1052 1064
1053 1065 e.preventDefault();
1054 1066 });
1055 1067
1068 diffNavText = 'diff navigation:'
1069
1056 1070 getCurrentChunk = function () {
1057 1071
1058 1072 var chunksAll = $('.nav-chunk').filter(function () {
1059 1073 return $(this).parents('.filediff').prev().get(0).checked !== true
1060 1074 })
1061 1075 var chunkSelected = $('.nav-chunk.selected');
1062 1076 var initial = false;
1063 1077
1064 1078 if (chunkSelected.length === 0) {
1065 1079 // no initial chunk selected, we pick first
1066 1080 chunkSelected = $(chunksAll.get(0));
1067 1081 var initial = true;
1068 1082 }
1069 1083
1070 1084 return {
1071 1085 'all': chunksAll,
1072 1086 'selected': chunkSelected,
1073 1087 'initial': initial,
1074 1088 }
1075 1089 }
1076 1090
1077 1091 animateDiffNavText = function () {
1078 1092 var $diffNav = $('#diff_nav')
1079 1093
1080 1094 var callback = function () {
1081 1095 $diffNav.animate({'opacity': 1.00}, 200)
1082 1096 };
1083 1097 $diffNav.animate({'opacity': 0.15}, 200, callback);
1084 1098 }
1085 1099
1086 1100 scrollToChunk = function (moveBy) {
1087 1101 var chunk = getCurrentChunk();
1088 1102 var all = chunk.all
1089 1103 var selected = chunk.selected
1090 1104
1091 1105 var curPos = all.index(selected);
1092 1106 var newPos = curPos;
1093 1107 if (!chunk.initial) {
1094 1108 var newPos = curPos + moveBy;
1095 1109 }
1096 1110
1097 1111 var curElem = all.get(newPos);
1098 1112
1099 1113 if (curElem === undefined) {
1100 1114 // end or back
1101 $('#diff_nav').html('No next diff element.')
1115 $('#diff_nav').html('no next diff element:')
1102 1116 animateDiffNavText()
1103 1117 return
1104 1118 } else if (newPos < 0) {
1105 $('#diff_nav').html('No previous diff element.')
1119 $('#diff_nav').html('no previous diff element:')
1106 1120 animateDiffNavText()
1107 1121 return
1108 1122 } else {
1109 $('#diff_nav').html('Diff navigation:')
1123 $('#diff_nav').html(diffNavText)
1110 1124 }
1111 1125
1112 1126 curElem = $(curElem)
1113 1127 var offset = 100;
1114 1128 $(window).scrollTop(curElem.position().top - offset);
1115 1129
1116 1130 //clear selection
1117 1131 all.removeClass('selected')
1118 1132 curElem.addClass('selected')
1119 1133 }
1120 1134
1121 1135 scrollToPrevChunk = function () {
1122 1136 scrollToChunk(-1)
1123 1137 }
1124 1138 scrollToNextChunk = function () {
1125 1139 scrollToChunk(1)
1126 1140 }
1127 1141
1128 1142 </script>
1129 1143 % endif
1130 1144
1131 1145 <script type="text/javascript">
1132 1146 $('#diff_nav').html('loading diff...') // wait until whole page is loaded
1133 1147
1134 1148 $(document).ready(function () {
1135 1149
1136 1150 var contextPrefix = _gettext('Context file: ');
1137 1151 ## sticky sidebar
1138 1152 var sidebarElement = document.getElementById('diff-file-sticky');
1139 1153 sidebar = new StickySidebar(sidebarElement, {
1140 1154 topSpacing: 0,
1141 1155 bottomSpacing: 0,
1142 1156 innerWrapperSelector: '.sidebar__inner'
1143 1157 });
1144 1158 sidebarElement.addEventListener('affixed.static.stickySidebar', function () {
1145 1159 // reset our file so it's not holding new value
1146 1160 $('.fpath-placeholder-text').html(contextPrefix + ' - ')
1147 1161 });
1148 1162
1149 1163 updateSticky = function () {
1150 1164 sidebar.updateSticky();
1151 1165 Waypoint.refreshAll();
1152 1166 };
1153 1167
1154 1168 var animateText = function (fPath, anchorId) {
1155 1169 fPath = Select2.util.escapeMarkup(fPath);
1156 1170 $('.fpath-placeholder-text').html(contextPrefix + '<a href="#a_' + anchorId + '">' + fPath + '</a>')
1157 1171 };
1158 1172
1159 1173 ## dynamic file waypoints
1160 1174 var setFPathInfo = function(fPath, anchorId){
1161 1175 animateText(fPath, anchorId)
1162 1176 };
1163 1177
1164 1178 var codeBlock = $('.filediff');
1165 1179
1166 1180 // forward waypoint
1167 1181 codeBlock.waypoint(
1168 1182 function(direction) {
1169 1183 if (direction === "down"){
1170 1184 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1171 1185 }
1172 1186 }, {
1173 1187 offset: function () {
1174 1188 return 70;
1175 1189 },
1176 1190 context: '.fpath-placeholder'
1177 1191 }
1178 1192 );
1179 1193
1180 1194 // backward waypoint
1181 1195 codeBlock.waypoint(
1182 1196 function(direction) {
1183 1197 if (direction === "up"){
1184 1198 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1185 1199 }
1186 1200 }, {
1187 1201 offset: function () {
1188 1202 return -this.element.clientHeight + 90;
1189 1203 },
1190 1204 context: '.fpath-placeholder'
1191 1205 }
1192 1206 );
1193 1207
1194 1208 toggleWideDiff = function (el) {
1195 1209 updateSticky();
1196 1210 var wide = Rhodecode.comments.toggleWideMode(this);
1197 1211 storeUserSessionAttr('rc_user_session_attr.wide_diff_mode', wide);
1198 1212 if (wide === true) {
1199 1213 $(el).addClass('btn-active');
1200 1214 } else {
1201 1215 $(el).removeClass('btn-active');
1202 1216 }
1203 1217 return null;
1204 1218 };
1205 1219
1206 1220 var preloadDiffMenuData = {
1207 1221 results: [
1208 1222
1209 1223 ## Whitespace change
1210 1224 % if request.GET.get('ignorews', '') == '1':
1211 1225 {
1212 1226 id: 2,
1213 1227 text: _gettext('Show whitespace changes'),
1214 1228 action: function () {},
1215 1229 url: "${h.current_route_path(request, ignorews=0)|n}"
1216 1230 },
1217 1231 % else:
1218 1232 {
1219 1233 id: 2,
1220 1234 text: _gettext('Hide whitespace changes'),
1221 1235 action: function () {},
1222 1236 url: "${h.current_route_path(request, ignorews=1)|n}"
1223 1237 },
1224 1238 % endif
1225 1239
1226 1240 ## FULL CONTEXT
1227 1241 % if request.GET.get('fullcontext', '') == '1':
1228 1242 {
1229 1243 id: 3,
1230 1244 text: _gettext('Hide full context diff'),
1231 1245 action: function () {},
1232 1246 url: "${h.current_route_path(request, fullcontext=0)|n}"
1233 1247 },
1234 1248 % else:
1235 1249 {
1236 1250 id: 3,
1237 1251 text: _gettext('Show full context diff'),
1238 1252 action: function () {},
1239 1253 url: "${h.current_route_path(request, fullcontext=1)|n}"
1240 1254 },
1241 1255 % endif
1242 1256
1243 1257 ]
1244 1258 };
1245 1259
1246 1260 var diffMenuId = "#diff_menu_" + "${diffset_container_id}";
1247 1261 $(diffMenuId).select2({
1248 1262 minimumResultsForSearch: -1,
1249 1263 containerCssClass: "drop-menu-no-width",
1250 1264 dropdownCssClass: "drop-menu-dropdown",
1251 1265 dropdownAutoWidth: true,
1252 1266 data: preloadDiffMenuData,
1253 1267 placeholder: "${_('...')}",
1254 1268 });
1255 1269 $(diffMenuId).on('select2-selecting', function (e) {
1256 1270 e.choice.action();
1257 1271 if (e.choice.url !== null) {
1258 1272 window.location = e.choice.url
1259 1273 }
1260 1274 });
1261 1275 toggleExpand = function (el, diffsetEl) {
1262 1276 var el = $(el);
1263 1277 if (el.hasClass('collapsed')) {
1264 1278 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', false);
1265 1279 el.removeClass('collapsed');
1266 1280 el.html(
1267 1281 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1268 1282 _gettext('Collapse all files'));
1269 1283 }
1270 1284 else {
1271 1285 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', true);
1272 1286 el.addClass('collapsed');
1273 1287 el.html(
1274 1288 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1275 1289 _gettext('Expand all files'));
1276 1290 }
1277 1291 updateSticky()
1278 1292 };
1279 1293
1280 1294 toggleCommitExpand = function (el) {
1281 1295 var $el = $(el);
1282 1296 var commits = $el.data('toggleCommitsCnt');
1283 1297 var collapseMsg = _ngettext('Collapse {0} commit', 'Collapse {0} commits', commits).format(commits);
1284 1298 var expandMsg = _ngettext('Expand {0} commit', 'Expand {0} commits', commits).format(commits);
1285 1299
1286 1300 if ($el.hasClass('collapsed')) {
1287 1301 $('.compare_select').show();
1288 1302 $('.compare_select_hidden').hide();
1289 1303
1290 1304 $el.removeClass('collapsed');
1291 1305 $el.html(
1292 1306 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1293 1307 collapseMsg);
1294 1308 }
1295 1309 else {
1296 1310 $('.compare_select').hide();
1297 1311 $('.compare_select_hidden').show();
1298 1312 $el.addClass('collapsed');
1299 1313 $el.html(
1300 1314 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1301 1315 expandMsg);
1302 1316 }
1303 1317 updateSticky();
1304 1318 };
1305 1319
1306 1320 // get stored diff mode and pre-enable it
1307 1321 if (templateContext.session_attrs.wide_diff_mode === "true") {
1308 1322 Rhodecode.comments.toggleWideMode(null);
1309 1323 $('.toggle-wide-diff').addClass('btn-active');
1310 1324 updateSticky();
1311 1325 }
1312 1326
1313 1327 // DIFF NAV //
1314 1328
1315 1329 // element to detect scroll direction of
1316 1330 var $window = $(window);
1317 1331
1318 1332 // initialize last scroll position
1319 1333 var lastScrollY = $window.scrollTop();
1320 1334
1321 1335 $window.on('resize scrollstop', {latency: 350}, function () {
1322 1336 var visibleChunks = $('.nav-chunk').withinviewport({top: 75});
1323 1337
1324 1338 // get current scroll position
1325 1339 var currentScrollY = $window.scrollTop();
1326 1340
1327 1341 // determine current scroll direction
1328 1342 if (currentScrollY > lastScrollY) {
1329 1343 var y = 'down'
1330 1344 } else if (currentScrollY !== lastScrollY) {
1331 1345 var y = 'up';
1332 1346 }
1333 1347
1334 1348 var pos = -1; // by default we use last element in viewport
1335 1349 if (y === 'down') {
1336 1350 pos = -1;
1337 1351 } else if (y === 'up') {
1338 1352 pos = 0;
1339 1353 }
1340 1354
1341 1355 if (visibleChunks.length > 0) {
1342 1356 $('.nav-chunk').removeClass('selected');
1343 1357 $(visibleChunks.get(pos)).addClass('selected');
1344 1358 }
1345 1359
1346 1360 // update last scroll position to current position
1347 1361 lastScrollY = currentScrollY;
1348 1362
1349 1363 });
1350 $('#diff_nav').html('Diff navigation:')
1364 $('#diff_nav').html(diffNavText);
1351 1365
1352 1366 });
1353 1367 </script>
1354 1368
1355 1369 </%def>
@@ -1,920 +1,921 b''
1 1 <%inherit file="/base/base.mako"/>
2 2 <%namespace name="base" file="/base/base.mako"/>
3 3 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
4 4
5 5 <%def name="title()">
6 6 ${_('{} Pull Request !{}').format(c.repo_name, c.pull_request.pull_request_id)}
7 7 %if c.rhodecode_name:
8 8 &middot; ${h.branding(c.rhodecode_name)}
9 9 %endif
10 10 </%def>
11 11
12 12 <%def name="breadcrumbs_links()">
13 13
14 14 </%def>
15 15
16 16 <%def name="menu_bar_nav()">
17 17 ${self.menu_items(active='repositories')}
18 18 </%def>
19 19
20 20 <%def name="menu_bar_subnav()">
21 21 ${self.repo_menu(active='showpullrequest')}
22 22 </%def>
23 23
24 24 <%def name="main()">
25 25
26 26 <script type="text/javascript">
27 27 // TODO: marcink switch this to pyroutes
28 28 AJAX_COMMENT_DELETE_URL = "${h.route_path('pullrequest_comment_delete',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id,comment_id='__COMMENT_ID__')}";
29 29 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
30 30 </script>
31 31
32 32 <div class="box">
33 33
34 34 <div class="box pr-summary">
35 35
36 36 <div class="summary-details block-left">
37 37 <div id="pr-title">
38 38 % if c.pull_request.is_closed():
39 39 <span class="pr-title-closed-tag tag">${_('Closed')}</span>
40 40 % endif
41 41 <input class="pr-title-input large disabled" disabled="disabled" name="pullrequest_title" type="text" value="${c.pull_request.title}">
42 42 </div>
43 43 <div id="pr-title-edit" class="input" style="display: none;">
44 44 <input class="pr-title-input large" id="pr-title-input" name="pullrequest_title" type="text" value="${c.pull_request.title}">
45 45 </div>
46 46
47 47 <% summary = lambda n:{False:'summary-short'}.get(n) %>
48 48 <div class="pr-details-title">
49 49 <div class="pull-left">
50 50 <a href="${h.route_path('pull_requests_global', pull_request_id=c.pull_request.pull_request_id)}">${_('Pull request !{}').format(c.pull_request.pull_request_id)}</a>
51 51 ${_('Created on')}
52 52 <span class="tooltip" title="${_('Last updated on')} ${h.format_date(c.pull_request.updated_on)}">${h.format_date(c.pull_request.created_on)},</span>
53 53 <span class="pr-details-title-author-pref">${_('by')}</span>
54 54 </div>
55 55
56 56 <div class="pull-left">
57 57 ${self.gravatar_with_user(c.pull_request.author.email, 16, tooltip=True)}
58 58 </div>
59 59
60 60 %if c.allowed_to_update:
61 61 <div class="pull-right">
62 62 <div id="edit_pull_request" class="action_button pr-save" style="display: none;">${_('Update title & description')}</div>
63 63 <div id="delete_pullrequest" class="action_button pr-save ${('' if c.allowed_to_delete else 'disabled' )}" style="display: none;">
64 64 % if c.allowed_to_delete:
65 65 ${h.secure_form(h.route_path('pullrequest_delete', repo_name=c.pull_request.target_repo.repo_name, pull_request_id=c.pull_request.pull_request_id), request=request)}
66 66 <input class="btn btn-link btn-danger no-margin" id="remove_${c.pull_request.pull_request_id}" name="remove_${c.pull_request.pull_request_id}"
67 67 onclick="submitConfirm(event, this, _gettext('Confirm to delete this pull request'), _gettext('Delete'), '${'!{}'.format(c.pull_request.pull_request_id)}')"
68 68 type="submit" value="${_('Delete pull request')}">
69 69 ${h.end_form()}
70 70 % else:
71 71 <span class="tooltip" title="${_('Not allowed to delete this pull request')}">${_('Delete pull request')}</span>
72 72 % endif
73 73 </div>
74 74 <div id="open_edit_pullrequest" class="action_button">${_('Edit')}</div>
75 75 <div id="close_edit_pullrequest" class="action_button" style="display: none;">${_('Cancel')}</div>
76 76 </div>
77 77
78 78 %endif
79 79 </div>
80 80
81 81 <div id="pr-desc" class="input" title="${_('Rendered using {} renderer').format(c.renderer)}">
82 82 ${h.render(c.pull_request.description, renderer=c.renderer, repo_name=c.repo_name)}
83 83 </div>
84 84
85 85 <div id="pr-desc-edit" class="input textarea" style="display: none;">
86 86 <input id="pr-renderer-input" type="hidden" name="description_renderer" value="${c.visual.default_renderer}">
87 87 ${dt.markup_form('pr-description-input', form_text=c.pull_request.description)}
88 88 </div>
89 89
90 90 <div id="summary" class="fields pr-details-content">
91 91
92 92 ## review
93 93 <div class="field">
94 94 <div class="label-pr-detail">
95 95 <label>${_('Review status')}:</label>
96 96 </div>
97 97 <div class="input">
98 98 %if c.pull_request_review_status:
99 99 <div class="tag status-tag-${c.pull_request_review_status}">
100 100 <i class="icon-circle review-status-${c.pull_request_review_status}"></i>
101 101 <span class="changeset-status-lbl">
102 102 %if c.pull_request.is_closed():
103 103 ${_('Closed')},
104 104 %endif
105 105
106 106 ${h.commit_status_lbl(c.pull_request_review_status)}
107 107
108 108 </span>
109 109 </div>
110 110 - ${_ungettext('calculated based on {} reviewer vote', 'calculated based on {} reviewers votes', len(c.pull_request_reviewers)).format(len(c.pull_request_reviewers))}
111 111 %endif
112 112 </div>
113 113 </div>
114 114
115 115 ## source
116 116 <div class="field">
117 117 <div class="label-pr-detail">
118 118 <label>${_('Commit flow')}:</label>
119 119 </div>
120 120 <div class="input">
121 121 <div class="pr-commit-flow">
122 122 ## Source
123 123 %if c.pull_request.source_ref_parts.type == 'branch':
124 124 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.source_repo.repo_name, _query=dict(branch=c.pull_request.source_ref_parts.name))}"><code class="pr-source-info">${c.pull_request.source_ref_parts.type}:${c.pull_request.source_ref_parts.name}</code></a>
125 125 %else:
126 126 <code class="pr-source-info">${'{}:{}'.format(c.pull_request.source_ref_parts.type, c.pull_request.source_ref_parts.name)}</code>
127 127 %endif
128 128 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.repo_name}</a>
129 129 &rarr;
130 130 ## Target
131 131 %if c.pull_request.target_ref_parts.type == 'branch':
132 132 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.target_repo.repo_name, _query=dict(branch=c.pull_request.target_ref_parts.name))}"><code class="pr-target-info">${c.pull_request.target_ref_parts.type}:${c.pull_request.target_ref_parts.name}</code></a>
133 133 %else:
134 134 <code class="pr-target-info">${'{}:{}'.format(c.pull_request.target_ref_parts.type, c.pull_request.target_ref_parts.name)}</code>
135 135 %endif
136 136
137 137 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.repo_name}</a>
138 138
139 139 <a class="source-details-action" href="#expand-source-details" onclick="return versionController.toggleElement(this, '.source-details')" data-toggle-on='<i class="icon-angle-down">more details</i>' data-toggle-off='<i class="icon-angle-up">less details</i>'>
140 140 <i class="icon-angle-down">more details</i>
141 141 </a>
142 142
143 143 </div>
144 144
145 145 <div class="source-details" style="display: none">
146 146
147 147 <ul>
148 148
149 149 ## common ancestor
150 150 <li>
151 151 ${_('Common ancestor')}:
152 152 % if c.ancestor_commit:
153 153 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a>
154 154 % else:
155 155 ${_('not available')}
156 156 % endif
157 157 </li>
158 158
159 159 ## pull url
160 160 <li>
161 161 %if h.is_hg(c.pull_request.source_repo):
162 162 <% clone_url = 'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %>
163 163 %elif h.is_git(c.pull_request.source_repo):
164 164 <% clone_url = 'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %>
165 165 %endif
166 166
167 167 <span>${_('Pull changes from source')}</span>: <input type="text" class="input-monospace pr-pullinfo" value="${clone_url}" readonly="readonly">
168 168 <i class="tooltip icon-clipboard clipboard-action pull-right pr-pullinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the pull url')}"></i>
169 169 </li>
170 170
171 171 ## Shadow repo
172 172 <li>
173 173 % if not c.pull_request.is_closed() and c.pull_request.shadow_merge_ref:
174 174 %if h.is_hg(c.pull_request.target_repo):
175 175 <% clone_url = 'hg clone --update {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
176 176 %elif h.is_git(c.pull_request.target_repo):
177 177 <% clone_url = 'git clone --branch {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
178 178 %endif
179 179
180 180 <span class="tooltip" title="${_('Clone repository in its merged state using shadow repository')}">${_('Clone from shadow repository')}</span>: <input type="text" class="input-monospace pr-mergeinfo" value="${clone_url}" readonly="readonly">
181 181 <i class="tooltip icon-clipboard clipboard-action pull-right pr-mergeinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the clone url')}"></i>
182 182
183 183 % else:
184 184 <div class="">
185 185 ${_('Shadow repository data not available')}.
186 186 </div>
187 187 % endif
188 188 </li>
189 189
190 190 </ul>
191 191
192 192 </div>
193 193
194 194 </div>
195 195
196 196 </div>
197 197
198 198 ## versions
199 199 <div class="field">
200 200 <div class="label-pr-detail">
201 201 <label>${_('Versions')}:</label>
202 202 </div>
203 203
204 204 <% outdated_comm_count_ver = len(c.inline_versions[None]['outdated']) %>
205 205 <% general_outdated_comm_count_ver = len(c.comment_versions[None]['outdated']) %>
206 206
207 207 <div class="pr-versions">
208 208 % if c.show_version_changes:
209 209 <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %>
210 210 <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %>
211 211 ${_ungettext('{} version available for this pull request, ', '{} versions available for this pull request, ', len(c.versions)).format(len(c.versions))}
212 212 <a id="show-pr-versions" onclick="return versionController.toggleVersionView(this)" href="#show-pr-versions"
213 213 data-toggle-on="${_('show versions')}."
214 214 data-toggle-off="${_('hide versions')}.">
215 215 ${_('show versions')}.
216 216 </a>
217 217 <table>
218 218 ## SHOW ALL VERSIONS OF PR
219 219 <% ver_pr = None %>
220 220
221 221 % for data in reversed(list(enumerate(c.versions, 1))):
222 222 <% ver_pos = data[0] %>
223 223 <% ver = data[1] %>
224 224 <% ver_pr = ver.pull_request_version_id %>
225 225 <% display_row = '' if c.at_version and (c.at_version_num == ver_pr or c.from_version_num == ver_pr) else 'none' %>
226 226
227 227 <tr class="version-pr" style="display: ${display_row}">
228 228 <td>
229 229 <code>
230 230 <a href="${request.current_route_path(_query=dict(version=ver_pr or 'latest'))}">v${ver_pos}</a>
231 231 </code>
232 232 </td>
233 233 <td>
234 234 <input ${('checked="checked"' if c.from_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
235 235 <input ${('checked="checked"' if c.at_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
236 236 </td>
237 237 <td>
238 238 <% review_status = c.review_versions[ver_pr].status if ver_pr in c.review_versions else 'not_reviewed' %>
239 239 <i class="tooltip icon-circle review-status-${review_status}" title="${_('Your review status at this version')}"></i>
240 240
241 241 </td>
242 242 <td>
243 243 % if c.at_version_num != ver_pr:
244 244 <i class="tooltip icon-comment" title="${_('Comments from pull request version v{0}').format(ver_pos)}"></i>
245 245 <code>
246 246 General:${len(c.comment_versions[ver_pr]['at'])} / Inline:${len(c.inline_versions[ver_pr]['at'])}
247 247 </code>
248 248 % endif
249 249 </td>
250 250 <td>
251 251 ##<code>${ver.source_ref_parts.commit_id[:6]}</code>
252 252 </td>
253 253 <td>
254 254 <code>${h.age_component(ver.updated_on, time_is_local=True, tooltip=False)}</code>
255 255 </td>
256 256 </tr>
257 257 % endfor
258 258
259 259 <tr>
260 260 <td colspan="6">
261 261 <button id="show-version-diff" onclick="return versionController.showVersionDiff()" class="btn btn-sm" style="display: none"
262 262 data-label-text-locked="${_('select versions to show changes')}"
263 263 data-label-text-diff="${_('show changes between versions')}"
264 264 data-label-text-show="${_('show pull request for this version')}"
265 265 >
266 266 ${_('select versions to show changes')}
267 267 </button>
268 268 </td>
269 269 </tr>
270 270 </table>
271 271 % else:
272 272 <div>
273 273 ${_('Pull request versions not available')}.
274 274 </div>
275 275 % endif
276 276 </div>
277 277 </div>
278 278
279 279 </div>
280 280
281 281 </div>
282 282
283 283 ## REVIEW RULES
284 284 <div id="review_rules" style="display: none" class="reviewers-title block-right">
285 285 <div class="pr-details-title">
286 286 ${_('Reviewer rules')}
287 287 %if c.allowed_to_update:
288 288 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
289 289 %endif
290 290 </div>
291 291 <div class="pr-reviewer-rules">
292 292 ## review rules will be appended here, by default reviewers logic
293 293 </div>
294 294 <input id="review_data" type="hidden" name="review_data" value="">
295 295 </div>
296 296
297 297 ## REVIEWERS
298 298 <div class="reviewers-title first-panel block-right">
299 299 <div class="pr-details-title">
300 300 ${_('Pull request reviewers')}
301 301 %if c.allowed_to_update:
302 302 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
303 303 %endif
304 304 </div>
305 305 </div>
306 306 <div id="reviewers" class="block-right pr-details-content reviewers">
307 307
308 308 ## members redering block
309 309 <input type="hidden" name="__start__" value="review_members:sequence">
310 310 <ul id="review_members" class="group_members">
311 311
312 312 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
313 313 <script>
314 314 var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n};
315 315 var status = "${(status[0][1].status if status else 'not_reviewed')}";
316 316 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
317 317 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
318 318
319 319 var entry = renderTemplate('reviewMemberEntry', {
320 320 'member': member,
321 321 'mandatory': member.mandatory,
322 322 'reasons': member.reasons,
323 323 'allowed_to_update': allowed_to_update,
324 324 'review_status': status,
325 325 'review_status_label': status_lbl,
326 326 'user_group': member.user_group,
327 327 'create': false
328 328 });
329 329 $('#review_members').append(entry)
330 330 </script>
331 331
332 332 % endfor
333 333
334 334 </ul>
335 335
336 336 <input type="hidden" name="__end__" value="review_members:sequence">
337 337 ## end members redering block
338 338
339 339 %if not c.pull_request.is_closed():
340 340 <div id="add_reviewer" class="ac" style="display: none;">
341 341 %if c.allowed_to_update:
342 342 % if not c.forbid_adding_reviewers:
343 343 <div id="add_reviewer_input" class="reviewer_ac">
344 344 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
345 345 <div id="reviewers_container"></div>
346 346 </div>
347 347 % endif
348 348 <div class="pull-right">
349 349 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
350 350 </div>
351 351 %endif
352 352 </div>
353 353 %endif
354 354 </div>
355 355
356 356 ## TODOs will be listed here
357 357 <div class="reviewers-title block-right">
358 358 <div class="pr-details-title">
359 359 ## Only show unresolved, that is only what matters
360 360 TODO Comments - ${len(c.unresolved_comments)} / ${(len(c.unresolved_comments) + len(c.resolved_comments))}
361 361
362 362 % if not c.at_version:
363 363 % if c.resolved_comments:
364 364 <span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return versionController.toggleElement(this, '.unresolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span>
365 365 % else:
366 366 <span class="block-right last-item noselect">Show resolved</span>
367 367 % endif
368 368 % endif
369 369 </div>
370 370 </div>
371 371 <div class="block-right pr-details-content reviewers">
372 372
373 373 <table class="todo-table">
374 374 <%
375 375 def sorter(entry):
376 376 user_id = entry.author.user_id
377 377 resolved = '1' if entry.resolved else '0'
378 378 if user_id == c.rhodecode_user.user_id:
379 379 # own comments first
380 380 user_id = 0
381 381 return '{}_{}_{}'.format(resolved, user_id, str(entry.comment_id).zfill(100))
382 382 %>
383 383
384 384 % if c.at_version:
385 385 <tr>
386 386 <td class="unresolved-todo-text">${_('unresolved TODOs unavailable in this view')}.</td>
387 387 </tr>
388 388 % else:
389 389 % for todo_comment in sorted(c.unresolved_comments + c.resolved_comments, key=sorter):
390 390 <% resolved = todo_comment.resolved %>
391 391 % if inline:
392 392 <% outdated_at_ver = todo_comment.outdated_at_version(getattr(c, 'at_version_num', None)) %>
393 393 % else:
394 394 <% outdated_at_ver = todo_comment.older_than_version(getattr(c, 'at_version_num', None)) %>
395 395 % endif
396 396
397 397 <tr ${('class="unresolved-todo" style="display: none"' if resolved else '') |n}>
398 398
399 399 <td class="td-todo-number">
400 400 % if resolved:
401 401 <a class="permalink todo-resolved tooltip" title="${_('Resolved by comment #{}').format(todo_comment.resolved.comment_id)}" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})">
402 402 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
403 403 % else:
404 404 <a class="permalink" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})">
405 405 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
406 406 % endif
407 407 </td>
408 408 <td class="td-todo-gravatar">
409 409 ${base.gravatar(todo_comment.author.email, 16, user=todo_comment.author, tooltip=True, extra_class=['no-margin'])}
410 410 </td>
411 411 <td class="todo-comment-text-wrapper">
412 412 <div class="todo-comment-text">
413 413 <code>${h.chop_at_smart(todo_comment.text, '\n', suffix_if_chopped='...')}</code>
414 414 </div>
415 415 </td>
416 416
417 417 </tr>
418 418 % endfor
419 419
420 420 % if len(c.unresolved_comments) == 0:
421 421 <tr>
422 422 <td class="unresolved-todo-text">${_('No unresolved TODOs')}.</td>
423 423 </tr>
424 424 % endif
425 425
426 426 % endif
427 427
428 428 </table>
429 429
430 430 </div>
431 431 </div>
432 432
433 433 </div>
434 434
435 435 <div class="box">
436 436
437 437 % if c.state_progressing:
438 438
439 439 <h2 style="text-align: center">
440 440 ${_('Cannot show diff when pull request state is changing. Current progress state')}: <span class="tag tag-merge-state-${c.pull_request.state}">${c.pull_request.state}</span>
441 441
442 442 % if c.is_super_admin:
443 443 <br/>
444 444 If you think this is an error try <a href="${h.current_route_path(request, force_state='created')}">forced state reset</a> to <span class="tag tag-merge-state-created">created</span> state.
445 445 % endif
446 446 </h2>
447 447
448 448 % else:
449 449
450 450 ## Diffs rendered here
451 451 <div class="table" >
452 452 <div id="changeset_compare_view_content">
453 453 ##CS
454 454 % if c.missing_requirements:
455 455 <div class="box">
456 456 <div class="alert alert-warning">
457 457 <div>
458 458 <strong>${_('Missing requirements:')}</strong>
459 459 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
460 460 </div>
461 461 </div>
462 462 </div>
463 463 % elif c.missing_commits:
464 464 <div class="box">
465 465 <div class="alert alert-warning">
466 466 <div>
467 467 <strong>${_('Missing commits')}:</strong>
468 468 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
469 469 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
470 470 ${_('Consider doing a {force_refresh_url} in case you think this is an error.').format(force_refresh_url=h.link_to('force refresh', h.current_route_path(request, force_refresh='1')))|n}
471 471 </div>
472 472 </div>
473 473 </div>
474 474 % elif c.pr_merge_source_commit.changed and not c.pull_request.is_closed():
475 475 <div class="box">
476 476 <div class="alert alert-info">
477 477 <div>
478 478 <strong>${_('There are new changes for `{}:{}` in source repository, please consider updating this pull request.').format(c.pr_merge_source_commit.ref_spec.type, c.pr_merge_source_commit.ref_spec.name)}</strong>
479 479 </div>
480 480 </div>
481 481 </div>
482 482 % endif
483 483
484 484 <div class="compare_view_commits_title">
485 485 % if not c.compare_mode:
486 486
487 487 % if c.at_version_pos:
488 488 <h4>
489 489 ${_('Showing changes at v%d, commenting is disabled.') % c.at_version_pos}
490 490 </h4>
491 491 % endif
492 492
493 493 <div class="pull-left">
494 494 <div class="btn-group">
495 495 <a class="${('collapsed' if c.collapse_all_commits else '')}" href="#expand-commits" onclick="toggleCommitExpand(this); return false" data-toggle-commits-cnt=${len(c.commit_ranges)} >
496 496 % if c.collapse_all_commits:
497 497 <i class="icon-plus-squared-alt icon-no-margin"></i>
498 498 ${_ungettext('Expand {} commit', 'Expand {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
499 499 % else:
500 500 <i class="icon-minus-squared-alt icon-no-margin"></i>
501 501 ${_ungettext('Collapse {} commit', 'Collapse {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
502 502 % endif
503 503 </a>
504 504 </div>
505 505 </div>
506 506
507 507 <div class="pull-right">
508 508 % if c.allowed_to_update and not c.pull_request.is_closed():
509 509
510 510 <div class="btn-group btn-group-actions">
511 511 <a id="update_commits" class="btn btn-primary no-margin" onclick="updateController.updateCommits(this); return false">
512 512 ${_('Update commits')}
513 513 </a>
514 514
515 515 <a id="update_commits_switcher" class="tooltip btn btn-primary" style="margin-left: -1px" data-toggle="dropdown" aria-pressed="false" role="button" title="${_('more update options')}">
516 516 <i class="icon-down"></i>
517 517 </a>
518 518
519 519 <div class="btn-action-switcher-container" id="update-commits-switcher">
520 520 <ul class="btn-action-switcher" role="menu">
521 521 <li>
522 522 <a href="#forceUpdate" onclick="updateController.forceUpdateCommits(this); return false">
523 523 ${_('Force update commits')}
524 524 </a>
525 525 <div class="action-help-block">
526 526 ${_('Update commits and force refresh this pull request.')}
527 527 </div>
528 528 </li>
529 529 </ul>
530 530 </div>
531 531 </div>
532 532
533 533 % else:
534 534 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
535 535 % endif
536 536
537 537 </div>
538 538 % endif
539 539 </div>
540 540
541 541 % if not c.missing_commits:
542 542 % if c.compare_mode:
543 543 % if c.at_version:
544 544 <h4>
545 545 ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_pos, ver_to=c.at_version_pos if c.at_version_pos else 'latest')}:
546 546 </h4>
547 547
548 548 <div class="subtitle-compare">
549 549 ${_('commits added: {}, removed: {}').format(len(c.commit_changes_summary.added), len(c.commit_changes_summary.removed))}
550 550 </div>
551 551
552 552 <div class="container">
553 553 <table class="rctable compare_view_commits">
554 554 <tr>
555 555 <th></th>
556 556 <th>${_('Time')}</th>
557 557 <th>${_('Author')}</th>
558 558 <th>${_('Commit')}</th>
559 559 <th></th>
560 560 <th>${_('Description')}</th>
561 561 </tr>
562 562
563 563 % for c_type, commit in c.commit_changes:
564 564 % if c_type in ['a', 'r']:
565 565 <%
566 566 if c_type == 'a':
567 567 cc_title = _('Commit added in displayed changes')
568 568 elif c_type == 'r':
569 569 cc_title = _('Commit removed in displayed changes')
570 570 else:
571 571 cc_title = ''
572 572 %>
573 573 <tr id="row-${commit.raw_id}" commit_id="${commit.raw_id}" class="compare_select">
574 574 <td>
575 575 <div class="commit-change-indicator color-${c_type}-border">
576 576 <div class="commit-change-content color-${c_type} tooltip" title="${h.tooltip(cc_title)}">
577 577 ${c_type.upper()}
578 578 </div>
579 579 </div>
580 580 </td>
581 581 <td class="td-time">
582 582 ${h.age_component(commit.date)}
583 583 </td>
584 584 <td class="td-user">
585 585 ${base.gravatar_with_user(commit.author, 16, tooltip=True)}
586 586 </td>
587 587 <td class="td-hash">
588 588 <code>
589 589 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
590 590 r${commit.idx}:${h.short_id(commit.raw_id)}
591 591 </a>
592 592 ${h.hidden('revisions', commit.raw_id)}
593 593 </code>
594 594 </td>
595 595 <td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_( 'Expand commit message')}" onclick="commitsController.expandCommit(this); return false">
596 596 <i class="icon-expand-linked"></i>
597 597 </td>
598 598 <td class="mid td-description">
599 599 <div class="log-container truncate-wrap">
600 600 <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
601 601 </div>
602 602 </td>
603 603 </tr>
604 604 % endif
605 605 % endfor
606 606 </table>
607 607 </div>
608 608
609 609 % endif
610 610
611 611 % else:
612 612 <%include file="/compare/compare_commits.mako" />
613 613 % endif
614 614
615 615 <div class="cs_files">
616 616 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
617 617 % if c.at_version:
618 618 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['display']) %>
619 619 <% c.comments = c.comment_versions[c.at_version_num]['display'] %>
620 620 % else:
621 621 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['until']) %>
622 622 <% c.comments = c.comment_versions[c.at_version_num]['until'] %>
623 623 % endif
624 624
625 625 <%
626 626 pr_menu_data = {
627 'outdated_comm_count_ver': outdated_comm_count_ver
627 'outdated_comm_count_ver': outdated_comm_count_ver,
628 'pull_request': c.pull_request
628 629 }
629 630 %>
630 631
631 ${cbdiffs.render_diffset_menu(c.diffset, range_diff_on=c.range_diff_on)}
632 ${cbdiffs.render_diffset_menu(c.diffset, range_diff_on=c.range_diff_on, pull_request_menu=pr_menu_data)}
632 633
633 634 % if c.range_diff_on:
634 635 % for commit in c.commit_ranges:
635 636 ${cbdiffs.render_diffset(
636 637 c.changes[commit.raw_id],
637 638 commit=commit, use_comments=True,
638 639 collapse_when_files_over=5,
639 640 disable_new_comments=True,
640 641 deleted_files_comments=c.deleted_files_comments,
641 642 inline_comments=c.inline_comments,
642 643 pull_request_menu=pr_menu_data, show_todos=False)}
643 644 % endfor
644 645 % else:
645 646 ${cbdiffs.render_diffset(
646 647 c.diffset, use_comments=True,
647 648 collapse_when_files_over=30,
648 649 disable_new_comments=not c.allowed_to_comment,
649 650 deleted_files_comments=c.deleted_files_comments,
650 651 inline_comments=c.inline_comments,
651 652 pull_request_menu=pr_menu_data, show_todos=False)}
652 653 % endif
653 654
654 655 </div>
655 656 % else:
656 657 ## skipping commits we need to clear the view for missing commits
657 658 <div style="clear:both;"></div>
658 659 % endif
659 660
660 661 </div>
661 662 </div>
662 663
663 664 ## template for inline comment form
664 665 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
665 666
666 667 ## comments heading with count
667 668 <div class="comments-heading">
668 669 <i class="icon-comment"></i>
669 670 ${_('Comments')} ${len(c.comments)}
670 671 </div>
671 672
672 673 ## render general comments
673 674 <div id="comment-tr-show">
674 675 % if general_outdated_comm_count_ver:
675 676 <div class="info-box">
676 677 % if general_outdated_comm_count_ver == 1:
677 678 ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)},
678 679 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a>
679 680 % else:
680 681 ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)},
681 682 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a>
682 683 % endif
683 684 </div>
684 685 % endif
685 686 </div>
686 687
687 688 ${comment.generate_comments(c.comments, include_pull_request=True, is_pull_request=True)}
688 689
689 690 % if not c.pull_request.is_closed():
690 691 ## main comment form and it status
691 692 ${comment.comments(h.route_path('pullrequest_comment_create', repo_name=c.repo_name,
692 693 pull_request_id=c.pull_request.pull_request_id),
693 694 c.pull_request_review_status,
694 695 is_pull_request=True, change_status=c.allowed_to_change_status)}
695 696
696 697 ## merge status, and merge action
697 698 <div class="pull-request-merge">
698 699 <%include file="/pullrequests/pullrequest_merge_checks.mako"/>
699 700 </div>
700 701
701 702 %endif
702 703
703 704 % endif
704 705 </div>
705 706
706 707 <script type="text/javascript">
707 708
708 709 versionController = new VersionController();
709 710 versionController.init();
710 711
711 712 reviewersController = new ReviewersController();
712 713 commitsController = new CommitsController();
713 714
714 715 updateController = new UpdatePrController();
715 716
716 717 $(function () {
717 718
718 719 // custom code mirror
719 720 var codeMirrorInstance = $('#pr-description-input').get(0).MarkupForm.cm;
720 721
721 722 var PRDetails = {
722 723 editButton: $('#open_edit_pullrequest'),
723 724 closeButton: $('#close_edit_pullrequest'),
724 725 deleteButton: $('#delete_pullrequest'),
725 726 viewFields: $('#pr-desc, #pr-title'),
726 727 editFields: $('#pr-desc-edit, #pr-title-edit, .pr-save'),
727 728
728 729 init: function () {
729 730 var that = this;
730 731 this.editButton.on('click', function (e) {
731 732 that.edit();
732 733 });
733 734 this.closeButton.on('click', function (e) {
734 735 that.view();
735 736 });
736 737 },
737 738
738 739 edit: function (event) {
739 740 this.viewFields.hide();
740 741 this.editButton.hide();
741 742 this.deleteButton.hide();
742 743 this.closeButton.show();
743 744 this.editFields.show();
744 745 codeMirrorInstance.refresh();
745 746 },
746 747
747 748 view: function (event) {
748 749 this.editButton.show();
749 750 this.deleteButton.show();
750 751 this.editFields.hide();
751 752 this.closeButton.hide();
752 753 this.viewFields.show();
753 754 }
754 755 };
755 756
756 757 var ReviewersPanel = {
757 758 editButton: $('#open_edit_reviewers'),
758 759 closeButton: $('#close_edit_reviewers'),
759 760 addButton: $('#add_reviewer'),
760 761 removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'),
761 762
762 763 init: function () {
763 764 var self = this;
764 765 this.editButton.on('click', function (e) {
765 766 self.edit();
766 767 });
767 768 this.closeButton.on('click', function (e) {
768 769 self.close();
769 770 });
770 771 },
771 772
772 773 edit: function (event) {
773 774 this.editButton.hide();
774 775 this.closeButton.show();
775 776 this.addButton.show();
776 777 this.removeButtons.css('visibility', 'visible');
777 778 // review rules
778 779 reviewersController.loadReviewRules(
779 780 ${c.pull_request.reviewer_data_json | n});
780 781 },
781 782
782 783 close: function (event) {
783 784 this.editButton.show();
784 785 this.closeButton.hide();
785 786 this.addButton.hide();
786 787 this.removeButtons.css('visibility', 'hidden');
787 788 // hide review rules
788 789 reviewersController.hideReviewRules()
789 790 }
790 791 };
791 792
792 793 PRDetails.init();
793 794 ReviewersPanel.init();
794 795
795 796 showOutdated = function (self) {
796 797 $('.comment-inline.comment-outdated').show();
797 798 $('.filediff-outdated').show();
798 799 $('.showOutdatedComments').hide();
799 800 $('.hideOutdatedComments').show();
800 801 };
801 802
802 803 hideOutdated = function (self) {
803 804 $('.comment-inline.comment-outdated').hide();
804 805 $('.filediff-outdated').hide();
805 806 $('.hideOutdatedComments').hide();
806 807 $('.showOutdatedComments').show();
807 808 };
808 809
809 810 refreshMergeChecks = function () {
810 811 var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
811 812 $('.pull-request-merge').css('opacity', 0.3);
812 813 $('.action-buttons-extra').css('opacity', 0.3);
813 814
814 815 $('.pull-request-merge').load(
815 816 loadUrl, function () {
816 817 $('.pull-request-merge').css('opacity', 1);
817 818
818 819 $('.action-buttons-extra').css('opacity', 1);
819 820 }
820 821 );
821 822 };
822 823
823 824 closePullRequest = function (status) {
824 825 if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
825 826 return false;
826 827 }
827 828 // inject closing flag
828 829 $('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
829 830 $(generalCommentForm.statusChange).select2("val", status).trigger('change');
830 831 $(generalCommentForm.submitForm).submit();
831 832 };
832 833
833 834 $('#show-outdated-comments').on('click', function (e) {
834 835 var button = $(this);
835 836 var outdated = $('.comment-outdated');
836 837
837 838 if (button.html() === "(Show)") {
838 839 button.html("(Hide)");
839 840 outdated.show();
840 841 } else {
841 842 button.html("(Show)");
842 843 outdated.hide();
843 844 }
844 845 });
845 846
846 847 $('.show-inline-comments').on('change', function (e) {
847 848 var show = 'none';
848 849 var target = e.currentTarget;
849 850 if (target.checked) {
850 851 show = ''
851 852 }
852 853 var boxid = $(target).attr('id_for');
853 854 var comments = $('#{0} .inline-comments'.format(boxid));
854 855 var fn_display = function (idx) {
855 856 $(this).css('display', show);
856 857 };
857 858 $(comments).each(fn_display);
858 859 var btns = $('#{0} .inline-comments-button'.format(boxid));
859 860 $(btns).each(fn_display);
860 861 });
861 862
862 863 $('#merge_pull_request_form').submit(function () {
863 864 if (!$('#merge_pull_request').attr('disabled')) {
864 865 $('#merge_pull_request').attr('disabled', 'disabled');
865 866 }
866 867 return true;
867 868 });
868 869
869 870 $('#edit_pull_request').on('click', function (e) {
870 871 var title = $('#pr-title-input').val();
871 872 var description = codeMirrorInstance.getValue();
872 873 var renderer = $('#pr-renderer-input').val();
873 874 editPullRequest(
874 875 "${c.repo_name}", "${c.pull_request.pull_request_id}",
875 876 title, description, renderer);
876 877 });
877 878
878 879 $('#update_pull_request').on('click', function (e) {
879 880 $(this).attr('disabled', 'disabled');
880 881 $(this).addClass('disabled');
881 882 $(this).html(_gettext('Saving...'));
882 883 reviewersController.updateReviewers(
883 884 "${c.repo_name}", "${c.pull_request.pull_request_id}");
884 885 });
885 886
886 887
887 888 // fixing issue with caches on firefox
888 889 $('#update_commits').removeAttr("disabled");
889 890
890 891 $('.show-inline-comments').on('click', function (e) {
891 892 var boxid = $(this).attr('data-comment-id');
892 893 var button = $(this);
893 894
894 895 if (button.hasClass("comments-visible")) {
895 896 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
896 897 $(this).hide();
897 898 });
898 899 button.removeClass("comments-visible");
899 900 } else {
900 901 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
901 902 $(this).show();
902 903 });
903 904 button.addClass("comments-visible");
904 905 }
905 906 });
906 907
907 908 // register submit callback on commentForm form to track TODOs
908 909 window.commentFormGlobalSubmitSuccessCallback = function () {
909 910 refreshMergeChecks();
910 911 };
911 912
912 913 ReviewerAutoComplete('#user');
913 914
914 915 })
915 916
916 917 </script>
917 918
918 919 </div>
919 920
920 921 </%def>
General Comments 0
You need to be logged in to leave comments. Login now