##// END OF EJS Templates
comments: introduce new draft comments....
milka -
r4540:25406ecd default
parent child Browse files
Show More
@@ -0,0 +1,53 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.ChangesetComment.__table__
30 with op.batch_alter_table(table.name) as batch_op:
31 new_column = Column('draft', Boolean(), nullable=True)
32 batch_op.add_column(new_column)
33
34 _set_default_as_non_draft(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 _set_default_as_non_draft(op, session):
47 params = {'draft': False}
48 query = text(
49 'UPDATE changeset_comments SET draft = :draft'
50 ).bindparams(**params)
51 op.execute(query)
52 session().commit()
53
@@ -48,7 +48,7 b' PYRAMID_SETTINGS = {}'
48 EXTENSIONS = {}
48 EXTENSIONS = {}
49
49
50 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
50 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
51 __dbversion__ = 110 # defines current db version for migrations
51 __dbversion__ = 111 # defines current db version for migrations
52 __platform__ = platform.system()
52 __platform__ = platform.system()
53 __license__ = 'AGPLv3, and Commercial License'
53 __license__ = 'AGPLv3, and Commercial License'
54 __author__ = 'RhodeCode GmbH'
54 __author__ = 'RhodeCode GmbH'
@@ -47,7 +47,7 b' from rhodecode.lib.vcs.exceptions import'
47 from rhodecode.model.changeset_status import ChangesetStatusModel
47 from rhodecode.model.changeset_status import ChangesetStatusModel
48 from rhodecode.model.comment import CommentsModel
48 from rhodecode.model.comment import CommentsModel
49 from rhodecode.model.db import (
49 from rhodecode.model.db import (
50 func, or_, PullRequest, ChangesetComment, ChangesetStatus, Repository,
50 func, false, or_, PullRequest, ChangesetComment, ChangesetStatus, Repository,
51 PullRequestReviewers)
51 PullRequestReviewers)
52 from rhodecode.model.forms import PullRequestForm
52 from rhodecode.model.forms import PullRequestForm
53 from rhodecode.model.meta import Session
53 from rhodecode.model.meta import Session
@@ -268,12 +268,14 b' class RepoPullRequestsView(RepoAppView, '
268
268
269 return diffset
269 return diffset
270
270
271 def register_comments_vars(self, c, pull_request, versions):
271 def register_comments_vars(self, c, pull_request, versions, include_drafts=True):
272 comments_model = CommentsModel()
272 comments_model = CommentsModel()
273
273
274 # GENERAL COMMENTS with versions #
274 # GENERAL COMMENTS with versions #
275 q = comments_model._all_general_comments_of_pull_request(pull_request)
275 q = comments_model._all_general_comments_of_pull_request(pull_request)
276 q = q.order_by(ChangesetComment.comment_id.asc())
276 q = q.order_by(ChangesetComment.comment_id.asc())
277 if not include_drafts:
278 q = q.filter(ChangesetComment.draft == false())
277 general_comments = q
279 general_comments = q
278
280
279 # pick comments we want to render at current version
281 # pick comments we want to render at current version
@@ -283,6 +285,8 b' class RepoPullRequestsView(RepoAppView, '
283 # INLINE COMMENTS with versions #
285 # INLINE COMMENTS with versions #
284 q = comments_model._all_inline_comments_of_pull_request(pull_request)
286 q = comments_model._all_inline_comments_of_pull_request(pull_request)
285 q = q.order_by(ChangesetComment.comment_id.asc())
287 q = q.order_by(ChangesetComment.comment_id.asc())
288 if not include_drafts:
289 q = q.filter(ChangesetComment.draft == false())
286 inline_comments = q
290 inline_comments = q
287
291
288 c.inline_versions = comments_model.aggregate_comments(
292 c.inline_versions = comments_model.aggregate_comments(
@@ -1015,7 +1019,7 b' class RepoPullRequestsView(RepoAppView, '
1015 if at_version and at_version != PullRequest.LATEST_VER
1019 if at_version and at_version != PullRequest.LATEST_VER
1016 else None)
1020 else None)
1017
1021
1018 self.register_comments_vars(c, pull_request_latest, versions)
1022 self.register_comments_vars(c, pull_request_latest, versions, include_drafts=False)
1019 all_comments = c.inline_comments_flat + c.comments
1023 all_comments = c.inline_comments_flat + c.comments
1020
1024
1021 existing_ids = self._get_existing_ids(self.request.POST)
1025 existing_ids = self._get_existing_ids(self.request.POST)
@@ -1055,9 +1059,9 b' class RepoPullRequestsView(RepoAppView, '
1055 else None)
1059 else None)
1056
1060
1057 c.unresolved_comments = CommentsModel() \
1061 c.unresolved_comments = CommentsModel() \
1058 .get_pull_request_unresolved_todos(pull_request)
1062 .get_pull_request_unresolved_todos(pull_request, include_drafts=False)
1059 c.resolved_comments = CommentsModel() \
1063 c.resolved_comments = CommentsModel() \
1060 .get_pull_request_resolved_todos(pull_request)
1064 .get_pull_request_resolved_todos(pull_request, include_drafts=False)
1061
1065
1062 all_comments = c.unresolved_comments + c.resolved_comments
1066 all_comments = c.unresolved_comments + c.resolved_comments
1063 existing_ids = self._get_existing_ids(self.request.POST)
1067 existing_ids = self._get_existing_ids(self.request.POST)
@@ -1544,6 +1548,7 b' class RepoPullRequestsView(RepoAppView, '
1544 status = self.request.POST.get('changeset_status', None)
1548 status = self.request.POST.get('changeset_status', None)
1545 text = self.request.POST.get('text')
1549 text = self.request.POST.get('text')
1546 comment_type = self.request.POST.get('comment_type')
1550 comment_type = self.request.POST.get('comment_type')
1551 is_draft = str2bool(self.request.POST.get('draft'))
1547 resolves_comment_id = self.request.POST.get('resolves_comment_id', None)
1552 resolves_comment_id = self.request.POST.get('resolves_comment_id', None)
1548 close_pull_request = self.request.POST.get('close_pull_request')
1553 close_pull_request = self.request.POST.get('close_pull_request')
1549
1554
@@ -1574,9 +1579,9 b' class RepoPullRequestsView(RepoAppView, '
1574 else:
1579 else:
1575 # regular comment case, could be inline, or one with status.
1580 # regular comment case, could be inline, or one with status.
1576 # for that one we check also permissions
1581 # for that one we check also permissions
1577
1582 # Additionally ENSURE if somehow draft is sent we're then unable to change status
1578 allowed_to_change_status = PullRequestModel().check_user_change_status(
1583 allowed_to_change_status = PullRequestModel().check_user_change_status(
1579 pull_request, self._rhodecode_user)
1584 pull_request, self._rhodecode_user) and not is_draft
1580
1585
1581 if status and allowed_to_change_status:
1586 if status and allowed_to_change_status:
1582 message = (_('Status change %(transition_icon)s %(status)s')
1587 message = (_('Status change %(transition_icon)s %(status)s')
@@ -1596,8 +1601,10 b' class RepoPullRequestsView(RepoAppView, '
1596 status_change_type=(status
1601 status_change_type=(status
1597 if status and allowed_to_change_status else None),
1602 if status and allowed_to_change_status else None),
1598 comment_type=comment_type,
1603 comment_type=comment_type,
1604 is_draft=is_draft,
1599 resolves_comment_id=resolves_comment_id,
1605 resolves_comment_id=resolves_comment_id,
1600 auth_user=self._rhodecode_user
1606 auth_user=self._rhodecode_user,
1607 send_email=not is_draft, # skip notification for draft comments
1601 )
1608 )
1602 is_inline = comment.is_inline
1609 is_inline = comment.is_inline
1603
1610
@@ -1638,6 +1645,7 b' class RepoPullRequestsView(RepoAppView, '
1638 'target_id': h.safeid(h.safe_unicode(
1645 'target_id': h.safeid(h.safe_unicode(
1639 self.request.POST.get('f_path'))),
1646 self.request.POST.get('f_path'))),
1640 }
1647 }
1648
1641 if comment:
1649 if comment:
1642 c.co = comment
1650 c.co = comment
1643 c.at_version_num = None
1651 c.at_version_num = None
@@ -1648,15 +1656,17 b' class RepoPullRequestsView(RepoAppView, '
1648 data.update(comment.get_dict())
1656 data.update(comment.get_dict())
1649 data.update({'rendered_text': rendered_comment})
1657 data.update({'rendered_text': rendered_comment})
1650
1658
1651 comment_broadcast_channel = channelstream.comment_channel(
1659 # skip channelstream for draft comments
1652 self.db_repo_name, pull_request_obj=pull_request)
1660 if not is_draft:
1661 comment_broadcast_channel = channelstream.comment_channel(
1662 self.db_repo_name, pull_request_obj=pull_request)
1653
1663
1654 comment_data = data
1664 comment_data = data
1655 comment_type = 'inline' if is_inline else 'general'
1665 comment_type = 'inline' if is_inline else 'general'
1656 channelstream.comment_channelstream_push(
1666 channelstream.comment_channelstream_push(
1657 self.request, comment_broadcast_channel, self._rhodecode_user,
1667 self.request, comment_broadcast_channel, self._rhodecode_user,
1658 _('posted a new {} comment').format(comment_type),
1668 _('posted a new {} comment').format(comment_type),
1659 comment_data=comment_data)
1669 comment_data=comment_data)
1660
1670
1661 return data
1671 return data
1662
1672
@@ -37,6 +37,7 b' from rhodecode.lib.exceptions import Com'
37 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str, safe_int
37 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str, safe_int
38 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
39 from rhodecode.model.db import (
39 from rhodecode.model.db import (
40 false,
40 ChangesetComment,
41 ChangesetComment,
41 User,
42 User,
42 Notification,
43 Notification,
@@ -160,7 +161,7 b' class CommentsModel(BaseModel):'
160
161
161 return todos
162 return todos
162
163
163 def get_pull_request_unresolved_todos(self, pull_request, show_outdated=True):
164 def get_pull_request_unresolved_todos(self, pull_request, show_outdated=True, include_drafts=True):
164
165
165 todos = Session().query(ChangesetComment) \
166 todos = Session().query(ChangesetComment) \
166 .filter(ChangesetComment.pull_request == pull_request) \
167 .filter(ChangesetComment.pull_request == pull_request) \
@@ -168,6 +169,9 b' class CommentsModel(BaseModel):'
168 .filter(ChangesetComment.comment_type
169 .filter(ChangesetComment.comment_type
169 == ChangesetComment.COMMENT_TYPE_TODO)
170 == ChangesetComment.COMMENT_TYPE_TODO)
170
171
172 if not include_drafts:
173 todos = todos.filter(ChangesetComment.draft == false())
174
171 if not show_outdated:
175 if not show_outdated:
172 todos = todos.filter(
176 todos = todos.filter(
173 coalesce(ChangesetComment.display_state, '') !=
177 coalesce(ChangesetComment.display_state, '') !=
@@ -177,7 +181,7 b' class CommentsModel(BaseModel):'
177
181
178 return todos
182 return todos
179
183
180 def get_pull_request_resolved_todos(self, pull_request, show_outdated=True):
184 def get_pull_request_resolved_todos(self, pull_request, show_outdated=True, include_drafts=True):
181
185
182 todos = Session().query(ChangesetComment) \
186 todos = Session().query(ChangesetComment) \
183 .filter(ChangesetComment.pull_request == pull_request) \
187 .filter(ChangesetComment.pull_request == pull_request) \
@@ -185,6 +189,9 b' class CommentsModel(BaseModel):'
185 .filter(ChangesetComment.comment_type
189 .filter(ChangesetComment.comment_type
186 == ChangesetComment.COMMENT_TYPE_TODO)
190 == ChangesetComment.COMMENT_TYPE_TODO)
187
191
192 if not include_drafts:
193 todos = todos.filter(ChangesetComment.draft == false())
194
188 if not show_outdated:
195 if not show_outdated:
189 todos = todos.filter(
196 todos = todos.filter(
190 coalesce(ChangesetComment.display_state, '') !=
197 coalesce(ChangesetComment.display_state, '') !=
@@ -194,7 +201,7 b' class CommentsModel(BaseModel):'
194
201
195 return todos
202 return todos
196
203
197 def get_commit_unresolved_todos(self, commit_id, show_outdated=True):
204 def get_commit_unresolved_todos(self, commit_id, show_outdated=True, include_drafts=True):
198
205
199 todos = Session().query(ChangesetComment) \
206 todos = Session().query(ChangesetComment) \
200 .filter(ChangesetComment.revision == commit_id) \
207 .filter(ChangesetComment.revision == commit_id) \
@@ -202,6 +209,9 b' class CommentsModel(BaseModel):'
202 .filter(ChangesetComment.comment_type
209 .filter(ChangesetComment.comment_type
203 == ChangesetComment.COMMENT_TYPE_TODO)
210 == ChangesetComment.COMMENT_TYPE_TODO)
204
211
212 if not include_drafts:
213 todos = todos.filter(ChangesetComment.draft == false())
214
205 if not show_outdated:
215 if not show_outdated:
206 todos = todos.filter(
216 todos = todos.filter(
207 coalesce(ChangesetComment.display_state, '') !=
217 coalesce(ChangesetComment.display_state, '') !=
@@ -211,7 +221,7 b' class CommentsModel(BaseModel):'
211
221
212 return todos
222 return todos
213
223
214 def get_commit_resolved_todos(self, commit_id, show_outdated=True):
224 def get_commit_resolved_todos(self, commit_id, show_outdated=True, include_drafts=True):
215
225
216 todos = Session().query(ChangesetComment) \
226 todos = Session().query(ChangesetComment) \
217 .filter(ChangesetComment.revision == commit_id) \
227 .filter(ChangesetComment.revision == commit_id) \
@@ -219,6 +229,9 b' class CommentsModel(BaseModel):'
219 .filter(ChangesetComment.comment_type
229 .filter(ChangesetComment.comment_type
220 == ChangesetComment.COMMENT_TYPE_TODO)
230 == ChangesetComment.COMMENT_TYPE_TODO)
221
231
232 if not include_drafts:
233 todos = todos.filter(ChangesetComment.draft == false())
234
222 if not show_outdated:
235 if not show_outdated:
223 todos = todos.filter(
236 todos = todos.filter(
224 coalesce(ChangesetComment.display_state, '') !=
237 coalesce(ChangesetComment.display_state, '') !=
@@ -228,11 +241,15 b' class CommentsModel(BaseModel):'
228
241
229 return todos
242 return todos
230
243
231 def get_commit_inline_comments(self, commit_id):
244 def get_commit_inline_comments(self, commit_id, include_drafts=True):
232 inline_comments = Session().query(ChangesetComment) \
245 inline_comments = Session().query(ChangesetComment) \
233 .filter(ChangesetComment.line_no != None) \
246 .filter(ChangesetComment.line_no != None) \
234 .filter(ChangesetComment.f_path != None) \
247 .filter(ChangesetComment.f_path != None) \
235 .filter(ChangesetComment.revision == commit_id)
248 .filter(ChangesetComment.revision == commit_id)
249
250 if not include_drafts:
251 inline_comments = inline_comments.filter(ChangesetComment.draft == false())
252
236 inline_comments = inline_comments.all()
253 inline_comments = inline_comments.all()
237 return inline_comments
254 return inline_comments
238
255
@@ -245,7 +262,7 b' class CommentsModel(BaseModel):'
245
262
246 def create(self, text, repo, user, commit_id=None, pull_request=None,
263 def create(self, text, repo, user, commit_id=None, pull_request=None,
247 f_path=None, line_no=None, status_change=None,
264 f_path=None, line_no=None, status_change=None,
248 status_change_type=None, comment_type=None,
265 status_change_type=None, comment_type=None, is_draft=False,
249 resolves_comment_id=None, closing_pr=False, send_email=True,
266 resolves_comment_id=None, closing_pr=False, send_email=True,
250 renderer=None, auth_user=None, extra_recipients=None):
267 renderer=None, auth_user=None, extra_recipients=None):
251 """
268 """
@@ -262,6 +279,7 b' class CommentsModel(BaseModel):'
262 :param line_no:
279 :param line_no:
263 :param status_change: Label for status change
280 :param status_change: Label for status change
264 :param comment_type: Type of comment
281 :param comment_type: Type of comment
282 :param is_draft: is comment a draft only
265 :param resolves_comment_id: id of comment which this one will resolve
283 :param resolves_comment_id: id of comment which this one will resolve
266 :param status_change_type: type of status change
284 :param status_change_type: type of status change
267 :param closing_pr:
285 :param closing_pr:
@@ -288,6 +306,7 b' class CommentsModel(BaseModel):'
288 validated_kwargs = schema.deserialize(dict(
306 validated_kwargs = schema.deserialize(dict(
289 comment_body=text,
307 comment_body=text,
290 comment_type=comment_type,
308 comment_type=comment_type,
309 is_draft=is_draft,
291 comment_file=f_path,
310 comment_file=f_path,
292 comment_line=line_no,
311 comment_line=line_no,
293 renderer_type=renderer,
312 renderer_type=renderer,
@@ -296,6 +315,7 b' class CommentsModel(BaseModel):'
296 repo=repo.repo_id,
315 repo=repo.repo_id,
297 user=user.user_id,
316 user=user.user_id,
298 ))
317 ))
318 is_draft = validated_kwargs['is_draft']
299
319
300 comment = ChangesetComment()
320 comment = ChangesetComment()
301 comment.renderer = validated_kwargs['renderer_type']
321 comment.renderer = validated_kwargs['renderer_type']
@@ -303,6 +323,7 b' class CommentsModel(BaseModel):'
303 comment.f_path = validated_kwargs['comment_file']
323 comment.f_path = validated_kwargs['comment_file']
304 comment.line_no = validated_kwargs['comment_line']
324 comment.line_no = validated_kwargs['comment_line']
305 comment.comment_type = validated_kwargs['comment_type']
325 comment.comment_type = validated_kwargs['comment_type']
326 comment.draft = is_draft
306
327
307 comment.repo = repo
328 comment.repo = repo
308 comment.author = user
329 comment.author = user
@@ -462,10 +483,11 b' class CommentsModel(BaseModel):'
462 else:
483 else:
463 action = 'repo.commit.comment.create'
484 action = 'repo.commit.comment.create'
464
485
465 comment_data = comment.get_api_data()
486 if not is_draft:
487 comment_data = comment.get_api_data()
466
488
467 self._log_audit_action(
489 self._log_audit_action(
468 action, {'data': comment_data}, auth_user, comment)
490 action, {'data': comment_data}, auth_user, comment)
469
491
470 return comment
492 return comment
471
493
@@ -3767,6 +3767,7 b' class ChangesetComment(Base, BaseModel):'
3767 renderer = Column('renderer', Unicode(64), nullable=True)
3767 renderer = Column('renderer', Unicode(64), nullable=True)
3768 display_state = Column('display_state', Unicode(128), nullable=True)
3768 display_state = Column('display_state', Unicode(128), nullable=True)
3769 immutable_state = Column('immutable_state', Unicode(128), nullable=True, default=OP_CHANGEABLE)
3769 immutable_state = Column('immutable_state', Unicode(128), nullable=True, default=OP_CHANGEABLE)
3770 draft = Column('draft', Boolean(), nullable=True, default=False)
3770
3771
3771 comment_type = Column('comment_type', Unicode(128), nullable=True, default=COMMENT_TYPE_NOTE)
3772 comment_type = Column('comment_type', Unicode(128), nullable=True, default=COMMENT_TYPE_NOTE)
3772 resolved_comment_id = Column('resolved_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'), nullable=True)
3773 resolved_comment_id = Column('resolved_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'), nullable=True)
@@ -60,7 +60,7 b' class CommentSchema(colander.MappingSche'
60 colander.String(),
60 colander.String(),
61 validator=colander.OneOf(ChangesetComment.COMMENT_TYPES),
61 validator=colander.OneOf(ChangesetComment.COMMENT_TYPES),
62 missing=ChangesetComment.COMMENT_TYPE_NOTE)
62 missing=ChangesetComment.COMMENT_TYPE_NOTE)
63
63 is_draft = colander.SchemaNode(colander.Boolean(),missing=False)
64 comment_file = colander.SchemaNode(colander.String(), missing=None)
64 comment_file = colander.SchemaNode(colander.String(), missing=None)
65 comment_line = colander.SchemaNode(colander.String(), missing=None)
65 comment_line = colander.SchemaNode(colander.String(), missing=None)
66 status_change = colander.SchemaNode(
66 status_change = colander.SchemaNode(
@@ -162,7 +162,6 b' input[type="button"] {'
162 }
162 }
163 }
163 }
164
164
165 .btn-warning,
166 .btn-danger,
165 .btn-danger,
167 .revoke_perm,
166 .revoke_perm,
168 .btn-x,
167 .btn-x,
@@ -196,6 +195,36 b' input[type="button"] {'
196 }
195 }
197 }
196 }
198
197
198 .btn-warning {
199 .border ( @border-thickness, @alert3 );
200 background-color: white;
201 color: @alert3;
202
203 a {
204 color: @alert3;
205 }
206
207 &:hover,
208 &.active {
209 .border ( @border-thickness, @alert3 );
210 color: white;
211 background-color: @alert3;
212
213 a {
214 color: white;
215 }
216 }
217
218 i {
219 display:none;
220 }
221
222 &:disabled {
223 background-color: white;
224 color: @alert3;
225 }
226 }
227
199 .btn-approved-status {
228 .btn-approved-status {
200 .border ( @border-thickness, @alert1 );
229 .border ( @border-thickness, @alert1 );
201 background-color: white;
230 background-color: white;
@@ -401,6 +430,37 b' input[type="button"] {'
401 }
430 }
402
431
403
432
433 input[type="submit"].btn-warning {
434 &:extend(.btn-warning);
435
436 &:focus {
437 outline: 0;
438 }
439
440 &:hover {
441 &:extend(.btn-warning:hover);
442 }
443
444 &.btn-link {
445 &:extend(.btn-link);
446 color: @alert3;
447
448 &:disabled {
449 color: @alert3;
450 background-color: transparent;
451 }
452 }
453
454 &:disabled {
455 .border ( @border-thickness-buttons, @alert3 );
456 background-color: white;
457 color: @alert3;
458 opacity: 0.5;
459 }
460 }
461
462
463
404 // TODO: johbo: Form button tweaks, check if we can use the classes instead
464 // TODO: johbo: Form button tweaks, check if we can use the classes instead
405 input[type="submit"] {
465 input[type="submit"] {
406 &:extend(.btn-primary);
466 &:extend(.btn-primary);
@@ -61,6 +61,13 b' tr.inline-comments div {'
61 visibility: hidden;
61 visibility: hidden;
62 }
62 }
63
63
64 .comment-draft {
65 float: left;
66 margin-right: 10px;
67 font-weight: 600;
68 color: @alert3;
69 }
70
64 .comment-label {
71 .comment-label {
65 float: left;
72 float: left;
66
73
@@ -349,7 +349,12 b' var initCommentBoxCodeMirror = function('
349 };
349 };
350
350
351 var submitForm = function(cm, pred) {
351 var submitForm = function(cm, pred) {
352 $(cm.display.input.textarea.form).submit();
352 $(cm.display.input.textarea.form).find('.submit-comment-action').click();
353 return CodeMirror.Pass;
354 };
355
356 var submitFormAsDraft = function(cm, pred) {
357 $(cm.display.input.textarea.form).find('.submit-draft-action').click();
353 return CodeMirror.Pass;
358 return CodeMirror.Pass;
354 };
359 };
355
360
@@ -475,9 +480,11 b' var initCommentBoxCodeMirror = function('
475 // submit form on Meta-Enter
480 // submit form on Meta-Enter
476 if (OSType === "mac") {
481 if (OSType === "mac") {
477 extraKeys["Cmd-Enter"] = submitForm;
482 extraKeys["Cmd-Enter"] = submitForm;
483 extraKeys["Shift-Cmd-Enter"] = submitFormAsDraft;
478 }
484 }
479 else {
485 else {
480 extraKeys["Ctrl-Enter"] = submitForm;
486 extraKeys["Ctrl-Enter"] = submitForm;
487 extraKeys["Shift-Ctrl-Enter"] = submitFormAsDraft;
481 }
488 }
482
489
483 if (triggerActions) {
490 if (triggerActions) {
@@ -124,16 +124,20 b' var _submitAjaxPOST = function(url, post'
124 this.statusChange = this.withLineNo('#change_status');
124 this.statusChange = this.withLineNo('#change_status');
125
125
126 this.submitForm = formElement;
126 this.submitForm = formElement;
127 this.submitButton = $(this.submitForm).find('input[type="submit"]');
127
128 this.submitButton = $(this.submitForm).find('.submit-comment-action');
128 this.submitButtonText = this.submitButton.val();
129 this.submitButtonText = this.submitButton.val();
129
130
131 this.submitDraftButton = $(this.submitForm).find('.submit-draft-action');
132 this.submitDraftButtonText = this.submitDraftButton.val();
130
133
131 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
134 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
132 {'repo_name': templateContext.repo_name,
135 {'repo_name': templateContext.repo_name,
133 'commit_id': templateContext.commit_data.commit_id});
136 'commit_id': templateContext.commit_data.commit_id});
134
137
135 if (edit){
138 if (edit){
136 this.submitButtonText = _gettext('Updated Comment');
139 this.submitDraftButton.hide();
140 this.submitButtonText = _gettext('Update Comment');
137 $(this.commentType).prop('disabled', true);
141 $(this.commentType).prop('disabled', true);
138 $(this.commentType).addClass('disabled');
142 $(this.commentType).addClass('disabled');
139 var editInfo =
143 var editInfo =
@@ -215,10 +219,17 b' var _submitAjaxPOST = function(url, post'
215 this.getCommentStatus = function() {
219 this.getCommentStatus = function() {
216 return $(this.submitForm).find(this.statusChange).val();
220 return $(this.submitForm).find(this.statusChange).val();
217 };
221 };
222
218 this.getCommentType = function() {
223 this.getCommentType = function() {
219 return $(this.submitForm).find(this.commentType).val();
224 return $(this.submitForm).find(this.commentType).val();
220 };
225 };
221
226
227 this.getDraftState = function () {
228 var submitterElem = $(this.submitForm).find('input[type="submit"].submitter');
229 var data = $(submitterElem).data('isDraft');
230 return data
231 }
232
222 this.getResolvesId = function() {
233 this.getResolvesId = function() {
223 return $(this.submitForm).find(this.resolvesId).val() || null;
234 return $(this.submitForm).find(this.resolvesId).val() || null;
224 };
235 };
@@ -233,7 +244,9 b' var _submitAjaxPOST = function(url, post'
233 };
244 };
234
245
235 this.isAllowedToSubmit = function() {
246 this.isAllowedToSubmit = function() {
236 return !$(this.submitButton).prop('disabled');
247 var commentDisabled = $(this.submitButton).prop('disabled');
248 var draftDisabled = $(this.submitDraftButton).prop('disabled');
249 return !commentDisabled && !draftDisabled;
237 };
250 };
238
251
239 this.initStatusChangeSelector = function(){
252 this.initStatusChangeSelector = function(){
@@ -259,11 +272,13 b' var _submitAjaxPOST = function(url, post'
259 dropdownAutoWidth: true,
272 dropdownAutoWidth: true,
260 minimumResultsForSearch: -1
273 minimumResultsForSearch: -1
261 });
274 });
275
262 $(this.submitForm).find(this.statusChange).on('change', function() {
276 $(this.submitForm).find(this.statusChange).on('change', function() {
263 var status = self.getCommentStatus();
277 var status = self.getCommentStatus();
264
278
265 if (status && !self.isInline()) {
279 if (status && !self.isInline()) {
266 $(self.submitButton).prop('disabled', false);
280 $(self.submitButton).prop('disabled', false);
281 $(self.submitDraftButton).prop('disabled', false);
267 }
282 }
268
283
269 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
284 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
@@ -295,10 +310,10 b' var _submitAjaxPOST = function(url, post'
295 $(this.statusChange).select2('readonly', false);
310 $(this.statusChange).select2('readonly', false);
296 };
311 };
297
312
298 this.globalSubmitSuccessCallback = function(){
313 this.globalSubmitSuccessCallback = function(comment){
299 // default behaviour is to call GLOBAL hook, if it's registered.
314 // default behaviour is to call GLOBAL hook, if it's registered.
300 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
315 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
301 commentFormGlobalSubmitSuccessCallback();
316 commentFormGlobalSubmitSuccessCallback(comment);
302 }
317 }
303 };
318 };
304
319
@@ -321,6 +336,7 b' var _submitAjaxPOST = function(url, post'
321 var text = self.cm.getValue();
336 var text = self.cm.getValue();
322 var status = self.getCommentStatus();
337 var status = self.getCommentStatus();
323 var commentType = self.getCommentType();
338 var commentType = self.getCommentType();
339 var isDraft = self.getDraftState();
324 var resolvesCommentId = self.getResolvesId();
340 var resolvesCommentId = self.getResolvesId();
325 var closePullRequest = self.getClosePr();
341 var closePullRequest = self.getClosePr();
326
342
@@ -365,7 +381,7 b' var _submitAjaxPOST = function(url, post'
365 }
381 }
366
382
367 // run global callback on submit
383 // run global callback on submit
368 self.globalSubmitSuccessCallback();
384 self.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
369
385
370 };
386 };
371 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
387 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
@@ -409,10 +425,20 b' var _submitAjaxPOST = function(url, post'
409 }
425 }
410
426
411 $(this.submitButton).prop('disabled', submitState);
427 $(this.submitButton).prop('disabled', submitState);
428 $(this.submitDraftButton).prop('disabled', submitState);
429
412 if (submitEvent) {
430 if (submitEvent) {
413 $(this.submitButton).val(_gettext('Submitting...'));
431 var isDraft = self.getDraftState();
432
433 if (isDraft) {
434 $(this.submitDraftButton).val(_gettext('Saving Draft...'));
435 } else {
436 $(this.submitButton).val(_gettext('Submitting...'));
437 }
438
414 } else {
439 } else {
415 $(this.submitButton).val(this.submitButtonText);
440 $(this.submitButton).val(this.submitButtonText);
441 $(this.submitDraftButton).val(this.submitDraftButtonText);
416 }
442 }
417
443
418 };
444 };
@@ -488,6 +514,7 b' var _submitAjaxPOST = function(url, post'
488 if (!allowedToSubmit){
514 if (!allowedToSubmit){
489 return false;
515 return false;
490 }
516 }
517
491 self.handleFormSubmit();
518 self.handleFormSubmit();
492 });
519 });
493
520
@@ -659,7 +686,8 b' var CommentsController = function() {'
659 var $node = $(node);
686 var $node = $(node);
660 var $td = $node.closest('td');
687 var $td = $node.closest('td');
661 var $comment = $node.closest('.comment');
688 var $comment = $node.closest('.comment');
662 var comment_id = $comment.attr('data-comment-id');
689 var comment_id = $($comment).data('commentId');
690 var isDraft = $($comment).data('commentDraft');
663 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
691 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
664 var postData = {
692 var postData = {
665 'csrf_token': CSRF_TOKEN
693 'csrf_token': CSRF_TOKEN
@@ -677,7 +705,7 b' var CommentsController = function() {'
677 updateSticky()
705 updateSticky()
678 }
706 }
679
707
680 if (window.refreshAllComments !== undefined) {
708 if (window.refreshAllComments !== undefined && !isDraft) {
681 // if we have this handler, run it, and refresh all comments boxes
709 // if we have this handler, run it, and refresh all comments boxes
682 refreshAllComments()
710 refreshAllComments()
683 }
711 }
@@ -716,6 +744,25 b' var CommentsController = function() {'
716 })
744 })
717 };
745 };
718
746
747 this._finalizeDrafts = function(commentIds) {
748 window.finalizeDrafts(commentIds)
749 }
750
751 this.finalizeDrafts = function(commentIds) {
752
753 SwalNoAnimation.fire({
754 title: _ngettext('Submit {0} draft comment', 'Submit {0} draft comments', commentIds.length).format(commentIds.length),
755 icon: 'warning',
756 showCancelButton: true,
757 confirmButtonText: _gettext('Yes, finalize drafts'),
758
759 }).then(function(result) {
760 if (result.value) {
761 self._finalizeDrafts(commentIds);
762 }
763 })
764 };
765
719 this.toggleWideMode = function (node) {
766 this.toggleWideMode = function (node) {
720 if ($('#content').hasClass('wrapper')) {
767 if ($('#content').hasClass('wrapper')) {
721 $('#content').removeClass("wrapper");
768 $('#content').removeClass("wrapper");
@@ -916,7 +963,8 b' var CommentsController = function() {'
916 this.editComment = function(node) {
963 this.editComment = function(node) {
917 var $node = $(node);
964 var $node = $(node);
918 var $comment = $(node).closest('.comment');
965 var $comment = $(node).closest('.comment');
919 var comment_id = $comment.attr('data-comment-id');
966 var comment_id = $($comment).data('commentId');
967 var isDraft = $($comment).data('commentDraft');
920 var $form = null
968 var $form = null
921
969
922 var $comments = $node.closest('div.inline-comments');
970 var $comments = $node.closest('div.inline-comments');
@@ -1002,6 +1050,7 b' var CommentsController = function() {'
1002 'f_path': f_path,
1050 'f_path': f_path,
1003 'line': lineno,
1051 'line': lineno,
1004 'comment_type': commentType,
1052 'comment_type': commentType,
1053 'draft': isDraft,
1005 'version': version,
1054 'version': version,
1006 'csrf_token': CSRF_TOKEN
1055 'csrf_token': CSRF_TOKEN
1007 };
1056 };
@@ -1084,7 +1133,7 b' var CommentsController = function() {'
1084 $comments.find('.cb-comment-add-button').before(html);
1133 $comments.find('.cb-comment-add-button').before(html);
1085
1134
1086 // run global callback on submit
1135 // run global callback on submit
1087 commentForm.globalSubmitSuccessCallback();
1136 commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
1088
1137
1089 } catch (e) {
1138 } catch (e) {
1090 console.error(e);
1139 console.error(e);
@@ -1101,7 +1150,7 b' var CommentsController = function() {'
1101 updateSticky()
1150 updateSticky()
1102 }
1151 }
1103
1152
1104 if (window.refreshAllComments !== undefined) {
1153 if (window.refreshAllComments !== undefined && !isDraft) {
1105 // if we have this handler, run it, and refresh all comments boxes
1154 // if we have this handler, run it, and refresh all comments boxes
1106 refreshAllComments()
1155 refreshAllComments()
1107 }
1156 }
@@ -1178,6 +1227,7 b' var CommentsController = function() {'
1178 var text = commentForm.cm.getValue();
1227 var text = commentForm.cm.getValue();
1179 var commentType = commentForm.getCommentType();
1228 var commentType = commentForm.getCommentType();
1180 var resolvesCommentId = commentForm.getResolvesId();
1229 var resolvesCommentId = commentForm.getResolvesId();
1230 var isDraft = commentForm.getDraftState();
1181
1231
1182 if (text === "") {
1232 if (text === "") {
1183 return;
1233 return;
@@ -1201,6 +1251,7 b' var CommentsController = function() {'
1201 'f_path': f_path,
1251 'f_path': f_path,
1202 'line': lineno,
1252 'line': lineno,
1203 'comment_type': commentType,
1253 'comment_type': commentType,
1254 'draft': isDraft,
1204 'csrf_token': CSRF_TOKEN
1255 'csrf_token': CSRF_TOKEN
1205 };
1256 };
1206 if (resolvesCommentId){
1257 if (resolvesCommentId){
@@ -1222,7 +1273,7 b' var CommentsController = function() {'
1222 }
1273 }
1223
1274
1224 // run global callback on submit
1275 // run global callback on submit
1225 commentForm.globalSubmitSuccessCallback();
1276 commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
1226
1277
1227 } catch (e) {
1278 } catch (e) {
1228 console.error(e);
1279 console.error(e);
@@ -1239,7 +1290,7 b' var CommentsController = function() {'
1239 updateSticky()
1290 updateSticky()
1240 }
1291 }
1241
1292
1242 if (window.refreshAllComments !== undefined) {
1293 if (window.refreshAllComments !== undefined && !isDraft) {
1243 // if we have this handler, run it, and refresh all comments boxes
1294 // if we have this handler, run it, and refresh all comments boxes
1244 refreshAllComments()
1295 refreshAllComments()
1245 }
1296 }
@@ -1225,6 +1225,14 b''
1225 (function () {
1225 (function () {
1226 "use sctrict";
1226 "use sctrict";
1227
1227
1228 // details block auto-hide menu
1229 $(document).mouseup(function(e) {
1230 var container = $('.details-inline-block');
1231 if (!container.is(e.target) && container.has(e.target).length === 0) {
1232 $('.details-inline-block[open]').removeAttr('open')
1233 }
1234 });
1235
1228 var $sideBar = $('.right-sidebar');
1236 var $sideBar = $('.right-sidebar');
1229 var expanded = $sideBar.hasClass('right-sidebar-expanded');
1237 var expanded = $sideBar.hasClass('right-sidebar-expanded');
1230 var sidebarState = templateContext.session_attrs.sidebarState;
1238 var sidebarState = templateContext.session_attrs.sidebarState;
@@ -31,8 +31,12 b''
31 <%
31 <%
32 display = ''
32 display = ''
33 _cls = ''
33 _cls = ''
34 ## Extra precaution to not show drafts in the sidebar for todo/comments
35 if comment_obj.draft:
36 continue
34 %>
37 %>
35
38
39
36 <%
40 <%
37 comment_ver_index = comment_obj.get_index_version(getattr(c, 'versions', []))
41 comment_ver_index = comment_obj.get_index_version(getattr(c, 'versions', []))
38 prev_comment_ver_index = 0
42 prev_comment_ver_index = 0
@@ -3,20 +3,25 b''
3 ## <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
3 ## <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
4 ## ${comment.comment_block(comment)}
4 ## ${comment.comment_block(comment)}
5 ##
5 ##
6 <%namespace name="base" file="/base/base.mako"/>
6
7
7 <%!
8 <%!
8 from rhodecode.lib import html_filters
9 from rhodecode.lib import html_filters
9 %>
10 %>
10
11
11 <%namespace name="base" file="/base/base.mako"/>
12
12 <%def name="comment_block(comment, inline=False, active_pattern_entries=None)">
13 <%def name="comment_block(comment, inline=False, active_pattern_entries=None)">
13
14
14 <%
15 <%
15 from rhodecode.model.comment import CommentsModel
16 from rhodecode.model.comment import CommentsModel
16 comment_model = CommentsModel()
17 comment_model = CommentsModel()
18
19 comment_ver = comment.get_index_version(getattr(c, 'versions', []))
20 latest_ver = len(getattr(c, 'versions', []))
21 visible_for_user = True
22 if comment.draft:
23 visible_for_user = comment.user_id == c.rhodecode_user.user_id
17 %>
24 %>
18 <% comment_ver = comment.get_index_version(getattr(c, 'versions', [])) %>
19 <% latest_ver = len(getattr(c, 'versions', [])) %>
20
25
21 % if inline:
26 % if inline:
22 <% outdated_at_ver = comment.outdated_at_version(c.at_version_num) %>
27 <% outdated_at_ver = comment.outdated_at_version(c.at_version_num) %>
@@ -24,6 +29,7 b''
24 <% outdated_at_ver = comment.older_than_version(c.at_version_num) %>
29 <% outdated_at_ver = comment.older_than_version(c.at_version_num) %>
25 % endif
30 % endif
26
31
32 % if visible_for_user:
27 <div class="comment
33 <div class="comment
28 ${'comment-inline' if inline else 'comment-general'}
34 ${'comment-inline' if inline else 'comment-general'}
29 ${'comment-outdated' if outdated_at_ver else 'comment-current'}"
35 ${'comment-outdated' if outdated_at_ver else 'comment-current'}"
@@ -31,6 +37,7 b''
31 line="${comment.line_no}"
37 line="${comment.line_no}"
32 data-comment-id="${comment.comment_id}"
38 data-comment-id="${comment.comment_id}"
33 data-comment-type="${comment.comment_type}"
39 data-comment-type="${comment.comment_type}"
40 data-comment-draft=${h.json.dumps(comment.draft)}
34 data-comment-renderer="${comment.renderer}"
41 data-comment-renderer="${comment.renderer}"
35 data-comment-text="${comment.text | html_filters.base64,n}"
42 data-comment-text="${comment.text | html_filters.base64,n}"
36 data-comment-line-no="${comment.line_no}"
43 data-comment-line-no="${comment.line_no}"
@@ -39,6 +46,9 b''
39
46
40 <div class="meta">
47 <div class="meta">
41 <div class="comment-type-label">
48 <div class="comment-type-label">
49 % if comment.draft:
50 <div class="tooltip comment-draft" title="${_('Draft comments are only visible to the author until submitted')}.">DRAFT</div>
51 % endif
42 <div class="comment-label ${comment.comment_type or 'note'}" id="comment-label-${comment.comment_id}">
52 <div class="comment-label ${comment.comment_type or 'note'}" id="comment-label-${comment.comment_id}">
43
53
44 ## TODO COMMENT
54 ## TODO COMMENT
@@ -90,7 +100,7 b''
90
100
91 </div>
101 </div>
92 </div>
102 </div>
93
103 ## NOTE 0 and .. => because we disable it for now until UI ready
94 % if 0 and comment.status_change:
104 % if 0 and comment.status_change:
95 <div class="pull-left">
105 <div class="pull-left">
96 <span class="tag authortag tooltip" title="${_('Status from pull request.')}">
106 <span class="tag authortag tooltip" title="${_('Status from pull request.')}">
@@ -100,10 +110,12 b''
100 </span>
110 </span>
101 </div>
111 </div>
102 % endif
112 % endif
103
113 ## Since only author can see drafts, we don't show it
114 % if not comment.draft:
104 <div class="author ${'author-inline' if inline else 'author-general'}">
115 <div class="author ${'author-inline' if inline else 'author-general'}">
105 ${base.gravatar_with_user(comment.author.email, 16, tooltip=True)}
116 ${base.gravatar_with_user(comment.author.email, 16, tooltip=True)}
106 </div>
117 </div>
118 % endif
107
119
108 <div class="date">
120 <div class="date">
109 ${h.age_component(comment.modified_at, time_is_local=True)}
121 ${h.age_component(comment.modified_at, time_is_local=True)}
@@ -215,6 +227,11 b''
215 <div class="dropdown-item">
227 <div class="dropdown-item">
216 <a onclick="return Rhodecode.comments.deleteComment(this);" class="btn btn-link btn-sm btn-danger delete-comment">${_('Delete')}</a>
228 <a onclick="return Rhodecode.comments.deleteComment(this);" class="btn btn-link btn-sm btn-danger delete-comment">${_('Delete')}</a>
217 </div>
229 </div>
230 % if comment.draft:
231 <div class="dropdown-item">
232 <a onclick="return Rhodecode.comments.finalizeDrafts([${comment.comment_id}]);" class="btn btn-link btn-sm finalize-draft-comment">${_('Submit draft')}</a>
233 </div>
234 % endif
218 %else:
235 %else:
219 <div class="dropdown-divider"></div>
236 <div class="dropdown-divider"></div>
220 <div class="dropdown-item">
237 <div class="dropdown-item">
@@ -252,6 +269,7 b''
252 </div>
269 </div>
253
270
254 </div>
271 </div>
272 % endif
255 </%def>
273 </%def>
256
274
257 ## generate main comments
275 ## generate main comments
@@ -311,6 +329,7 b''
311 var text = self.cm.getValue();
329 var text = self.cm.getValue();
312 var status = self.getCommentStatus();
330 var status = self.getCommentStatus();
313 var commentType = self.getCommentType();
331 var commentType = self.getCommentType();
332 var isDraft = self.getDraftState();
314
333
315 if (text === "" && !status) {
334 if (text === "" && !status) {
316 return;
335 return;
@@ -337,6 +356,7 b''
337 'text': text,
356 'text': text,
338 'changeset_status': status,
357 'changeset_status': status,
339 'comment_type': commentType,
358 'comment_type': commentType,
359 'draft': isDraft,
340 'commit_ids': commitIds,
360 'commit_ids': commitIds,
341 'csrf_token': CSRF_TOKEN
361 'csrf_token': CSRF_TOKEN
342 };
362 };
@@ -477,14 +497,18 b''
477 <div class="action-buttons-extra"></div>
497 <div class="action-buttons-extra"></div>
478 % endif
498 % endif
479
499
480 <input class="btn btn-success comment-button-input" id="save_${lineno_id}" name="save" type="submit" value="${_('Comment')}">
500 <input class="btn btn-success comment-button-input submit-comment-action" id="save_${lineno_id}" name="save" type="submit" value="${_('Add comment')}" data-is-draft=false onclick="$(this).addClass('submitter')">
501
502 % if form_type == 'inline':
503 <input class="btn btn-warning comment-button-input submit-draft-action" id="save_draft_${lineno_id}" name="save_draft" type="submit" value="${_('Add draft')}" data-is-draft=true onclick="$(this).addClass('submitter')">
504 % endif
481
505
482 ## inline for has a file, and line-number together with cancel hide button.
506 ## inline for has a file, and line-number together with cancel hide button.
483 % if form_type == 'inline':
507 % if form_type == 'inline':
484 <input type="hidden" name="f_path" value="{0}">
508 <input type="hidden" name="f_path" value="{0}">
485 <input type="hidden" name="line" value="${lineno_id}">
509 <input type="hidden" name="line" value="${lineno_id}">
486 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
510 <button type="button" class="tooltip cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);" title="Hide comment box">
487 ${_('Cancel')}
511 <i class="icon-cancel-circled2"></i>
488 </button>
512 </button>
489 % endif
513 % endif
490 </div>
514 </div>
@@ -711,16 +711,19 b' def get_comments_for(diff_type, comments'
711 data-line-no="${line.original.lineno}"
711 data-line-no="${line.original.lineno}"
712 >
712 >
713
713
714 <% line_old_comments = None %>
714 <% line_old_comments, line_old_comments_no_drafts = None, None %>
715 %if line.original.get_comment_args:
715 %if line.original.get_comment_args:
716 <% line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args) %>
716 <%
717 line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args)
718 line_old_comments_no_drafts = [c for c in line_old_comments if not c.draft] if line_old_comments else []
719 has_outdated = any([x.outdated for x in line_old_comments_no_drafts])
720 %>
717 %endif
721 %endif
718 %if line_old_comments:
722 %if line_old_comments_no_drafts:
719 <% has_outdated = any([x.outdated for x in line_old_comments]) %>
720 % if has_outdated:
723 % if has_outdated:
721 <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>
724 <i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
722 % else:
725 % else:
723 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_old_comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
726 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
724 % endif
727 % endif
725 %endif
728 %endif
726 </td>
729 </td>
@@ -752,18 +755,20 b' def get_comments_for(diff_type, comments'
752 >
755 >
753 <div>
756 <div>
754
757
758 <% line_new_comments, line_new_comments_no_drafts = None, None %>
755 %if line.modified.get_comment_args:
759 %if line.modified.get_comment_args:
756 <% line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args) %>
760 <%
757 %else:
761 line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args)
758 <% line_new_comments = None%>
762 line_new_comments_no_drafts = [c for c in line_new_comments if not c.draft] if line_new_comments else []
763 has_outdated = any([x.outdated for x in line_new_comments_no_drafts])
764 %>
759 %endif
765 %endif
760 %if line_new_comments:
761
766
762 <% has_outdated = any([x.outdated for x in line_new_comments]) %>
767 %if line_new_comments_no_drafts:
763 % if has_outdated:
768 % if has_outdated:
764 <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>
769 <i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
765 % else:
770 % else:
766 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_new_comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
771 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
767 % endif
772 % endif
768 %endif
773 %endif
769 </div>
774 </div>
@@ -814,20 +819,22 b' def get_comments_for(diff_type, comments'
814 <td class="cb-data ${action_class(action)}">
819 <td class="cb-data ${action_class(action)}">
815 <div>
820 <div>
816
821
817 %if comments_args:
822 <% comments, comments_no_drafts = None, None %>
818 <% comments = get_comments_for('unified', inline_comments, *comments_args) %>
823 %if comments_args:
819 %else:
824 <%
820 <% comments = None %>
825 comments = get_comments_for('unified', inline_comments, *comments_args)
821 %endif
826 comments_no_drafts = [c for c in line_new_comments if not c.draft] if line_new_comments else []
827 has_outdated = any([x.outdated for x in comments_no_drafts])
828 %>
829 %endif
822
830
823 % if comments:
831 % if comments_no_drafts:
824 <% has_outdated = any([x.outdated for x in comments]) %>
832 % if has_outdated:
825 % if has_outdated:
833 <i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
826 <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>
834 % else:
827 % else:
835 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
828 <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
836 % endif
829 % endif
837 % endif
830 % endif
831 </div>
838 </div>
832 </td>
839 </td>
833 <td class="cb-lineno ${action_class(action)}"
840 <td class="cb-lineno ${action_class(action)}"
@@ -980,9 +980,11 b' window.setObserversData = ${c.pull_reque'
980 $(btns).each(fn_display);
980 $(btns).each(fn_display);
981 });
981 });
982
982
983 // register submit callback on commentForm form to track TODOs
983 // register submit callback on commentForm form to track TODOs, and refresh mergeChecks conditions
984 window.commentFormGlobalSubmitSuccessCallback = function () {
984 window.commentFormGlobalSubmitSuccessCallback = function (comment) {
985 refreshMergeChecks();
985 if (!comment.draft) {
986 refreshMergeChecks();
987 }
986 };
988 };
987
989
988 ReviewerAutoComplete('#user', reviewersController);
990 ReviewerAutoComplete('#user', reviewersController);
@@ -995,6 +997,12 b' window.setObserversData = ${c.pull_reque'
995 var channel = '${c.pr_broadcast_channel}';
997 var channel = '${c.pr_broadcast_channel}';
996 new ReviewerPresenceController(channel)
998 new ReviewerPresenceController(channel)
997
999
1000
1001 window.finalizeDrafts = function(commentIds) {
1002 alert('okok !' + commentIds)
1003
1004 }
1005
998 })
1006 })
999 </script>
1007 </script>
1000
1008
General Comments 0
You need to be logged in to leave comments. Login now