changeset 2936:62e493c7f436 beta

Added lightweight dashboard option. ref #500
author Marcin Kuzminski <marcin@python-works.com>
date Thu, 18 Oct 2012 20:16:00 +0200
parents 20c0af65ac52
children d439d408b415
files rhodecode/controllers/admin/settings.py rhodecode/controllers/home.py rhodecode/lib/base.py rhodecode/lib/helpers.py rhodecode/model/db.py rhodecode/model/forms.py rhodecode/model/scm.py rhodecode/templates/admin/settings/settings.html rhodecode/templates/data_table/_dt_elements.html rhodecode/templates/index_base.html
diffstat 10 files changed, 246 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/controllers/admin/settings.py	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/controllers/admin/settings.py	Thu Oct 18 20:16:00 2012 +0200
@@ -185,18 +185,23 @@
                 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
                 sett1.app_settings_value = \
                     form_result['rhodecode_show_public_icon']
+                Session().add(sett1)
 
                 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
                 sett2.app_settings_value = \
                     form_result['rhodecode_show_private_icon']
+                Session().add(sett2)
 
                 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
                 sett3.app_settings_value = \
                     form_result['rhodecode_stylify_metatags']
+                Session().add(sett3)
 
-                Session().add(sett1)
-                Session().add(sett2)
-                Session().add(sett3)
+                sett4 = RhodeCodeSetting.get_by_name_or_create('lightweight_dashboard')
+                sett4.app_settings_value = \
+                    form_result['rhodecode_lightweight_dashboard']
+                Session().add(sett4)
+
                 Session().commit()
                 set_rhodecode_config(config)
                 h.flash(_('Updated visualisation settings'),
--- a/rhodecode/controllers/home.py	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/controllers/home.py	Thu Oct 18 20:16:00 2012 +0200
@@ -26,11 +26,16 @@
 import logging
 
 from pylons import tmpl_context as c, request
+from pylons.i18n.translation import _
 from webob.exc import HTTPBadRequest
 
+import rhodecode
+from rhodecode.lib import helpers as h
+from rhodecode.lib.ext_json import json
 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
 
 log = logging.getLogger(__name__)
 
@@ -42,9 +47,55 @@
         super(HomeController, self).__before__()
 
     def index(self):
-        c.repos_list = self.scm_model.get_repos()
         c.groups = self.scm_model.get_repos_groups()
         c.group = None
+
+        if c.visual.lightweight_dashboard is False:
+            c.repos_list = self.scm_model.get_repos()
+        ## lightweight version of dashboard
+        else:
+            c.repos_list = Repository.query()\
+                            .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))
+            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": h.age(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
+            })
+
         return render('/index.html')
 
     def repo_switcher(self):
--- a/rhodecode/lib/base.py	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/lib/base.py	Thu Oct 18 20:16:00 2012 +0200
@@ -245,6 +245,7 @@
         c.visual.show_public_icon = str2bool(config.get('rhodecode_show_public_icon'))
         c.visual.show_private_icon = str2bool(config.get('rhodecode_show_private_icon'))
         c.visual.stylify_metatags = str2bool(config.get('rhodecode_stylify_metatags'))
+        c.visual.lightweight_dashboard = str2bool(config.get('rhodecode_lightweight_dashboard'))
 
         c.repo_name = get_repo_slug(request)
         c.backends = BACKENDS.keys()
--- a/rhodecode/lib/helpers.py	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/lib/helpers.py	Thu Oct 18 20:16:00 2012 +0200
@@ -42,7 +42,7 @@
 from rhodecode.lib.annotate import annotate_highlight
 from rhodecode.lib.utils import repo_name_slug
 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
-    get_changeset_safe, datetime_to_time, time_to_datetime
+    get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict
 from rhodecode.lib.markup_renderer import MarkupRenderer
 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
 from rhodecode.lib.vcs.backends.base import BaseChangeset
--- a/rhodecode/model/db.py	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/model/db.py	Thu Oct 18 20:16:00 2012 +0200
@@ -856,6 +856,10 @@
         Session().add(repo)
         Session().commit()
 
+    @property
+    def last_db_change(self):
+        return self.updated_on
+
     #==========================================================================
     # SCM PROPERTIES
     #==========================================================================
--- a/rhodecode/model/forms.py	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/model/forms.py	Thu Oct 18 20:16:00 2012 +0200
@@ -254,6 +254,8 @@
         rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
         rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
 
+        rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
+
     return _ApplicationVisualisationForm
 
 
--- a/rhodecode/model/scm.py	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/model/scm.py	Thu Oct 18 20:16:00 2012 +0200
@@ -115,6 +115,7 @@
             tmp_d = {}
             tmp_d['name'] = dbr.repo_name
             tmp_d['name_sort'] = tmp_d['name'].lower()
+            tmp_d['raw_name'] = tmp_d['name'].lower()
             tmp_d['description'] = dbr.description
             tmp_d['description_sort'] = tmp_d['description'].lower()
             tmp_d['last_change'] = last_change
@@ -149,6 +150,7 @@
             tmp_d = {}
             tmp_d['name'] = dbr.repo_name
             tmp_d['name_sort'] = tmp_d['name'].lower()
+            tmp_d['raw_name'] = tmp_d['name'].lower()
             tmp_d['description'] = dbr.description
             tmp_d['description_sort'] = tmp_d['description'].lower()
             tmp_d['dbrepo'] = dbr.get_dict()
--- a/rhodecode/templates/admin/settings/settings.html	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/templates/admin/settings/settings.html	Thu Oct 18 20:16:00 2012 +0200
@@ -122,6 +122,17 @@
         <!-- fields -->
 
         <div class="fields">
+             <div class="field">
+                <div class="label label-checkbox">
+                    <label>${_('General')}:</label>
+                </div>
+                <div class="checkboxes">
+                    <div class="checkbox">
+                        ${h.checkbox('rhodecode_lightweight_dashboard','True')}
+                        <label for="rhodecode_lightweight_dashboard">${_('Use lightweight dashboard')}</label>
+                    </div>
+                 </div>
+             </div>
 
              <div class="field">
                 <div class="label label-checkbox">
--- a/rhodecode/templates/data_table/_dt_elements.html	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/templates/data_table/_dt_elements.html	Thu Oct 18 20:16:00 2012 +0200
@@ -76,8 +76,8 @@
     ${h.link_to(get_name(name),h.url('summary_home',repo_name=name),class_="repo_name")}
    %endif
    %if fork_of:
-        <a href="${h.url('summary_home',repo_name=fork_of)}">
-        <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
+        <a href="${h.url('summary_home',repo_name=fork_of.repo_name)}">
+        <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
    %endif
   </div>
 </%def>
@@ -94,6 +94,22 @@
   </div>
 </%def>
 
+<%def name="rss(name)">
+  %if c.rhodecode_user.username != 'default':
+    <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon"  href="${h.url('rss_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
+  %else:
+    <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon"  href="${h.url('rss_feed_home',repo_name=name)}"></a>
+  %endif
+</%def>
+
+<%def name="atom(name)">
+  %if c.rhodecode_user.username != 'default':
+    <a title="${_('Subscribe to %s atom feed')% name}"  class="atom_icon" href="${h.url('atom_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
+  %else:
+    <a title="${_('Subscribe to %s atom feed')% name}"  class="atom_icon" href="${h.url('atom_feed_home',repo_name=name)}"></a>
+  %endif
+</%def>
+
 <%def name="user_gravatar(email, size=24)">
     <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(email, size)}"/> </div>
 </%def>
--- a/rhodecode/templates/index_base.html	Thu Oct 18 02:14:30 2012 +0200
+++ b/rhodecode/templates/index_base.html	Thu Oct 18 20:16:00 2012 +0200
@@ -59,10 +59,11 @@
             <div id="welcome" style="display:none;text-align:center">
                 <h1><a href="${h.url('home')}">${c.rhodecode_name} ${c.rhodecode_version}</a></h1>
             </div>
+             <%cnt=0%>
+             <%namespace name="dt" file="/data_table/_dt_elements.html"/>
+            % if c.visual.lightweight_dashboard is False:
+              ## old full detailed version
             <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>
@@ -85,7 +86,7 @@
                     </td>
                     ##REPO NAME AND ICONS
                     <td class="reponame">
-                      ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],repo['dbrepo_fork'].get('repo_name'),pageargs.get('short_repo_names'))}
+                      ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']),pageargs.get('short_repo_names'))}
                     </td>
                     ##DESCRIPTION
                     <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
@@ -106,38 +107,33 @@
                     ##
                     <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
                     <td>
-                      %if c.rhodecode_user.username != 'default':
-                        <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon"  href="${h.url('rss_feed_home',repo_name=repo['name'],api_key=c.rhodecode_user.api_key)}"></a>
-                      %else:
-                        <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon"  href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
-                      %endif:
+                      ${dt.rss(repo['name'])}
                     </td>
                     <td>
-                      %if c.rhodecode_user.username != 'default':
-                        <a title="${_('Subscribe to %s atom feed')%repo['name']}"  class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'],api_key=c.rhodecode_user.api_key)}"></a>
-                      %else:
-                        <a title="${_('Subscribe to %s atom feed')%repo['name']}"  class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
-                      %endif:
+                      ${dt.atom(repo['name'])}
                     </td>
                 </tr>
             %endfor
             </tbody>
             </table>
             </div>
+            % else:
+              ## lightweight version
+                <div class="yui-skin-sam" id="repos_list_wrap"></div>
+                <div id="user-paginator" style="padding: 0px 0px 0px 0px"></div>
+            % endif
         </div>
     </div>
+    % 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;
       }
 
-      var sort_by = "name";
-      var sort_dir = "asc";
-
       // groups table sorting
       var myColumnDefs = [
-          {key:"name",label:"${_('Group Name')}",sortable:true,
+          {key:"name",label:"${_('Group name')}",sortable:true,
               sortOptions: { sortFunction: groupNameSort }},
           {key:"desc",label:"${_('Description')}",sortable:true},
       ];
@@ -152,13 +148,25 @@
           ]
       };
 
-      var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,
-              {
-               sortedBy:{key:"name",dir:"asc"},
-               MSG_SORTASC:"${_('Click to sort ascending')}",
-               MSG_SORTDESC:"${_('Click to sort descending')}"
-              }
-      );
+      var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,{
+          sortedBy:{key:"name",dir:"asc"},
+          paginator: new YAHOO.widget.Paginator({
+              rowsPerPage: 5,
+              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')}"
+      });
 
       // main table sorting
       var myColumnDefs = [
@@ -182,6 +190,7 @@
       myDataSource.responseSchema = {
           fields: [
               {key:"menu"},
+              //{key:"raw_name"},
               {key:"name"},
               {key:"desc"},
               {key:"last_change"},
@@ -194,7 +203,7 @@
 
       var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
               {
-               sortedBy:{key:sort_by,dir:sort_dir},
+    	       sortedBy:{key:"name",dir:"asc"},
                MSG_SORTASC:"${_('Click to sort ascending')}",
                MSG_SORTDESC:"${_('Click to sort descending')}",
                MSG_EMPTY:"${_('No records found.')}",
@@ -209,3 +218,115 @@
       });
 
     </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;
+      
+        myDataSource.responseSchema = {
+            resultsList: "records",
+            fields: [
+               {key:"menu"},
+               {key:"raw_name"},
+               {key:"name"},
+               {key:"desc"},
+               //{key:"last_change"},
+               {key:"owner"},
+               {key:"rss"},
+               {key:"atom"},
+            ]
+         };
+        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 }},
+            {key:"desc",label:"${_('Description')}",sortable:true},
+            //{key:"last_change",label:"${_('Last Change')}",sortable:true,
+            //    sortOptions: { sortFunction: ageSort }},
+            {key:"owner",label:"${_('Owner')}",sortable:true},
+            {key:"rss",label:"",sortable:false},
+            {key:"atom",label:"",sortable:false},
+        ];
+      
+        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']
+          }),
+      
+          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>
+    % endif
+    
\ No newline at end of file