diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -1066,6 +1066,12 @@ def make_map(config): f_path='', annotate=True, conditions={'function': check_repo}, requirements=URL_NAME_REQUIREMENTS, jsroute=True) + rmap.connect('files_annotate_previous', + '/{repo_name}/annotate-previous/{revision}/{f_path}', + controller='files', action='annotate_previous', revision='tip', + f_path='', annotate=True, conditions={'function': check_repo}, + requirements=URL_NAME_REQUIREMENTS, jsroute=True) + rmap.connect('files_edit', '/{repo_name}/edit/{revision}/{f_path}', controller='files', action='edit', revision='tip', diff --git a/rhodecode/controllers/files.py b/rhodecode/controllers/files.py --- a/rhodecode/controllers/files.py +++ b/rhodecode/controllers/files.py @@ -260,6 +260,32 @@ class FilesController(BaseRepoController return render('files/files.mako') @LoginRequired() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') + def annotate_previous(self, repo_name, revision, f_path): + + commit_id = revision + commit = self.__get_commit_or_redirect(commit_id, repo_name) + prev_commit_id = commit.raw_id + + f_path = f_path + is_file = False + try: + _file = commit.get_node(f_path) + is_file = _file.is_file() + except (NodeDoesNotExistError, CommitDoesNotExistError, VCSError): + pass + + if is_file: + history = commit.get_file_history(f_path) + prev_commit_id = history[1].raw_id \ + if len(history) > 1 else prev_commit_id + + return redirect(h.url( + 'files_annotate_home', repo_name=repo_name, + revision=prev_commit_id, f_path=f_path)) + + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') @jsonify diff --git a/rhodecode/public/css/code-block.less b/rhodecode/public/css/code-block.less --- a/rhodecode/public/css/code-block.less +++ b/rhodecode/public/css/code-block.less @@ -1105,6 +1105,7 @@ table.cb { } &.cb-annotate-message-spacer { width:8px; + padding: 1px 0px 0px 3px; } &.cb-annotate-info { width: 320px; diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -49,6 +49,7 @@ function registerRCRoutes() { pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('files_annotate_previous', '/%(repo_name)s/annotate-previous/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); diff --git a/rhodecode/templates/codeblocks/source.mako b/rhodecode/templates/codeblocks/source.mako --- a/rhodecode/templates/codeblocks/source.mako +++ b/rhodecode/templates/codeblocks/source.mako @@ -20,7 +20,11 @@ ${h.gravatar_with_user(annotation.author, 16) | n}
${h.chop_at_smart(annotation.message, '\n', suffix_if_chopped='...')}
- + + + + + +var AnnotationController = function() { + var self = this; + this.previousAnnotation = function(commitId, fPath) { + var params = { + 'repo_name': templateContext.repo_name, + 'revision': commitId, + 'f_path': fPath + }; + window.location = pyroutes.url('files_annotate_previous', params); + return false; + }; +}; +var annotationController = new AnnotationController(); +