changeset 3001:37c7abd34d44 beta

implements #636, lazy loading of history and authors to speed up page responsiveness. - loading full history is not always needed, and it's very heavy operation. Now this is lazy loaded when clicking on button
author Marcin Kuzminski <marcin@python-works.com>
date Tue, 13 Nov 2012 22:26:06 +0100
parents 4034eb731b33
children dec78aee1d53
files rhodecode/config/routing.py rhodecode/controllers/files.py rhodecode/public/js/rhodecode.js rhodecode/templates/base/root.html rhodecode/templates/files/files.html rhodecode/templates/files/files_history_box.html rhodecode/templates/files/files_source.html
diffstat 7 files changed, 148 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/config/routing.py	Sat Nov 10 19:04:23 2012 +0100
+++ b/rhodecode/config/routing.py	Tue Nov 13 22:26:06 2012 +0100
@@ -534,6 +534,11 @@
                 controller='files', revision='tip', f_path='',
                 conditions=dict(function=check_repo))
 
+    rmap.connect('files_history_home',
+                 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
+                 controller='files', action='history', revision='tip', f_path='',
+                 conditions=dict(function=check_repo))
+
     rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
                 controller='files', action='diff', revision='tip', f_path='',
                 conditions=dict(function=check_repo))
--- a/rhodecode/controllers/files.py	Sat Nov 10 19:04:23 2012 +0100
+++ b/rhodecode/controllers/files.py	Tue Nov 13 22:26:06 2012 +0100
@@ -155,12 +155,16 @@
             c.file = c.changeset.get_node(f_path)
 
             if c.file.is_file():
-                c.file_history, _hist = self._get_node_history(c.changeset, f_path)
-                c.file_changeset = c.changeset
-                if _hist:
-                    c.file_changeset = (c.changeset
-                                        if c.changeset.revision < _hist[0].revision
-                                        else _hist[0])
+                c.load_full_history = False
+                file_last_cs = c.file.last_changeset
+                c.file_changeset = (c.changeset
+                                    if c.changeset.revision < file_last_cs.revision
+                                    else file_last_cs)
+                _hist = []
+                c.file_history = []
+                if c.load_full_history:
+                    c.file_history, _hist = self._get_node_history(c.changeset, f_path)
+
                 c.authors = []
                 for a in set([x.author for x in _hist]):
                     c.authors.append((h.email(a), h.person(a)))
@@ -176,6 +180,23 @@
 
         return render('files/files.html')
 
+    def history(self, repo_name, revision, f_path, annotate=False):
+        if request.environ.get('HTTP_X_PARTIAL_XHR'):
+            c.changeset = self.__get_cs_or_redirect(revision, repo_name)
+            c.f_path = f_path
+            c.annotate = annotate
+            c.file = c.changeset.get_node(f_path)
+            if c.file.is_file():
+                file_last_cs = c.file.last_changeset
+                c.file_changeset = (c.changeset
+                                    if c.changeset.revision < file_last_cs.revision
+                                    else file_last_cs)
+                c.file_history, _hist = self._get_node_history(c.changeset, f_path)
+                c.authors = []
+                for a in set([x.author for x in _hist]):
+                    c.authors.append((h.email(a), h.person(a)))
+                return render('files/files_history_box.html')
+
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
                                    'repository.admin')
@@ -530,6 +551,8 @@
         :param changesets: if passed don't calculate history and take
             changesets defined in this list
         """
+        import time
+        s = time.time()
         # calculate history based on tip
         tip_cs = c.rhodecode_repo.get_changeset()
         if changesets is None:
@@ -538,7 +561,7 @@
             except (NodeDoesNotExistError, ChangesetError):
                 #this node is not present at tip !
                 changesets = cs.get_file_history(f_path)
-
+        print time.time()-s
         hist_l = []
 
         changesets_group = ([], _("Changesets"))
@@ -546,10 +569,11 @@
         tags_group = ([], _("Tags"))
         _hg = cs.repository.alias == 'hg'
         for chs in changesets:
-            _branch = '(%s)' % chs.branch if _hg else ''
+            #_branch = '(%s)' % chs.branch if _hg else ''
+            _branch = chs.branch
             n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
             changesets_group[0].append((chs.raw_id, n_desc,))
-
+        print time.time()-s
         hist_l.append(changesets_group)
 
         for name, chs in c.rhodecode_repo.branches.items():
@@ -559,7 +583,7 @@
         for name, chs in c.rhodecode_repo.tags.items():
             tags_group[0].append((chs, name),)
         hist_l.append(tags_group)
-
+        print time.time()-s
         return hist_l, changesets
 
     @LoginRequired()
--- a/rhodecode/public/js/rhodecode.js	Sat Nov 10 19:04:23 2012 +0100
+++ b/rhodecode/public/js/rhodecode.js	Tue Nov 13 22:26:06 2012 +0100
@@ -951,54 +951,53 @@
 	}
 };
 
-var  getSelectionLink = function(selection_link_label) {
-	return function(){
-	    //get selection from start/to nodes    	
-	    if (typeof window.getSelection != "undefined") {
-	    	s = window.getSelection();
+var  getSelectionLink = function(e) {
+	
+	//get selection from start/to nodes    	
+	if (typeof window.getSelection != "undefined") {
+		s = window.getSelection();
 	
-	       	from = getIdentNode(s.anchorNode);
-	       	till = getIdentNode(s.focusNode);
-	        
-	        f_int = parseInt(from.id.replace('L',''));
-	        t_int = parseInt(till.id.replace('L',''));
-	        
-	        if (f_int > t_int){
-	        	//highlight from bottom 
-	        	offset = -35;
-	        	ranges = [t_int,f_int];
-	        	
+	   	from = getIdentNode(s.anchorNode);
+	   	till = getIdentNode(s.focusNode);
+	   	
+	    f_int = parseInt(from.id.replace('L',''));
+	    t_int = parseInt(till.id.replace('L',''));
+	    
+	    if (f_int > t_int){
+	    	//highlight from bottom 
+	    	offset = -35;
+	    	ranges = [t_int,f_int];
+	    	
+	    }
+	    else{
+	    	//highligth from top 
+	    	offset = 35;
+	    	ranges = [f_int,t_int];
+	    }
+	    
+	    if (ranges[0] != ranges[1]){
+	        if(YUD.get('linktt') == null){
+	            hl_div = document.createElement('div');
+	            hl_div.id = 'linktt';
 	        }
-	        else{
-	        	//highligth from top 
-	        	offset = 35;
-	        	ranges = [f_int,t_int];
-	        }
+	        anchor = '#L'+ranges[0]+'-'+ranges[1];
+	        hl_div.innerHTML = '';
+	        l = document.createElement('a');
+	        l.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
+	        l.innerHTML = _TM['Selection link'];
+	        hl_div.appendChild(l);
 	        
-	        if (ranges[0] != ranges[1]){
-	            if(YUD.get('linktt') == null){
-	                hl_div = document.createElement('div');
-	                hl_div.id = 'linktt';
-	            }
-	            anchor = '#L'+ranges[0]+'-'+ranges[1];
-	            hl_div.innerHTML = '';
-	            l = document.createElement('a');
-	            l.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
-	            l.innerHTML = selection_link_label;
-	            hl_div.appendChild(l);
-	            
-	            YUD.get('body').appendChild(hl_div);
-	            
-	            xy = YUD.getXY(till.id);
-	            
-	            YUD.addClass('linktt','yui-tt');
-	            YUD.setStyle('linktt','top',xy[1]+offset+'px');
-	            YUD.setStyle('linktt','left',xy[0]+'px');
-	            YUD.setStyle('linktt','visibility','visible');
-	        }
-	        else{
-	        	YUD.setStyle('linktt','visibility','hidden');
-	        }
+	        YUD.get('body').appendChild(hl_div);
+	        
+	        xy = YUD.getXY(till.id);
+	        
+	        YUD.addClass('linktt','yui-tt');
+	        YUD.setStyle('linktt','top',xy[1]+offset+'px');
+	        YUD.setStyle('linktt','left',xy[0]+'px');
+	        YUD.setStyle('linktt','visibility','visible');
+	    }
+	    else{
+	    	YUD.setStyle('linktt','visibility','hidden');
 	    }
 	}
 };
--- a/rhodecode/templates/base/root.html	Sat Nov 10 19:04:23 2012 +0100
+++ b/rhodecode/templates/base/root.html	Tue Nov 13 22:26:06 2012 +0100
@@ -50,6 +50,7 @@
                 'Open new pull request': "${_('Open new pull request')}",
                 'Open new pull request for selected changesets':  "${_('Open new pull request for selected changesets')}",
                 'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
+                'Selection link': "${_('Selection link')}",
             };
             var _TM = TRANSLATION_MAP;
             </script>
--- a/rhodecode/templates/files/files.html	Sat Nov 10 19:04:23 2012 +0100
+++ b/rhodecode/templates/files/files.html	Tue Nov 13 22:26:06 2012 +0100
@@ -39,11 +39,13 @@
 
 <script type="text/javascript">
 var CACHE = {};
-var CACHE_EXPIRE = 60*1000; //cache for 60s
+var CACHE_EXPIRE = 5*60*1000; //cache for 5*60s
 //used to construct links from the search list
 var url_base = '${h.url("files_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
 //send the nodelist request to this url
 var node_list_url = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
+// send the node history requst to this url
+var node_history_url = '${h.url("files_history_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
 
 var ypjax_links = function(){
     YUE.on(YUQ('.ypjax-link'), 'click',function(e){
@@ -76,7 +78,7 @@
 
         // Change our States and save some data for handling events
         var data = {url:url,title:title, url_base:_url_base,
-                    node_list_url:_node_list_url};
+                    node_list_url:_node_list_url, rev:rev, f_path:f_path};
         History.pushState(data, title, url);
 
         //now we're sure that we can do ypjax things
@@ -89,8 +91,19 @@
     ypjax_links();
     tooltip_activate();
     fileBrowserListeners(State.url, State.data.node_list_url, State.data.url_base);
-    YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"));
-
+    
+    if(YUD.get('hlcode')){
+    	YUE.on('hlcode', 'mouseup', getSelectionLink);
+    }
+    //console.log(State);
+    if(YUD.get('load_node_history')){
+      //remove all listeners due to problems of history state
+      YUE.removeListener('load_node_history', 'click');
+      YUE.on('load_node_history', 'click', function(e){
+          var _url = node_history_url.replace('__REV__',State.data.rev).replace('__FPATH__', State.data.f_path);
+          ypjax(_url, 'node_history', function(o){})
+      });
+    }
     // Inform Google Analytics of the change
     if ( typeof window.pageTracker !== 'undefined' ) {
         window.pageTracker._trackPageview(State.url);
@@ -133,7 +146,9 @@
        url: "${h.url.current()}",
        data: {
          node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}"),
-         url_base: url_base.replace('__REV__',"${c.changeset.raw_id}")
+         url_base: url_base.replace('__REV__',"${c.changeset.raw_id}"),
+         rev:"${c.changeset.raw_id}",
+         f_path: "${h.safe_unicode(c.file.path)}"
        }
     }
     fileBrowserListeners(_State.url, _State.data.node_list_url, _State.data.url_base);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/templates/files/files_history_box.html	Tue Nov 13 22:26:06 2012 +0100
@@ -0,0 +1,25 @@
+<dl>
+    <dt class="file_history">${_('History')}</dt>
+    <dd>
+        <div>
+            <div style="float:left">
+            ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
+            ${h.hidden('diff2',c.file_changeset.raw_id)}
+            ${h.select('diff1',c.file_changeset.raw_id,c.file_history)}
+            ${h.submit('diff',_('diff to revision'),class_="ui-btn")}
+            ${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
+            ${h.hidden('annotate', c.annotate)}
+            ${h.end_form()}
+            </div>
+            <div class="file_author">
+                <div class="item">${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('<b>%s</b>' % len(c.authors))) }</div>
+                %for email, user in c.authors:
+                  <div class="contributor tooltip" style="float:left" title="${h.tooltip(user)}">
+                    <div class="gravatar" style="margin:1px"><img alt="gravatar" src="${h.gravatar_url(email, 20)}"/> </div>
+                  </div>
+                %endfor
+            </div>
+        </div>
+        <div style="clear:both"></div>
+    </dd>
+</dl>
\ No newline at end of file
--- a/rhodecode/templates/files/files_source.html	Sat Nov 10 19:04:23 2012 +0100
+++ b/rhodecode/templates/files/files_source.html	Tue Nov 13 22:26:06 2012 +0100
@@ -1,29 +1,13 @@
-<dl>
-	<dt class="file_history">${_('History')}</dt>
-	<dd>
-        <div>
-    		<div style="float:left">
-    		${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
-    		${h.hidden('diff2',c.file_changeset.raw_id)}
-    		${h.select('diff1',c.file_changeset.raw_id,c.file_history)}
-    		${h.submit('diff',_('diff to revision'),class_="ui-btn")}
-    		${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
-            ${h.hidden('annotate', c.annotate)}
-    		${h.end_form()}
-    		</div>
-            <div class="file_author">
-                <div class="item">${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('<b>%s</b>' % len(c.authors))) }</div>
-                %for email, user in c.authors:
-                  <div class="contributor tooltip" style="float:left" title="${h.tooltip(user)}">
-                    <div class="gravatar" style="margin:1px"><img alt="gravatar" src="${h.gravatar_url(email, 20)}"/> </div>
-                  </div>
-                %endfor
-            </div>
-        </div>
-        <div style="clear:both"></div>
-	</dd>
+<div id="node_history">
+%if c.load_full_history:
+    <%include file='files_history_box.html'/>
+%else:
+    <div style="padding-bottom:10px">
+        <span id="load_node_history" class="ui-btn">${_('Load file history')}</span>
+    </div>
+%endif
+</div>
 
-</dl>
 
 <div id="body" class="codeblock">
 	<div class="code-header">
@@ -113,6 +97,15 @@
 
     }
 
-    YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
+    // select code link event
+    YUE.on('hlcode', 'mouseup', getSelectionLink);
+
+    //load history of file
+    YUE.on('load_node_history', 'click', function(e){
+        var _url = node_history_url.replace('__REV__','${c.file_changeset.raw_id}').replace('__FPATH__', '${c.f_path}');
+        ypjax(_url, 'node_history', function(o){})
+    });    
+
    });
+   
 </script>