@@ -21,21 +21,28 @@
# 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
from mercurial import graphmod
from pylons import request, session, tmpl_context as c
from pylons import request, url, session, tmpl_context as c
from pylons.controllers.util import redirect
from pylons.i18n.translation import _
import rhodecode.lib.helpers as h
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from rhodecode.lib.base import BaseRepoController, render
from rhodecode.lib.helpers import RepoPage
from rhodecode.lib.compat import json
from vcs.exceptions import RepositoryError, ChangesetError, \
ChangesetDoesNotExistError,BranchDoesNotExistError
log = logging.getLogger(__name__)
class ChangelogController(BaseRepoController):
@LoginRequired()
@@ -59,44 +66,62 @@ class ChangelogController(BaseRepoContro
session.save()
else:
c.size = int(session.get('changelog_size', default))
p = int(request.params.get('page', 1))
branch_name = request.params.get('branch', None)
c.total_cs = len(c.rhodecode_repo)
c.pagination = RepoPage(c.rhodecode_repo, page=p,
item_count=c.total_cs, items_per_page=c.size,
branch_name=branch_name)
try:
if branch_name:
collection = [z for z in
c.rhodecode_repo.get_changesets(start=0,
branch_name=branch_name)]
c.total_cs = len(collection)
collection = list(c.rhodecode_repo)
self._graph(c.rhodecode_repo, c.total_cs, c.size, p)
c.pagination = RepoPage(collection, page=p, item_count=c.total_cs,
items_per_page=c.size, branch=branch_name)
except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
log.error(traceback.format_exc())
h.flash(str(e), category='warning')
return redirect(url('home'))
self._graph(c.rhodecode_repo, collection, c.total_cs, c.size, p)
c.branch_name = branch_name
c.branch_filters = [('',_('All Branches'))] + \
[(k,k) for k in c.rhodecode_repo.branches.keys()]
return render('changelog/changelog.html')
def changelog_details(self, cs):
if request.environ.get('HTTP_X_PARTIAL_XHR'):
c.cs = c.rhodecode_repo.get_changeset(cs)
return render('changelog/changelog_details.html')
def _graph(self, repo, repo_size, size, p):
def _graph(self, repo, collection, repo_size, size, p):
"""
Generates a DAG graph for mercurial
:param repo: repo instance
:param size: number of commits to show
:param p: page number
if not repo.revisions:
if not collection:
c.jsdata = json.dumps([])
return
revcount = min(repo_size, size)
offset = 1 if p == 1 else ((p - 1) * revcount + 1)
rev_end = repo.revisions.index(repo.revisions[(-1 * offset)])
rev_end = collection.index(collection[(-1 * offset)])
except IndexError:
rev_end = repo.revisions.index(repo.revisions[-1])
rev_end = collection.index(collection[-1])
rev_start = max(0, rev_end - revcount)
data = []
rev_end += 1
if repo.alias == 'git':
@@ -111,6 +136,7 @@ class ChangelogController(BaseRepoContro
for (id, type, ctx, vtx, edges) in c.dag:
if type != graphmod.CHANGESET:
continue
data.append(['', vtx, edges])
c.jsdata = json.dumps(data)
@@ -63,23 +63,25 @@ class ChangesetController(BaseRepoContro
<td class="code"><pre>%s</pre></td>
</tr>
</table>''' % str
#get ranges of revisions if preset
rev_range = revision.split('...')[:2]
if len(rev_range) == 2:
rev_start = rev_range[0]
rev_end = rev_range[1]
rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
end=rev_end)
rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
c.cs_ranges = list(rev_ranges)
if not c.cs_ranges:
raise RepositoryError('Changeset range returned empty result')
@@ -47,13 +47,13 @@ class ShortlogController(BaseRepoControl
size = int(request.params.get('size', 20))
def url_generator(**kw):
return url('shortlog_home', repo_name=repo_name, size=size, **kw)
c.repo_changesets = RepoPage(c.rhodecode_repo, page=p,
items_per_page=size,
url=url_generator)
items_per_page=size, url=url_generator)
c.shortlog_data = render('shortlog/shortlog_data.html')
return c.shortlog_data
r = render('shortlog/shortlog.html')
return r
@@ -34,13 +34,13 @@ from webhelpers.date import time_ago_in_
from webhelpers.paginate import Page
from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
convert_boolean_attrs, NotGiven
from vcs.utils.annotate import annotate_highlight
from rhodecode.lib.utils import repo_name_slug
from rhodecode.lib import str2bool, safe_unicode, safe_str,get_changeset_safe
from rhodecode.lib import str2bool, safe_unicode, safe_str, get_changeset_safe
def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
Reset button
_set_input_attrs(attrs, type, name, value)
@@ -477,13 +477,13 @@ def gravatar_url(email_address, size=30)
#==============================================================================
# REPO PAGER, PAGER FOR REPOSITORY
class RepoPage(Page):
def __init__(self, collection, page=1, items_per_page=20,
item_count=None, url=None, branch_name=None, **kwargs):
item_count=None, url=None, **kwargs):
"""Create a "RepoPage" instance. special pager for paging
repository
self._url_generator = url
@@ -528,17 +528,14 @@ class RepoPage(Page):
# items_per_page if the last page is not full
self.first_item = max(0, (self.item_count) - (self.page *
items_per_page))
self.last_item = ((self.item_count - 1) - items_per_page *
(self.page - 1))
iterator = self.collection.get_changesets(start=self.first_item,
end=self.last_item,
reverse=True,
self.items = list(iterator)
self.items = list(self.collection[self.first_item:self.last_item+1])
# Links to previous and next page
if self.page > self.first_page:
self.previous_page = self.page - 1
self.previous_page = None
@@ -557,13 +554,13 @@ class RepoPage(Page):
self.last_item = None
self.next_page = None
self.items = []
# This is a subclass of the 'list' type. Initialise the list now.
list.__init__(self, self.items)
list.__init__(self, reversed(self.items))
def changed_tooltip(nodes):
Generates a html string for changed nodes in changeset page.
It limits the output to 30 entries
@@ -667,6 +664,7 @@ def urlify_text(text):
def url_func(match_obj):
url_full = match_obj.groups()[0]
return '<a href="%(url)s">%(url)s</a>' % ({'url':url_full})
return literal(url_pat.sub(url_func, text))
@@ -1911,16 +1911,18 @@ h3.files_location {
float: left;
}
#graph_content .container_header {
border: 1px solid #CCC;
padding: 10px;
height: 45px;
#graph_content #rev_range_container {
padding: 10px 0px;
clear: both;
#graph_content .container {
border-bottom: 1px solid #CCC;
border-left: 1px solid #CCC;
border-right: 1px solid #CCC;
@@ -2019,29 +2021,48 @@ h3.files_location {
font-weight: 700;
.right .parent {
font-size: 90%;
font-family: monospace;
.right .logtags .branchtag {
background: #FFF url("../images/icons/arrow_branch.png") no-repeat right
6px;
display: block;
font-size: 0.8em;
padding: 11px 16px 0 0;
.right .logtags .tagtag {
background: #FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
padding: 2px 2px 2px 2px;
.right .logtags{
.right .logtags .branchtag,.logtags .branchtag {
padding: 1px 3px 2px;
background-color: #bfbfbf;
font-size: 9.75px;
font-weight: bold;
color: #ffffff;
text-transform: uppercase;
white-space: nowrap;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
padding-left:4px;
.right .logtags .branchtag a:hover,.logtags .branchtag a:hover{
text-decoration: none;
.right .logtags .tagtag,.logtags .tagtag {
background-color: #62cffc;
.right .logtags .tagtag a:hover,.logtags .tagtag a:hover{
div.browserblock {
overflow: hidden;
border: 1px solid #ccc;
background: #f8f8f8;
font-size: 100%;
line-height: 125%;
@@ -3092,25 +3113,25 @@ div.readme .readme_box code {
color: #444 !important;
padding: 0 .2em !important;
border: 1px solid #dedede !important;
div.readme .readme_box pre code {
padding: 0 !important;
font-size: 12px !important;
background-color: #eee !important;
border: none !important;
div.readme .readme_box pre {
margin: 1em 0;
font-size: 12px;
background-color: #eee;
border: 1px solid #ddd;
padding: 5px;
color: #444;
overflow: auto;
-webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
@@ -16,17 +16,17 @@
<span class="branchtag">${h.link_to(branch[0],
h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
</span>
</td>
<td title="${branch[1].author}">${h.person(branch[1].author)}</td>
<td>r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</td>
<td class="nowrap">
${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}
|
${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id))}
${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id),class_="ui-button-small")}
<span style="color:#515151">|</span>
${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id),class_="ui-button-small")}
%endfor
% if hasattr(c,'repo_closed_branches') and c.repo_closed_branches:
%for cnt,branch in enumerate(c.repo_closed_branches.items()):
<tr class="parity${cnt%2}">
<td><span class="tooltip" title="${h.age(branch[1].date)}">${branch[1].date}</span>
@@ -37,15 +37,15 @@
%endif
</table>
%else:
@@ -30,18 +30,19 @@ ${c.repo_name} ${_('Changelog')} - ${c.r
<div id="graph_nodes">
<canvas id="graph_canvas"></canvas>
</div>
<div id="graph_content">
<div class="container_header">
${h.form(h.url.current(),method='get')}
<div class="info_box">
<div class="info_box" style="float:left">
${h.submit('set',_('Show'),class_="ui-button-small")}
${h.text('size',size=1,value=c.size)}
<span class="rev">${_('revisions')}</span>
${h.end_form()}
<div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
<div id="rev_range_container" style="display:none"></div>
%for cnt,cs in enumerate(c.pagination):
<div id="chg_${cnt+1}" class="container">
<div class="left">
@@ -60,15 +61,13 @@ ${c.repo_name} ${_('Changelog')} - ${c.r
<div class="right">
<div id="${cs.raw_id}_changes_info" class="changes">
<span id="${cs.raw_id}" class="changed_total tooltip" title="${_('Affected number of files, click to show more details')}">${len(cs.affected_files)}</span>
%if len(cs.parents)>1:
<div class="merge">
${_('merge')}<img alt="merge" src="${h.url('/images/icons/arrow_join.png')}"/>
<div class="merge">${_('merge')}</div>
%if cs.parents:
%for p_cs in reversed(cs.parents):
<div class="parent">${_('Parent')} ${p_cs.revision}: ${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)}
@@ -128,20 +127,34 @@ ${c.repo_name} ${_('Changelog')} - ${c.r
else{
YUD.setStyle('rev_range_container','display','none');
});
//Fetch changeset details
// 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);
ypjax(url,id+'_changes_info',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;
console.log(selected_branch);
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(heads) {
var c = document.getElementById('graph_nodes');
var t = document.getElementById('graph_content');
canvas = document.getElementById('graph_canvas');
var div_h = t.clientHeight;
@@ -162,13 +175,13 @@ ${c.repo_name} ${_('Changelog')} - ${c.r
var max_w = Math.max(100,max_heads*25);
set_canvas(max_w);
var r = new BranchRenderer();
r.render(jsdata,max_w);
</script>
${_('There are no changes yet')}
@@ -33,15 +33,15 @@
%for tag in cs.tags:
<span class="tagtag">${tag}</span>
${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),class_="ui-button-small")}
${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id),class_="ui-button-small")}
@@ -18,15 +18,15 @@
h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].raw_id))}</span>
<td title="${tag[1].author}">${h.person(tag[1].author)}</td>
<td>r${tag[1].revision}:${h.short_id(tag[1].raw_id)}</td>
${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].raw_id),class_="ui-button-small")}
${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id),class_="ui-button-small")}
${_('There are no tags yet')}
Status change: