changelog: added dynamic loaders to extend number of commits inside changelog.
- implements #5187
This commit is contained in:
parent
933651e934
commit
608e51e4cb
13 changed files with 488 additions and 272 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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='',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
|
|
|
|||
173
rhodecode/public/js/src/rhodecode/changelog.js
Normal file
173
rhodecode/public/js/src/rhodecode/changelog.js
Normal 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();
|
||||
}
|
||||
};
|
||||
|
|
@ -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>
|
||||
</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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
122
rhodecode/templates/changelog/changelog_elements.mako
Normal file
122
rhodecode/templates/changelog/changelog_elements.mako
Normal 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>
|
||||
</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>
|
||||
|
|
@ -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)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue