##// END OF EJS Templates
comment-history: fixes/ui changes...
marcink -
r4408:1349565d default
parent child Browse files
Show More
@@ -378,9 +378,9 b' class TestRepoCommitCommentsView(TestCon'
378 'text': test_text_v2,
378 'text': test_text_v2,
379 'version': '0',
379 'version': '0',
380 },
380 },
381 status=404,
381 status=409,
382 )
382 )
383 assert response.status_int == 404
383 assert response.status_int == 409
384
384
385 text_form_db = ChangesetComment.query().filter(
385 text_form_db = ChangesetComment.query().filter(
386 ChangesetComment.comment_id == comment_id).first().text
386 ChangesetComment.comment_id == comment_id).first().text
@@ -480,9 +480,7 b' class TestPullrequestsView(object):'
480 )
480 )
481 assert response.status_int == 404
481 assert response.status_int == 404
482
482
483 def test_comment_and_try_edit_already_edited(
483 def test_comment_and_try_edit_already_edited(self, pr_util, csrf_token, xhr_header):
484 self, pr_util, csrf_token, xhr_header
485 ):
486 pull_request = pr_util.create_pull_request()
484 pull_request = pr_util.create_pull_request()
487 response = self.app.post(
485 response = self.app.post(
488 route_path(
486 route_path(
@@ -498,8 +496,9 b' class TestPullrequestsView(object):'
498 assert response.json
496 assert response.json
499 comment_id = response.json.get('comment_id', None)
497 comment_id = response.json.get('comment_id', None)
500 assert comment_id
498 assert comment_id
499
501 test_text = 'test'
500 test_text = 'test'
502 response = self.app.post(
501 self.app.post(
503 route_path(
502 route_path(
504 'pullrequest_comment_edit',
503 'pullrequest_comment_edit',
505 repo_name=pull_request.target_repo.scm_instance().name,
504 repo_name=pull_request.target_repo.scm_instance().name,
@@ -528,9 +527,9 b' class TestPullrequestsView(object):'
528 'text': test_text_v2,
527 'text': test_text_v2,
529 'version': '0',
528 'version': '0',
530 },
529 },
531 status=404,
530 status=409,
532 )
531 )
533 assert response.status_int == 404
532 assert response.status_int == 409
534
533
535 text_form_db = ChangesetComment.query().filter(
534 text_form_db = ChangesetComment.query().filter(
536 ChangesetComment.comment_id == comment_id).first().text
535 ChangesetComment.comment_id == comment_id).first().text
@@ -20,9 +20,9 b''
20
20
21
21
22 import logging
22 import logging
23 import collections
24
23
25 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound, HTTPForbidden
24 from pyramid.httpexceptions import (
25 HTTPNotFound, HTTPBadRequest, HTTPFound, HTTPForbidden, HTTPConflict)
26 from pyramid.view import view_config
26 from pyramid.view import view_config
27 from pyramid.renderers import render
27 from pyramid.renderers import render
28 from pyramid.response import Response
28 from pyramid.response import Response
@@ -39,7 +39,7 b' from rhodecode.lib.compat import Ordered'
39 from rhodecode.lib.diffs import (
39 from rhodecode.lib.diffs import (
40 cache_diff, load_cached_diff, diff_cache_exist, get_diff_context,
40 cache_diff, load_cached_diff, diff_cache_exist, get_diff_context,
41 get_diff_whitespace_flag)
41 get_diff_whitespace_flag)
42 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
42 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError, CommentVersionMismatch
43 import rhodecode.lib.helpers as h
43 import rhodecode.lib.helpers as h
44 from rhodecode.lib.utils2 import safe_unicode, str2bool
44 from rhodecode.lib.utils2 import safe_unicode, str2bool
45 from rhodecode.lib.vcs.backends.base import EmptyCommit
45 from rhodecode.lib.vcs.backends.base import EmptyCommit
@@ -595,6 +595,8 b' class RepoCommitsView(RepoAppView):'
595 route_name='repo_commit_comment_edit', request_method='POST',
595 route_name='repo_commit_comment_edit', request_method='POST',
596 renderer='json_ext')
596 renderer='json_ext')
597 def repo_commit_comment_edit(self):
597 def repo_commit_comment_edit(self):
598 self.load_default_context()
599
598 comment_id = self.request.matchdict['comment_id']
600 comment_id = self.request.matchdict['comment_id']
599 comment = ChangesetComment.get_or_404(comment_id)
601 comment = ChangesetComment.get_or_404(comment_id)
600
602
@@ -615,11 +617,12 b' class RepoCommitsView(RepoAppView):'
615 log.warning(
617 log.warning(
616 'Comment(repo): '
618 'Comment(repo): '
617 'Trying to create new version '
619 'Trying to create new version '
618 'of existing comment {}'.format(
620 'with the same comment body {}'.format(
619 comment_id,
621 comment_id,
620 )
622 )
621 )
623 )
622 raise HTTPNotFound()
624 raise HTTPNotFound()
625
623 if version.isdigit():
626 if version.isdigit():
624 version = int(version)
627 version = int(version)
625 else:
628 else:
@@ -633,19 +636,28 b' class RepoCommitsView(RepoAppView):'
633 )
636 )
634 raise HTTPNotFound()
637 raise HTTPNotFound()
635
638
636 comment_history = CommentsModel().edit(
639 try:
637 comment_id=comment_id,
640 comment_history = CommentsModel().edit(
638 text=text,
641 comment_id=comment_id,
639 auth_user=self._rhodecode_user,
642 text=text,
640 version=version,
643 auth_user=self._rhodecode_user,
641 )
644 version=version,
645 )
646 except CommentVersionMismatch:
647 raise HTTPConflict()
648
642 if not comment_history:
649 if not comment_history:
643 raise HTTPNotFound()
650 raise HTTPNotFound()
651
644 Session().commit()
652 Session().commit()
645 return {
653 return {
646 'comment_history_id': comment_history.comment_history_id,
654 'comment_history_id': comment_history.comment_history_id,
647 'comment_id': comment.comment_id,
655 'comment_id': comment.comment_id,
648 'comment_version': comment_history.version,
656 'comment_version': comment_history.version,
657 'comment_author_username': comment_history.author.username,
658 'comment_author_gravatar': h.gravatar_url(comment_history.author.email, 16),
659 'comment_created_on': h.age_component(comment_history.created_on,
660 time_is_local=True),
649 }
661 }
650 else:
662 else:
651 log.warning('No permissions for user %s to edit comment_id: %s',
663 log.warning('No permissions for user %s to edit comment_id: %s',
@@ -25,7 +25,7 b' import formencode'
25 import formencode.htmlfill
25 import formencode.htmlfill
26 import peppercorn
26 import peppercorn
27 from pyramid.httpexceptions import (
27 from pyramid.httpexceptions import (
28 HTTPFound, HTTPNotFound, HTTPForbidden, HTTPBadRequest)
28 HTTPFound, HTTPNotFound, HTTPForbidden, HTTPBadRequest, HTTPConflict)
29 from pyramid.view import view_config
29 from pyramid.view import view_config
30 from pyramid.renderers import render
30 from pyramid.renderers import render
31
31
@@ -34,6 +34,7 b' from rhodecode.apps._base import RepoApp'
34 from rhodecode.lib import helpers as h, diffs, codeblocks, channelstream
34 from rhodecode.lib import helpers as h, diffs, codeblocks, channelstream
35 from rhodecode.lib.base import vcs_operation_context
35 from rhodecode.lib.base import vcs_operation_context
36 from rhodecode.lib.diffs import load_cached_diff, cache_diff, diff_cache_exist
36 from rhodecode.lib.diffs import load_cached_diff, cache_diff, diff_cache_exist
37 from rhodecode.lib.exceptions import CommentVersionMismatch
37 from rhodecode.lib.ext_json import json
38 from rhodecode.lib.ext_json import json
38 from rhodecode.lib.auth import (
39 from rhodecode.lib.auth import (
39 LoginRequired, HasRepoPermissionAny, HasRepoPermissionAnyDecorator,
40 LoginRequired, HasRepoPermissionAny, HasRepoPermissionAnyDecorator,
@@ -1528,6 +1529,8 b' class RepoPullRequestsView(RepoAppView, '
1528 route_name='pullrequest_comment_edit', request_method='POST',
1529 route_name='pullrequest_comment_edit', request_method='POST',
1529 renderer='json_ext')
1530 renderer='json_ext')
1530 def pull_request_comment_edit(self):
1531 def pull_request_comment_edit(self):
1532 self.load_default_context()
1533
1531 pull_request = PullRequest.get_or_404(
1534 pull_request = PullRequest.get_or_404(
1532 self.request.matchdict['pull_request_id']
1535 self.request.matchdict['pull_request_id']
1533 )
1536 )
@@ -1566,11 +1569,12 b' class RepoPullRequestsView(RepoAppView, '
1566 log.warning(
1569 log.warning(
1567 'Comment(PR): '
1570 'Comment(PR): '
1568 'Trying to create new version '
1571 'Trying to create new version '
1569 'of existing comment {}'.format(
1572 'with the same comment body {}'.format(
1570 comment_id,
1573 comment_id,
1571 )
1574 )
1572 )
1575 )
1573 raise HTTPNotFound()
1576 raise HTTPNotFound()
1577
1574 if version.isdigit():
1578 if version.isdigit():
1575 version = int(version)
1579 version = int(version)
1576 else:
1580 else:
@@ -1584,24 +1588,30 b' class RepoPullRequestsView(RepoAppView, '
1584 )
1588 )
1585 raise HTTPNotFound()
1589 raise HTTPNotFound()
1586
1590
1587 comment_history = CommentsModel().edit(
1591 try:
1588 comment_id=comment_id,
1592 comment_history = CommentsModel().edit(
1589 text=text,
1593 comment_id=comment_id,
1590 auth_user=self._rhodecode_user,
1594 text=text,
1591 version=version,
1595 auth_user=self._rhodecode_user,
1592 )
1596 version=version,
1597 )
1598 except CommentVersionMismatch:
1599 raise HTTPConflict()
1600
1593 if not comment_history:
1601 if not comment_history:
1594 raise HTTPNotFound()
1602 raise HTTPNotFound()
1603
1595 Session().commit()
1604 Session().commit()
1596 return {
1605 return {
1597 'comment_history_id': comment_history.comment_history_id,
1606 'comment_history_id': comment_history.comment_history_id,
1598 'comment_id': comment.comment_id,
1607 'comment_id': comment.comment_id,
1599 'comment_version': comment_history.version,
1608 'comment_version': comment_history.version,
1609 'comment_author_username': comment_history.author.username,
1610 'comment_author_gravatar': h.gravatar_url(comment_history.author.email, 16),
1611 'comment_created_on': h.age_component(comment_history.created_on,
1612 time_is_local=True),
1600 }
1613 }
1601 else:
1614 else:
1602 log.warning(
1615 log.warning('No permissions for user %s to edit comment_id: %s',
1603 'No permissions for user {} to edit comment_id: {}'.format(
1616 self._rhodecode_db_user, comment_id)
1604 self._rhodecode_db_user, comment_id
1605 )
1606 )
1607 raise HTTPNotFound()
1617 raise HTTPNotFound()
@@ -177,3 +177,7 b' class ArtifactMetadataDuplicate(ValueErr'
177
177
178 class ArtifactMetadataBadValueType(ValueError):
178 class ArtifactMetadataBadValueType(ValueError):
179 pass
179 pass
180
181
182 class CommentVersionMismatch(ValueError):
183 pass
@@ -24,6 +24,7 b' Helper functions'
24 Consists of functions to typically be used within templates, but also
24 Consists of functions to typically be used within templates, but also
25 available to Controllers. This module is available to both as 'h'.
25 available to Controllers. This module is available to both as 'h'.
26 """
26 """
27 import base64
27
28
28 import os
29 import os
29 import random
30 import random
@@ -1352,7 +1353,7 b' class InitialsGravatar(object):'
1352
1353
1353 def generate_svg(self, svg_type=None):
1354 def generate_svg(self, svg_type=None):
1354 img_data = self.get_img_data(svg_type)
1355 img_data = self.get_img_data(svg_type)
1355 return "data:image/svg+xml;base64,%s" % img_data.encode('base64')
1356 return "data:image/svg+xml;base64,%s" % base64.b64encode(img_data)
1356
1357
1357
1358
1358 def initials_gravatar(email_address, first_name, last_name, size=30):
1359 def initials_gravatar(email_address, first_name, last_name, size=30):
@@ -33,6 +33,7 b' from sqlalchemy.sql.functions import coa'
33
33
34 from rhodecode.lib import helpers as h, diffs, channelstream, hooks_utils
34 from rhodecode.lib import helpers as h, diffs, channelstream, hooks_utils
35 from rhodecode.lib import audit_logger
35 from rhodecode.lib import audit_logger
36 from rhodecode.lib.exceptions import CommentVersionMismatch
36 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str
37 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str
37 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
38 from rhodecode.model.db import (
39 from rhodecode.model.db import (
@@ -507,13 +508,13 b' class CommentsModel(BaseModel):'
507 comment_version = ChangesetCommentHistory.get_version(comment_id)
508 comment_version = ChangesetCommentHistory.get_version(comment_id)
508 if (comment_version - version) != 1:
509 if (comment_version - version) != 1:
509 log.warning(
510 log.warning(
510 'Version mismatch, skipping... '
511 'Version mismatch comment_version {} submitted {}, skipping'.format(
511 'version {} but should be {}'.format(
512 (version - 1),
513 comment_version,
512 comment_version,
513 version
514 )
514 )
515 )
515 )
516 return
516 raise CommentVersionMismatch()
517
517 comment_history = ChangesetCommentHistory()
518 comment_history = ChangesetCommentHistory()
518 comment_history.comment_id = comment_id
519 comment_history.comment_id = comment_id
519 comment_history.version = comment_version
520 comment_history.version = comment_version
@@ -148,6 +148,38 b' select.select2{height:28px;visibility:hi'
148 margin: 0;
148 margin: 0;
149 }
149 }
150
150
151
152 .drop-menu-comment-history {
153 .drop-menu-core;
154 border: none;
155 padding: 0 6px 0 0;
156 width: auto;
157 min-width: 0;
158 margin: 0;
159 position: relative;
160 display: inline-block;
161 line-height: 1em;
162 z-index: 2;
163 cursor: pointer;
164
165 a {
166 display:block;
167 padding: 0;
168 position: relative;
169
170 &:after {
171 position: absolute;
172 content: "\00A0\25BE";
173 right: -0.80em;
174 line-height: 1em;
175 top: -0.20em;
176 width: 1em;
177 font-size: 16px;
178 }
179 }
180
181 }
182
151 .field-sm .drop-menu {
183 .field-sm .drop-menu {
152 padding: 1px 0 0 0;
184 padding: 1px 0 0 0;
153 a {
185 a {
@@ -496,6 +496,43 b' var _submitAjaxPOST = function(url, post'
496 return CommentForm;
496 return CommentForm;
497 });
497 });
498
498
499 /* selector for comment versions */
500 var initVersionSelector = function(selector, initialData) {
501
502 var formatResult = function(result, container, query, escapeMarkup) {
503
504 return renderTemplate('commentVersion', {
505 show_disabled: true,
506 version: result.comment_version,
507 user_name: result.comment_author_username,
508 gravatar_url: result.comment_author_gravatar,
509 size: 16,
510 timeago_component: result.comment_created_on,
511 })
512 };
513
514 $(selector).select2({
515 placeholder: "Edited",
516 containerCssClass: "drop-menu-comment-history",
517 dropdownCssClass: "drop-menu-dropdown",
518 dropdownAutoWidth: true,
519 minimumResultsForSearch: -1,
520 data: initialData,
521 formatResult: formatResult,
522 });
523
524 $(selector).on('select2-selecting', function (e) {
525 // hide the mast as we later do preventDefault()
526 $("#select2-drop-mask").click();
527 e.preventDefault();
528 e.choice.action();
529 });
530
531 $(selector).on("select2-open", function() {
532 timeagoActivate();
533 });
534 };
535
499 /* comments controller */
536 /* comments controller */
500 var CommentsController = function() {
537 var CommentsController = function() {
501 var mainComment = '#text';
538 var mainComment = '#text';
@@ -521,21 +558,8 b' var CommentsController = function() {'
521 return false;
558 return false;
522 };
559 };
523
560
524 this.showVersion = function (node) {
561 this.showVersion = function (comment_id, comment_history_id) {
525 var $node = $(node);
526 var selectedIndex = $node.context.selectedIndex;
527 var option = $node.find('option[value="'+ selectedIndex +'"]');
528 var zero_option = $node.find('option[value="0"]');
529 if (!option){
530 return;
531 }
532
562
533 // little trick to cheat onchange and allow to display the same version again
534 $node.context.selectedIndex = 0;
535 zero_option.text(selectedIndex);
536
537 var comment_history_id = option.attr('data-comment-history-id');
538 var comment_id = option.attr('data-comment-id');
539 var historyViewUrl = pyroutes.url(
563 var historyViewUrl = pyroutes.url(
540 'repo_commit_comment_history_view',
564 'repo_commit_comment_history_view',
541 {
565 {
@@ -557,7 +581,8 b' var CommentsController = function() {'
557 });
581 });
558 };
582 };
559 _submitAjaxPOST(
583 _submitAjaxPOST(
560 historyViewUrl, {'csrf_token': CSRF_TOKEN}, successRenderCommit,
584 historyViewUrl, {'csrf_token': CSRF_TOKEN},
585 successRenderCommit,
561 failRenderCommit
586 failRenderCommit
562 );
587 );
563 };
588 };
@@ -863,6 +888,7 b' var CommentsController = function() {'
863
888
864 return commentForm;
889 return commentForm;
865 };
890 };
891
866 this.editComment = function(node) {
892 this.editComment = function(node) {
867 var $node = $(node);
893 var $node = $(node);
868 var $comment = $(node).closest('.comment');
894 var $comment = $(node).closest('.comment');
@@ -917,15 +943,16 b' var CommentsController = function() {'
917 lineno: lineno,
943 lineno: lineno,
918 f_path: f_path}
944 f_path: f_path}
919 );
945 );
946
920 // set a CUSTOM submit handler for inline comments.
947 // set a CUSTOM submit handler for inline comments.
921 commentForm.setHandleFormSubmit(function(o) {
948 commentForm.setHandleFormSubmit(function(o) {
922 var text = commentForm.cm.getValue();
949 var text = commentForm.cm.getValue();
923 var commentType = commentForm.getCommentType();
950 var commentType = commentForm.getCommentType();
924 var resolvesCommentId = commentForm.getResolvesId();
925
951
926 if (text === "") {
952 if (text === "") {
927 return;
953 return;
928 }
954 }
955
929 if (old_comment_text == text) {
956 if (old_comment_text == text) {
930 SwalNoAnimation.fire({
957 SwalNoAnimation.fire({
931 title: 'Unable to edit comment',
958 title: 'Unable to edit comment',
@@ -937,19 +964,22 b' var CommentsController = function() {'
937 var submitEvent = true;
964 var submitEvent = true;
938 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
965 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
939 commentForm.cm.setOption("readOnly", true);
966 commentForm.cm.setOption("readOnly", true);
940 var dropDown = $('#comment_history_for_comment_'+comment_id);
967
968 // Read last version known
969 var versionSelector = $('#comment_versions_{0}'.format(comment_id));
970 var version = versionSelector.data('lastVersion');
941
971
942 var version = dropDown.children().last().val()
972 if (!version) {
943 if(!version){
973 version = 0;
944 version = 0;
945 }
974 }
975
946 var postData = {
976 var postData = {
947 'text': text,
977 'text': text,
948 'f_path': f_path,
978 'f_path': f_path,
949 'line': lineno,
979 'line': lineno,
950 'comment_type': commentType,
980 'comment_type': commentType,
951 'csrf_token': CSRF_TOKEN,
952 'version': version,
981 'version': version,
982 'csrf_token': CSRF_TOKEN
953 };
983 };
954
984
955 var submitSuccessCallback = function(json_data) {
985 var submitSuccessCallback = function(json_data) {
@@ -961,32 +991,61 b' var CommentsController = function() {'
961 'csrf_token': CSRF_TOKEN
991 'csrf_token': CSRF_TOKEN
962 };
992 };
963
993
994 /* Inject new edited version selector */
964 var updateCommentVersionDropDown = function () {
995 var updateCommentVersionDropDown = function () {
965 var dropDown = $('#comment_history_for_comment_'+comment_id);
996 var versionSelectId = '#comment_versions_'+comment_id;
997 var preLoadVersionData = [
998 {
999 id: json_data['comment_version'],
1000 text: "v{0}".format(json_data['comment_version']),
1001 action: function () {
1002 Rhodecode.comments.showVersion(
1003 json_data['comment_id'],
1004 json_data['comment_history_id']
1005 )
1006 },
1007 comment_version: json_data['comment_version'],
1008 comment_author_username: json_data['comment_author_username'],
1009 comment_author_gravatar: json_data['comment_author_gravatar'],
1010 comment_created_on: json_data['comment_created_on'],
1011 },
1012 ]
1013
1014
1015 if ($(versionSelectId).data('select2')) {
1016 var oldData = $(versionSelectId).data('select2').opts.data.results;
1017 $(versionSelectId).select2("destroy");
1018 preLoadVersionData = oldData.concat(preLoadVersionData)
1019 }
1020
1021 initVersionSelector(versionSelectId, {results: preLoadVersionData});
1022
966 $comment.attr('data-comment-text', btoa(text));
1023 $comment.attr('data-comment-text', btoa(text));
967 var version = json_data['comment_version']
1024
968 var option = new Option(version, version);
1025 var versionSelector = $('#comment_versions_'+comment_id);
969 var $option = $(option);
1026
970 $option.attr('data-comment-history-id', json_data['comment_history_id']);
1027 // set lastVersion so we know our last edit version
971 $option.attr('data-comment-id', json_data['comment_id']);
1028 versionSelector.data('lastVersion', json_data['comment_version'])
972 dropDown.append(option);
1029 versionSelector.parent().show();
973 dropDown.parent().show();
974 }
1030 }
975 updateCommentVersionDropDown();
1031 updateCommentVersionDropDown();
1032
976 // by default we reset state of comment preserving the text
1033 // by default we reset state of comment preserving the text
977 var failRenderCommit = function(jqXHR, textStatus, errorThrown) {
1034 var failRenderCommit = function(jqXHR, textStatus, errorThrown) {
978 var prefix = "Error while editing of comment.\n"
1035 var prefix = "Error while editing this comment.\n"
979 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1036 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
980 ajaxErrorSwal(message);
1037 ajaxErrorSwal(message);
1038 };
981
1039
982 };
983 var successRenderCommit = function(o){
1040 var successRenderCommit = function(o){
984 $comment.show();
1041 $comment.show();
985 $comment[0].lastElementChild.innerHTML = o;
1042 $comment[0].lastElementChild.innerHTML = o;
986 }
1043 };
987 var previewUrl = pyroutes.url('repo_commit_comment_preview',
1044
988 {'repo_name': templateContext.repo_name,
1045 var previewUrl = pyroutes.url(
989 'commit_id': templateContext.commit_data.commit_id});
1046 'repo_commit_comment_preview',
1047 {'repo_name': templateContext.repo_name,
1048 'commit_id': templateContext.commit_data.commit_id});
990
1049
991 _submitAjaxPOST(
1050 _submitAjaxPOST(
992 previewUrl, postData, successRenderCommit,
1051 previewUrl, postData, successRenderCommit,
@@ -1000,11 +1059,6 b' var CommentsController = function() {'
1000
1059
1001 $comments.find('.cb-comment-add-button').before(html);
1060 $comments.find('.cb-comment-add-button').before(html);
1002
1061
1003 //mark visually which comment was resolved
1004 if (resolvesCommentId) {
1005 commentForm.markCommentResolved(resolvesCommentId);
1006 }
1007
1008 // run global callback on submit
1062 // run global callback on submit
1009 commentForm.globalSubmitSuccessCallback();
1063 commentForm.globalSubmitSuccessCallback();
1010
1064
@@ -1029,16 +1083,25 b' var CommentsController = function() {'
1029 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1083 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1030 var prefix = "Error while editing comment.\n"
1084 var prefix = "Error while editing comment.\n"
1031 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1085 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1032 ajaxErrorSwal(message);
1086 if (jqXHR.status == 409){
1087 message = 'This comment was probably changed somewhere else. Please reload the content of this comment.'
1088 ajaxErrorSwal(message, 'Comment version mismatch.');
1089 } else {
1090 ajaxErrorSwal(message);
1091 }
1092
1033 commentForm.resetCommentFormState(text)
1093 commentForm.resetCommentFormState(text)
1034 };
1094 };
1035 commentForm.submitAjaxPOST(
1095 commentForm.submitAjaxPOST(
1036 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
1096 commentForm.submitUrl, postData,
1097 submitSuccessCallback,
1098 submitFailCallback);
1037 });
1099 });
1038 }
1100 }
1039
1101
1040 $form.addClass('comment-inline-form-open');
1102 $form.addClass('comment-inline-form-open');
1041 };
1103 };
1104
1042 this.createComment = function(node, resolutionComment) {
1105 this.createComment = function(node, resolutionComment) {
1043 var resolvesCommentId = resolutionComment || null;
1106 var resolvesCommentId = resolutionComment || null;
1044 var $node = $(node);
1107 var $node = $(node);
@@ -130,10 +130,13 b' function formatErrorMessage(jqXHR, textS'
130 }
130 }
131 }
131 }
132
132
133 function ajaxErrorSwal(message) {
133 function ajaxErrorSwal(message, title) {
134
135 var title = (typeof title !== 'undefined') ? title : _gettext('Ajax Request Error');
136
134 SwalNoAnimation.fire({
137 SwalNoAnimation.fire({
135 icon: 'error',
138 icon: 'error',
136 title: _gettext('Ajax Request Error'),
139 title: title,
137 html: '<span style="white-space: pre-line">{0}</span>'.format(message),
140 html: '<span style="white-space: pre-line">{0}</span>'.format(message),
138 showClass: {
141 showClass: {
139 popup: 'swal2-noanimation',
142 popup: 'swal2-noanimation',
@@ -66,31 +66,47 b''
66 <div class="date">
66 <div class="date">
67 ${h.age_component(comment.modified_at, time_is_local=True)}
67 ${h.age_component(comment.modified_at, time_is_local=True)}
68 </div>
68 </div>
69 <%
70 comment_version_selector = 'comment_versions_{}'.format(comment.comment_id)
71 %>
72
69 % if comment.history:
73 % if comment.history:
70 <div class="date">
74 <div class="date">
71 <span class="comment-area-text">${_('Edited')}:</span>
75
72 <select class="comment-version-select" id="comment_history_for_comment_${comment.comment_id}"
76 <input id="${comment_version_selector}" name="${comment_version_selector}"
73 onchange="return Rhodecode.comments.showVersion(this)"
77 type="hidden"
74 name="comment_type">
78 data-last-version="${comment.history[-1].version}">
79
80 <script type="text/javascript">
75
81
76 <option style="display: none" value="0">---</option>
82 var preLoadVersionData = [
77 % for comment_history in comment.history:
83 % for comment_history in comment.history:
78 <option data-comment-history-id="${comment_history.comment_history_id}"
84 {
79 data-comment-id="${comment.comment_id}"
85 id: ${comment_history.comment_history_id},
80 value="${comment_history.version}">
86 text: 'v${comment_history.version}',
81 ${comment_history.version}
87 action: function () {
82 </option>
88 Rhodecode.comments.showVersion(
83 % endfor
89 "${comment.comment_id}",
84 </select>
90 "${comment_history.comment_history_id}"
91 )
92 },
93 comment_version: "${comment_history.version}",
94 comment_author_username: "${comment_history.author.username}",
95 comment_author_gravatar: "${h.gravatar_url(comment_history.author.email, 16)}",
96 comment_created_on: '${h.age_component(comment_history.created_on, time_is_local=True)}',
97 },
98 % endfor
99 ]
100 initVersionSelector("#${comment_version_selector}", {results: preLoadVersionData});
101
102 </script>
103
85 </div>
104 </div>
86 % else:
105 % else:
87 <div class="date" style="display: none">
106 <div class="date" style="display: none">
88 <span class="comment-area-text">${_('Edited')}</span>
107 <input id="${comment_version_selector}" name="${comment_version_selector}"
89 <select class="comment-version-select" id="comment_history_for_comment_${comment.comment_id}"
108 type="hidden"
90 onchange="return Rhodecode.comments.showVersion(this)"
109 data-last-version="0">
91 name="comment_type">
92 <option style="display: none" value="0">---</option>
93 </select>
94 </div>
110 </div>
95 %endif
111 %endif
96 % if inline:
112 % if inline:
@@ -169,12 +185,8 b''
169 %if not outdated_at_ver and (not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed())):
185 %if not outdated_at_ver and (not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed())):
170 ## permissions to delete
186 ## permissions to delete
171 %if comment.immutable is False and (c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id):
187 %if comment.immutable is False and (c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id):
172 %if comment.comment_type == 'note':
173 <a onclick="return Rhodecode.comments.editComment(this);"
188 <a onclick="return Rhodecode.comments.editComment(this);"
174 class="edit-comment">${_('Edit')}</a>
189 class="edit-comment">${_('Edit')}</a>
175 %else:
176 <a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Edit')}</a>
177 %endif
178 | <a onclick="return Rhodecode.comments.deleteComment(this);"
190 | <a onclick="return Rhodecode.comments.deleteComment(this);"
179 class="delete-comment">${_('Delete')}</a>
191 class="delete-comment">${_('Delete')}</a>
180 %else:
192 %else:
@@ -130,6 +130,34 b' var CG = new ColorGenerator();'
130 </script>
130 </script>
131
131
132
132
133 <script id="ejs_commentVersion" type="text/template" class="ejsTemplate">
134
135 <%
136 if (size > 16) {
137 var gravatar_class = 'gravatar gravatar-large';
138 } else {
139 var gravatar_class = 'gravatar';
140 }
141
142 %>
143
144 <%
145 if (show_disabled) {
146 var user_cls = 'user user-disabled';
147 } else {
148 var user_cls = 'user';
149 }
150
151 %>
152
153 <div style='line-height: 20px'>
154 <img style="margin: -3px 0" class="<%= gravatar_class %>" height="<%= size %>" width="<%= size %>" src="<%- gravatar_url -%>">
155 <strong><%- user_name -%></strong>, <code>v<%- version -%></code> edited <%- timeago_component -%>
156 </div>
157
158 </script>
159
160
133 </div>
161 </div>
134
162
135 <script>
163 <script>
General Comments 0
You need to be logged in to leave comments. Login now