changeset 2664:c525d7e641a6 beta

rewrote admin repos page. - less info (no VCS data), but much faster. - having 1000s of repos is not a problem now - pagination/filtering using YUI datatable
author Marcin Kuzminski <marcin@python-works.com>
date Thu, 26 Jul 2012 22:03:40 +0200
parents cc8d7d450d15
children 81a17ef4afc0
files rhodecode/controllers/admin/repos.py rhodecode/templates/admin/repos/repos.html
diffstat 2 files changed, 131 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/controllers/admin/repos.py	Thu Jul 26 22:01:41 2012 +0200
+++ b/rhodecode/controllers/admin/repos.py	Thu Jul 26 22:03:40 2012 +0200
@@ -34,6 +34,7 @@
 from pylons.i18n.translation import _
 from sqlalchemy.exc import IntegrityError
 
+import rhodecode
 from rhodecode.lib import helpers as h
 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
     HasPermissionAnyDecorator, HasRepoPermissionAllDecorator
@@ -45,6 +46,7 @@
 from rhodecode.model.forms import RepoForm
 from rhodecode.model.scm import ScmModel
 from rhodecode.model.repo import RepoModel
+from rhodecode.lib.compat import json
 
 log = logging.getLogger(__name__)
 
@@ -131,9 +133,44 @@
         """GET /repos: All items in the collection"""
         # url('repos')
 
-        c.repos_list = ScmModel().get_repos(Repository.query()
-                                            .order_by(Repository.repo_name)
-                                            .all(), sort_key='name_sort')
+        c.repos_list = Repository.query()\
+                        .order_by(Repository.repo_name)\
+                        .all()
+
+        repos_data = []
+        total_records = len(c.repos_list)
+
+        _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
+        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
+
+        quick_menu = lambda repo_name: (template.get_def("quick_menu")
+                                        .render(repo_name, _=_, h=h))
+        repo_lnk = lambda name, rtype, private, fork_of: (
+            template.get_def("repo_name")
+            .render(name, rtype, private, fork_of, short_name=False, 
+                    admin=True, _=_, h=h))
+
+        repo_actions = lambda repo_name: (template.get_def("repo_actions")
+                                       .render(repo_name, _=_, h=h))
+
+        for repo in c.repos_list:
+            repos_data.append({
+                "menu": quick_menu(repo.repo_name),
+                "raw_name": repo.repo_name,
+                "name": repo_lnk(repo.repo_name, repo.repo_type, repo.private, repo.fork),
+                "desc": repo.description,
+                "owner": repo.user.username,
+                "action": repo_actions(repo.repo_name),
+            })
+
+        c.data = json.dumps({
+            "totalRecords": total_records,
+            "startIndex": 0,
+            "sort": "name",
+            "dir": "asc",
+            "records": repos_data
+        })
+
         return render('admin/repos/repos.html')
 
     @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
--- a/rhodecode/templates/admin/repos/repos.html	Thu Jul 26 22:01:41 2012 +0200
+++ b/rhodecode/templates/admin/repos/repos.html	Thu Jul 26 22:03:40 2012 +0200
@@ -5,9 +5,8 @@
     ${_('Repositories administration')} - ${c.rhodecode_name}
 </%def>
 
-
 <%def name="breadcrumbs_links()">
-    ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Repositories')}
+    <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="repo_count">0</span> ${_('repositories')}
 </%def>
 <%def name="page_nav()">
 	${self.menu('admin')}
@@ -23,102 +22,114 @@
           </li>
         </ul>
     </div>
-
-    <div class="table">
-        <div id='repos_list_wrap' class="yui-skin-sam">
-        <%cnt=0%>
-        <%namespace name="dt" file="/data_table/_dt_elements.html"/>
-
-        <table id="repos_list">
-         <thead>
-          <tr>
-            <th class="left"></th>
-  	        <th class="left">${_('Name')}</th>
-  	        <th class="left">${_('Description')}</th>
-  	        <th class="left">${_('Last change')}</th>
-  	        <th class="left">${_('Tip')}</th>
-  	        <th class="left">${_('Contact')}</th>
-            <th class="left">${_('Action')}</th>
-          </tr>
-         </thead>
+    <div class="table yui-skin-sam" id="repos_list_wrap"></div>
+    <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
+    
 
-          %for cnt,repo in enumerate(c.repos_list):
-          <tr class="parity${(cnt+1)%2}">
-              <td class="quick_repo_menu">
-                ${dt.quick_menu(repo['name'])}
-              </td>
-              <td class="reponame">
-                ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'), admin=True)}
-              </td>
-              ##DESCRIPTION
-              <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
-                 ${h.truncate(repo['description'],60)}</span>
-              </td>
-              ##LAST CHANGE
-              <td>
-                <span class="tooltip" date="${repo['last_change']}" title="${h.tooltip(repo['last_change'])}">${h.age(repo['last_change'])}</span>
-              </td>
-              ##LAST REVISION
-              <td>
-                  ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
-              </td>
-            <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
-              <td>
-                ${h.form(url('repo', repo_name=repo['name']),method='delete')}
-                  ${h.submit('remove_%s' % repo['name'],_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")}
-                ${h.end_form()}
-              </td>
-          </tr>
-          %endfor
-        </table>
-        </div>
-    </div>
 </div>
 <script>
+  var url = "${h.url('formatted_users', format='json')}";
+  var data = ${c.data|n};
+  var myDataSource = new YAHOO.util.DataSource(data);
+  myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
+
+  myDataSource.responseSchema = {
+      resultsList: "records",
+      fields: [
+         {key:"menu"},
+         {key:"raw_name"},
+         {key:"name"},
+         {key:"desc"},
+         {key:"owner"},
+         {key:"action"},
+      ]
+   };
+  myDataSource.doBeforeCallback = function(req,raw,res,cb) {
+      // This is the filter function
+      var data     = res.results || [],
+          filtered = [],
+          i,l;
+     
+      if (req) {
+          req = req.toLowerCase();
+          for (i = 0; i<data.length; i++) {
+              var pos = data[i].raw_name.toLowerCase().indexOf(req)
+              if (pos != -1) {
+                  filtered.push(data[i]);
+              }
+          }
+          res.results = filtered;
+      }
+      YUD.get('repo_count').innerHTML = res.results.length;
+      return res;
+  }
 
   // main table sorting
   var myColumnDefs = [
       {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
       {key:"name",label:"${_('Name')}",sortable:true,
-          sortOptions: { sortFunction: nameSort }},
+    	  sortOptions: { sortFunction: nameSort }},
       {key:"desc",label:"${_('Description')}",sortable:true},
-      {key:"last_change",label:"${_('Last Change')}",sortable:true,
-          sortOptions: { sortFunction: ageSort }},
-      {key:"tip",label:"${_('Tip')}",sortable:true,
-          sortOptions: { sortFunction: revisionSort }},
       {key:"owner",label:"${_('Owner')}",sortable:true},
       {key:"action",label:"${_('Action')}",sortable:false},
   ];
 
-  var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
-
-  myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
+  var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
+    sortedBy:{key:"name",dir:"asc"},
+    paginator: new YAHOO.widget.Paginator({
+        rowsPerPage: 15,
+        alwaysVisible: false,
+        template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
+        pageLinks: 5,
+        containerClass: 'pagination-wh',
+        currentPageClass: 'pager_curpage',
+        pageLinkClass: 'pager_link',
+        nextPageLinkLabel: '&gt;',
+        previousPageLinkLabel: '&lt;',
+        firstPageLinkLabel: '&lt;&lt;',
+        lastPageLinkLabel: '&gt;&gt;',
+        containers:['user-paginator']
+    }),
 
-  myDataSource.responseSchema = {
-      fields: [
-          {key:"menu"},
-          {key:"name"},
-          {key:"desc"},
-          {key:"last_change"},
-          {key:"tip"},
-          {key:"owner"},
-          {key:"action"},
-      ]
-  };
-
-  var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
-          {
-            sortedBy:{key:"name",dir:"asc"},
-            MSG_SORTASC:"${_('Click to sort ascending')}",
-            MSG_SORTDESC:"${_('Click to sort descending')}",
-            MSG_EMPTY:"${_('No records found.')}",
-            MSG_ERROR:"${_('Data error.')}",
-            MSG_LOADING:"${_('Loading...')}",
-          }
+    MSG_SORTASC:"${_('Click to sort ascending')}",
+    MSG_SORTDESC:"${_('Click to sort descending')}",
+    MSG_EMPTY:"${_('No records found.')}",
+    MSG_ERROR:"${_('Data error.')}",
+    MSG_LOADING:"${_('Loading...')}",
+  }
   );
   myDataTable.subscribe('postRenderEvent',function(oArgs) {
       tooltip_activate();
       quick_repo_menu();
   });
+  
+  var filterTimeout = null;
+
+  updateFilter  = function () {
+      // Reset timeout
+      filterTimeout = null;
+
+      // Reset sort
+      var state = myDataTable.getState();
+          state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
+
+      // Get filtered data
+      myDataSource.sendRequest(YUD.get('q_filter').value,{
+          success : myDataTable.onDataReturnInitializeTable,
+          failure : myDataTable.onDataReturnInitializeTable,
+          scope   : myDataTable,
+          argument: state
+      });
+
+  };  
+  YUE.on('q_filter','click',function(){
+      YUD.get('q_filter').value = '';
+   });
+
+  YUE.on('q_filter','keyup',function (e) {
+      clearTimeout(filterTimeout);
+      filterTimeout = setTimeout(updateFilter,600);
+  });  
 </script>
+
 </%def>