Show More
@@ -0,0 +1,30 b'' | |||
|
1 | import logging | |
|
2 | ||
|
3 | from sqlalchemy import Column, MetaData, Integer, Unicode, ForeignKey | |
|
4 | ||
|
5 | from rhodecode.lib.dbmigrate.versions import _reset_base | |
|
6 | ||
|
7 | log = logging.getLogger(__name__) | |
|
8 | ||
|
9 | ||
|
10 | def upgrade(migrate_engine): | |
|
11 | """ | |
|
12 | Upgrade operations go here. | |
|
13 | Don't create your own engine; bind migrate_engine to your metadata | |
|
14 | """ | |
|
15 | _reset_base(migrate_engine) | |
|
16 | from rhodecode.lib.dbmigrate.schema import db_4_5_0_0 as db | |
|
17 | ||
|
18 | # add comment type and link to resolve by id | |
|
19 | comment_table = db.ChangesetComment.__table__ | |
|
20 | col1 = Column('comment_type', Unicode(128), nullable=True) | |
|
21 | col1.create(table=comment_table) | |
|
22 | ||
|
23 | col1 = Column('resolved_comment_id', Integer(), | |
|
24 | ForeignKey('changeset_comments.comment_id'), nullable=True) | |
|
25 | col1.create(table=comment_table) | |
|
26 | ||
|
27 | ||
|
28 | def downgrade(migrate_engine): | |
|
29 | meta = MetaData() | |
|
30 | meta.bind = migrate_engine |
@@ -0,0 +1,70 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2017-2017 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | import os | |
|
22 | ||
|
23 | import colander | |
|
24 | ||
|
25 | from rhodecode.translation import _ | |
|
26 | from rhodecode.model.validation_schema import preparers | |
|
27 | from rhodecode.model.validation_schema import types | |
|
28 | ||
|
29 | ||
|
30 | @colander.deferred | |
|
31 | def deferred_lifetime_validator(node, kw): | |
|
32 | options = kw.get('lifetime_options', []) | |
|
33 | return colander.All( | |
|
34 | colander.Range(min=-1, max=60 * 24 * 30 * 12), | |
|
35 | colander.OneOf([x for x in options])) | |
|
36 | ||
|
37 | ||
|
38 | def unique_gist_validator(node, value): | |
|
39 | from rhodecode.model.db import Gist | |
|
40 | existing = Gist.get_by_access_id(value) | |
|
41 | if existing: | |
|
42 | msg = _(u'Gist with name {} already exists').format(value) | |
|
43 | raise colander.Invalid(node, msg) | |
|
44 | ||
|
45 | ||
|
46 | def filename_validator(node, value): | |
|
47 | if value != os.path.basename(value): | |
|
48 | msg = _(u'Filename {} cannot be inside a directory').format(value) | |
|
49 | raise colander.Invalid(node, msg) | |
|
50 | ||
|
51 | ||
|
52 | comment_types = ['note', 'todo'] | |
|
53 | ||
|
54 | ||
|
55 | class CommentSchema(colander.MappingSchema): | |
|
56 | from rhodecode.model.db import ChangesetComment | |
|
57 | ||
|
58 | comment_body = colander.SchemaNode(colander.String()) | |
|
59 | comment_type = colander.SchemaNode( | |
|
60 | colander.String(), | |
|
61 | validator=colander.OneOf(ChangesetComment.COMMENT_TYPES)) | |
|
62 | ||
|
63 | comment_file = colander.SchemaNode(colander.String(), missing=None) | |
|
64 | comment_line = colander.SchemaNode(colander.String(), missing=None) | |
|
65 | status_change = colander.SchemaNode(colander.String(), missing=None) | |
|
66 | renderer_type = colander.SchemaNode(colander.String()) | |
|
67 | ||
|
68 | # do those ? | |
|
69 | user = colander.SchemaNode(types.StrOrIntType()) | |
|
70 | repo = colander.SchemaNode(types.StrOrIntType()) |
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}' | |||
|
51 | 51 | EXTENSIONS = {} |
|
52 | 52 | |
|
53 | 53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) |
|
54 |
__dbversion__ = 6 |
|
|
54 | __dbversion__ = 64 # defines current db version for migrations | |
|
55 | 55 | __platform__ = platform.system() |
|
56 | 56 | __license__ = 'AGPLv3, and Commercial License' |
|
57 | 57 | __author__ = 'RhodeCode GmbH' |
@@ -334,6 +334,8 b' class ChangesetController(BaseRepoContro' | |||
|
334 | 334 | commit_id = revision |
|
335 | 335 | status = request.POST.get('changeset_status', None) |
|
336 | 336 | text = request.POST.get('text') |
|
337 | comment_type = request.POST.get('comment_type') | |
|
338 | ||
|
337 | 339 | if status: |
|
338 | 340 | text = text or (_('Status change %(transition_icon)s %(status)s') |
|
339 | 341 | % {'transition_icon': '>', |
@@ -355,7 +357,8 b' class ChangesetController(BaseRepoContro' | |||
|
355 | 357 | line_no=request.POST.get('line'), |
|
356 | 358 | status_change=(ChangesetStatus.get_status_lbl(status) |
|
357 | 359 | if status else None), |
|
358 | status_change_type=status | |
|
360 | status_change_type=status, | |
|
361 | comment_type=comment_type | |
|
359 | 362 | ) |
|
360 | 363 | c.inline_comment = True if comment.line_no else False |
|
361 | 364 |
@@ -903,6 +903,7 b' class PullrequestsController(BaseRepoCon' | |||
|
903 | 903 | # as a changeset status, still we want to send it in one value. |
|
904 | 904 | status = request.POST.get('changeset_status', None) |
|
905 | 905 | text = request.POST.get('text') |
|
906 | comment_type = request.POST.get('comment_type') | |
|
906 | 907 | if status and '_closed' in status: |
|
907 | 908 | close_pr = True |
|
908 | 909 | status = status.replace('_closed', '') |
@@ -934,7 +935,8 b' class PullrequestsController(BaseRepoCon' | |||
|
934 | 935 | if status and allowed_to_change_status else None), |
|
935 | 936 | status_change_type=(status |
|
936 | 937 | if status and allowed_to_change_status else None), |
|
937 | closing_pr=close_pr | |
|
938 | closing_pr=close_pr, | |
|
939 | comment_type=comment_type | |
|
938 | 940 | ) |
|
939 | 941 | |
|
940 | 942 | if allowed_to_change_status: |
@@ -56,7 +56,7 b' from rhodecode.lib.utils2 import (' | |||
|
56 | 56 | str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist) |
|
57 | 57 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
58 | 58 | from rhodecode.model import meta |
|
59 | from rhodecode.model.db import Repository, User | |
|
59 | from rhodecode.model.db import Repository, User, ChangesetComment | |
|
60 | 60 | from rhodecode.model.notification import NotificationModel |
|
61 | 61 | from rhodecode.model.scm import ScmModel |
|
62 | 62 | from rhodecode.model.settings import VcsSettingsModel, SettingsModel |
@@ -299,6 +299,7 b' def attach_context_attributes(context, r' | |||
|
299 | 299 | context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url') |
|
300 | 300 | context.visual.default_renderer = rc_config.get( |
|
301 | 301 | 'rhodecode_markup_renderer', 'rst') |
|
302 | context.visual.comment_types = ChangesetComment.COMMENT_TYPES | |
|
302 | 303 | context.visual.rhodecode_support_url = \ |
|
303 | 304 | rc_config.get('rhodecode_support_url') or url('rhodecode_support') |
|
304 | 305 |
@@ -44,6 +44,8 b' from rhodecode.model.notification import' | |||
|
44 | 44 | from rhodecode.model.meta import Session |
|
45 | 45 | from rhodecode.model.settings import VcsSettingsModel |
|
46 | 46 | from rhodecode.model.notification import EmailNotificationModel |
|
47 | from rhodecode.model.validation_schema.schemas import comment_schema | |
|
48 | ||
|
47 | 49 | |
|
48 | 50 | log = logging.getLogger(__name__) |
|
49 | 51 | |
@@ -111,15 +113,32 b' class CommentsModel(BaseModel):' | |||
|
111 | 113 | if not renderer: |
|
112 | 114 | renderer = self._get_renderer() |
|
113 | 115 | |
|
114 | repo = self._get_repo(repo) | |
|
115 | user = self._get_user(user) | |
|
116 | ||
|
117 | schema = comment_schema.CommentSchema() | |
|
118 | validated_kwargs = schema.deserialize(dict( | |
|
119 | comment_body=text, | |
|
120 | comment_type=comment_type, | |
|
121 | comment_file=f_path, | |
|
122 | comment_line=line_no, | |
|
123 | renderer_type=renderer, | |
|
124 | status_change=status_change, | |
|
125 | ||
|
126 | repo=repo, | |
|
127 | user=user, | |
|
128 | )) | |
|
129 | ||
|
130 | repo = self._get_repo(validated_kwargs['repo']) | |
|
131 | user = self._get_user(validated_kwargs['user']) | |
|
132 | ||
|
116 | 133 | comment = ChangesetComment() |
|
117 | comment.renderer = renderer | |
|
134 | comment.renderer = validated_kwargs['renderer_type'] | |
|
135 | comment.text = validated_kwargs['comment_body'] | |
|
136 | comment.f_path = validated_kwargs['comment_file'] | |
|
137 | comment.line_no = validated_kwargs['comment_line'] | |
|
138 | comment.comment_type = validated_kwargs['comment_type'] | |
|
139 | ||
|
118 | 140 | comment.repo = repo |
|
119 | 141 | comment.author = user |
|
120 | comment.text = text | |
|
121 | comment.f_path = f_path | |
|
122 | comment.line_no = line_no | |
|
123 | 142 | |
|
124 | 143 | pull_request_id = pull_request |
|
125 | 144 |
@@ -2896,6 +2896,9 b' class ChangesetComment(Base, BaseModel):' | |||
|
2896 | 2896 | ) |
|
2897 | 2897 | |
|
2898 | 2898 | COMMENT_OUTDATED = u'comment_outdated' |
|
2899 | COMMENT_TYPE_NOTE = u'note' | |
|
2900 | COMMENT_TYPE_TODO = u'todo' | |
|
2901 | COMMENT_TYPES = [COMMENT_TYPE_NOTE, COMMENT_TYPE_TODO] | |
|
2899 | 2902 | |
|
2900 | 2903 | comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True) |
|
2901 | 2904 | repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) |
@@ -2912,6 +2915,9 b' class ChangesetComment(Base, BaseModel):' | |||
|
2912 | 2915 | renderer = Column('renderer', Unicode(64), nullable=True) |
|
2913 | 2916 | display_state = Column('display_state', Unicode(128), nullable=True) |
|
2914 | 2917 | |
|
2918 | comment_type = Column('comment_type', Unicode(128), nullable=True, default=COMMENT_TYPE_NOTE) | |
|
2919 | resolved_comment_id = Column('resolved_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'), nullable=True) | |
|
2920 | resolved_comment = relationship('ChangesetComment', remote_side=comment_id) | |
|
2915 | 2921 | author = relationship('User', lazy='joined') |
|
2916 | 2922 | repo = relationship('Repository') |
|
2917 | 2923 | status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan") |
@@ -186,3 +186,11 b' class UserType(UserOrUserGroupType):' | |||
|
186 | 186 | |
|
187 | 187 | class UserGroupType(UserOrUserGroupType): |
|
188 | 188 | scopes = ('usergroup',) |
|
189 | ||
|
190 | ||
|
191 | class StrOrIntType(colander.String): | |
|
192 | def deserialize(self, node, cstruct): | |
|
193 | if isinstance(node, basestring): | |
|
194 | return super(StrOrIntType, self).deserialize(node, cstruct) | |
|
195 | else: | |
|
196 | return colander.Integer().deserialize(node, cstruct) |
@@ -880,8 +880,6 b' input.filediff-collapse-state {' | |||
|
880 | 880 | display: inline; |
|
881 | 881 | } |
|
882 | 882 | |
|
883 | @comment-padding: 5px; | |
|
884 | ||
|
885 | 883 | /**** COMMENTS ****/ |
|
886 | 884 | |
|
887 | 885 | .filediff-menu { |
@@ -909,59 +907,6 b' input.filediff-collapse-state {' | |||
|
909 | 907 | } |
|
910 | 908 | } |
|
911 | 909 | |
|
912 | .inline-comments { | |
|
913 | border-radius: @border-radius; | |
|
914 | .comment { | |
|
915 | margin: 0; | |
|
916 | border-radius: @border-radius; | |
|
917 | } | |
|
918 | .comment-outdated { | |
|
919 | opacity: 0.5; | |
|
920 | } | |
|
921 | ||
|
922 | .comment-inline { | |
|
923 | background: white; | |
|
924 | padding: (@comment-padding + 3px) @comment-padding; | |
|
925 | border: @comment-padding solid @grey6; | |
|
926 | ||
|
927 | .text { | |
|
928 | border: none; | |
|
929 | } | |
|
930 | .meta { | |
|
931 | border-bottom: 1px solid @grey6; | |
|
932 | padding-bottom: 10px; | |
|
933 | } | |
|
934 | } | |
|
935 | .comment-selected { | |
|
936 | border-left: 6px solid @comment-highlight-color; | |
|
937 | } | |
|
938 | .comment-inline-form { | |
|
939 | padding: @comment-padding; | |
|
940 | display: none; | |
|
941 | } | |
|
942 | .cb-comment-add-button { | |
|
943 | margin: @comment-padding; | |
|
944 | } | |
|
945 | /* hide add comment button when form is open */ | |
|
946 | .comment-inline-form-open ~ .cb-comment-add-button { | |
|
947 | display: none; | |
|
948 | } | |
|
949 | .comment-inline-form-open { | |
|
950 | display: block; | |
|
951 | } | |
|
952 | /* hide add comment button when form but no comments */ | |
|
953 | .comment-inline-form:first-child + .cb-comment-add-button { | |
|
954 | display: none; | |
|
955 | } | |
|
956 | /* hide add comment button when no comments or form */ | |
|
957 | .cb-comment-add-button:first-child { | |
|
958 | display: none; | |
|
959 | } | |
|
960 | /* hide add comment button when only comment is being deleted */ | |
|
961 | .comment-deleting:first-child + .cb-comment-add-button { | |
|
962 | display: none; | |
|
963 | } | |
|
964 | } | |
|
965 | 910 | /**** END COMMENTS ****/ |
|
966 | 911 | |
|
967 | 912 | } |
@@ -47,6 +47,33 b' tr.inline-comments div {' | |||
|
47 | 47 | visibility: hidden; |
|
48 | 48 | } |
|
49 | 49 | |
|
50 | .comment-label { | |
|
51 | float: left; | |
|
52 | ||
|
53 | padding: 0.4em 0.4em; | |
|
54 | margin: 2px 5px 0px -10px; | |
|
55 | display: inline-block; | |
|
56 | min-height: 0; | |
|
57 | ||
|
58 | text-align: center; | |
|
59 | font-size: 10px; | |
|
60 | line-height: .8em; | |
|
61 | ||
|
62 | font-family: @text-italic; | |
|
63 | background: #fff none; | |
|
64 | color: @grey4; | |
|
65 | border: 1px solid @grey4; | |
|
66 | white-space: nowrap; | |
|
67 | ||
|
68 | text-transform: uppercase; | |
|
69 | ||
|
70 | &.todo { | |
|
71 | color: @color5; | |
|
72 | font-family: @text-bold-italic; | |
|
73 | } | |
|
74 | } | |
|
75 | ||
|
76 | ||
|
50 | 77 | .comment { |
|
51 | 78 | |
|
52 | 79 | &.comment-general { |
@@ -60,15 +87,19 b' tr.inline-comments div {' | |||
|
60 | 87 | |
|
61 | 88 | .rc-user { |
|
62 | 89 | min-width: 0; |
|
63 |
margin: |
|
|
90 | margin: 0px .5em 0 0; | |
|
91 | ||
|
92 | .user { | |
|
93 | display: inline; | |
|
94 | } | |
|
64 | 95 | } |
|
65 | 96 | |
|
66 | 97 | .meta { |
|
67 | 98 | position: relative; |
|
68 | 99 | width: 100%; |
|
69 | margin: 0 0 .5em 0; | |
|
70 | 100 | border-bottom: 1px solid @grey5; |
|
71 |
|
|
|
101 | margin: -5px 0px; | |
|
102 | line-height: 24px; | |
|
72 | 103 | |
|
73 | 104 | &:hover .permalink { |
|
74 | 105 | visibility: visible; |
@@ -87,10 +118,10 b' tr.inline-comments div {' | |||
|
87 | 118 | } |
|
88 | 119 | |
|
89 | 120 | .author-general img { |
|
90 |
top: |
|
|
121 | top: 3px; | |
|
91 | 122 | } |
|
92 | 123 | .author-inline img { |
|
93 |
top: |
|
|
124 | top: 3px; | |
|
94 | 125 | } |
|
95 | 126 | |
|
96 | 127 | .status-change, |
@@ -182,7 +213,7 b' tr.inline-comments div {' | |||
|
182 | 213 | } |
|
183 | 214 | .pr-version-inline { |
|
184 | 215 | float: left; |
|
185 |
margin: |
|
|
216 | margin: 0px 4px; | |
|
186 | 217 | } |
|
187 | 218 | .pr-version-num { |
|
188 | 219 | font-size: 10px; |
@@ -190,6 +221,64 b' tr.inline-comments div {' | |||
|
190 | 221 | |
|
191 | 222 | } |
|
192 | 223 | |
|
224 | @comment-padding: 5px; | |
|
225 | ||
|
226 | .inline-comments { | |
|
227 | border-radius: @border-radius; | |
|
228 | .comment { | |
|
229 | margin: 0; | |
|
230 | border-radius: @border-radius; | |
|
231 | } | |
|
232 | .comment-outdated { | |
|
233 | opacity: 0.5; | |
|
234 | } | |
|
235 | ||
|
236 | .comment-inline { | |
|
237 | background: white; | |
|
238 | padding: @comment-padding @comment-padding; | |
|
239 | border: @comment-padding solid @grey6; | |
|
240 | ||
|
241 | .text { | |
|
242 | border: none; | |
|
243 | } | |
|
244 | .meta { | |
|
245 | border-bottom: 1px solid @grey6; | |
|
246 | margin: -5px 0px; | |
|
247 | line-height: 24px; | |
|
248 | } | |
|
249 | } | |
|
250 | .comment-selected { | |
|
251 | border-left: 6px solid @comment-highlight-color; | |
|
252 | } | |
|
253 | .comment-inline-form { | |
|
254 | padding: @comment-padding; | |
|
255 | display: none; | |
|
256 | } | |
|
257 | .cb-comment-add-button { | |
|
258 | margin: @comment-padding; | |
|
259 | } | |
|
260 | /* hide add comment button when form is open */ | |
|
261 | .comment-inline-form-open ~ .cb-comment-add-button { | |
|
262 | display: none; | |
|
263 | } | |
|
264 | .comment-inline-form-open { | |
|
265 | display: block; | |
|
266 | } | |
|
267 | /* hide add comment button when form but no comments */ | |
|
268 | .comment-inline-form:first-child + .cb-comment-add-button { | |
|
269 | display: none; | |
|
270 | } | |
|
271 | /* hide add comment button when no comments or form */ | |
|
272 | .cb-comment-add-button:first-child { | |
|
273 | display: none; | |
|
274 | } | |
|
275 | /* hide add comment button when only comment is being deleted */ | |
|
276 | .comment-deleting:first-child + .cb-comment-add-button { | |
|
277 | display: none; | |
|
278 | } | |
|
279 | } | |
|
280 | ||
|
281 | ||
|
193 | 282 | .show-outdated-comments { |
|
194 | 283 | display: inline; |
|
195 | 284 | color: @rcblue; |
@@ -300,6 +389,12 b' form.comment-form {' | |||
|
300 | 389 | } |
|
301 | 390 | } |
|
302 | 391 | |
|
392 | .comment-type { | |
|
393 | margin: 0px; | |
|
394 | border-radius: inherit; | |
|
395 | border-color: @grey6; | |
|
396 | } | |
|
397 | ||
|
303 | 398 | .preview-box { |
|
304 | 399 | min-height: 105px; |
|
305 | 400 | margin-bottom: 15px; |
@@ -688,6 +688,7 b' label {' | |||
|
688 | 688 | padding: 0; |
|
689 | 689 | line-height: 1em; |
|
690 | 690 | border: 1px solid @grey4; |
|
691 | box-sizing: content-box; | |
|
691 | 692 | |
|
692 | 693 | &.gravatar-large { |
|
693 | 694 | margin: -0.5em .25em -0.5em 0; |
@@ -132,12 +132,13 b' var CommentForm = (function() {' | |||
|
132 | 132 | |
|
133 | 133 | this.editButton = this.withLineNo('#edit-btn'); |
|
134 | 134 | this.editContainer = this.withLineNo('#edit-container'); |
|
135 | this.cancelButton = this.withLineNo('#cancel-btn'); | |
|
136 | this.commentType = this.withLineNo('#comment_type'); | |
|
135 | 137 | |
|
136 |
this.c |
|
|
138 | this.cmBox = this.withLineNo('#text'); | |
|
139 | this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions); | |
|
137 | 140 | |
|
138 | 141 | this.statusChange = '#change_status'; |
|
139 | this.cmBox = this.withLineNo('#text'); | |
|
140 | this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions); | |
|
141 | 142 | |
|
142 | 143 | this.submitForm = formElement; |
|
143 | 144 | this.submitButton = $(this.submitForm).find('input[type="submit"]'); |
@@ -172,7 +173,9 b' var CommentForm = (function() {' | |||
|
172 | 173 | this.getCommentStatus = function() { |
|
173 | 174 | return $(this.submitForm).find(this.statusChange).val(); |
|
174 | 175 | }; |
|
175 | ||
|
176 | this.getCommentType = function() { | |
|
177 | return $(this.submitForm).find(this.commentType).val(); | |
|
178 | }; | |
|
176 | 179 | this.isAllowedToSubmit = function() { |
|
177 | 180 | return !$(this.submitButton).prop('disabled'); |
|
178 | 181 | }; |
@@ -256,6 +259,7 b' var CommentForm = (function() {' | |||
|
256 | 259 | this.handleFormSubmit = function() { |
|
257 | 260 | var text = self.cm.getValue(); |
|
258 | 261 | var status = self.getCommentStatus(); |
|
262 | var commentType = self.getCommentType(); | |
|
259 | 263 | |
|
260 | 264 | if (text === "" && !status) { |
|
261 | 265 | return; |
@@ -268,6 +272,7 b' var CommentForm = (function() {' | |||
|
268 | 272 | var postData = { |
|
269 | 273 | 'text': text, |
|
270 | 274 | 'changeset_status': status, |
|
275 | 'comment_type': commentType, | |
|
271 | 276 | 'csrf_token': CSRF_TOKEN |
|
272 | 277 | }; |
|
273 | 278 | |
@@ -536,6 +541,7 b' var CommentsController = function() { /*' | |||
|
536 | 541 | $filediff.removeClass('hide-comments'); |
|
537 | 542 | var f_path = $filediff.attr('data-f-path'); |
|
538 | 543 | var lineno = self.getLineNumber(node); |
|
544 | ||
|
539 | 545 | tmpl = tmpl.format(f_path, lineno); |
|
540 | 546 | $form = $(tmpl); |
|
541 | 547 | |
@@ -557,6 +563,7 b' var CommentsController = function() { /*' | |||
|
557 | 563 | // set a CUSTOM submit handler for inline comments. |
|
558 | 564 | commentForm.setHandleFormSubmit(function(o) { |
|
559 | 565 | var text = commentForm.cm.getValue(); |
|
566 | var commentType = commentForm.getCommentType(); | |
|
560 | 567 | |
|
561 | 568 | if (text === "") { |
|
562 | 569 | return; |
@@ -579,6 +586,7 b' var CommentsController = function() { /*' | |||
|
579 | 586 | 'text': text, |
|
580 | 587 | 'f_path': f_path, |
|
581 | 588 | 'line': lineno, |
|
589 | 'comment_type': commentType, | |
|
582 | 590 | 'csrf_token': CSRF_TOKEN |
|
583 | 591 | }; |
|
584 | 592 | var submitSuccessCallback = function(json_data) { |
@@ -18,8 +18,14 b'' | |||
|
18 | 18 | style="${'display: none;' if outdated_at_ver else ''}"> |
|
19 | 19 | |
|
20 | 20 | <div class="meta"> |
|
21 | <div class="comment-type-label tooltip"> | |
|
22 | <div class="comment-label ${comment.comment_type or 'note'}"> | |
|
23 | ${comment.comment_type or 'note'} | |
|
24 | </div> | |
|
25 | </div> | |
|
26 | ||
|
21 | 27 | <div class="author ${'author-inline' if inline else 'author-general'}"> |
|
22 |
${base.gravatar_with_user(comment.author.email, |
|
|
28 | ${base.gravatar_with_user(comment.author.email, 16)} | |
|
23 | 29 | </div> |
|
24 | 30 | <div class="date"> |
|
25 | 31 | ${h.age_component(comment.modified_at, time_is_local=True)} |
@@ -31,16 +37,14 b'' | |||
|
31 | 37 | % if comment.pull_request: |
|
32 | 38 | <a href="${h.url('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id)}"> |
|
33 | 39 | % if comment.status_change: |
|
34 |
${_(' |
|
|
40 | ${_('pull request #%s') % comment.pull_request.pull_request_id}: | |
|
35 | 41 | % else: |
|
36 |
${_(' |
|
|
42 | ${_('pull request #%s') % comment.pull_request.pull_request_id} | |
|
37 | 43 | % endif |
|
38 | 44 | </a> |
|
39 | 45 | % else: |
|
40 | 46 | % if comment.status_change: |
|
41 | 47 | ${_('Status change on commit')}: |
|
42 | % else: | |
|
43 | ${_('Comment on commit')} | |
|
44 | 48 | % endif |
|
45 | 49 | % endif |
|
46 | 50 | </div> |
@@ -185,6 +189,13 b'' | |||
|
185 | 189 | <li class=""> |
|
186 | 190 | <a href="#preview-btn" tabindex="-1" id="preview-btn">${_('Preview')}</a> |
|
187 | 191 | </li> |
|
192 | <li class="pull-right"> | |
|
193 | <select class="comment-type" id="comment_type" name="comment_type"> | |
|
194 | % for val in c.visual.comment_types: | |
|
195 | <option value="${val}">${val.upper()}</option> | |
|
196 | % endfor | |
|
197 | </select> | |
|
198 | </li> | |
|
188 | 199 | </ul> |
|
189 | 200 | </div> |
|
190 | 201 |
@@ -70,6 +70,13 b" return h.url('', **new_args)" | |||
|
70 | 70 | <li class=""> |
|
71 | 71 | <a href="#preview-btn" tabindex="-1" id="preview-btn_{1}">${_('Preview')}</a> |
|
72 | 72 | </li> |
|
73 | <li class="pull-right"> | |
|
74 | <select class="comment-type" id="comment_type_{1}" name="comment_type"> | |
|
75 | % for val in c.visual.comment_types: | |
|
76 | <option value="${val}">${val.upper()}</option> | |
|
77 | % endfor | |
|
78 | </select> | |
|
79 | </li> | |
|
73 | 80 | </ul> |
|
74 | 81 | </div> |
|
75 | 82 |
General Comments 0
You need to be logged in to leave comments.
Login now