##// END OF EJS Templates
comments: add comments type into comments.
marcink -
r1324:efd94f49 default
parent child Browse files
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 EXTENSIONS = {}
51 EXTENSIONS = {}
52
52
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
53 __version__ = ('.'.join((str(each) for each in VERSION[:3])))
54 __dbversion__ = 63 # defines current db version for migrations
54 __dbversion__ = 64 # defines current db version for migrations
55 __platform__ = platform.system()
55 __platform__ = platform.system()
56 __license__ = 'AGPLv3, and Commercial License'
56 __license__ = 'AGPLv3, and Commercial License'
57 __author__ = 'RhodeCode GmbH'
57 __author__ = 'RhodeCode GmbH'
@@ -334,6 +334,8 b' class ChangesetController(BaseRepoContro'
334 commit_id = revision
334 commit_id = revision
335 status = request.POST.get('changeset_status', None)
335 status = request.POST.get('changeset_status', None)
336 text = request.POST.get('text')
336 text = request.POST.get('text')
337 comment_type = request.POST.get('comment_type')
338
337 if status:
339 if status:
338 text = text or (_('Status change %(transition_icon)s %(status)s')
340 text = text or (_('Status change %(transition_icon)s %(status)s')
339 % {'transition_icon': '>',
341 % {'transition_icon': '>',
@@ -355,7 +357,8 b' class ChangesetController(BaseRepoContro'
355 line_no=request.POST.get('line'),
357 line_no=request.POST.get('line'),
356 status_change=(ChangesetStatus.get_status_lbl(status)
358 status_change=(ChangesetStatus.get_status_lbl(status)
357 if status else None),
359 if status else None),
358 status_change_type=status
360 status_change_type=status,
361 comment_type=comment_type
359 )
362 )
360 c.inline_comment = True if comment.line_no else False
363 c.inline_comment = True if comment.line_no else False
361
364
@@ -903,6 +903,7 b' class PullrequestsController(BaseRepoCon'
903 # as a changeset status, still we want to send it in one value.
903 # as a changeset status, still we want to send it in one value.
904 status = request.POST.get('changeset_status', None)
904 status = request.POST.get('changeset_status', None)
905 text = request.POST.get('text')
905 text = request.POST.get('text')
906 comment_type = request.POST.get('comment_type')
906 if status and '_closed' in status:
907 if status and '_closed' in status:
907 close_pr = True
908 close_pr = True
908 status = status.replace('_closed', '')
909 status = status.replace('_closed', '')
@@ -934,7 +935,8 b' class PullrequestsController(BaseRepoCon'
934 if status and allowed_to_change_status else None),
935 if status and allowed_to_change_status else None),
935 status_change_type=(status
936 status_change_type=(status
936 if status and allowed_to_change_status else None),
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 if allowed_to_change_status:
942 if allowed_to_change_status:
@@ -56,7 +56,7 b' from rhodecode.lib.utils2 import ('
56 str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist)
56 str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist)
57 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
57 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
58 from rhodecode.model import meta
58 from rhodecode.model import meta
59 from rhodecode.model.db import Repository, User
59 from rhodecode.model.db import Repository, User, ChangesetComment
60 from rhodecode.model.notification import NotificationModel
60 from rhodecode.model.notification import NotificationModel
61 from rhodecode.model.scm import ScmModel
61 from rhodecode.model.scm import ScmModel
62 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
62 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
@@ -299,6 +299,7 b' def attach_context_attributes(context, r'
299 context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
299 context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
300 context.visual.default_renderer = rc_config.get(
300 context.visual.default_renderer = rc_config.get(
301 'rhodecode_markup_renderer', 'rst')
301 'rhodecode_markup_renderer', 'rst')
302 context.visual.comment_types = ChangesetComment.COMMENT_TYPES
302 context.visual.rhodecode_support_url = \
303 context.visual.rhodecode_support_url = \
303 rc_config.get('rhodecode_support_url') or url('rhodecode_support')
304 rc_config.get('rhodecode_support_url') or url('rhodecode_support')
304
305
@@ -44,6 +44,8 b' from rhodecode.model.notification import'
44 from rhodecode.model.meta import Session
44 from rhodecode.model.meta import Session
45 from rhodecode.model.settings import VcsSettingsModel
45 from rhodecode.model.settings import VcsSettingsModel
46 from rhodecode.model.notification import EmailNotificationModel
46 from rhodecode.model.notification import EmailNotificationModel
47 from rhodecode.model.validation_schema.schemas import comment_schema
48
47
49
48 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
49
51
@@ -111,15 +113,32 b' class CommentsModel(BaseModel):'
111 if not renderer:
113 if not renderer:
112 renderer = self._get_renderer()
114 renderer = self._get_renderer()
113
115
114 repo = self._get_repo(repo)
116
115 user = self._get_user(user)
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 comment = ChangesetComment()
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 comment.repo = repo
140 comment.repo = repo
119 comment.author = user
141 comment.author = user
120 comment.text = text
121 comment.f_path = f_path
122 comment.line_no = line_no
123
142
124 pull_request_id = pull_request
143 pull_request_id = pull_request
125
144
@@ -2896,6 +2896,9 b' class ChangesetComment(Base, BaseModel):'
2896 )
2896 )
2897
2897
2898 COMMENT_OUTDATED = u'comment_outdated'
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 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
2903 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
2901 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
2904 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
@@ -2912,6 +2915,9 b' class ChangesetComment(Base, BaseModel):'
2912 renderer = Column('renderer', Unicode(64), nullable=True)
2915 renderer = Column('renderer', Unicode(64), nullable=True)
2913 display_state = Column('display_state', Unicode(128), nullable=True)
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 author = relationship('User', lazy='joined')
2921 author = relationship('User', lazy='joined')
2916 repo = relationship('Repository')
2922 repo = relationship('Repository')
2917 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
2923 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
@@ -186,3 +186,11 b' class UserType(UserOrUserGroupType):'
186
186
187 class UserGroupType(UserOrUserGroupType):
187 class UserGroupType(UserOrUserGroupType):
188 scopes = ('usergroup',)
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 display: inline;
880 display: inline;
881 }
881 }
882
882
883 @comment-padding: 5px;
884
885 /**** COMMENTS ****/
883 /**** COMMENTS ****/
886
884
887 .filediff-menu {
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 /**** END COMMENTS ****/
910 /**** END COMMENTS ****/
966
911
967 }
912 }
@@ -47,6 +47,33 b' tr.inline-comments div {'
47 visibility: hidden;
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 .comment {
77 .comment {
51
78
52 &.comment-general {
79 &.comment-general {
@@ -60,15 +87,19 b' tr.inline-comments div {'
60
87
61 .rc-user {
88 .rc-user {
62 min-width: 0;
89 min-width: 0;
63 margin: -2px .5em 0 0;
90 margin: 0px .5em 0 0;
91
92 .user {
93 display: inline;
94 }
64 }
95 }
65
96
66 .meta {
97 .meta {
67 position: relative;
98 position: relative;
68 width: 100%;
99 width: 100%;
69 margin: 0 0 .5em 0;
70 border-bottom: 1px solid @grey5;
100 border-bottom: 1px solid @grey5;
71 padding: 8px 0px;
101 margin: -5px 0px;
102 line-height: 24px;
72
103
73 &:hover .permalink {
104 &:hover .permalink {
74 visibility: visible;
105 visibility: visible;
@@ -87,10 +118,10 b' tr.inline-comments div {'
87 }
118 }
88
119
89 .author-general img {
120 .author-general img {
90 top: -3px;
121 top: 3px;
91 }
122 }
92 .author-inline img {
123 .author-inline img {
93 top: -3px;
124 top: 3px;
94 }
125 }
95
126
96 .status-change,
127 .status-change,
@@ -182,7 +213,7 b' tr.inline-comments div {'
182 }
213 }
183 .pr-version-inline {
214 .pr-version-inline {
184 float: left;
215 float: left;
185 margin: 1px 4px;
216 margin: 0px 4px;
186 }
217 }
187 .pr-version-num {
218 .pr-version-num {
188 font-size: 10px;
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 .show-outdated-comments {
282 .show-outdated-comments {
194 display: inline;
283 display: inline;
195 color: @rcblue;
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 .preview-box {
398 .preview-box {
304 min-height: 105px;
399 min-height: 105px;
305 margin-bottom: 15px;
400 margin-bottom: 15px;
@@ -688,6 +688,7 b' label {'
688 padding: 0;
688 padding: 0;
689 line-height: 1em;
689 line-height: 1em;
690 border: 1px solid @grey4;
690 border: 1px solid @grey4;
691 box-sizing: content-box;
691
692
692 &.gravatar-large {
693 &.gravatar-large {
693 margin: -0.5em .25em -0.5em 0;
694 margin: -0.5em .25em -0.5em 0;
@@ -132,12 +132,13 b' var CommentForm = (function() {'
132
132
133 this.editButton = this.withLineNo('#edit-btn');
133 this.editButton = this.withLineNo('#edit-btn');
134 this.editContainer = this.withLineNo('#edit-container');
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.cancelButton = this.withLineNo('#cancel-btn');
138 this.cmBox = this.withLineNo('#text');
139 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
137
140
138 this.statusChange = '#change_status';
141 this.statusChange = '#change_status';
139 this.cmBox = this.withLineNo('#text');
140 this.cm = initCommentBoxCodeMirror(this.cmBox, this.initAutocompleteActions);
141
142
142 this.submitForm = formElement;
143 this.submitForm = formElement;
143 this.submitButton = $(this.submitForm).find('input[type="submit"]');
144 this.submitButton = $(this.submitForm).find('input[type="submit"]');
@@ -172,7 +173,9 b' var CommentForm = (function() {'
172 this.getCommentStatus = function() {
173 this.getCommentStatus = function() {
173 return $(this.submitForm).find(this.statusChange).val();
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 this.isAllowedToSubmit = function() {
179 this.isAllowedToSubmit = function() {
177 return !$(this.submitButton).prop('disabled');
180 return !$(this.submitButton).prop('disabled');
178 };
181 };
@@ -256,6 +259,7 b' var CommentForm = (function() {'
256 this.handleFormSubmit = function() {
259 this.handleFormSubmit = function() {
257 var text = self.cm.getValue();
260 var text = self.cm.getValue();
258 var status = self.getCommentStatus();
261 var status = self.getCommentStatus();
262 var commentType = self.getCommentType();
259
263
260 if (text === "" && !status) {
264 if (text === "" && !status) {
261 return;
265 return;
@@ -268,6 +272,7 b' var CommentForm = (function() {'
268 var postData = {
272 var postData = {
269 'text': text,
273 'text': text,
270 'changeset_status': status,
274 'changeset_status': status,
275 'comment_type': commentType,
271 'csrf_token': CSRF_TOKEN
276 'csrf_token': CSRF_TOKEN
272 };
277 };
273
278
@@ -536,6 +541,7 b' var CommentsController = function() { /*'
536 $filediff.removeClass('hide-comments');
541 $filediff.removeClass('hide-comments');
537 var f_path = $filediff.attr('data-f-path');
542 var f_path = $filediff.attr('data-f-path');
538 var lineno = self.getLineNumber(node);
543 var lineno = self.getLineNumber(node);
544
539 tmpl = tmpl.format(f_path, lineno);
545 tmpl = tmpl.format(f_path, lineno);
540 $form = $(tmpl);
546 $form = $(tmpl);
541
547
@@ -557,6 +563,7 b' var CommentsController = function() { /*'
557 // set a CUSTOM submit handler for inline comments.
563 // set a CUSTOM submit handler for inline comments.
558 commentForm.setHandleFormSubmit(function(o) {
564 commentForm.setHandleFormSubmit(function(o) {
559 var text = commentForm.cm.getValue();
565 var text = commentForm.cm.getValue();
566 var commentType = commentForm.getCommentType();
560
567
561 if (text === "") {
568 if (text === "") {
562 return;
569 return;
@@ -579,6 +586,7 b' var CommentsController = function() { /*'
579 'text': text,
586 'text': text,
580 'f_path': f_path,
587 'f_path': f_path,
581 'line': lineno,
588 'line': lineno,
589 'comment_type': commentType,
582 'csrf_token': CSRF_TOKEN
590 'csrf_token': CSRF_TOKEN
583 };
591 };
584 var submitSuccessCallback = function(json_data) {
592 var submitSuccessCallback = function(json_data) {
@@ -18,8 +18,14 b''
18 style="${'display: none;' if outdated_at_ver else ''}">
18 style="${'display: none;' if outdated_at_ver else ''}">
19
19
20 <div class="meta">
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 <div class="author ${'author-inline' if inline else 'author-general'}">
27 <div class="author ${'author-inline' if inline else 'author-general'}">
22 ${base.gravatar_with_user(comment.author.email, 20)}
28 ${base.gravatar_with_user(comment.author.email, 16)}
23 </div>
29 </div>
24 <div class="date">
30 <div class="date">
25 ${h.age_component(comment.modified_at, time_is_local=True)}
31 ${h.age_component(comment.modified_at, time_is_local=True)}
@@ -31,16 +37,14 b''
31 % if comment.pull_request:
37 % if comment.pull_request:
32 <a href="${h.url('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id)}">
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 % if comment.status_change:
39 % if comment.status_change:
34 ${_('Vote on pull request #%s') % comment.pull_request.pull_request_id}:
40 ${_('pull request #%s') % comment.pull_request.pull_request_id}:
35 % else:
41 % else:
36 ${_('Comment on pull request #%s') % comment.pull_request.pull_request_id}
42 ${_('pull request #%s') % comment.pull_request.pull_request_id}
37 % endif
43 % endif
38 </a>
44 </a>
39 % else:
45 % else:
40 % if comment.status_change:
46 % if comment.status_change:
41 ${_('Status change on commit')}:
47 ${_('Status change on commit')}:
42 % else:
43 ${_('Comment on commit')}
44 % endif
48 % endif
45 % endif
49 % endif
46 </div>
50 </div>
@@ -185,6 +189,13 b''
185 <li class="">
189 <li class="">
186 <a href="#preview-btn" tabindex="-1" id="preview-btn">${_('Preview')}</a>
190 <a href="#preview-btn" tabindex="-1" id="preview-btn">${_('Preview')}</a>
187 </li>
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 </ul>
199 </ul>
189 </div>
200 </div>
190
201
@@ -70,6 +70,13 b" return h.url('', **new_args)"
70 <li class="">
70 <li class="">
71 <a href="#preview-btn" tabindex="-1" id="preview-btn_{1}">${_('Preview')}</a>
71 <a href="#preview-btn" tabindex="-1" id="preview-btn_{1}">${_('Preview')}</a>
72 </li>
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 </ul>
80 </ul>
74 </div>
81 </div>
75
82
General Comments 0
You need to be logged in to leave comments. Login now