changeset 1045:3fc9183e05dd beta

another major codes rewrite: - created BaseRepo controller for all repo specific controller, and added common data propagation - removed obosete codes, and made optimizations, removed to often calls to RepoModel - fixed found bugs in files controller that generated unhandled 500 errors - cache issues - removed repo_branches global template values - journal fixes - main repo list is fully dict now it's less resource heavy that way
author Marcin Kuzminski <marcin@python-works.com>
date Tue, 15 Feb 2011 01:36:07 +0100
parents f3402cb92fdf
children 9e93cad9357b
files rhodecode/controllers/admin/settings.py rhodecode/controllers/branches.py rhodecode/controllers/changelog.py rhodecode/controllers/changeset.py rhodecode/controllers/feed.py rhodecode/controllers/files.py rhodecode/controllers/home.py rhodecode/controllers/journal.py rhodecode/controllers/search.py rhodecode/controllers/settings.py rhodecode/controllers/shortlog.py rhodecode/controllers/summary.py rhodecode/controllers/tags.py rhodecode/lib/base.py rhodecode/lib/helpers.py rhodecode/model/repo.py rhodecode/model/scm.py rhodecode/public/css/style.css rhodecode/templates/admin/repos/repos.html rhodecode/templates/admin/users/user_edit_my_account.html rhodecode/templates/base/base.html rhodecode/templates/index.html rhodecode/templates/journal/journal_data.html
diffstat 23 files changed, 215 insertions(+), 193 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/controllers/admin/settings.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/admin/settings.py	Tue Feb 15 01:36:07 2011 +0100
@@ -257,11 +257,9 @@
         # url('admin_settings_my_account')
 
         c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
-        all_repos = self.sa.query(Repository)\
-            .filter(Repository.user_id == c.user.user_id)\
-            .order_by(func.lower(Repository.repo_name))\
-            .all()
-
+        all_repos = [r.repo_name for r in 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)
 
         if c.user.username == 'default':
--- a/rhodecode/controllers/branches.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/branches.py	Tue Feb 15 01:36:07 2011 +0100
@@ -30,13 +30,12 @@
 from pylons import tmpl_context as c
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import OrderedDict
-from rhodecode.model.scm import ScmModel
 
 log = logging.getLogger(__name__)
 
-class BranchesController(BaseController):
+class BranchesController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -45,9 +44,9 @@
         super(BranchesController, self).__before__()
 
     def index(self):
-        c.repo_info, dbrepo = ScmModel().get(c.repo_name, retval='repo')
+
         c.repo_branches = OrderedDict()
-        for name, hash_ in c.repo_info.branches.items():
-            c.repo_branches[name] = c.repo_info.get_changeset(hash_)
+        for name, hash_ in c.rhodecode_repo.branches.items():
+            c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
 
         return render('branches/branches.html')
--- a/rhodecode/controllers/changelog.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/changelog.py	Tue Feb 15 01:36:07 2011 +0100
@@ -37,14 +37,13 @@
 from pylons import request, session, tmpl_context as c
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController, render
-from rhodecode.model.scm import ScmModel
+from rhodecode.lib.base import BaseRepoController, render
 
 from webhelpers.paginate import Page
 
 log = logging.getLogger(__name__)
 
-class ChangelogController(BaseController):
+class ChangelogController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -67,14 +66,12 @@
         else:
             c.size = int(session.get('changelog_size', default))
 
-        repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
-
         p = int(request.params.get('page', 1))
-        c.total_cs = len(repo)
-        c.pagination = Page(repo, page=p, item_count=c.total_cs,
+        c.total_cs = len(c.rhodecode_repo)
+        c.pagination = Page(c.rhodecode_repo, page=p, item_count=c.total_cs,
                             items_per_page=c.size)
 
-        self._graph(repo, c.size, p)
+        self._graph(c.rhodecode_repo, c.size, p)
 
         return render('changelog/changelog.html')
 
--- a/rhodecode/controllers/changeset.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/changeset.py	Tue Feb 15 01:36:07 2011 +0100
@@ -34,9 +34,8 @@
 
 import rhodecode.lib.helpers as h
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import EmptyChangeset
-from rhodecode.model.scm import ScmModel
 
 from vcs.exceptions import RepositoryError, ChangesetError, \
 ChangesetDoesNotExistError
@@ -46,7 +45,7 @@
 
 log = logging.getLogger(__name__)
 
-class ChangesetController(BaseController):
+class ChangesetController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -69,14 +68,13 @@
         rev_range = revision.split('...')[:2]
         range_limit = 50
         try:
-            repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
             if len(rev_range) == 2:
                 rev_start = rev_range[0]
                 rev_end = rev_range[1]
-                rev_ranges = repo.get_changesets_ranges(rev_start, rev_end,
+                rev_ranges = c.rhodecode_repo.get_changesets_ranges(rev_start, rev_end,
                                                        range_limit)
             else:
-                rev_ranges = [repo.get_changeset(revision)]
+                rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
 
             c.cs_ranges = list(rev_ranges)
 
@@ -164,9 +162,8 @@
 
         method = request.GET.get('diff', 'show')
         try:
-            repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
-            c.scm_type = repo.alias
-            c.changeset = repo.get_changeset(revision)
+            c.scm_type = c.rhodecode_repo.alias
+            c.changeset = c.rhodecode_repo.get_changeset(revision)
         except RepositoryError:
             log.error(traceback.format_exc())
             return redirect(url('home'))
@@ -182,7 +179,7 @@
                 if filenode_old.is_binary or node.is_binary:
                     diff = _('binary file') + '\n'
                 else:
-                    f_udiff = differ.get_udiff(filenode_old, node)
+                    f_udiff = differ.get_gitdiff(filenode_old, node)
                     diff = differ.DiffProcessor(f_udiff).raw_diff()
 
                 cs1 = None
@@ -194,7 +191,7 @@
                 if filenode_old.is_binary or node.is_binary:
                     diff = _('binary file')
                 else:
-                    f_udiff = differ.get_udiff(filenode_old, node)
+                    f_udiff = differ.get_gitdiff(filenode_old, node)
                     diff = differ.DiffProcessor(f_udiff).raw_diff()
 
                 cs1 = filenode_old.last_changeset.raw_id
--- a/rhodecode/controllers/feed.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/feed.py	Tue Feb 15 01:36:07 2011 +0100
@@ -27,18 +27,17 @@
 
 import logging
 
-from pylons import url, response
+from pylons import url, response, tmpl_context as c
 from pylons.i18n.translation import _
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController
-from rhodecode.model.scm import ScmModel
+from rhodecode.lib.base import BaseRepoController
 
 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
 
 log = logging.getLogger(__name__)
 
-class FeedController(BaseController):
+class FeedController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -60,9 +59,7 @@
                          language=self.language,
                          ttl=self.ttl)
 
-        repo, dbrepo = ScmModel().get(repo_name, retval='repo')
-
-        for cs in repo[:self.feed_nr]:
+        for cs in c.rhodecode_repo[:self.feed_nr]:
             feed.add_item(title=cs.message,
                           link=url('changeset_home', repo_name=repo_name,
                                    revision=cs.raw_id, qualified=True),
@@ -80,8 +77,7 @@
                          language=self.language,
                          ttl=self.ttl)
 
-        repo, dbrepo = ScmModel().get(repo_name, retval='repo')
-        for cs in repo[:self.feed_nr]:
+        for cs in c.rhodecode_repo[:self.feed_nr]:
             feed.add_item(title=cs.message,
                           link=url('changeset_home', repo_name=repo_name,
                                    revision=cs.raw_id, qualified=True),
--- a/rhodecode/controllers/files.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/files.py	Tue Feb 15 01:36:07 2011 +0100
@@ -24,30 +24,28 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA  02110-1301, USA.
-import tempfile
 import logging
 import rhodecode.lib.helpers as h
 
-from mercurial import archival
-
 from pylons import request, response, session, tmpl_context as c, url
 from pylons.i18n.translation import _
 from pylons.controllers.util import redirect
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import EmptyChangeset
-from rhodecode.model.scm import ScmModel
+from rhodecode.model.repo import RepoModel
 
 from vcs.backends import ARCHIVE_SPECS
 from vcs.exceptions import RepositoryError, ChangesetError, \
-    ChangesetDoesNotExistError, EmptyRepositoryError, ImproperArchiveTypeError
-from vcs.nodes import FileNode
+    ChangesetDoesNotExistError, EmptyRepositoryError, ImproperArchiveTypeError, \
+    VCSError
+from vcs.nodes import FileNode, NodeKind
 from vcs.utils import diffs as differ
 
 log = logging.getLogger(__name__)
 
-class FilesController(BaseController):
+class FilesController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -56,15 +54,30 @@
         super(FilesController, self).__before__()
         c.cut_off_limit = self.cut_off_limit
 
+    def __get_cs(self, rev, repo_name):
+        """
+        Safe way to get changeset if error ucure it redirects to given
+        :param rev: revision to fetch
+        :param repo_name: repo name to redirect after
+        """
+
+        try:
+            return c.rhodecode_repo.get_changeset(rev)
+        except EmptyRepositoryError, e:
+            h.flash(_('There are no files yet'), category='warning')
+            redirect(h.url('summary_home', repo_name=repo_name))
+
+        except RepositoryError, e:
+            h.flash(str(e), category='warning')
+            redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
+
     def index(self, repo_name, revision, f_path):
-        c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
-
 
         try:
             #reditect to given revision from form
             post_revision = request.POST.get('at_rev', None)
             if post_revision:
-                post_revision = c.repo.get_changeset(post_revision).raw_id
+                post_revision = c.rhodecode_repo.get_changeset(post_revision).raw_id
                 redirect(url('files_home', repo_name=c.repo_name,
                              revision=post_revision, f_path=f_path))
 
@@ -72,33 +85,33 @@
 
             c.f_path = f_path
 
-            c.changeset = c.repo.get_changeset(revision)
+            c.changeset = c.rhodecode_repo.get_changeset(revision)
             cur_rev = c.changeset.revision
 
             #prev link
             try:
-                prev_rev = c.repo.get_changeset(cur_rev).prev(c.branch).raw_id
+                prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch).raw_id
                 c.url_prev = url('files_home', repo_name=c.repo_name,
                              revision=prev_rev, f_path=f_path)
                 if c.branch:
                     c.url_prev += '?branch=%s' % c.branch
-            except ChangesetDoesNotExistError:
+            except (ChangesetDoesNotExistError, VCSError):
                 c.url_prev = '#'
 
             #next link
             try:
-                next_rev = c.repo.get_changeset(cur_rev).next(c.branch).raw_id
+                next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch).raw_id
                 c.url_next = url('files_home', repo_name=c.repo_name,
                          revision=next_rev, f_path=f_path)
                 if c.branch:
                     c.url_next += '?branch=%s' % c.branch
-            except ChangesetDoesNotExistError:
+            except (ChangesetDoesNotExistError, VCSError):
                 c.url_next = '#'
 
             #files
             try:
                 c.files_list = c.changeset.get_node(f_path)
-                c.file_history = self._get_history(c.repo, c.files_list, f_path)
+                c.file_history = self._get_history(c.rhodecode_repo, c.files_list, f_path)
             except RepositoryError, e:
                 h.flash(str(e), category='warning')
                 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
@@ -116,32 +129,40 @@
         return render('files/files.html')
 
     def rawfile(self, repo_name, revision, f_path):
-        c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
-        file_node = c.repo.get_changeset(revision).get_node(f_path)
+        cs = self.__get_cs(revision, repo_name)
+        try:
+            file_node = cs.get_node(f_path)
+        except RepositoryError, e:
+            h.flash(str(e), category='warning')
+            redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
+
         response.content_type = file_node.mimetype
         response.content_disposition = 'attachment; filename=%s' \
                                                     % f_path.split('/')[-1]
         return file_node.content
 
     def raw(self, repo_name, revision, f_path):
-        c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
-        file_node = c.repo.get_changeset(revision).get_node(f_path)
+        cs = self.__get_cs(revision, repo_name)
+        try:
+            file_node = cs.get_node(f_path)
+        except RepositoryError, e:
+            h.flash(str(e), category='warning')
+            redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
+
         response.content_type = 'text/plain'
 
         return file_node.content
 
     def annotate(self, repo_name, revision, f_path):
-        c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
-
+        cs = self.__get_cs(revision, repo_name)
         try:
-            c.cs = c.repo.get_changeset(revision)
-            c.file = c.cs.get_node(f_path)
+            c.file = cs.get_node(f_path)
         except RepositoryError, e:
             h.flash(str(e), category='warning')
-            redirect(h.url('files_home', repo_name=repo_name, revision=revision))
+            redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
 
-        c.file_history = self._get_history(c.repo, c.file, f_path)
-
+        c.file_history = self._get_history(c.rhodecode_repo, c.file, f_path)
+        c.cs = cs
         c.f_path = f_path
 
         return render('files/files_annotate.html')
@@ -160,12 +181,11 @@
                 ext = ext_data[1]
 
         try:
-            repo, dbrepo = ScmModel().get(repo_name)
-
+            dbrepo = RepoModel().get_by_repo_name(repo_name)
             if dbrepo.enable_downloads is False:
                 return _('downloads disabled')
 
-            cs = repo.get_changeset(revision)
+            cs = c.rhodecode_repo.get_changeset(revision)
             content_type = ARCHIVE_SPECS[fileformat][0]
         except ChangesetDoesNotExistError:
             return _('Unknown revision %s') % revision
@@ -187,18 +207,17 @@
         c.action = request.GET.get('diff')
         c.no_changes = diff1 == diff2
         c.f_path = f_path
-        c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
 
         try:
             if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
-                c.changeset_1 = c.repo.get_changeset(diff1)
+                c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
                 node1 = c.changeset_1.get_node(f_path)
             else:
                 c.changeset_1 = EmptyChangeset()
                 node1 = FileNode('.', '', changeset=c.changeset_1)
 
             if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
-                c.changeset_2 = c.repo.get_changeset(diff2)
+                c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
                 node2 = c.changeset_2.get_node(f_path)
             else:
                 c.changeset_2 = EmptyChangeset()
@@ -245,7 +264,6 @@
         return render('files/file_diff.html')
 
     def _get_history(self, repo, node, f_path):
-        from vcs.nodes import NodeKind
         if not node.kind is NodeKind.FILE:
             return []
         changesets = node.history
@@ -261,12 +279,12 @@
 
         hist_l.append(changesets_group)
 
-        for name, chs in c.repository_branches.items():
+        for name, chs in c.rhodecode_repo.branches.items():
             #chs = chs.split(':')[-1]
             branches_group[0].append((chs, name),)
         hist_l.append(branches_group)
 
-        for name, chs in c.repository_tags.items():
+        for name, chs in c.rhodecode_repo.tags.items():
             #chs = chs.split(':')[-1]
             tags_group[0].append((chs, name),)
         hist_l.append(tags_group)
--- a/rhodecode/controllers/home.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/home.py	Tue Feb 15 01:36:07 2011 +0100
@@ -32,7 +32,6 @@
 
 from rhodecode.lib.auth import LoginRequired
 from rhodecode.lib.base import BaseController, render
-from rhodecode.model.scm import ScmModel
 
 log = logging.getLogger(__name__)
 
@@ -53,14 +52,14 @@
         else:
             c.sort_by = current_sort
         c.sort_slug = current_sort_slug
-        cached_repo_list = ScmModel().get_repos()
 
         sort_key = current_sort_slug + '_sort'
+
         if c.sort_by.startswith('-'):
-            c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key),
+            c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
                                   reverse=True)
         else:
-            c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key),
+            c.repos_list = sorted(c.cached_repo_list, key=itemgetter(sort_key),
                                   reverse=False)
 
         return render('/index.html')
--- a/rhodecode/controllers/journal.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/journal.py	Tue Feb 15 01:36:07 2011 +0100
@@ -29,15 +29,15 @@
 from sqlalchemy import or_
 from sqlalchemy.orm import joinedload, make_transient
 from webhelpers.paginate import Page
+from itertools import groupby
 
 from paste.httpexceptions import HTTPInternalServerError
-from pylons import request, response, session, tmpl_context as c, url
+from pylons import request, tmpl_context as c
 
 from rhodecode.lib.auth import LoginRequired, NotAnonymous
 from rhodecode.lib.base import BaseController, render
 from rhodecode.lib.helpers import get_token
 from rhodecode.model.db import UserLog, UserFollowing
-from rhodecode.model.scm import ScmModel
 
 log = logging.getLogger(__name__)
 
@@ -51,6 +51,7 @@
 
     def index(self):
         # Return a rendered template
+
         c.following = self.sa.query(UserFollowing)\
             .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
             .options(joinedload(UserFollowing.follows_repository))\
@@ -71,7 +72,6 @@
             filtering_criterion = UserLog.repository_id.in_(repo_ids)
         if not repo_ids and user_ids:
             filtering_criterion = UserLog.user_id.in_(user_ids)
-
         if filtering_criterion is not None:
             journal = self.sa.query(UserLog)\
                 .options(joinedload(UserLog.user))\
@@ -80,19 +80,19 @@
                 .order_by(UserLog.action_date.desc())
         else:
             journal = []
+        p = int(request.params.get('page', 1))
 
-        p = int(request.params.get('page', 1))
-        c.journal_pager = Page(journal, page=p, items_per_page=10)
+        c.journal_pager = Page(journal, page=p, items_per_page=20)
+
         c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
+
         c.journal_data = render('journal/journal_data.html')
         if request.params.get('partial'):
             return c.journal_data
-
         return render('journal/journal.html')
 
 
     def _get_daily_aggregate(self, journal):
-        from itertools import groupby
         groups = []
         for k, g in groupby(journal, lambda x:x.action_as_day):
             user_group = []
@@ -109,12 +109,11 @@
         cur_token = request.POST.get('auth_token')
         token = get_token()
         if cur_token == token:
-            scm_model = ScmModel()
 
             user_id = request.POST.get('follows_user_id')
             if user_id:
                 try:
-                    scm_model.toggle_following_user(user_id,
+                    self.scm_model.toggle_following_user(user_id,
                                                     c.rhodecode_user.user_id)
                     return 'ok'
                 except:
@@ -123,7 +122,7 @@
             repo_id = request.POST.get('follows_repo_id')
             if repo_id:
                 try:
-                    scm_model.toggle_following_repo(repo_id,
+                    self.scm_model.toggle_following_repo(repo_id,
                                                     c.rhodecode_user.user_id)
                     return 'ok'
                 except:
--- a/rhodecode/controllers/search.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/search.py	Tue Feb 15 01:36:07 2011 +0100
@@ -28,8 +28,7 @@
 import traceback
 
 from pylons.i18n.translation import _
-from pylons import request, response, config, session, tmpl_context as c, url
-from pylons.controllers.util import abort, redirect
+from pylons import request, config, session, tmpl_context as c
 
 from rhodecode.lib.auth import LoginRequired
 from rhodecode.lib.base import BaseController, render
--- a/rhodecode/controllers/settings.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/settings.py	Tue Feb 15 01:36:07 2011 +0100
@@ -29,7 +29,6 @@
 import traceback
 
 import formencode
-from formencode import htmlfill
 
 from pylons import tmpl_context as c, request, url
 from pylons.controllers.util import redirect
@@ -37,7 +36,7 @@
 
 import rhodecode.lib.helpers as h
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
-from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import invalidate_cache, action_logger
 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
 from rhodecode.model.repo import RepoModel
@@ -45,7 +44,7 @@
 
 log = logging.getLogger(__name__)
 
-class SettingsController(BaseController):
+class SettingsController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAllDecorator('repository.admin')
@@ -87,7 +86,7 @@
             defaults.update({'g_perm_%s' % p.users_group.users_group_name:
                              p.permission.permission_name})
 
-        return htmlfill.render(
+        return formencode.htmlfill.render(
             render('settings/repo_settings.html'),
             defaults=defaults,
             encoding="UTF-8",
@@ -111,7 +110,7 @@
             c.repo_info = repo_model.get_by_repo_name(repo_name)
             c.users_array = repo_model.get_users_js()
             errors.value.update({'user':c.repo_info.user.username})
-            return htmlfill.render(
+            return formencode.htmlfill.render(
                 render('settings/repo_settings.html'),
                 defaults=errors.value,
                 errors=errors.error_dict or {},
@@ -192,7 +191,7 @@
             c.new_repo = errors.value['fork_name']
             r = render('settings/repo_fork.html')
 
-            return htmlfill.render(
+            return formencode.htmlfill.render(
                 r,
                 defaults=errors.value,
                 errors=errors.error_dict or {},
--- a/rhodecode/controllers/shortlog.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/shortlog.py	Tue Feb 15 01:36:07 2011 +0100
@@ -32,12 +32,11 @@
 from webhelpers.paginate import Page
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController, render
-from rhodecode.model.scm import ScmModel
+from rhodecode.lib.base import BaseRepoController, render
 
 log = logging.getLogger(__name__)
 
-class ShortlogController(BaseController):
+class ShortlogController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -47,8 +46,7 @@
 
     def index(self):
         p = int(request.params.get('page', 1))
-        repo, dbrepo = ScmModel().get(c.repo_name, 'repo')
-        c.repo_changesets = Page(repo, page=p, items_per_page=20)
+        c.repo_changesets = Page(c.rhodecode_repo, page=p, items_per_page=20)
         c.shortlog_data = render('shortlog/shortlog_data.html')
         if request.params.get('partial'):
             return c.shortlog_data
--- a/rhodecode/controllers/summary.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/summary.py	Tue Feb 15 01:36:07 2011 +0100
@@ -35,11 +35,10 @@
 from pylons import tmpl_context as c, request, url
 from pylons.i18n.translation import _
 
-from rhodecode.model.scm import ScmModel
 from rhodecode.model.db import Statistics
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
 
 from rhodecode.lib.celerylib import run_task
@@ -54,7 +53,7 @@
     import simplejson as json
 log = logging.getLogger(__name__)
 
-class SummaryController(BaseController):
+class SummaryController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -63,10 +62,10 @@
         super(SummaryController, self).__before__()
 
     def index(self):
-        scm_model = ScmModel()
-        c.repo, dbrepo = scm_model.get(c.repo_name)
+        c.repo, dbrepo = self.scm_model.get(c.repo_name)
         c.dbrepo = dbrepo
-        c.following = scm_model.is_following_repo(c.repo_name,
+
+        c.following = self.scm_model.is_following_repo(c.repo_name,
                                              c.rhodecode_user.user_id)
         def url_generator(**kw):
             return url('shortlog_home', repo_name=c.repo_name, **kw)
@@ -158,12 +157,12 @@
         branches_group = ([], _("Branches"))
         tags_group = ([], _("Tags"))
 
-        for name, chs in c.repository_branches.items():
+        for name, chs in c.rhodecode_repo.branches.items():
             #chs = chs.split(':')[-1]
             branches_group[0].append((chs, name),)
         download_l.append(branches_group)
 
-        for name, chs in c.repository_tags.items():
+        for name, chs in c.rhodecode_repo.tags.items():
             #chs = chs.split(':')[-1]
             tags_group[0].append((chs, name),)
         download_l.append(tags_group)
--- a/rhodecode/controllers/tags.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/controllers/tags.py	Tue Feb 15 01:36:07 2011 +0100
@@ -29,13 +29,12 @@
 from pylons import tmpl_context as c
 
 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
-from rhodecode.lib.base import BaseController, render
+from rhodecode.lib.base import BaseRepoController, render
 from rhodecode.lib.utils import OrderedDict
-from rhodecode.model.scm import ScmModel
 
 log = logging.getLogger(__name__)
 
-class TagsController(BaseController):
+class TagsController(BaseRepoController):
 
     @LoginRequired()
     @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -44,9 +43,8 @@
         super(TagsController, self).__before__()
 
     def index(self):
-        c.repo_info, dbrepo = ScmModel().get(c.repo_name, retval='repo')
         c.repo_tags = OrderedDict()
-        for name, hash_ in c.repo_info.tags.items():
-            c.repo_tags[name] = c.repo_info.get_changeset(hash_)
+        for name, hash_ in c.rhodecode_repo.tags.items():
+            c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_)
 
         return render('tags/tags.html')
--- a/rhodecode/lib/base.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/lib/base.py	Tue Feb 15 01:36:07 2011 +0100
@@ -23,24 +23,10 @@
         self.cut_off_limit = int(config.get('cut_off_limit'))
 
         self.sa = meta.Session()
-        scm_model = ScmModel(self.sa)
-        c.cached_repo_list = scm_model.get_repos()
+        self.scm_model = ScmModel(self.sa)
+        c.cached_repo_list = self.scm_model.get_repos()
         #c.unread_journal = scm_model.get_unread_journal()
 
-        if c.repo_name:
-            repo, dbrepo = scm_model.get(c.repo_name)
-            if repo:
-                c.repository_tags = repo.tags
-                c.repository_branches = repo.branches
-                c.repository_followers = scm_model.get_followers(dbrepo.repo_id)
-                c.repository_forks = scm_model.get_forks(dbrepo.repo_id)
-            else:
-                c.repository_tags = {}
-                c.repository_branches = {}
-                c.repository_followers = 0
-                c.repository_forks = 0
-
-
     def __call__(self, environ, start_response):
         """Invoke the Controller"""
         # WSGIController.__call__ dispatches to the Controller method
@@ -52,3 +38,26 @@
             return WSGIController.__call__(self, environ, start_response)
         finally:
             meta.Session.remove()
+
+
+class BaseRepoController(BaseController):
+    """
+    Base class for controllers responsible for loading all needed data
+    for those controllers, loaded items are
+    
+    c.rhodecode_repo: instance of scm repository (taken from cache)
+     
+    """
+
+    def __before__(self):
+        super(BaseRepoController, self).__before__()
+        if c.repo_name:
+
+            c.rhodecode_repo, dbrepo = self.scm_model.get(c.repo_name,
+                                                          retval='repo')
+            if c.rhodecode_repo:
+                c.repository_followers = self.scm_model.get_followers(c.repo_name)
+                c.repository_forks = self.scm_model.get_forks(c.repo_name)
+            else:
+                c.repository_followers = 0
+                c.repository_forks = 0
--- a/rhodecode/lib/helpers.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/lib/helpers.py	Tue Feb 15 01:36:07 2011 +0100
@@ -440,8 +440,11 @@
         revs_top_limit = 50 #show upto this amount of changesets hidden
         revs = action_params.split(',')
         repo_name = user_log.repository.repo_name
+
         from rhodecode.model.scm import ScmModel
-        repo, dbrepo = ScmModel().get(repo_name, retval='repo')
+        repo, dbrepo = ScmModel().get(repo_name, retval='repo',
+                                      invalidation_list=[])
+
         message = lambda rev: get_changeset_safe(repo, rev).message
 
         cs_links = " " + ', '.join ([link_to(rev,
@@ -481,14 +484,9 @@
         return cs_links
 
     def get_fork_name():
-        from rhodecode.model.scm import ScmModel
         repo_name = action_params
-        repo, dbrepo = ScmModel().get(repo_name)
-        if repo is None:
-            return repo_name
-        return link_to(action_params, url('summary_home',
-                                          repo_name=repo.name,),
-                                          title=dbrepo.description)
+        return str(link_to(action_params, url('summary_home',
+                                          repo_name=repo_name,)))
 
     map = {'user_deleted_repo':(_('[deleted] repository'), None),
            'user_created_repo':(_('[created] repository'), None),
--- a/rhodecode/model/repo.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/model/repo.py	Tue Feb 15 01:36:07 2011 +0100
@@ -30,7 +30,7 @@
 import traceback
 from datetime import datetime
 
-from sqlalchemy.orm import joinedload
+from sqlalchemy.orm import joinedload, make_transient
 
 from vcs.utils.lazy import LazyProperty
 from vcs.backends import get_backend
@@ -79,9 +79,6 @@
         repo = self.sa.query(Repository)\
             .options(joinedload(Repository.fork))\
             .options(joinedload(Repository.user))\
-            .options(joinedload(Repository.followers))\
-            .options(joinedload(Repository.repo_to_perm))\
-            .options(joinedload(Repository.users_group_to_perm))\
             .filter(Repository.repo_name == repo_name)\
 
         if cache:
@@ -91,7 +88,13 @@
             repo.invalidate()
 
         ret = repo.scalar()
-        self.sa.expunge_all()
+
+        #make transient for sake of errors
+        make_transient(ret)
+        for k in ['fork', 'user']:
+            attr = getattr(ret, k, False)
+            if attr:
+                make_transient(attr)
         return ret
 
 
--- a/rhodecode/model/scm.py	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/model/scm.py	Tue Feb 15 01:36:07 2011 +0100
@@ -32,6 +32,7 @@
 from mercurial import ui
 
 from sqlalchemy.exc import DatabaseError
+from sqlalchemy.orm import make_transient
 
 from beaker.cache import cache_region, region_invalidate
 
@@ -121,29 +122,27 @@
         and fill that backed with information from database
         
         :param all_repos: give specific repositories list, good for filtering
+            this have to be a list of  just the repository names
         """
-
         if all_repos is None:
-            all_repos = self.sa.query(Repository)\
-                .order_by(Repository.repo_name).all()
+            all_repos = [r.repo_name for r in self.sa.query(Repository)\
+                .order_by(Repository.repo_name).all()]
 
         #get the repositories that should be invalidated
         invalidation_list = [str(x.cache_key) for x in \
                              self.sa.query(CacheInvalidation.cache_key)\
                              .filter(CacheInvalidation.cache_active == False)\
                              .all()]
-
-        for r in all_repos:
-
-            r_dbr = self.get(r.repo_name, invalidation_list)
-
+        for r_name in all_repos:
+            r_dbr = self.get(r_name, invalidation_list)
             if r_dbr is not None:
                 repo, dbrepo = r_dbr
+
                 last_change = repo.last_change
                 tip = h.get_changeset_safe(repo, 'tip')
 
                 tmp_d = {}
-                tmp_d['name'] = r.repo_name
+                tmp_d['name'] = dbrepo.repo_name
                 tmp_d['name_sort'] = tmp_d['name'].lower()
                 tmp_d['description'] = dbrepo.description
                 tmp_d['description_sort'] = tmp_d['description']
@@ -158,7 +157,8 @@
                 tmp_d['repo_archives'] = list(repo._get_archives())
                 tmp_d['last_msg'] = tip.message
                 tmp_d['repo'] = repo
-                tmp_d['dbrepo'] = dbrepo
+                tmp_d['dbrepo'] = dbrepo.get_dict()
+                tmp_d['dbrepo_fork'] = dbrepo.fork.get_dict() if dbrepo.fork else {}
                 yield tmp_d
 
     def get(self, repo_name, invalidation_list=None, retval='all'):
@@ -226,7 +226,7 @@
         if retval == 'repo' or 'all':
             r = _get_repo(repo_name)
         if retval == 'dbrepo' or 'all':
-            dbr = RepoModel(self.sa).get_full(repo_name, cache=True,
+            dbr = RepoModel().get_full(repo_name, cache=True,
                                           invalidate=dbinvalidate)
 
 
@@ -341,12 +341,22 @@
         return f is not None
 
     def get_followers(self, repo_id):
-        return self.sa.query(UserFollowing)\
-                .filter(UserFollowing.follows_repo_id == repo_id).count()
+        if isinstance(repo_id, int):
+            return self.sa.query(UserFollowing)\
+                    .filter(UserFollowing.follows_repo_id == repo_id).count()
+        else:
+            return self.sa.query(UserFollowing)\
+                    .filter(UserFollowing.follows_repository \
+                            == RepoModel().get_by_repo_name(repo_id)).count()
 
     def get_forks(self, repo_id):
-        return self.sa.query(Repository)\
+        if isinstance(repo_id, int):
+            return self.sa.query(Repository)\
                 .filter(Repository.fork_id == repo_id).count()
+        else:
+            return self.sa.query(Repository)\
+                .filter(Repository.fork \
+                        == RepoModel().get_by_repo_name(repo_id)).count()
 
 
     def get_unread_journal(self):
--- a/rhodecode/public/css/style.css	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/public/css/style.css	Tue Feb 15 01:36:07 2011 +0100
@@ -1420,11 +1420,11 @@
 height: 30px;
 }
 #journal .journal_icon{
+clear: both;
 float: left;
-padding-top: 4px;
-padding-left:12px;
+padding-left: 36px;
 padding-right: 4px;
-clear: both;
+padding-top: 3px;
 }
 #journal .journal_action{
 padding-top:4px;
@@ -1436,7 +1436,12 @@
 margin-left: 6px;
 padding-top: 3px;
 }
-
+#journal .date{
+clear: both;
+color: #777777;
+font-size: 11px;
+padding-left: 56px;
+}
 #journal .journal_repo .journal_repo_name{
 font-weight: bold;
 font-size: 1.1em;
--- a/rhodecode/templates/admin/repos/repos.html	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/templates/admin/repos/repos.html	Tue Feb 15 01:36:07 2011 +0100
@@ -38,26 +38,26 @@
             <tr class="parity${cnt%2}">
                  <td>
                  ## TYPE OF REPO
-                 %if repo['dbrepo'].repo_type =='hg':
+                 %if repo['dbrepo']['repo_type'] =='hg':
                    <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
-                 %elif repo['dbrepo'].repo_type =='git':
+                 %elif repo['dbrepo']['repo_type'] =='git':
                    <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
                  %else:
                    
                  %endif
                  
                  ## PRIVATE/PUBLIC REPO                  
-                 %if repo['dbrepo'].private:
+                 %if repo['dbrepo']['private']:
                     <img alt="${_('private')}" src="/images/icons/lock.png"/>
                  %else:
                     <img alt="${_('public')}" src="/images/icons/lock_open.png"/>
                  %endif         
                 ${h.link_to(repo['name'],h.url('edit_repo',repo_name=repo['name']))}
                 
-	            %if repo['dbrepo'].fork:
-	            	<a href="${h.url('summary_home',repo_name=repo['dbrepo'].fork.repo_name)}">
+	            %if repo['dbrepo_fork']:
+	            	<a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
 	            	<img class="icon" alt="${_('public')}"
-	            	title="${_('Fork of')} ${repo['dbrepo'].fork.repo_name}" 
+	            	title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}" 
 	            	src="/images/icons/arrow_divide.png"/></a>
 	            %endif                
                 </td>
--- a/rhodecode/templates/admin/users/user_edit_my_account.html	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/templates/admin/users/user_edit_my_account.html	Tue Feb 15 01:36:07 2011 +0100
@@ -119,24 +119,24 @@
 		     %for repo in c.user_repos:
 		        <tr>
 		            <td>
-                     %if repo['dbrepo'].repo_type =='hg':
+                     %if repo['dbrepo']['repo_type'] =='hg':
                        <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
-                     %elif repo['dbrepo'].repo_type =='git':
+                     %elif repo['dbrepo']['repo_type'] =='git':
                        <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
                      %else:
                        
                      %endif 		            
-		             %if repo['dbrepo'].private:
+		             %if repo['dbrepo']['private']:
 		                <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
 		             %else:
 		                <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
 		             %endif
 		                                             
 		            ${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")}
-		            %if repo['dbrepo'].fork:
-		            	<a href="${h.url('summary_home',repo_name=repo['dbrepo'].fork.repo_name)}">
+		            %if repo['dbrepo_fork']:
+		            	<a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
 		            	<img class="icon" alt="${_('public')}"
-		            	title="${_('Fork of')} ${repo['dbrepo'].fork.repo_name}" 
+		            	title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}" 
 		            	src="/images/icons/arrow_divide.png"/></a>
 		            %endif		            
 		            </td> 
--- a/rhodecode/templates/base/base.html	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/templates/base/base.html	Tue Feb 15 01:36:07 2011 +0100
@@ -142,10 +142,10 @@
 					<ul class="repo_switcher">
                         %for repo in c.cached_repo_list:
                         
-                          %if repo['dbrepo'].private:
-                             <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['dbrepo'].repo_type)}</li>
+                          %if repo['dbrepo']['private']:
+                             <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['dbrepo']['repo_type'])}</li>
                           %else:
-                             <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['dbrepo'].repo_type)}</li>
+                             <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['dbrepo']['repo_type'])}</li>
                           %endif  
                         %endfor					
 					</ul>			
@@ -185,10 +185,10 @@
                    </a>    
                     <ul>
                         <li>
-                            ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
+                            ${h.link_to('%s (%s)' % (_('branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
                             <ul>
-                            %if c.repository_branches.values():
-						        %for cnt,branch in enumerate(c.repository_branches.items()):
+                            %if c.rhodecode_repo.branches.values():
+						        %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
 						            <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
 						        %endfor
 						    %else:
@@ -197,10 +197,10 @@
                             </ul>                        
                         </li>
                         <li>
-                            ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
+                            ${h.link_to('%s (%s)' % (_('tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
                             <ul>
-                            %if c.repository_tags.values():
-                                %for cnt,tag in enumerate(c.repository_tags.items()):
+                            %if c.rhodecode_repo.tags.values():
+                                %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
                                  <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
                                 %endfor
                             %else:
--- a/rhodecode/templates/index.html	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/templates/index.html	Tue Feb 15 01:36:07 2011 +0100
@@ -60,16 +60,16 @@
 		            <td>
 		            <div style="white-space: nowrap">
 		             ## TYPE OF REPO
-		             %if repo['dbrepo'].repo_type =='hg':
+		             %if repo['dbrepo']['repo_type'] =='hg':
 		               <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
-		             %elif repo['dbrepo'].repo_type =='git':
+		             %elif repo['dbrepo']['repo_type'] =='git':
 		               <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
 		             %else:
 		               
 		             %endif 
 		            
 		             ##PRIVATE/PUBLIC
-		             %if repo['dbrepo'].private:
+		             %if repo['dbrepo']['private']:
 		                <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
 		             %else:
 		                <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
@@ -78,10 +78,10 @@
 		            ##NAME   
 		            ${h.link_to(repo['name'],
 		                h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
-		            %if repo['dbrepo'].fork:
-		            	<a href="${h.url('summary_home',repo_name=repo['dbrepo'].fork.repo_name)}">
+		            %if repo['dbrepo_fork']:
+		            	<a href="${h.url('summary_home',repo_name=repo['dbrepo_fork']['repo_name'])}">
 		            	<img class="icon" alt="${_('fork')}"
-		            	title="${_('Fork of')} ${repo['dbrepo'].fork.repo_name}" 
+		            	title="${_('Fork of')} ${repo['dbrepo_fork']['repo_name']}" 
 		            	src="/images/icons/arrow_divide.png"/></a>
 		            %endif
 		            </div>
--- a/rhodecode/templates/journal/journal_data.html	Mon Feb 14 16:43:57 2011 +0100
+++ b/rhodecode/templates/journal/journal_data.html	Tue Feb 15 01:36:07 2011 +0100
@@ -14,14 +14,15 @@
             <div class="journal_action">${h.action_parser(entry)}</div>
             <div class="journal_repo">
                 <span class="journal_repo_name">
-                %if entry.repository:
+                %if entry.repository is not None:
                   ${h.link_to(entry.repository.repo_name,
                               h.url('summary_home',repo_name=entry.repository.repo_name))}
                 %else:
                   ${entry.repository_name}
                 %endif             
-                </span> - <span title="${entry.action_date}">${h.age(entry.action_date)}</span>
+                </span>
             </div>
+            <div class="date"><span class="tooltip" title="${entry.action_date}">${h.age(entry.action_date)}</span></div>
             %endfor
         </div>
         <div style="clear:both;border-bottom:1px dashed #DDD;padding:3px 3px;margin:0px 10px 0px 10px"></div>