##// END OF EJS Templates
pull-requests: added observers, and fix few problems with versioned comments
marcink -
r4481:d52ab7ab default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -0,0 +1,52 b''
1 # -*- coding: utf-8 -*-
2
3 import logging
4 from sqlalchemy import *
5
6 from alembic.migration import MigrationContext
7 from alembic.operations import Operations
8
9 from rhodecode.lib.dbmigrate.versions import _reset_base
10 from rhodecode.model import meta, init_model_encryption
11
12
13 log = logging.getLogger(__name__)
14
15
16 def upgrade(migrate_engine):
17 """
18 Upgrade operations go here.
19 Don't create your own engine; bind migrate_engine to your metadata
20 """
21 _reset_base(migrate_engine)
22 from rhodecode.lib.dbmigrate.schema import db_4_20_0_0 as db
23
24 init_model_encryption(db)
25
26 context = MigrationContext.configure(migrate_engine.connect())
27 op = Operations(context)
28
29 table = db.PullRequestReviewers.__table__
30 with op.batch_alter_table(table.name) as batch_op:
31 new_column = Column('role', Unicode(255), nullable=True)
32 batch_op.add_column(new_column)
33
34 _fill_reviewers_role(db, op, meta.Session)
35
36
37 def downgrade(migrate_engine):
38 meta = MetaData()
39 meta.bind = migrate_engine
40
41
42 def fixups(models, _SESSION):
43 pass
44
45
46 def _fill_reviewers_role(models, op, session):
47 params = {'role': 'reviewer'}
48 query = text(
49 'UPDATE pull_request_reviewers SET role = :role'
50 ).bindparams(**params)
51 op.execute(query)
52 session().commit()
@@ -48,7 +48,7 b' PYRAMID_SETTINGS = {}'
48 48 EXTENSIONS = {}
49 49
50 50 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
51 __dbversion__ = 108 # defines current db version for migrations
51 __dbversion__ = 109 # defines current db version for migrations
52 52 __platform__ = platform.system()
53 53 __license__ = 'AGPLv3, and Commercial License'
54 54 __author__ = 'RhodeCode GmbH'
@@ -166,8 +166,8 b' class RepoCommitsView(RepoAppView):'
166 166 if method == 'show':
167 167 inline_comments = CommentsModel().get_inline_comments(
168 168 self.db_repo.repo_id, revision=commit.raw_id)
169 c.inline_cnt = CommentsModel().get_inline_comments_count(
170 inline_comments)
169 c.inline_cnt = len(CommentsModel().get_inline_comments_as_list(
170 inline_comments))
171 171 c.inline_comments = inline_comments
172 172
173 173 cache_path = self.rhodecode_vcs_repo.get_create_shadow_cache_pr_path(
@@ -641,7 +641,7 b' class CommentsModel(BaseModel):'
641 641 q = self._get_inline_comments_query(repo_id, revision, pull_request)
642 642 return self._group_comments_by_path_and_line_number(q)
643 643
644 def get_inline_comments_count(self, inline_comments, skip_outdated=True,
644 def get_inline_comments_as_list(self, inline_comments, skip_outdated=True,
645 645 version=None):
646 646 inline_cnt = 0
647 647 for fname, per_line_comments in inline_comments.iteritems():
@@ -3810,6 +3810,10 b' class ChangesetComment(Base, BaseModel):'
3810 3810 return self.display_state == self.COMMENT_OUTDATED
3811 3811
3812 3812 @property
3813 def outdated_js(self):
3814 return json.dumps(self.display_state == self.COMMENT_OUTDATED)
3815
3816 @property
3813 3817 def immutable(self):
3814 3818 return self.immutable_state == self.OP_IMMUTABLE
3815 3819
@@ -4492,6 +4496,8 b' class PullRequestReviewers(Base, BaseMod'
4492 4496 __table_args__ = (
4493 4497 base_table_args,
4494 4498 )
4499 ROLE_REVIEWER = u'reviewer'
4500 ROLE_OBSERVER = u'observer'
4495 4501
4496 4502 @hybrid_property
4497 4503 def reasons(self):
@@ -4519,6 +4525,8 b' class PullRequestReviewers(Base, BaseMod'
4519 4525 JsonType('list', dialect_map=dict(mysql=UnicodeText(16384)))))
4520 4526
4521 4527 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
4528 role = Column('role', Unicode(255), nullable=True, default=ROLE_REVIEWER)
4529
4522 4530 user = relationship('User')
4523 4531 pull_request = relationship('PullRequest')
4524 4532
@@ -484,10 +484,6 b' ul.auth_plugins {'
484 484 white-space: pre-line;
485 485 }
486 486
487 .pr-details-title {
488 height: 16px
489 }
490
491 487 .pr-details-title-author-pref {
492 488 padding-right: 10px
493 489 }
@@ -1492,26 +1488,17 b' table.integrations {'
1492 1488
1493 1489 // Pull Requests
1494 1490 .summary-details {
1495 width: 72%;
1491 width: 100%;
1496 1492 }
1497 1493 .pr-summary {
1498 1494 border-bottom: @border-thickness solid @grey5;
1499 1495 margin-bottom: @space;
1500 1496 }
1501 1497
1502 .reviewers-title {
1503 width: 25%;
1504 min-width: 200px;
1505
1506 &.first-panel {
1507 margin-top: 34px;
1508 }
1498 .reviewers {
1499 width: 98%;
1509 1500 }
1510 1501
1511 .reviewers {
1512 width: 25%;
1513 min-width: 200px;
1514 }
1515 1502 .reviewers ul li {
1516 1503 position: relative;
1517 1504 width: 100%;
@@ -1593,6 +1580,9 b' table.integrations {'
1593 1580 cursor: pointer;
1594 1581 }
1595 1582 .pr-details-title {
1583 height: 20px;
1584 line-height: 20px;
1585
1596 1586 padding-bottom: 8px;
1597 1587 border-bottom: @border-thickness solid @grey5;
1598 1588
@@ -1617,7 +1607,7 b' table.integrations {'
1617 1607 text-decoration: line-through;
1618 1608 }
1619 1609
1620 .todo-table {
1610 .todo-table, .comments-table {
1621 1611 width: 100%;
1622 1612
1623 1613 td {
@@ -38,10 +38,12 b''
38 38 <div class="main">
39 39 ${next.main()}
40 40 </div>
41
41 42 </div>
42 43 <!-- END CONTENT -->
43 44
44 45 </div>
46
45 47 <!-- FOOTER -->
46 48 <div id="footer">
47 49 <div id="footer-inner" class="title wrapper">
@@ -159,45 +159,45 b" return '%s_%s_%i' % (h.md5_safe(commit+f"
159 159 </div>
160 160 % endif
161 161
162 ## comments
163 <div class="pull-right">
164 <div class="comments-number" style="padding-left: 10px">
165 % if hasattr(c, 'comments') and hasattr(c, 'inline_cnt'):
166 <i class="icon-comment" style="color: #949494">COMMENTS:</i>
167 % if c.comments:
168 <a href="#comments">${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))}</a>,
169 % else:
170 ${_('0 General')}
171 % endif
172
173 % if c.inline_cnt:
174 <a href="#" onclick="return Rhodecode.comments.nextComment();"
175 id="inline-comments-counter">${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(c.inline_cnt)}
176 </a>
177 % else:
178 ${_('0 Inline')}
179 % endif
180 % endif
181
182 % if pull_request_menu:
183 <%
184 outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver']
185 %>
186
187 % if outdated_comm_count_ver:
188 <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">
189 (${_("{} Outdated").format(outdated_comm_count_ver)})
190 </a>
191 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a>
192 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a>
193 % else:
194 (${_("{} Outdated").format(outdated_comm_count_ver)})
195 % endif
196
197 % endif
198
199 </div>
200 </div>
162 ## ## comments
163 ## <div class="pull-right">
164 ## <div class="comments-number" style="padding-left: 10px">
165 ## % if hasattr(c, 'comments') and hasattr(c, 'inline_cnt'):
166 ## <i class="icon-comment" style="color: #949494">COMMENTS:</i>
167 ## % if c.comments:
168 ## <a href="#comments">${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))}</a>,
169 ## % else:
170 ## ${_('0 General')}
171 ## % endif
172 ##
173 ## % if c.inline_cnt:
174 ## <a href="#" onclick="return Rhodecode.comments.nextComment();"
175 ## id="inline-comments-counter">${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(c.inline_cnt)}
176 ## </a>
177 ## % else:
178 ## ${_('0 Inline')}
179 ## % endif
180 ## % endif
181 ##
182 ## % if pull_request_menu:
183 ## <%
184 ## outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver']
185 ## %>
186 ##
187 ## % if outdated_comm_count_ver:
188 ## <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">
189 ## (${_("{} Outdated").format(outdated_comm_count_ver)})
190 ## </a>
191 ## <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a>
192 ## <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a>
193 ## % else:
194 ## (${_("{} Outdated").format(outdated_comm_count_ver)})
195 ## % endif
196 ##
197 ## % endif
198 ##
199 ## </div>
200 ## </div>
201 201
202 202 </div>
203 203
@@ -934,7 +934,7 b' def get_comments_for(diff_type, comments'
934 934 </span>
935 935 %endif
936 936 % if commit or pull_request_menu:
937 <span id="diff_nav">Loading diff...:</span>
937 <span class="tooltip" title="Navigate to previous or next change inside files." id="diff_nav">Loading diff...:</span>
938 938 <span class="cursor-pointer" onclick="scrollToPrevChunk(); return false">
939 939 <i class="icon-angle-up"></i>
940 940 </span>
@@ -39,25 +39,26 b' var CG = new ColorGenerator();'
39 39 </script>
40 40
41 41 <script id="ejs_reviewMemberEntry" type="text/template" class="ejsTemplate">
42
43 <li id="reviewer_<%= member.user_id %>" class="reviewer_entry">
44 <%
45 if (create) {
46 var edit_visibility = 'visible';
47 } else {
48 var edit_visibility = 'hidden';
49 }
42 <%
43 if (create) {
44 var edit_visibility = 'visible';
45 } else {
46 var edit_visibility = 'hidden';
47 }
50 48
51 if (member.user_group && member.user_group.vote_rule) {
52 var groupStyle = 'border-left: 1px solid '+CG.asRGB(CG.getColor(member.user_group.vote_rule));
53 } else {
54 var groupStyle = 'border-left: 1px solid white';
55 }
56 %>
49 if (member.user_group && member.user_group.vote_rule) {
50 var groupStyle = 'border-right: 2px solid '+CG.asRGB(CG.getColor(member.user_group.vote_rule));
51 } else {
52 var groupStyle = 'border-right: 2px solid transparent';
53 }
54 %>
57 55
58 <div class="reviewers_member" style="<%= groupStyle%>" >
56 <li id="reviewer_<%= member.user_id %>" class="reviewer_entry" style="<%= groupStyle%>" tooltip="Review Group">
57
58 <div class="reviewers_member">
59 59 <div class="reviewer_status tooltip" title="<%= review_status_label %>">
60 60 <i class="icon-circle review-status-<%= review_status %>"></i>
61
61 62 </div>
62 63 <div id="reviewer_<%= member.user_id %>_name" class="reviewer_name">
63 64 <% if (mandatory) { %>
This diff has been collapsed as it changes many lines, (590 lines changed) Show them Hide them
@@ -280,159 +280,14 b''
280 280
281 281 </div>
282 282
283 ## REVIEW RULES
284 <div id="review_rules" style="display: none" class="reviewers-title block-right">
285 <div class="pr-details-title">
286 ${_('Reviewer rules')}
287 %if c.allowed_to_update:
288 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
289 %endif
290 </div>
291 <div class="pr-reviewer-rules">
292 ## review rules will be appended here, by default reviewers logic
293 </div>
294 <input id="review_data" type="hidden" name="review_data" value="">
295 </div>
296
297 ## REVIEWERS
298 <div class="reviewers-title first-panel block-right">
299 <div class="pr-details-title">
300 ${_('Pull request reviewers')}
301 %if c.allowed_to_update:
302 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
303 %endif
304 </div>
305 </div>
306 <div id="reviewers" class="block-right pr-details-content reviewers">
307
308 ## members redering block
309 <input type="hidden" name="__start__" value="review_members:sequence">
310 <ul id="review_members" class="group_members">
311
312 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
313 <script>
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 var status = "${(status[0][1].status if status else 'not_reviewed')}";
316 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
317 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
318
319 var entry = renderTemplate('reviewMemberEntry', {
320 'member': member,
321 'mandatory': member.mandatory,
322 'reasons': member.reasons,
323 'allowed_to_update': allowed_to_update,
324 'review_status': status,
325 'review_status_label': status_lbl,
326 'user_group': member.user_group,
327 'create': false
328 });
329 $('#review_members').append(entry)
330 </script>
331
332 % endfor
333
334 </ul>
335
336 <input type="hidden" name="__end__" value="review_members:sequence">
337 ## end members redering block
338
339 %if not c.pull_request.is_closed():
340 <div id="add_reviewer" class="ac" style="display: none;">
341 %if c.allowed_to_update:
342 % if not c.forbid_adding_reviewers:
343 <div id="add_reviewer_input" class="reviewer_ac">
344 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
345 <div id="reviewers_container"></div>
346 </div>
347 % endif
348 <div class="pull-right">
349 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
350 </div>
351 %endif
352 </div>
353 %endif
354 </div>
355 283
356 ## TODOs will be listed here
357 <div class="reviewers-title block-right">
358 <div class="pr-details-title">
359 ## Only show unresolved, that is only what matters
360 TODO Comments - ${len(c.unresolved_comments)} / ${(len(c.unresolved_comments) + len(c.resolved_comments))}
361 284
362 % if not c.at_version:
363 % if c.resolved_comments:
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 % else:
366 <span class="block-right last-item noselect">Show resolved</span>
367 % endif
368 % endif
369 </div>
370 </div>
371 <div class="block-right pr-details-content reviewers">
372
373 <table class="todo-table">
374 <%
375 def sorter(entry):
376 user_id = entry.author.user_id
377 resolved = '1' if entry.resolved else '0'
378 if user_id == c.rhodecode_user.user_id:
379 # own comments first
380 user_id = 0
381 return '{}_{}_{}'.format(resolved, user_id, str(entry.comment_id).zfill(100))
382 %>
383
384 % if c.at_version:
385 <tr>
386 <td class="unresolved-todo-text">${_('unresolved TODOs unavailable in this view')}.</td>
387 </tr>
388 % else:
389 % for todo_comment in sorted(c.unresolved_comments + c.resolved_comments, key=sorter):
390 <% resolved = todo_comment.resolved %>
391 % if inline:
392 <% outdated_at_ver = todo_comment.outdated_at_version(getattr(c, 'at_version_num', None)) %>
393 % else:
394 <% outdated_at_ver = todo_comment.older_than_version(getattr(c, 'at_version_num', None)) %>
395 % endif
396
397 <tr ${('class="unresolved-todo" style="display: none"' if resolved else '') |n}>
398
399 <td class="td-todo-number">
400 % if resolved:
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 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
403 % else:
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 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
406 % endif
407 </td>
408 <td class="td-todo-gravatar">
409 ${base.gravatar(todo_comment.author.email, 16, user=todo_comment.author, tooltip=True, extra_class=['no-margin'])}
410 </td>
411 <td class="todo-comment-text-wrapper">
412 <div class="todo-comment-text">
413 <code>${h.chop_at_smart(todo_comment.text, '\n', suffix_if_chopped='...')}</code>
414 </div>
415 </td>
416
417 </tr>
418 % endfor
419
420 % if len(c.unresolved_comments) == 0:
421 <tr>
422 <td class="unresolved-todo-text">${_('No unresolved TODOs')}.</td>
423 </tr>
424 % endif
425
426 % endif
427
428 </table>
429
430 </div>
431 </div>
432 285
433 286 </div>
434 287
435 <div class="box">
288 </div>
289
290 <div class="box">
436 291
437 292 % if c.state_progressing:
438 293
@@ -616,9 +471,11 b''
616 471 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
617 472 % if c.at_version:
618 473 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['display']) %>
474 <% c.inline_comments_flat = c.inline_versions[c.at_version_num]['display'] %>
619 475 <% c.comments = c.comment_versions[c.at_version_num]['display'] %>
620 476 % else:
621 477 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['until']) %>
478 <% c.inline_comments_flat = c.inline_versions[c.at_version_num]['until'] %>
622 479 <% c.comments = c.comment_versions[c.at_version_num]['until'] %>
623 480 % endif
624 481
@@ -704,7 +561,7 b''
704 561 % endif
705 562 </div>
706 563
707 <script type="text/javascript">
564 <script type="text/javascript">
708 565
709 566 versionController = new VersionController();
710 567 versionController.init();
@@ -916,6 +773,439 b''
916 773
917 774 </script>
918 775
919 </div>
776
777 ### NAVBOG RIGHT
778 <style>
779
780 .right-sidebar {
781 position: fixed;
782 top: 0px;
783 bottom: 0;
784 right: 0;
785
786 background: #fafafa;
787 z-index: 200;
788 }
789
790 .right-sidebar {
791 border-left: 1px solid #dbdbdb;
792 }
793
794 .right-sidebar.right-sidebar-expanded {
795 width: 320px;
796 overflow: scroll;
797 }
798
799 .right-sidebar.right-sidebar-collapsed {
800 width: 62px;
801 padding: 0;
802 display: block;
803 overflow: hidden;
804 }
805
806 .sidenav {
807 float: right;
808 will-change: min-height;
809 background: #fafafa;
810 width: 100%;
811 }
812
813 .sidebar-toggle {
814 height: 30px;
815 text-align: center;
816 margin: 15px 0 0 0;
817 }
818 .sidebar-toggle a {
819
820 }
821
822 .sidebar-content {
823 margin-left: 5px;
824 margin-right: 5px;
825 }
826
827 .sidebar-heading {
828 font-size: 1.2em;
829 font-weight: 700;
830 margin-top: 10px;
831 }
832
833 .sidebar-element {
834 margin-top: 20px;
835 }
836 .right-sidebar-collapsed-state {
837 display: flex;
838 flex-direction: column;
839 justify-content: center;
840 align-items: center;
841 padding: 0 10px;
842 cursor: pointer;
843 font-size: 1.3em;
844 margin: 0 -10px;
845 }
846
847 .right-sidebar-collapsed-state:hover {
848 background-color: #dbd9da;
849 }
850
851 .navbar__inner {
852 height: 100%;
853 background: #fafafa;
854 position: relative;
855 }
856
857 </style>
858
859
860
861 <aside class="right-sidebar right-sidebar-expanded">
862 <div class="sidenav">
863 ## TOGGLE
864 <div class="sidebar-toggle" onclick="toggleSidebar(); return false">
865 <a href="#toggleSidebar">
866
867 </a>
868 </div>
869
870 ## CONTENT
871 <div class="sidebar-content">
872
873 ## RULES SUMMARY/RULES
874 <div class="sidebar-element clear-both">
875
876 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Reviewers')}">
877 <i class="icon-circle review-status-${c.pull_request_review_status}"></i>
878 <br/>${len(c.pull_request_reviewers)}
879 </div>
880
881 ## REVIEW RULES
882 <div id="review_rules" style="display: none" class="">
883 <div class="pr-details-title">
884 <span class="sidebar-heading">
885 ${_('Reviewer rules')}
886 </span>
887
888 </div>
889 <div class="pr-reviewer-rules">
890 ## review rules will be appended here, by default reviewers logic
891 </div>
892 <input id="review_data" type="hidden" name="review_data" value="">
893 </div>
894
895 ## REVIEWERS
896 <div class="right-sidebar-expanded-state pr-details-title">
897 <span class="sidebar-heading">
898 <i class="icon-circle review-status-${c.pull_request_review_status}"></i>
899 ${_('Reviewers')} - ${len(c.pull_request_reviewers)}
900 </span>
901 %if c.allowed_to_update:
902 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
903 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
904 %endif
905 </div>
906 <div id="reviewers" class="right-sidebar-expanded-state pr-details-content reviewers">
907
908 ## members redering block
909 <input type="hidden" name="__start__" value="review_members:sequence">
910 <ul id="review_members" class="group_members">
911
912 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
913 <script>
914 var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n};
915 var status = "${(status[0][1].status if status else 'not_reviewed')}";
916 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
917 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
918
919 var entry = renderTemplate('reviewMemberEntry', {
920 'member': member,
921 'mandatory': member.mandatory,
922 'reasons': member.reasons,
923 'allowed_to_update': allowed_to_update,
924 'review_status': status,
925 'review_status_label': status_lbl,
926 'user_group': member.user_group,
927 'create': false
928 });
929 $('#review_members').append(entry)
930 </script>
931
932 % endfor
933
934 </ul>
935
936 <input type="hidden" name="__end__" value="review_members:sequence">
937 ## end members redering block
938
939 %if not c.pull_request.is_closed():
940 <div id="add_reviewer" class="ac" style="display: none;">
941 %if c.allowed_to_update:
942 % if not c.forbid_adding_reviewers:
943 <div id="add_reviewer_input" class="reviewer_ac">
944 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
945 <div id="reviewers_container"></div>
946 </div>
947 % endif
948 <div class="pull-right">
949 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
950 </div>
951 %endif
952 </div>
953 %endif
954 </div>
955 </div>
956
957 ## OBSERVERS
958 <div class="sidebar-element clear-both">
959 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Observers')}">
960 <i class="icon-eye"></i>
961 <br/> 0
962 </div>
963
964 <div class="right-sidebar-expanded-state pr-details-title">
965 <span class="sidebar-heading">
966 <i class="icon-eye"></i>
967 ${_('Observers')}
968 </span>
969 </div>
970 <div class="right-sidebar-expanded-state pr-details-content">
971 No observers - 0
972 </div>
973 </div>
974
975 ## TODOs
976 <div class="sidebar-element clear-both">
977 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="TODOs">
978 <i class="icon-flag-filled"></i>
979 <br/> ${len(c.unresolved_comments)}
980 </div>
981
982 ## TODOs will be listed here
983 <div class="right-sidebar-expanded-state pr-details-title">
984 ## Only show unresolved, that is only what matters
985 <span class="sidebar-heading">
986 <i class="icon-flag-filled"></i>
987 TODOs - ${len(c.unresolved_comments)}
988 ##/ ${(len(c.unresolved_comments) + len(c.resolved_comments))}
989 </span>
920 990
991 % if not c.at_version:
992 % if c.resolved_comments:
993 <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>
994 % else:
995 <span class="block-right last-item noselect">Show resolved</span>
996 % endif
997 % endif
998 </div>
999
1000 <div class="right-sidebar-expanded-state pr-details-content">
1001
1002 <table class="todo-table">
1003 <%
1004 def sorter(entry):
1005 user_id = entry.author.user_id
1006 resolved = '1' if entry.resolved else '0'
1007 if user_id == c.rhodecode_user.user_id:
1008 # own comments first
1009 user_id = 0
1010 return '{}_{}_{}'.format(resolved, user_id, str(entry.comment_id).zfill(100))
1011 %>
1012
1013 % if c.at_version:
1014 <tr>
1015 <td class="unresolved-todo-text">${_('unresolved TODOs unavailable in this view')}.</td>
1016 </tr>
1017 % else:
1018 % for todo_comment in sorted(c.unresolved_comments + c.resolved_comments, key=sorter):
1019 <% resolved = todo_comment.resolved %>
1020 % if inline:
1021 <% outdated_at_ver = todo_comment.outdated_at_version(getattr(c, 'at_version_num', None)) %>
1022 % else:
1023 <% outdated_at_ver = todo_comment.older_than_version(getattr(c, 'at_version_num', None)) %>
1024 % endif
1025
1026 <tr ${('class="unresolved-todo" style="display: none"' if resolved else '') |n}>
1027
1028 <td class="td-todo-number">
1029 % if resolved:
1030 <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)})">
1031 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
1032 % else:
1033 <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)})">
1034 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
1035 % endif
1036 </td>
1037 <td class="td-todo-gravatar">
1038 ${base.gravatar(todo_comment.author.email, 16, user=todo_comment.author, tooltip=True, extra_class=['no-margin'])}
1039 </td>
1040 <td class="todo-comment-text-wrapper">
1041 <div class="todo-comment-text">
1042 <code>${h.chop_at_smart(todo_comment.text, '\n', suffix_if_chopped='...')}</code>
1043 </div>
1044 </td>
1045
1046 </tr>
1047 % endfor
1048
1049 % if len(c.unresolved_comments) == 0:
1050 <tr>
1051 <td class="unresolved-todo-text">${_('No unresolved TODOs')}.</td>
1052 </tr>
1053 % endif
1054
1055 % endif
1056
1057 </table>
1058
1059 </div>
1060 </div>
1061
1062 ## COMMENTS
1063 <div class="sidebar-element clear-both">
1064 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}">
1065 <i class="icon-comment" style="color: #949494"></i>
1066 <br/> ${len(c.inline_comments_flat+c.comments)}
1067 </div>
1068
1069 <div class="right-sidebar-expanded-state pr-details-title">
1070 <span class="sidebar-heading">
1071 <i class="icon-comment" style="color: #949494"></i>
1072 ${_('Comments')} - ${len(c.inline_comments_flat+c.comments)}
1073 ##${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))} /
1074 ##${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(len(c.inline_comments_flat))}
1075
1076 ## TODO check why this ins't working
1077 % if pull_request_menu:
1078 <%
1079 outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver']
1080 %>
1081
1082 % if outdated_comm_count_ver:
1083 <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">
1084 (${_("{} Outdated").format(outdated_comm_count_ver)})
1085 </a>
1086 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a>
1087 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a>
1088 % else:
1089 (${_("{} Outdated").format(outdated_comm_count_ver)})
1090 % endif
1091
1092 % endif
1093 </span>
1094 <span class="block-right action_button last-item noselect" onclick="return versionController.toggleElement(this, '.hidden-comment');" data-toggle-on="Show all" data-toggle-off="Hide all">Show all</span>
1095 </div>
1096
1097 <div class="right-sidebar-expanded-state pr-details-content">
1098 <table class="todo-table">
1099 <%
1100 def sorter(entry):
1101 user_id = entry.author.user_id
1102 return '{}'.format(str(entry.comment_id).zfill(100))
1103 %>
1104
1105 % for comment_obj in reversed(sorted(c.inline_comments_flat + c.comments, key=sorter)):
1106 <%
1107 display = ''
1108 _cls = ''
1109 %>
1110 ## SKIP TODOs we display them above
1111 % if comment_obj.is_todo:
1112 <% display = 'none' %>
1113 % endif
1114
1115 ## Skip outdated comments
1116 % if comment_obj.outdated:
1117 <% display = 'none' %>
1118 <% _cls = 'hidden-comment' %>
1119 % endif
1120
1121 <tr class="${_cls}" style="display: ${display}">
1122 <td class="td-todo-number">
1123 <a class="permalink" href="#comment-${comment_obj.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${comment_obj.comment_id}'), 0, ${comment_obj.outdated_js})">
1124 % if comment_obj.outdated:
1125 <i class="tooltip icon-comment-toggle" title="Outdated"></i>
1126 % elif comment_obj.is_inline:
1127 <i class="tooltip icon-code" title="Inline"></i>
1128 % else:
1129 <i class="tooltip icon-comment" title="General"></i>
1130 % endif
1131 ${comment_obj.comment_id}
1132 </a>
1133 </td>
1134 <td class="td-todo-gravatar">
1135 ${base.gravatar(comment_obj.author.email, 16, user=comment_obj.author, tooltip=True, extra_class=['no-margin'])}
1136 </td>
1137 <td class="todo-comment-text-wrapper">
1138 <div class="todo-comment-text">
1139 <code>${h.chop_at_smart(comment_obj.text, '\n', suffix_if_chopped='...')}</code>
1140 </div>
1141 </td>
1142 </tr>
1143 % endfor
1144
1145 </table>
1146 </div>
1147
1148 </div>
1149 </div>
1150
1151 </div>
1152 </aside>
1153
1154
1155 <script>
1156 var $sideBar = $('.right-sidebar');
1157 var marginExpanded = {'margin': '0 320px 0 0'};
1158 var marginCollapsed = {'margin': '0 50px 0 0'};
1159
1160 if($sideBar.hasClass('right-sidebar-expanded')) {
1161 $('.outerwrapper').css(marginExpanded);
1162 $('.sidebar-toggle a').html('<i class="icon-right" style="margin-right: -10px"></i><i class="icon-right"></i>');
1163 $('.right-sidebar-collapsed-state').hide();
1164 $('.right-sidebar-expanded-state').show();
1165 updateSticky()
1166
1167 } else {
1168 $('.outerwrapper').css(marginCollapsed);
1169 $('.sidebar-toggle a').html('<i class="icon-left" style="margin-right: -10px"></i><i class="icon-left"></i>');
1170 $('.right-sidebar-collapsed-state').hide();
1171 $('.right-sidebar-expanded-state').show();
1172 updateSticky()
1173 }
1174
1175 var toggleSidebar = function(){
1176 var $sideBar = $('.right-sidebar');
1177
1178 if($sideBar.hasClass('right-sidebar-expanded')) {
1179 // collapse now
1180 $sideBar.removeClass('right-sidebar-expanded')
1181 $sideBar.addClass('right-sidebar-collapsed')
1182 $('.outerwrapper').css(marginCollapsed);
1183 $('.sidebar-toggle a').html('<i class="icon-left" style="margin-right: -10px"></i><i class="icon-left"></i>');
1184 $('.right-sidebar-collapsed-state').show();
1185 $('.right-sidebar-expanded-state').hide();
1186
1187 } else {
1188 // expand now
1189 $('.outerwrapper').css(marginExpanded);
1190 $sideBar.addClass('right-sidebar-expanded')
1191 $sideBar.removeClass('right-sidebar-collapsed')
1192 $('.sidebar-toggle a').html('<i class="icon-right" style="margin-right: -10px"></i><i class="icon-right"></i>');
1193 $('.right-sidebar-collapsed-state').hide();
1194 $('.right-sidebar-expanded-state').show();
1195 }
1196
1197 // update our other sticky header in same context
1198 updateSticky()
1199 }
1200
1201 var sidebarElement = document.getElementById('pr-nav-sticky');
1202
1203 ## sidebar = new StickySidebar(sidebarElement, {
1204 ## containerSelector: '.main',
1205 ## minWidth: 62,
1206 ## innerWrapperSelector: '.navbar__inner',
1207 ## stickyClass: 'is-sticky',
1208 ## });
1209
1210 </script>
921 1211 </%def>
@@ -948,8 +948,8 b' def assert_inline_comments(pull_request,'
948 948 if visible is not None:
949 949 inline_comments = CommentsModel().get_inline_comments(
950 950 pull_request.target_repo.repo_id, pull_request=pull_request)
951 inline_cnt = CommentsModel().get_inline_comments_count(
952 inline_comments)
951 inline_cnt = len(CommentsModel().get_inline_comments_as_list(
952 inline_comments))
953 953 assert inline_cnt == visible
954 954 if outdated is not None:
955 955 outdated_comments = CommentsModel().get_outdated_comments(
General Comments 0
You need to be logged in to leave comments. Login now