changeset 3154:0226b6d6b2b5 beta

Use common function for generation of grid data - admin grid now has dedicated edit button, and uses changeset_cache - some small improvements to grid - all other datatables use this
author Marcin Kuzminski <marcin@python-works.com>
date Wed, 09 Jan 2013 01:59:43 +0100
parents 8046d1979674
children 0cb48c083c6b
files rhodecode/config/routing.py rhodecode/controllers/admin/repos.py rhodecode/controllers/admin/repos_groups.py rhodecode/controllers/admin/settings.py rhodecode/controllers/home.py rhodecode/controllers/journal.py rhodecode/model/repo.py rhodecode/public/css/style.css rhodecode/templates/admin/repos/repos.html rhodecode/templates/admin/users/user_edit_my_account.html rhodecode/templates/admin/users/user_edit_my_account_repos.html rhodecode/templates/data_table/_dt_elements.html rhodecode/templates/index_base.html rhodecode/templates/journal/journal.html rhodecode/templates/journal/journal_page_repos.html
diffstat 15 files changed, 611 insertions(+), 483 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/config/routing.py	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/config/routing.py	Wed Jan 09 01:59:43 2013 +0100
@@ -359,8 +359,6 @@
         m.connect('api', '/api')
 
     #USER JOURNAL
-    rmap.connect('journal_my_repos', '%s/journal_my_repos' % ADMIN_PREFIX,
-                 controller='journal', action='index_my_repos')
     rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
                  controller='journal', action='index')
     rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
--- a/rhodecode/controllers/admin/repos.py	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/controllers/admin/repos.py	Wed Jan 09 01:59:43 2013 +0100
@@ -135,40 +135,10 @@
                         .order_by(func.lower(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, c=c))
-        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, c=c))
-
-        repo_actions = lambda repo_name: (template.get_def("repo_actions")
-                                       .render(repo_name, _=_, h=h, c=c))
-
-        for repo in c.repos_list:
-            repos_data.append({
-                "menu": quick_menu(repo.repo_name),
-                "raw_name": repo.repo_name.lower(),
-                "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
-        })
+        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
+                                                   admin=True)
+        #json used to render the grid
+        c.data = json.dumps(repos_data)
 
         return render('admin/repos/repos.html')
 
--- a/rhodecode/controllers/admin/repos_groups.py	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/controllers/admin/repos_groups.py	Wed Jan 09 01:59:43 2013 +0100
@@ -295,54 +295,18 @@
         c.groups = self.scm_model.get_repos_groups(groups)
 
         if c.visual.lightweight_dashboard is False:
-            c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
-
-            c.repos_list = c.cached_repo_list
+            c.repo_list = self.scm_model.get_repos(all_repos=gr_filter)
         ## lightweight version of dashboard
         else:
             c.repos_list = Repository.query()\
                             .filter(Repository.group_id == id)\
                             .order_by(func.lower(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, c=c))
-            repo_lnk = lambda name, rtype, private, fork_of: (
-                template.get_def("repo_name")
-                .render(name, rtype, private, fork_of, short_name=False,
-                        admin=False, _=_, h=h, c=c))
-            last_change = lambda last_change:  (template.get_def("last_change")
-                                           .render(last_change, _=_, h=h, c=c))
-            rss_lnk = lambda repo_name: (template.get_def("rss")
-                                           .render(repo_name, _=_, h=h, c=c))
-            atom_lnk = lambda repo_name: (template.get_def("atom")
-                                           .render(repo_name, _=_, h=h, c=c))
-
-            for repo in c.repos_list:
-                repos_data.append({
-                    "menu": quick_menu(repo.repo_name),
-                    "raw_name": repo.repo_name.lower(),
-                    "name": repo_lnk(repo.repo_name, repo.repo_type,
-                                     repo.private, repo.fork),
-                    "last_change": last_change(repo.last_db_change),
-                    "desc": repo.description,
-                    "owner": h.person(repo.user.username),
-                    "rss": rss_lnk(repo.repo_name),
-                    "atom": atom_lnk(repo.repo_name),
-                })
-
-            c.data = json.dumps({
-                "totalRecords": total_records,
-                "startIndex": 0,
-                "sort": "name",
-                "dir": "asc",
-                "records": repos_data
-            })
+        repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
+                                                   admin=False)
+        #json used to render the grid
+        c.data = json.dumps(repos_data)
 
         return render('admin/repos_groups/repos_groups.html')
 
--- a/rhodecode/controllers/admin/settings.py	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/controllers/admin/settings.py	Wed Jan 09 01:59:43 2013 +0100
@@ -48,11 +48,12 @@
     ApplicationUiSettingsForm, ApplicationVisualisationForm
 from rhodecode.model.scm import ScmModel
 from rhodecode.model.user import UserModel
+from rhodecode.model.repo import RepoModel
 from rhodecode.model.db import User
 from rhodecode.model.notification import EmailNotificationModel
 from rhodecode.model.meta import Session
 from rhodecode.lib.utils2 import str2bool, safe_unicode
-
+from rhodecode.lib.compat import json
 log = logging.getLogger(__name__)
 
 
@@ -390,17 +391,22 @@
         # url('admin_settings_my_account')
 
         c.user = User.get(self.rhodecode_user.user_id)
-        all_repos = Session().query(Repository)\
-                     .filter(Repository.user_id == c.user.user_id)\
-                     .order_by(func.lower(Repository.repo_name)).all()
-
-        c.user_repos = ScmModel().get_repos(all_repos)
 
         if c.user.username == 'default':
             h.flash(_("You can't edit this user since it's"
               " crucial for entire application"), category='warning')
             return redirect(url('users'))
 
+        repos_list = Session().query(Repository)\
+                     .filter(Repository.user_id ==
+                             self.rhodecode_user.user_id)\
+                     .order_by(func.lower(Repository.repo_name)).all()
+
+        repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
+                                                   admin=True)
+        #json used to render the grid
+        c.data = json.dumps(repos_data)
+
         defaults = c.user.get_dict()
 
         c.form = htmlfill.render(
@@ -449,23 +455,14 @@
         return redirect(url('my_account'))
 
     @NotAnonymous()
-    def my_account_my_repos(self):
-        all_repos = Session().query(Repository)\
-            .filter(Repository.user_id == self.rhodecode_user.user_id)\
-            .order_by(func.lower(Repository.repo_name))\
-            .all()
-        c.user_repos = ScmModel().get_repos(all_repos)
-        return render('admin/users/user_edit_my_account_repos.html')
-
-    @NotAnonymous()
     def my_account_my_pullrequests(self):
         c.my_pull_requests = PullRequest.query()\
-                                .filter(PullRequest.user_id==
+                                .filter(PullRequest.user_id ==
                                         self.rhodecode_user.user_id)\
                                 .all()
         c.participate_in_pull_requests = \
             [x.pull_request for x in PullRequestReviewers.query()\
-                                    .filter(PullRequestReviewers.user_id==
+                                    .filter(PullRequestReviewers.user_id ==
                                             self.rhodecode_user.user_id)\
                                     .all()]
         return render('admin/users/user_edit_my_account_pullrequests.html')
--- a/rhodecode/controllers/home.py	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/controllers/home.py	Wed Jan 09 01:59:43 2013 +0100
@@ -28,6 +28,7 @@
 from pylons import tmpl_context as c, request
 from pylons.i18n.translation import _
 from webob.exc import HTTPBadRequest
+from sqlalchemy.sql.expression import func
 
 import rhodecode
 from rhodecode.lib import helpers as h
@@ -35,7 +36,8 @@
 from rhodecode.lib.auth import LoginRequired
 from rhodecode.lib.base import BaseController, render
 from rhodecode.model.db import Repository
-from sqlalchemy.sql.expression import func
+from rhodecode.model.repo import RepoModel
+
 
 log = logging.getLogger(__name__)
 
@@ -58,59 +60,11 @@
                             .filter(Repository.group_id == None)\
                             .order_by(func.lower(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, c=c))
-            repo_lnk = lambda name, rtype, private, fork_of: (
-                template.get_def("repo_name")
-                .render(name, rtype, private, fork_of, short_name=False,
-                        admin=False, _=_, h=h, c=c))
-            last_change = lambda last_change:  (template.get_def("last_change")
-                                           .render(last_change, _=_, h=h, c=c))
-            rss_lnk = lambda repo_name: (template.get_def("rss")
-                                           .render(repo_name, _=_, h=h, c=c))
-            atom_lnk = lambda repo_name: (template.get_def("atom")
-                                           .render(repo_name, _=_, h=h, c=c))
-            tip = lambda repo_name, cs_cache: (template.get_def("revision")
-                                    .render(repo_name,
-                                            cs_cache.get('revision'),
-                                            cs_cache.get('raw_id'),
-                                            cs_cache.get('author'),
-                                            cs_cache.get('message'), _=_, h=h,
-                                            c=c))
-
-            def desc(desc):
-                if c.visual.stylify_metatags:
-                    return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
-                else:
-                    return h.urlify_text(h.truncate(desc, 60))
-
-            for repo in c.repos_list:
-                repos_data.append({
-                    "menu": quick_menu(repo.repo_name),
-                    "raw_name": repo.repo_name.lower(),
-                    "name": repo_lnk(repo.repo_name, repo.repo_type,
-                                     repo.private, repo.fork),
-                    "last_change": last_change(repo.last_db_change),
-                    "tip": tip(repo.repo_name, repo.changeset_cache),
-                    "desc": desc(repo.description),
-                    "owner": h.person(repo.user.username),
-                    "rss": rss_lnk(repo.repo_name),
-                    "atom": atom_lnk(repo.repo_name),
-                })
-
-            c.data = json.dumps({
-                "totalRecords": total_records,
-                "startIndex": 0,
-                "sort": "name",
-                "dir": "asc",
-                "records": repos_data
-            })
+            repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
+                                                       admin=False)
+            #json used to render the grid
+            c.data = json.dumps(repos_data)
 
         return render('/index.html')
 
--- a/rhodecode/controllers/journal.py	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/controllers/journal.py	Wed Jan 09 01:59:43 2013 +0100
@@ -27,6 +27,8 @@
 
 from sqlalchemy import or_
 from sqlalchemy.orm import joinedload
+from sqlalchemy.sql.expression import func
+
 from webhelpers.paginate import Page
 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
 
@@ -39,10 +41,10 @@
 from rhodecode.lib.base import BaseController, render
 from rhodecode.model.db import UserLog, UserFollowing, Repository, User
 from rhodecode.model.meta import Session
-from sqlalchemy.sql.expression import func
-from rhodecode.model.scm import ScmModel
 from rhodecode.lib.utils2 import safe_int, AttributeDict
 from rhodecode.controllers.admin.admin import _journal_filter
+from rhodecode.model.repo import RepoModel
+from rhodecode.lib.compat import json
 
 log = logging.getLogger(__name__)
 
@@ -78,18 +80,73 @@
         c.journal_data = render('journal/journal_data.html')
         if request.environ.get('HTTP_X_PARTIAL_XHR'):
             return c.journal_data
-        return render('journal/journal.html')
+
+        repos_list = Session().query(Repository)\
+                     .filter(Repository.user_id ==
+                             self.rhodecode_user.user_id)\
+                     .order_by(func.lower(Repository.repo_name)).all()
+
+        repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
+                                                   admin=True)
+        #json used to render the grid
+        c.data = json.dumps(repos_data)
+
+        watched_repos_data = []
+
+        ## watched repos
+        _render = RepoModel._render_datatable
+
+        def quick_menu(repo_name):
+            return _render('quick_menu', repo_name)
+
+        def repo_lnk(name, rtype, private, fork_of):
+            return _render('repo_name', name, rtype, private, fork_of,
+                           short_name=False, admin=False)
+
+        def last_rev(repo_name, cs_cache):
+            return _render('revision', repo_name, cs_cache.get('revision'),
+                           cs_cache.get('raw_id'), cs_cache.get('author'),
+                           cs_cache.get('message'))
 
-    @LoginRequired()
-    @NotAnonymous()
-    def index_my_repos(self):
-        c.user = User.get(self.rhodecode_user.user_id)
-        if request.environ.get('HTTP_X_PARTIAL_XHR'):
-            all_repos = self.sa.query(Repository)\
-                     .filter(Repository.user_id == c.user.user_id)\
-                     .order_by(func.lower(Repository.repo_name)).all()
-            c.user_repos = ScmModel().get_repos(all_repos)
-            return render('journal/journal_page_repos.html')
+        def desc(desc):
+            from pylons import tmpl_context as c
+            if c.visual.stylify_metatags:
+                return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
+            else:
+                return h.urlify_text(h.truncate(desc, 60))
+
+        def repo_actions(repo_name):
+            return _render('repo_actions', repo_name)
+
+        def owner_actions(user_id, username):
+            return _render('user_name', user_id, username)
+
+        def toogle_follow(repo_id):
+            return  _render('toggle_follow', repo_id)
+
+        for entry in c.following:
+            repo = entry.follows_repository
+            cs_cache = repo.changeset_cache
+            row = {
+                "menu": quick_menu(repo.repo_name),
+                "raw_name": repo.repo_name.lower(),
+                "name": repo_lnk(repo.repo_name, repo.repo_type,
+                                 repo.private, repo.fork),
+                "last_changeset": last_rev(repo.repo_name, cs_cache),
+                "raw_tip": cs_cache.get('revision'),
+                "action": toogle_follow(repo.repo_id)
+            }
+
+            watched_repos_data.append(row)
+
+        c.watched_data = json.dumps({
+            "totalRecords": len(c.following),
+            "startIndex": 0,
+            "sort": "name",
+            "dir": "asc",
+            "records": watched_repos_data
+        })
+        return render('journal/journal.html')
 
     @LoginRequired(api_access=True)
     @NotAnonymous()
--- a/rhodecode/model/repo.py	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/model/repo.py	Wed Jan 09 01:59:43 2013 +0100
@@ -41,6 +41,7 @@
     Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
     RhodeCodeSetting
 from rhodecode.lib import helpers as h
+from rhodecode.lib.auth import HasRepoPermissionAny
 
 
 log = logging.getLogger(__name__)
@@ -113,6 +114,95 @@
             } for gr in users_groups]
         )
 
+    @classmethod
+    def _render_datatable(cls, tmpl, *args, **kwargs):
+        import rhodecode
+        from pylons import tmpl_context as c
+        from pylons.i18n.translation import _
+
+        _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
+        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
+
+        tmpl = template.get_def(tmpl)
+        kwargs.update(dict(_=_, h=h, c=c))
+        return tmpl.render(*args, **kwargs)
+
+    def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True):
+        _render = self._render_datatable
+
+        def quick_menu(repo_name):
+            return _render('quick_menu', repo_name)
+
+        def repo_lnk(name, rtype, private, fork_of):
+            return _render('repo_name', name, rtype, private, fork_of,
+                           short_name=not admin, admin=False)
+
+        def last_change(last_change):
+            return _render("last_change", last_change)
+
+        def rss_lnk(repo_name):
+            return _render("rss", repo_name)
+
+        def atom_lnk(repo_name):
+            return _render("atom", repo_name)
+
+        def last_rev(repo_name, cs_cache):
+            return _render('revision', repo_name, cs_cache.get('revision'),
+                           cs_cache.get('raw_id'), cs_cache.get('author'),
+                           cs_cache.get('message'))
+
+        def desc(desc):
+            from pylons import tmpl_context as c
+            if c.visual.stylify_metatags:
+                return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
+            else:
+                return h.urlify_text(h.truncate(desc, 60))
+
+        def repo_actions(repo_name):
+            return _render('repo_actions', repo_name)
+
+        def owner_actions(user_id, username):
+            return _render('user_name', user_id, username)
+
+        repos_data = []
+        for repo in repos_list:
+            if perm_check:
+                # check permission at this level
+                if not HasRepoPermissionAny(
+                    'repository.read', 'repository.write', 'repository.admin'
+                )(repo.repo_name, 'get_repos_as_dict check'):
+                    continue
+            cs_cache = repo.changeset_cache
+            row = {
+                "menu": quick_menu(repo.repo_name),
+                "raw_name": repo.repo_name.lower(),
+                "name": repo_lnk(repo.repo_name, repo.repo_type,
+                                 repo.private, repo.fork),
+                "last_change": last_change(repo.last_db_change),
+                "last_changeset": last_rev(repo.repo_name, cs_cache),
+                "raw_tip": cs_cache.get('revision'),
+                "desc": desc(repo.description),
+                "owner": h.person(repo.user.username),
+                "rss": rss_lnk(repo.repo_name),
+                "atom": atom_lnk(repo.repo_name),
+
+            }
+            if admin:
+                row.update({
+                    "action": repo_actions(repo.repo_name),
+                    "owner": owner_actions(repo.user.user_id,
+                                           h.person(repo.user.username))
+                })
+            repos_data.append(row)
+
+        return {
+            "totalRecords": len(repos_list),
+            "startIndex": 0,
+            "sort": "name",
+            "dir": "asc",
+            "records": repos_data
+        }
+
     def _get_defaults(self, repo_name):
         """
         Get's information about repository, and returns a dict for
--- a/rhodecode/public/css/style.css	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/public/css/style.css	Wed Jan 09 01:59:43 2013 +0100
@@ -3235,7 +3235,7 @@
 }
 
 .edit_icon {
-	background: url("../images/icons/folder_edit.png") no-repeat scroll 3px;
+	background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
 	padding-left: 20px;
 	padding-top: 0px;
 	text-align: left;
--- a/rhodecode/templates/admin/repos/repos.html	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/templates/admin/repos/repos.html	Wed Jan 09 01:59:43 2013 +0100
@@ -40,6 +40,7 @@
          {key:"raw_name"},
          {key:"name"},
          {key:"desc"},
+         {key:"last_changeset"},
          {key:"owner"},
          {key:"action"},
       ]
@@ -70,6 +71,8 @@
       {key:"name",label:"${_('Name')}",sortable:true,
     	  sortOptions: { sortFunction: nameSort }},
       {key:"desc",label:"${_('Description')}",sortable:true},
+      {key:"last_changeset",label:"${_('Tip')}",sortable:true,
+          sortOptions: { sortFunction: revisionSort }},      
       {key:"owner",label:"${_('Owner')}",sortable:true},
       {key:"action",label:"${_('Action')}",sortable:false},
   ];
@@ -77,7 +80,7 @@
   var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
     sortedBy:{key:"name",dir:"asc"},
     paginator: new YAHOO.widget.Paginator({
-        rowsPerPage: 15,
+        rowsPerPage: 25,
         alwaysVisible: false,
         template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
         pageLinks: 5,
@@ -111,7 +114,7 @@
 
       // Reset sort
       var state = myDataTable.getState();
-          state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
+      state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
 
       // Get filtered data
       myDataSource.sendRequest(YUD.get('q_filter').value,{
@@ -123,7 +126,11 @@
 
   };
   YUE.on('q_filter','click',function(){
-      YUD.get('q_filter').value = '';
+	  if(!YUD.hasClass('q_filter', 'loaded')){
+		  YUD.get('q_filter').value = '';
+		  //TODO: load here full list later to do search within groups
+		  YUD.addClass('q_filter', 'loaded');
+	  }
    });
 
   YUE.on('q_filter','keyup',function (e) {
--- a/rhodecode/templates/admin/users/user_edit_my_account.html	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/templates/admin/users/user_edit_my_account.html	Wed Jan 09 01:59:43 2013 +0100
@@ -48,7 +48,7 @@
          </ul>
     </div>
     <!-- end box / title -->
-    <div id="perms" class="table">
+    <div id="perms_container" class="table">
            %for section in sorted(c.rhodecode_user.permissions.keys()):
             <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
 
@@ -94,30 +94,26 @@
             </div>
            %endfor
     </div>
-    <div id="my" class="table" style="display:none">
+    <div id="my_container" style="display:none">
+        <div class="table yui-skin-sam" id="repos_list_wrap"></div>
+        <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
     </div>
-    <div id="pullrequests" class="table" style="display:none"></div>
+    <div id="pullrequests_container" class="table" style="display:none">
+        ## loaded via AJAX
+        ${_('Loading...')}    
+    </div>
 </div>
 
-
-
 <script type="text/javascript">
-var filter_activate = function(){
-    var nodes = YUQ('#my tr td a.repo_name');
-    var func = function(node){
-        return node.parentNode.parentNode.parentNode.parentNode;
-    }
-    q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
-}
 
 var show_perms = function(e){
     YUD.addClass('show_perms', 'current');
     YUD.removeClass('show_my','current');
     YUD.removeClass('show_pullrequests','current');
 
-    YUD.setStyle('my','display','none');
-    YUD.setStyle('pullrequests','display','none');
-    YUD.setStyle('perms','display','');
+    YUD.setStyle('my_container','display','none');
+    YUD.setStyle('pullrequests_container','display','none');
+    YUD.setStyle('perms_container','display','');
     YUD.setStyle('q_filter','display','none');
 }
 YUE.on('show_perms','click',function(e){
@@ -129,17 +125,14 @@
     YUD.removeClass('show_perms','current');
     YUD.removeClass('show_pullrequests','current');
 
-    YUD.setStyle('perms','display','none');
-    YUD.setStyle('pullrequests','display','none');
-    YUD.setStyle('my','display','');
+    YUD.setStyle('perms_container','display','none');
+    YUD.setStyle('pullrequests_container','display','none');
+    YUD.setStyle('my_container','display','');
     YUD.setStyle('q_filter','display','');
-
-
-    var url = "${h.url('journal_my_repos')}";
-    ypjax(url, 'my', function(){
-        table_sort();
-        filter_activate();
-    });
+    if(!YUD.hasClass('show_my', 'loaded')){
+    	table_renderer(${c.data |n});
+        YUD.addClass('show_my', 'loaded');
+    }
 }
 YUE.on('show_my','click',function(e){
 	show_my(e);
@@ -150,13 +143,13 @@
     YUD.removeClass('show_my','current');
     YUD.removeClass('show_perms','current');
 
-    YUD.setStyle('my','display','none');
-    YUD.setStyle('perms','display','none');
-    YUD.setStyle('pullrequests','display','');
+    YUD.setStyle('my_container','display','none');
+    YUD.setStyle('perms_container','display','none');
+    YUD.setStyle('pullrequests_container','display','');
     YUD.setStyle('q_filter','display','none');
 
     var url = "${h.url('admin_settings_my_pullrequests')}";
-    ypjax(url, 'pullrequests');
+    ypjax(url, 'pullrequests_container');
 }
 YUE.on('show_pullrequests','click',function(e){
 	show_pullrequests(e)
@@ -177,72 +170,109 @@
     }
 }
 
-// main table sorting
-var myColumnDefs = [
-    {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
-    {key:"name",label:"${_('Name')}",sortable:true,
-        sortOptions: { sortFunction: nameSort }},
-    {key:"tip",label:"${_('Tip')}",sortable:true,
-        sortOptions: { sortFunction: revisionSort }},
-    {key:"action1",label:"",sortable:false},
-    {key:"action2",label:"",sortable:false},
-];
+function table_renderer(data){
+	  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:"last_changeset"},
+	         {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;
+          }
+          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 }},
+	      {key:"last_changeset",label:"${_('Tip')}",sortable:true,
+	          sortOptions: { sortFunction: revisionSort }},      
+	      {key:"action",label:"${_('Action')}",sortable:false},
+	  ];
 
-function table_sort(){
-var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
-myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
-myDataSource.responseSchema = {
-    fields: [
-        {key:"menu"},
-        {key:"name"},
-        {key:"tip"},
-        {key:"action1"},
-        {key:"action2"},
-    ]
-};
-var trans_defs =  {
-    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...')}",
-}
-var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,trans_defs);
-myDataTable.subscribe('postRenderEvent',function(oArgs) {
-    tooltip_activate();
-    quick_repo_menu();
-    filter_activate();
-});
+	  var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
+	    sortedBy:{key:"name",dir:"asc"},
+	    paginator: new YAHOO.widget.Paginator({
+	        rowsPerPage: 50,
+	        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']
+	    }),
+
+	    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;
 
-var permsColumnDefs = [
-    {key:"name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: permNameSort }},
-    {key:"perm",label:"${_('Permission')}",sortable:false,},
-];
+	  updateFilter = function() {
+	      // Reset timeout
+	      filterTimeout = null;
 
-// perms repos table
-var myDataSource2 = new YAHOO.util.DataSource(YUD.get("tbl_list_repositories"));
-myDataSource2.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
-myDataSource2.responseSchema = {
-    fields: [
-        {key:"name"},
-        {key:"perm"},
-    ]
-};
+	      // Reset sort
+	      var state = myDataTable.getState();
+	      state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
 
-new YAHOO.widget.DataTable("tbl_list_wrap_repositories", permsColumnDefs, myDataSource2, trans_defs);
+	      // Get filtered data
+	      myDataSource.sendRequest(YUD.get('q_filter').value,{
+	          success : myDataTable.onDataReturnInitializeTable,
+	          failure : myDataTable.onDataReturnInitializeTable,
+	          scope   : myDataTable,
+	          argument: state
+	      });
 
-//perms groups table
-var myDataSource3 = new YAHOO.util.DataSource(YUD.get("tbl_list_repositories_groups"));
-myDataSource3.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
-myDataSource3.responseSchema = {
-    fields: [
-        {key:"name"},
-        {key:"perm"},
-    ]
-};
+	  };
+	  YUE.on('q_filter','click',function(){
+	      if(!YUD.hasClass('q_filter', 'loaded')){
+	          YUD.get('q_filter').value = '';
+	          //TODO: load here full list later to do search within groups
+	          YUD.addClass('q_filter', 'loaded');
+	      }
+	   });
 
-new YAHOO.widget.DataTable("tbl_list_wrap_repositories_groups", permsColumnDefs, myDataSource3, trans_defs);
-}
+	  YUE.on('q_filter','keyup',function (e) {
+	      clearTimeout(filterTimeout);
+	      filterTimeout = setTimeout(updateFilter,600);
+	  });
+	}
 </script>
 </%def>
--- a/rhodecode/templates/admin/users/user_edit_my_account_repos.html	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/templates/admin/users/user_edit_my_account_repos.html	Wed Jan 09 01:59:43 2013 +0100
@@ -1,46 +1,1 @@
-<div id='repos_list_wrap' class="yui-skin-sam">
-  <table id="repos_list">
-  <thead>
-      <tr>
-      <th></th>
-      <th class="left">${_('Name')}</th>
-      <th class="left">${_('Revision')}</th>
-      <th class="left">${_('Action')}</th>
-      <th class="left">${_('Action')}</th>
-  </thead>
-   <tbody>
-   <%namespace name="dt" file="/data_table/_dt_elements.html"/>
-   %if c.user_repos:
-       %for repo in c.user_repos:
-          <tr>
-              ##QUICK MENU
-              <td class="quick_repo_menu">
-                ${dt.quick_menu(repo['name'])}
-              </td>
-              ##REPO NAME AND ICONS
-              <td class="reponame">
-                ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']))}
-              </td>
-              ##LAST REVISION
-              <td>
-                  ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
-              </td>
-              <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
-              <td>
-                ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
-                  ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")}
-                ${h.end_form()}
-              </td>
-          </tr>
-       %endfor
-   %else:
-      <div style="padding:5px 0px 10px 0px;">
-      ${_('No repositories yet')}
-      %if h.HasPermissionAny('hg.admin','hg.create.repository')():
-          ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")}
-      %endif
-      </div>
-   %endif
-   </tbody>
-   </table>
-</div>
+
--- a/rhodecode/templates/data_table/_dt_elements.html	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/templates/data_table/_dt_elements.html	Wed Jan 09 01:59:43 2013 +0100
@@ -2,12 +2,6 @@
 ## usage:
 ## <%namespace name="dt" file="/data_table/_dt_elements.html"/>
 
-<%def name="repo_actions(repo_name)">
-  ${h.form(h.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()}
-</%def>
-
 <%def name="quick_menu(repo_name)">
   <ul class="menu_items hidden">
     <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
@@ -46,7 +40,7 @@
   </ul>
 </%def>
 
-<%def name="repo_name(name,rtype,private,fork_of,short_name=False, admin=False)">
+<%def name="repo_name(name,rtype,private,fork_of,short_name=False,admin=False)">
     <%
     def get_name(name,short_name=short_name):
       if short_name:
@@ -116,6 +110,21 @@
     <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(email, size)}"/> </div>
 </%def>
 
+<%def name="repo_actions(repo_name)">
+  <div>
+    <div style="float:left">
+    <a href="${h.url('repo_settings_home',repo_name=repo_name)}" title="${_('edit')}">
+      ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
+    </a>
+    </div>
+    <div style="float:left">
+    ${h.form(h.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()}
+    </div>
+  </div>  
+</%def>
+
 <%def name="user_actions(user_id, username)">
   ${h.form(h.url('delete_user', id=user_id),method='delete')}
       ${h.submit('remove_',_('delete'),id="remove_user_%s" % user_id,
@@ -126,3 +135,10 @@
 <%def name="user_name(user_id, username)">
     ${h.link_to(username,h.url('edit_user', id=user_id))}
 </%def>
+
+<%def name="toggle_follow(repo_id)">
+  <span id="follow_toggle_${repo_id}" class="following" title="${_('Stop following this repository')}"
+        onclick="javascript:toggleFollowingRepo(this, ${repo_id},'${str(h.get_token())}')">
+  </span>
+</%def>
+
--- a/rhodecode/templates/index_base.html	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/templates/index_base.html	Wed Jan 09 01:59:43 2013 +0100
@@ -127,9 +127,6 @@
     % if c.visual.lightweight_dashboard is False:
     <script>
       YUD.get('repo_count').innerHTML = ${cnt+1 if cnt else 0};
-      var func = function(node){
-          return node.parentNode.parentNode.parentNode.parentNode;
-      }
 
       // groups table sorting
       var myColumnDefs = [
@@ -214,13 +211,15 @@
       myDataTable.subscribe('postRenderEvent',function(oArgs) {
           tooltip_activate();
           quick_repo_menu();
+          var func = function(node){
+              return node.parentNode.parentNode.parentNode.parentNode;
+          }          
           q_filter('q_filter',YUQ('div.table tr td a.repo_name'),func);
       });
 
     </script>
     % else:
       <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;
@@ -233,7 +232,7 @@
                {key:"name"},
                {key:"desc"},
                {key:"last_change"},
-               {key: "tip"},
+               {key:"last_changeset"},
                {key:"owner"},
                {key:"rss"},
                {key:"atom"},
@@ -267,7 +266,7 @@
             {key:"desc",label:"${_('Description')}",sortable:true},
             {key:"last_change",label:"${_('Last Change')}",sortable:true,
                 sortOptions: { sortFunction: ageSort }},
-            {key:"tip",label:"${_('Tip')}",sortable:true,
+            {key:"last_changeset",label:"${_('Tip')}",sortable:true,
                 sortOptions: { sortFunction: revisionSort }},
             {key:"owner",label:"${_('Owner')}",sortable:true},
             {key:"rss",label:"",sortable:false},
@@ -311,7 +310,7 @@
 
             // Reset sort
             var state = myDataTable.getState();
-                state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
+            state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
 
             // Get filtered data
             myDataSource.sendRequest(YUD.get('q_filter').value,{
@@ -323,7 +322,11 @@
 
         };
         YUE.on('q_filter','click',function(){
-            YUD.get('q_filter').value = '';
+            if(!YUD.hasClass('q_filter', 'loaded')){
+                YUD.get('q_filter').value = '';
+                //TODO: load here full list later to do search within groups
+                YUD.addClass('q_filter', 'loaded');
+            }
          });
 
         YUE.on('q_filter','keyup',function (e) {
--- a/rhodecode/templates/journal/journal.html	Tue Jan 08 20:42:48 2013 +0100
+++ b/rhodecode/templates/journal/journal.html	Wed Jan 09 01:59:43 2013 +0100
@@ -43,73 +43,36 @@
     </div>
     <div class="box box-right">
         <!-- box / title -->
+    
         <div class="title">
             <h5>
-            <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
-            <a id="show_watched" class="link-white" href="#watched">${_('Watched')}</a> / <a id="show_my" class="link-white" href="#my">${_('My repos')}</a>
+            <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}" style="display: none"/>
+            <input class="q_filter_box" id="q_filter_watched" size="15" type="text" name="filter" value="${_('quick filter...')}" style="display: none"/>
             </h5>
-             %if h.HasPermissionAny('hg.admin','hg.create.repository')():
-             <ul class="links">
+             <ul class="links" style="color:#DADADA">
                <li>
-                 <span>${h.link_to(_('ADD'),h.url('admin_settings_create_repository'))}</span>
+                 <span><a id="show_watched" class="link-white current" href="#watched">${_('Watched')}</a> </span>
+               </li>
+               <li>
+                 <span><a id="show_my" class="link-white" href="#my">${_('My repos')}</a> </span>
                </li>
+               %if h.HasPermissionAny('hg.admin','hg.create.repository')():
+                 <li>
+                   <span>${h.link_to(_('Add repo'),h.url('admin_settings_create_repository'))}</span>
+                 </li>
+               %endif
              </ul>
-             %endif
-        </div>
+        </div>        
+        
         <!-- end box / title -->
-        <div id="my" class="table" style="display:none">
-        ## loaded via AJAX
-        ${_('Loading...')}
+        <div id="my_container" style="display:none">
+            <div class="table yui-skin-sam" id="repos_list_wrap"></div>
+            <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
         </div>
-
-        <div id="watched" class="table">
-          %if c.following:
-            <table>
-            <thead>
-                <tr>
-                <th class="left">${_('Name')}</th>
-            </thead>
-             <tbody>
-                %for entry in c.following:
-                  <tr>
-                    <td>
-                      %if entry.follows_user_id:
-                        <img title="${_('following user')}" alt="${_('user')}" src="${h.url('/images/icons/user.png')}"/>
-                        ${entry.follows_user.full_contact}
-                      %endif
-
-                      %if entry.follows_repo_id:
-                        <div style="float:right;padding-right:5px">
-                        <span id="follow_toggle_${entry.follows_repository.repo_id}" class="following" title="${_('Stop following this repository')}"
-                              onclick="javascript:toggleFollowingRepo(this,${entry.follows_repository.repo_id},'${str(h.get_token())}')">
-                        </span>
-                        </div>
-
-                         %if h.is_hg(entry.follows_repository):
-                           <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
-                         %elif h.is_git(entry.follows_repository):
-                           <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
-                         %endif
-
-                        %if entry.follows_repository.private and c.visual.show_private_icon:
-                          <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
-                        %elif not entry.follows_repository.private and c.visual.show_public_icon:
-                          <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
-                        %endif
-                        <span class="watched_repo">
-                            ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',repo_name=entry.follows_repository.repo_name))}
-                        </span>
-                      %endif
-                    </td>
-                  </tr>
-                %endfor
-            </tbody>
-            </table>
-          %else:
-              <div style="padding:5px 0px 10px 0px;">
-              ${_('You are not following any users or repositories')}
-              </div>
-          %endif
+        
+        <div id="watched_container">
+            <div class="table yui-skin-sam" id="watched_repos_list_wrap"></div>
+            <div id="watched-user-paginator" style="padding: 0px 0px 0px 20px"></div>
         </div>
     </div>
 
@@ -134,29 +97,47 @@
     });
     fix_j_filter_width(YUD.get('j_filter').value.length);
 
-    var show_my = function(e){
-        YUD.setStyle('watched','display','none');
-        YUD.setStyle('my','display','');
-
-        var url = "${h.url('admin_settings_my_repos')}";
-        ypjax(url, 'my', function(){
+    YUE.on('refresh','click',function(e){
+        ypjax("${h.url.current(filter=c.search_term)}","journal",function(){
+            show_more_event();
             tooltip_activate();
-            quick_repo_menu();
-            var nodes = YUQ('#my tr td a.repo_name');
-            var func = function(node){
-                return node.parentNode.parentNode.parentNode;
-            }
-            q_filter('q_filter',nodes,func);
-        });
+            show_changeset_tooltip();
+            });
+        YUE.preventDefault(e);
+    });    
+    
+    var show_my = function(e){
+        YUD.setStyle('watched_container','display','none');
+        YUD.setStyle('my_container','display','');
+        YUD.setStyle('q_filter','display','');
+        YUD.setStyle('q_filter_watched','display','none');
 
+        YUD.addClass('show_my', 'current');
+        YUD.removeClass('show_watched','current');
+        
+        if(!YUD.hasClass('show_my', 'loaded')){
+            table_renderer(${c.data |n});
+            YUD.addClass('show_my', 'loaded');
+        }
     }
     YUE.on('show_my','click',function(e){
         show_my(e);
     })
     var show_watched = function(e){
-    	YUD.setStyle('my','display','none');
-        YUD.setStyle('watched','display','');
-        var nodes = YUQ('#watched .watched_repo a');
+    	YUD.setStyle('my_container','display','none');
+        YUD.setStyle('watched_container','display','');
+        YUD.setStyle('q_filter_watched','display','');
+        YUD.setStyle('q_filter','display','none');
+
+        YUD.addClass('show_watched', 'current');
+        YUD.removeClass('show_my','current');
+        if(!YUD.hasClass('show_watched', 'loaded')){
+        	watched_renderer(${c.watched_data |n});
+            YUD.addClass('show_watched', 'loaded');
+        }        
+        
+        return
+        var nodes = YUQ('#watched_container .watched_repo a');
         var target = 'q_filter';
         var func = function(node){
             return node.parentNode.parentNode;
@@ -182,60 +163,213 @@
         	func();
         }
     }
+    function watched_renderer(data){
+        var myDataSource = new YAHOO.util.DataSource(data);
+        myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
 
-    YUE.on('refresh','click',function(e){
-        ypjax("${h.url.current(filter=c.search_term)}","journal",function(){
-        	show_more_event();
-        	tooltip_activate();
-        	show_changeset_tooltip();
-        	});
-        YUE.preventDefault(e);
-    });
+        myDataSource.responseSchema = {
+            resultsList: "records",
+            fields: [
+               {key:"menu"},
+               {key:"raw_name"},
+               {key:"name"},
+               {key:"last_changeset"},
+               {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;
+            }
+            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 }},
+            {key:"last_changeset",label:"${_('Tip')}",sortable:true,
+                sortOptions: { sortFunction: revisionSort }},      
+            {key:"action",label:"${_('Action')}",sortable:false},
+        ];
 
-    // main table sorting
-    var myColumnDefs = [
-        {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
-        {key:"name",label:"${_('Name')}",sortable:true,
-            sortOptions: { sortFunction: nameSort }},
-        {key:"tip",label:"${_('Tip')}",sortable:true,
-            sortOptions: { sortFunction: revisionSort }},
-        {key:"action1",label:"",sortable:false},
-        {key:"action2",label:"",sortable:false},
-    ];
+        var myDataTable = new YAHOO.widget.DataTable("watched_repos_list_wrap", myColumnDefs, myDataSource,{
+          sortedBy:{key:"name",dir:"asc"},
+          paginator: new YAHOO.widget.Paginator({
+              rowsPerPage: 25,
+              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:['watched-user-paginator']
+          }),
 
-    var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
+          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;
 
-    myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
+            // 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_watched').value,{
+                success : myDataTable.onDataReturnInitializeTable,
+                failure : myDataTable.onDataReturnInitializeTable,
+                scope   : myDataTable,
+                argument: state
+            });
+
+        };
+        YUE.on('q_filter_watched','click',function(){
+            if(!YUD.hasClass('q_filter_watched', 'loaded')){
+                YUD.get('q_filter_watched').value = '';
+                //TODO: load here full list later to do search within groups
+                YUD.addClass('q_filter_watched', 'loaded');
+            }
+         });
 
-    myDataSource.responseSchema = {
-        fields: [
-            {key:"menu"},
-            {key:"name"},
-            {key:"tip"},
-            {key:"action1"},
-            {key:"action2"}
-        ]
-    };
+        YUE.on('q_filter_watched','keyup',function (e) {
+            clearTimeout(filterTimeout);
+            filterTimeout = setTimeout(updateFilter,600);
+        });
+      }
+    
+    function table_renderer(data){
+        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:"last_changeset"},
+               {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;
+            }
+            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 }},
+            {key:"last_changeset",label:"${_('Tip')}",sortable:true,
+                sortOptions: { sortFunction: revisionSort }},      
+            {key:"action",label:"${_('Action')}",sortable:false},
+        ];
 
-    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...')}",
+        var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
+          sortedBy:{key:"name",dir:"asc"},
+          paginator: new YAHOO.widget.Paginator({
+              rowsPerPage: 25,
+              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']
+          }),
+
+          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(){
+            if(!YUD.hasClass('q_filter', 'loaded')){
+                YUD.get('q_filter').value = '';
+                //TODO: load here full list later to do search within groups
+                YUD.addClass('q_filter', 'loaded');
             }
-    );
-    myDataTable.subscribe('postRenderEvent',function(oArgs) {
-        tooltip_activate();
-        quick_repo_menu();
-        var func = function(node){
-            return node.parentNode.parentNode.parentNode.parentNode;
-        }
-        q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
-    });
+         });
 
+        YUE.on('q_filter','keyup',function (e) {
+            clearTimeout(filterTimeout);
+            filterTimeout = setTimeout(updateFilter,600);
+        });
+      }    
+    
     </script>
 </%def>
--- a/rhodecode/templates/journal/journal_page_repos.html	Tue Jan 08 20:42:48 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-%if c.user_repos:
-<div id='repos_list_wrap' class="yui-skin-sam">
-<table id="repos_list">
- <thead>
-      <tr>
-      <th></th>
-      <th class="left">${_('Name')}</th>
-      <th class="left">${_('Revision')}</th>
-      <th class="left">${_('Action')}</th>
-      <th class="left">${_('Action')}</th>
- </thead>
- <tbody>
-     <%namespace name="dt" file="/data_table/_dt_elements.html"/>
-     %for repo in c.user_repos:
-        <tr>
-            ##QUICK MENU
-            <td class="quick_repo_menu">
-              ${dt.quick_menu(repo['name'])}
-            </td>
-            ##REPO NAME AND ICONS
-            <td class="reponame">
-              ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']))}
-            </td>
-            ##LAST REVISION
-            <td>
-                ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
-            </td>
-            ##
-            <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td>
-            <td>
-              ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
-                ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")}
-              ${h.end_form()}
-            </td>
-        </tr>
-     %endfor
- </tbody>
- </table>
- </div>
- %else:
-    <div style="padding:5px 0px 10px 0px;">
-    ${_('No repositories yet')}
-    %if h.HasPermissionAny('hg.admin','hg.create.repository')():
-        ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")}
-    %endif
-    </div>
- %endif