Changeset - e74557f57f76
[Not reviewed]
beta
0 2 0
Marcin Kuzminski - 13 years ago 2013-03-03 23:35:39
marcin@python-works.com
whitespace cleanup
2 files changed with 2 insertions and 2 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/pullrequests.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.pullrequests
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    pull requests controller for rhodecode for initializing pull requests
 

	
 
    :created_on: May 7, 2012
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import logging
 
import traceback
 
import formencode
 

	
 
from webob.exc import HTTPNotFound, HTTPForbidden
 
from collections import defaultdict
 
from itertools import groupby
 

	
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
 
    NotAnonymous
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib import diffs
 
from rhodecode.lib.utils import action_logger, jsonify
 
from rhodecode.lib.vcs.exceptions import EmptyRepositoryError
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.diffs import LimitedDiffContainer
 
from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
 
    ChangesetComment
 
from rhodecode.model.pull_request import PullRequestModel
 
from rhodecode.model.meta import Session
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.comment import ChangesetCommentsModel
 
from rhodecode.model.changeset_status import ChangesetStatusModel
 
from rhodecode.model.forms import PullRequestForm
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PullrequestsController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        super(PullrequestsController, self).__before__()
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
    def _get_repo_refs(self, repo, rev=None):
 
        """return a structure with repo's interesting changesets, suitable for
 
        the selectors in pullrequest.html"""
 
        branches = [('branch:%s:%s' % (k, v), k)
 
                    for k, v in repo.branches.iteritems()]
 
        bookmarks = [('book:%s:%s' % (k, v), k)
 
                     for k, v in repo.bookmarks.iteritems()]
 
        tags = [('tag:%s:%s' % (k, v), k)
 
                for k, v in repo.tags.iteritems()
 
                if k != 'tip']
 

	
 
        tip = repo.tags['tip']
 
        colontip = ':' + tip
 
        tips = [x[1] for x in branches + bookmarks + tags
 
                if x[0].endswith(colontip)]
 
        selected = 'tag:tip:%s' % tip
 
        special = [(selected, 'tip (%s)' % ', '.join(tips))]
 

	
 
        if rev:
 
            selected = 'rev:%s:%s' % (rev, rev)
 
            special.append((selected, rev))            
 
            special.append((selected, rev))
 

	
 
        return [(special, _("Special")),
 
                (bookmarks, _("Bookmarks")),
 
                (branches, _("Branches")),
 
                (tags, _("Tags")),
 
                ], selected
 

	
 
    def _get_is_allowed_change_status(self, pull_request):
 
        owner = self.rhodecode_user.user_id == pull_request.user_id
 
        reviewer = self.rhodecode_user.user_id in [x.user_id for x in
 
                                                   pull_request.reviewers]
 
        return (self.rhodecode_user.admin or owner or reviewer)
 

	
 
    def show_all(self, repo_name):
 
        c.pull_requests = PullRequestModel().get_all(repo_name)
 
        c.repo_name = repo_name
 
        return render('/pullrequests/pullrequest_show_all.html')
 

	
 
    @NotAnonymous()
 
    def index(self):
 
        org_repo = c.rhodecode_db_repo
 

	
 
        if org_repo.scm_instance.alias != 'hg':
 
            log.error('Review not available for GIT REPOS')
 
            raise HTTPNotFound
 

	
 
        try:
 
            org_repo.scm_instance.get_changeset()
 
        except EmptyRepositoryError, e:
 
            h.flash(h.literal(_('There are no changesets yet')),
 
                    category='warning')
 
            redirect(url('summary_home', repo_name=org_repo.repo_name))
 

	
 
        other_repos_info = {}
 

	
 
        c.org_repos = []
 
        c.org_repos.append((org_repo.repo_name, org_repo.repo_name))
 
        c.default_org_repo = org_repo.repo_name
 
        c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance)
 

	
 
        c.other_repos = []
 
        # add org repo to other so we can open pull request against itself
 
        c.other_repos.extend(c.org_repos)
 
        c.default_other_repo = org_repo.repo_name
 
        c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.scm_instance)
 
        usr_data = lambda usr: dict(user_id=usr.user_id,
 
                                    username=usr.username,
 
                                    firstname=usr.firstname,
 
                                    lastname=usr.lastname,
 
                                    gravatar_link=h.gravatar_url(usr.email, 14))
 
        other_repos_info[org_repo.repo_name] = {
 
            'user': usr_data(org_repo.user),
 
            'description': org_repo.description,
 
            'revs': h.select('other_ref', c.default_other_ref,
 
                             c.default_other_refs, class_='refs')
 
        }
 

	
 
        # gather forks and add to this list ... even though it is rare to
 
        # request forks to pull their parent
 
        for fork in org_repo.forks:
 
            c.other_repos.append((fork.repo_name, fork.repo_name))
 
            refs, default_ref = self._get_repo_refs(fork.scm_instance)
 
            other_repos_info[fork.repo_name] = {
 
                'user': usr_data(fork.user),
 
                'description': fork.description,
 
                'revs': h.select('other_ref', default_ref, refs, class_='refs')
 
            }
 

	
 
        # add parents of this fork also, but only if it's not empty
 
        if org_repo.parent and org_repo.parent.scm_instance.revisions:
 
            c.default_other_repo = org_repo.parent.repo_name
 
            c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.parent.scm_instance)
 
            c.other_repos.append((org_repo.parent.repo_name, org_repo.parent.repo_name))
 
            other_repos_info[org_repo.parent.repo_name] = {
 
                'user': usr_data(org_repo.parent.user),
 
                'description': org_repo.parent.description,
 
                'revs': h.select('other_ref', c.default_other_ref,
 
                                 c.default_other_refs, class_='refs')
 
            }
 

	
 
        c.other_repos_info = json.dumps(other_repos_info)
 
        # other repo owner
 
        c.review_members = []
 
        return render('/pullrequests/pullrequest.html')
 

	
 
    @NotAnonymous()
 
    def create(self, repo_name):
 
        repo = RepoModel()._get_repo(repo_name)
 
        try:
 
            _form = PullRequestForm(repo.repo_id)().to_python(request.POST)
 
        except formencode.Invalid, errors:
 
            log.error(traceback.format_exc())
 
            if errors.error_dict.get('revisions'):
 
                msg = 'Revisions: %s' % errors.error_dict['revisions']
 
            elif errors.error_dict.get('pullrequest_title'):
 
                msg = _('Pull request requires a title with min. 3 chars')
 
            else:
 
                msg = _('error during creation of pull request')
 

	
 
            h.flash(msg, 'error')
 
            return redirect(url('pullrequest_home', repo_name=repo_name))
 

	
 
        org_repo = _form['org_repo']
 
        org_ref = _form['org_ref']
 
        other_repo = _form['other_repo']
 
        other_ref = _form['other_ref']
 
        revisions = _form['revisions']
 
        reviewers = _form['review_members']
 

	
 
        # if we have cherry picked pull request we don't care what is in
 
        # org_ref/other_ref
 
        rev_start = request.POST.get('rev_start')
 
        rev_end = request.POST.get('rev_end')
 

	
 
        if rev_start and rev_end:
 
            # this is swapped to simulate that rev_end is a revision from
 
            # parent of the fork
 
            org_ref = 'rev:%s:%s' % (rev_end, rev_end)
 
            other_ref = 'rev:%s:%s' % (rev_start, rev_start)
 

	
 
        title = _form['pullrequest_title']
 
        description = _form['pullrequest_desc']
 

	
 
        try:
 
            pull_request = PullRequestModel().create(
 
                self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
 
                other_ref, revisions, reviewers, title, description
 
            )
 
            Session().commit()
 
            h.flash(_('Successfully opened new pull request'),
 
                    category='success')
 
        except Exception:
 
            h.flash(_('Error occurred during sending pull request'),
 
                    category='error')
 
            log.error(traceback.format_exc())
 
            return redirect(url('pullrequest_home', repo_name=repo_name))
 

	
 
        return redirect(url('pullrequest_show', repo_name=other_repo,
 
                            pull_request_id=pull_request.pull_request_id))
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def update(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        if pull_request.is_closed():
 
            raise HTTPForbidden()
 
        #only owner or admin can update it
 
        owner = pull_request.author.user_id == c.rhodecode_user.user_id
 
        if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
 
            reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
 
                       request.POST.get('reviewers_ids', '').split(',')))
 

	
 
            PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
 
            Session().commit()
 
            return True
 
        raise HTTPForbidden()
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def delete(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        #only owner can delete it !
 
        if pull_request.author.user_id == c.rhodecode_user.user_id:
 
            PullRequestModel().delete(pull_request)
 
            Session().commit()
 
            h.flash(_('Successfully deleted pull request'),
 
                    category='success')
 
            return redirect(url('admin_settings_my_account', anchor='pullrequests'))
 
        raise HTTPForbidden()
 

	
 
    def _load_compare_data(self, pull_request, enable_comments=True):
 
        """
 
        Load context data needed for generating compare diff
 

	
 
        :param pull_request:
 
        :type pull_request:
 
        """
 
        rev_start = request.GET.get('rev_start')
 
        rev_end = request.GET.get('rev_end')
 

	
 
        org_repo = pull_request.org_repo
 
        (org_ref_type,
 
         org_ref_name,
 
         org_ref_rev) = pull_request.org_ref.split(':')
 

	
 
        other_repo = org_repo
 
        (other_ref_type,
 
         other_ref_name,
 
         other_ref_rev) = pull_request.other_ref.split(':')
 

	
 
        # despite opening revisions for bookmarks/branches/tags, we always
 
        # convert this to rev to prevent changes after book or branch change
 
        org_ref = ('rev', org_ref_rev)
 
        other_ref = ('rev', other_ref_rev)
 

	
 
        c.org_repo = org_repo
 
        c.other_repo = other_repo
 

	
 
        c.fulldiff = fulldiff = request.GET.get('fulldiff')
 

	
 
        c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
 

	
 
        other_ref = ('rev', getattr(c.cs_ranges[0].parents[0]
 
                                  if c.cs_ranges[0].parents
 
                                  else EmptyChangeset(), 'raw_id'))
 

	
 
        c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
 

	
 
        c.org_ref = org_ref[1]
 
        c.org_ref_type = org_ref[0]
 
        c.other_ref = other_ref[1]
 
        c.other_ref_type = other_ref[0]
 

	
 
        diff_limit = self.cut_off_limit if not fulldiff else None
 

	
 
        #we swap org/other ref since we run a simple diff on one repo
 
        _diff = diffs.differ(org_repo, other_ref, other_repo, org_ref)
 

	
 
        diff_processor = diffs.DiffProcessor(_diff or '', format='gitdiff',
 
                                             diff_limit=diff_limit)
 
        _parsed = diff_processor.prepare()
 

	
 
        c.limited_diff = False
 
        if isinstance(_parsed, LimitedDiffContainer):
 
            c.limited_diff = True
 

	
 
        c.files = []
 
        c.changes = {}
 
        c.lines_added = 0
 
        c.lines_deleted = 0
 
        for f in _parsed:
 
            st = f['stats']
 
            if st[0] != 'b':
 
                c.lines_added += st[0]
 
                c.lines_deleted += st[1]
 
            fid = h.FID('', f['filename'])
 
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
 
            diff = diff_processor.as_html(enable_comments=enable_comments,
 
                                          parsed_lines=[f])
 
            c.changes[fid] = [f['operation'], f['filename'], diff]
 

	
 
    def show(self, repo_name, pull_request_id):
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 
        c.pull_request = PullRequest.get_or_404(pull_request_id)
 
        c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
 
        cc_model = ChangesetCommentsModel()
 
        cs_model = ChangesetStatusModel()
 
        _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
 
                                            pull_request=c.pull_request,
 
                                            with_revisions=True)
 

	
 
        cs_statuses = defaultdict(list)
 
        for st in _cs_statuses:
 
            cs_statuses[st.author.username] += [st]
 

	
 
        c.pull_request_reviewers = []
 
        c.pull_request_pending_reviewers = []
 
        for o in c.pull_request.reviewers:
 
            st = cs_statuses.get(o.user.username, None)
 
            if st:
 
                sorter = lambda k: k.version
 
                st = [(x, list(y)[0])
 
                      for x, y in (groupby(sorted(st, key=sorter), sorter))]
 
            else:
 
                c.pull_request_pending_reviewers.append(o.user)
 
            c.pull_request_reviewers.append([o.user, st])
 

	
 
        # pull_requests repo_name we opened it against
 
        # ie. other_repo must match
 
        if repo_name != c.pull_request.other_repo.repo_name:
 
            raise HTTPNotFound
 

	
 
        # load compare data into template context
 
        enable_comments = not c.pull_request.is_closed()
 
        self._load_compare_data(c.pull_request, enable_comments=enable_comments)
 

	
 
        # inline comments
 
        c.inline_cnt = 0
 
        c.inline_comments = cc_model.get_inline_comments(
 
                                c.rhodecode_db_repo.repo_id,
 
                                pull_request=pull_request_id)
 
        # count inline comments
 
        for __, lines in c.inline_comments:
 
            for comments in lines.values():
 
                c.inline_cnt += len(comments)
 
        # comments
 
        c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
 
                                           pull_request=pull_request_id)
 

	
 
        try:
 
            cur_status = c.statuses[c.pull_request.revisions[0]][0]
 
        except:
 
            log.error(traceback.format_exc())
 
            cur_status = 'undefined'
 
        if c.pull_request.is_closed() and 0:
 
            c.current_changeset_status = cur_status
 
        else:
 
            # changeset(pull-request) status calulation based on reviewers
 
            c.current_changeset_status = cs_model.calculate_status(
 
                                            c.pull_request_reviewers,
 
                                         )
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 

	
 
        c.as_form = False
 
        return render('/pullrequests/pullrequest_show.html')
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def comment(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        if pull_request.is_closed():
 
            raise HTTPForbidden()
 

	
 
        status = request.POST.get('changeset_status')
 
        change_status = request.POST.get('change_changeset_status')
 
        text = request.POST.get('text')
 
        close_pr = request.POST.get('save_close')
 

	
 
        allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
 
        if status and change_status and allowed_to_change_status:
 
            _def = (_('status change -> %s')
 
                            % ChangesetStatus.get_status_lbl(status))
 
            if close_pr:
 
                _def = _('Closing with') + ' ' + _def
 
            text = text or _def
 
        comm = ChangesetCommentsModel().create(
 
            text=text,
 
            repo=c.rhodecode_db_repo.repo_id,
 
            user=c.rhodecode_user.user_id,
 
            pull_request=pull_request_id,
 
            f_path=request.POST.get('f_path'),
 
            line_no=request.POST.get('line'),
 
            status_change=(ChangesetStatus.get_status_lbl(status)
 
                           if status and change_status
 
                           and allowed_to_change_status else None),
 
            closing_pr=close_pr
 
        )
 

	
 
        action_logger(self.rhodecode_user,
 
                      'user_commented_pull_request:%s' % pull_request_id,
 
                      c.rhodecode_db_repo, self.ip_addr, self.sa)
 

	
 
        if allowed_to_change_status:
 
            # get status if set !
 
            if status and change_status:
 
                ChangesetStatusModel().set_status(
 
                    c.rhodecode_db_repo.repo_id,
 
                    status,
 
                    c.rhodecode_user.user_id,
 
                    comm,
 
                    pull_request=pull_request_id
 
                )
 

	
 
            if close_pr:
 
                if status in ['rejected', 'approved']:
 
                    PullRequestModel().close_pull_request(pull_request_id)
 
                    action_logger(self.rhodecode_user,
 
                              'user_closed_pull_request:%s' % pull_request_id,
 
                              c.rhodecode_db_repo, self.ip_addr, self.sa)
 
                else:
 
                    h.flash(_('Closing pull request on other statuses than '
 
                              'rejected or approved forbidden'),
 
                            category='warning')
 

	
 
        Session().commit()
 

	
 
        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            return redirect(h.url('pullrequest_show', repo_name=repo_name,
 
                                  pull_request_id=pull_request_id))
 

	
 
        data = {
 
           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
 
        }
 
        if comm:
 
            c.co = comm
 
            data.update(comm.get_dict())
 
            data.update({'rendered_text':
 
                         render('changeset/changeset_comment_block.html')})
 

	
 
        return data
 

	
 
    @NotAnonymous()
rhodecode/templates/changelog/changelog.html
Show inline comments
 
## -*- coding: utf-8 -*-
 

	
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_(u'Home'),h.url('/'))}
 
    &raquo;
 
    ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
 
    &raquo;
 
    <% size = c.size if c.size <= c.total_cs else c.total_cs %>
 
    ${_('changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
 
</%def>
 

	
 
<%def name="page_nav()">
 
    ${self.menu('changelog')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <div class="table">
 
        % if c.pagination:
 
            <div id="graph">
 
                <div id="graph_nodes">
 
                    <canvas id="graph_canvas"></canvas>
 
                </div>
 
                <div id="graph_content">
 
                    <div class="info_box" style="clear: both;padding: 10px 6px;text-align: right;">
 
                    <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
 
                    <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
 

	
 
                    %if c.rhodecode_db_repo.fork:
 
                        <a title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default')}" class="ui-btn small">${_('Compare fork with parent')}</a>
 
                    %endif
 
                    %if h.is_hg(c.rhodecode_repo):
 
                    <a id="open_new_pr" href="${h.url('pullrequest_form',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
 
                    %endif
 
                    </div>
 
                    <div class="container_header">
 
                        ${h.form(h.url.current(),method='get')}
 
                        <div class="info_box" style="float:left">
 
                          ${h.submit('set',_('Show'),class_="ui-btn")}
 
                          ${h.text('size',size=1,value=c.size)}
 
                          ${_('revisions')}
 
                        </div>
 
                        ${h.end_form()}
 
                    <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
 
                    </div>
 

	
 
                %for cnt,cs in enumerate(c.pagination):
 
                    <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
 
                        <div class="left">
 
                            <div>
 
                            ${h.checkbox(cs.raw_id,class_="changeset_range")}
 
                            <span class="tooltip" title="${h.tooltip(h.age(cs.date))}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
 
                            </div>
 
                            <div class="author">
 
                                <div class="gravatar">
 
                                    <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
 
                                </div>
 
                                <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div>
 
                            </div>
 
                            <div class="date">${h.fmt_date(cs.date)}</div>
 
                        </div>
 
                        <div class="mid">
 
                            <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
 
                            <div class="expand"><span class="expandtext">&darr; ${_('Show more')} &darr;</span></div>
 
                        </div>
 
                        <div class="right">
 
                                    <div class="changes">
 
                                        <div id="changed_total_${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${h.tooltip(_('Affected number of files, click to show more details'))}">${len(cs.affected_files)}</div>
 
                                        <div class="comments-container">
 
                                        %if len(c.comments.get(cs.raw_id,[])) > 0:
 
                                            <div class="comments-cnt" title="${('comments')}">
 
                                              <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
 
                                               <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
 
                                               <img src="${h.url('/images/icons/comments.png')}">
 
                                              </a>
 
                                            </div>
 
                                        %endif
 
                                        </div>
 
                                        <div class="changeset-status-container">
 
                                            %if c.statuses.get(cs.raw_id):
 
                                              <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
 
                                              <div class="changeset-status-ico">
 
                                              %if c.statuses.get(cs.raw_id)[2]:
 
                                                <a class="tooltip" title="${_('Click to open associated pull request #%s' % c.statuses.get(cs.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a>
 
                                              %else:
 
                                                <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
 
                                              %endif
 
                                              </div>
 
                                            %endif
 
                                        </div>
 
                                    </div>
 
                                   %if cs.parents:
 
                                    %for p_cs in reversed(cs.parents):
 
                                        <div class="parent">${_('Parent')}
 
                                            <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
 
                                            h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
 
                                        </div>
 
                                    %endfor
 
                                   %else:
 
                                        <div class="parent">${_('No parents')}</div>
 
                                   %endif
 

	
 
                                <span class="logtags">
 
                                    %if len(cs.parents)>1:
 
                                    <span class="merge">${_('merge')}</span>
 
                                    %endif
 
                                    %if cs.branch:
 
                                    <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
 
                                       ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
 
                                    </span>
 
                                    %endif
 
                                    %if h.is_hg(c.rhodecode_repo):
 
                                      %for book in cs.bookmarks:
 
                                      <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
 
                                         ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
 
                                      </span>
 
                                      %endfor
 
                                    %endif
 
                                    %for tag in cs.tags:
 
                                        <span class="tagtag"  title="${'%s %s' % (_('tag'),tag)}">
 
                                        ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
 
                                    %endfor
 
                                </span>
 
                        </div>
 
                    </div>
 

	
 
                %endfor
 
                <div class="pagination-wh pagination-left">
 
                    ${c.pagination.pager('$link_previous ~2~ $link_next')}
 
                </div>
 
                </div>
 
            </div>
 

	
 
            <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
 
            <script type="text/javascript">
 
                YAHOO.util.Event.onDOMReady(function(){
 

	
 
                    //Monitor range checkboxes and build a link to changesets
 
                    //ranges
 
                    var checkboxes = YUD.getElementsByClassName('changeset_range');
 
                    var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
 
                    var pr_tmpl = "${h.url('pullrequest_home',repo_name=c.repo_name)}";
 
                    YUE.on(checkboxes,'click',function(e){
 
                        var clicked_cb = e.currentTarget;
 
                        var checked_checkboxes = [];
 
                        for (pos in checkboxes){
 
                            if(checkboxes[pos].checked){
 
                                checked_checkboxes.push(checkboxes[pos]);
 
                            }
 
                        }
 
                        if(YUD.get('open_new_pr')){
 
                          if(checked_checkboxes.length>0){
 
                            // modify open pull request to show we have selected cs
 
                            YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
 
                          }else{
 
                            YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
 
                          }
 
                        }
 

	
 
                        if(checked_checkboxes.length>0){
 
                            var rev_end = checked_checkboxes[0].name;
 
                            var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
 
                            var url = url_tmpl.replace('__REVRANGE__',
 
                                    rev_start+'...'+rev_end);
 

	
 
                            var link = (rev_start == rev_end)
 
                              	? _TM['Show selected change __S']
 
                            	: _TM['Show selected changes __S -> __E'];
 
                            
 

	
 
                            link = link.replace('__S',rev_start.substr(0,6));
 
                            link = link.replace('__E',rev_end.substr(0,6));
 
                            YUD.get('rev_range_container').href = url;
 
                            YUD.get('rev_range_container').innerHTML = link;
 
                            YUD.setStyle('rev_range_container','display','');
 
                            YUD.setStyle('rev_range_clear','display','');
 

	
 
                            YUD.get('open_new_pr').href = pr_tmpl + '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
 

	
 
                        }
 
                        else{
 
                            YUD.setStyle('rev_range_container','display','none');
 
                            YUD.setStyle('rev_range_clear','display','none');
 
                        }
 
                    });
 
                    YUE.on('rev_range_clear','click',function(e){
 
                        for (var i=0; i<checkboxes.length; i++){
 
                            var cb = checkboxes[i];
 
                            cb.checked = false;
 
                        }
 
                        YUE.preventDefault(e);
 
                    })
 
                    var msgs = YUQ('.message');
 
                    // get first element height
 
                    var el = YUQ('#graph_content .container')[0];
 
                    var row_h = el.clientHeight;
 
                    for(var i=0;i<msgs.length;i++){
 
                        var m = msgs[i];
 

	
 
                        var h = m.clientHeight;
 
                        var pad = YUD.getStyle(m,'padding');
 
                        if(h > row_h){
 
                            var offset = row_h - (h+12);
 
                            YUD.setStyle(m.nextElementSibling,'display','block');
 
                            YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
 
                        };
 
                    }
 
                    YUE.on(YUQ('.expand'),'click',function(e){
 
                        var elem = e.currentTarget.parentNode.parentNode;
 
                        YUD.setStyle(e.currentTarget,'display','none');
 
                        YUD.setStyle(elem,'height','auto');
 

	
 
                        //redraw the graph, line_count and jsdata are global vars
 
                        set_canvas(100);
 

	
 
                        var r = new BranchRenderer();
 
                        r.render(jsdata,100,line_count);
 

	
 
                    })
 

	
 
                    // Fetch changeset details
 
                    YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
 
                        var id = e.currentTarget.id;
 
                        var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}";
 
                        var url = url.replace('__CS__',id.replace('changed_total_',''));
 
                        ypjax(url,id,function(){tooltip_activate()});
 
                    });
 

	
 
                    // change branch filter
 
                    YUE.on(YUD.get('branch_filter'),'change',function(e){
 
                        var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
 
                        var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
 
                        var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
 
                        var url = url.replace('__BRANCH__',selected_branch);
 
                        if(selected_branch != ''){
 
                            window.location = url;
 
                        }else{
 
                            window.location = url_main;
 
                        }
 

	
 
                    });
 

	
 
                    function set_canvas(width) {
 
                        var c = document.getElementById('graph_nodes');
 
                        var t = document.getElementById('graph_content');
 
                        canvas = document.getElementById('graph_canvas');
 
                        var div_h = t.clientHeight;
 
                        c.style.height=div_h+'px';
 
                        canvas.setAttribute('height',div_h);
 
                        c.style.height=width+'px';
 
                        canvas.setAttribute('width',width);
 
                    };
 
                    var heads = 1;
 
                    var line_count = 0;
 
                    var jsdata = ${c.jsdata|n};
 

	
 
                    for (var i=0;i<jsdata.length;i++) {
 
                        var in_l = jsdata[i][2];
 
                        for (var j in in_l) {
 
                            var m = in_l[j][1];
 
                            if (m > line_count)
 
                                line_count = m;
 
                        }
 
                    }
 
                    set_canvas(100);
 

	
 
                    var r = new BranchRenderer();
 
                    r.render(jsdata,100,line_count);
 

	
 
                });
 
            </script>
 
        %else:
 
            ${_('There are no changes yet')}
 
        %endif
 
    </div>
 
</div>
 
</%def>
0 comments (0 inline, 0 general)