diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -1103,9 +1103,9 @@ def make_map(config): conditions={'function': check_repo}, requirements=URL_NAME_REQUIREMENTS, jsroute=True) - rmap.connect('files_metadata_list_home', - '/{repo_name}/metadata_list/{revision}/{f_path}', - controller='files', action='metadata_list', + rmap.connect('files_nodetree_full', + '/{repo_name}/nodetree_full/{commit_id}/{f_path}', + controller='files', action='nodetree_full', conditions={'function': check_repo}, requirements=URL_NAME_REQUIREMENTS, jsroute=True) diff --git a/rhodecode/controllers/files.py b/rhodecode/controllers/files.py --- a/rhodecode/controllers/files.py +++ b/rhodecode/controllers/files.py @@ -136,10 +136,12 @@ class FilesController(BaseRepoController _namespace = caches.get_repo_namespace_key(namespace_type, repo_name) return caches.get_cache_manager('repo_cache_long', _namespace) - def _get_tree_at_commit(self, repo_name, commit_id, f_path): + def _get_tree_at_commit(self, repo_name, commit_id, f_path, + full_load=False, force=False): def _cached_tree(): log.debug('Generating cached file tree for %s, %s, %s', repo_name, commit_id, f_path) + c.full_load = full_load return render('files/files_browser_tree.html') cache_manager = self.__get_tree_cache_manager( @@ -148,6 +150,10 @@ class FilesController(BaseRepoController cache_key = caches.compute_key_from_params( repo_name, commit_id, f_path) + if force: + # we want to force recompute of caches + cache_manager.remove_value(cache_key) + return cache_manager.get(cache_key, createfunc=_cached_tree) def _get_nodelist_at_commit(self, repo_name, commit_id, f_path): @@ -165,22 +171,6 @@ class FilesController(BaseRepoController repo_name, commit_id, f_path) return cache_manager.get(cache_key, createfunc=_cached_nodes) - def _get_metadata_at_commit(self, repo_name, commit, dir_node): - def _cached_metadata(): - log.debug('Generating cached metadata for %s, %s, %s', - repo_name, commit.raw_id, safe_str(dir_node.path)) - - data = ScmModel().get_dirnode_metadata(commit, dir_node) - return data - - cache_manager = self.__get_tree_cache_manager( - repo_name, caches.FILE_TREE_META) - - cache_key = caches.compute_key_from_params( - repo_name, commit.raw_id, safe_str(dir_node.path)) - - return cache_manager.get(cache_key, createfunc=_cached_metadata) - @LoginRequired() @HasRepoPermissionAnyDecorator( 'repository.read', 'repository.write', 'repository.admin') @@ -246,6 +236,7 @@ class FilesController(BaseRepoController c.authors = [] c.file_tree = self._get_tree_at_commit( repo_name, c.commit.raw_id, f_path) + except RepositoryError as e: h.flash(safe_str(e), category='error') raise HTTPNotFound() @@ -1092,23 +1083,32 @@ class FilesController(BaseRepoController @XHRRequired() @HasRepoPermissionAnyDecorator( 'repository.read', 'repository.write', 'repository.admin') - @jsonify - def metadata_list(self, repo_name, revision, f_path): + def nodetree_full(self, repo_name, commit_id, f_path): """ - Returns a json dict that contains commit date, author, revision - and id for the specified repo, revision and file path + Returns rendered html of file tree that contains commit date, + author, revision for the specified combination of + repo, commit_id and file path :param repo_name: name of the repository - :param revision: revision of files + :param commit_id: commit_id of file tree :param f_path: file path of the requested directory """ - commit = self.__get_commit_or_redirect(revision, repo_name) + commit = self.__get_commit_or_redirect(commit_id, repo_name) try: - file_node = commit.get_node(f_path) + dir_node = commit.get_node(f_path) except RepositoryError as e: - return {'error': safe_str(e)} + return 'error {}'.format(safe_str(e)) + + if dir_node.is_file(): + return '' - metadata = self._get_metadata_at_commit( - repo_name, commit, file_node) - return {'metadata': metadata} + c.file = dir_node + c.commit = commit + + # using force=True here, make a little trick. We flush the cache and + # compute it using the same key as without full_load, so the fully + # loaded cached tree is now returned instead of partial + return self._get_tree_at_commit( + repo_name, commit.raw_id, dir_node.path, full_load=True, + force=True) diff --git a/rhodecode/lib/caches.py b/rhodecode/lib/caches.py --- a/rhodecode/lib/caches.py +++ b/rhodecode/lib/caches.py @@ -35,7 +35,7 @@ FILE_SEARCH_TREE_META = 'cache_file_sear SUMMARY_STATS = 'cache_summary_stats' # This list of caches gets purged when invalidation happens -USED_REPO_CACHES = (FILE_TREE, FILE_TREE_META, FILE_TREE_META) +USED_REPO_CACHES = (FILE_TREE, FILE_SEARCH_TREE_META) DEFAULT_CACHE_MANAGER_CONFIG = { 'type': 'memorylru_base', diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -4,7 +4,8 @@ * DO NOT CHANGE THIS FILE MANUALLY * * * * * - * This file is automatically generated when the app starts up. * + * This file is automatically generated when the app starts up with * + * generate_js_files = true * * * * To add a route here pass jsroute=True to the route definition in the app * * * @@ -44,7 +45,7 @@ function registerRCRoutes() { pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); - pyroutes.register('files_metadata_list_home', '/%(repo_name)s/metadata_list/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']); + pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']); pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']); pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']); } diff --git a/rhodecode/templates/files/files.html b/rhodecode/templates/files/files.html --- a/rhodecode/templates/files/files.html +++ b/rhodecode/templates/files/files.html @@ -91,36 +91,26 @@ if (source_page) { return false; } + + if ($('#file-tree-wrapper').hasClass('full-load')) { + // in case our HTML wrapper has full-load class we don't + // trigger the async load of metadata + return false; + } + var state = getState('metadata'); var url_data = { 'repo_name': templateContext.repo_name, - 'revision': state.commit_id, + 'commit_id': state.commit_id, 'f_path': state.f_path }; - var url = pyroutes.url('files_metadata_list_home', url_data); + var url = pyroutes.url('files_nodetree_full', url_data); metadataRequest = $.ajax({url: url}); metadataRequest.done(function(data) { - var data = data.metadata; - var dataLength = data.length; - for (var i = 0; i < dataLength; i++) { - var rowData = data[i]; - var name = rowData.name.replace('\\', '\\\\'); - - $('td[title="size-' + name + '"]').html(rowData.size); - var timeComponent = AgeModule.createTimeComponent( - rowData.modified_ts, rowData.modified_at); - $('td[title="modified_at-' + name + '"]').html(timeComponent); - - $('td[title="revision-' + name + '"]').html( - '
r{1}:{2}
- | - ${_('Loading...')} + | + % if c.full_load: + ${h.format_byte_size_binary(node.size)} + % else: + ${_('Loading ...')} + % endif + | ++ % if c.full_load: + ${h.age_component(node.last_commit.date)} + % endif | -- | + |
+ % if c.full_load:
+
+
+ % endif
+ r${node.last_commit.revision}:${node.last_commit.short_id}+ |
+ + % if c.full_load: + ${h.gravatar_with_user(node.last_commit.author)|n} + % endif + | %else:@@ -57,4 +75,4 @@ |