changelog: added dynamic loaders to extend number of commits inside changelog.

- implements #5187
This commit is contained in:
Marcin Kuzminski 2017-01-31 22:05:36 +01:00
parent 933651e934
commit 608e51e4cb
13 changed files with 488 additions and 272 deletions

View file

@ -68,6 +68,7 @@
"<%= dirs.js.src %>/rhodecode/utils/os.js",
"<%= dirs.js.src %>/rhodecode/utils/topics.js",
"<%= dirs.js.src %>/rhodecode/init.js",
"<%= dirs.js.src %>/rhodecode/changelog.js",
"<%= dirs.js.src %>/rhodecode/codemirror.js",
"<%= dirs.js.src %>/rhodecode/comments.js",
"<%= dirs.js.src %>/rhodecode/constants.js",

View file

@ -997,10 +997,10 @@ def make_map(config):
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
controller='changelog', action='changelog_details',
rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
controller='changelog', action='changelog_elements',
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS)
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
controller='files', revision='tip', f_path='',

View file

@ -30,7 +30,8 @@ from pylons.i18n.translation import _
from webob.exc import HTTPNotFound, HTTPBadRequest
import rhodecode.lib.helpers as h
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from rhodecode.lib.auth import (
LoginRequired, HasRepoPermissionAnyDecorator, XHRRequired)
from rhodecode.lib.base import BaseRepoController, render
from rhodecode.lib.ext_json import json
from rhodecode.lib.graphmod import _colored, _dagwalker
@ -98,7 +99,7 @@ class ChangelogController(BaseRepoController):
redirect(h.url('changelog_home', repo_name=repo.repo_name))
raise HTTPBadRequest()
def _graph(self, repo, commits):
def _graph(self, repo, commits, prev_data=None, next_data=None):
"""
Generates a DAG graph for repo
@ -106,12 +107,30 @@ class ChangelogController(BaseRepoController):
:param commits: list of commits
"""
if not commits:
c.jsdata = json.dumps([])
return
return json.dumps([])
def serialize(commit, parents=True):
data = dict(
raw_id=commit.raw_id,
idx=commit.idx,
branch=commit.branch,
)
if parents:
data['parents'] = [
serialize(x, parents=False) for x in commit.parents]
return data
prev_data = prev_data or []
next_data = next_data or []
current = [serialize(x) for x in commits]
commits = prev_data + current + next_data
dag = _dagwalker(repo, commits)
data = [['', vtx, edges] for vtx, edges in _colored(dag)]
c.jsdata = json.dumps(data)
data = [[commit_id, vtx, edges, branch]
for commit_id, vtx, edges, branch in _colored(dag)]
return json.dumps(data), json.dumps(current)
def _check_if_valid_branch(self, branch_name, repo_name, f_path):
if branch_name not in c.rhodecode_repo.branches_all:
@ -120,26 +139,37 @@ class ChangelogController(BaseRepoController):
redirect(url('changelog_file_home', repo_name=repo_name,
revision=branch_name, f_path=f_path or ''))
def _load_changelog_data(self, collection, page, chunk_size, branch_name=None, dynamic=False):
c.total_cs = len(collection)
c.showing_commits = min(chunk_size, c.total_cs)
c.pagination = RepoPage(collection, page=page, item_count=c.total_cs,
items_per_page=chunk_size, branch=branch_name)
c.next_page = c.pagination.next_page
c.prev_page = c.pagination.previous_page
if dynamic:
if request.GET.get('chunk') != 'next':
c.next_page = None
if request.GET.get('chunk') != 'prev':
c.prev_page = None
page_commit_ids = [x.raw_id for x in c.pagination]
c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids)
c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids)
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
def index(self, repo_name, revision=None, f_path=None):
commit_id = revision
limit = 100
hist_limit = safe_int(request.GET.get('limit')) or None
if request.GET.get('size'):
c.size = safe_int(request.GET.get('size'), 1)
session['changelog_size'] = c.size
session.save()
else:
c.size = int(session.get('changelog_size', DEFAULT_CHANGELOG_SIZE))
chunk_size = 20
# min size must be 1 and less than limit
c.size = max(c.size, 1) if c.size <= limit else limit
p = safe_int(request.GET.get('page', 1), 1)
c.branch_name = branch_name = request.GET.get('branch', None)
c.book_name = book_name = request.GET.get('bookmark', None)
hist_limit = safe_int(request.GET.get('limit')) or None
p = safe_int(request.GET.get('page', 1), 1)
c.selected_name = branch_name or book_name
if not commit_id and branch_name:
@ -147,6 +177,8 @@ class ChangelogController(BaseRepoController):
c.changelog_for_path = f_path
pre_load = ['author', 'branch', 'date', 'message', 'parents']
commit_ids = []
try:
if f_path:
log.debug('generating changelog for path %s', f_path)
@ -174,13 +206,9 @@ class ChangelogController(BaseRepoController):
collection = c.rhodecode_repo.get_commits(
branch_name=branch_name, pre_load=pre_load)
c.total_cs = len(collection)
c.showing_commits = min(c.size, c.total_cs)
c.pagination = RepoPage(collection, page=p, item_count=c.total_cs,
items_per_page=c.size, branch=branch_name)
page_commit_ids = [x.raw_id for x in c.pagination]
c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids)
c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids)
self._load_changelog_data(
collection, p, chunk_size, c.branch_name, dynamic=f_path)
except EmptyRepositoryError as e:
h.flash(safe_str(e), category='warning')
return redirect(url('summary_home', repo_name=repo_name))
@ -195,22 +223,62 @@ class ChangelogController(BaseRepoController):
# loading from ajax, we don't want the first result, it's popped
return render('changelog/changelog_file_history.mako')
if f_path:
revs = []
else:
revs = c.pagination
self._graph(c.rhodecode_repo, revs)
if not f_path:
commit_ids = c.pagination
c.graph_data, c.graph_commits = self._graph(
c.rhodecode_repo, commit_ids)
return render('changelog/changelog.mako')
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
def changelog_details(self, commit_id):
if request.environ.get('HTTP_X_PARTIAL_XHR'):
c.commit = c.rhodecode_repo.get_commit(commit_id=commit_id)
return render('changelog/changelog_details.mako')
raise HTTPNotFound()
@XHRRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
def changelog_elements(self, repo_name):
commit_id = None
chunk_size = 20
def wrap_for_error(err):
return '<tr><td colspan="9" class="alert alert-error">ERROR: {}</td></tr>'.format(err)
c.branch_name = branch_name = request.GET.get('branch', None)
c.book_name = book_name = request.GET.get('bookmark', None)
p = safe_int(request.GET.get('page', 1), 1)
c.selected_name = branch_name or book_name
if not commit_id and branch_name:
if branch_name not in c.rhodecode_repo.branches_all:
return wrap_for_error(
safe_str('Missing branch: {}'.format(branch_name)))
pre_load = ['author', 'branch', 'date', 'message', 'parents']
collection = c.rhodecode_repo.get_commits(
branch_name=branch_name, pre_load=pre_load)
try:
self._load_changelog_data(collection, p, chunk_size, dynamic=True)
except EmptyRepositoryError as e:
return wrap_for_error(safe_str(e))
except (RepositoryError, CommitDoesNotExistError, Exception) as e:
log.exception('Failed to fetch commits')
return wrap_for_error(safe_str(e))
prev_data = None
next_data = None
prev_graph = json.loads(request.POST.get('graph', ''))
if request.GET.get('chunk') == 'prev':
next_data = prev_graph
elif request.GET.get('chunk') == 'next':
prev_data = prev_graph
c.graph_data, c.graph_commits = self._graph(
c.rhodecode_repo, c.pagination,
prev_data=prev_data, next_data=next_data)
return render('changelog/changelog_elements.mako')
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',

View file

@ -21,7 +21,7 @@
"""
Modified mercurial DAG graph functions that re-uses VCS structure
It allows to have a shared codebase for DAG generation for hg and git repos
It allows to have a shared codebase for DAG generation for hg, git, svn repos
"""
nullrev = -1
@ -51,36 +51,30 @@ def _dagwalker(repo, commits):
if not commits:
return
# TODO: johbo: Use some sort of vcs api here
if repo.alias == 'hg':
def get_parent_indexes(idx):
return repo._remote.ctx_parents(idx)
def get_parent_indexes(idx):
return [commit.idx for commit in repo[idx].parents]
elif repo.alias in ['git', 'svn']:
def get_parent_indexes(idx):
return [commit.idx for commit in repo[idx].parents]
indexes = [commit.idx for commit in commits]
indexes = [commit['idx'] for commit in commits]
lowest_idx = min(indexes)
known_indexes = set(indexes)
gpcache = {}
grandparnet_cache = {}
for commit in commits:
parents = sorted(set([p.idx for p in commit.parents
if p.idx in known_indexes]))
mpars = [p.idx for p in commit.parents if
p.idx != nullrev and p.idx not in parents]
parents = sorted(set([p['idx'] for p in commit['parents']
if p['idx'] in known_indexes]))
mpars = [p['idx'] for p in commit['parents'] if
p['idx'] != nullrev and p['idx'] not in parents]
for mpar in mpars:
gp = gpcache.get(mpar)
gp = grandparnet_cache.get(mpar)
if gp is None:
gp = gpcache[mpar] = grandparent(
gp = grandparnet_cache[mpar] = grandparent(
get_parent_indexes, lowest_idx, indexes, mpar)
if not gp:
parents.append(mpar)
else:
parents.extend(g for g in gp if g not in parents)
yield (commit.idx, parents)
yield (commit['raw_id'], commit['idx'], parents, commit['branch'])
def _colored(dag):
@ -100,7 +94,7 @@ def _colored(dag):
colors = {}
newcolor = 1
for commit_idx, parents in dag:
for commit_id, commit_idx, parents, branch in dag:
# Compute seen and next_
if commit_idx not in seen:
@ -137,7 +131,7 @@ def _colored(dag):
for p in parents])
# Yield and move on
yield ((col, color), edges)
yield (commit_id, (col, color), edges, branch)
seen = next_

View file

@ -957,6 +957,18 @@ label {
clear: left;
}
}
.load-more-commits {
text-align: center;
}
.load-more-commits:hover {
background-color: @grey7;
}
.load-more-commits {
a {
display: block;
}
}
}
#filter_changelog {

View file

@ -50,7 +50,8 @@ h6, .h6 { font-size: 1em; font-family: @text-bold-italic; }
.breadcrumbs_light {
float:left;
margin: @padding 0;
font-size: 1.3em;
line-height: 38px;
}
// Body text

View file

@ -21,7 +21,7 @@ function Route( commit, data, options ) {
self.branch = data[2];
}
Route.prototype.drawRoute = function ( ctx ) {
Route.prototype.drawRoute = function ( commit, ctx ) {
var self = this;
if (self.options.orientation === "horizontal") {
@ -52,12 +52,13 @@ Route.prototype.drawRoute = function ( ctx ) {
} else {
var from_x = self.options.width * self.options.scaleFactor - (self.from + 1) * self.options.x_step * self.options.scaleFactor;
var row = $("#chg_"+(self.commit.idx+1))
var row = $("#sha_" + commit.sha);
if (row.length) {
var from_y = (row.offset().top + row.height() / 2 - self.options.relaOffset) * self.options.scaleFactor;
}
var to_x = self.options.width * self.options.scaleFactor - (self.to + 1) * self.options.x_step * self.options.scaleFactor;
var next_row = $("#chg_"+(self.commit.idx+2))
var next_row = $("#sha_" + commit.sha).next('tr');
if (next_row.length) {
var to_y = ((next_row.offset().top + next_row.height() / 2 - self.options.relaOffset) + 0.2) * self.options.scaleFactor;
}
@ -108,7 +109,8 @@ Commit.prototype.drawDot = function ( ctx ) {
} else {
var x = self.options.width * self.options.scaleFactor - (self.dot_offset + 1) * self.options.x_step * self.options.scaleFactor;
var row = $("#chg_"+(self.idx+1))
var row = $("#sha_" + self.sha);
var y = (row.offset().top + row.height() / 2 - self.options.relaOffset) * self.options.scaleFactor;
ctx.fillStyle = self.graph.get_color(self.dot_branch);
ctx.beginPath();
@ -218,7 +220,7 @@ GraphCanvas.prototype.draw = function () {
ctx.lineWidth = self.options.lineWidth;
self.options.relaOffset = $("#chg_1").offset().top;
self.options.relaOffset = $(".changelogRow").first().offset().top;
var n_commits = self.data.length;
for (var i=0; i<n_commits; i++) {
@ -226,7 +228,7 @@ GraphCanvas.prototype.draw = function () {
for (var j=0; j<commit.routes.length; j++) {
var route = commit.routes[j];
route.drawRoute(ctx);
route.drawRoute(commit, ctx);
}
commit.drawDot(ctx);
}

View file

@ -44,6 +44,7 @@ function registerRCRoutes() {
pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
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']);

View file

@ -0,0 +1,173 @@
// # Copyright (C) 2016-2017 RhodeCode GmbH
// #
// # This program is free software: you can redistribute it and/or modify
// # it under the terms of the GNU Affero General Public License, version 3
// # (only), as published by the Free Software Foundation.
// #
// # 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 Affero General Public License
// # along with this program. If not, see <http://www.gnu.org/licenses/>.
// #
// # This program is dual-licensed. If you wish to learn more about the
// # RhodeCode Enterprise Edition, including its added features, Support services,
// # and proprietary license terms, please see https://rhodecode.com/licenses/
var CommitsController = function () {
var self = this;
this.$graphCanvas = $('#graph_canvas');
this.$commitCounter = $('#commit-counter');
this.getCurrentGraphData = function () {
// raw form
return self.$graphCanvas.data('commits');
};
this.setLabelText = function (graphData) {
var shown = $('.commit_hash').length;
var total = self.$commitCounter.data('total');
if (shown == 1) {
var text = _gettext('showing {0} out of {1} commit').format(shown, total);
} else {
var text = _gettext('showing {0} out of {1} commits').format(shown, total);
}
self.$commitCounter.html(text)
};
this.reloadGraph = function (chunk) {
chunk = chunk || 'next';
// reset state on re-render !
self.$graphCanvas.html('');
var edgeData = $("[data-graph]").data('graph') || this.$graphCanvas.data('graph') || [];
// Determine max number of edges per row in graph
var edgeCount = 1;
$.each(edgeData, function (i, item) {
$.each(item[2], function (key, value) {
if (value[1] > edgeCount) {
edgeCount = value[1];
}
});
});
var x_step = Math.min(10, Math.floor(86 / edgeCount));
var graph_options = {
width: 100,
height: $('#changesets').find('.commits-range').height(),
x_step: x_step,
y_step: 42,
dotRadius: 3.5,
lineWidth: 2.5
};
var prevCommitsData = this.$graphCanvas.data('commits') || [];
var nextCommitsData = $("[data-graph]").data('commits') || [];
if (chunk == 'next') {
var commitData = $.merge(prevCommitsData, nextCommitsData);
} else {
var commitData = $.merge(nextCommitsData, prevCommitsData);
}
this.$graphCanvas.data('graph', edgeData);
this.$graphCanvas.data('commits', commitData);
// destroy dynamic loaded graph
$("[data-graph]").remove();
this.$graphCanvas.commits(graph_options);
this.setLabelText(edgeData);
if ($('.load-more-commits').find('.prev-commits').get(0)) {
var padding = 75;
} else {
var padding = 43;
}
$('#graph_nodes').css({'padding-top': padding});
};
this.getChunkUrl = function (page, chunk, branch) {
var urlData = {
'repo_name': templateContext.repo_name,
'page': page,
'chunk': chunk
};
if (branch !== undefined && branch !== '') {
urlData['branch'] = branch;
}
return pyroutes.url('changelog_elements', urlData);
};
this.loadNext = function (node, page, branch) {
var loadUrl = this.getChunkUrl(page, 'next', branch);
var postData = {'graph': JSON.stringify(this.getCurrentGraphData())};
$.post(loadUrl, postData, function (data) {
$(node).closest('tbody').append(data);
$(node).closest('td').remove();
self.reloadGraph('next');
})
};
this.loadPrev = function (node, page, branch) {
var loadUrl = this.getChunkUrl(page, 'prev', branch);
var postData = {'graph': JSON.stringify(this.getCurrentGraphData())};
$.post(loadUrl, postData, function (data) {
$(node).closest('tbody').prepend(data);
$(node).closest('td').remove();
self.reloadGraph('prev');
})
};
this.expandCommit = function (node) {
var target_expand = $(node);
var cid = target_expand.data('commitId');
if (target_expand.hasClass('open')) {
$('#c-' + cid).css({
'height': '1.5em',
'white-space': 'nowrap',
'text-overflow': 'ellipsis',
'overflow': 'hidden'
});
$('#t-' + cid).css({
'height': 'auto',
'line-height': '.9em',
'text-overflow': 'ellipsis',
'overflow': 'hidden',
'white-space': 'nowrap'
});
target_expand.removeClass('open');
}
else {
$('#c-' + cid).css({
'height': 'auto',
'white-space': 'pre-line',
'text-overflow': 'initial',
'overflow': 'visible'
});
$('#t-' + cid).css({
'height': 'auto',
'max-height': 'none',
'text-overflow': 'initial',
'overflow': 'visible',
'white-space': 'normal'
});
target_expand.addClass('open');
}
// redraw the graph
self.reloadGraph();
}
};

View file

@ -16,7 +16,6 @@
%if c.changelog_for_path:
/${c.changelog_for_path}
%endif
${ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)}
</%def>
<%def name="menu_bar_nav()">
@ -74,6 +73,7 @@
</div>
% if c.pagination:
<script type="text/javascript" src="${h.asset('js/jquery.commits-graph.js')}"></script>
<div class="graph-header">
<div id="filter_changelog">
@ -85,134 +85,53 @@
%endif
</div>
${self.breadcrumbs('breadcrumbs_light')}
<div id="commit-counter" data-total=${c.total_cs} class="pull-right">
${ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)}
</div>
</div>
<div id="graph">
<div class="graph-col-wrapper">
<div id="graph_nodes">
<div id="graph_canvas" data-graph='${c.jsdata|n}'></div>
<div id="graph">
<div class="graph-col-wrapper">
<div id="graph_nodes">
<div id="graph_canvas"></div>
</div>
<div id="graph_content" class="main-content graph_full_width">
<div class="table">
<table id="changesets" class="rctable">
<tr>
## checkbox
<th></th>
<th colspan="2"></th>
<th>${_('Commit')}</th>
## commit message expand arrow
<th></th>
<th>${_('Commit Message')}</th>
<th>${_('Age')}</th>
<th>${_('Author')}</th>
<th>${_('Refs')}</th>
</tr>
<tbody class="commits-range">
<%include file='changelog_elements.mako'/>
</tbody>
</table>
</div>
</div>
<div class="pagination-wh pagination-left">
${c.pagination.pager('$link_previous ~2~ $link_next')}
</div>
</div>
<div id="graph_content" class="main-content graph_full_width">
<div class="table">
<table id="changesets" class="rctable">
<tr>
## checkbox
<th></th>
<th colspan="2"></th>
<th>${_('Commit')}</th>
## commit message expand arrow
<th></th>
<th>${_('Commit Message')}</th>
<th>${_('Age')}</th>
<th>${_('Author')}</th>
<th>${_('Refs')}</th>
</tr>
<tbody>
%for cnt,commit in enumerate(c.pagination):
<tr id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
<td class="td-checkbox">
${h.checkbox(commit.raw_id,class_="commit-range")}
</td>
<td class="td-status">
%if c.statuses.get(commit.raw_id):
<div class="changeset-status-ico">
%if c.statuses.get(commit.raw_id)[2]:
<a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (h.commit_status_lbl(c.statuses.get(commit.raw_id)[0]), c.statuses.get(commit.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(commit.raw_id)[3],pull_request_id=c.statuses.get(commit.raw_id)[2])}">
<div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
</a>
%else:
<a class="tooltip" title="${_('Commit status: %s') % h.commit_status_lbl(c.statuses.get(commit.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
<div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
</a>
%endif
</div>
%else:
<div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div>
%endif
</td>
<td class="td-comments comments-col">
%if c.comments.get(commit.raw_id):
<a title="${_('Commit has comments')}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
<i class="icon-comment"></i> ${len(c.comments[commit.raw_id])}
</a>
%endif
</td>
<td class="td-hash">
<code>
<a href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">
<span class="commit_hash">${h.show_id(commit)}</span>
</a>
</code>
</td>
<td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_('Expand commit message')}">
<div class="show_more_col">
<i class="show_more"></i>&nbsp;
</div>
</td>
<td class="td-description mid">
<div class="log-container truncate-wrap">
<div class="message truncate" id="c-${commit.raw_id}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
</div>
</td>
<td class="td-time">
${h.age_component(commit.date)}
</td>
<td class="td-user">
${self.gravatar_with_user(commit.author)}
</td>
<td class="td-tags tags-col">
<div id="t-${commit.raw_id}">
## branch
%if commit.branch:
<span class="branchtag tag" title="${_('Branch %s') % commit.branch}">
<a href="${h.url('changelog_home',repo_name=c.repo_name,branch=commit.branch)}"><i class="icon-code-fork"></i>${h.shorter(commit.branch)}</a>
</span>
%endif
## bookmarks
%if h.is_hg(c.rhodecode_repo):
%for book in commit.bookmarks:
<span class="tag booktag" title="${_('Bookmark %s') % book}">
<a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
</span>
%endfor
%endif
## tags
%for tag in commit.tags:
<span class="tagtag tag" title="${_('Tag %s') % tag}">
<a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-tag"></i>${h.shorter(tag)}</a>
</span>
%endfor
</div>
</td>
</tr>
%endfor
</tbody>
</table>
</div>
</div>
</div>
<div class="pagination-wh pagination-left">
${c.pagination.pager('$link_previous ~2~ $link_next')}
</div>
<script type="text/javascript" src="${h.asset('js/jquery.commits-graph.js')}"></script>
<script type="text/javascript">
<script type="text/javascript">
var cache = {};
$(function(){
// Create links to commit ranges when range checkboxes are selected
var $commitCheckboxes = $('.commit-range');
var $commitCheckboxes = $('.commit-range');
// cache elements
var $commitRangeContainer = $('#rev_range_container');
var $commitRangeClear = $('#rev_range_clear');
@ -293,7 +212,6 @@
// make sure the buttons are consistent when navigate back and forth
checkboxRangeSelector();
var msgs = $('.message');
// get first element height
var el = $('#graph_content .container')[0];
@ -310,48 +228,6 @@
}
}
$('.expand_commit').on('click', function (e) {
var target_expand = $(this);
var cid = target_expand.data('commitId');
if (target_expand.hasClass('open')) {
$('#c-' + cid).css({
'height': '1.5em',
'white-space': 'nowrap',
'text-overflow': 'ellipsis',
'overflow': 'hidden'
});
$('#t-' + cid).css({
'height': 'auto',
'line-height': '.9em',
'text-overflow': 'ellipsis',
'overflow': 'hidden',
'white-space': 'nowrap'
});
target_expand.removeClass('open');
}
else {
$('#c-' + cid).css({
'height': 'auto',
'white-space': 'pre-line',
'text-overflow': 'initial',
'overflow': 'visible'
});
$('#t-' + cid).css({
'height': 'auto',
'max-height': 'none',
'text-overflow': 'initial',
'overflow': 'visible',
'white-space': 'normal'
});
target_expand.addClass('open');
}
// redraw the graph
graph_options.height = $("#changesets").height();
$("canvas").remove();
$("[data-graph]").commits(graph_options);
});
$("#clear_filter").on("click", function() {
var filter = {'repo_name': '${c.repo_name}'};
window.location = pyroutes.url('changelog_home', filter);
@ -394,7 +270,6 @@
}
}
});
$('#branch_filter').on('change', function(e){
var data = $('#branch_filter').select2('data');
var selected = data.text;
@ -408,33 +283,17 @@
window.location = pyroutes.url('changelog_home', filter);
});
// Determine max number of edges per row in graph
var jsdata = $.parseJSON($("[data-graph]").attr('data-graph'));
var edgeCount = 1;
$.each(jsdata, function(i, item){
$.each(item[2], function(key, value) {
if (value[1] > edgeCount){
edgeCount = value[1];
}
});
});
var x_step = Math.min(18, Math.floor(86 / edgeCount));
var graph_options = {
width: 100,
height: $("#changesets").height(),
x_step: x_step,
y_step: 42,
dotRadius: 3.5,
lineWidth: 2.5
};
$("[data-graph]").commits(graph_options);
commitsController = new CommitsController();
% if not c.changelog_for_path:
commitsController.reloadGraph();
% endif
});
</script>
%else:
</div>
% else:
${_('There are no changes yet')}
%endif
</div>
% endif
</div>
</%def>

View file

@ -1,11 +0,0 @@
## small box that displays changed/added/removed details fetched by AJAX
% if len(c.commit.affected_files) <= c.affected_files_cut_off:
<span class="removed tooltip" title="<b>${h.tooltip(_('Removed'))}</b>${h.changed_tooltip(c.commit.removed)}">${len(c.commit.removed)}</span>
<span class="changed tooltip" title="<b>${h.tooltip(_('Changed'))}</b>${h.changed_tooltip(c.commit.changed)}">${len(c.commit.changed)}</span>
<span class="added tooltip" title="<b>${h.tooltip(_('Added'))}</b>${h.changed_tooltip(c.commit.added)}">${len(c.commit.added)}</span>
% else:
<span class="removed tooltip" title="${h.tooltip(_('Affected %s files') % len(c.commit.affected_files))}">!</span>
<span class="changed tooltip" title="${h.tooltip(_('Affected %s files') % len(c.commit.affected_files))}">!</span>
<span class="added tooltip" title="${h.tooltip(_('Affected %s files') % len(c.commit.affected_files))}">!</span>
% endif

View file

@ -0,0 +1,122 @@
## small box that displays changed/added/removed details fetched by AJAX
<%namespace name="base" file="/base/base.mako"/>
% if c.prev_page:
<tr>
<td colspan="9" class="load-more-commits">
<a class="prev-commits" href="#loadPrevCommits" onclick="commitsController.loadPrev(this, ${c.prev_page}, '${c.branch_name}');return false">
${_('load previous')}
</a>
</td>
</tr>
% endif
% for cnt,commit in enumerate(c.pagination):
<tr id="sha_${commit.raw_id}" class="changelogRow container ${'tablerow%s' % (cnt%2)}">
<td class="td-checkbox">
${h.checkbox(commit.raw_id,class_="commit-range")}
</td>
<td class="td-status">
%if c.statuses.get(commit.raw_id):
<div class="changeset-status-ico">
%if c.statuses.get(commit.raw_id)[2]:
<a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (h.commit_status_lbl(c.statuses.get(commit.raw_id)[0]), c.statuses.get(commit.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(commit.raw_id)[3],pull_request_id=c.statuses.get(commit.raw_id)[2])}">
<div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
</a>
%else:
<a class="tooltip" title="${_('Commit status: %s') % h.commit_status_lbl(c.statuses.get(commit.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
<div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
</a>
%endif
</div>
%else:
<div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div>
%endif
</td>
<td class="td-comments comments-col">
%if c.comments.get(commit.raw_id):
<a title="${_('Commit has comments')}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
<i class="icon-comment"></i> ${len(c.comments[commit.raw_id])}
</a>
%endif
</td>
<td class="td-hash">
<code>
<a href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">
<span class="commit_hash">${h.show_id(commit)}</span>
</a>
</code>
</td>
<td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_('Expand commit message')}" onclick="commitsController.expandCommit(this); return false">
<div class="show_more_col">
<i class="show_more"></i>&nbsp;
</div>
</td>
<td class="td-description mid">
<div class="log-container truncate-wrap">
<div class="message truncate" id="c-${commit.raw_id}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
</div>
</td>
<td class="td-time">
${h.age_component(commit.date)}
</td>
<td class="td-user">
${base.gravatar_with_user(commit.author)}
</td>
<td class="td-tags tags-col">
<div id="t-${commit.raw_id}">
## merge
%if commit.merge:
<span class="tag mergetag">
<i class="icon-merge"></i>${_('merge')}
</span>
%endif
## branch
%if commit.branch:
<span class="tag branchtag" title="${_('Branch %s') % commit.branch}">
<a href="${h.url('changelog_home',repo_name=c.repo_name,branch=commit.branch)}"><i class="icon-code-fork"></i>${h.shorter(commit.branch)}</a>
</span>
%endif
## bookmarks
%if h.is_hg(c.rhodecode_repo):
%for book in commit.bookmarks:
<span class="tag booktag" title="${_('Bookmark %s') % book}">
<a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
</span>
%endfor
%endif
## tags
%for tag in commit.tags:
<span class="tag tagtag" title="${_('Tag %s') % tag}">
<a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-tag"></i>${h.shorter(tag)}</a>
</span>
%endfor
</div>
</td>
</tr>
% endfor
% if c.next_page:
<tr>
<td colspan="9" class="load-more-commits">
<a class="next-commits" href="#loadNextCommits" onclick="commitsController.loadNext(this, ${c.next_page}, '${c.branch_name}');return false">
${_('load next')}
</a>
</td>
</tr>
% endif
<tr class="chunk-graph-data" style="display:none"
data-graph='${c.graph_data|n}'
data-node='${c.prev_page}:${c.next_page}'
data-commits='${c.graph_commits|n}'>
</tr>

View file

@ -14,12 +14,6 @@
</td>
<td class="td-message">
<div class="log-container">
%if cs.merge:
<span class="mergetag">
<i class="icon-merge"></i>${_('merge')}
</span>
%endif
<div class="message_history" title="${cs.message}">
<a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
${h.shorter(cs.message, 75)}