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