##// END OF EJS Templates
Fixes for raw_id, needed for git...
marcink -
r636:ffd07396 beta
parent child Browse files
Show More
@@ -1,190 +1,190 b''
1 """
1 """
2 Routes configuration
2 Routes configuration
3
3
4 The more specific and detailed routes should be defined first so they
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
6 refer to the routes manual at http://routes.groovie.org/docs/
7 """
7 """
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from routes import Mapper
9 from routes import Mapper
10 from rhodecode.lib.utils import check_repo_fast as cr
10 from rhodecode.lib.utils import check_repo_fast as cr
11
11
12 def make_map(config):
12 def make_map(config):
13 """Create, configure and return the routes Mapper"""
13 """Create, configure and return the routes Mapper"""
14 map = Mapper(directory=config['pylons.paths']['controllers'],
14 map = Mapper(directory=config['pylons.paths']['controllers'],
15 always_scan=config['debug'])
15 always_scan=config['debug'])
16 map.minimization = False
16 map.minimization = False
17 map.explicit = False
17 map.explicit = False
18
18
19 def check_repo(environ, match_dict):
19 def check_repo(environ, match_dict):
20 """
20 """
21 check for valid repository for proper 404 handling
21 check for valid repository for proper 404 handling
22 :param environ:
22 :param environ:
23 :param match_dict:
23 :param match_dict:
24 """
24 """
25 repo_name = match_dict.get('repo_name')
25 repo_name = match_dict.get('repo_name')
26 return not cr(repo_name, config['base_path'])
26 return not cr(repo_name, config['base_path'])
27
27
28 # The ErrorController route (handles 404/500 error pages); it should
28 # The ErrorController route (handles 404/500 error pages); it should
29 # likely stay at the top, ensuring it can always be resolved
29 # likely stay at the top, ensuring it can always be resolved
30 map.connect('/error/{action}', controller='error')
30 map.connect('/error/{action}', controller='error')
31 map.connect('/error/{action}/{id}', controller='error')
31 map.connect('/error/{action}/{id}', controller='error')
32
32
33 #==========================================================================
33 #==========================================================================
34 # CUSTOM ROUTES HERE
34 # CUSTOM ROUTES HERE
35 #==========================================================================
35 #==========================================================================
36
36
37 #MAIN PAGE
37 #MAIN PAGE
38 map.connect('hg_home', '/', controller='hg', action='index')
38 map.connect('home', '/', controller='home', action='index')
39 map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
39 map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
40 map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
40 map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
41 #ADMIN REPOSITORY REST ROUTES
41 #ADMIN REPOSITORY REST ROUTES
42 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
42 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
43 m.connect("repos", "/repos",
43 m.connect("repos", "/repos",
44 action="create", conditions=dict(method=["POST"]))
44 action="create", conditions=dict(method=["POST"]))
45 m.connect("repos", "/repos",
45 m.connect("repos", "/repos",
46 action="index", conditions=dict(method=["GET"]))
46 action="index", conditions=dict(method=["GET"]))
47 m.connect("formatted_repos", "/repos.{format}",
47 m.connect("formatted_repos", "/repos.{format}",
48 action="index",
48 action="index",
49 conditions=dict(method=["GET"]))
49 conditions=dict(method=["GET"]))
50 m.connect("new_repo", "/repos/new",
50 m.connect("new_repo", "/repos/new",
51 action="new", conditions=dict(method=["GET"]))
51 action="new", conditions=dict(method=["GET"]))
52 m.connect("formatted_new_repo", "/repos/new.{format}",
52 m.connect("formatted_new_repo", "/repos/new.{format}",
53 action="new", conditions=dict(method=["GET"]))
53 action="new", conditions=dict(method=["GET"]))
54 m.connect("/repos/{repo_name:.*}",
54 m.connect("/repos/{repo_name:.*}",
55 action="update", conditions=dict(method=["PUT"],
55 action="update", conditions=dict(method=["PUT"],
56 function=check_repo))
56 function=check_repo))
57 m.connect("/repos/{repo_name:.*}",
57 m.connect("/repos/{repo_name:.*}",
58 action="delete", conditions=dict(method=["DELETE"],
58 action="delete", conditions=dict(method=["DELETE"],
59 function=check_repo))
59 function=check_repo))
60 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
60 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
61 action="edit", conditions=dict(method=["GET"],
61 action="edit", conditions=dict(method=["GET"],
62 function=check_repo))
62 function=check_repo))
63 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
63 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
64 action="edit", conditions=dict(method=["GET"],
64 action="edit", conditions=dict(method=["GET"],
65 function=check_repo))
65 function=check_repo))
66 m.connect("repo", "/repos/{repo_name:.*}",
66 m.connect("repo", "/repos/{repo_name:.*}",
67 action="show", conditions=dict(method=["GET"],
67 action="show", conditions=dict(method=["GET"],
68 function=check_repo))
68 function=check_repo))
69 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
69 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
70 action="show", conditions=dict(method=["GET"],
70 action="show", conditions=dict(method=["GET"],
71 function=check_repo))
71 function=check_repo))
72 #ajax delete repo perm user
72 #ajax delete repo perm user
73 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
73 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
74 action="delete_perm_user", conditions=dict(method=["DELETE"],
74 action="delete_perm_user", conditions=dict(method=["DELETE"],
75 function=check_repo))
75 function=check_repo))
76
76
77 #ADMIN USER REST ROUTES
77 #ADMIN USER REST ROUTES
78 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
78 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
79
79
80 #ADMIN PERMISSIONS REST ROUTES
80 #ADMIN PERMISSIONS REST ROUTES
81 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
81 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
82
82
83 #ADMIN SETTINGS REST ROUTES
83 #ADMIN SETTINGS REST ROUTES
84 with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
84 with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
85 m.connect("admin_settings", "/settings",
85 m.connect("admin_settings", "/settings",
86 action="create", conditions=dict(method=["POST"]))
86 action="create", conditions=dict(method=["POST"]))
87 m.connect("admin_settings", "/settings",
87 m.connect("admin_settings", "/settings",
88 action="index", conditions=dict(method=["GET"]))
88 action="index", conditions=dict(method=["GET"]))
89 m.connect("formatted_admin_settings", "/settings.{format}",
89 m.connect("formatted_admin_settings", "/settings.{format}",
90 action="index", conditions=dict(method=["GET"]))
90 action="index", conditions=dict(method=["GET"]))
91 m.connect("admin_new_setting", "/settings/new",
91 m.connect("admin_new_setting", "/settings/new",
92 action="new", conditions=dict(method=["GET"]))
92 action="new", conditions=dict(method=["GET"]))
93 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
93 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
94 action="new", conditions=dict(method=["GET"]))
94 action="new", conditions=dict(method=["GET"]))
95 m.connect("/settings/{setting_id}",
95 m.connect("/settings/{setting_id}",
96 action="update", conditions=dict(method=["PUT"]))
96 action="update", conditions=dict(method=["PUT"]))
97 m.connect("/settings/{setting_id}",
97 m.connect("/settings/{setting_id}",
98 action="delete", conditions=dict(method=["DELETE"]))
98 action="delete", conditions=dict(method=["DELETE"]))
99 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
99 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
100 action="edit", conditions=dict(method=["GET"]))
100 action="edit", conditions=dict(method=["GET"]))
101 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
101 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
102 action="edit", conditions=dict(method=["GET"]))
102 action="edit", conditions=dict(method=["GET"]))
103 m.connect("admin_setting", "/settings/{setting_id}",
103 m.connect("admin_setting", "/settings/{setting_id}",
104 action="show", conditions=dict(method=["GET"]))
104 action="show", conditions=dict(method=["GET"]))
105 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
105 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
106 action="show", conditions=dict(method=["GET"]))
106 action="show", conditions=dict(method=["GET"]))
107 m.connect("admin_settings_my_account", "/my_account",
107 m.connect("admin_settings_my_account", "/my_account",
108 action="my_account", conditions=dict(method=["GET"]))
108 action="my_account", conditions=dict(method=["GET"]))
109 m.connect("admin_settings_my_account_update", "/my_account_update",
109 m.connect("admin_settings_my_account_update", "/my_account_update",
110 action="my_account_update", conditions=dict(method=["PUT"]))
110 action="my_account_update", conditions=dict(method=["PUT"]))
111 m.connect("admin_settings_create_repository", "/create_repository",
111 m.connect("admin_settings_create_repository", "/create_repository",
112 action="create_repository", conditions=dict(method=["GET"]))
112 action="create_repository", conditions=dict(method=["GET"]))
113
113
114 #ADMIN MAIN PAGES
114 #ADMIN MAIN PAGES
115 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
115 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
116 m.connect('admin_home', '', action='index')#main page
116 m.connect('admin_home', '', action='index')#main page
117 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
117 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
118 action='add_repo')
118 action='add_repo')
119 #SEARCH
119 #SEARCH
120 map.connect('search', '/_admin/search', controller='search',)
120 map.connect('search', '/_admin/search', controller='search',)
121 map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
121 map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
122
122
123 #LOGIN/LOGOUT/REGISTER/SIGN IN
123 #LOGIN/LOGOUT/REGISTER/SIGN IN
124 map.connect('login_home', '/_admin/login', controller='login')
124 map.connect('login_home', '/_admin/login', controller='login')
125 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
125 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
126 map.connect('register', '/_admin/register', controller='login', action='register')
126 map.connect('register', '/_admin/register', controller='login', action='register')
127 map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
127 map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
128
128
129 #FEEDS
129 #FEEDS
130 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
130 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
131 controller='feed', action='rss',
131 controller='feed', action='rss',
132 conditions=dict(function=check_repo))
132 conditions=dict(function=check_repo))
133 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
133 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
134 controller='feed', action='atom',
134 controller='feed', action='atom',
135 conditions=dict(function=check_repo))
135 conditions=dict(function=check_repo))
136
136
137
137
138 #REPOSITORY ROUTES
138 #REPOSITORY ROUTES
139 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
139 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
140 controller='changeset', revision='tip',
140 controller='changeset', revision='tip',
141 conditions=dict(function=check_repo))
141 conditions=dict(function=check_repo))
142 map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
142 map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
143 controller='changeset', action='raw_changeset', revision='tip',
143 controller='changeset', action='raw_changeset', revision='tip',
144 conditions=dict(function=check_repo))
144 conditions=dict(function=check_repo))
145 map.connect('summary_home', '/{repo_name:.*}/summary',
145 map.connect('summary_home', '/{repo_name:.*}/summary',
146 controller='summary', conditions=dict(function=check_repo))
146 controller='summary', conditions=dict(function=check_repo))
147 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
147 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
148 controller='shortlog', conditions=dict(function=check_repo))
148 controller='shortlog', conditions=dict(function=check_repo))
149 map.connect('branches_home', '/{repo_name:.*}/branches',
149 map.connect('branches_home', '/{repo_name:.*}/branches',
150 controller='branches', conditions=dict(function=check_repo))
150 controller='branches', conditions=dict(function=check_repo))
151 map.connect('tags_home', '/{repo_name:.*}/tags',
151 map.connect('tags_home', '/{repo_name:.*}/tags',
152 controller='tags', conditions=dict(function=check_repo))
152 controller='tags', conditions=dict(function=check_repo))
153 map.connect('changelog_home', '/{repo_name:.*}/changelog',
153 map.connect('changelog_home', '/{repo_name:.*}/changelog',
154 controller='changelog', conditions=dict(function=check_repo))
154 controller='changelog', conditions=dict(function=check_repo))
155 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
155 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
156 controller='files', revision='tip', f_path='',
156 controller='files', revision='tip', f_path='',
157 conditions=dict(function=check_repo))
157 conditions=dict(function=check_repo))
158 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
158 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
159 controller='files', action='diff', revision='tip', f_path='',
159 controller='files', action='diff', revision='tip', f_path='',
160 conditions=dict(function=check_repo))
160 conditions=dict(function=check_repo))
161 map.connect('files_rawfile_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
161 map.connect('files_rawfile_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
162 controller='files', action='rawfile', revision='tip', f_path='',
162 controller='files', action='rawfile', revision='tip', f_path='',
163 conditions=dict(function=check_repo))
163 conditions=dict(function=check_repo))
164 map.connect('files_raw_home', '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
164 map.connect('files_raw_home', '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
165 controller='files', action='raw', revision='tip', f_path='',
165 controller='files', action='raw', revision='tip', f_path='',
166 conditions=dict(function=check_repo))
166 conditions=dict(function=check_repo))
167 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
167 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
168 controller='files', action='annotate', revision='tip', f_path='',
168 controller='files', action='annotate', revision='tip', f_path='',
169 conditions=dict(function=check_repo))
169 conditions=dict(function=check_repo))
170 map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
170 map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
171 controller='files', action='archivefile', revision='tip',
171 controller='files', action='archivefile', revision='tip',
172 conditions=dict(function=check_repo))
172 conditions=dict(function=check_repo))
173 map.connect('repo_settings_delete', '/{repo_name:.*}/settings',
173 map.connect('repo_settings_delete', '/{repo_name:.*}/settings',
174 controller='settings', action="delete",
174 controller='settings', action="delete",
175 conditions=dict(method=["DELETE"], function=check_repo))
175 conditions=dict(method=["DELETE"], function=check_repo))
176 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
176 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
177 controller='settings', action="update",
177 controller='settings', action="update",
178 conditions=dict(method=["PUT"], function=check_repo))
178 conditions=dict(method=["PUT"], function=check_repo))
179 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
179 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
180 controller='settings', action='index',
180 controller='settings', action='index',
181 conditions=dict(function=check_repo))
181 conditions=dict(function=check_repo))
182
182
183 map.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
183 map.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
184 controller='settings', action='fork_create',
184 controller='settings', action='fork_create',
185 conditions=dict(function=check_repo, method=["POST"]))
185 conditions=dict(function=check_repo, method=["POST"]))
186 map.connect('repo_fork_home', '/{repo_name:.*}/fork',
186 map.connect('repo_fork_home', '/{repo_name:.*}/fork',
187 controller='settings', action='fork',
187 controller='settings', action='fork',
188 conditions=dict(function=check_repo))
188 conditions=dict(function=check_repo))
189
189
190 return map
190 return map
@@ -1,245 +1,245 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # repos controller for pylons
3 # repos controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 7, 2010
21 Created on April 7, 2010
22 admin controller for pylons
22 admin controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from formencode import htmlfill
25 from formencode import htmlfill
26 from operator import itemgetter
26 from operator import itemgetter
27 from paste.httpexceptions import HTTPInternalServerError
27 from paste.httpexceptions import HTTPInternalServerError
28 from pylons import request, response, session, tmpl_context as c, url
28 from pylons import request, response, session, tmpl_context as c, url
29 from pylons.controllers.util import abort, redirect
29 from pylons.controllers.util import abort, redirect
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31 from rhodecode.lib import helpers as h
31 from rhodecode.lib import helpers as h
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
33 HasPermissionAnyDecorator
33 HasPermissionAnyDecorator
34 from rhodecode.lib.base import BaseController, render
34 from rhodecode.lib.base import BaseController, render
35 from rhodecode.lib.utils import invalidate_cache, action_logger
35 from rhodecode.lib.utils import invalidate_cache, action_logger
36 from rhodecode.model.db import User
36 from rhodecode.model.db import User
37 from rhodecode.model.forms import RepoForm
37 from rhodecode.model.forms import RepoForm
38 from rhodecode.model.hg import HgModel
38 from rhodecode.model.hg import HgModel
39 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.repo import RepoModel
40 import formencode
40 import formencode
41 import logging
41 import logging
42 import traceback
42 import traceback
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46 class ReposController(BaseController):
46 class ReposController(BaseController):
47 """REST Controller styled on the Atom Publishing Protocol"""
47 """REST Controller styled on the Atom Publishing Protocol"""
48 # To properly map this controller, ensure your config/routing.py
48 # To properly map this controller, ensure your config/routing.py
49 # file has a resource setup:
49 # file has a resource setup:
50 # map.resource('repo', 'repos')
50 # map.resource('repo', 'repos')
51
51
52 @LoginRequired()
52 @LoginRequired()
53 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
53 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
54 def __before__(self):
54 def __before__(self):
55 c.admin_user = session.get('admin_user')
55 c.admin_user = session.get('admin_user')
56 c.admin_username = session.get('admin_username')
56 c.admin_username = session.get('admin_username')
57 super(ReposController, self).__before__()
57 super(ReposController, self).__before__()
58
58
59 @HasPermissionAllDecorator('hg.admin')
59 @HasPermissionAllDecorator('hg.admin')
60 def index(self, format='html'):
60 def index(self, format='html'):
61 """GET /repos: All items in the collection"""
61 """GET /repos: All items in the collection"""
62 # url('repos')
62 # url('repos')
63 cached_repo_list = HgModel().get_repos()
63 cached_repo_list = HgModel().get_repos()
64 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
64 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
65 return render('admin/repos/repos.html')
65 return render('admin/repos/repos.html')
66
66
67 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
67 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
68 def create(self):
68 def create(self):
69 """POST /repos: Create a new item"""
69 """POST /repos: Create a new item"""
70 # url('repos')
70 # url('repos')
71 repo_model = RepoModel()
71 repo_model = RepoModel()
72 _form = RepoForm()()
72 _form = RepoForm()()
73 form_result = {}
73 form_result = {}
74 try:
74 try:
75 form_result = _form.to_python(dict(request.POST))
75 form_result = _form.to_python(dict(request.POST))
76 repo_model.create(form_result, c.rhodecode_user)
76 repo_model.create(form_result, c.rhodecode_user)
77 invalidate_cache('cached_repo_list')
77 invalidate_cache('cached_repo_list')
78 h.flash(_('created repository %s') % form_result['repo_name'],
78 h.flash(_('created repository %s') % form_result['repo_name'],
79 category='success')
79 category='success')
80
80
81 if request.POST.get('user_created'):
81 if request.POST.get('user_created'):
82 action_logger(self.rhodecode_user, 'user_created_repo',
82 action_logger(self.rhodecode_user, 'user_created_repo',
83 form_result['repo_name'], '', self.sa)
83 form_result['repo_name'], '', self.sa)
84 else:
84 else:
85 action_logger(self.rhodecode_user, 'admin_created_repo',
85 action_logger(self.rhodecode_user, 'admin_created_repo',
86 form_result['repo_name'], '', self.sa)
86 form_result['repo_name'], '', self.sa)
87
87
88 except formencode.Invalid, errors:
88 except formencode.Invalid, errors:
89 c.new_repo = errors.value['repo_name']
89 c.new_repo = errors.value['repo_name']
90
90
91 if request.POST.get('user_created'):
91 if request.POST.get('user_created'):
92 r = render('admin/repos/repo_add_create_repository.html')
92 r = render('admin/repos/repo_add_create_repository.html')
93 else:
93 else:
94 r = render('admin/repos/repo_add.html')
94 r = render('admin/repos/repo_add.html')
95
95
96 return htmlfill.render(
96 return htmlfill.render(
97 r,
97 r,
98 defaults=errors.value,
98 defaults=errors.value,
99 errors=errors.error_dict or {},
99 errors=errors.error_dict or {},
100 prefix_error=False,
100 prefix_error=False,
101 encoding="UTF-8")
101 encoding="UTF-8")
102
102
103 except Exception:
103 except Exception:
104 log.error(traceback.format_exc())
104 log.error(traceback.format_exc())
105 msg = _('error occured during creation of repository %s') \
105 msg = _('error occured during creation of repository %s') \
106 % form_result.get('repo_name')
106 % form_result.get('repo_name')
107 h.flash(msg, category='error')
107 h.flash(msg, category='error')
108 if request.POST.get('user_created'):
108 if request.POST.get('user_created'):
109 return redirect(url('hg_home'))
109 return redirect(url('home'))
110 return redirect(url('repos'))
110 return redirect(url('repos'))
111
111
112 @HasPermissionAllDecorator('hg.admin')
112 @HasPermissionAllDecorator('hg.admin')
113 def new(self, format='html'):
113 def new(self, format='html'):
114 """GET /repos/new: Form to create a new item"""
114 """GET /repos/new: Form to create a new item"""
115 new_repo = request.GET.get('repo', '')
115 new_repo = request.GET.get('repo', '')
116 c.new_repo = h.repo_name_slug(new_repo)
116 c.new_repo = h.repo_name_slug(new_repo)
117
117
118 return render('admin/repos/repo_add.html')
118 return render('admin/repos/repo_add.html')
119
119
120 @HasPermissionAllDecorator('hg.admin')
120 @HasPermissionAllDecorator('hg.admin')
121 def update(self, repo_name):
121 def update(self, repo_name):
122 """PUT /repos/repo_name: Update an existing item"""
122 """PUT /repos/repo_name: Update an existing item"""
123 # Forms posted to this method should contain a hidden field:
123 # Forms posted to this method should contain a hidden field:
124 # <input type="hidden" name="_method" value="PUT" />
124 # <input type="hidden" name="_method" value="PUT" />
125 # Or using helpers:
125 # Or using helpers:
126 # h.form(url('repo', repo_name=ID),
126 # h.form(url('repo', repo_name=ID),
127 # method='put')
127 # method='put')
128 # url('repo', repo_name=ID)
128 # url('repo', repo_name=ID)
129 repo_model = RepoModel()
129 repo_model = RepoModel()
130 changed_name = repo_name
130 changed_name = repo_name
131 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
131 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
132
132
133 try:
133 try:
134 form_result = _form.to_python(dict(request.POST))
134 form_result = _form.to_python(dict(request.POST))
135 repo_model.update(repo_name, form_result)
135 repo_model.update(repo_name, form_result)
136 invalidate_cache('cached_repo_list')
136 invalidate_cache('cached_repo_list')
137 h.flash(_('Repository %s updated succesfully' % repo_name),
137 h.flash(_('Repository %s updated succesfully' % repo_name),
138 category='success')
138 category='success')
139 changed_name = form_result['repo_name']
139 changed_name = form_result['repo_name']
140 except formencode.Invalid, errors:
140 except formencode.Invalid, errors:
141 c.repo_info = repo_model.get(repo_name)
141 c.repo_info = repo_model.get(repo_name)
142 c.users_array = repo_model.get_users_js()
142 c.users_array = repo_model.get_users_js()
143 errors.value.update({'user':c.repo_info.user.username})
143 errors.value.update({'user':c.repo_info.user.username})
144 return htmlfill.render(
144 return htmlfill.render(
145 render('admin/repos/repo_edit.html'),
145 render('admin/repos/repo_edit.html'),
146 defaults=errors.value,
146 defaults=errors.value,
147 errors=errors.error_dict or {},
147 errors=errors.error_dict or {},
148 prefix_error=False,
148 prefix_error=False,
149 encoding="UTF-8")
149 encoding="UTF-8")
150
150
151 except Exception:
151 except Exception:
152 log.error(traceback.format_exc())
152 log.error(traceback.format_exc())
153 h.flash(_('error occured during update of repository %s') \
153 h.flash(_('error occured during update of repository %s') \
154 % repo_name, category='error')
154 % repo_name, category='error')
155
155
156 return redirect(url('edit_repo', repo_name=changed_name))
156 return redirect(url('edit_repo', repo_name=changed_name))
157
157
158 @HasPermissionAllDecorator('hg.admin')
158 @HasPermissionAllDecorator('hg.admin')
159 def delete(self, repo_name):
159 def delete(self, repo_name):
160 """DELETE /repos/repo_name: Delete an existing item"""
160 """DELETE /repos/repo_name: Delete an existing item"""
161 # Forms posted to this method should contain a hidden field:
161 # Forms posted to this method should contain a hidden field:
162 # <input type="hidden" name="_method" value="DELETE" />
162 # <input type="hidden" name="_method" value="DELETE" />
163 # Or using helpers:
163 # Or using helpers:
164 # h.form(url('repo', repo_name=ID),
164 # h.form(url('repo', repo_name=ID),
165 # method='delete')
165 # method='delete')
166 # url('repo', repo_name=ID)
166 # url('repo', repo_name=ID)
167
167
168 repo_model = RepoModel()
168 repo_model = RepoModel()
169 repo = repo_model.get(repo_name)
169 repo = repo_model.get(repo_name)
170 if not repo:
170 if not repo:
171 h.flash(_('%s repository is not mapped to db perhaps'
171 h.flash(_('%s repository is not mapped to db perhaps'
172 ' it was moved or renamed from the filesystem'
172 ' it was moved or renamed from the filesystem'
173 ' please run the application again'
173 ' please run the application again'
174 ' in order to rescan repositories') % repo_name,
174 ' in order to rescan repositories') % repo_name,
175 category='error')
175 category='error')
176
176
177 return redirect(url('repos'))
177 return redirect(url('repos'))
178 try:
178 try:
179 action_logger(self.rhodecode_user, 'admin_deleted_repo',
179 action_logger(self.rhodecode_user, 'admin_deleted_repo',
180 repo_name, '', self.sa)
180 repo_name, '', self.sa)
181 repo_model.delete(repo)
181 repo_model.delete(repo)
182 invalidate_cache('cached_repo_list')
182 invalidate_cache('cached_repo_list')
183 h.flash(_('deleted repository %s') % repo_name, category='success')
183 h.flash(_('deleted repository %s') % repo_name, category='success')
184
184
185 except Exception, e:
185 except Exception, e:
186 log.error(traceback.format_exc())
186 log.error(traceback.format_exc())
187 h.flash(_('An error occured during deletion of %s') % repo_name,
187 h.flash(_('An error occured during deletion of %s') % repo_name,
188 category='error')
188 category='error')
189
189
190 return redirect(url('repos'))
190 return redirect(url('repos'))
191
191
192 @HasPermissionAllDecorator('hg.admin')
192 @HasPermissionAllDecorator('hg.admin')
193 def delete_perm_user(self, repo_name):
193 def delete_perm_user(self, repo_name):
194 """
194 """
195 DELETE an existing repository permission user
195 DELETE an existing repository permission user
196 :param repo_name:
196 :param repo_name:
197 """
197 """
198
198
199 try:
199 try:
200 repo_model = RepoModel()
200 repo_model = RepoModel()
201 repo_model.delete_perm_user(request.POST, repo_name)
201 repo_model.delete_perm_user(request.POST, repo_name)
202 except Exception, e:
202 except Exception, e:
203 h.flash(_('An error occured during deletion of repository user'),
203 h.flash(_('An error occured during deletion of repository user'),
204 category='error')
204 category='error')
205 raise HTTPInternalServerError()
205 raise HTTPInternalServerError()
206
206
207 @HasPermissionAllDecorator('hg.admin')
207 @HasPermissionAllDecorator('hg.admin')
208 def show(self, repo_name, format='html'):
208 def show(self, repo_name, format='html'):
209 """GET /repos/repo_name: Show a specific item"""
209 """GET /repos/repo_name: Show a specific item"""
210 # url('repo', repo_name=ID)
210 # url('repo', repo_name=ID)
211
211
212 @HasPermissionAllDecorator('hg.admin')
212 @HasPermissionAllDecorator('hg.admin')
213 def edit(self, repo_name, format='html'):
213 def edit(self, repo_name, format='html'):
214 """GET /repos/repo_name/edit: Form to edit an existing item"""
214 """GET /repos/repo_name/edit: Form to edit an existing item"""
215 # url('edit_repo', repo_name=ID)
215 # url('edit_repo', repo_name=ID)
216 repo_model = RepoModel()
216 repo_model = RepoModel()
217 c.repo_info = repo = repo_model.get(repo_name)
217 c.repo_info = repo = repo_model.get(repo_name)
218 if not repo:
218 if not repo:
219 h.flash(_('%s repository is not mapped to db perhaps'
219 h.flash(_('%s repository is not mapped to db perhaps'
220 ' it was created or renamed from the filesystem'
220 ' it was created or renamed from the filesystem'
221 ' please run the application again'
221 ' please run the application again'
222 ' in order to rescan repositories') % repo_name,
222 ' in order to rescan repositories') % repo_name,
223 category='error')
223 category='error')
224
224
225 return redirect(url('repos'))
225 return redirect(url('repos'))
226 defaults = c.repo_info.__dict__
226 defaults = c.repo_info.__dict__
227 if c.repo_info.user:
227 if c.repo_info.user:
228 defaults.update({'user':c.repo_info.user.username})
228 defaults.update({'user':c.repo_info.user.username})
229 else:
229 else:
230 replacement_user = self.sa.query(User)\
230 replacement_user = self.sa.query(User)\
231 .filter(User.admin == True).first().username
231 .filter(User.admin == True).first().username
232 defaults.update({'user':replacement_user})
232 defaults.update({'user':replacement_user})
233
233
234 c.users_array = repo_model.get_users_js()
234 c.users_array = repo_model.get_users_js()
235
235
236 for p in c.repo_info.repo_to_perm:
236 for p in c.repo_info.repo_to_perm:
237 defaults.update({'perm_%s' % p.user.username:
237 defaults.update({'perm_%s' % p.user.username:
238 p.permission.permission_name})
238 p.permission.permission_name})
239
239
240 return htmlfill.render(
240 return htmlfill.render(
241 render('admin/repos/repo_edit.html'),
241 render('admin/repos/repo_edit.html'),
242 defaults=defaults,
242 defaults=defaults,
243 encoding="UTF-8",
243 encoding="UTF-8",
244 force_defaults=False
244 force_defaults=False
245 )
245 )
@@ -1,95 +1,97 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # changelog controller for pylons
3 # changelog controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 21, 2010
21 Created on April 21, 2010
22 changelog controller for pylons
22 changelog controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25
25
26 try:
26 try:
27 import json
27 import json
28 except ImportError:
28 except ImportError:
29 #python 2.5 compatibility
29 #python 2.5 compatibility
30 import simplejson as json
30 import simplejson as json
31 from mercurial.graphmod import colored, CHANGESET, revisions as graph_rev
31 from mercurial.graphmod import colored, CHANGESET, revisions as graph_rev
32 from pylons import request, session, tmpl_context as c
32 from pylons import request, session, tmpl_context as c
33 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
33 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.base import BaseController, render
34 from rhodecode.lib.base import BaseController, render
35 from rhodecode.model.hg import HgModel
35 from rhodecode.model.hg import HgModel
36 from webhelpers.paginate import Page
36 from webhelpers.paginate import Page
37 import logging
37 import logging
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40 class ChangelogController(BaseController):
40 class ChangelogController(BaseController):
41
41
42 @LoginRequired()
42 @LoginRequired()
43 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
43 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
44 'repository.admin')
44 'repository.admin')
45 def __before__(self):
45 def __before__(self):
46 super(ChangelogController, self).__before__()
46 super(ChangelogController, self).__before__()
47
47
48 def index(self):
48 def index(self):
49 limit = 100
49 limit = 100
50 default = 20
50 default = 20
51 if request.params.get('size'):
51 if request.params.get('size'):
52 try:
52 try:
53 int_size = int(request.params.get('size'))
53 int_size = int(request.params.get('size'))
54 except ValueError:
54 except ValueError:
55 int_size = default
55 int_size = default
56 int_size = int_size if int_size <= limit else limit
56 int_size = int_size if int_size <= limit else limit
57 c.size = int_size
57 c.size = int_size
58 session['changelog_size'] = c.size
58 session['changelog_size'] = c.size
59 session.save()
59 session.save()
60 else:
60 else:
61 c.size = int(session.get('changelog_size', default))
61 c.size = int(session.get('changelog_size', default))
62
62
63 changesets = HgModel().get_repo(c.repo_name)
63 changesets = HgModel().get_repo(c.repo_name)
64
64
65 p = int(request.params.get('page', 1))
65 p = int(request.params.get('page', 1))
66 c.total_cs = len(changesets)
66 c.total_cs = len(changesets)
67 c.pagination = Page(changesets, page=p, item_count=c.total_cs,
67 c.pagination = Page(changesets, page=p, item_count=c.total_cs,
68 items_per_page=c.size)
68 items_per_page=c.size)
69
69
70 self._graph(changesets, c.size, p)
70 self._graph(changesets, c.size, p)
71
71
72 return render('changelog/changelog.html')
72 return render('changelog/changelog.html')
73
73
74
74
75 def _graph(self, repo, size, p):
75 def _graph(self, repo, size, p):
76 revcount = size
76 revcount = size
77 if not repo.revisions:return json.dumps([]), 0
77 if not repo.revisions:return json.dumps([]), 0
78
78
79 max_rev = repo.revisions[-1]
79 max_rev = repo.revisions[-1]
80
80 offset = 1 if p == 1 else ((p - 1) * revcount + 1)
81 offset = 1 if p == 1 else ((p - 1) * revcount + 1)
82
81 rev_start = repo.revisions[(-1 * offset)]
83 rev_start = repo.revisions[(-1 * offset)]
82
84
83 revcount = min(max_rev, revcount)
85 revcount = min(max_rev, revcount)
84 rev_end = max(0, rev_start - revcount)
86 rev_end = max(0, rev_start - revcount)
85 dag = graph_rev(repo.repo, rev_start, rev_end)
87 dag = graph_rev(repo.repo, rev_start, rev_end)
86
88
87 c.dag = tree = list(colored(dag))
89 c.dag = tree = list(colored(dag))
88 data = []
90 data = []
89 for (id, type, ctx, vtx, edges) in tree:
91 for (id, type, ctx, vtx, edges) in tree:
90 if type != CHANGESET:
92 if type != CHANGESET:
91 continue
93 continue
92 data.append(('', vtx, edges))
94 data.append(('', vtx, edges))
93
94 c.jsdata = json.dumps(data)
95
95
96 c.jsdata = json.dumps(data)
97
@@ -1,181 +1,181 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # changeset controller for pylons
3 # changeset controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19 from rhodecode.lib.utils import EmptyChangeset
19 from rhodecode.lib.utils import EmptyChangeset
20 """
20 """
21 Created on April 25, 2010
21 Created on April 25, 2010
22 changeset controller for pylons
22 changeset controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from pylons import tmpl_context as c, url, request, response
25 from pylons import tmpl_context as c, url, request, response
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from pylons.controllers.util import redirect
27 from pylons.controllers.util import redirect
28 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
28 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
29 from rhodecode.lib.base import BaseController, render
29 from rhodecode.lib.base import BaseController, render
30 from rhodecode.model.hg import HgModel
30 from rhodecode.model.hg import HgModel
31 from vcs.exceptions import RepositoryError, ChangesetError
31 from vcs.exceptions import RepositoryError, ChangesetError
32 from vcs.nodes import FileNode
32 from vcs.nodes import FileNode
33 from vcs.utils import diffs as differ
33 from vcs.utils import diffs as differ
34 import logging
34 import logging
35 import traceback
35 import traceback
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39 class ChangesetController(BaseController):
39 class ChangesetController(BaseController):
40
40
41 @LoginRequired()
41 @LoginRequired()
42 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
42 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
43 'repository.admin')
43 'repository.admin')
44 def __before__(self):
44 def __before__(self):
45 super(ChangesetController, self).__before__()
45 super(ChangesetController, self).__before__()
46
46
47 def index(self, revision):
47 def index(self, revision):
48 hg_model = HgModel()
48 hg_model = HgModel()
49 cut_off_limit = 1024 * 250
49 cut_off_limit = 1024 * 250
50
50
51 def wrap_to_table(str):
51 def wrap_to_table(str):
52
52
53 return '''<table class="code-difftable">
53 return '''<table class="code-difftable">
54 <tr class="line">
54 <tr class="line">
55 <td class="lineno new"></td>
55 <td class="lineno new"></td>
56 <td class="code"><pre>%s</pre></td>
56 <td class="code"><pre>%s</pre></td>
57 </tr>
57 </tr>
58 </table>''' % str
58 </table>''' % str
59
59
60 try:
60 try:
61 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
61 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
62 except RepositoryError:
62 except RepositoryError:
63 log.error(traceback.format_exc())
63 log.error(traceback.format_exc())
64 return redirect(url('hg_home'))
64 return redirect(url('home'))
65 else:
65 else:
66 try:
66 try:
67 c.changeset_old = c.changeset.parents[0]
67 c.changeset_old = c.changeset.parents[0]
68 except IndexError:
68 except IndexError:
69 c.changeset_old = None
69 c.changeset_old = None
70 c.changes = []
70 c.changes = []
71
71
72 #===================================================================
72 #===================================================================
73 # ADDED FILES
73 # ADDED FILES
74 #===================================================================
74 #===================================================================
75 c.sum_added = 0
75 c.sum_added = 0
76 for node in c.changeset.added:
76 for node in c.changeset.added:
77
77
78 filenode_old = FileNode(node.path, '', EmptyChangeset())
78 filenode_old = FileNode(node.path, '', EmptyChangeset())
79 if filenode_old.is_binary or node.is_binary:
79 if filenode_old.is_binary or node.is_binary:
80 diff = wrap_to_table(_('binary file'))
80 diff = wrap_to_table(_('binary file'))
81 else:
81 else:
82 c.sum_added += node.size
82 c.sum_added += node.size
83 if c.sum_added < cut_off_limit:
83 if c.sum_added < cut_off_limit:
84 f_udiff = differ.get_udiff(filenode_old, node)
84 f_udiff = differ.get_udiff(filenode_old, node)
85 diff = differ.DiffProcessor(f_udiff).as_html()
85 diff = differ.DiffProcessor(f_udiff).as_html()
86
86
87 else:
87 else:
88 diff = wrap_to_table(_('Changeset is to big and was cut'
88 diff = wrap_to_table(_('Changeset is to big and was cut'
89 ' off, see raw changeset instead'))
89 ' off, see raw changeset instead'))
90
90
91 cs1 = None
91 cs1 = None
92 cs2 = node.last_changeset.short_id
92 cs2 = node.last_changeset.raw_id
93 c.changes.append(('added', node, diff, cs1, cs2))
93 c.changes.append(('added', node, diff, cs1, cs2))
94
94
95 #===================================================================
95 #===================================================================
96 # CHANGED FILES
96 # CHANGED FILES
97 #===================================================================
97 #===================================================================
98 c.sum_removed = 0
98 c.sum_removed = 0
99 for node in c.changeset.changed:
99 for node in c.changeset.changed:
100 try:
100 try:
101 filenode_old = c.changeset_old.get_node(node.path)
101 filenode_old = c.changeset_old.get_node(node.path)
102 except ChangesetError:
102 except ChangesetError:
103 filenode_old = FileNode(node.path, '', EmptyChangeset())
103 filenode_old = FileNode(node.path, '', EmptyChangeset())
104
104
105 if filenode_old.is_binary or node.is_binary:
105 if filenode_old.is_binary or node.is_binary:
106 diff = wrap_to_table(_('binary file'))
106 diff = wrap_to_table(_('binary file'))
107 else:
107 else:
108
108
109 if c.sum_removed < cut_off_limit:
109 if c.sum_removed < cut_off_limit:
110 f_udiff = differ.get_udiff(filenode_old, node)
110 f_udiff = differ.get_udiff(filenode_old, node)
111 diff = differ.DiffProcessor(f_udiff).as_html()
111 diff = differ.DiffProcessor(f_udiff).as_html()
112 if diff:
112 if diff:
113 c.sum_removed += len(diff)
113 c.sum_removed += len(diff)
114 else:
114 else:
115 diff = wrap_to_table(_('Changeset is to big and was cut'
115 diff = wrap_to_table(_('Changeset is to big and was cut'
116 ' off, see raw changeset instead'))
116 ' off, see raw changeset instead'))
117
117
118
118
119 cs1 = filenode_old.last_changeset.short_id
119 cs1 = filenode_old.last_changeset.raw_id
120 cs2 = node.last_changeset.short_id
120 cs2 = node.last_changeset.raw_id
121 c.changes.append(('changed', node, diff, cs1, cs2))
121 c.changes.append(('changed', node, diff, cs1, cs2))
122
122
123 #===================================================================
123 #===================================================================
124 # REMOVED FILES
124 # REMOVED FILES
125 #===================================================================
125 #===================================================================
126 for node in c.changeset.removed:
126 for node in c.changeset.removed:
127 c.changes.append(('removed', node, None, None, None))
127 c.changes.append(('removed', node, None, None, None))
128
128
129 return render('changeset/changeset.html')
129 return render('changeset/changeset.html')
130
130
131 def raw_changeset(self, revision):
131 def raw_changeset(self, revision):
132
132
133 hg_model = HgModel()
133 hg_model = HgModel()
134 method = request.GET.get('diff', 'show')
134 method = request.GET.get('diff', 'show')
135 try:
135 try:
136 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
136 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
137 except RepositoryError:
137 except RepositoryError:
138 log.error(traceback.format_exc())
138 log.error(traceback.format_exc())
139 return redirect(url('hg_home'))
139 return redirect(url('home'))
140 else:
140 else:
141 try:
141 try:
142 c.changeset_old = c.changeset.parents[0]
142 c.changeset_old = c.changeset.parents[0]
143 except IndexError:
143 except IndexError:
144 c.changeset_old = None
144 c.changeset_old = None
145 c.changes = []
145 c.changes = []
146
146
147 for node in c.changeset.added:
147 for node in c.changeset.added:
148 filenode_old = FileNode(node.path, '')
148 filenode_old = FileNode(node.path, '')
149 if filenode_old.is_binary or node.is_binary:
149 if filenode_old.is_binary or node.is_binary:
150 diff = _('binary file')
150 diff = _('binary file')
151 else:
151 else:
152 f_udiff = differ.get_udiff(filenode_old, node)
152 f_udiff = differ.get_udiff(filenode_old, node)
153 diff = differ.DiffProcessor(f_udiff).raw_diff()
153 diff = differ.DiffProcessor(f_udiff).raw_diff()
154
154
155 cs1 = None
155 cs1 = None
156 cs2 = node.last_changeset.short_id
156 cs2 = node.last_changeset.raw_id
157 c.changes.append(('added', node, diff, cs1, cs2))
157 c.changes.append(('added', node, diff, cs1, cs2))
158
158
159 for node in c.changeset.changed:
159 for node in c.changeset.changed:
160 filenode_old = c.changeset_old.get_node(node.path)
160 filenode_old = c.changeset_old.get_node(node.path)
161 if filenode_old.is_binary or node.is_binary:
161 if filenode_old.is_binary or node.is_binary:
162 diff = _('binary file')
162 diff = _('binary file')
163 else:
163 else:
164 f_udiff = differ.get_udiff(filenode_old, node)
164 f_udiff = differ.get_udiff(filenode_old, node)
165 diff = differ.DiffProcessor(f_udiff).raw_diff()
165 diff = differ.DiffProcessor(f_udiff).raw_diff()
166
166
167 cs1 = filenode_old.last_changeset.short_id
167 cs1 = filenode_old.last_changeset.raw_id
168 cs2 = node.last_changeset.short_id
168 cs2 = node.last_changeset.raw_id
169 c.changes.append(('changed', node, diff, cs1, cs2))
169 c.changes.append(('changed', node, diff, cs1, cs2))
170
170
171 response.content_type = 'text/plain'
171 response.content_type = 'text/plain'
172 if method == 'download':
172 if method == 'download':
173 response.content_disposition = 'attachment; filename=%s.patch' % revision
173 response.content_disposition = 'attachment; filename=%s.patch' % revision
174 parent = True if len(c.changeset.parents) > 0 else False
174 parent = True if len(c.changeset.parents) > 0 else False
175 c.parent_tmpl = 'Parent %s' % c.changeset.parents[0].raw_id if parent else ''
175 c.parent_tmpl = 'Parent %s' % c.changeset.parents[0].raw_id if parent else ''
176
176
177 c.diffs = ''
177 c.diffs = ''
178 for x in c.changes:
178 for x in c.changes:
179 c.diffs += x[2]
179 c.diffs += x[2]
180
180
181 return render('changeset/raw_changeset.html')
181 return render('changeset/raw_changeset.html')
@@ -1,80 +1,80 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # feed controller for pylons
3 # feed controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
5
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 23, 2010
21 Created on April 23, 2010
22 feed controller for pylons
22 feed controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from pylons import tmpl_context as c, url, response
25 from pylons import tmpl_context as c, url, response
26 from rhodecode.lib.base import BaseController, render
26 from rhodecode.lib.base import BaseController, render
27 from rhodecode.model.hg import HgModel
27 from rhodecode.model.hg import HgModel
28 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
28 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
29 import logging
29 import logging
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
32 class FeedController(BaseController):
32 class FeedController(BaseController):
33
33
34 #secure it or not ?
34 #secure it or not ?
35 def __before__(self):
35 def __before__(self):
36 super(FeedController, self).__before__()
36 super(FeedController, self).__before__()
37 #common values for feeds
37 #common values for feeds
38 self.description = 'Changes on %s repository'
38 self.description = 'Changes on %s repository'
39 self.title = "%s feed"
39 self.title = "%s feed"
40 self.language = 'en-us'
40 self.language = 'en-us'
41 self.ttl = "5"
41 self.ttl = "5"
42 self.feed_nr = 10
42 self.feed_nr = 10
43
43
44 def atom(self, repo_name):
44 def atom(self, repo_name):
45 """Produce an atom-1.0 feed via feedgenerator module"""
45 """Produce an atom-1.0 feed via feedgenerator module"""
46 feed = Atom1Feed(title=self.title % repo_name,
46 feed = Atom1Feed(title=self.title % repo_name,
47 link=url('summary_home', repo_name=repo_name, qualified=True),
47 link=url('summary_home', repo_name=repo_name, qualified=True),
48 description=self.description % repo_name,
48 description=self.description % repo_name,
49 language=self.language,
49 language=self.language,
50 ttl=self.ttl)
50 ttl=self.ttl)
51
51
52 changesets = HgModel().get_repo(repo_name)
52 changesets = HgModel().get_repo(repo_name)
53
53
54 for cs in changesets[:self.feed_nr]:
54 for cs in changesets[:self.feed_nr]:
55 feed.add_item(title=cs.message,
55 feed.add_item(title=cs.message,
56 link=url('changeset_home', repo_name=repo_name,
56 link=url('changeset_home', repo_name=repo_name,
57 revision=cs.short_id, qualified=True),
57 revision=cs.raw_id, qualified=True),
58 description=str(cs.date))
58 description=str(cs.date))
59
59
60 response.content_type = feed.mime_type
60 response.content_type = feed.mime_type
61 return feed.writeString('utf-8')
61 return feed.writeString('utf-8')
62
62
63
63
64 def rss(self, repo_name):
64 def rss(self, repo_name):
65 """Produce an rss2 feed via feedgenerator module"""
65 """Produce an rss2 feed via feedgenerator module"""
66 feed = Rss201rev2Feed(title=self.title % repo_name,
66 feed = Rss201rev2Feed(title=self.title % repo_name,
67 link=url('summary_home', repo_name=repo_name, qualified=True),
67 link=url('summary_home', repo_name=repo_name, qualified=True),
68 description=self.description % repo_name,
68 description=self.description % repo_name,
69 language=self.language,
69 language=self.language,
70 ttl=self.ttl)
70 ttl=self.ttl)
71
71
72 changesets = HgModel().get_repo(repo_name)
72 changesets = HgModel().get_repo(repo_name)
73 for cs in changesets[:self.feed_nr]:
73 for cs in changesets[:self.feed_nr]:
74 feed.add_item(title=cs.message,
74 feed.add_item(title=cs.message,
75 link=url('changeset_home', repo_name=repo_name,
75 link=url('changeset_home', repo_name=repo_name,
76 revision=cs.short_id, qualified=True),
76 revision=cs.raw_id, qualified=True),
77 description=str(cs.date))
77 description=str(cs.date))
78
78
79 response.content_type = feed.mime_type
79 response.content_type = feed.mime_type
80 return feed.writeString('utf-8')
80 return feed.writeString('utf-8')
@@ -1,215 +1,212 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # files controller for pylons
3 # files controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
5
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 21, 2010
21 Created on April 21, 2010
22 files controller for pylons
22 files controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from mercurial import archival
25 from mercurial import archival
26 from pylons import request, response, session, tmpl_context as c, url
26 from pylons import request, response, session, tmpl_context as c, url
27 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
28 from pylons.controllers.util import redirect
28 from pylons.controllers.util import redirect
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
30 from rhodecode.lib.base import BaseController, render
30 from rhodecode.lib.base import BaseController, render
31 from rhodecode.lib.utils import EmptyChangeset
31 from rhodecode.lib.utils import EmptyChangeset
32 from rhodecode.model.hg import HgModel
32 from rhodecode.model.hg import HgModel
33 from vcs.exceptions import RepositoryError, ChangesetError
33 from vcs.exceptions import RepositoryError, ChangesetError
34 from vcs.nodes import FileNode
34 from vcs.nodes import FileNode
35 from vcs.utils import diffs as differ
35 from vcs.utils import diffs as differ
36 import logging
36 import logging
37 import rhodecode.lib.helpers as h
37 import rhodecode.lib.helpers as h
38 import tempfile
38 import tempfile
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42 class FilesController(BaseController):
42 class FilesController(BaseController):
43
43
44 @LoginRequired()
44 @LoginRequired()
45 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
45 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
46 'repository.admin')
46 'repository.admin')
47 def __before__(self):
47 def __before__(self):
48 super(FilesController, self).__before__()
48 super(FilesController, self).__before__()
49 c.file_size_limit = 250 * 1024 #limit of file size to display
49 c.file_size_limit = 250 * 1024 #limit of file size to display
50
50
51 def index(self, repo_name, revision, f_path):
51 def index(self, repo_name, revision, f_path):
52 hg_model = HgModel()
52 hg_model = HgModel()
53 c.repo = repo = hg_model.get_repo(c.repo_name)
53 c.repo = repo = hg_model.get_repo(c.repo_name)
54 revision = request.POST.get('at_rev', None) or revision
54 revision = request.POST.get('at_rev', None) or revision
55
55
56 def get_next_rev(cur):
56 def get_next_rev(cur):
57 max_rev = len(c.repo.revisions) - 1
57 max_rev = len(c.repo.revisions) - 1
58 r = cur + 1
58 r = cur + 1
59 if r > max_rev:
59 if r > max_rev:
60 r = max_rev
60 r = max_rev
61 return r
61 return r
62
62
63 def get_prev_rev(cur):
63 def get_prev_rev(cur):
64 r = cur - 1
64 r = cur - 1
65 return r
65 return r
66
66
67 c.f_path = f_path
67 c.f_path = f_path
68
68
69
69
70 try:
70 try:
71 cur_rev = repo.get_changeset(revision).revision
71 cur_rev = repo.get_changeset(revision).revision
72 prev_rev = repo.get_changeset(get_prev_rev(cur_rev)).short_id
72 prev_rev = repo.get_changeset(get_prev_rev(cur_rev)).raw_id
73 next_rev = repo.get_changeset(get_next_rev(cur_rev)).short_id
73 next_rev = repo.get_changeset(get_next_rev(cur_rev)).raw_id
74
74
75 c.url_prev = url('files_home', repo_name=c.repo_name,
75 c.url_prev = url('files_home', repo_name=c.repo_name,
76 revision=prev_rev, f_path=f_path)
76 revision=prev_rev, f_path=f_path)
77 c.url_next = url('files_home', repo_name=c.repo_name,
77 c.url_next = url('files_home', repo_name=c.repo_name,
78 revision=next_rev, f_path=f_path)
78 revision=next_rev, f_path=f_path)
79
79
80 c.changeset = repo.get_changeset(revision)
80 c.changeset = repo.get_changeset(revision)
81
81
82 c.cur_rev = c.changeset.short_id
82 c.cur_rev = c.changeset.raw_id
83 c.rev_nr = c.changeset.revision
83 c.rev_nr = c.changeset.revision
84 c.files_list = c.changeset.get_node(f_path)
84 c.files_list = c.changeset.get_node(f_path)
85 c.file_history = self._get_history(repo, c.files_list, f_path)
85 c.file_history = self._get_history(repo, c.files_list, f_path)
86
86
87 except (RepositoryError, ChangesetError):
87 except (RepositoryError, ChangesetError):
88 c.files_list = None
88 c.files_list = None
89
89
90 return render('files/files.html')
90 return render('files/files.html')
91
91
92 def rawfile(self, repo_name, revision, f_path):
92 def rawfile(self, repo_name, revision, f_path):
93 hg_model = HgModel()
93 hg_model = HgModel()
94 c.repo = hg_model.get_repo(c.repo_name)
94 c.repo = hg_model.get_repo(c.repo_name)
95 file_node = c.repo.get_changeset(revision).get_node(f_path)
95 file_node = c.repo.get_changeset(revision).get_node(f_path)
96 response.content_type = file_node.mimetype
96 response.content_type = file_node.mimetype
97 response.content_disposition = 'attachment; filename=%s' \
97 response.content_disposition = 'attachment; filename=%s' \
98 % f_path.split('/')[-1]
98 % f_path.split('/')[-1]
99 return file_node.content
99 return file_node.content
100
100
101 def raw(self, repo_name, revision, f_path):
101 def raw(self, repo_name, revision, f_path):
102 hg_model = HgModel()
102 hg_model = HgModel()
103 c.repo = hg_model.get_repo(c.repo_name)
103 c.repo = hg_model.get_repo(c.repo_name)
104 file_node = c.repo.get_changeset(revision).get_node(f_path)
104 file_node = c.repo.get_changeset(revision).get_node(f_path)
105 response.content_type = 'text/plain'
105 response.content_type = 'text/plain'
106
106
107 return file_node.content
107 return file_node.content
108
108
109 def annotate(self, repo_name, revision, f_path):
109 def annotate(self, repo_name, revision, f_path):
110 hg_model = HgModel()
110 hg_model = HgModel()
111 c.repo = hg_model.get_repo(c.repo_name)
111 c.repo = hg_model.get_repo(c.repo_name)
112 cs = c.repo.get_changeset(revision)
112 cs = c.repo.get_changeset(revision)
113 c.file = cs.get_node(f_path)
113 c.file = cs.get_node(f_path)
114 c.file_msg = cs.get_file_message(f_path)
114 c.file_msg = cs.get_file_message(f_path)
115 c.cur_rev = cs.short_id
115 c.cur_rev = cs.raw_id
116 c.rev_nr = cs.revision
116 c.rev_nr = cs.revision
117 c.f_path = f_path
117 c.f_path = f_path
118
118
119 return render('files/files_annotate.html')
119 return render('files/files_annotate.html')
120
120
121 def archivefile(self, repo_name, revision, fileformat):
121 def archivefile(self, repo_name, revision, fileformat):
122 archive_specs = {
122 archive_specs = {
123 '.tar.bz2': ('application/x-tar', 'tbz2'),
123 '.tar.bz2': ('application/x-tar', 'tbz2'),
124 '.tar.gz': ('application/x-tar', 'tgz'),
124 '.tar.gz': ('application/x-tar', 'tgz'),
125 '.zip': ('application/zip', 'zip'),
125 '.zip': ('application/zip', 'zip'),
126 }
126 }
127 if not archive_specs.has_key(fileformat):
127 if not archive_specs.has_key(fileformat):
128 return 'Unknown archive type %s' % fileformat
128 return 'Unknown archive type %s' % fileformat
129
129
130 def read_in_chunks(file_object, chunk_size=1024 * 40):
130 def read_in_chunks(file_object, chunk_size=1024 * 40):
131 """Lazy function (generator) to read a file piece by piece.
131 """Lazy function (generator) to read a file piece by piece.
132 Default chunk size: 40k."""
132 Default chunk size: 40k."""
133 while True:
133 while True:
134 data = file_object.read(chunk_size)
134 data = file_object.read(chunk_size)
135 if not data:
135 if not data:
136 break
136 break
137 yield data
137 yield data
138
138
139 archive = tempfile.TemporaryFile()
139 archive = tempfile.TemporaryFile()
140 repo = HgModel().get_repo(repo_name).repo
140 repo = HgModel().get_repo(repo_name).repo
141 fname = '%s-%s%s' % (repo_name, revision, fileformat)
141 fname = '%s-%s%s' % (repo_name, revision, fileformat)
142 archival.archive(repo, archive, revision, archive_specs[fileformat][1],
142 archival.archive(repo, archive, revision, archive_specs[fileformat][1],
143 prefix='%s-%s' % (repo_name, revision))
143 prefix='%s-%s' % (repo_name, revision))
144 response.content_type = archive_specs[fileformat][0]
144 response.content_type = archive_specs[fileformat][0]
145 response.content_disposition = 'attachment; filename=%s' % fname
145 response.content_disposition = 'attachment; filename=%s' % fname
146 archive.seek(0)
146 archive.seek(0)
147 return read_in_chunks(archive)
147 return read_in_chunks(archive)
148
148
149 def diff(self, repo_name, f_path):
149 def diff(self, repo_name, f_path):
150 hg_model = HgModel()
150 hg_model = HgModel()
151 diff1 = request.GET.get('diff1')
151 diff1 = request.GET.get('diff1')
152 diff2 = request.GET.get('diff2')
152 diff2 = request.GET.get('diff2')
153 c.action = request.GET.get('diff')
153 c.action = request.GET.get('diff')
154 c.no_changes = diff1 == diff2
154 c.no_changes = diff1 == diff2
155 c.f_path = f_path
155 c.f_path = f_path
156 c.repo = hg_model.get_repo(c.repo_name)
156 c.repo = hg_model.get_repo(c.repo_name)
157
157
158 try:
158 try:
159 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
159 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
160 c.changeset_1 = c.repo.get_changeset(diff1)
160 c.changeset_1 = c.repo.get_changeset(diff1)
161 node1 = c.changeset_1.get_node(f_path)
161 node1 = c.changeset_1.get_node(f_path)
162 else:
162 else:
163 c.changeset_1 = EmptyChangeset()
163 c.changeset_1 = EmptyChangeset()
164 node1 = FileNode('.', '', changeset=c.changeset_1)
164 node1 = FileNode('.', '', changeset=c.changeset_1)
165
165
166 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
166 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
167 c.changeset_2 = c.repo.get_changeset(diff2)
167 c.changeset_2 = c.repo.get_changeset(diff2)
168 node2 = c.changeset_2.get_node(f_path)
168 node2 = c.changeset_2.get_node(f_path)
169 else:
169 else:
170 c.changeset_2 = EmptyChangeset()
170 c.changeset_2 = EmptyChangeset()
171 node2 = FileNode('.', '', changeset=c.changeset_2)
171 node2 = FileNode('.', '', changeset=c.changeset_2)
172 except RepositoryError:
172 except RepositoryError:
173 return redirect(url('files_home',
173 return redirect(url('files_home',
174 repo_name=c.repo_name, f_path=f_path))
174 repo_name=c.repo_name, f_path=f_path))
175
175
176 c.diff1 = 'r%s:%s' % (c.changeset_1.revision, c.changeset_1.short_id)
177 c.diff2 = 'r%s:%s' % (c.changeset_2.revision, c.changeset_2.short_id)
178
179 f_udiff = differ.get_udiff(node1, node2)
176 f_udiff = differ.get_udiff(node1, node2)
180 diff = differ.DiffProcessor(f_udiff)
177 diff = differ.DiffProcessor(f_udiff)
181
178
182 if c.action == 'download':
179 if c.action == 'download':
183 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
180 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
184 response.content_type = 'text/plain'
181 response.content_type = 'text/plain'
185 response.content_disposition = 'attachment; filename=%s' \
182 response.content_disposition = 'attachment; filename=%s' \
186 % diff_name
183 % diff_name
187 return diff.raw_diff()
184 return diff.raw_diff()
188
185
189 elif c.action == 'raw':
186 elif c.action == 'raw':
190 c.cur_diff = '<pre class="raw">%s</pre>' % h.escape(diff.raw_diff())
187 c.cur_diff = '<pre class="raw">%s</pre>' % h.escape(diff.raw_diff())
191 elif c.action == 'diff':
188 elif c.action == 'diff':
192 if node1.size > c.file_size_limit or node2.size > c.file_size_limit:
189 if node1.size > c.file_size_limit or node2.size > c.file_size_limit:
193 c.cur_diff = _('Diff is to big to display')
190 c.cur_diff = _('Diff is to big to display')
194 else:
191 else:
195 c.cur_diff = diff.as_html()
192 c.cur_diff = diff.as_html()
196 else:
193 else:
197 #default option
194 #default option
198 if node1.size > c.file_size_limit or node2.size > c.file_size_limit:
195 if node1.size > c.file_size_limit or node2.size > c.file_size_limit:
199 c.cur_diff = _('Diff is to big to display')
196 c.cur_diff = _('Diff is to big to display')
200 else:
197 else:
201 c.cur_diff = diff.as_html()
198 c.cur_diff = diff.as_html()
202
199
203 if not c.cur_diff: c.no_changes = True
200 if not c.cur_diff: c.no_changes = True
204 return render('files/file_diff.html')
201 return render('files/file_diff.html')
205
202
206 def _get_history(self, repo, node, f_path):
203 def _get_history(self, repo, node, f_path):
207 from vcs.nodes import NodeKind
204 from vcs.nodes import NodeKind
208 if not node.kind is NodeKind.FILE:
205 if not node.kind is NodeKind.FILE:
209 return []
206 return []
210 changesets = node.history
207 changesets = node.history
211 hist_l = []
208 hist_l = []
212 for chs in changesets:
209 for chs in changesets:
213 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
210 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
214 hist_l.append((chs.short_id, n_desc,))
211 hist_l.append((chs.raw_id, n_desc,))
215 return hist_l
212 return hist_l
@@ -1,58 +1,58 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # hg controller for pylons
3 # hg controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on February 18, 2010
21 Created on February 18, 2010
22 hg controller for pylons
22 hg controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from operator import itemgetter
25 from operator import itemgetter
26 from pylons import tmpl_context as c, request
26 from pylons import tmpl_context as c, request
27 from rhodecode.lib.auth import LoginRequired
27 from rhodecode.lib.auth import LoginRequired
28 from rhodecode.lib.base import BaseController, render
28 from rhodecode.lib.base import BaseController, render
29 from rhodecode.model.hg import HgModel
29 from rhodecode.model.hg import HgModel
30 import logging
30 import logging
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33 class HgController(BaseController):
33 class HomeController(BaseController):
34
34
35 @LoginRequired()
35 @LoginRequired()
36 def __before__(self):
36 def __before__(self):
37 super(HgController, self).__before__()
37 super(HomeController, self).__before__()
38
38
39 def index(self):
39 def index(self):
40 sortables = ['name', 'description', 'last_change', 'tip', 'contact']
40 sortables = ['name', 'description', 'last_change', 'tip', 'contact']
41 current_sort = request.GET.get('sort', 'name')
41 current_sort = request.GET.get('sort', 'name')
42 current_sort_slug = current_sort.replace('-', '')
42 current_sort_slug = current_sort.replace('-', '')
43
43
44 if current_sort_slug not in sortables:
44 if current_sort_slug not in sortables:
45 c.sort_by = 'name'
45 c.sort_by = 'name'
46 current_sort_slug = c.sort_by
46 current_sort_slug = c.sort_by
47 else:
47 else:
48 c.sort_by = current_sort
48 c.sort_by = current_sort
49 c.sort_slug = current_sort_slug
49 c.sort_slug = current_sort_slug
50 cached_repo_list = HgModel().get_repos()
50 cached_repo_list = HgModel().get_repos()
51
51
52 sort_key = current_sort_slug + '_sort'
52 sort_key = current_sort_slug + '_sort'
53 if c.sort_by.startswith('-'):
53 if c.sort_by.startswith('-'):
54 c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=True)
54 c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=True)
55 else:
55 else:
56 c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=False)
56 c.repos_list = sorted(cached_repo_list, key=itemgetter(sort_key), reverse=False)
57
57
58 return render('/index.html')
58 return render('/index.html')
@@ -1,144 +1,144 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # login controller for pylons
3 # login controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20
20
21 """
21 """
22 Created on April 22, 2010
22 Created on April 22, 2010
23 login controller for pylons
23 login controller for pylons
24 @author: marcink
24 @author: marcink
25 """
25 """
26 from formencode import htmlfill
26 from formencode import htmlfill
27 from pylons import request, response, session, tmpl_context as c, url
27 from pylons import request, response, session, tmpl_context as c, url
28 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
29 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
29 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
30 from rhodecode.lib.base import BaseController, render
30 from rhodecode.lib.base import BaseController, render
31 import rhodecode.lib.helpers as h
31 import rhodecode.lib.helpers as h
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
33 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
34 from rhodecode.model.user import UserModel
34 from rhodecode.model.user import UserModel
35 import formencode
35 import formencode
36 import logging
36 import logging
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40 class LoginController(BaseController):
40 class LoginController(BaseController):
41
41
42 def __before__(self):
42 def __before__(self):
43 super(LoginController, self).__before__()
43 super(LoginController, self).__before__()
44
44
45 def index(self):
45 def index(self):
46 #redirect if already logged in
46 #redirect if already logged in
47 c.came_from = request.GET.get('came_from', None)
47 c.came_from = request.GET.get('came_from', None)
48
48
49 if c.rhodecode_user.is_authenticated:
49 if c.rhodecode_user.is_authenticated:
50 return redirect(url('hg_home'))
50 return redirect(url('home'))
51
51
52 if request.POST:
52 if request.POST:
53 #import Login Form validator class
53 #import Login Form validator class
54 login_form = LoginForm()
54 login_form = LoginForm()
55 try:
55 try:
56 c.form_result = login_form.to_python(dict(request.POST))
56 c.form_result = login_form.to_python(dict(request.POST))
57 username = c.form_result['username']
57 username = c.form_result['username']
58 user = UserModel().get_by_username(username)
58 user = UserModel().get_by_username(username)
59 auth_user = AuthUser()
59 auth_user = AuthUser()
60 auth_user.username = user.username
60 auth_user.username = user.username
61 auth_user.is_authenticated = True
61 auth_user.is_authenticated = True
62 auth_user.is_admin = user.admin
62 auth_user.is_admin = user.admin
63 auth_user.user_id = user.user_id
63 auth_user.user_id = user.user_id
64 auth_user.name = user.name
64 auth_user.name = user.name
65 auth_user.lastname = user.lastname
65 auth_user.lastname = user.lastname
66 session['rhodecode_user'] = auth_user
66 session['rhodecode_user'] = auth_user
67 session.save()
67 session.save()
68 log.info('user %s is now authenticated', username)
68 log.info('user %s is now authenticated', username)
69
69
70 user.update_lastlogin()
70 user.update_lastlogin()
71
71
72 if c.came_from:
72 if c.came_from:
73 return redirect(c.came_from)
73 return redirect(c.came_from)
74 else:
74 else:
75 return redirect(url('hg_home'))
75 return redirect(url('home'))
76
76
77 except formencode.Invalid, errors:
77 except formencode.Invalid, errors:
78 return htmlfill.render(
78 return htmlfill.render(
79 render('/login.html'),
79 render('/login.html'),
80 defaults=errors.value,
80 defaults=errors.value,
81 errors=errors.error_dict or {},
81 errors=errors.error_dict or {},
82 prefix_error=False,
82 prefix_error=False,
83 encoding="UTF-8")
83 encoding="UTF-8")
84
84
85 return render('/login.html')
85 return render('/login.html')
86
86
87 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
87 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
88 'hg.register.manual_activate')
88 'hg.register.manual_activate')
89 def register(self):
89 def register(self):
90 user_model = UserModel()
90 user_model = UserModel()
91 c.auto_active = False
91 c.auto_active = False
92 for perm in user_model.get_by_username('default', cache=False).user_perms:
92 for perm in user_model.get_by_username('default', cache=False).user_perms:
93 if perm.permission.permission_name == 'hg.register.auto_activate':
93 if perm.permission.permission_name == 'hg.register.auto_activate':
94 c.auto_active = True
94 c.auto_active = True
95 break
95 break
96
96
97 if request.POST:
97 if request.POST:
98
98
99 register_form = RegisterForm()()
99 register_form = RegisterForm()()
100 try:
100 try:
101 form_result = register_form.to_python(dict(request.POST))
101 form_result = register_form.to_python(dict(request.POST))
102 form_result['active'] = c.auto_active
102 form_result['active'] = c.auto_active
103 user_model.create_registration(form_result)
103 user_model.create_registration(form_result)
104 h.flash(_('You have successfully registered into rhodecode'),
104 h.flash(_('You have successfully registered into rhodecode'),
105 category='success')
105 category='success')
106 return redirect(url('login_home'))
106 return redirect(url('login_home'))
107
107
108 except formencode.Invalid, errors:
108 except formencode.Invalid, errors:
109 return htmlfill.render(
109 return htmlfill.render(
110 render('/register.html'),
110 render('/register.html'),
111 defaults=errors.value,
111 defaults=errors.value,
112 errors=errors.error_dict or {},
112 errors=errors.error_dict or {},
113 prefix_error=False,
113 prefix_error=False,
114 encoding="UTF-8")
114 encoding="UTF-8")
115
115
116 return render('/register.html')
116 return render('/register.html')
117
117
118 def password_reset(self):
118 def password_reset(self):
119 user_model = UserModel()
119 user_model = UserModel()
120 if request.POST:
120 if request.POST:
121
121
122 password_reset_form = PasswordResetForm()()
122 password_reset_form = PasswordResetForm()()
123 try:
123 try:
124 form_result = password_reset_form.to_python(dict(request.POST))
124 form_result = password_reset_form.to_python(dict(request.POST))
125 user_model.reset_password(form_result)
125 user_model.reset_password(form_result)
126 h.flash(_('Your new password was sent'),
126 h.flash(_('Your new password was sent'),
127 category='success')
127 category='success')
128 return redirect(url('login_home'))
128 return redirect(url('login_home'))
129
129
130 except formencode.Invalid, errors:
130 except formencode.Invalid, errors:
131 return htmlfill.render(
131 return htmlfill.render(
132 render('/password_reset.html'),
132 render('/password_reset.html'),
133 defaults=errors.value,
133 defaults=errors.value,
134 errors=errors.error_dict or {},
134 errors=errors.error_dict or {},
135 prefix_error=False,
135 prefix_error=False,
136 encoding="UTF-8")
136 encoding="UTF-8")
137
137
138 return render('/password_reset.html')
138 return render('/password_reset.html')
139
139
140 def logout(self):
140 def logout(self):
141 session['rhodecode_user'] = AuthUser()
141 session['rhodecode_user'] = AuthUser()
142 session.save()
142 session.save()
143 log.info('Logging out and setting user as Empty')
143 log.info('Logging out and setting user as Empty')
144 redirect(url('hg_home'))
144 redirect(url('home'))
@@ -1,175 +1,175 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # settings controller for pylons
3 # settings controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on June 30, 2010
21 Created on June 30, 2010
22 settings controller for pylons
22 settings controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from formencode import htmlfill
25 from formencode import htmlfill
26 from pylons import tmpl_context as c, request, url
26 from pylons import tmpl_context as c, request, url
27 from pylons.controllers.util import redirect
27 from pylons.controllers.util import redirect
28 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
30 from rhodecode.lib.base import BaseController, render
30 from rhodecode.lib.base import BaseController, render
31 from rhodecode.lib.utils import invalidate_cache, action_logger
31 from rhodecode.lib.utils import invalidate_cache, action_logger
32 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
32 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
33 from rhodecode.model.repo import RepoModel
33 from rhodecode.model.repo import RepoModel
34 import formencode
34 import formencode
35 import logging
35 import logging
36 import rhodecode.lib.helpers as h
36 import rhodecode.lib.helpers as h
37 import traceback
37 import traceback
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41 class SettingsController(BaseController):
41 class SettingsController(BaseController):
42
42
43 @LoginRequired()
43 @LoginRequired()
44 @HasRepoPermissionAllDecorator('repository.admin')
44 @HasRepoPermissionAllDecorator('repository.admin')
45 def __before__(self):
45 def __before__(self):
46 super(SettingsController, self).__before__()
46 super(SettingsController, self).__before__()
47
47
48 def index(self, repo_name):
48 def index(self, repo_name):
49 repo_model = RepoModel()
49 repo_model = RepoModel()
50 c.repo_info = repo = repo_model.get(repo_name)
50 c.repo_info = repo = repo_model.get(repo_name)
51 if not repo:
51 if not repo:
52 h.flash(_('%s repository is not mapped to db perhaps'
52 h.flash(_('%s repository is not mapped to db perhaps'
53 ' it was created or renamed from the filesystem'
53 ' it was created or renamed from the filesystem'
54 ' please run the application again'
54 ' please run the application again'
55 ' in order to rescan repositories') % repo_name,
55 ' in order to rescan repositories') % repo_name,
56 category='error')
56 category='error')
57
57
58 return redirect(url('hg_home'))
58 return redirect(url('home'))
59 defaults = c.repo_info.__dict__
59 defaults = c.repo_info.__dict__
60 defaults.update({'user':c.repo_info.user.username})
60 defaults.update({'user':c.repo_info.user.username})
61 c.users_array = repo_model.get_users_js()
61 c.users_array = repo_model.get_users_js()
62
62
63 for p in c.repo_info.repo_to_perm:
63 for p in c.repo_info.repo_to_perm:
64 defaults.update({'perm_%s' % p.user.username:
64 defaults.update({'perm_%s' % p.user.username:
65 p.permission.permission_name})
65 p.permission.permission_name})
66
66
67 return htmlfill.render(
67 return htmlfill.render(
68 render('settings/repo_settings.html'),
68 render('settings/repo_settings.html'),
69 defaults=defaults,
69 defaults=defaults,
70 encoding="UTF-8",
70 encoding="UTF-8",
71 force_defaults=False
71 force_defaults=False
72 )
72 )
73
73
74 def update(self, repo_name):
74 def update(self, repo_name):
75 repo_model = RepoModel()
75 repo_model = RepoModel()
76 changed_name = repo_name
76 changed_name = repo_name
77 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
77 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
78 try:
78 try:
79 form_result = _form.to_python(dict(request.POST))
79 form_result = _form.to_python(dict(request.POST))
80 repo_model.update(repo_name, form_result)
80 repo_model.update(repo_name, form_result)
81 invalidate_cache('cached_repo_list')
81 invalidate_cache('cached_repo_list')
82 h.flash(_('Repository %s updated successfully' % repo_name),
82 h.flash(_('Repository %s updated successfully' % repo_name),
83 category='success')
83 category='success')
84 changed_name = form_result['repo_name']
84 changed_name = form_result['repo_name']
85 except formencode.Invalid, errors:
85 except formencode.Invalid, errors:
86 c.repo_info = repo_model.get(repo_name)
86 c.repo_info = repo_model.get(repo_name)
87 c.users_array = repo_model.get_users_js()
87 c.users_array = repo_model.get_users_js()
88 errors.value.update({'user':c.repo_info.user.username})
88 errors.value.update({'user':c.repo_info.user.username})
89 return htmlfill.render(
89 return htmlfill.render(
90 render('settings/repo_settings.html'),
90 render('settings/repo_settings.html'),
91 defaults=errors.value,
91 defaults=errors.value,
92 errors=errors.error_dict or {},
92 errors=errors.error_dict or {},
93 prefix_error=False,
93 prefix_error=False,
94 encoding="UTF-8")
94 encoding="UTF-8")
95 except Exception:
95 except Exception:
96 log.error(traceback.format_exc())
96 log.error(traceback.format_exc())
97 h.flash(_('error occured during update of repository %s') \
97 h.flash(_('error occured during update of repository %s') \
98 % repo_name, category='error')
98 % repo_name, category='error')
99
99
100 return redirect(url('repo_settings_home', repo_name=changed_name))
100 return redirect(url('repo_settings_home', repo_name=changed_name))
101
101
102
102
103
103
104 def delete(self, repo_name):
104 def delete(self, repo_name):
105 """DELETE /repos/repo_name: Delete an existing item"""
105 """DELETE /repos/repo_name: Delete an existing item"""
106 # Forms posted to this method should contain a hidden field:
106 # Forms posted to this method should contain a hidden field:
107 # <input type="hidden" name="_method" value="DELETE" />
107 # <input type="hidden" name="_method" value="DELETE" />
108 # Or using helpers:
108 # Or using helpers:
109 # h.form(url('repo_settings_delete', repo_name=ID),
109 # h.form(url('repo_settings_delete', repo_name=ID),
110 # method='delete')
110 # method='delete')
111 # url('repo_settings_delete', repo_name=ID)
111 # url('repo_settings_delete', repo_name=ID)
112
112
113 repo_model = RepoModel()
113 repo_model = RepoModel()
114 repo = repo_model.get(repo_name)
114 repo = repo_model.get(repo_name)
115 if not repo:
115 if not repo:
116 h.flash(_('%s repository is not mapped to db perhaps'
116 h.flash(_('%s repository is not mapped to db perhaps'
117 ' it was moved or renamed from the filesystem'
117 ' it was moved or renamed from the filesystem'
118 ' please run the application again'
118 ' please run the application again'
119 ' in order to rescan repositories') % repo_name,
119 ' in order to rescan repositories') % repo_name,
120 category='error')
120 category='error')
121
121
122 return redirect(url('hg_home'))
122 return redirect(url('home'))
123 try:
123 try:
124 action_logger(self.rhodecode_user, 'user_deleted_repo',
124 action_logger(self.rhodecode_user, 'user_deleted_repo',
125 repo_name, '', self.sa)
125 repo_name, '', self.sa)
126 repo_model.delete(repo)
126 repo_model.delete(repo)
127 invalidate_cache('cached_repo_list')
127 invalidate_cache('cached_repo_list')
128 h.flash(_('deleted repository %s') % repo_name, category='success')
128 h.flash(_('deleted repository %s') % repo_name, category='success')
129 except Exception:
129 except Exception:
130 h.flash(_('An error occurred during deletion of %s') % repo_name,
130 h.flash(_('An error occurred during deletion of %s') % repo_name,
131 category='error')
131 category='error')
132
132
133 return redirect(url('hg_home'))
133 return redirect(url('home'))
134
134
135 def fork(self, repo_name):
135 def fork(self, repo_name):
136 repo_model = RepoModel()
136 repo_model = RepoModel()
137 c.repo_info = repo = repo_model.get(repo_name)
137 c.repo_info = repo = repo_model.get(repo_name)
138 if not repo:
138 if not repo:
139 h.flash(_('%s repository is not mapped to db perhaps'
139 h.flash(_('%s repository is not mapped to db perhaps'
140 ' it was created or renamed from the filesystem'
140 ' it was created or renamed from the filesystem'
141 ' please run the application again'
141 ' please run the application again'
142 ' in order to rescan repositories') % repo_name,
142 ' in order to rescan repositories') % repo_name,
143 category='error')
143 category='error')
144
144
145 return redirect(url('hg_home'))
145 return redirect(url('home'))
146
146
147 return render('settings/repo_fork.html')
147 return render('settings/repo_fork.html')
148
148
149
149
150
150
151 def fork_create(self, repo_name):
151 def fork_create(self, repo_name):
152 repo_model = RepoModel()
152 repo_model = RepoModel()
153 c.repo_info = repo_model.get(repo_name)
153 c.repo_info = repo_model.get(repo_name)
154 _form = RepoForkForm()()
154 _form = RepoForkForm()()
155 form_result = {}
155 form_result = {}
156 try:
156 try:
157 form_result = _form.to_python(dict(request.POST))
157 form_result = _form.to_python(dict(request.POST))
158 form_result.update({'repo_name':repo_name})
158 form_result.update({'repo_name':repo_name})
159 repo_model.create_fork(form_result, c.rhodecode_user)
159 repo_model.create_fork(form_result, c.rhodecode_user)
160 h.flash(_('fork %s repository as %s task added') \
160 h.flash(_('fork %s repository as %s task added') \
161 % (repo_name, form_result['fork_name']),
161 % (repo_name, form_result['fork_name']),
162 category='success')
162 category='success')
163 action_logger(self.rhodecode_user, 'user_forked_repo',
163 action_logger(self.rhodecode_user, 'user_forked_repo',
164 repo_name, '', self.sa)
164 repo_name, '', self.sa)
165 except formencode.Invalid, errors:
165 except formencode.Invalid, errors:
166 c.new_repo = errors.value['fork_name']
166 c.new_repo = errors.value['fork_name']
167 r = render('settings/repo_fork.html')
167 r = render('settings/repo_fork.html')
168
168
169 return htmlfill.render(
169 return htmlfill.render(
170 r,
170 r,
171 defaults=errors.value,
171 defaults=errors.value,
172 errors=errors.error_dict or {},
172 errors=errors.error_dict or {},
173 prefix_error=False,
173 prefix_error=False,
174 encoding="UTF-8")
174 encoding="UTF-8")
175 return redirect(url('hg_home'))
175 return redirect(url('home'))
@@ -1,397 +1,398 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 from pygments.formatters import HtmlFormatter
6 from pygments.formatters import HtmlFormatter
7 from pygments import highlight as code_highlight
7 from pygments import highlight as code_highlight
8 from pylons import url, app_globals as g
8 from pylons import url, app_globals as g
9 from pylons.i18n.translation import _, ungettext
9 from pylons.i18n.translation import _, ungettext
10 from vcs.utils.annotate import annotate_highlight
10 from vcs.utils.annotate import annotate_highlight
11 from webhelpers.html import literal, HTML, escape
11 from webhelpers.html import literal, HTML, escape
12 from webhelpers.html.tools import *
12 from webhelpers.html.tools import *
13 from webhelpers.html.builder import make_tag
13 from webhelpers.html.builder import make_tag
14 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
14 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
15 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
15 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
16 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
16 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
17 password, textarea, title, ul, xml_declaration, radio
17 password, textarea, title, ul, xml_declaration, radio
18 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
18 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
19 mail_to, strip_links, strip_tags, tag_re
19 mail_to, strip_links, strip_tags, tag_re
20 from webhelpers.number import format_byte_size, format_bit_size
20 from webhelpers.number import format_byte_size, format_bit_size
21 from webhelpers.pylonslib import Flash as _Flash
21 from webhelpers.pylonslib import Flash as _Flash
22 from webhelpers.pylonslib.secure_form import secure_form
22 from webhelpers.pylonslib.secure_form import secure_form
23 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
23 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
24 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
24 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
25 replace_whitespace, urlify, truncate, wrap_paragraphs
25 replace_whitespace, urlify, truncate, wrap_paragraphs
26 from webhelpers.date import time_ago_in_words
26 from webhelpers.date import time_ago_in_words
27
27
28 #Custom helpers here :)
28 #Custom helpers here :)
29 class _Link(object):
29 class _Link(object):
30 '''
30 '''
31 Make a url based on label and url with help of url_for
31 Make a url based on label and url with help of url_for
32 :param label:name of link if not defined url is used
32 :param label:name of link if not defined url is used
33 :param url: the url for link
33 :param url: the url for link
34 '''
34 '''
35
35
36 def __call__(self, label='', *url_, **urlargs):
36 def __call__(self, label='', *url_, **urlargs):
37 if label is None or '':
37 if label is None or '':
38 label = url
38 label = url
39 link_fn = link_to(label, url(*url_, **urlargs))
39 link_fn = link_to(label, url(*url_, **urlargs))
40 return link_fn
40 return link_fn
41
41
42 link = _Link()
42 link = _Link()
43
43
44 class _GetError(object):
44 class _GetError(object):
45
45
46 def __call__(self, field_name, form_errors):
46 def __call__(self, field_name, form_errors):
47 tmpl = """<span class="error_msg">%s</span>"""
47 tmpl = """<span class="error_msg">%s</span>"""
48 if form_errors and form_errors.has_key(field_name):
48 if form_errors and form_errors.has_key(field_name):
49 return literal(tmpl % form_errors.get(field_name))
49 return literal(tmpl % form_errors.get(field_name))
50
50
51 get_error = _GetError()
51 get_error = _GetError()
52
52
53 def recursive_replace(str, replace=' '):
53 def recursive_replace(str, replace=' '):
54 """
54 """
55 Recursive replace of given sign to just one instance
55 Recursive replace of given sign to just one instance
56 :param str: given string
56 :param str: given string
57 :param replace:char to find and replace multiple instances
57 :param replace:char to find and replace multiple instances
58
58
59 Examples::
59 Examples::
60 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
60 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
61 'Mighty-Mighty-Bo-sstones'
61 'Mighty-Mighty-Bo-sstones'
62 """
62 """
63
63
64 if str.find(replace * 2) == -1:
64 if str.find(replace * 2) == -1:
65 return str
65 return str
66 else:
66 else:
67 str = str.replace(replace * 2, replace)
67 str = str.replace(replace * 2, replace)
68 return recursive_replace(str, replace)
68 return recursive_replace(str, replace)
69
69
70 class _ToolTip(object):
70 class _ToolTip(object):
71
71
72 def __call__(self, tooltip_title, trim_at=50):
72 def __call__(self, tooltip_title, trim_at=50):
73 """
73 """
74 Special function just to wrap our text into nice formatted autowrapped
74 Special function just to wrap our text into nice formatted autowrapped
75 text
75 text
76 :param tooltip_title:
76 :param tooltip_title:
77 """
77 """
78
78
79 return wrap_paragraphs(escape(tooltip_title), trim_at)\
79 return wrap_paragraphs(escape(tooltip_title), trim_at)\
80 .replace('\n', '<br/>')
80 .replace('\n', '<br/>')
81
81
82 def activate(self):
82 def activate(self):
83 """
83 """
84 Adds tooltip mechanism to the given Html all tooltips have to have
84 Adds tooltip mechanism to the given Html all tooltips have to have
85 set class tooltip and set attribute tooltip_title.
85 set class tooltip and set attribute tooltip_title.
86 Then a tooltip will be generated based on that
86 Then a tooltip will be generated based on that
87 All with yui js tooltip
87 All with yui js tooltip
88 """
88 """
89
89
90 js = '''
90 js = '''
91 YAHOO.util.Event.onDOMReady(function(){
91 YAHOO.util.Event.onDOMReady(function(){
92 function toolTipsId(){
92 function toolTipsId(){
93 var ids = [];
93 var ids = [];
94 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
94 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
95
95
96 for (var i = 0; i < tts.length; i++) {
96 for (var i = 0; i < tts.length; i++) {
97 //if element doesn not have and id autgenerate one for tooltip
97 //if element doesn not have and id autgenerate one for tooltip
98
98
99 if (!tts[i].id){
99 if (!tts[i].id){
100 tts[i].id='tt'+i*100;
100 tts[i].id='tt'+i*100;
101 }
101 }
102 ids.push(tts[i].id);
102 ids.push(tts[i].id);
103 }
103 }
104 return ids
104 return ids
105 };
105 };
106 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
106 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
107 context: toolTipsId(),
107 context: toolTipsId(),
108 monitorresize:false,
108 monitorresize:false,
109 xyoffset :[0,0],
109 xyoffset :[0,0],
110 autodismissdelay:300000,
110 autodismissdelay:300000,
111 hidedelay:5,
111 hidedelay:5,
112 showdelay:20,
112 showdelay:20,
113 });
113 });
114
114
115 //Mouse Over event disabled for new repositories since they dont
115 //Mouse Over event disabled for new repositories since they dont
116 //have last commit message
116 //have last commit message
117 myToolTips.contextMouseOverEvent.subscribe(
117 myToolTips.contextMouseOverEvent.subscribe(
118 function(type, args) {
118 function(type, args) {
119 var context = args[0];
119 var context = args[0];
120 var txt = context.getAttribute('tooltip_title');
120 var txt = context.getAttribute('tooltip_title');
121 if(txt){
121 if(txt){
122 return true;
122 return true;
123 }
123 }
124 else{
124 else{
125 return false;
125 return false;
126 }
126 }
127 });
127 });
128
128
129
129
130 // Set the text for the tooltip just before we display it. Lazy method
130 // Set the text for the tooltip just before we display it. Lazy method
131 myToolTips.contextTriggerEvent.subscribe(
131 myToolTips.contextTriggerEvent.subscribe(
132 function(type, args) {
132 function(type, args) {
133
133
134
134
135 var context = args[0];
135 var context = args[0];
136
136
137 var txt = context.getAttribute('tooltip_title');
137 var txt = context.getAttribute('tooltip_title');
138 this.cfg.setProperty("text", txt);
138 this.cfg.setProperty("text", txt);
139
139
140
140
141 // positioning of tooltip
141 // positioning of tooltip
142 var tt_w = this.element.clientWidth;
142 var tt_w = this.element.clientWidth;
143 var tt_h = this.element.clientHeight;
143 var tt_h = this.element.clientHeight;
144
144
145 var context_w = context.offsetWidth;
145 var context_w = context.offsetWidth;
146 var context_h = context.offsetHeight;
146 var context_h = context.offsetHeight;
147
147
148 var pos_x = YAHOO.util.Dom.getX(context);
148 var pos_x = YAHOO.util.Dom.getX(context);
149 var pos_y = YAHOO.util.Dom.getY(context);
149 var pos_y = YAHOO.util.Dom.getY(context);
150
150
151 var display_strategy = 'top';
151 var display_strategy = 'top';
152 var xy_pos = [0,0];
152 var xy_pos = [0,0];
153 switch (display_strategy){
153 switch (display_strategy){
154
154
155 case 'top':
155 case 'top':
156 var cur_x = (pos_x+context_w/2)-(tt_w/2);
156 var cur_x = (pos_x+context_w/2)-(tt_w/2);
157 var cur_y = pos_y-tt_h-4;
157 var cur_y = pos_y-tt_h-4;
158 xy_pos = [cur_x,cur_y];
158 xy_pos = [cur_x,cur_y];
159 break;
159 break;
160 case 'bottom':
160 case 'bottom':
161 var cur_x = (pos_x+context_w/2)-(tt_w/2);
161 var cur_x = (pos_x+context_w/2)-(tt_w/2);
162 var cur_y = pos_y+context_h+4;
162 var cur_y = pos_y+context_h+4;
163 xy_pos = [cur_x,cur_y];
163 xy_pos = [cur_x,cur_y];
164 break;
164 break;
165 case 'left':
165 case 'left':
166 var cur_x = (pos_x-tt_w-4);
166 var cur_x = (pos_x-tt_w-4);
167 var cur_y = pos_y-((tt_h/2)-context_h/2);
167 var cur_y = pos_y-((tt_h/2)-context_h/2);
168 xy_pos = [cur_x,cur_y];
168 xy_pos = [cur_x,cur_y];
169 break;
169 break;
170 case 'right':
170 case 'right':
171 var cur_x = (pos_x+context_w+4);
171 var cur_x = (pos_x+context_w+4);
172 var cur_y = pos_y-((tt_h/2)-context_h/2);
172 var cur_y = pos_y-((tt_h/2)-context_h/2);
173 xy_pos = [cur_x,cur_y];
173 xy_pos = [cur_x,cur_y];
174 break;
174 break;
175 default:
175 default:
176 var cur_x = (pos_x+context_w/2)-(tt_w/2);
176 var cur_x = (pos_x+context_w/2)-(tt_w/2);
177 var cur_y = pos_y-tt_h-4;
177 var cur_y = pos_y-tt_h-4;
178 xy_pos = [cur_x,cur_y];
178 xy_pos = [cur_x,cur_y];
179 break;
179 break;
180
180
181 }
181 }
182
182
183 this.cfg.setProperty("xy",xy_pos);
183 this.cfg.setProperty("xy",xy_pos);
184
184
185 });
185 });
186
186
187 //Mouse out
187 //Mouse out
188 myToolTips.contextMouseOutEvent.subscribe(
188 myToolTips.contextMouseOutEvent.subscribe(
189 function(type, args) {
189 function(type, args) {
190 var context = args[0];
190 var context = args[0];
191
191
192 });
192 });
193 });
193 });
194 '''
194 '''
195 return literal(js)
195 return literal(js)
196
196
197 tooltip = _ToolTip()
197 tooltip = _ToolTip()
198
198
199 class _FilesBreadCrumbs(object):
199 class _FilesBreadCrumbs(object):
200
200
201 def __call__(self, repo_name, rev, paths):
201 def __call__(self, repo_name, rev, paths):
202 url_l = [link_to(repo_name, url('files_home',
202 url_l = [link_to(repo_name, url('files_home',
203 repo_name=repo_name,
203 repo_name=repo_name,
204 revision=rev, f_path=''))]
204 revision=rev, f_path=''))]
205 paths_l = paths.split('/')
205 paths_l = paths.split('/')
206
206
207 for cnt, p in enumerate(paths_l, 1):
207 for cnt, p in enumerate(paths_l, 1):
208 if p != '':
208 if p != '':
209 url_l.append(link_to(p, url('files_home',
209 url_l.append(link_to(p, url('files_home',
210 repo_name=repo_name,
210 repo_name=repo_name,
211 revision=rev,
211 revision=rev,
212 f_path='/'.join(paths_l[:cnt]))))
212 f_path='/'.join(paths_l[:cnt]))))
213
213
214 return literal('/'.join(url_l))
214 return literal('/'.join(url_l))
215
215
216 files_breadcrumbs = _FilesBreadCrumbs()
216 files_breadcrumbs = _FilesBreadCrumbs()
217 class CodeHtmlFormatter(HtmlFormatter):
217 class CodeHtmlFormatter(HtmlFormatter):
218
218
219 def wrap(self, source, outfile):
219 def wrap(self, source, outfile):
220 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
220 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
221
221
222 def _wrap_code(self, source):
222 def _wrap_code(self, source):
223 for cnt, it in enumerate(source, 1):
223 for cnt, it in enumerate(source, 1):
224 i, t = it
224 i, t = it
225 t = '<div id="#S-%s">%s</div>' % (cnt, t)
225 t = '<div id="#S-%s">%s</div>' % (cnt, t)
226 yield i, t
226 yield i, t
227 def pygmentize(filenode, **kwargs):
227 def pygmentize(filenode, **kwargs):
228 """
228 """
229 pygmentize function using pygments
229 pygmentize function using pygments
230 :param filenode:
230 :param filenode:
231 """
231 """
232 return literal(code_highlight(filenode.content,
232 return literal(code_highlight(filenode.content,
233 filenode.lexer, CodeHtmlFormatter(**kwargs)))
233 filenode.lexer, CodeHtmlFormatter(**kwargs)))
234
234
235 def pygmentize_annotation(filenode, **kwargs):
235 def pygmentize_annotation(filenode, **kwargs):
236 """
236 """
237 pygmentize function for annotation
237 pygmentize function for annotation
238 :param filenode:
238 :param filenode:
239 """
239 """
240
240
241 color_dict = {}
241 color_dict = {}
242 def gen_color():
242 def gen_color():
243 """generator for getting 10k of evenly distibuted colors using hsv color
243 """generator for getting 10k of evenly distibuted colors using hsv color
244 and golden ratio.
244 and golden ratio.
245 """
245 """
246 import colorsys
246 import colorsys
247 n = 10000
247 n = 10000
248 golden_ratio = 0.618033988749895
248 golden_ratio = 0.618033988749895
249 h = 0.22717784590367374
249 h = 0.22717784590367374
250 #generate 10k nice web friendly colors in the same order
250 #generate 10k nice web friendly colors in the same order
251 for c in xrange(n):
251 for c in xrange(n):
252 h += golden_ratio
252 h += golden_ratio
253 h %= 1
253 h %= 1
254 HSV_tuple = [h, 0.95, 0.95]
254 HSV_tuple = [h, 0.95, 0.95]
255 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
255 RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
256 yield map(lambda x:str(int(x * 256)), RGB_tuple)
256 yield map(lambda x:str(int(x * 256)), RGB_tuple)
257
257
258 cgenerator = gen_color()
258 cgenerator = gen_color()
259
259
260 def get_color_string(cs):
260 def get_color_string(cs):
261 if color_dict.has_key(cs):
261 if color_dict.has_key(cs):
262 col = color_dict[cs]
262 col = color_dict[cs]
263 else:
263 else:
264 col = color_dict[cs] = cgenerator.next()
264 col = color_dict[cs] = cgenerator.next()
265 return "color: rgb(%s)! important;" % (', '.join(col))
265 return "color: rgb(%s)! important;" % (', '.join(col))
266
266
267 def url_func(changeset):
267 def url_func(changeset):
268 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
268 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
269 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
269 " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
270
270
271 tooltip_html = tooltip_html % (changeset.author,
271 tooltip_html = tooltip_html % (changeset.author,
272 changeset.date,
272 changeset.date,
273 tooltip(changeset.message))
273 tooltip(changeset.message))
274 lnk_format = 'r%-5s:%s' % (changeset.revision,
274 lnk_format = 'r%-5s:%s' % (changeset.revision,
275 changeset.short_id)
275 changeset.raw_id)
276 uri = link_to(
276 uri = link_to(
277 lnk_format,
277 lnk_format,
278 url('changeset_home', repo_name=changeset.repository.name,
278 url('changeset_home', repo_name=changeset.repository.name,
279 revision=changeset.short_id),
279 revision=changeset.raw_id),
280 style=get_color_string(changeset.short_id),
280 style=get_color_string(changeset.raw_id),
281 class_='tooltip',
281 class_='tooltip',
282 tooltip_title=tooltip_html
282 tooltip_title=tooltip_html
283 )
283 )
284
284
285 uri += '\n'
285 uri += '\n'
286 return uri
286 return uri
287 return literal(annotate_highlight(filenode, url_func, **kwargs))
287 return literal(annotate_highlight(filenode, url_func, **kwargs))
288
288
289 def repo_name_slug(value):
289 def repo_name_slug(value):
290 """Return slug of name of repository
290 """Return slug of name of repository
291 This function is called on each creation/modification
291 This function is called on each creation/modification
292 of repository to prevent bad names in repo
292 of repository to prevent bad names in repo
293 """
293 """
294 slug = remove_formatting(value)
294 slug = remove_formatting(value)
295 slug = strip_tags(slug)
295 slug = strip_tags(slug)
296
296
297 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
297 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
298 slug = slug.replace(c, '-')
298 slug = slug.replace(c, '-')
299 slug = recursive_replace(slug, '-')
299 slug = recursive_replace(slug, '-')
300 slug = collapse(slug, '-')
300 slug = collapse(slug, '-')
301 return slug
301 return slug
302
302
303 def get_changeset_safe(repo, rev):
303 def get_changeset_safe(repo, rev):
304 from vcs.backends.base import BaseRepository
304 from vcs.backends.base import BaseRepository
305 from vcs.exceptions import RepositoryError
305 from vcs.exceptions import RepositoryError
306 if not isinstance(repo, BaseRepository):
306 if not isinstance(repo, BaseRepository):
307 raise Exception('You must pass an Repository '
307 raise Exception('You must pass an Repository '
308 'object as first argument got %s', type(repo))
308 'object as first argument got %s', type(repo))
309
309
310 try:
310 try:
311 cs = repo.get_changeset(rev)
311 cs = repo.get_changeset(rev)
312 except RepositoryError:
312 except RepositoryError:
313 from rhodecode.lib.utils import EmptyChangeset
313 from rhodecode.lib.utils import EmptyChangeset
314 cs = EmptyChangeset()
314 cs = EmptyChangeset()
315 return cs
315 return cs
316
316
317
317
318 flash = _Flash()
318 flash = _Flash()
319
319
320
320
321 #==============================================================================
321 #==============================================================================
322 # MERCURIAL FILTERS available via h.
322 # MERCURIAL FILTERS available via h.
323 #==============================================================================
323 #==============================================================================
324 from mercurial import util
324 from mercurial import util
325 from mercurial.templatefilters import person as _person
325 from mercurial.templatefilters import person as _person
326
326
327
327
328
328
329 def _age(curdate):
329 def _age(curdate):
330 """turns a datetime into an age string."""
330 """turns a datetime into an age string."""
331
331
332 from datetime import timedelta, datetime
332 from datetime import timedelta, datetime
333 agescales = [("year", 3600 * 24 * 365),
333 agescales = [("year", 3600 * 24 * 365),
334 ("month", 3600 * 24 * 30),
334 ("month", 3600 * 24 * 30),
335 #("week", 3600 * 24 * 7),
335 #("week", 3600 * 24 * 7),
336 ("day", 3600 * 24),
336 ("day", 3600 * 24),
337 ("hour", 3600),
337 ("hour", 3600),
338 ("minute", 60),
338 ("minute", 60),
339 ("second", 1)]
339 ("second", 1)]
340
340
341 age = datetime.now() - curdate
341 age = datetime.now() - curdate
342 age_seconds = (age.days * agescales[2][1]) + age.seconds
342 age_seconds = (age.days * agescales[2][1]) + age.seconds
343
343
344 pos = 1
344 pos = 1
345 for scale in agescales:
345 for scale in agescales:
346 if scale[1] <= age_seconds:
346 if scale[1] <= age_seconds:
347 return time_ago_in_words(curdate, agescales[pos][0])
347 return time_ago_in_words(curdate, agescales[pos][0])
348 pos += 1
348 pos += 1
349
349
350 age = lambda x:_age(x)
350 age = lambda x:_age(x)
351 capitalize = lambda x: x.capitalize()
351 capitalize = lambda x: x.capitalize()
352 email = util.email
352 email = util.email
353 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
353 email_or_none = lambda x: util.email(x) if util.email(x) != x else None
354 person = lambda x: _person(x)
354 person = lambda x: _person(x)
355 short_id = lambda x: x[:12]
355
356
356 #==============================================================================
357 #==============================================================================
357 # PERMS
358 # PERMS
358 #==============================================================================
359 #==============================================================================
359 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
360 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
360 HasRepoPermissionAny, HasRepoPermissionAll
361 HasRepoPermissionAny, HasRepoPermissionAll
361
362
362 #==============================================================================
363 #==============================================================================
363 # GRAVATAR URL
364 # GRAVATAR URL
364 #==============================================================================
365 #==============================================================================
365 import hashlib
366 import hashlib
366 import urllib
367 import urllib
367 from pylons import request
368 from pylons import request
368
369
369 def gravatar_url(email_address, size=30):
370 def gravatar_url(email_address, size=30):
370 ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
371 ssl_enabled = 'https' == request.environ.get('HTTP_X_URL_SCHEME')
371 default = 'identicon'
372 default = 'identicon'
372 baseurl_nossl = "http://www.gravatar.com/avatar/"
373 baseurl_nossl = "http://www.gravatar.com/avatar/"
373 baseurl_ssl = "https://secure.gravatar.com/avatar/"
374 baseurl_ssl = "https://secure.gravatar.com/avatar/"
374 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
375 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
375
376
376
377
377 # construct the url
378 # construct the url
378 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
379 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
379 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
380 gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
380
381
381 return gravatar_url
382 return gravatar_url
382
383
383 def safe_unicode(str):
384 def safe_unicode(str):
384 """safe unicode function. In case of UnicodeDecode error we try to return
385 """safe unicode function. In case of UnicodeDecode error we try to return
385 unicode with errors replace, if this failes we return unicode with
386 unicode with errors replace, if this failes we return unicode with
386 string_escape decoding """
387 string_escape decoding """
387
388
388 try:
389 try:
389 u_str = unicode(str)
390 u_str = unicode(str)
390 except UnicodeDecodeError:
391 except UnicodeDecodeError:
391 try:
392 try:
392 u_str = unicode(str, 'utf-8', 'replace')
393 u_str = unicode(str, 'utf-8', 'replace')
393 except UnicodeDecodeError:
394 except UnicodeDecodeError:
394 #incase we have a decode error just represent as byte string
395 #incase we have a decode error just represent as byte string
395 u_str = unicode(str(str).encode('string_escape'))
396 u_str = unicode(str(str).encode('string_escape'))
396
397
397 return u_str
398 return u_str
@@ -1,537 +1,538 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Utilities for RhodeCode
3 # Utilities for RhodeCode
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19 """
19 """
20 Created on April 18, 2010
20 Created on April 18, 2010
21 Utilities for RhodeCode
21 Utilities for RhodeCode
22 @author: marcink
22 @author: marcink
23 """
23 """
24
24
25 from UserDict import DictMixin
25 from UserDict import DictMixin
26 from mercurial import ui, config, hg
26 from mercurial import ui, config, hg
27 from mercurial.error import RepoError
27 from mercurial.error import RepoError
28 from rhodecode.model import meta
28 from rhodecode.model import meta
29 from rhodecode.model.caching_query import FromCache
29 from rhodecode.model.caching_query import FromCache
30 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, \
30 from rhodecode.model.db import Repository, User, RhodeCodeUi, RhodeCodeSettings, \
31 UserLog
31 UserLog
32 from rhodecode.model.repo import RepoModel
32 from rhodecode.model.repo import RepoModel
33 from rhodecode.model.user import UserModel
33 from rhodecode.model.user import UserModel
34 from vcs.backends.base import BaseChangeset
34 from vcs.backends.base import BaseChangeset
35 from vcs.backends.git import GitRepository
35 from vcs.backends.git import GitRepository
36 from vcs.backends.hg import MercurialRepository
36 from vcs.backends.hg import MercurialRepository
37 from vcs.utils.lazy import LazyProperty
37 from vcs.utils.lazy import LazyProperty
38 import datetime
38 import datetime
39 import logging
39 import logging
40 import os
40 import os
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 def get_repo_slug(request):
45 def get_repo_slug(request):
46 return request.environ['pylons.routes_dict'].get('repo_name')
46 return request.environ['pylons.routes_dict'].get('repo_name')
47
47
48 def is_mercurial(environ):
48 def is_mercurial(environ):
49 """
49 """
50 Returns True if request's target is mercurial server - header
50 Returns True if request's target is mercurial server - header
51 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
51 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
52 """
52 """
53 http_accept = environ.get('HTTP_ACCEPT')
53 http_accept = environ.get('HTTP_ACCEPT')
54 if http_accept and http_accept.startswith('application/mercurial'):
54 if http_accept and http_accept.startswith('application/mercurial'):
55 return True
55 return True
56 return False
56 return False
57
57
58 def is_git(environ):
58 def is_git(environ):
59 """
59 """
60 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
60 Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
61 then have git client version given.
61 then have git client version given.
62
62
63 :param environ:
63 :param environ:
64 """
64 """
65 http_user_agent = environ.get('HTTP_USER_AGENT')
65 http_user_agent = environ.get('HTTP_USER_AGENT')
66 if http_user_agent.startswith('git'):
66 if http_user_agent.startswith('git'):
67 return True
67 return True
68 return False
68 return False
69
69
70 def action_logger(user, action, repo, ipaddr, sa=None):
70 def action_logger(user, action, repo, ipaddr, sa=None):
71 """
71 """
72 Action logger for various action made by users
72 Action logger for various action made by users
73 """
73 """
74
74
75 if not sa:
75 if not sa:
76 sa = meta.Session()
76 sa = meta.Session()
77
77
78 try:
78 try:
79 if hasattr(user, 'user_id'):
79 if hasattr(user, 'user_id'):
80 user_id = user.user_id
80 user_id = user.user_id
81 elif isinstance(user, basestring):
81 elif isinstance(user, basestring):
82 user_id = UserModel(sa).get_by_username(user, cache=False).user_id
82 user_id = UserModel(sa).get_by_username(user, cache=False).user_id
83 else:
83 else:
84 raise Exception('You have to provide user object or username')
84 raise Exception('You have to provide user object or username')
85
85
86 repo_name = repo.lstrip('/')
86 repo_name = repo.lstrip('/')
87 user_log = UserLog()
87 user_log = UserLog()
88 user_log.user_id = user_id
88 user_log.user_id = user_id
89 user_log.action = action
89 user_log.action = action
90 user_log.repository_name = repo_name
90 user_log.repository_name = repo_name
91 user_log.repository = RepoModel(sa).get(repo_name, cache=False)
91 user_log.repository = RepoModel(sa).get(repo_name, cache=False)
92 user_log.action_date = datetime.datetime.now()
92 user_log.action_date = datetime.datetime.now()
93 user_log.user_ip = ipaddr
93 user_log.user_ip = ipaddr
94 sa.add(user_log)
94 sa.add(user_log)
95 sa.commit()
95 sa.commit()
96
96
97 log.info('Adding user %s, action %s on %s',
97 log.info('Adding user %s, action %s on %s',
98 user.username, action, repo)
98 user.username, action, repo)
99 except Exception, e:
99 except Exception, e:
100 sa.rollback()
100 sa.rollback()
101 log.error('could not log user action:%s', str(e))
101 log.error('could not log user action:%s', str(e))
102
102
103 def get_repos(path, recursive=False, initial=False):
103 def get_repos(path, recursive=False, initial=False):
104 """
104 """
105 Scans given path for repos and return (name,(type,path)) tuple
105 Scans given path for repos and return (name,(type,path)) tuple
106 :param prefix:
106 :param prefix:
107 :param path:
107 :param path:
108 :param recursive:
108 :param recursive:
109 :param initial:
109 :param initial:
110 """
110 """
111 from vcs.utils.helpers import get_scm
111 from vcs.utils.helpers import get_scm
112 from vcs.exceptions import VCSError
112 from vcs.exceptions import VCSError
113
113
114 try:
114 try:
115 scm = get_scm(path)
115 scm = get_scm(path)
116 except:
116 except:
117 pass
117 pass
118 else:
118 else:
119 raise Exception('The given path %s should not be a repository got %s',
119 raise Exception('The given path %s should not be a repository got %s',
120 path, scm)
120 path, scm)
121
121
122 for dirpath in os.listdir(path):
122 for dirpath in os.listdir(path):
123 try:
123 try:
124 yield dirpath, get_scm(os.path.join(path, dirpath))
124 yield dirpath, get_scm(os.path.join(path, dirpath))
125 except VCSError:
125 except VCSError:
126 pass
126 pass
127
127
128 if __name__ == '__main__':
128 if __name__ == '__main__':
129 get_repos('', '/home/marcink/workspace-python')
129 get_repos('', '/home/marcink/workspace-python')
130
130
131
131
132 def check_repo_fast(repo_name, base_path):
132 def check_repo_fast(repo_name, base_path):
133 if os.path.isdir(os.path.join(base_path, repo_name)):return False
133 if os.path.isdir(os.path.join(base_path, repo_name)):return False
134 return True
134 return True
135
135
136 def check_repo(repo_name, base_path, verify=True):
136 def check_repo(repo_name, base_path, verify=True):
137
137
138 repo_path = os.path.join(base_path, repo_name)
138 repo_path = os.path.join(base_path, repo_name)
139
139
140 try:
140 try:
141 if not check_repo_fast(repo_name, base_path):
141 if not check_repo_fast(repo_name, base_path):
142 return False
142 return False
143 r = hg.repository(ui.ui(), repo_path)
143 r = hg.repository(ui.ui(), repo_path)
144 if verify:
144 if verify:
145 hg.verify(r)
145 hg.verify(r)
146 #here we hnow that repo exists it was verified
146 #here we hnow that repo exists it was verified
147 log.info('%s repo is already created', repo_name)
147 log.info('%s repo is already created', repo_name)
148 return False
148 return False
149 except RepoError:
149 except RepoError:
150 #it means that there is no valid repo there...
150 #it means that there is no valid repo there...
151 log.info('%s repo is free for creation', repo_name)
151 log.info('%s repo is free for creation', repo_name)
152 return True
152 return True
153
153
154 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
154 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
155 while True:
155 while True:
156 ok = raw_input(prompt)
156 ok = raw_input(prompt)
157 if ok in ('y', 'ye', 'yes'): return True
157 if ok in ('y', 'ye', 'yes'): return True
158 if ok in ('n', 'no', 'nop', 'nope'): return False
158 if ok in ('n', 'no', 'nop', 'nope'): return False
159 retries = retries - 1
159 retries = retries - 1
160 if retries < 0: raise IOError
160 if retries < 0: raise IOError
161 print complaint
161 print complaint
162
162
163 def get_hg_ui_cached():
163 def get_hg_ui_cached():
164 try:
164 try:
165 sa = meta.Session
165 sa = meta.Session
166 ret = sa.query(RhodeCodeUi)\
166 ret = sa.query(RhodeCodeUi)\
167 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
167 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
168 .all()
168 .all()
169 except:
169 except:
170 pass
170 pass
171 finally:
171 finally:
172 meta.Session.remove()
172 meta.Session.remove()
173 return ret
173 return ret
174
174
175
175
176 def get_hg_settings():
176 def get_hg_settings():
177 try:
177 try:
178 sa = meta.Session()
178 sa = meta.Session()
179 ret = sa.query(RhodeCodeSettings)\
179 ret = sa.query(RhodeCodeSettings)\
180 .options(FromCache("sql_cache_short", "get_hg_settings"))\
180 .options(FromCache("sql_cache_short", "get_hg_settings"))\
181 .all()
181 .all()
182 except:
182 except:
183 pass
183 pass
184 finally:
184 finally:
185 meta.Session.remove()
185 meta.Session.remove()
186
186
187 if not ret:
187 if not ret:
188 raise Exception('Could not get application settings !')
188 raise Exception('Could not get application settings !')
189 settings = {}
189 settings = {}
190 for each in ret:
190 for each in ret:
191 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
191 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
192
192
193 return settings
193 return settings
194
194
195 def get_hg_ui_settings():
195 def get_hg_ui_settings():
196 try:
196 try:
197 sa = meta.Session()
197 sa = meta.Session()
198 ret = sa.query(RhodeCodeUi).all()
198 ret = sa.query(RhodeCodeUi).all()
199 except:
199 except:
200 pass
200 pass
201 finally:
201 finally:
202 meta.Session.remove()
202 meta.Session.remove()
203
203
204 if not ret:
204 if not ret:
205 raise Exception('Could not get application ui settings !')
205 raise Exception('Could not get application ui settings !')
206 settings = {}
206 settings = {}
207 for each in ret:
207 for each in ret:
208 k = each.ui_key
208 k = each.ui_key
209 v = each.ui_value
209 v = each.ui_value
210 if k == '/':
210 if k == '/':
211 k = 'root_path'
211 k = 'root_path'
212
212
213 if k.find('.') != -1:
213 if k.find('.') != -1:
214 k = k.replace('.', '_')
214 k = k.replace('.', '_')
215
215
216 if each.ui_section == 'hooks':
216 if each.ui_section == 'hooks':
217 v = each.ui_active
217 v = each.ui_active
218
218
219 settings[each.ui_section + '_' + k] = v
219 settings[each.ui_section + '_' + k] = v
220
220
221 return settings
221 return settings
222
222
223 #propagated from mercurial documentation
223 #propagated from mercurial documentation
224 ui_sections = ['alias', 'auth',
224 ui_sections = ['alias', 'auth',
225 'decode/encode', 'defaults',
225 'decode/encode', 'defaults',
226 'diff', 'email',
226 'diff', 'email',
227 'extensions', 'format',
227 'extensions', 'format',
228 'merge-patterns', 'merge-tools',
228 'merge-patterns', 'merge-tools',
229 'hooks', 'http_proxy',
229 'hooks', 'http_proxy',
230 'smtp', 'patch',
230 'smtp', 'patch',
231 'paths', 'profiling',
231 'paths', 'profiling',
232 'server', 'trusted',
232 'server', 'trusted',
233 'ui', 'web', ]
233 'ui', 'web', ]
234
234
235 def make_ui(read_from='file', path=None, checkpaths=True):
235 def make_ui(read_from='file', path=None, checkpaths=True):
236 """
236 """
237 A function that will read python rc files or database
237 A function that will read python rc files or database
238 and make an mercurial ui object from read options
238 and make an mercurial ui object from read options
239
239
240 :param path: path to mercurial config file
240 :param path: path to mercurial config file
241 :param checkpaths: check the path
241 :param checkpaths: check the path
242 :param read_from: read from 'file' or 'db'
242 :param read_from: read from 'file' or 'db'
243 """
243 """
244
244
245 baseui = ui.ui()
245 baseui = ui.ui()
246
246
247 if read_from == 'file':
247 if read_from == 'file':
248 if not os.path.isfile(path):
248 if not os.path.isfile(path):
249 log.warning('Unable to read config file %s' % path)
249 log.warning('Unable to read config file %s' % path)
250 return False
250 return False
251 log.debug('reading hgrc from %s', path)
251 log.debug('reading hgrc from %s', path)
252 cfg = config.config()
252 cfg = config.config()
253 cfg.read(path)
253 cfg.read(path)
254 for section in ui_sections:
254 for section in ui_sections:
255 for k, v in cfg.items(section):
255 for k, v in cfg.items(section):
256 baseui.setconfig(section, k, v)
256 baseui.setconfig(section, k, v)
257 log.debug('settings ui from file[%s]%s:%s', section, k, v)
257 log.debug('settings ui from file[%s]%s:%s', section, k, v)
258
258
259 elif read_from == 'db':
259 elif read_from == 'db':
260 hg_ui = get_hg_ui_cached()
260 hg_ui = get_hg_ui_cached()
261 for ui_ in hg_ui:
261 for ui_ in hg_ui:
262 if ui_.ui_active:
262 if ui_.ui_active:
263 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
263 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section, ui_.ui_key, ui_.ui_value)
264 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
264 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
265
265
266
266
267 return baseui
267 return baseui
268
268
269
269
270 def set_rhodecode_config(config):
270 def set_rhodecode_config(config):
271 hgsettings = get_hg_settings()
271 hgsettings = get_hg_settings()
272
272
273 for k, v in hgsettings.items():
273 for k, v in hgsettings.items():
274 config[k] = v
274 config[k] = v
275
275
276 def invalidate_cache(name, *args):
276 def invalidate_cache(name, *args):
277 """Invalidates given name cache"""
277 """Invalidates given name cache"""
278
278
279 from beaker.cache import region_invalidate
279 from beaker.cache import region_invalidate
280 log.info('INVALIDATING CACHE FOR %s', name)
280 log.info('INVALIDATING CACHE FOR %s', name)
281
281
282 """propagate our arguments to make sure invalidation works. First
282 """propagate our arguments to make sure invalidation works. First
283 argument has to be the name of cached func name give to cache decorator
283 argument has to be the name of cached func name give to cache decorator
284 without that the invalidation would not work"""
284 without that the invalidation would not work"""
285 tmp = [name]
285 tmp = [name]
286 tmp.extend(args)
286 tmp.extend(args)
287 args = tuple(tmp)
287 args = tuple(tmp)
288
288
289 if name == 'cached_repo_list':
289 if name == 'cached_repo_list':
290 from rhodecode.model.hg import _get_repos_cached
290 from rhodecode.model.hg import _get_repos_cached
291 region_invalidate(_get_repos_cached, None, *args)
291 region_invalidate(_get_repos_cached, None, *args)
292
292
293 if name == 'full_changelog':
293 if name == 'full_changelog':
294 from rhodecode.model.hg import _full_changelog_cached
294 from rhodecode.model.hg import _full_changelog_cached
295 region_invalidate(_full_changelog_cached, None, *args)
295 region_invalidate(_full_changelog_cached, None, *args)
296
296
297 class EmptyChangeset(BaseChangeset):
297 class EmptyChangeset(BaseChangeset):
298 """
298 """
299 An dummy empty changeset.
299 An dummy empty changeset.
300 """
300 """
301
301
302 revision = -1
302 revision = -1
303 message = ''
303 message = ''
304 author = ''
304 author = ''
305 date = ''
305 date = ''
306
306 @LazyProperty
307 @LazyProperty
307 def raw_id(self):
308 def raw_id(self):
308 """
309 """
309 Returns raw string identifying this changeset, useful for web
310 Returns raw string identifying this changeset, useful for web
310 representation.
311 representation.
311 """
312 """
312 return '0' * 40
313 return '0' * 40
313
314
314 @LazyProperty
315 @LazyProperty
315 def short_id(self):
316 def short_id(self):
316 return self.raw_id[:12]
317 return self.raw_id[:12]
317
318
318 def get_file_changeset(self, path):
319 def get_file_changeset(self, path):
319 return self
320 return self
320
321
321 def get_file_content(self, path):
322 def get_file_content(self, path):
322 return u''
323 return u''
323
324
324 def get_file_size(self, path):
325 def get_file_size(self, path):
325 return 0
326 return 0
326
327
327 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
328 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
328 """
329 """
329 maps all found repositories into db
330 maps all found repositories into db
330 """
331 """
331
332
332 sa = meta.Session()
333 sa = meta.Session()
333 rm = RepoModel(sa)
334 rm = RepoModel(sa)
334 user = sa.query(User).filter(User.admin == True).first()
335 user = sa.query(User).filter(User.admin == True).first()
335
336
336 for name, repo in initial_repo_list.items():
337 for name, repo in initial_repo_list.items():
337 if not rm.get(name, cache=False):
338 if not rm.get(name, cache=False):
338 log.info('repository %s not found creating default', name)
339 log.info('repository %s not found creating default', name)
339
340
340 if isinstance(repo, MercurialRepository):
341 if isinstance(repo, MercurialRepository):
341 repo_type = 'hg'
342 repo_type = 'hg'
342 if isinstance(repo, GitRepository):
343 if isinstance(repo, GitRepository):
343 repo_type = 'git'
344 repo_type = 'git'
344
345
345 form_data = {
346 form_data = {
346 'repo_name':name,
347 'repo_name':name,
347 'repo_type':repo_type,
348 'repo_type':repo_type,
348 'description':repo.description if repo.description != 'unknown' else \
349 'description':repo.description if repo.description != 'unknown' else \
349 'auto description for %s' % name,
350 'auto description for %s' % name,
350 'private':False
351 'private':False
351 }
352 }
352 rm.create(form_data, user, just_db=True)
353 rm.create(form_data, user, just_db=True)
353
354
354
355
355 if remove_obsolete:
356 if remove_obsolete:
356 #remove from database those repositories that are not in the filesystem
357 #remove from database those repositories that are not in the filesystem
357 for repo in sa.query(Repository).all():
358 for repo in sa.query(Repository).all():
358 if repo.repo_name not in initial_repo_list.keys():
359 if repo.repo_name not in initial_repo_list.keys():
359 sa.delete(repo)
360 sa.delete(repo)
360 sa.commit()
361 sa.commit()
361
362
362
363
363 meta.Session.remove()
364 meta.Session.remove()
364
365
365
366
366 class OrderedDict(dict, DictMixin):
367 class OrderedDict(dict, DictMixin):
367
368
368 def __init__(self, *args, **kwds):
369 def __init__(self, *args, **kwds):
369 if len(args) > 1:
370 if len(args) > 1:
370 raise TypeError('expected at most 1 arguments, got %d' % len(args))
371 raise TypeError('expected at most 1 arguments, got %d' % len(args))
371 try:
372 try:
372 self.__end
373 self.__end
373 except AttributeError:
374 except AttributeError:
374 self.clear()
375 self.clear()
375 self.update(*args, **kwds)
376 self.update(*args, **kwds)
376
377
377 def clear(self):
378 def clear(self):
378 self.__end = end = []
379 self.__end = end = []
379 end += [None, end, end] # sentinel node for doubly linked list
380 end += [None, end, end] # sentinel node for doubly linked list
380 self.__map = {} # key --> [key, prev, next]
381 self.__map = {} # key --> [key, prev, next]
381 dict.clear(self)
382 dict.clear(self)
382
383
383 def __setitem__(self, key, value):
384 def __setitem__(self, key, value):
384 if key not in self:
385 if key not in self:
385 end = self.__end
386 end = self.__end
386 curr = end[1]
387 curr = end[1]
387 curr[2] = end[1] = self.__map[key] = [key, curr, end]
388 curr[2] = end[1] = self.__map[key] = [key, curr, end]
388 dict.__setitem__(self, key, value)
389 dict.__setitem__(self, key, value)
389
390
390 def __delitem__(self, key):
391 def __delitem__(self, key):
391 dict.__delitem__(self, key)
392 dict.__delitem__(self, key)
392 key, prev, next = self.__map.pop(key)
393 key, prev, next = self.__map.pop(key)
393 prev[2] = next
394 prev[2] = next
394 next[1] = prev
395 next[1] = prev
395
396
396 def __iter__(self):
397 def __iter__(self):
397 end = self.__end
398 end = self.__end
398 curr = end[2]
399 curr = end[2]
399 while curr is not end:
400 while curr is not end:
400 yield curr[0]
401 yield curr[0]
401 curr = curr[2]
402 curr = curr[2]
402
403
403 def __reversed__(self):
404 def __reversed__(self):
404 end = self.__end
405 end = self.__end
405 curr = end[1]
406 curr = end[1]
406 while curr is not end:
407 while curr is not end:
407 yield curr[0]
408 yield curr[0]
408 curr = curr[1]
409 curr = curr[1]
409
410
410 def popitem(self, last=True):
411 def popitem(self, last=True):
411 if not self:
412 if not self:
412 raise KeyError('dictionary is empty')
413 raise KeyError('dictionary is empty')
413 if last:
414 if last:
414 key = reversed(self).next()
415 key = reversed(self).next()
415 else:
416 else:
416 key = iter(self).next()
417 key = iter(self).next()
417 value = self.pop(key)
418 value = self.pop(key)
418 return key, value
419 return key, value
419
420
420 def __reduce__(self):
421 def __reduce__(self):
421 items = [[k, self[k]] for k in self]
422 items = [[k, self[k]] for k in self]
422 tmp = self.__map, self.__end
423 tmp = self.__map, self.__end
423 del self.__map, self.__end
424 del self.__map, self.__end
424 inst_dict = vars(self).copy()
425 inst_dict = vars(self).copy()
425 self.__map, self.__end = tmp
426 self.__map, self.__end = tmp
426 if inst_dict:
427 if inst_dict:
427 return (self.__class__, (items,), inst_dict)
428 return (self.__class__, (items,), inst_dict)
428 return self.__class__, (items,)
429 return self.__class__, (items,)
429
430
430 def keys(self):
431 def keys(self):
431 return list(self)
432 return list(self)
432
433
433 setdefault = DictMixin.setdefault
434 setdefault = DictMixin.setdefault
434 update = DictMixin.update
435 update = DictMixin.update
435 pop = DictMixin.pop
436 pop = DictMixin.pop
436 values = DictMixin.values
437 values = DictMixin.values
437 items = DictMixin.items
438 items = DictMixin.items
438 iterkeys = DictMixin.iterkeys
439 iterkeys = DictMixin.iterkeys
439 itervalues = DictMixin.itervalues
440 itervalues = DictMixin.itervalues
440 iteritems = DictMixin.iteritems
441 iteritems = DictMixin.iteritems
441
442
442 def __repr__(self):
443 def __repr__(self):
443 if not self:
444 if not self:
444 return '%s()' % (self.__class__.__name__,)
445 return '%s()' % (self.__class__.__name__,)
445 return '%s(%r)' % (self.__class__.__name__, self.items())
446 return '%s(%r)' % (self.__class__.__name__, self.items())
446
447
447 def copy(self):
448 def copy(self):
448 return self.__class__(self)
449 return self.__class__(self)
449
450
450 @classmethod
451 @classmethod
451 def fromkeys(cls, iterable, value=None):
452 def fromkeys(cls, iterable, value=None):
452 d = cls()
453 d = cls()
453 for key in iterable:
454 for key in iterable:
454 d[key] = value
455 d[key] = value
455 return d
456 return d
456
457
457 def __eq__(self, other):
458 def __eq__(self, other):
458 if isinstance(other, OrderedDict):
459 if isinstance(other, OrderedDict):
459 return len(self) == len(other) and self.items() == other.items()
460 return len(self) == len(other) and self.items() == other.items()
460 return dict.__eq__(self, other)
461 return dict.__eq__(self, other)
461
462
462 def __ne__(self, other):
463 def __ne__(self, other):
463 return not self == other
464 return not self == other
464
465
465
466
466 #===============================================================================
467 #===============================================================================
467 # TEST FUNCTIONS AND CREATORS
468 # TEST FUNCTIONS AND CREATORS
468 #===============================================================================
469 #===============================================================================
469 def create_test_index(repo_location, full_index):
470 def create_test_index(repo_location, full_index):
470 """Makes default test index
471 """Makes default test index
471 :param repo_location:
472 :param repo_location:
472 :param full_index:
473 :param full_index:
473 """
474 """
474 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
475 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
475 from rhodecode.lib.pidlock import DaemonLock, LockHeld
476 from rhodecode.lib.pidlock import DaemonLock, LockHeld
476 from rhodecode.lib.indexers import IDX_LOCATION
477 from rhodecode.lib.indexers import IDX_LOCATION
477 import shutil
478 import shutil
478
479
479 if os.path.exists(IDX_LOCATION):
480 if os.path.exists(IDX_LOCATION):
480 shutil.rmtree(IDX_LOCATION)
481 shutil.rmtree(IDX_LOCATION)
481
482
482 try:
483 try:
483 l = DaemonLock()
484 l = DaemonLock()
484 WhooshIndexingDaemon(repo_location=repo_location)\
485 WhooshIndexingDaemon(repo_location=repo_location)\
485 .run(full_index=full_index)
486 .run(full_index=full_index)
486 l.release()
487 l.release()
487 except LockHeld:
488 except LockHeld:
488 pass
489 pass
489
490
490 def create_test_env(repos_test_path, config):
491 def create_test_env(repos_test_path, config):
491 """Makes a fresh database and
492 """Makes a fresh database and
492 install test repository into tmp dir
493 install test repository into tmp dir
493 """
494 """
494 from rhodecode.lib.db_manage import DbManage
495 from rhodecode.lib.db_manage import DbManage
495 import tarfile
496 import tarfile
496 import shutil
497 import shutil
497 from os.path import dirname as dn, join as jn, abspath
498 from os.path import dirname as dn, join as jn, abspath
498
499
499 log = logging.getLogger('TestEnvCreator')
500 log = logging.getLogger('TestEnvCreator')
500 # create logger
501 # create logger
501 log.setLevel(logging.DEBUG)
502 log.setLevel(logging.DEBUG)
502 log.propagate = True
503 log.propagate = True
503 # create console handler and set level to debug
504 # create console handler and set level to debug
504 ch = logging.StreamHandler()
505 ch = logging.StreamHandler()
505 ch.setLevel(logging.DEBUG)
506 ch.setLevel(logging.DEBUG)
506
507
507 # create formatter
508 # create formatter
508 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
509 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
509
510
510 # add formatter to ch
511 # add formatter to ch
511 ch.setFormatter(formatter)
512 ch.setFormatter(formatter)
512
513
513 # add ch to logger
514 # add ch to logger
514 log.addHandler(ch)
515 log.addHandler(ch)
515
516
516 #PART ONE create db
517 #PART ONE create db
517 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
518 dbname = config['sqlalchemy.db1.url'].split('/')[-1]
518 log.debug('making test db %s', dbname)
519 log.debug('making test db %s', dbname)
519
520
520 dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
521 dbmanage = DbManage(log_sql=True, dbname=dbname, root=config['here'],
521 tests=True)
522 tests=True)
522 dbmanage.create_tables(override=True)
523 dbmanage.create_tables(override=True)
523 dbmanage.config_prompt(repos_test_path)
524 dbmanage.config_prompt(repos_test_path)
524 dbmanage.create_default_user()
525 dbmanage.create_default_user()
525 dbmanage.admin_prompt()
526 dbmanage.admin_prompt()
526 dbmanage.create_permissions()
527 dbmanage.create_permissions()
527 dbmanage.populate_default_permissions()
528 dbmanage.populate_default_permissions()
528
529
529 #PART TWO make test repo
530 #PART TWO make test repo
530 log.debug('making test vcs repo')
531 log.debug('making test vcs repo')
531 if os.path.isdir('/tmp/vcs_test'):
532 if os.path.isdir('/tmp/vcs_test'):
532 shutil.rmtree('/tmp/vcs_test')
533 shutil.rmtree('/tmp/vcs_test')
533
534
534 cur_dir = dn(dn(abspath(__file__)))
535 cur_dir = dn(dn(abspath(__file__)))
535 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
536 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test.tar.gz"))
536 tar.extractall('/tmp')
537 tar.extractall('/tmp')
537 tar.close()
538 tar.close()
@@ -1,183 +1,183 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for RhodeCode
3 # Model for RhodeCode
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 9, 2010
21 Created on April 9, 2010
22 Model for RhodeCode
22 Model for RhodeCode
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from beaker.cache import cache_region
25 from beaker.cache import cache_region
26 from mercurial import ui
26 from mercurial import ui
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib.utils import invalidate_cache
28 from rhodecode.lib.utils import invalidate_cache
29 from rhodecode.lib.auth import HasRepoPermissionAny
29 from rhodecode.lib.auth import HasRepoPermissionAny
30 from rhodecode.model import meta
30 from rhodecode.model import meta
31 from rhodecode.model.db import Repository, User
31 from rhodecode.model.db import Repository, User
32 from sqlalchemy.orm import joinedload
32 from sqlalchemy.orm import joinedload
33 from vcs.exceptions import RepositoryError, VCSError
33 from vcs.exceptions import RepositoryError, VCSError
34 import logging
34 import logging
35 import sys
35 import sys
36 import time
36 import time
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40 try:
40 try:
41 from vcs.backends.hg import MercurialRepository
41 from vcs.backends.hg import MercurialRepository
42 from vcs.backends.git import GitRepository
42 from vcs.backends.git import GitRepository
43 except ImportError:
43 except ImportError:
44 sys.stderr.write('You have to import vcs module')
44 sys.stderr.write('You have to import vcs module')
45 raise Exception('Unable to import vcs')
45 raise Exception('Unable to import vcs')
46
46
47 def _get_repos_cached_initial(app_globals, initial):
47 def _get_repos_cached_initial(app_globals, initial):
48 """return cached dict with repos
48 """return cached dict with repos
49 """
49 """
50 g = app_globals
50 g = app_globals
51 return HgModel().repo_scan(g.paths[0][1], g.baseui, initial)
51 return HgModel().repo_scan(g.paths[0][1], g.baseui, initial)
52
52
53 @cache_region('long_term', 'cached_repo_list')
53 @cache_region('long_term', 'cached_repo_list')
54 def _get_repos_cached():
54 def _get_repos_cached():
55 """return cached dict with repos
55 """return cached dict with repos
56 """
56 """
57 log.info('getting all repositories list')
57 log.info('getting all repositories list')
58 from pylons import app_globals as g
58 from pylons import app_globals as g
59 return HgModel().repo_scan(g.paths[0][1], g.baseui)
59 return HgModel().repo_scan(g.paths[0][1], g.baseui)
60
60
61 @cache_region('super_short_term', 'cached_repos_switcher_list')
61 @cache_region('super_short_term', 'cached_repos_switcher_list')
62 def _get_repos_switcher_cached(cached_repo_list):
62 def _get_repos_switcher_cached(cached_repo_list):
63 repos_lst = []
63 repos_lst = []
64 for repo in [x for x in cached_repo_list.values()]:
64 for repo in [x for x in cached_repo_list.values()]:
65 if HasRepoPermissionAny('repository.write', 'repository.read',
65 if HasRepoPermissionAny('repository.write', 'repository.read',
66 'repository.admin')(repo.name, 'main page check'):
66 'repository.admin')(repo.name, 'main page check'):
67 repos_lst.append((repo.name, repo.dbrepo.private,))
67 repos_lst.append((repo.name, repo.dbrepo.private,))
68
68
69 return sorted(repos_lst, key=lambda k:k[0].lower())
69 return sorted(repos_lst, key=lambda k:k[0].lower())
70
70
71 @cache_region('long_term', 'full_changelog')
71 @cache_region('long_term', 'full_changelog')
72 def _full_changelog_cached(repo_name):
72 def _full_changelog_cached(repo_name):
73 log.info('getting full changelog for %s', repo_name)
73 log.info('getting full changelog for %s', repo_name)
74 return list(reversed(list(HgModel().get_repo(repo_name))))
74 return list(reversed(list(HgModel().get_repo(repo_name))))
75
75
76 class HgModel(object):
76 class HgModel(object):
77 """
77 """
78 Mercurial Model
78 Mercurial Model
79 """
79 """
80
80
81 def __init__(self, sa=None):
81 def __init__(self, sa=None):
82 if not sa:
82 if not sa:
83 self.sa = meta.Session()
83 self.sa = meta.Session()
84 else:
84 else:
85 self.sa = sa
85 self.sa = sa
86
86
87 def repo_scan(self, repos_path, baseui, initial=False):
87 def repo_scan(self, repos_path, baseui, initial=False):
88 """
88 """
89 Listing of repositories in given path. This path should not be a
89 Listing of repositories in given path. This path should not be a
90 repository itself. Return a dictionary of repository objects
90 repository itself. Return a dictionary of repository objects
91
91
92 :param repos_path: path to directory containing repositories
92 :param repos_path: path to directory containing repositories
93 :param baseui
93 :param baseui
94 :param initial: initial scann
94 :param initial: initial scann
95 """
95 """
96 log.info('scanning for repositories in %s', repos_path)
96 log.info('scanning for repositories in %s', repos_path)
97
97
98 if not isinstance(baseui, ui.ui):
98 if not isinstance(baseui, ui.ui):
99 baseui = ui.ui()
99 baseui = ui.ui()
100
100
101 from rhodecode.lib.utils import get_repos
101 from rhodecode.lib.utils import get_repos
102 repos = get_repos(repos_path)
102 repos = get_repos(repos_path)
103
103
104
104
105 repos_list = {}
105 repos_list = {}
106 for name, path in repos:
106 for name, path in repos:
107 try:
107 try:
108 #name = name.split('/')[-1]
108 #name = name.split('/')[-1]
109 if repos_list.has_key(name):
109 if repos_list.has_key(name):
110 raise RepositoryError('Duplicate repository name %s found in'
110 raise RepositoryError('Duplicate repository name %s found in'
111 ' %s' % (name, path))
111 ' %s' % (name, path))
112 else:
112 else:
113 if path[0] == 'hg':
113 if path[0] == 'hg':
114 repos_list[name] = MercurialRepository(path[1], baseui=baseui)
114 repos_list[name] = MercurialRepository(path[1], baseui=baseui)
115 repos_list[name].name = name
115 repos_list[name].name = name
116
116
117 if path[0] == 'git':
117 if path[0] == 'git':
118 repos_list[name] = GitRepository(path[1])
118 repos_list[name] = GitRepository(path[1])
119 repos_list[name].name = name
119 repos_list[name].name = name
120
120
121 dbrepo = None
121 dbrepo = None
122 if not initial:
122 if not initial:
123 #for initial scann on application first run we don't
123 #for initial scann on application first run we don't
124 #have db repos yet.
124 #have db repos yet.
125 dbrepo = self.sa.query(Repository)\
125 dbrepo = self.sa.query(Repository)\
126 .options(joinedload(Repository.fork))\
126 .options(joinedload(Repository.fork))\
127 .filter(Repository.repo_name == name)\
127 .filter(Repository.repo_name == name)\
128 .scalar()
128 .scalar()
129
129
130 if dbrepo:
130 if dbrepo:
131 log.info('Adding db instance to cached list')
131 log.info('Adding db instance to cached list')
132 repos_list[name].dbrepo = dbrepo
132 repos_list[name].dbrepo = dbrepo
133 repos_list[name].description = dbrepo.description
133 repos_list[name].description = dbrepo.description
134 if dbrepo.user:
134 if dbrepo.user:
135 repos_list[name].contact = dbrepo.user.full_contact
135 repos_list[name].contact = dbrepo.user.full_contact
136 else:
136 else:
137 repos_list[name].contact = self.sa.query(User)\
137 repos_list[name].contact = self.sa.query(User)\
138 .filter(User.admin == True).first().full_contact
138 .filter(User.admin == True).first().full_contact
139 except OSError:
139 except OSError:
140 continue
140 continue
141
141
142 return repos_list
142 return repos_list
143
143
144 def get_repos(self):
144 def get_repos(self):
145 for name, repo in _get_repos_cached().items():
145 for name, repo in _get_repos_cached().items():
146
146
147 if isinstance(repo, MercurialRepository) and repo._get_hidden():
147 if isinstance(repo, MercurialRepository) and repo._get_hidden():
148 #skip hidden web repository
148 #skip hidden web repository
149 continue
149 continue
150
150
151 last_change = repo.last_change
151 last_change = repo.last_change
152 tip = h.get_changeset_safe(repo, 'tip')
152 tip = h.get_changeset_safe(repo, 'tip')
153
153
154 tmp_d = {}
154 tmp_d = {}
155 tmp_d['name'] = repo.name
155 tmp_d['name'] = repo.name
156 tmp_d['name_sort'] = tmp_d['name'].lower()
156 tmp_d['name_sort'] = tmp_d['name'].lower()
157 tmp_d['description'] = repo.description
157 tmp_d['description'] = repo.description
158 tmp_d['description_sort'] = tmp_d['description']
158 tmp_d['description_sort'] = tmp_d['description']
159 tmp_d['last_change'] = last_change
159 tmp_d['last_change'] = last_change
160 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
160 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
161 tmp_d['tip'] = tip.short_id
161 tmp_d['tip'] = tip.raw_id
162 tmp_d['tip_sort'] = tip.revision
162 tmp_d['tip_sort'] = tip.revision
163 tmp_d['rev'] = tip.revision
163 tmp_d['rev'] = tip.revision
164 tmp_d['contact'] = repo.contact
164 tmp_d['contact'] = repo.contact
165 tmp_d['contact_sort'] = tmp_d['contact']
165 tmp_d['contact_sort'] = tmp_d['contact']
166 tmp_d['repo_archives'] = list(repo._get_archives())
166 tmp_d['repo_archives'] = list(repo._get_archives())
167 tmp_d['last_msg'] = tip.message
167 tmp_d['last_msg'] = tip.message
168 tmp_d['repo'] = repo
168 tmp_d['repo'] = repo
169 yield tmp_d
169 yield tmp_d
170
170
171 def get_repo(self, repo_name):
171 def get_repo(self, repo_name):
172 try:
172 try:
173 repo = _get_repos_cached()[repo_name]
173 repo = _get_repos_cached()[repo_name]
174 return repo
174 return repo
175 except KeyError:
175 except KeyError:
176 #i we're here and we got key errors let's try to invalidate the
176 #i we're here and we got key errors let's try to invalidate the
177 #cahce and try again
177 #cahce and try again
178 invalidate_cache('cached_repo_list')
178 invalidate_cache('cached_repo_list')
179 repo = _get_repos_cached()[repo_name]
179 repo = _get_repos_cached()[repo_name]
180 return repo
180 return repo
181
181
182
182
183
183
@@ -1,2312 +1,2313 b''
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
2 border:0;
2 border:0;
3 outline:0;
3 outline:0;
4 font-size:100%;
4 font-size:100%;
5 vertical-align:baseline;
5 vertical-align:baseline;
6 background:transparent;
6 background:transparent;
7 margin:0;
7 margin:0;
8 padding:0;
8 padding:0;
9 }
9 }
10
10
11 body {
11 body {
12 line-height:1;
12 line-height:1;
13 height:100%;
13 height:100%;
14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
16 font-size:12px;
16 font-size:12px;
17 color:#000;
17 color:#000;
18 margin:0;
18 margin:0;
19 padding:0;
19 padding:0;
20 }
20 }
21
21
22 ol,ul {
22 ol,ul {
23 list-style:none;
23 list-style:none;
24 }
24 }
25
25
26 blockquote,q {
26 blockquote,q {
27 quotes:none;
27 quotes:none;
28 }
28 }
29
29
30 blockquote:before,blockquote:after,q:before,q:after {
30 blockquote:before,blockquote:after,q:before,q:after {
31 content:none;
31 content:none;
32 }
32 }
33
33
34 :focus {
34 :focus {
35 outline:0;
35 outline:0;
36 }
36 }
37
37
38 del {
38 del {
39 text-decoration:line-through;
39 text-decoration:line-through;
40 }
40 }
41
41
42 table {
42 table {
43 border-collapse:collapse;
43 border-collapse:collapse;
44 border-spacing:0;
44 border-spacing:0;
45 }
45 }
46
46
47 html {
47 html {
48 height:100%;
48 height:100%;
49 }
49 }
50
50
51 a {
51 a {
52 color:#003367;
52 color:#003367;
53 text-decoration:none;
53 text-decoration:none;
54 cursor:pointer;
54 cursor:pointer;
55 font-weight:700;
55 font-weight:700;
56 }
56 }
57
57
58 a:hover {
58 a:hover {
59 color:#316293;
59 color:#316293;
60 text-decoration:underline;
60 text-decoration:underline;
61 }
61 }
62
62
63 h1,h2,h3,h4,h5,h6 {
63 h1,h2,h3,h4,h5,h6 {
64 color:#292929;
64 color:#292929;
65 font-weight:700;
65 font-weight:700;
66 }
66 }
67
67
68 h1 {
68 h1 {
69 font-size:22px;
69 font-size:22px;
70 }
70 }
71
71
72 h2 {
72 h2 {
73 font-size:20px;
73 font-size:20px;
74 }
74 }
75
75
76 h3 {
76 h3 {
77 font-size:18px;
77 font-size:18px;
78 }
78 }
79
79
80 h4 {
80 h4 {
81 font-size:16px;
81 font-size:16px;
82 }
82 }
83
83
84 h5 {
84 h5 {
85 font-size:14px;
85 font-size:14px;
86 }
86 }
87
87
88 h6 {
88 h6 {
89 font-size:11px;
89 font-size:11px;
90 }
90 }
91
91
92 ul.circle {
92 ul.circle {
93 list-style-type:circle;
93 list-style-type:circle;
94 }
94 }
95
95
96 ul.disc {
96 ul.disc {
97 list-style-type:disc;
97 list-style-type:disc;
98 }
98 }
99
99
100 ul.square {
100 ul.square {
101 list-style-type:square;
101 list-style-type:square;
102 }
102 }
103
103
104 ol.lower-roman {
104 ol.lower-roman {
105 list-style-type:lower-roman;
105 list-style-type:lower-roman;
106 }
106 }
107
107
108 ol.upper-roman {
108 ol.upper-roman {
109 list-style-type:upper-roman;
109 list-style-type:upper-roman;
110 }
110 }
111
111
112 ol.lower-alpha {
112 ol.lower-alpha {
113 list-style-type:lower-alpha;
113 list-style-type:lower-alpha;
114 }
114 }
115
115
116 ol.upper-alpha {
116 ol.upper-alpha {
117 list-style-type:upper-alpha;
117 list-style-type:upper-alpha;
118 }
118 }
119
119
120 ol.decimal {
120 ol.decimal {
121 list-style-type:decimal;
121 list-style-type:decimal;
122 }
122 }
123
123
124 div.color {
124 div.color {
125 clear:both;
125 clear:both;
126 overflow:hidden;
126 overflow:hidden;
127 position:absolute;
127 position:absolute;
128 background:#FFF;
128 background:#FFF;
129 margin:7px 0 0 60px;
129 margin:7px 0 0 60px;
130 padding:1px 1px 1px 0;
130 padding:1px 1px 1px 0;
131 }
131 }
132
132
133 div.color a {
133 div.color a {
134 width:15px;
134 width:15px;
135 height:15px;
135 height:15px;
136 display:block;
136 display:block;
137 float:left;
137 float:left;
138 margin:0 0 0 1px;
138 margin:0 0 0 1px;
139 padding:0;
139 padding:0;
140 }
140 }
141
141
142 div.options {
142 div.options {
143 clear:both;
143 clear:both;
144 overflow:hidden;
144 overflow:hidden;
145 position:absolute;
145 position:absolute;
146 background:#FFF;
146 background:#FFF;
147 margin:7px 0 0 162px;
147 margin:7px 0 0 162px;
148 padding:0;
148 padding:0;
149 }
149 }
150
150
151 div.options a {
151 div.options a {
152 height:1%;
152 height:1%;
153 display:block;
153 display:block;
154 text-decoration:none;
154 text-decoration:none;
155 margin:0;
155 margin:0;
156 padding:3px 8px;
156 padding:3px 8px;
157 }
157 }
158
158
159 .top-left-rounded-corner {
159 .top-left-rounded-corner {
160 -webkit-border-top-left-radius: 8px;
160 -webkit-border-top-left-radius: 8px;
161 -khtml-border-radius-topleft: 8px;
161 -khtml-border-radius-topleft: 8px;
162 -moz-border-radius-topleft: 8px;
162 -moz-border-radius-topleft: 8px;
163 border-top-left-radius: 8px;
163 border-top-left-radius: 8px;
164 }
164 }
165
165
166 .top-right-rounded-corner {
166 .top-right-rounded-corner {
167 -webkit-border-top-right-radius: 8px;
167 -webkit-border-top-right-radius: 8px;
168 -khtml-border-radius-topright: 8px;
168 -khtml-border-radius-topright: 8px;
169 -moz-border-radius-topright: 8px;
169 -moz-border-radius-topright: 8px;
170 border-top-right-radius: 8px;
170 border-top-right-radius: 8px;
171 }
171 }
172
172
173 .bottom-left-rounded-corner {
173 .bottom-left-rounded-corner {
174 -webkit-border-bottom-left-radius: 8px;
174 -webkit-border-bottom-left-radius: 8px;
175 -khtml-border-radius-bottomleft: 8px;
175 -khtml-border-radius-bottomleft: 8px;
176 -moz-border-radius-bottomleft: 8px;
176 -moz-border-radius-bottomleft: 8px;
177 border-bottom-left-radius: 8px;
177 border-bottom-left-radius: 8px;
178 }
178 }
179
179
180 .bottom-right-rounded-corner {
180 .bottom-right-rounded-corner {
181 -webkit-border-bottom-right-radius: 8px;
181 -webkit-border-bottom-right-radius: 8px;
182 -khtml-border-radius-bottomright: 8px;
182 -khtml-border-radius-bottomright: 8px;
183 -moz-border-radius-bottomright: 8px;
183 -moz-border-radius-bottomright: 8px;
184 border-bottom-right-radius: 8px;
184 border-bottom-right-radius: 8px;
185 }
185 }
186
186
187
187
188 #header {
188 #header {
189 margin:0;
189 margin:0;
190 padding:0 30px;
190 padding:0 30px;
191 }
191 }
192
192
193 #header ul#logged-user li {
193 #header ul#logged-user li {
194 list-style:none;
194 list-style:none;
195 float:left;
195 float:left;
196 border-left:1px solid #bbb;
196 border-left:1px solid #bbb;
197 border-right:1px solid #a5a5a5;
197 border-right:1px solid #a5a5a5;
198 margin:-2px 0 0;
198 margin:-2px 0 0;
199 padding:10px 12px;
199 padding:10px 12px;
200 }
200 }
201
201
202 #header ul#logged-user li.first {
202 #header ul#logged-user li.first {
203 border-left:none;
203 border-left:none;
204 margin:-6px;
204 margin:-6px;
205 }
205 }
206
206
207 #header ul#logged-user li.first div.account {
207 #header ul#logged-user li.first div.account {
208 padding-top:4px;
208 padding-top:4px;
209 float:left;
209 float:left;
210 }
210 }
211
211
212 #header ul#logged-user li.last {
212 #header ul#logged-user li.last {
213 border-right:none;
213 border-right:none;
214 }
214 }
215
215
216 #header ul#logged-user li a {
216 #header ul#logged-user li a {
217 color:#4e4e4e;
217 color:#4e4e4e;
218 font-weight:700;
218 font-weight:700;
219 text-decoration:none;
219 text-decoration:none;
220 }
220 }
221
221
222 #header ul#logged-user li a:hover {
222 #header ul#logged-user li a:hover {
223 color:#376ea6;
223 color:#376ea6;
224 text-decoration:underline;
224 text-decoration:underline;
225 }
225 }
226
226
227 #header ul#logged-user li.highlight a {
227 #header ul#logged-user li.highlight a {
228 color:#fff;
228 color:#fff;
229 }
229 }
230
230
231 #header ul#logged-user li.highlight a:hover {
231 #header ul#logged-user li.highlight a:hover {
232 color:#376ea6;
232 color:#376ea6;
233 }
233 }
234
234
235 #header #header-inner {
235 #header #header-inner {
236 height:40px;
236 height:40px;
237 clear:both;
237 clear:both;
238 position:relative;
238 position:relative;
239 background:#003367 url("../images/header_inner.png") repeat-x;
239 background:#003367 url("../images/header_inner.png") repeat-x;
240 border-bottom:2px solid #fff;
240 border-bottom:2px solid #fff;
241 margin:0;
241 margin:0;
242 padding:0;
242 padding:0;
243 }
243 }
244
244
245 #header #header-inner #home a {
245 #header #header-inner #home a {
246 height:40px;
246 height:40px;
247 width:46px;
247 width:46px;
248 display:block;
248 display:block;
249 background:url("../images/button_home.png");
249 background:url("../images/button_home.png");
250 background-position:0 0;
250 background-position:0 0;
251 margin:0;
251 margin:0;
252 padding:0;
252 padding:0;
253 }
253 }
254
254
255 #header #header-inner #home a:hover {
255 #header #header-inner #home a:hover {
256 background-position:0 -40px;
256 background-position:0 -40px;
257 }
257 }
258
258
259 #header #header-inner #logo h1 {
259 #header #header-inner #logo h1 {
260 color:#FFF;
260 color:#FFF;
261 font-size:14px;
261 font-size:14px;
262 text-transform:uppercase;
262 text-transform:uppercase;
263 margin:13px 0 0 13px;
263 margin:13px 0 0 13px;
264 padding:0;
264 padding:0;
265 }
265 }
266
266
267 #header #header-inner #logo a {
267 #header #header-inner #logo a {
268 color:#fff;
268 color:#fff;
269 text-decoration:none;
269 text-decoration:none;
270 }
270 }
271
271
272 #header #header-inner #logo a:hover {
272 #header #header-inner #logo a:hover {
273 color:#dabf29;
273 color:#dabf29;
274 }
274 }
275
275
276 #header #header-inner #quick,#header #header-inner #quick ul {
276 #header #header-inner #quick,#header #header-inner #quick ul {
277 position:relative;
277 position:relative;
278 float:right;
278 float:right;
279 list-style-type:none;
279 list-style-type:none;
280 list-style-position:outside;
280 list-style-position:outside;
281 margin:10px 5px 0 0;
281 margin:10px 5px 0 0;
282 padding:0;
282 padding:0;
283 }
283 }
284
284
285 #header #header-inner #quick li {
285 #header #header-inner #quick li {
286 position:relative;
286 position:relative;
287 float:left;
287 float:left;
288 margin:0 5px 0 0;
288 margin:0 5px 0 0;
289 padding:0;
289 padding:0;
290 }
290 }
291
291
292 #header #header-inner #quick li a {
292 #header #header-inner #quick li a {
293 top:0;
293 top:0;
294 left:0;
294 left:0;
295 height:1%;
295 height:1%;
296 display:block;
296 display:block;
297 clear:both;
297 clear:both;
298 overflow:hidden;
298 overflow:hidden;
299 color:#FFF;
299 color:#FFF;
300 font-weight:700;
300 font-weight:700;
301 text-decoration:none;
301 text-decoration:none;
302 background:#369 url("../../images/quick_l.png") no-repeat top left;
302 background:#369 url("../../images/quick_l.png") no-repeat top left;
303 padding:0;
303 padding:0;
304 }
304 }
305
305
306 #header #header-inner #quick li span {
306 #header #header-inner #quick li span {
307 top:0;
307 top:0;
308 right:0;
308 right:0;
309 height:1%;
309 height:1%;
310 display:block;
310 display:block;
311 float:left;
311 float:left;
312 background:url("../../images/quick_r.png") no-repeat top right;
312 background:url("../../images/quick_r.png") no-repeat top right;
313 border-left:1px solid #3f6f9f;
313 border-left:1px solid #3f6f9f;
314 margin:0;
314 margin:0;
315 padding:10px 12px 8px 10px;
315 padding:10px 12px 8px 10px;
316 }
316 }
317
317
318 #header #header-inner #quick li span.normal {
318 #header #header-inner #quick li span.normal {
319 border:none;
319 border:none;
320 padding:10px 12px 8px;
320 padding:10px 12px 8px;
321 }
321 }
322
322
323 #header #header-inner #quick li span.icon {
323 #header #header-inner #quick li span.icon {
324 top:0;
324 top:0;
325 left:0;
325 left:0;
326 border-left:none;
326 border-left:none;
327 background:url("../../images/quick_l.png") no-repeat top left;
327 background:url("../../images/quick_l.png") no-repeat top left;
328 border-right:1px solid #2e5c89;
328 border-right:1px solid #2e5c89;
329 padding:8px 8px 4px;
329 padding:8px 8px 4px;
330 }
330 }
331
331
332 #header #header-inner #quick li a:hover {
332 #header #header-inner #quick li a:hover {
333 background:#4e4e4e url("../../images/quick_l_selected.png") no-repeat top left;
333 background:#4e4e4e url("../../images/quick_l_selected.png") no-repeat top left;
334 }
334 }
335
335
336 #header #header-inner #quick li a:hover span {
336 #header #header-inner #quick li a:hover span {
337 border-left:1px solid #545454;
337 border-left:1px solid #545454;
338 background:url("../../images/quick_r_selected.png") no-repeat top right;
338 background:url("../../images/quick_r_selected.png") no-repeat top right;
339 }
339 }
340
340
341 #header #header-inner #quick li a:hover span.icon {
341 #header #header-inner #quick li a:hover span.icon {
342 border-left:none;
342 border-left:none;
343 border-right:1px solid #464646;
343 border-right:1px solid #464646;
344 background:url("../../images/quick_l_selected.png") no-repeat top left;
344 background:url("../../images/quick_l_selected.png") no-repeat top left;
345 }
345 }
346
346
347 #header #header-inner #quick ul {
347 #header #header-inner #quick ul {
348 top:29px;
348 top:29px;
349 right:0;
349 right:0;
350 min-width:200px;
350 min-width:200px;
351 display:none;
351 display:none;
352 position:absolute;
352 position:absolute;
353 background:#FFF;
353 background:#FFF;
354 border:1px solid #666;
354 border:1px solid #666;
355 border-top:1px solid #003367;
355 border-top:1px solid #003367;
356 z-index:100;
356 z-index:100;
357 margin:0;
357 margin:0;
358 padding:0;
358 padding:0;
359 }
359 }
360
360
361 #header #header-inner #quick ul.repo_switcher {
361 #header #header-inner #quick ul.repo_switcher {
362 max-height:275px;
362 max-height:275px;
363 overflow-x:hidden;
363 overflow-x:hidden;
364 overflow-y:auto;
364 overflow-y:auto;
365 }
365 }
366
366
367 #header #header-inner #quick li ul li {
367 #header #header-inner #quick li ul li {
368 border-bottom:1px solid #ddd;
368 border-bottom:1px solid #ddd;
369 }
369 }
370
370
371 #header #header-inner #quick li ul li a {
371 #header #header-inner #quick li ul li a {
372 width:182px;
372 width:182px;
373 height:auto;
373 height:auto;
374 display:block;
374 display:block;
375 float:left;
375 float:left;
376 background:#FFF;
376 background:#FFF;
377 color:#003367;
377 color:#003367;
378 font-weight:400;
378 font-weight:400;
379 margin:0;
379 margin:0;
380 padding:7px 9px;
380 padding:7px 9px;
381 }
381 }
382
382
383 #header #header-inner #quick li ul li a:hover {
383 #header #header-inner #quick li ul li a:hover {
384 color:#000;
384 color:#000;
385 background:#FFF;
385 background:#FFF;
386 }
386 }
387
387
388 #header #header-inner #quick ul ul {
388 #header #header-inner #quick ul ul {
389 top:auto;
389 top:auto;
390 }
390 }
391
391
392 #header #header-inner #quick li ul ul {
392 #header #header-inner #quick li ul ul {
393 right:200px;
393 right:200px;
394 max-height:275px;
394 max-height:275px;
395 overflow:auto;
395 overflow:auto;
396 overflow-x:hidden;
396 overflow-x:hidden;
397 white-space:nowrap;
397 white-space:nowrap;
398 }
398 }
399
399
400 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
400 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
401 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
401 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
402 width:167px;
402 width:167px;
403 margin:0;
403 margin:0;
404 padding:12px 9px 7px 24px;
404 padding:12px 9px 7px 24px;
405 }
405 }
406
406
407 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
407 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
408 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
408 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
409 min-width:167px;
409 min-width:167px;
410 margin:0;
410 margin:0;
411 padding:12px 9px 7px 24px;
411 padding:12px 9px 7px 24px;
412 }
412 }
413
413
414 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
414 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
415 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
415 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
416 min-width:167px;
416 min-width:167px;
417 margin:0;
417 margin:0;
418 padding:12px 9px 7px 24px;
418 padding:12px 9px 7px 24px;
419 }
419 }
420
420
421 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
421 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
422 background:url("../images/icons/folder_edit.png") no-repeat scroll 4px 9px #FFF;
422 background:url("../images/icons/folder_edit.png") no-repeat scroll 4px 9px #FFF;
423 width:167px;
423 width:167px;
424 margin:0;
424 margin:0;
425 padding:12px 9px 7px 24px;
425 padding:12px 9px 7px 24px;
426 }
426 }
427
427
428 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
428 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
429 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
429 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
430 width:167px;
430 width:167px;
431 margin:0;
431 margin:0;
432 padding:12px 9px 7px 24px;
432 padding:12px 9px 7px 24px;
433 }
433 }
434
434
435 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
435 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
436 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
436 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
437 width:167px;
437 width:167px;
438 margin:0;
438 margin:0;
439 padding:12px 9px 7px 24px;
439 padding:12px 9px 7px 24px;
440 }
440 }
441
441
442 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
442 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
443 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
443 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
444 width:167px;
444 width:167px;
445 margin:0;
445 margin:0;
446 padding:12px 9px 7px 24px;
446 padding:12px 9px 7px 24px;
447 }
447 }
448
448
449 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
449 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
450 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
450 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
451 width:167px;
451 width:167px;
452 margin:0;
452 margin:0;
453 padding:12px 9px 7px 24px;
453 padding:12px 9px 7px 24px;
454 }
454 }
455
455
456 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
456 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
457 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
457 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
458 width:167px;
458 width:167px;
459 margin:0;
459 margin:0;
460 padding:12px 9px 7px 24px;
460 padding:12px 9px 7px 24px;
461 }
461 }
462
462
463 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
463 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
464 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
464 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
465 width:167px;
465 width:167px;
466 margin:0;
466 margin:0;
467 padding:12px 9px 7px 24px;
467 padding:12px 9px 7px 24px;
468 }
468 }
469
469
470 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
470 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
471 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
471 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
472 width:167px;
472 width:167px;
473 margin:0;
473 margin:0;
474 padding:12px 9px 7px 24px;
474 padding:12px 9px 7px 24px;
475 }
475 }
476
476
477 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
477 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
478 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
478 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
479 width:167px;
479 width:167px;
480 margin:0;
480 margin:0;
481 padding:12px 9px 7px 24px;
481 padding:12px 9px 7px 24px;
482 }
482 }
483
483
484 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
484 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
485 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
485 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
486 width:167px;
486 width:167px;
487 margin:0;
487 margin:0;
488 padding:12px 9px 7px 24px;
488 padding:12px 9px 7px 24px;
489 }
489 }
490
490
491 #content #left {
491 #content #left {
492 left:0;
492 left:0;
493 width:280px;
493 width:280px;
494 position:absolute;
494 position:absolute;
495 }
495 }
496
496
497 #content #right {
497 #content #right {
498 margin:0 60px 10px 290px;
498 margin:0 60px 10px 290px;
499 }
499 }
500
500
501 #content div.box {
501 #content div.box {
502 clear:both;
502 clear:both;
503 overflow:hidden;
503 overflow:hidden;
504 background:#fff;
504 background:#fff;
505 margin:0 0 10px;
505 margin:0 0 10px;
506 padding:0 0 10px;
506 padding:0 0 10px;
507 }
507 }
508
508
509 #content div.box-left {
509 #content div.box-left {
510 width:49%;
510 width:49%;
511 clear:none;
511 clear:none;
512 float:left;
512 float:left;
513 margin:0 0 10px;
513 margin:0 0 10px;
514 }
514 }
515
515
516 #content div.box-right {
516 #content div.box-right {
517 width:49%;
517 width:49%;
518 clear:none;
518 clear:none;
519 float:right;
519 float:right;
520 margin:0 0 10px;
520 margin:0 0 10px;
521 }
521 }
522
522
523 #content div.box div.title {
523 #content div.box div.title {
524 clear:both;
524 clear:both;
525 overflow:hidden;
525 overflow:hidden;
526 background:#369 url("../images/header_inner.png") repeat-x;
526 background:#369 url("../images/header_inner.png") repeat-x;
527 margin:0 0 20px;
527 margin:0 0 20px;
528 padding:0;
528 padding:0;
529 }
529 }
530
530
531 #content div.box div.title h5 {
531 #content div.box div.title h5 {
532 float:left;
532 float:left;
533 border:none;
533 border:none;
534 color:#fff;
534 color:#fff;
535 text-transform:uppercase;
535 text-transform:uppercase;
536 margin:0;
536 margin:0;
537 padding:11px 0 11px 10px;
537 padding:11px 0 11px 10px;
538 }
538 }
539
539
540 #content div.box div.title ul.links li {
540 #content div.box div.title ul.links li {
541 list-style:none;
541 list-style:none;
542 float:left;
542 float:left;
543 margin:0;
543 margin:0;
544 padding:0;
544 padding:0;
545 }
545 }
546
546
547 #content div.box div.title ul.links li a {
547 #content div.box div.title ul.links li a {
548 height:1%;
548 height:1%;
549 display:block;
549 display:block;
550 float:left;
550 float:left;
551 border-left:1px solid #316293;
551 border-left:1px solid #316293;
552 color:#fff;
552 color:#fff;
553 font-size:11px;
553 font-size:11px;
554 font-weight:700;
554 font-weight:700;
555 text-decoration:none;
555 text-decoration:none;
556 margin:0;
556 margin:0;
557 padding:13px 16px 12px;
557 padding:13px 16px 12px;
558 }
558 }
559
559
560 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
560 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
561 clear:both;
561 clear:both;
562 overflow:hidden;
562 overflow:hidden;
563 border-bottom:1px solid #DDD;
563 border-bottom:1px solid #DDD;
564 margin:10px 20px;
564 margin:10px 20px;
565 padding:0 0 15px;
565 padding:0 0 15px;
566 }
566 }
567
567
568 #content div.box p {
568 #content div.box p {
569 color:#5f5f5f;
569 color:#5f5f5f;
570 font-size:12px;
570 font-size:12px;
571 line-height:150%;
571 line-height:150%;
572 margin:0 24px 10px;
572 margin:0 24px 10px;
573 padding:0;
573 padding:0;
574 }
574 }
575
575
576 #content div.box blockquote {
576 #content div.box blockquote {
577 border-left:4px solid #DDD;
577 border-left:4px solid #DDD;
578 color:#5f5f5f;
578 color:#5f5f5f;
579 font-size:11px;
579 font-size:11px;
580 line-height:150%;
580 line-height:150%;
581 margin:0 34px;
581 margin:0 34px;
582 padding:0 0 0 14px;
582 padding:0 0 0 14px;
583 }
583 }
584
584
585 #content div.box blockquote p {
585 #content div.box blockquote p {
586 margin:10px 0;
586 margin:10px 0;
587 padding:0;
587 padding:0;
588 }
588 }
589
589
590 #content div.box dl {
590 #content div.box dl {
591 margin:10px 24px;
591 margin:10px 24px;
592 }
592 }
593
593
594 #content div.box dt {
594 #content div.box dt {
595 font-size:12px;
595 font-size:12px;
596 margin:0;
596 margin:0;
597 }
597 }
598
598
599 #content div.box dd {
599 #content div.box dd {
600 font-size:12px;
600 font-size:12px;
601 margin:0;
601 margin:0;
602 padding:8px 0 8px 15px;
602 padding:8px 0 8px 15px;
603 }
603 }
604
604
605 #content div.box li {
605 #content div.box li {
606 font-size:12px;
606 font-size:12px;
607 padding:4px 0;
607 padding:4px 0;
608 }
608 }
609
609
610 #content div.box ul.disc,#content div.box ul.circle {
610 #content div.box ul.disc,#content div.box ul.circle {
611 margin:10px 24px 10px 38px;
611 margin:10px 24px 10px 38px;
612 }
612 }
613
613
614 #content div.box ul.square {
614 #content div.box ul.square {
615 margin:10px 24px 10px 40px;
615 margin:10px 24px 10px 40px;
616 }
616 }
617
617
618 #content div.box img.left {
618 #content div.box img.left {
619 border:none;
619 border:none;
620 float:left;
620 float:left;
621 margin:10px 10px 10px 0;
621 margin:10px 10px 10px 0;
622 }
622 }
623
623
624 #content div.box img.right {
624 #content div.box img.right {
625 border:none;
625 border:none;
626 float:right;
626 float:right;
627 margin:10px 0 10px 10px;
627 margin:10px 0 10px 10px;
628 }
628 }
629
629
630 #content div.box div.messages {
630 #content div.box div.messages {
631 clear:both;
631 clear:both;
632 overflow:hidden;
632 overflow:hidden;
633 margin:0 20px;
633 margin:0 20px;
634 padding:0;
634 padding:0;
635 }
635 }
636
636
637 #content div.box div.message {
637 #content div.box div.message {
638 clear:both;
638 clear:both;
639 overflow:hidden;
639 overflow:hidden;
640 margin:0;
640 margin:0;
641 padding:10px 0;
641 padding:10px 0;
642 }
642 }
643
643
644 #content div.box div.message a {
644 #content div.box div.message a {
645 font-weight:400 !important;
645 font-weight:400 !important;
646 }
646 }
647
647
648 #content div.box div.message div.image {
648 #content div.box div.message div.image {
649 float:left;
649 float:left;
650 margin:9px 0 0 5px;
650 margin:9px 0 0 5px;
651 padding:6px;
651 padding:6px;
652 }
652 }
653
653
654 #content div.box div.message div.image img {
654 #content div.box div.message div.image img {
655 vertical-align:middle;
655 vertical-align:middle;
656 margin:0;
656 margin:0;
657 }
657 }
658
658
659 #content div.box div.message div.text {
659 #content div.box div.message div.text {
660 float:left;
660 float:left;
661 margin:0;
661 margin:0;
662 padding:9px 6px;
662 padding:9px 6px;
663 }
663 }
664
664
665 #content div.box div.message div.dismiss a {
665 #content div.box div.message div.dismiss a {
666 height:16px;
666 height:16px;
667 width:16px;
667 width:16px;
668 display:block;
668 display:block;
669 background:url("../images/icons/cross.png") no-repeat;
669 background:url("../images/icons/cross.png") no-repeat;
670 margin:15px 14px 0 0;
670 margin:15px 14px 0 0;
671 padding:0;
671 padding:0;
672 }
672 }
673
673
674 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6 {
674 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6 {
675 border:none;
675 border:none;
676 margin:0;
676 margin:0;
677 padding:0;
677 padding:0;
678 }
678 }
679
679
680 #content div.box div.message div.text span {
680 #content div.box div.message div.text span {
681 height:1%;
681 height:1%;
682 display:block;
682 display:block;
683 margin:0;
683 margin:0;
684 padding:5px 0 0;
684 padding:5px 0 0;
685 }
685 }
686
686
687 #content div.box div.message-error {
687 #content div.box div.message-error {
688 height:1%;
688 height:1%;
689 clear:both;
689 clear:both;
690 overflow:hidden;
690 overflow:hidden;
691 background:#FBE3E4;
691 background:#FBE3E4;
692 border:1px solid #FBC2C4;
692 border:1px solid #FBC2C4;
693 color:#860006;
693 color:#860006;
694 }
694 }
695
695
696 #content div.box div.message-error h6 {
696 #content div.box div.message-error h6 {
697 color:#860006;
697 color:#860006;
698 }
698 }
699
699
700 #content div.box div.message-warning {
700 #content div.box div.message-warning {
701 height:1%;
701 height:1%;
702 clear:both;
702 clear:both;
703 overflow:hidden;
703 overflow:hidden;
704 background:#FFF6BF;
704 background:#FFF6BF;
705 border:1px solid #FFD324;
705 border:1px solid #FFD324;
706 color:#5f5200;
706 color:#5f5200;
707 }
707 }
708
708
709 #content div.box div.message-warning h6 {
709 #content div.box div.message-warning h6 {
710 color:#5f5200;
710 color:#5f5200;
711 }
711 }
712
712
713 #content div.box div.message-notice {
713 #content div.box div.message-notice {
714 height:1%;
714 height:1%;
715 clear:both;
715 clear:both;
716 overflow:hidden;
716 overflow:hidden;
717 background:#8FBDE0;
717 background:#8FBDE0;
718 border:1px solid #6BACDE;
718 border:1px solid #6BACDE;
719 color:#003863;
719 color:#003863;
720 }
720 }
721
721
722 #content div.box div.message-notice h6 {
722 #content div.box div.message-notice h6 {
723 color:#003863;
723 color:#003863;
724 }
724 }
725
725
726 #content div.box div.message-success {
726 #content div.box div.message-success {
727 height:1%;
727 height:1%;
728 clear:both;
728 clear:both;
729 overflow:hidden;
729 overflow:hidden;
730 background:#E6EFC2;
730 background:#E6EFC2;
731 border:1px solid #C6D880;
731 border:1px solid #C6D880;
732 color:#4e6100;
732 color:#4e6100;
733 }
733 }
734
734
735 #content div.box div.message-success h6 {
735 #content div.box div.message-success h6 {
736 color:#4e6100;
736 color:#4e6100;
737 }
737 }
738
738
739 #content div.box div.form div.fields div.field {
739 #content div.box div.form div.fields div.field {
740 height:1%;
740 height:1%;
741 border-bottom:1px solid #DDD;
741 border-bottom:1px solid #DDD;
742 clear:both;
742 clear:both;
743 margin:0;
743 margin:0;
744 padding:10px 0;
744 padding:10px 0;
745 }
745 }
746
746
747 #content div.box div.form div.fields div.field-first {
747 #content div.box div.form div.fields div.field-first {
748 padding:0 0 10px;
748 padding:0 0 10px;
749 }
749 }
750
750
751 #content div.box div.form div.fields div.field-noborder {
751 #content div.box div.form div.fields div.field-noborder {
752 border-bottom:0 !important;
752 border-bottom:0 !important;
753 }
753 }
754
754
755 #content div.box div.form div.fields div.field span.error-message {
755 #content div.box div.form div.fields div.field span.error-message {
756 height:1%;
756 height:1%;
757 display:inline-block;
757 display:inline-block;
758 color:red;
758 color:red;
759 margin:8px 0 0 4px;
759 margin:8px 0 0 4px;
760 padding:0;
760 padding:0;
761 }
761 }
762
762
763 #content div.box div.form div.fields div.field span.success {
763 #content div.box div.form div.fields div.field span.success {
764 height:1%;
764 height:1%;
765 display:block;
765 display:block;
766 color:#316309;
766 color:#316309;
767 margin:8px 0 0;
767 margin:8px 0 0;
768 padding:0;
768 padding:0;
769 }
769 }
770
770
771 #content div.box div.form div.fields div.field div.label {
771 #content div.box div.form div.fields div.field div.label {
772 left:80px;
772 left:80px;
773 width:auto;
773 width:auto;
774 position:absolute;
774 position:absolute;
775 margin:0;
775 margin:0;
776 padding:8px 0 0 5px;
776 padding:8px 0 0 5px;
777 }
777 }
778
778
779 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
779 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
780 clear:both;
780 clear:both;
781 overflow:hidden;
781 overflow:hidden;
782 left:0;
782 left:0;
783 width:auto;
783 width:auto;
784 position:relative;
784 position:relative;
785 margin:0;
785 margin:0;
786 padding:0 0 8px;
786 padding:0 0 8px;
787 }
787 }
788
788
789 #content div.box div.form div.fields div.field div.label-select {
789 #content div.box div.form div.fields div.field div.label-select {
790 padding:2px 0 0 5px;
790 padding:2px 0 0 5px;
791 }
791 }
792
792
793 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
793 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
794 padding:0 0 8px;
794 padding:0 0 8px;
795 }
795 }
796
796
797 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
797 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
798 padding:0 0 8px !important;
798 padding:0 0 8px !important;
799 }
799 }
800
800
801 #content div.box div.form div.fields div.field div.label label {
801 #content div.box div.form div.fields div.field div.label label {
802 color:#393939;
802 color:#393939;
803 font-weight:700;
803 font-weight:700;
804 }
804 }
805
805
806 #content div.box div.form div.fields div.field div.input {
806 #content div.box div.form div.fields div.field div.input {
807 margin:0 0 0 200px;
807 margin:0 0 0 200px;
808 }
808 }
809
809
810 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
810 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
811 clear:both;
811 clear:both;
812 overflow:hidden;
812 overflow:hidden;
813 border-top:1px solid #b3b3b3;
813 border-top:1px solid #b3b3b3;
814 border-left:1px solid #b3b3b3;
814 border-left:1px solid #b3b3b3;
815 border-right:1px solid #eaeaea;
815 border-right:1px solid #eaeaea;
816 border-bottom:1px solid #eaeaea;
816 border-bottom:1px solid #eaeaea;
817 margin:0;
817 margin:0;
818 padding:7px 7px 6px;
818 padding:7px 7px 6px;
819 }
819 }
820
820
821 #content div.box div.form div.fields div.field div.input input {
821 #content div.box div.form div.fields div.field div.input input {
822 background:#FFF;
822 background:#FFF;
823 border-top:1px solid #b3b3b3;
823 border-top:1px solid #b3b3b3;
824 border-left:1px solid #b3b3b3;
824 border-left:1px solid #b3b3b3;
825 border-right:1px solid #eaeaea;
825 border-right:1px solid #eaeaea;
826 border-bottom:1px solid #eaeaea;
826 border-bottom:1px solid #eaeaea;
827 color:#000;
827 color:#000;
828 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
828 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
829 font-size:11px;
829 font-size:11px;
830 margin:0;
830 margin:0;
831 padding:7px 7px 6px;
831 padding:7px 7px 6px;
832 }
832 }
833
833
834 #content div.box-left div.form div.fields div.field div.input input,#content div.box-right div.form div.fields div.field div.input input {
834 #content div.box-left div.form div.fields div.field div.input input,#content div.box-right div.form div.fields div.field div.input input {
835 width:100%;
835 width:100%;
836 border:none;
836 border:none;
837 padding:0;
837 padding:0;
838 }
838 }
839
839
840 #content div.box div.form div.fields div.field div.input input.small {
840 #content div.box div.form div.fields div.field div.input input.small {
841 width:30%;
841 width:30%;
842 }
842 }
843
843
844 #content div.box div.form div.fields div.field div.input input.medium {
844 #content div.box div.form div.fields div.field div.input input.medium {
845 width:55%;
845 width:55%;
846 }
846 }
847
847
848 #content div.box div.form div.fields div.field div.input input.large {
848 #content div.box div.form div.fields div.field div.input input.large {
849 width:85%;
849 width:85%;
850 }
850 }
851
851
852 #content div.box div.form div.fields div.field div.input input.date {
852 #content div.box div.form div.fields div.field div.input input.date {
853 width:177px;
853 width:177px;
854 }
854 }
855
855
856 #content div.box div.form div.fields div.field div.input input.button {
856 #content div.box div.form div.fields div.field div.input input.button {
857 background:#D4D0C8;
857 background:#D4D0C8;
858 border-top:1px solid #FFF;
858 border-top:1px solid #FFF;
859 border-left:1px solid #FFF;
859 border-left:1px solid #FFF;
860 border-right:1px solid #404040;
860 border-right:1px solid #404040;
861 border-bottom:1px solid #404040;
861 border-bottom:1px solid #404040;
862 color:#000;
862 color:#000;
863 margin:0;
863 margin:0;
864 padding:4px 8px;
864 padding:4px 8px;
865 }
865 }
866
866
867 #content div.box div.form div.fields div.field div.input a.ui-input-file {
867 #content div.box div.form div.fields div.field div.input a.ui-input-file {
868 width:28px;
868 width:28px;
869 height:28px;
869 height:28px;
870 display:inline;
870 display:inline;
871 position:absolute;
871 position:absolute;
872 overflow:hidden;
872 overflow:hidden;
873 cursor:pointer;
873 cursor:pointer;
874 background:#e5e3e3 url("../images/button_browse.png") no-repeat;
874 background:#e5e3e3 url("../images/button_browse.png") no-repeat;
875 border:none;
875 border:none;
876 text-decoration:none;
876 text-decoration:none;
877 margin:0 0 0 6px;
877 margin:0 0 0 6px;
878 padding:0;
878 padding:0;
879 }
879 }
880
880
881 #content div.box div.form div.fields div.field div.textarea {
881 #content div.box div.form div.fields div.field div.textarea {
882 border-top:1px solid #b3b3b3;
882 border-top:1px solid #b3b3b3;
883 border-left:1px solid #b3b3b3;
883 border-left:1px solid #b3b3b3;
884 border-right:1px solid #eaeaea;
884 border-right:1px solid #eaeaea;
885 border-bottom:1px solid #eaeaea;
885 border-bottom:1px solid #eaeaea;
886 margin:0 0 0 200px;
886 margin:0 0 0 200px;
887 padding:10px;
887 padding:10px;
888 }
888 }
889
889
890 #content div.box div.form div.fields div.field div.textarea-editor {
890 #content div.box div.form div.fields div.field div.textarea-editor {
891 border:1px solid #ddd;
891 border:1px solid #ddd;
892 padding:0;
892 padding:0;
893 }
893 }
894
894
895 #content div.box div.form div.fields div.field div.textarea textarea {
895 #content div.box div.form div.fields div.field div.textarea textarea {
896 width:100%;
896 width:100%;
897 height:220px;
897 height:220px;
898 overflow:hidden;
898 overflow:hidden;
899 background:#FFF;
899 background:#FFF;
900 color:#000;
900 color:#000;
901 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
901 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
902 font-size:11px;
902 font-size:11px;
903 outline:none;
903 outline:none;
904 border-width:0;
904 border-width:0;
905 margin:0;
905 margin:0;
906 padding:0;
906 padding:0;
907 }
907 }
908
908
909 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea {
909 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea {
910 width:100%;
910 width:100%;
911 height:100px;
911 height:100px;
912 }
912 }
913
913
914 #content div.box div.form div.fields div.field div.textarea table {
914 #content div.box div.form div.fields div.field div.textarea table {
915 width:100%;
915 width:100%;
916 border:none;
916 border:none;
917 margin:0;
917 margin:0;
918 padding:0;
918 padding:0;
919 }
919 }
920
920
921 #content div.box div.form div.fields div.field div.textarea table td {
921 #content div.box div.form div.fields div.field div.textarea table td {
922 background:#DDD;
922 background:#DDD;
923 border:none;
923 border:none;
924 padding:0;
924 padding:0;
925 }
925 }
926
926
927 #content div.box div.form div.fields div.field div.textarea table td table {
927 #content div.box div.form div.fields div.field div.textarea table td table {
928 width:auto;
928 width:auto;
929 border:none;
929 border:none;
930 margin:0;
930 margin:0;
931 padding:0;
931 padding:0;
932 }
932 }
933
933
934 #content div.box div.form div.fields div.field div.textarea table td table td {
934 #content div.box div.form div.fields div.field div.textarea table td table td {
935 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
935 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
936 font-size:11px;
936 font-size:11px;
937 padding:5px 5px 5px 0;
937 padding:5px 5px 5px 0;
938 }
938 }
939
939
940 #content div.box div.form div.fields div.field div.textarea table td table td a.mceButtonActive {
940 #content div.box div.form div.fields div.field div.textarea table td table td a.mceButtonActive {
941 background:#b1b1b1;
941 background:#b1b1b1;
942 }
942 }
943
943
944 #content div.box div.form div.fields div.field div.select a.ui-selectmenu {
944 #content div.box div.form div.fields div.field div.select a.ui-selectmenu {
945 color:#565656;
945 color:#565656;
946 text-decoration:none;
946 text-decoration:none;
947 }
947 }
948
948
949 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
949 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
950 background:#f6f6f6;
950 background:#f6f6f6;
951 border-color:#666;
951 border-color:#666;
952 }
952 }
953
953
954 div.form div.fields div.field div.button {
954 div.form div.fields div.field div.button {
955 margin:0;
955 margin:0;
956 padding:0 0 0 8px;
956 padding:0 0 0 8px;
957 }
957 }
958
958
959 div.form div.fields div.field div.highlight .ui-state-default {
959 div.form div.fields div.field div.highlight .ui-state-default {
960 background:#4e85bb url("../images/button_highlight.png") repeat-x;
960 background:#4e85bb url("../images/button_highlight.png") repeat-x;
961 border-top:1px solid #5c91a4;
961 border-top:1px solid #5c91a4;
962 border-left:1px solid #2a6f89;
962 border-left:1px solid #2a6f89;
963 border-right:1px solid #2b7089;
963 border-right:1px solid #2b7089;
964 border-bottom:1px solid #1a6480;
964 border-bottom:1px solid #1a6480;
965 color:#FFF;
965 color:#FFF;
966 margin:0;
966 margin:0;
967 padding:6px 12px;
967 padding:6px 12px;
968 }
968 }
969
969
970 div.form div.fields div.field div.highlight .ui-state-hover {
970 div.form div.fields div.field div.highlight .ui-state-hover {
971 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
971 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
972 border-top:1px solid #78acbf;
972 border-top:1px solid #78acbf;
973 border-left:1px solid #34819e;
973 border-left:1px solid #34819e;
974 border-right:1px solid #35829f;
974 border-right:1px solid #35829f;
975 border-bottom:1px solid #257897;
975 border-bottom:1px solid #257897;
976 color:#FFF;
976 color:#FFF;
977 margin:0;
977 margin:0;
978 padding:6px 12px;
978 padding:6px 12px;
979 }
979 }
980
980
981 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-default {
981 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-default {
982 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
982 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
983 border-top:1px solid #5c91a4;
983 border-top:1px solid #5c91a4;
984 border-left:1px solid #2a6f89;
984 border-left:1px solid #2a6f89;
985 border-right:1px solid #2b7089;
985 border-right:1px solid #2b7089;
986 border-bottom:1px solid #1a6480;
986 border-bottom:1px solid #1a6480;
987 color:#fff;
987 color:#fff;
988 margin:0;
988 margin:0;
989 padding:6px 12px;
989 padding:6px 12px;
990 }
990 }
991
991
992 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
992 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
993 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
993 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
994 border-top:1px solid #78acbf;
994 border-top:1px solid #78acbf;
995 border-left:1px solid #34819e;
995 border-left:1px solid #34819e;
996 border-right:1px solid #35829f;
996 border-right:1px solid #35829f;
997 border-bottom:1px solid #257897;
997 border-bottom:1px solid #257897;
998 color:#fff;
998 color:#fff;
999 margin:0;
999 margin:0;
1000 padding:6px 12px;
1000 padding:6px 12px;
1001 }
1001 }
1002
1002
1003 #content div.box table {
1003 #content div.box table {
1004 width:100%;
1004 width:100%;
1005 border-collapse:collapse;
1005 border-collapse:collapse;
1006 margin:0;
1006 margin:0;
1007 padding:0;
1007 padding:0;
1008 }
1008 }
1009
1009
1010 #content div.box table th {
1010 #content div.box table th {
1011 background:#eee;
1011 background:#eee;
1012 border-bottom:1px solid #ddd;
1012 border-bottom:1px solid #ddd;
1013 padding:5px 0px 5px 5px;
1013 padding:5px 0px 5px 5px;
1014 }
1014 }
1015
1015
1016 #content div.box table th.left {
1016 #content div.box table th.left {
1017 text-align:left;
1017 text-align:left;
1018 }
1018 }
1019
1019
1020 #content div.box table th.right {
1020 #content div.box table th.right {
1021 text-align:right;
1021 text-align:right;
1022 }
1022 }
1023
1023
1024 #content div.box table th.center {
1024 #content div.box table th.center {
1025 text-align:center;
1025 text-align:center;
1026 }
1026 }
1027
1027
1028 #content div.box table th.selected {
1028 #content div.box table th.selected {
1029 vertical-align:middle;
1029 vertical-align:middle;
1030 padding:0;
1030 padding:0;
1031 }
1031 }
1032
1032
1033 #content div.box table td {
1033 #content div.box table td {
1034 background:#fff;
1034 background:#fff;
1035 border-bottom:1px solid #cdcdcd;
1035 border-bottom:1px solid #cdcdcd;
1036 vertical-align:middle;
1036 vertical-align:middle;
1037 padding:5px;
1037 padding:5px;
1038 }
1038 }
1039
1039
1040 #content div.box table tr.selected td {
1040 #content div.box table tr.selected td {
1041 background:#FFC;
1041 background:#FFC;
1042 }
1042 }
1043
1043
1044 #content div.box table td.selected {
1044 #content div.box table td.selected {
1045 width:3%;
1045 width:3%;
1046 text-align:center;
1046 text-align:center;
1047 vertical-align:middle;
1047 vertical-align:middle;
1048 padding:0;
1048 padding:0;
1049 }
1049 }
1050
1050
1051 #content div.box table td.action {
1051 #content div.box table td.action {
1052 width:45%;
1052 width:45%;
1053 text-align:left;
1053 text-align:left;
1054 }
1054 }
1055
1055
1056 #content div.box table td.date {
1056 #content div.box table td.date {
1057 width:33%;
1057 width:33%;
1058 text-align:center;
1058 text-align:center;
1059 }
1059 }
1060
1060
1061 #content div.box div.action {
1061 #content div.box div.action {
1062 float:right;
1062 float:right;
1063 background:#FFF;
1063 background:#FFF;
1064 text-align:right;
1064 text-align:right;
1065 margin:10px 0 0;
1065 margin:10px 0 0;
1066 padding:0;
1066 padding:0;
1067 }
1067 }
1068
1068
1069 #content div.box div.action select {
1069 #content div.box div.action select {
1070 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1070 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1071 font-size:11px;
1071 font-size:11px;
1072 margin:0;
1072 margin:0;
1073 }
1073 }
1074
1074
1075 #content div.box div.action .ui-selectmenu {
1075 #content div.box div.action .ui-selectmenu {
1076 margin:0;
1076 margin:0;
1077 padding:0;
1077 padding:0;
1078 }
1078 }
1079
1079
1080 #content div.box div.pagination {
1080 #content div.box div.pagination {
1081 height:1%;
1081 height:1%;
1082 clear:both;
1082 clear:both;
1083 overflow:hidden;
1083 overflow:hidden;
1084 margin:10px 0 0;
1084 margin:10px 0 0;
1085 padding:0;
1085 padding:0;
1086 }
1086 }
1087
1087
1088 #content div.box div.pagination ul.pager {
1088 #content div.box div.pagination ul.pager {
1089 float:right;
1089 float:right;
1090 text-align:right;
1090 text-align:right;
1091 margin:0;
1091 margin:0;
1092 padding:0;
1092 padding:0;
1093 }
1093 }
1094
1094
1095 #content div.box div.pagination ul.pager li {
1095 #content div.box div.pagination ul.pager li {
1096 height:1%;
1096 height:1%;
1097 float:left;
1097 float:left;
1098 list-style:none;
1098 list-style:none;
1099 background:#ebebeb url("../images/pager.png") repeat-x;
1099 background:#ebebeb url("../images/pager.png") repeat-x;
1100 border-top:1px solid #dedede;
1100 border-top:1px solid #dedede;
1101 border-left:1px solid #cfcfcf;
1101 border-left:1px solid #cfcfcf;
1102 border-right:1px solid #c4c4c4;
1102 border-right:1px solid #c4c4c4;
1103 border-bottom:1px solid #c4c4c4;
1103 border-bottom:1px solid #c4c4c4;
1104 color:#4A4A4A;
1104 color:#4A4A4A;
1105 font-weight:700;
1105 font-weight:700;
1106 margin:0 0 0 4px;
1106 margin:0 0 0 4px;
1107 padding:0;
1107 padding:0;
1108 }
1108 }
1109
1109
1110 #content div.box div.pagination ul.pager li.separator {
1110 #content div.box div.pagination ul.pager li.separator {
1111 padding:6px;
1111 padding:6px;
1112 }
1112 }
1113
1113
1114 #content div.box div.pagination ul.pager li.current {
1114 #content div.box div.pagination ul.pager li.current {
1115 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1115 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1116 border-top:1px solid #ccc;
1116 border-top:1px solid #ccc;
1117 border-left:1px solid #bebebe;
1117 border-left:1px solid #bebebe;
1118 border-right:1px solid #b1b1b1;
1118 border-right:1px solid #b1b1b1;
1119 border-bottom:1px solid #afafaf;
1119 border-bottom:1px solid #afafaf;
1120 color:#515151;
1120 color:#515151;
1121 padding:6px;
1121 padding:6px;
1122 }
1122 }
1123
1123
1124 #content div.box div.pagination ul.pager li a {
1124 #content div.box div.pagination ul.pager li a {
1125 height:1%;
1125 height:1%;
1126 display:block;
1126 display:block;
1127 float:left;
1127 float:left;
1128 color:#515151;
1128 color:#515151;
1129 text-decoration:none;
1129 text-decoration:none;
1130 margin:0;
1130 margin:0;
1131 padding:6px;
1131 padding:6px;
1132 }
1132 }
1133
1133
1134 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1134 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1135 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1135 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1136 border-top:1px solid #ccc;
1136 border-top:1px solid #ccc;
1137 border-left:1px solid #bebebe;
1137 border-left:1px solid #bebebe;
1138 border-right:1px solid #b1b1b1;
1138 border-right:1px solid #b1b1b1;
1139 border-bottom:1px solid #afafaf;
1139 border-bottom:1px solid #afafaf;
1140 margin:-1px;
1140 margin:-1px;
1141 }
1141 }
1142
1142
1143 #content div.box div.pagination-wh {
1143 #content div.box div.pagination-wh {
1144 height:1%;
1144 height:1%;
1145 clear:both;
1145 clear:both;
1146 overflow:hidden;
1146 overflow:hidden;
1147 text-align:right;
1147 text-align:right;
1148 margin:10px 0 0;
1148 margin:10px 0 0;
1149 padding:0;
1149 padding:0;
1150 }
1150 }
1151
1151
1152 #content div.box div.pagination-right {
1152 #content div.box div.pagination-right {
1153 float:right;
1153 float:right;
1154 }
1154 }
1155
1155
1156 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1156 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1157 height:1%;
1157 height:1%;
1158 float:left;
1158 float:left;
1159 background:#ebebeb url("../images/pager.png") repeat-x;
1159 background:#ebebeb url("../images/pager.png") repeat-x;
1160 border-top:1px solid #dedede;
1160 border-top:1px solid #dedede;
1161 border-left:1px solid #cfcfcf;
1161 border-left:1px solid #cfcfcf;
1162 border-right:1px solid #c4c4c4;
1162 border-right:1px solid #c4c4c4;
1163 border-bottom:1px solid #c4c4c4;
1163 border-bottom:1px solid #c4c4c4;
1164 color:#4A4A4A;
1164 color:#4A4A4A;
1165 font-weight:700;
1165 font-weight:700;
1166 margin:0 0 0 4px;
1166 margin:0 0 0 4px;
1167 padding:6px;
1167 padding:6px;
1168 }
1168 }
1169
1169
1170 #content div.box div.pagination-wh span.pager_curpage {
1170 #content div.box div.pagination-wh span.pager_curpage {
1171 height:1%;
1171 height:1%;
1172 float:left;
1172 float:left;
1173 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1173 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1174 border-top:1px solid #ccc;
1174 border-top:1px solid #ccc;
1175 border-left:1px solid #bebebe;
1175 border-left:1px solid #bebebe;
1176 border-right:1px solid #b1b1b1;
1176 border-right:1px solid #b1b1b1;
1177 border-bottom:1px solid #afafaf;
1177 border-bottom:1px solid #afafaf;
1178 color:#515151;
1178 color:#515151;
1179 font-weight:700;
1179 font-weight:700;
1180 margin:0 0 0 4px;
1180 margin:0 0 0 4px;
1181 padding:6px;
1181 padding:6px;
1182 }
1182 }
1183
1183
1184 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1184 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1185 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1185 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1186 border-top:1px solid #ccc;
1186 border-top:1px solid #ccc;
1187 border-left:1px solid #bebebe;
1187 border-left:1px solid #bebebe;
1188 border-right:1px solid #b1b1b1;
1188 border-right:1px solid #b1b1b1;
1189 border-bottom:1px solid #afafaf;
1189 border-bottom:1px solid #afafaf;
1190 text-decoration:none;
1190 text-decoration:none;
1191 }
1191 }
1192
1192
1193 #content div.box div.traffic div.legend {
1193 #content div.box div.traffic div.legend {
1194 clear:both;
1194 clear:both;
1195 overflow:hidden;
1195 overflow:hidden;
1196 border-bottom:1px solid #ddd;
1196 border-bottom:1px solid #ddd;
1197 margin:0 0 10px;
1197 margin:0 0 10px;
1198 padding:0 0 10px;
1198 padding:0 0 10px;
1199 }
1199 }
1200
1200
1201 #content div.box div.traffic div.legend h6 {
1201 #content div.box div.traffic div.legend h6 {
1202 float:left;
1202 float:left;
1203 border:none;
1203 border:none;
1204 margin:0;
1204 margin:0;
1205 padding:0;
1205 padding:0;
1206 }
1206 }
1207
1207
1208 #content div.box div.traffic div.legend li {
1208 #content div.box div.traffic div.legend li {
1209 list-style:none;
1209 list-style:none;
1210 float:left;
1210 float:left;
1211 font-size:11px;
1211 font-size:11px;
1212 margin:0;
1212 margin:0;
1213 padding:0 8px 0 4px;
1213 padding:0 8px 0 4px;
1214 }
1214 }
1215
1215
1216 #content div.box div.traffic div.legend li.visits {
1216 #content div.box div.traffic div.legend li.visits {
1217 border-left:12px solid #edc240;
1217 border-left:12px solid #edc240;
1218 }
1218 }
1219
1219
1220 #content div.box div.traffic div.legend li.pageviews {
1220 #content div.box div.traffic div.legend li.pageviews {
1221 border-left:12px solid #afd8f8;
1221 border-left:12px solid #afd8f8;
1222 }
1222 }
1223
1223
1224 #content div.box div.traffic table {
1224 #content div.box div.traffic table {
1225 width:auto;
1225 width:auto;
1226 }
1226 }
1227
1227
1228 #content div.box div.traffic table td {
1228 #content div.box div.traffic table td {
1229 background:transparent;
1229 background:transparent;
1230 border:none;
1230 border:none;
1231 padding:2px 3px 3px;
1231 padding:2px 3px 3px;
1232 }
1232 }
1233
1233
1234 #content div.box div.traffic table td.legendLabel {
1234 #content div.box div.traffic table td.legendLabel {
1235 padding:0 3px 2px;
1235 padding:0 3px 2px;
1236 }
1236 }
1237
1237
1238 #footer {
1238 #footer {
1239 clear:both;
1239 clear:both;
1240 overflow:hidden;
1240 overflow:hidden;
1241 text-align:right;
1241 text-align:right;
1242 margin:0;
1242 margin:0;
1243 padding:0 30px 4px;
1243 padding:0 30px 4px;
1244 margin:-10px 0 0;
1244 margin:-10px 0 0;
1245 }
1245 }
1246
1246
1247 #footer div#footer-inner {
1247 #footer div#footer-inner {
1248 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1248 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1249 border-top:2px solid #FFFFFF;
1249 border-top:2px solid #FFFFFF;
1250 }
1250 }
1251
1251
1252 #footer div#footer-inner p {
1252 #footer div#footer-inner p {
1253 padding:15px 25px 15px 0;
1253 padding:15px 25px 15px 0;
1254 color:#FFF;
1254 color:#FFF;
1255 font-weight:700;
1255 font-weight:700;
1256 }
1256 }
1257 #footer div#footer-inner .footer-link {
1257 #footer div#footer-inner .footer-link {
1258 float:left;
1258 float:left;
1259 padding-left:10px;
1259 padding-left:10px;
1260 }
1260 }
1261 #footer div#footer-inner .footer-link a {
1261 #footer div#footer-inner .footer-link a {
1262 color:#FFF;
1262 color:#FFF;
1263 }
1263 }
1264
1264
1265 #login div.title {
1265 #login div.title {
1266 width:420px;
1266 width:420px;
1267 clear:both;
1267 clear:both;
1268 overflow:hidden;
1268 overflow:hidden;
1269 position:relative;
1269 position:relative;
1270 background:#003367 url("../../images/header_inner.png") repeat-x;
1270 background:#003367 url("../../images/header_inner.png") repeat-x;
1271 margin:0 auto;
1271 margin:0 auto;
1272 padding:0;
1272 padding:0;
1273 }
1273 }
1274
1274
1275 #login div.inner {
1275 #login div.inner {
1276 width:380px;
1276 width:380px;
1277 background:#FFF url("../images/login.png") no-repeat top left;
1277 background:#FFF url("../images/login.png") no-repeat top left;
1278 border-top:none;
1278 border-top:none;
1279 border-bottom:none;
1279 border-bottom:none;
1280 margin:0 auto;
1280 margin:0 auto;
1281 padding:20px;
1281 padding:20px;
1282 }
1282 }
1283
1283
1284 #login div.form div.fields div.field div.label {
1284 #login div.form div.fields div.field div.label {
1285 width:173px;
1285 width:173px;
1286 float:left;
1286 float:left;
1287 text-align:right;
1287 text-align:right;
1288 margin:2px 10px 0 0;
1288 margin:2px 10px 0 0;
1289 padding:5px 0 0 5px;
1289 padding:5px 0 0 5px;
1290 }
1290 }
1291
1291
1292 #login div.form div.fields div.field div.input input {
1292 #login div.form div.fields div.field div.input input {
1293 width:176px;
1293 width:176px;
1294 background:#FFF;
1294 background:#FFF;
1295 border-top:1px solid #b3b3b3;
1295 border-top:1px solid #b3b3b3;
1296 border-left:1px solid #b3b3b3;
1296 border-left:1px solid #b3b3b3;
1297 border-right:1px solid #eaeaea;
1297 border-right:1px solid #eaeaea;
1298 border-bottom:1px solid #eaeaea;
1298 border-bottom:1px solid #eaeaea;
1299 color:#000;
1299 color:#000;
1300 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1300 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1301 font-size:11px;
1301 font-size:11px;
1302 margin:0;
1302 margin:0;
1303 padding:7px 7px 6px;
1303 padding:7px 7px 6px;
1304 }
1304 }
1305
1305
1306 #login div.form div.fields div.buttons {
1306 #login div.form div.fields div.buttons {
1307 clear:both;
1307 clear:both;
1308 overflow:hidden;
1308 overflow:hidden;
1309 border-top:1px solid #DDD;
1309 border-top:1px solid #DDD;
1310 text-align:right;
1310 text-align:right;
1311 margin:0;
1311 margin:0;
1312 padding:10px 0 0;
1312 padding:10px 0 0;
1313 }
1313 }
1314
1314
1315 #login div.form div.links {
1315 #login div.form div.links {
1316 clear:both;
1316 clear:both;
1317 overflow:hidden;
1317 overflow:hidden;
1318 margin:10px 0 0;
1318 margin:10px 0 0;
1319 padding:0 0 2px;
1319 padding:0 0 2px;
1320 }
1320 }
1321
1321
1322 #register div.title {
1322 #register div.title {
1323 width:420px;
1323 width:420px;
1324 clear:both;
1324 clear:both;
1325 overflow:hidden;
1325 overflow:hidden;
1326 position:relative;
1326 position:relative;
1327 background:#003367 url("../images/header_inner.png") repeat-x;
1327 background:#003367 url("../images/header_inner.png") repeat-x;
1328 margin:0 auto;
1328 margin:0 auto;
1329 padding:0;
1329 padding:0;
1330 }
1330 }
1331
1331
1332 #register div.inner {
1332 #register div.inner {
1333 width:380px;
1333 width:380px;
1334 background:#FFF;
1334 background:#FFF;
1335 border-top:none;
1335 border-top:none;
1336 border-bottom:none;
1336 border-bottom:none;
1337 margin:0 auto;
1337 margin:0 auto;
1338 padding:20px;
1338 padding:20px;
1339 }
1339 }
1340
1340
1341 #register div.form div.fields div.field div.label {
1341 #register div.form div.fields div.field div.label {
1342 width:100px;
1342 width:100px;
1343 float:left;
1343 float:left;
1344 text-align:right;
1344 text-align:right;
1345 margin:2px 10px 0 0;
1345 margin:2px 10px 0 0;
1346 padding:5px 0 0 5px;
1346 padding:5px 0 0 5px;
1347 }
1347 }
1348
1348
1349 #register div.form div.fields div.field div.input input {
1349 #register div.form div.fields div.field div.input input {
1350 width:245px;
1350 width:245px;
1351 background:#FFF;
1351 background:#FFF;
1352 border-top:1px solid #b3b3b3;
1352 border-top:1px solid #b3b3b3;
1353 border-left:1px solid #b3b3b3;
1353 border-left:1px solid #b3b3b3;
1354 border-right:1px solid #eaeaea;
1354 border-right:1px solid #eaeaea;
1355 border-bottom:1px solid #eaeaea;
1355 border-bottom:1px solid #eaeaea;
1356 color:#000;
1356 color:#000;
1357 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1357 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1358 font-size:11px;
1358 font-size:11px;
1359 margin:0;
1359 margin:0;
1360 padding:7px 7px 6px;
1360 padding:7px 7px 6px;
1361 }
1361 }
1362
1362
1363 #register div.form div.fields div.buttons {
1363 #register div.form div.fields div.buttons {
1364 clear:both;
1364 clear:both;
1365 overflow:hidden;
1365 overflow:hidden;
1366 border-top:1px solid #DDD;
1366 border-top:1px solid #DDD;
1367 text-align:left;
1367 text-align:left;
1368 margin:0;
1368 margin:0;
1369 padding:10px 0 0 114px;
1369 padding:10px 0 0 114px;
1370 }
1370 }
1371
1371
1372 #register div.form div.fields div.buttons div.highlight input.ui-state-default {
1372 #register div.form div.fields div.buttons div.highlight input.ui-state-default {
1373 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1373 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1374 color:#FFF;
1374 color:#FFF;
1375 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1375 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1376 border-style:solid;
1376 border-style:solid;
1377 border-width:1px;
1377 border-width:1px;
1378 }
1378 }
1379
1379
1380 #register div.form div.activation_msg {
1380 #register div.form div.activation_msg {
1381 padding-top:4px;
1381 padding-top:4px;
1382 padding-bottom:4px;
1382 padding-bottom:4px;
1383 }
1383 }
1384
1384
1385 .trending_language_tbl,.trending_language_tbl td {
1385 .trending_language_tbl,.trending_language_tbl td {
1386 border:0 !important;
1386 border:0 !important;
1387 margin:0 !important;
1387 margin:0 !important;
1388 padding:0 !important;
1388 padding:0 !important;
1389 }
1389 }
1390
1390
1391 .trending_language {
1391 .trending_language {
1392 background-color:#003367;
1392 background-color:#003367;
1393 color:#FFF;
1393 color:#FFF;
1394 display:block;
1394 display:block;
1395 min-width:20px;
1395 min-width:20px;
1396 max-width:400px;
1396 max-width:400px;
1397 text-decoration:none;
1397 text-decoration:none;
1398 height:12px;
1398 height:12px;
1399 margin-bottom:4px;
1399 margin-bottom:4px;
1400 margin-left:5px;
1400 margin-left:5px;
1401 white-space:pre;
1401 white-space:pre;
1402 padding:3px;
1402 padding:3px;
1403 }
1403 }
1404
1404
1405 h3.files_location {
1405 h3.files_location {
1406 font-size:1.8em;
1406 font-size:1.8em;
1407 font-weight:700;
1407 font-weight:700;
1408 border-bottom:none !important;
1408 border-bottom:none !important;
1409 margin:10px 0 !important;
1409 margin:10px 0 !important;
1410 }
1410 }
1411
1411
1412 #files_data dl dt {
1412 #files_data dl dt {
1413 float:left;
1413 float:left;
1414 width:115px;
1414 width:115px;
1415 margin:0 !important;
1415 margin:0 !important;
1416 padding:5px;
1416 padding:5px;
1417 }
1417 }
1418
1418
1419 #files_data dl dd {
1419 #files_data dl dd {
1420 margin:0 !important;
1420 margin:0 !important;
1421 padding:5px !important;
1421 padding:5px !important;
1422 }
1422 }
1423
1423
1424 #changeset_content {
1424 #changeset_content {
1425 border:1px solid #CCC;
1425 border:1px solid #CCC;
1426 padding:5px;
1426 padding:5px;
1427 }
1427 }
1428
1428
1429 #changeset_content .container {
1429 #changeset_content .container {
1430 min-height:120px;
1430 min-height:120px;
1431 font-size:1.2em;
1431 font-size:1.2em;
1432 overflow:hidden;
1432 overflow:hidden;
1433 }
1433 }
1434
1434
1435 #changeset_content .container .right {
1435 #changeset_content .container .right {
1436 float:right;
1436 float:right;
1437 width:25%;
1437 width:25%;
1438 text-align:right;
1438 text-align:right;
1439 }
1439 }
1440
1440
1441 #changeset_content .container .left .message {
1441 #changeset_content .container .left .message {
1442 font-style:italic;
1442 font-style:italic;
1443 color:#556CB5;
1443 color:#556CB5;
1444 white-space:pre-wrap;
1444 white-space:pre-wrap;
1445 }
1445 }
1446
1446
1447 .cs_files .cs_added {
1447 .cs_files .cs_added {
1448 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1448 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1449 height:16px;
1449 height:16px;
1450 padding-left:20px;
1450 padding-left:20px;
1451 margin-top:7px;
1451 margin-top:7px;
1452 text-align:left;
1452 text-align:left;
1453 }
1453 }
1454
1454
1455 .cs_files .cs_changed {
1455 .cs_files .cs_changed {
1456 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1456 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1457 height:16px;
1457 height:16px;
1458 padding-left:20px;
1458 padding-left:20px;
1459 margin-top:7px;
1459 margin-top:7px;
1460 text-align:left;
1460 text-align:left;
1461 }
1461 }
1462
1462
1463 .cs_files .cs_removed {
1463 .cs_files .cs_removed {
1464 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1464 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1465 height:16px;
1465 height:16px;
1466 padding-left:20px;
1466 padding-left:20px;
1467 margin-top:7px;
1467 margin-top:7px;
1468 text-align:left;
1468 text-align:left;
1469 }
1469 }
1470
1470
1471 #graph {
1471 #graph {
1472 overflow:hidden;
1472 overflow:hidden;
1473 }
1473 }
1474
1474
1475 #graph_nodes {
1475 #graph_nodes {
1476 width:160px;
1476 width:160px;
1477 float:left;
1477 float:left;
1478 margin-left:-50px;
1478 margin-left:-50px;
1479 margin-top:5px;
1479 margin-top:5px;
1480 }
1480 }
1481
1481
1482 #graph_content {
1482 #graph_content {
1483 width:800px;
1483 width:800px;
1484 float:left;
1484 float:left;
1485 }
1485 }
1486
1486
1487 #graph_content .container_header {
1487 #graph_content .container_header {
1488 border:1px solid #CCC;
1488 border:1px solid #CCC;
1489 padding:10px;
1489 padding:10px;
1490 }
1490 }
1491
1491
1492 #graph_content .container {
1492 #graph_content .container {
1493 border-bottom:1px solid #CCC;
1493 border-bottom:1px solid #CCC;
1494 border-left:1px solid #CCC;
1494 border-left:1px solid #CCC;
1495 border-right:1px solid #CCC;
1495 border-right:1px solid #CCC;
1496 min-height:80px;
1496 min-height:80px;
1497 overflow:hidden;
1497 overflow:hidden;
1498 font-size:1.2em;
1498 font-size:1.2em;
1499 }
1499 }
1500
1500
1501 #graph_content .container .right {
1501 #graph_content .container .right {
1502 float:right;
1502 float:right;
1503 width:28%;
1503 width:28%;
1504 text-align:right;
1504 text-align:right;
1505 padding-bottom:5px;
1505 padding-bottom:5px;
1506 }
1506 }
1507
1507
1508 #graph_content .container .left .date {
1508 #graph_content .container .left .date {
1509 font-weight:700;
1509 font-weight:700;
1510 padding-bottom:5px;
1510 padding-bottom:5px;
1511 }
1511 }
1512
1512
1513 #graph_content .container .left .message {
1513 #graph_content .container .left .message {
1514 font-size:100%;
1514 font-size:100%;
1515 padding-top:3px;
1515 padding-top:3px;
1516 white-space:pre-wrap;
1516 white-space:pre-wrap;
1517 }
1517 }
1518
1518
1519 .right div {
1519 .right div {
1520 clear:both;
1520 clear:both;
1521 }
1521 }
1522
1522
1523 .right .changes .added,.changed,.removed {
1523 .right .changes .added,.changed,.removed {
1524 border:1px solid #DDD;
1524 border:1px solid #DDD;
1525 display:block;
1525 display:block;
1526 float:right;
1526 float:right;
1527 text-align:center;
1527 text-align:center;
1528 min-width:15px;
1528 min-width:15px;
1529 }
1529 }
1530
1530
1531 .right .changes .added {
1531 .right .changes .added {
1532 background:#BFB;
1532 background:#BFB;
1533 }
1533 }
1534
1534
1535 .right .changes .changed {
1535 .right .changes .changed {
1536 background:#FD8;
1536 background:#FD8;
1537 }
1537 }
1538
1538
1539 .right .changes .removed {
1539 .right .changes .removed {
1540 background:#F88;
1540 background:#F88;
1541 }
1541 }
1542
1542
1543 .right .merge {
1543 .right .merge {
1544 vertical-align:top;
1544 vertical-align:top;
1545 font-size:60%;
1545 font-size:60%;
1546 font-weight:700;
1546 font-weight:700;
1547 }
1547 }
1548
1548
1549 .right .parent {
1549 .right .parent {
1550 font-size:90%;
1550 font-size:90%;
1551 font-family:monospace;
1551 font-family:monospace;
1552 }
1552 }
1553
1553
1554 .right .logtags .branchtag {
1554 .right .logtags .branchtag {
1555 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1555 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1556 display:block;
1556 display:block;
1557 padding:8px 16px 0 0;
1557 padding:8px 16px 0 0;
1558 }
1558 }
1559
1559
1560 .right .logtags .tagtag {
1560 .right .logtags .tagtag {
1561 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1561 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1562 display:block;
1562 display:block;
1563 padding:6px 18px 0 0;
1563 padding:6px 18px 0 0;
1564 }
1564 }
1565
1565
1566 div.browserblock {
1566 div.browserblock {
1567 overflow:hidden;
1567 overflow:hidden;
1568 border:1px solid #ccc;
1568 border:1px solid #ccc;
1569 background:#f8f8f8;
1569 background:#f8f8f8;
1570 font-size:100%;
1570 font-size:100%;
1571 line-height:125%;
1571 line-height:125%;
1572 padding:0;
1572 padding:0;
1573 }
1573 }
1574
1574
1575 div.browserblock .browser-header {
1575 div.browserblock .browser-header {
1576 border-bottom:1px solid #CCC;
1576 border-bottom:1px solid #CCC;
1577 background:#FFF;
1577 background:#FFF;
1578 color:blue;
1578 color:blue;
1579 padding:10px 0;
1579 padding:10px 0;
1580 }
1580 }
1581
1581
1582 div.browserblock .browser-header span {
1582 div.browserblock .browser-header span {
1583 margin-left:25px;
1583 margin-left:25px;
1584 font-weight:700;
1584 font-weight:700;
1585 }
1585 }
1586
1586
1587 div.browserblock .browser-body {
1587 div.browserblock .browser-body {
1588 background:#EEE;
1588 background:#EEE;
1589 }
1589 }
1590
1590
1591 table.code-browser {
1591 table.code-browser {
1592 border-collapse:collapse;
1592 border-collapse:collapse;
1593 width:100%;
1593 width:100%;
1594 }
1594 }
1595
1595
1596 table.code-browser tr {
1596 table.code-browser tr {
1597 margin:3px;
1597 margin:3px;
1598 }
1598 }
1599
1599
1600 table.code-browser thead th {
1600 table.code-browser thead th {
1601 background-color:#EEE;
1601 background-color:#EEE;
1602 height:20px;
1602 height:20px;
1603 font-size:1.1em;
1603 font-size:1.1em;
1604 font-weight:700;
1604 font-weight:700;
1605 text-align:left;
1605 text-align:left;
1606 padding-left:10px;
1606 padding-left:10px;
1607 }
1607 }
1608
1608
1609 table.code-browser tbody td {
1609 table.code-browser tbody td {
1610 padding-left:10px;
1610 padding-left:10px;
1611 height:20px;
1611 height:20px;
1612 }
1612 }
1613
1613
1614 table.code-browser .browser-file {
1614 table.code-browser .browser-file {
1615 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1615 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1616 height:16px;
1616 height:16px;
1617 padding-left:20px;
1617 padding-left:20px;
1618 text-align:left;
1618 text-align:left;
1619 }
1619 }
1620
1620
1621 table.code-browser .browser-dir {
1621 table.code-browser .browser-dir {
1622 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1622 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1623 height:16px;
1623 height:16px;
1624 padding-left:20px;
1624 padding-left:20px;
1625 text-align:left;
1625 text-align:left;
1626 }
1626 }
1627
1627
1628 .box .search {
1628 .box .search {
1629 clear:both;
1629 clear:both;
1630 overflow:hidden;
1630 overflow:hidden;
1631 margin:0;
1631 margin:0;
1632 padding:0 20px 10px;
1632 padding:0 20px 10px;
1633 }
1633 }
1634
1634
1635 .box .search div.search_path {
1635 .box .search div.search_path {
1636 background:none repeat scroll 0 0 #EEE;
1636 background:none repeat scroll 0 0 #EEE;
1637 border:1px solid #CCC;
1637 border:1px solid #CCC;
1638 color:blue;
1638 color:blue;
1639 margin-bottom:10px;
1639 margin-bottom:10px;
1640 padding:10px 0;
1640 padding:10px 0;
1641 }
1641 }
1642
1642
1643 .box .search div.search_path div.link {
1643 .box .search div.search_path div.link {
1644 font-weight:700;
1644 font-weight:700;
1645 margin-left:25px;
1645 margin-left:25px;
1646 }
1646 }
1647
1647
1648 .box .search div.search_path div.link a {
1648 .box .search div.search_path div.link a {
1649 color:#003367;
1649 color:#003367;
1650 cursor:pointer;
1650 cursor:pointer;
1651 text-decoration:none;
1651 text-decoration:none;
1652 }
1652 }
1653
1653
1654 #path_unlock {
1654 #path_unlock {
1655 color:red;
1655 color:red;
1656 font-size:1.2em;
1656 font-size:1.2em;
1657 padding-left:4px;
1657 padding-left:4px;
1658 }
1658 }
1659
1659
1660 .info_box * {
1660 .info_box * {
1661 background:url("../../images/pager.png") repeat-x scroll 0 0 #EBEBEB;
1661 background:url("../../images/pager.png") repeat-x scroll 0 0 #EBEBEB;
1662 color:#4A4A4A;
1662 color:#4A4A4A;
1663 font-weight:700;
1663 font-weight:700;
1664 height:1%;
1664 height:1%;
1665 display:inline;
1665 display:inline;
1666 border-color:#DEDEDE #C4C4C4 #C4C4C4 #CFCFCF;
1666 border-color:#DEDEDE #C4C4C4 #C4C4C4 #CFCFCF;
1667 border-style:solid;
1667 border-style:solid;
1668 border-width:1px;
1668 border-width:1px;
1669 padding:4px 6px;
1669 padding:4px 6px;
1670 }
1670 }
1671
1671
1672 .info_box span {
1672 .info_box span {
1673 margin-left:3px;
1673 margin-left:3px;
1674 margin-right:3px;
1674 margin-right:3px;
1675 }
1675 }
1676
1676
1677 .info_box input#at_rev {
1677 .info_box input#at_rev {
1678 text-align:center;
1678 text-align:center;
1679 padding:5px 3px 3px 2px;
1679 padding:5px 3px 3px 2px;
1680 }
1680 }
1681
1681
1682 .info_box input#view {
1682 .info_box input#view {
1683 text-align:center;
1683 text-align:center;
1684 padding:4px 3px 2px 2px;
1684 padding:4px 3px 2px 2px;
1685 }
1685 }
1686
1686
1687 .yui-overlay,.yui-panel-container {
1687 .yui-overlay,.yui-panel-container {
1688 visibility:hidden;
1688 visibility:hidden;
1689 position:absolute;
1689 position:absolute;
1690 z-index:2;
1690 z-index:2;
1691 }
1691 }
1692
1692
1693 .yui-tt {
1693 .yui-tt {
1694 visibility:hidden;
1694 visibility:hidden;
1695 position:absolute;
1695 position:absolute;
1696 color:#666;
1696 color:#666;
1697 background-color:#FFF;
1697 background-color:#FFF;
1698 font-family:arial, helvetica, verdana, sans-serif;
1698 font-family:arial, helvetica, verdana, sans-serif;
1699 border:2px solid #003367;
1699 border:2px solid #003367;
1700 font:100% sans-serif;
1700 font:100% sans-serif;
1701 width:auto;
1701 width:auto;
1702 opacity:1px;
1702 opacity:1px;
1703 padding:8px;
1703 padding:8px;
1704 white-space: pre;
1704 }
1705 }
1705
1706
1706 .ac {
1707 .ac {
1707 vertical-align:top;
1708 vertical-align:top;
1708 }
1709 }
1709
1710
1710 .ac .yui-ac {
1711 .ac .yui-ac {
1711 position:relative;
1712 position:relative;
1712 font-family:arial;
1713 font-family:arial;
1713 font-size:100%;
1714 font-size:100%;
1714 }
1715 }
1715
1716
1716 .ac .perm_ac {
1717 .ac .perm_ac {
1717 width:15em;
1718 width:15em;
1718 }
1719 }
1719
1720
1720 .ac .yui-ac-input {
1721 .ac .yui-ac-input {
1721 width:100%;
1722 width:100%;
1722 }
1723 }
1723
1724
1724 .ac .yui-ac-container {
1725 .ac .yui-ac-container {
1725 position:absolute;
1726 position:absolute;
1726 top:1.6em;
1727 top:1.6em;
1727 width:100%;
1728 width:100%;
1728 }
1729 }
1729
1730
1730 .ac .yui-ac-content {
1731 .ac .yui-ac-content {
1731 position:absolute;
1732 position:absolute;
1732 width:100%;
1733 width:100%;
1733 border:1px solid gray;
1734 border:1px solid gray;
1734 background:#fff;
1735 background:#fff;
1735 overflow:hidden;
1736 overflow:hidden;
1736 z-index:9050;
1737 z-index:9050;
1737 }
1738 }
1738
1739
1739 .ac .yui-ac-shadow {
1740 .ac .yui-ac-shadow {
1740 position:absolute;
1741 position:absolute;
1741 width:100%;
1742 width:100%;
1742 background:#000;
1743 background:#000;
1743 -moz-opacity:0.1px;
1744 -moz-opacity:0.1px;
1744 opacity:.10;
1745 opacity:.10;
1745 filter:alpha(opacity = 10);
1746 filter:alpha(opacity = 10);
1746 z-index:9049;
1747 z-index:9049;
1747 margin:.3em;
1748 margin:.3em;
1748 }
1749 }
1749
1750
1750 .ac .yui-ac-content ul {
1751 .ac .yui-ac-content ul {
1751 width:100%;
1752 width:100%;
1752 margin:0;
1753 margin:0;
1753 padding:0;
1754 padding:0;
1754 }
1755 }
1755
1756
1756 .ac .yui-ac-content li {
1757 .ac .yui-ac-content li {
1757 cursor:default;
1758 cursor:default;
1758 white-space:nowrap;
1759 white-space:nowrap;
1759 margin:0;
1760 margin:0;
1760 padding:2px 5px;
1761 padding:2px 5px;
1761 }
1762 }
1762
1763
1763 .ac .yui-ac-content li.yui-ac-prehighlight {
1764 .ac .yui-ac-content li.yui-ac-prehighlight {
1764 background:#B3D4FF;
1765 background:#B3D4FF;
1765 }
1766 }
1766
1767
1767 .ac .yui-ac-content li.yui-ac-highlight {
1768 .ac .yui-ac-content li.yui-ac-highlight {
1768 background:#556CB5;
1769 background:#556CB5;
1769 color:#FFF;
1770 color:#FFF;
1770 }
1771 }
1771
1772
1772 .add_icon {
1773 .add_icon {
1773 background:url("../images/icons/add.png") no-repeat scroll 3px;
1774 background:url("../images/icons/add.png") no-repeat scroll 3px;
1774 height:16px;
1775 height:16px;
1775 padding-left:20px;
1776 padding-left:20px;
1776 padding-top:1px;
1777 padding-top:1px;
1777 text-align:left;
1778 text-align:left;
1778 }
1779 }
1779
1780
1780 .edit_icon {
1781 .edit_icon {
1781 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
1782 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
1782 height:16px;
1783 height:16px;
1783 padding-left:20px;
1784 padding-left:20px;
1784 padding-top:1px;
1785 padding-top:1px;
1785 text-align:left;
1786 text-align:left;
1786 }
1787 }
1787
1788
1788 .delete_icon {
1789 .delete_icon {
1789 background:url("../images/icons/delete.png") no-repeat scroll 3px;
1790 background:url("../images/icons/delete.png") no-repeat scroll 3px;
1790 height:16px;
1791 height:16px;
1791 padding-left:20px;
1792 padding-left:20px;
1792 padding-top:1px;
1793 padding-top:1px;
1793 text-align:left;
1794 text-align:left;
1794 }
1795 }
1795
1796
1796 .rss_icon {
1797 .rss_icon {
1797 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
1798 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
1798 height:16px;
1799 height:16px;
1799 padding-left:20px;
1800 padding-left:20px;
1800 padding-top:1px;
1801 padding-top:1px;
1801 text-align:left;
1802 text-align:left;
1802 }
1803 }
1803
1804
1804 .atom_icon {
1805 .atom_icon {
1805 background:url("../images/icons/atom.png") no-repeat scroll 3px;
1806 background:url("../images/icons/atom.png") no-repeat scroll 3px;
1806 height:16px;
1807 height:16px;
1807 padding-left:20px;
1808 padding-left:20px;
1808 padding-top:1px;
1809 padding-top:1px;
1809 text-align:left;
1810 text-align:left;
1810 }
1811 }
1811
1812
1812 .archive_icon {
1813 .archive_icon {
1813 background:url("../images/icons/compress.png") no-repeat scroll 3px;
1814 background:url("../images/icons/compress.png") no-repeat scroll 3px;
1814 height:16px;
1815 height:16px;
1815 padding-left:20px;
1816 padding-left:20px;
1816 text-align:left;
1817 text-align:left;
1817 padding-top:1px;
1818 padding-top:1px;
1818 }
1819 }
1819
1820
1820 .action_button {
1821 .action_button {
1821 border:0;
1822 border:0;
1822 display:block;
1823 display:block;
1823 }
1824 }
1824
1825
1825 .action_button:hover {
1826 .action_button:hover {
1826 border:0;
1827 border:0;
1827 text-decoration:underline;
1828 text-decoration:underline;
1828 cursor:pointer;
1829 cursor:pointer;
1829 }
1830 }
1830
1831
1831 #switch_repos {
1832 #switch_repos {
1832 position:absolute;
1833 position:absolute;
1833 height:25px;
1834 height:25px;
1834 z-index:1;
1835 z-index:1;
1835 }
1836 }
1836
1837
1837 #switch_repos select {
1838 #switch_repos select {
1838 min-width:150px;
1839 min-width:150px;
1839 max-height:250px;
1840 max-height:250px;
1840 z-index:1;
1841 z-index:1;
1841 }
1842 }
1842
1843
1843 .breadcrumbs {
1844 .breadcrumbs {
1844 border:medium none;
1845 border:medium none;
1845 color:#FFF;
1846 color:#FFF;
1846 float:left;
1847 float:left;
1847 text-transform:uppercase;
1848 text-transform:uppercase;
1848 font-weight:700;
1849 font-weight:700;
1849 font-size:14px;
1850 font-size:14px;
1850 margin:0;
1851 margin:0;
1851 padding:11px 0 11px 10px;
1852 padding:11px 0 11px 10px;
1852 }
1853 }
1853
1854
1854 .breadcrumbs a {
1855 .breadcrumbs a {
1855 color:#FFF;
1856 color:#FFF;
1856 }
1857 }
1857
1858
1858 .flash_msg ul {
1859 .flash_msg ul {
1859 margin:0;
1860 margin:0;
1860 padding:0 0 10px;
1861 padding:0 0 10px;
1861 }
1862 }
1862
1863
1863 .error_msg {
1864 .error_msg {
1864 background-color:#FFCFCF;
1865 background-color:#FFCFCF;
1865 background-image:url("../../images/icons/error_msg.png");
1866 background-image:url("../../images/icons/error_msg.png");
1866 border:1px solid #FF9595;
1867 border:1px solid #FF9595;
1867 color:#C30;
1868 color:#C30;
1868 }
1869 }
1869
1870
1870 .warning_msg {
1871 .warning_msg {
1871 background-color:#FFFBCC;
1872 background-color:#FFFBCC;
1872 background-image:url("../../images/icons/warning_msg.png");
1873 background-image:url("../../images/icons/warning_msg.png");
1873 border:1px solid #FFF35E;
1874 border:1px solid #FFF35E;
1874 color:#C69E00;
1875 color:#C69E00;
1875 }
1876 }
1876
1877
1877 .success_msg {
1878 .success_msg {
1878 background-color:#D5FFCF;
1879 background-color:#D5FFCF;
1879 background-image:url("../../images/icons/success_msg.png");
1880 background-image:url("../../images/icons/success_msg.png");
1880 border:1px solid #97FF88;
1881 border:1px solid #97FF88;
1881 color:#090;
1882 color:#090;
1882 }
1883 }
1883
1884
1884 .notice_msg {
1885 .notice_msg {
1885 background-color:#DCE3FF;
1886 background-color:#DCE3FF;
1886 background-image:url("../../images/icons/notice_msg.png");
1887 background-image:url("../../images/icons/notice_msg.png");
1887 border:1px solid #93A8FF;
1888 border:1px solid #93A8FF;
1888 color:#556CB5;
1889 color:#556CB5;
1889 }
1890 }
1890
1891
1891 .success_msg,.error_msg,.notice_msg,.warning_msg {
1892 .success_msg,.error_msg,.notice_msg,.warning_msg {
1892 background-position:10px center;
1893 background-position:10px center;
1893 background-repeat:no-repeat;
1894 background-repeat:no-repeat;
1894 font-size:12px;
1895 font-size:12px;
1895 font-weight:700;
1896 font-weight:700;
1896 min-height:14px;
1897 min-height:14px;
1897 line-height:14px;
1898 line-height:14px;
1898 margin-bottom:0;
1899 margin-bottom:0;
1899 margin-top:0;
1900 margin-top:0;
1900 display:block;
1901 display:block;
1901 overflow:auto;
1902 overflow:auto;
1902 padding:6px 10px 6px 40px;
1903 padding:6px 10px 6px 40px;
1903 }
1904 }
1904
1905
1905 #msg_close {
1906 #msg_close {
1906 background:transparent url("../../icons/cross_grey_small.png") no-repeat scroll 0 0;
1907 background:transparent url("../../icons/cross_grey_small.png") no-repeat scroll 0 0;
1907 cursor:pointer;
1908 cursor:pointer;
1908 height:16px;
1909 height:16px;
1909 position:absolute;
1910 position:absolute;
1910 right:5px;
1911 right:5px;
1911 top:5px;
1912 top:5px;
1912 width:16px;
1913 width:16px;
1913 }
1914 }
1914
1915
1915 div#legend_container table,div#legend_choices table {
1916 div#legend_container table,div#legend_choices table {
1916 width:auto !important;
1917 width:auto !important;
1917 }
1918 }
1918
1919
1919 table#permissions_manage {
1920 table#permissions_manage {
1920 width:0 !important;
1921 width:0 !important;
1921 }
1922 }
1922
1923
1923 table#permissions_manage span.private_repo_msg {
1924 table#permissions_manage span.private_repo_msg {
1924 font-size:0.8em;
1925 font-size:0.8em;
1925 opacity:0.6px;
1926 opacity:0.6px;
1926 }
1927 }
1927
1928
1928 table#permissions_manage td.private_repo_msg {
1929 table#permissions_manage td.private_repo_msg {
1929 font-size:0.8em;
1930 font-size:0.8em;
1930 }
1931 }
1931
1932
1932 table#permissions_manage tr#add_perm_input td {
1933 table#permissions_manage tr#add_perm_input td {
1933 vertical-align:middle;
1934 vertical-align:middle;
1934 }
1935 }
1935
1936
1936 div.gravatar {
1937 div.gravatar {
1937 background-color:#FFF;
1938 background-color:#FFF;
1938 border:1px solid #D0D0D0;
1939 border:1px solid #D0D0D0;
1939 float:left;
1940 float:left;
1940 margin-right:0.7em;
1941 margin-right:0.7em;
1941 padding:2px 2px 0;
1942 padding:2px 2px 0;
1942 }
1943 }
1943
1944
1944 #header,#content,#footer {
1945 #header,#content,#footer {
1945 min-width:1224px;
1946 min-width:1224px;
1946 }
1947 }
1947
1948
1948 #content {
1949 #content {
1949 min-height:100%;
1950 min-height:100%;
1950 clear:both;
1951 clear:both;
1951 overflow:hidden;
1952 overflow:hidden;
1952 padding:14px 30px;
1953 padding:14px 30px;
1953 }
1954 }
1954
1955
1955 #content div.box div.title div.search {
1956 #content div.box div.title div.search {
1956 background:url("../../images/title_link.png") no-repeat top left;
1957 background:url("../../images/title_link.png") no-repeat top left;
1957 border-left:1px solid #316293;
1958 border-left:1px solid #316293;
1958 }
1959 }
1959
1960
1960 #content div.box div.title div.search div.input input {
1961 #content div.box div.title div.search div.input input {
1961 border:1px solid #316293;
1962 border:1px solid #316293;
1962 }
1963 }
1963
1964
1964 #content div.box div.title div.search div.button input.ui-state-default {
1965 #content div.box div.title div.search div.button input.ui-state-default {
1965 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
1966 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
1966 border:1px solid #316293;
1967 border:1px solid #316293;
1967 border-left:none;
1968 border-left:none;
1968 color:#FFF;
1969 color:#FFF;
1969 }
1970 }
1970
1971
1971 #content div.box div.title div.search div.button input.ui-state-hover {
1972 #content div.box div.title div.search div.button input.ui-state-hover {
1972 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
1973 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
1973 border:1px solid #316293;
1974 border:1px solid #316293;
1974 border-left:none;
1975 border-left:none;
1975 color:#FFF;
1976 color:#FFF;
1976 }
1977 }
1977
1978
1978 #content div.box div.form div.fields div.field div.highlight .ui-state-default {
1979 #content div.box div.form div.fields div.field div.highlight .ui-state-default {
1979 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
1980 background:#4e85bb url("../../images/button_highlight.png") repeat-x;
1980 border-top:1px solid #5c91a4;
1981 border-top:1px solid #5c91a4;
1981 border-left:1px solid #2a6f89;
1982 border-left:1px solid #2a6f89;
1982 border-right:1px solid #2b7089;
1983 border-right:1px solid #2b7089;
1983 border-bottom:1px solid #1a6480;
1984 border-bottom:1px solid #1a6480;
1984 color:#fff;
1985 color:#fff;
1985 }
1986 }
1986
1987
1987 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
1988 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
1988 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
1989 background:#46a0c1 url("../../images/button_highlight_selected.png") repeat-x;
1989 border-top:1px solid #78acbf;
1990 border-top:1px solid #78acbf;
1990 border-left:1px solid #34819e;
1991 border-left:1px solid #34819e;
1991 border-right:1px solid #35829f;
1992 border-right:1px solid #35829f;
1992 border-bottom:1px solid #257897;
1993 border-bottom:1px solid #257897;
1993 color:#fff;
1994 color:#fff;
1994 }
1995 }
1995
1996
1996 ins,div.options a:hover {
1997 ins,div.options a:hover {
1997 text-decoration:none;
1998 text-decoration:none;
1998 }
1999 }
1999
2000
2000 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2001 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2001 border:none;
2002 border:none;
2002 }
2003 }
2003
2004
2004 img.icon,.right .merge img {
2005 img.icon,.right .merge img {
2005 vertical-align:bottom;
2006 vertical-align:bottom;
2006 }
2007 }
2007
2008
2008 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2009 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2009 float:right;
2010 float:right;
2010 margin:0;
2011 margin:0;
2011 padding:0;
2012 padding:0;
2012 }
2013 }
2013
2014
2014 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2015 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2015 float:left;
2016 float:left;
2016 }
2017 }
2017
2018
2018 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2019 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2019 display:none;
2020 display:none;
2020 }
2021 }
2021
2022
2022 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded {
2023 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded {
2023 display:block;
2024 display:block;
2024 }
2025 }
2025
2026
2026 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2027 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2027 background:url("../../images/title_tab_selected.png") no-repeat bottom center;
2028 background:url("../../images/title_tab_selected.png") no-repeat bottom center;
2028 color:#bfe3ff;
2029 color:#bfe3ff;
2029 }
2030 }
2030
2031
2031 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal {
2032 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal {
2032 margin:10px 24px 10px 44px;
2033 margin:10px 24px 10px 44px;
2033 }
2034 }
2034
2035
2035 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2036 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2036 clear:both;
2037 clear:both;
2037 overflow:hidden;
2038 overflow:hidden;
2038 margin:0;
2039 margin:0;
2039 padding:0 20px 10px;
2040 padding:0 20px 10px;
2040 }
2041 }
2041
2042
2042 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2043 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2043 clear:both;
2044 clear:both;
2044 overflow:hidden;
2045 overflow:hidden;
2045 margin:0;
2046 margin:0;
2046 padding:0;
2047 padding:0;
2047 }
2048 }
2048
2049
2049 #content div.box div.form div.fields div.field div.label-checkbox,#content div.box div.form div.fields div.field div.label-radio,#content div.box div.form div.fields div.field div.label-textarea {
2050 #content div.box div.form div.fields div.field div.label-checkbox,#content div.box div.form div.fields div.field div.label-radio,#content div.box div.form div.fields div.field div.label-textarea {
2050 padding:0 0 0 5px !important;
2051 padding:0 0 0 5px !important;
2051 }
2052 }
2052
2053
2053 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span {
2054 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span {
2054 height:1%;
2055 height:1%;
2055 display:block;
2056 display:block;
2056 color:#363636;
2057 color:#363636;
2057 margin:0;
2058 margin:0;
2058 padding:2px 0 0;
2059 padding:2px 0 0;
2059 }
2060 }
2060
2061
2061 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error {
2062 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error {
2062 background:#FBE3E4;
2063 background:#FBE3E4;
2063 border-top:1px solid #e1b2b3;
2064 border-top:1px solid #e1b2b3;
2064 border-left:1px solid #e1b2b3;
2065 border-left:1px solid #e1b2b3;
2065 border-right:1px solid #FBC2C4;
2066 border-right:1px solid #FBC2C4;
2066 border-bottom:1px solid #FBC2C4;
2067 border-bottom:1px solid #FBC2C4;
2067 }
2068 }
2068
2069
2069 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success {
2070 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success {
2070 background:#E6EFC2;
2071 background:#E6EFC2;
2071 border-top:1px solid #cebb98;
2072 border-top:1px solid #cebb98;
2072 border-left:1px solid #cebb98;
2073 border-left:1px solid #cebb98;
2073 border-right:1px solid #c6d880;
2074 border-right:1px solid #c6d880;
2074 border-bottom:1px solid #c6d880;
2075 border-bottom:1px solid #c6d880;
2075 }
2076 }
2076
2077
2077 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input {
2078 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input {
2078 margin:0;
2079 margin:0;
2079 }
2080 }
2080
2081
2081 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios {
2082 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios {
2082 margin:0 0 0 200px;
2083 margin:0 0 0 200px;
2083 padding:0;
2084 padding:0;
2084 }
2085 }
2085
2086
2086 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover {
2087 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover {
2087 color:#000;
2088 color:#000;
2088 text-decoration:none;
2089 text-decoration:none;
2089 }
2090 }
2090
2091
2091 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2092 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2092 border:1px solid #666;
2093 border:1px solid #666;
2093 }
2094 }
2094
2095
2095 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio {
2096 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio {
2096 clear:both;
2097 clear:both;
2097 overflow:hidden;
2098 overflow:hidden;
2098 margin:0;
2099 margin:0;
2099 padding:2px 0;
2100 padding:2px 0;
2100 }
2101 }
2101
2102
2102 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input {
2103 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input {
2103 float:left;
2104 float:left;
2104 margin:0;
2105 margin:0;
2105 }
2106 }
2106
2107
2107 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label {
2108 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label {
2108 height:1%;
2109 height:1%;
2109 display:block;
2110 display:block;
2110 float:left;
2111 float:left;
2111 margin:3px 0 0 4px;
2112 margin:3px 0 0 4px;
2112 }
2113 }
2113
2114
2114 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2115 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2115 color:#000;
2116 color:#000;
2116 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2117 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2117 font-size:11px;
2118 font-size:11px;
2118 font-weight:700;
2119 font-weight:700;
2119 margin:0;
2120 margin:0;
2120 }
2121 }
2121
2122
2122 div.form div.fields div.field div.button .ui-state-default,#content div.box div.form div.fields div.buttons input.ui-state-default {
2123 div.form div.fields div.field div.button .ui-state-default,#content div.box div.form div.fields div.buttons input.ui-state-default {
2123 background:#e5e3e3 url("../images/button.png") repeat-x;
2124 background:#e5e3e3 url("../images/button.png") repeat-x;
2124 border-top:1px solid #DDD;
2125 border-top:1px solid #DDD;
2125 border-left:1px solid #c6c6c6;
2126 border-left:1px solid #c6c6c6;
2126 border-right:1px solid #DDD;
2127 border-right:1px solid #DDD;
2127 border-bottom:1px solid #c6c6c6;
2128 border-bottom:1px solid #c6c6c6;
2128 color:#515151;
2129 color:#515151;
2129 outline:none;
2130 outline:none;
2130 margin:0;
2131 margin:0;
2131 padding:6px 12px;
2132 padding:6px 12px;
2132 }
2133 }
2133
2134
2134 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2135 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2135 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2136 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2136 border-top:1px solid #ccc;
2137 border-top:1px solid #ccc;
2137 border-left:1px solid #bebebe;
2138 border-left:1px solid #bebebe;
2138 border-right:1px solid #b1b1b1;
2139 border-right:1px solid #b1b1b1;
2139 border-bottom:1px solid #afafaf;
2140 border-bottom:1px solid #afafaf;
2140 color:#515151;
2141 color:#515151;
2141 outline:none;
2142 outline:none;
2142 margin:0;
2143 margin:0;
2143 padding:6px 12px;
2144 padding:6px 12px;
2144 }
2145 }
2145
2146
2146 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2147 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2147 display:inline;
2148 display:inline;
2148 }
2149 }
2149
2150
2150 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2151 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2151 margin:10px 0 0 200px;
2152 margin:10px 0 0 200px;
2152 padding:0;
2153 padding:0;
2153 }
2154 }
2154
2155
2155 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons {
2156 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons {
2156 margin:10px 0 0;
2157 margin:10px 0 0;
2157 }
2158 }
2158
2159
2159 #content div.box table td.user,#content div.box table td.address {
2160 #content div.box table td.user,#content div.box table td.address {
2160 width:10%;
2161 width:10%;
2161 text-align:center;
2162 text-align:center;
2162 }
2163 }
2163
2164
2164 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link {
2165 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link {
2165 text-align:right;
2166 text-align:right;
2166 margin:6px 0 0;
2167 margin:6px 0 0;
2167 padding:0;
2168 padding:0;
2168 }
2169 }
2169
2170
2170 #content div.box div.action div.button input.ui-state-default,#login div.form div.fields div.buttons input.ui-state-default,#register div.form div.fields div.buttons input.ui-state-default {
2171 #content div.box div.action div.button input.ui-state-default,#login div.form div.fields div.buttons input.ui-state-default,#register div.form div.fields div.buttons input.ui-state-default {
2171 background:#e5e3e3 url("../images/button.png") repeat-x;
2172 background:#e5e3e3 url("../images/button.png") repeat-x;
2172 border-top:1px solid #DDD;
2173 border-top:1px solid #DDD;
2173 border-left:1px solid #c6c6c6;
2174 border-left:1px solid #c6c6c6;
2174 border-right:1px solid #DDD;
2175 border-right:1px solid #DDD;
2175 border-bottom:1px solid #c6c6c6;
2176 border-bottom:1px solid #c6c6c6;
2176 color:#515151;
2177 color:#515151;
2177 margin:0;
2178 margin:0;
2178 padding:6px 12px;
2179 padding:6px 12px;
2179 }
2180 }
2180
2181
2181 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover {
2182 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover {
2182 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2183 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2183 border-top:1px solid #ccc;
2184 border-top:1px solid #ccc;
2184 border-left:1px solid #bebebe;
2185 border-left:1px solid #bebebe;
2185 border-right:1px solid #b1b1b1;
2186 border-right:1px solid #b1b1b1;
2186 border-bottom:1px solid #afafaf;
2187 border-bottom:1px solid #afafaf;
2187 color:#515151;
2188 color:#515151;
2188 margin:0;
2189 margin:0;
2189 padding:6px 12px;
2190 padding:6px 12px;
2190 }
2191 }
2191
2192
2192 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2193 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2193 text-align:left;
2194 text-align:left;
2194 float:left;
2195 float:left;
2195 margin:0;
2196 margin:0;
2196 padding:0;
2197 padding:0;
2197 }
2198 }
2198
2199
2199 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2200 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2200 height:1%;
2201 height:1%;
2201 display:block;
2202 display:block;
2202 float:left;
2203 float:left;
2203 background:#ebebeb url("../images/pager.png") repeat-x;
2204 background:#ebebeb url("../images/pager.png") repeat-x;
2204 border-top:1px solid #dedede;
2205 border-top:1px solid #dedede;
2205 border-left:1px solid #cfcfcf;
2206 border-left:1px solid #cfcfcf;
2206 border-right:1px solid #c4c4c4;
2207 border-right:1px solid #c4c4c4;
2207 border-bottom:1px solid #c4c4c4;
2208 border-bottom:1px solid #c4c4c4;
2208 color:#4A4A4A;
2209 color:#4A4A4A;
2209 font-weight:700;
2210 font-weight:700;
2210 margin:0;
2211 margin:0;
2211 padding:6px 8px;
2212 padding:6px 8px;
2212 }
2213 }
2213
2214
2214 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2215 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2215 color:#B4B4B4;
2216 color:#B4B4B4;
2216 padding:6px;
2217 padding:6px;
2217 }
2218 }
2218
2219
2219 #login,#register {
2220 #login,#register {
2220 width:420px;
2221 width:420px;
2221 margin:10% auto 0;
2222 margin:10% auto 0;
2222 padding:0;
2223 padding:0;
2223 }
2224 }
2224
2225
2225 #login div.color,#register div.color {
2226 #login div.color,#register div.color {
2226 clear:both;
2227 clear:both;
2227 overflow:hidden;
2228 overflow:hidden;
2228 background:#FFF;
2229 background:#FFF;
2229 margin:10px auto 0;
2230 margin:10px auto 0;
2230 padding:3px 3px 3px 0;
2231 padding:3px 3px 3px 0;
2231 }
2232 }
2232
2233
2233 #login div.color a,#register div.color a {
2234 #login div.color a,#register div.color a {
2234 width:20px;
2235 width:20px;
2235 height:20px;
2236 height:20px;
2236 display:block;
2237 display:block;
2237 float:left;
2238 float:left;
2238 margin:0 0 0 3px;
2239 margin:0 0 0 3px;
2239 padding:0;
2240 padding:0;
2240 }
2241 }
2241
2242
2242 #login div.title h5,#register div.title h5 {
2243 #login div.title h5,#register div.title h5 {
2243 color:#fff;
2244 color:#fff;
2244 margin:10px;
2245 margin:10px;
2245 padding:0;
2246 padding:0;
2246 }
2247 }
2247
2248
2248 #login div.form div.fields div.field,#register div.form div.fields div.field {
2249 #login div.form div.fields div.field,#register div.form div.fields div.field {
2249 clear:both;
2250 clear:both;
2250 overflow:hidden;
2251 overflow:hidden;
2251 margin:0;
2252 margin:0;
2252 padding:0 0 10px;
2253 padding:0 0 10px;
2253 }
2254 }
2254
2255
2255 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2256 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2256 height:1%;
2257 height:1%;
2257 display:block;
2258 display:block;
2258 color:red;
2259 color:red;
2259 margin:8px 0 0;
2260 margin:8px 0 0;
2260 padding:0;
2261 padding:0;
2261 }
2262 }
2262
2263
2263 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2264 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2264 color:#000;
2265 color:#000;
2265 font-weight:700;
2266 font-weight:700;
2266 }
2267 }
2267
2268
2268 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2269 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2269 float:left;
2270 float:left;
2270 margin:0;
2271 margin:0;
2271 padding:0;
2272 padding:0;
2272 }
2273 }
2273
2274
2274 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2275 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2275 margin:0 0 0 184px;
2276 margin:0 0 0 184px;
2276 padding:0;
2277 padding:0;
2277 }
2278 }
2278
2279
2279 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2280 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2280 color:#565656;
2281 color:#565656;
2281 font-weight:700;
2282 font-weight:700;
2282 }
2283 }
2283
2284
2284 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2285 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2285 color:#000;
2286 color:#000;
2286 font-size:1em;
2287 font-size:1em;
2287 font-weight:700;
2288 font-weight:700;
2288 font-family:Verdana, Helvetica, Sans-Serif;
2289 font-family:Verdana, Helvetica, Sans-Serif;
2289 margin:0;
2290 margin:0;
2290 }
2291 }
2291
2292
2292 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2293 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2293 width:600px;
2294 width:600px;
2294 }
2295 }
2295
2296
2296 #changeset_content .container .left,#graph_content .container .left {
2297 #changeset_content .container .left,#graph_content .container .left {
2297 float:left;
2298 float:left;
2298 width:70%;
2299 width:70%;
2299 padding-left:5px;
2300 padding-left:5px;
2300 }
2301 }
2301
2302
2302 #changeset_content .container .left .date,.ac .match {
2303 #changeset_content .container .left .date,.ac .match {
2303 font-weight:700;
2304 font-weight:700;
2304 padding-top: 5px;
2305 padding-top: 5px;
2305 padding-bottom:5px;
2306 padding-bottom:5px;
2306 }
2307 }
2307
2308
2308 div#legend_container table td,div#legend_choices table td {
2309 div#legend_container table td,div#legend_choices table td {
2309 border:none !important;
2310 border:none !important;
2310 height:20px !important;
2311 height:20px !important;
2311 padding:0 !important;
2312 padding:0 !important;
2312 } No newline at end of file
2313 }
@@ -1,283 +1,283 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${next.title()}</title>
5 <title>${next.title()}</title>
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <!-- stylesheets -->
9 <!-- stylesheets -->
10 ${self.css()}
10 ${self.css()}
11 <!-- scripts -->
11 <!-- scripts -->
12 ${self.js()}
12 ${self.js()}
13 </head>
13 </head>
14 <body>
14 <body>
15 <!-- header -->
15 <!-- header -->
16 <div id="header">
16 <div id="header">
17 <!-- user -->
17 <!-- user -->
18 <ul id="logged-user">
18 <ul id="logged-user">
19 <li class="first">
19 <li class="first">
20 <div class="gravatar">
20 <div class="gravatar">
21 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
21 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
22 </div>
22 </div>
23 <div class="account">
23 <div class="account">
24 ${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
24 ${h.link_to('%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname),h.url('admin_settings_my_account'))}<br/>
25 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'))}
25 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'))}
26 </div>
26 </div>
27 </li>
27 </li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
29 </ul>
29 </ul>
30 <!-- end user -->
30 <!-- end user -->
31 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
31 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
32 <!-- logo -->
32 <!-- logo -->
33 <div id="logo">
33 <div id="logo">
34 <h1><a href="${h.url('hg_home')}">${c.rhodecode_name}</a></h1>
34 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
35 </div>
35 </div>
36 <!-- end logo -->
36 <!-- end logo -->
37 <!-- menu -->
37 <!-- menu -->
38 ${self.page_nav()}
38 ${self.page_nav()}
39 <!-- quick -->
39 <!-- quick -->
40 </div>
40 </div>
41 </div>
41 </div>
42 <!-- end header -->
42 <!-- end header -->
43
43
44 <!-- CONTENT -->
44 <!-- CONTENT -->
45 <div id="content">
45 <div id="content">
46 <div class="flash_msg">
46 <div class="flash_msg">
47 <% messages = h.flash.pop_messages() %>
47 <% messages = h.flash.pop_messages() %>
48 % if messages:
48 % if messages:
49 <ul id="flash-messages">
49 <ul id="flash-messages">
50 % for message in messages:
50 % for message in messages:
51 <li class="${message.category}_msg">${message}</li>
51 <li class="${message.category}_msg">${message}</li>
52 % endfor
52 % endfor
53 </ul>
53 </ul>
54 % endif
54 % endif
55 </div>
55 </div>
56 <div id="main">
56 <div id="main">
57 ${next.main()}
57 ${next.main()}
58 </div>
58 </div>
59 </div>
59 </div>
60 <!-- END CONTENT -->
60 <!-- END CONTENT -->
61
61
62 <!-- footer -->
62 <!-- footer -->
63 <div id="footer">
63 <div id="footer">
64 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
64 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
65 <div>
65 <div>
66 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
66 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
67 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
67 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
68 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
68 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
69 </div>
69 </div>
70 </div>
70 </div>
71 <script type="text/javascript">${h.tooltip.activate()}</script>
71 <script type="text/javascript">${h.tooltip.activate()}</script>
72 </div>
72 </div>
73 <!-- end footer -->
73 <!-- end footer -->
74 </body>
74 </body>
75
75
76 </html>
76 </html>
77
77
78 ### MAKO DEFS ###
78 ### MAKO DEFS ###
79 <%def name="page_nav()">
79 <%def name="page_nav()">
80 ${self.menu()}
80 ${self.menu()}
81 </%def>
81 </%def>
82
82
83 <%def name="menu(current=None)">
83 <%def name="menu(current=None)">
84 <%
84 <%
85 def is_current(selected):
85 def is_current(selected):
86 if selected == current:
86 if selected == current:
87 return h.literal('class="current"')
87 return h.literal('class="current"')
88 %>
88 %>
89 %if current not in ['home','admin']:
89 %if current not in ['home','admin']:
90 ##REGULAR MENU
90 ##REGULAR MENU
91 <ul id="quick">
91 <ul id="quick">
92 <!-- repo switcher -->
92 <!-- repo switcher -->
93 <li>
93 <li>
94 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
94 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
95 <span class="icon">
95 <span class="icon">
96 <img src="/images/icons/database.png" alt="${_('Products')}" />
96 <img src="/images/icons/database.png" alt="${_('Products')}" />
97 </span>
97 </span>
98 <span>&darr;</span>
98 <span>&darr;</span>
99 </a>
99 </a>
100 <ul class="repo_switcher">
100 <ul class="repo_switcher">
101 %for repo,private in c.repo_switcher_list:
101 %for repo,private in c.repo_switcher_list:
102 %if private:
102 %if private:
103 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li>
103 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="private_repo")}</li>
104 %else:
104 %else:
105 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li>
105 <li>${h.link_to(repo,h.url('summary_home',repo_name=repo),class_="public_repo")}</li>
106 %endif
106 %endif
107 %endfor
107 %endfor
108 </ul>
108 </ul>
109 </li>
109 </li>
110
110
111 <li ${is_current('summary')}>
111 <li ${is_current('summary')}>
112 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
112 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
113 <span class="icon">
113 <span class="icon">
114 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
114 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
115 </span>
115 </span>
116 <span>${_('Summary')}</span>
116 <span>${_('Summary')}</span>
117 </a>
117 </a>
118 </li>
118 </li>
119 <li ${is_current('shortlog')}>
119 <li ${is_current('shortlog')}>
120 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
120 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
121 <span class="icon">
121 <span class="icon">
122 <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
122 <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
123 </span>
123 </span>
124 <span>${_('Shortlog')}</span>
124 <span>${_('Shortlog')}</span>
125 </a>
125 </a>
126 </li>
126 </li>
127 <li ${is_current('changelog')}>
127 <li ${is_current('changelog')}>
128 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
128 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
129 <span class="icon">
129 <span class="icon">
130 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
130 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
131 </span>
131 </span>
132 <span>${_('Changelog')}</span>
132 <span>${_('Changelog')}</span>
133 </a>
133 </a>
134 </li>
134 </li>
135
135
136 <li ${is_current('switch_to')}>
136 <li ${is_current('switch_to')}>
137 <a title="${_('Switch to')}" href="#">
137 <a title="${_('Switch to')}" href="#">
138 <span class="icon">
138 <span class="icon">
139 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
139 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
140 </span>
140 </span>
141 <span>${_('Switch to')}</span>
141 <span>${_('Switch to')}</span>
142 </a>
142 </a>
143 <ul>
143 <ul>
144 <li>
144 <li>
145 ${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
145 ${h.link_to(_('branches'),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
146 <ul>
146 <ul>
147 %if c.repository_branches.values():
147 %if c.repository_branches.values():
148 %for cnt,branch in enumerate(c.repository_branches.items()):
148 %for cnt,branch in enumerate(c.repository_branches.items()):
149 <li>${h.link_to('%s - %s' % (branch[0],branch[1]),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
149 <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>
150 %endfor
150 %endfor
151 %else:
151 %else:
152 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
152 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
153 %endif
153 %endif
154 </ul>
154 </ul>
155 </li>
155 </li>
156 <li>
156 <li>
157 ${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
157 ${h.link_to(_('tags'),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
158 <ul>
158 <ul>
159 %if c.repository_tags.values():
159 %if c.repository_tags.values():
160 %for cnt,tag in enumerate(c.repository_tags.items()):
160 %for cnt,tag in enumerate(c.repository_tags.items()):
161 <li>${h.link_to('%s - %s' % (tag[0],tag[1]),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
161 <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>
162 %endfor
162 %endfor
163 %else:
163 %else:
164 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
164 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
165 %endif
165 %endif
166 </ul>
166 </ul>
167 </li>
167 </li>
168 </ul>
168 </ul>
169 </li>
169 </li>
170 <li ${is_current('files')}>
170 <li ${is_current('files')}>
171 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
171 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
172 <span class="icon">
172 <span class="icon">
173 <img src="/images/icons/file.png" alt="${_('Files')}" />
173 <img src="/images/icons/file.png" alt="${_('Files')}" />
174 </span>
174 </span>
175 <span>${_('Files')}</span>
175 <span>${_('Files')}</span>
176 </a>
176 </a>
177 </li>
177 </li>
178
178
179 <li ${is_current('options')}>
179 <li ${is_current('options')}>
180 <a title="${_('Options')}" href="#">
180 <a title="${_('Options')}" href="#">
181 <span class="icon">
181 <span class="icon">
182 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
182 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
183 </span>
183 </span>
184 <span>${_('Options')}</span>
184 <span>${_('Options')}</span>
185 </a>
185 </a>
186 <ul>
186 <ul>
187 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
187 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
188 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
188 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
189 %endif
189 %endif
190 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
190 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
191 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
191 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
192
192
193 %if h.HasPermissionAll('hg.admin')('access admin main page'):
193 %if h.HasPermissionAll('hg.admin')('access admin main page'):
194 <li>
194 <li>
195 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
195 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
196 <ul>
196 <ul>
197 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
197 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
198 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
198 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
199 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
199 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
200 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
200 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
201 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
201 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
202 </ul>
202 </ul>
203 </li>
203 </li>
204 %endif
204 %endif
205
205
206
206
207 ## %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
207 ## %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
208 ## <li class="last">
208 ## <li class="last">
209 ## ${h.link_to(_('delete'),'#',class_='delete')}
209 ## ${h.link_to(_('delete'),'#',class_='delete')}
210 ## ${h.form(url('repo_settings_delete', repo_name=c.repo_name),method='delete')}
210 ## ${h.form(url('repo_settings_delete', repo_name=c.repo_name),method='delete')}
211 ## ${h.submit('remove_%s' % c.repo_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
211 ## ${h.submit('remove_%s' % c.repo_name,'delete',class_="delete_icon action_button",onclick="return confirm('Confirm to delete this repository');")}
212 ## ${h.end_form()}
212 ## ${h.end_form()}
213 ## </li>
213 ## </li>
214 ## %endif
214 ## %endif
215 </ul>
215 </ul>
216 </li>
216 </li>
217 </ul>
217 </ul>
218 %else:
218 %else:
219 ##ROOT MENU
219 ##ROOT MENU
220 <ul id="quick">
220 <ul id="quick">
221 <li>
221 <li>
222 <a title="${_('Home')}" href="${h.url('hg_home')}">
222 <a title="${_('Home')}" href="${h.url('home')}">
223 <span class="icon">
223 <span class="icon">
224 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
224 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
225 </span>
225 </span>
226 <span>${_('Home')}</span>
226 <span>${_('Home')}</span>
227 </a>
227 </a>
228 </li>
228 </li>
229
229
230 <li>
230 <li>
231 <a title="${_('Search')}" href="${h.url('search')}">
231 <a title="${_('Search')}" href="${h.url('search')}">
232 <span class="icon">
232 <span class="icon">
233 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
233 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
234 </span>
234 </span>
235 <span>${_('Search')}</span>
235 <span>${_('Search')}</span>
236 </a>
236 </a>
237 </li>
237 </li>
238
238
239 %if h.HasPermissionAll('hg.admin')('access admin main page'):
239 %if h.HasPermissionAll('hg.admin')('access admin main page'):
240 <li ${is_current('admin')}>
240 <li ${is_current('admin')}>
241 <a title="${_('Admin')}" href="${h.url('admin_home')}">
241 <a title="${_('Admin')}" href="${h.url('admin_home')}">
242 <span class="icon">
242 <span class="icon">
243 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
243 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
244 </span>
244 </span>
245 <span>${_('Admin')}</span>
245 <span>${_('Admin')}</span>
246 </a>
246 </a>
247 <ul>
247 <ul>
248 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
248 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
249 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
249 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
250 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
250 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
251 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
251 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
252 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
252 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
253 </ul>
253 </ul>
254 </li>
254 </li>
255 %endif
255 %endif
256
256
257 </ul>
257 </ul>
258 %endif
258 %endif
259 </%def>
259 </%def>
260
260
261
261
262 <%def name="css()">
262 <%def name="css()">
263 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
263 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
264 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
264 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
265 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
265 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
266 </%def>
266 </%def>
267
267
268 <%def name="js()">
268 <%def name="js()">
269 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
269 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
270 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
270 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
271 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
271 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
272 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
272 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
273
273
274 <script type="text/javascript" src="/js/yui2.js"></script>
274 <script type="text/javascript" src="/js/yui2.js"></script>
275 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
275 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
276 <script type="text/javascript" src="/js/yui.flot.js"></script>
276 <script type="text/javascript" src="/js/yui.flot.js"></script>
277 </%def>
277 </%def>
278
278
279 <%def name="breadcrumbs()">
279 <%def name="breadcrumbs()">
280 <div class="breadcrumbs">
280 <div class="breadcrumbs">
281 ${self.breadcrumbs_links()}
281 ${self.breadcrumbs_links()}
282 </div>
282 </div>
283 </%def> No newline at end of file
283 </%def>
@@ -1,30 +1,32 b''
1 % if c.repo_branches:
1 % if c.repo_branches:
2 <table class="table_disp">
2 <table class="table_disp">
3 <tr>
3 <tr>
4 <th class="left">${_('date')}</th>
4 <th class="left">${_('date')}</th>
5 <th class="left">${_('name')}</th>
6 <th class="left">${_('author')}</th>
5 <th class="left">${_('revision')}</th>
7 <th class="left">${_('revision')}</th>
6 <th class="left">${_('name')}</th>
7 <th class="left">${_('links')}</th>
8 <th class="left">${_('links')}</th>
8 </tr>
9 </tr>
9 %for cnt,branch in enumerate(c.repo_branches.items()):
10 %for cnt,branch in enumerate(c.repo_branches.items()):
10 <tr class="parity${cnt%2}">
11 <tr class="parity${cnt%2}">
11 <td>${h.age(branch[1].date)}</td>
12 <td>${branch[1].date} - ${h.age(branch[1].date)}</td>
12 <td>r${branch[1].revision}:${branch[1].short_id}</td>
13 <td>
13 <td>
14 <span class="logtags">
14 <span class="logtags">
15 <span class="branchtag">${h.link_to(branch[0],
15 <span class="branchtag">${h.link_to(branch[0],
16 h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}</span>
16 h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].short_id))}</span>
17 </span>
17 </span>
18 </td>
18 </td>
19 <td title="${branch[1].author}">${h.person(branch[1].author)}</td>
20 <td>r${branch[1].revision}:${h.short_id(branch[1].raw_id)}</td>
19 <td class="nowrap">
21 <td class="nowrap">
20 ${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].short_id))}
22 ${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=branch[1].raw_id))}
21 |
23 |
22 ${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=branch[1].short_id))}
24 ${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=branch[1].raw_id))}
23 </td>
25 </td>
24 </tr>
26 </tr>
25 %endfor
27 %endfor
26 </table>
28 </table>
27 %else:
29 %else:
28 ${_('There are no branches yet')}
30 ${_('There are no branches yet')}
29 %endif
31 %endif
30
32
@@ -1,121 +1,121 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 ${c.repo_name} ${_('Changelog')} - ${c.rhodecode_name}
6 ${c.repo_name} ${_('Changelog')} - ${c.rhodecode_name}
7 </%def>
7 </%def>
8
8
9 <%def name="breadcrumbs_links()">
9 <%def name="breadcrumbs_links()">
10 ${h.link_to(u'Home',h.url('/'))}
10 ${h.link_to(u'Home',h.url('/'))}
11 &raquo;
11 &raquo;
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 &raquo;
13 &raquo;
14 ${_('Changelog')} - ${_('showing ')} ${c.size if c.size <= c.total_cs else c.total_cs} ${_('out of')} ${c.total_cs} ${_('revisions')}
14 ${_('Changelog')} - ${_('showing ')} ${c.size if c.size <= c.total_cs else c.total_cs} ${_('out of')} ${c.total_cs} ${_('revisions')}
15 </%def>
15 </%def>
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('changelog')}
18 ${self.menu('changelog')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <div class="box">
22 <div class="box">
23 <!-- box / title -->
23 <!-- box / title -->
24 <div class="title">
24 <div class="title">
25 ${self.breadcrumbs()}
25 ${self.breadcrumbs()}
26 </div>
26 </div>
27 <div class="table">
27 <div class="table">
28 % if c.pagination:
28 % if c.pagination:
29 <div id="graph">
29 <div id="graph">
30 <div id="graph_nodes">
30 <div id="graph_nodes">
31 <canvas id="graph_canvas"></canvas>
31 <canvas id="graph_canvas"></canvas>
32 </div>
32 </div>
33 <div id="graph_content">
33 <div id="graph_content">
34 <div class="container_header">
34 <div class="container_header">
35
35
36 ${h.form(h.url.current(),method='get')}
36 ${h.form(h.url.current(),method='get')}
37 <div class="info_box">
37 <div class="info_box">
38 <span>${_('Show')}:</span>
38 <span>${_('Show')}:</span>
39 ${h.text('size',size=1,value=c.size)}
39 ${h.text('size',size=1,value=c.size)}
40 <span>${_('revisions')}</span>
40 <span>${_('revisions')}</span>
41 ${h.submit('set',_('set'))}
41 ${h.submit('set',_('set'))}
42 </div>
42 </div>
43 ${h.end_form()}
43 ${h.end_form()}
44
44
45 </div>
45 </div>
46 %for cnt,cs in enumerate(c.pagination):
46 %for cnt,cs in enumerate(c.pagination):
47 <div id="chg_${cnt+1}" class="container">
47 <div id="chg_${cnt+1}" class="container">
48 <div class="left">
48 <div class="left">
49 <div class="date">${_('commit')} ${cs.revision}: ${cs.short_id}@${cs.date}</div>
49 <div class="date">${_('commit')} ${cs.revision}: ${cs.raw_id}@${cs.date}</div>
50 <div class="author">
50 <div class="author">
51 <div class="gravatar">
51 <div class="gravatar">
52 <img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),20)}"/>
52 <img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),20)}"/>
53 </div>
53 </div>
54 <span>${h.person(cs.author)}</span><br/>
54 <span>${h.person(cs.author)}</span><br/>
55 <span><a href="mailto:${h.email_or_none(cs.author)}">${h.email_or_none(cs.author)}</a></span><br/>
55 <span><a href="mailto:${h.email_or_none(cs.author)}">${h.email_or_none(cs.author)}</a></span><br/>
56 </div>
56 </div>
57 <div class="message">${h.link_to(h.wrap_paragraphs(cs.message),h.url('changeset_home',repo_name=c.repo_name,revision=cs.short_id))}</div>
57 <div class="message">${h.link_to(h.wrap_paragraphs(cs.message),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
58 </div>
58 </div>
59 <div class="right">
59 <div class="right">
60 <div class="changes">
60 <div class="changes">
61 <span class="removed" title="${_('removed')}">${len(cs.removed)}</span>
61 <span class="removed" title="${_('removed')}">${len(cs.removed)}</span>
62 <span class="changed" title="${_('changed')}">${len(cs.changed)}</span>
62 <span class="changed" title="${_('changed')}">${len(cs.changed)}</span>
63 <span class="added" title="${_('added')}">${len(cs.added)}</span>
63 <span class="added" title="${_('added')}">${len(cs.added)}</span>
64 </div>
64 </div>
65 %if len(cs.parents)>1:
65 %if len(cs.parents)>1:
66 <div class="merge">
66 <div class="merge">
67 ${_('merge')}<img alt="merge" src="/images/icons/arrow_join.png"/>
67 ${_('merge')}<img alt="merge" src="/images/icons/arrow_join.png"/>
68 </div>
68 </div>
69 %endif
69 %endif
70 %if cs.parents:
70 %if cs.parents:
71 %for p_cs in reversed(cs.parents):
71 %for p_cs in reversed(cs.parents):
72 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(p_cs.short_id,
72 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(p_cs.raw_id,
73 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.short_id),title=p_cs.message)}
73 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
74 </div>
74 </div>
75 %endfor
75 %endfor
76 %else:
76 %else:
77 <div class="parent">${_('No parents')}</div>
77 <div class="parent">${_('No parents')}</div>
78 %endif
78 %endif
79
79
80 <span class="logtags">
80 <span class="logtags">
81 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
81 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
82 ${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}</span>
82 ${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
83 %for tag in cs.tags:
83 %for tag in cs.tags:
84 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
84 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
85 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}</span>
85 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
86 %endfor
86 %endfor
87 </span>
87 </span>
88 </div>
88 </div>
89 </div>
89 </div>
90
90
91 %endfor
91 %endfor
92 <div class="pagination-wh pagination-left">
92 <div class="pagination-wh pagination-left">
93 ${c.pagination.pager('$link_previous ~2~ $link_next')}
93 ${c.pagination.pager('$link_previous ~2~ $link_next')}
94 </div>
94 </div>
95 </div>
95 </div>
96 </div>
96 </div>
97
97
98 <script type="text/javascript" src="/js/graph.js"></script>
98 <script type="text/javascript" src="/js/graph.js"></script>
99 <script type="text/javascript">
99 <script type="text/javascript">
100 YAHOO.util.Event.onDOMReady(function(){
100 YAHOO.util.Event.onDOMReady(function(){
101 function set_canvas() {
101 function set_canvas() {
102 var c = document.getElementById('graph_nodes');
102 var c = document.getElementById('graph_nodes');
103 var t = document.getElementById('graph_content');
103 var t = document.getElementById('graph_content');
104 canvas = document.getElementById('graph_canvas');
104 canvas = document.getElementById('graph_canvas');
105 var div_h = t.clientHeight;
105 var div_h = t.clientHeight;
106 c.style.height=div_h+'px';
106 c.style.height=div_h+'px';
107 canvas.setAttribute('height',div_h);
107 canvas.setAttribute('height',div_h);
108 canvas.setAttribute('width',160);
108 canvas.setAttribute('width',160);
109 };
109 };
110 set_canvas();
110 set_canvas();
111 var jsdata = ${c.jsdata|n};
111 var jsdata = ${c.jsdata|n};
112 var r = new BranchRenderer();
112 var r = new BranchRenderer();
113 r.render(jsdata);
113 r.render(jsdata);
114 });
114 });
115 </script>
115 </script>
116 %else:
116 %else:
117 ${_('There are no changes yet')}
117 ${_('There are no changes yet')}
118 %endif
118 %endif
119 </div>
119 </div>
120 </div>
120 </div>
121 </%def> No newline at end of file
121 </%def>
@@ -1,124 +1,124 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${c.changeset.short_id} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('Changeset')} - r${c.changeset.revision}:${c.changeset.short_id}
12 ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('changelog')}
16 ${self.menu('changelog')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 <div class="box">
20 <div class="box">
21 <!-- box / title -->
21 <!-- box / title -->
22 <div class="title">
22 <div class="title">
23 ${self.breadcrumbs()}
23 ${self.breadcrumbs()}
24 </div>
24 </div>
25 <div class="table">
25 <div class="table">
26 <div id="body" class="diffblock">
26 <div id="body" class="diffblock">
27 <div class="code-header">
27 <div class="code-header">
28 <div>
28 <div>
29 ${_('Changeset')} - r${c.changeset.revision}:${c.changeset.short_id}
29 ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
30 &raquo; <span>${h.link_to(_('raw diff'),
30 &raquo; <span>${h.link_to(_('raw diff'),
31 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.short_id,diff='show'))}</span>
31 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span>
32 &raquo; <span>${h.link_to(_('download diff'),
32 &raquo; <span>${h.link_to(_('download diff'),
33 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.short_id,diff='download'))}</span>
33 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span>
34 </div>
34 </div>
35 </div>
35 </div>
36 </div>
36 </div>
37 <div id="changeset_content">
37 <div id="changeset_content">
38 <div class="container">
38 <div class="container">
39 <div class="left">
39 <div class="left">
40 <div class="date">${_('commit')} ${c.changeset.revision}: ${c.changeset.short_id}@${c.changeset.date}</div>
40 <div class="date">${_('commit')} ${c.changeset.revision}: ${h.short_id(c.changeset.raw_id)}@${c.changeset.date}</div>
41 <div class="author">
41 <div class="author">
42 <div class="gravatar">
42 <div class="gravatar">
43 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
43 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
44 </div>
44 </div>
45 <span>${h.person(c.changeset.author)}</span><br/>
45 <span>${h.person(c.changeset.author)}</span><br/>
46 <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
46 <span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
47 </div>
47 </div>
48 <div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.short_id))}</div>
48 <div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</div>
49 </div>
49 </div>
50 <div class="right">
50 <div class="right">
51 <div class="changes">
51 <div class="changes">
52 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
52 <span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
53 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
53 <span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
54 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
54 <span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
55 </div>
55 </div>
56 %if len(c.changeset.parents)>1:
56 %if len(c.changeset.parents)>1:
57 <div class="merge">
57 <div class="merge">
58 ${_('merge')}<img alt="merge" src="/images/icons/arrow_join.png"/>
58 ${_('merge')}<img alt="merge" src="/images/icons/arrow_join.png"/>
59 </div>
59 </div>
60 %endif
60 %endif
61
61
62 %if c.changeset.parents:
62 %if c.changeset.parents:
63 %for p_cs in reversed(c.changeset.parents):
63 %for p_cs in reversed(c.changeset.parents):
64 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(p_cs.short_id,
64 <div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(h.short_id(p_cs.raw_id),
65 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.short_id),title=p_cs.message)}
65 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
66 </div>
66 </div>
67 %endfor
67 %endfor
68 %else:
68 %else:
69 <div class="parent">${_('No parents')}</div>
69 <div class="parent">${_('No parents')}</div>
70 %endif
70 %endif
71 <span class="logtags">
71 <span class="logtags">
72 <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
72 <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
73 ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.short_id))}</span>
73 ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
74 %for tag in c.changeset.tags:
74 %for tag in c.changeset.tags:
75 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
75 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
76 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.short_id))}</span>
76 ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
77 %endfor
77 %endfor
78 </span>
78 </span>
79 </div>
79 </div>
80 </div>
80 </div>
81 <span style="font-size:1.1em;font-weight: bold">${_('Files affected')}</span>
81 <span style="font-size:1.1em;font-weight: bold">${_('Files affected')}</span>
82 <div class="cs_files">
82 <div class="cs_files">
83 %for change,filenode,diff,cs1,cs2 in c.changes:
83 %for change,filenode,diff,cs1,cs2 in c.changes:
84 <div class="cs_${change}">${h.link_to(filenode.path,h.url.current(anchor='CHANGE-%s'%filenode.path))}</div>
84 <div class="cs_${change}">${h.link_to(filenode.path,h.url.current(anchor='CHANGE-%s'%filenode.path))}</div>
85 %endfor
85 %endfor
86 </div>
86 </div>
87 </div>
87 </div>
88
88
89 </div>
89 </div>
90
90
91 %for change,filenode,diff,cs1,cs2 in c.changes:
91 %for change,filenode,diff,cs1,cs2 in c.changes:
92 %if change !='removed':
92 %if change !='removed':
93 <div style="clear:both;height:10px"></div>
93 <div style="clear:both;height:10px"></div>
94 <div id="body" class="diffblock">
94 <div id="body" class="diffblock">
95 <div id="${'CHANGE-%s'%filenode.path}" class="code-header">
95 <div id="${'CHANGE-%s'%filenode.path}" class="code-header">
96 <div>
96 <div>
97 <span>
97 <span>
98 ${h.link_to_if(change!='removed',filenode.path,h.url('files_home',repo_name=c.repo_name,
98 ${h.link_to_if(change!='removed',filenode.path,h.url('files_home',repo_name=c.repo_name,
99 revision=filenode.changeset.short_id,f_path=filenode.path))}
99 revision=filenode.changeset.raw_id,f_path=filenode.path))}
100 </span>
100 </span>
101 %if 1:
101 %if 1:
102 &raquo; <span>${h.link_to(_('diff'),
102 &raquo; <span>${h.link_to(_('diff'),
103 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='diff'))}</span>
103 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='diff'))}</span>
104 &raquo; <span>${h.link_to(_('raw diff'),
104 &raquo; <span>${h.link_to(_('raw diff'),
105 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='raw'))}</span>
105 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='raw'))}</span>
106 &raquo; <span>${h.link_to(_('download diff'),
106 &raquo; <span>${h.link_to(_('download diff'),
107 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='download'))}</span>
107 h.url('files_diff_home',repo_name=c.repo_name,f_path=filenode.path,diff2=cs2,diff1=cs1,diff='download'))}</span>
108 %endif
108 %endif
109 </div>
109 </div>
110 </div>
110 </div>
111 <div class="code-body">
111 <div class="code-body">
112 %if diff:
112 %if diff:
113 ${diff|n}
113 ${diff|n}
114 %else:
114 %else:
115 ${_('No changes in this file')}
115 ${_('No changes in this file')}
116 %endif
116 %endif
117 </div>
117 </div>
118 </div>
118 </div>
119 %endif
119 %endif
120 %endfor
120 %endfor
121 </div>
121 </div>
122 </div>
122 </div>
123
123
124 </%def> No newline at end of file
124 </%def>
@@ -1,32 +1,32 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="./../base/base.html"/>
2 <%inherit file="./../base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Repository not found')}
5 ${_('Repository not found')}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs()">
8 <%def name="breadcrumbs()">
9 ${h.link_to(u'Home',h.url('hg_home'))}
9 ${h.link_to(u'Home',h.url('home'))}
10 /
10 /
11 ${h.link_to(u'Admin',h.url('admin_home'))}
11 ${h.link_to(u'Admin',h.url('admin_home'))}
12 </%def>
12 </%def>
13
13
14 <%def name="page_nav()">
14 <%def name="page_nav()">
15 ${self.menu('admin')}
15 ${self.menu('admin')}
16 </%def>
16 </%def>
17 <%def name="js()">
17 <%def name="js()">
18
18
19 </%def>
19 </%def>
20 <%def name="main()">
20 <%def name="main()">
21
21
22 <h2 class="no-link no-border">${_('Not Found')}</h2>
22 <h2 class="no-link no-border">${_('Not Found')}</h2>
23 <p class="normal">${_('The specified repository "%s" is unknown, sorry.') % c.repo_name}</p>
23 <p class="normal">${_('The specified repository "%s" is unknown, sorry.') % c.repo_name}</p>
24 <p class="normal">
24 <p class="normal">
25 <a href="${h.url('new_repo',repo=c.repo_name_cleaned)}">
25 <a href="${h.url('new_repo',repo=c.repo_name_cleaned)}">
26 ${_('Create "%s" repository as %s' % (c.repo_name,c.repo_name_cleaned))}</a>
26 ${_('Create "%s" repository as %s' % (c.repo_name,c.repo_name_cleaned))}</a>
27
27
28 </p>
28 </p>
29 <p class="normal">${h.link_to(_('Go back to the main repository list page'),h.url('hg_home'))}</p>
29 <p class="normal">${h.link_to(_('Go back to the main repository list page'),h.url('home'))}</p>
30 <div class="page-footer">
30 <div class="page-footer">
31 </div>
31 </div>
32 </%def> No newline at end of file
32 </%def>
@@ -1,50 +1,50 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('File diff')} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('File diff')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${'%s: %s %s %s' % (_('File diff'),c.diff2,'&rarr;',c.diff1)|n}
12 ${_('File diff')} r${c.changeset_1.revision}:${h.short_id(c.changeset_1.raw_id)} &rarr; r${c.changeset_2.revision}:${h.short_id(c.changeset_2.raw_id)}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('files')}
16 ${self.menu('files')}
17 </%def>
17 </%def>
18 <%def name="main()">
18 <%def name="main()">
19 <div class="box">
19 <div class="box">
20 <!-- box / title -->
20 <!-- box / title -->
21 <div class="title">
21 <div class="title">
22 ${self.breadcrumbs()}
22 ${self.breadcrumbs()}
23 </div>
23 </div>
24 <div class="table">
24 <div class="table">
25 <div id="body" class="diffblock">
25 <div id="body" class="diffblock">
26 <div class="code-header">
26 <div class="code-header">
27 <div>
27 <div>
28 <span>${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
28 <span>${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name,
29 revision=c.diff2.split(':')[1],f_path=c.f_path))}</span>
29 revision=c.changeset_2.raw_id,f_path=c.f_path))}</span>
30 &raquo; <span>${h.link_to(_('diff'),
30 &raquo; <span>${h.link_to(_('diff'),
31 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='diff'))}</span>
31 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='diff'))}</span>
32 &raquo; <span>${h.link_to(_('raw diff'),
32 &raquo; <span>${h.link_to(_('raw diff'),
33 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='raw'))}</span>
33 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))}</span>
34 &raquo; <span>${h.link_to(_('download diff'),
34 &raquo; <span>${h.link_to(_('download diff'),
35 h.url.current(diff2=c.diff2.split(':')[-1],diff1=c.diff1.split(':')[-1],diff='download'))}</span>
35 h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='download'))}</span>
36 </div>
36 </div>
37 </div>
37 </div>
38 <div class="code-body">
38 <div class="code-body">
39 %if c.no_changes:
39 %if c.no_changes:
40 ${_('No changes')}
40 ${_('No changes')}
41 %else:
41 %else:
42 ${c.cur_diff|n}
42 ${c.cur_diff|n}
43 %endif
43 %endif
44 </div>
44 </div>
45 </div>
45 </div>
46 </div>
46 </div>
47 </div>
47 </div>
48 </%def>
48 </%def>
49
49
50 No newline at end of file
50
@@ -1,48 +1,48 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('Files')} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('Files')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.repo_name,h.url('files_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('files_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('files')}
12 ${_('files')}
13 %if c.files_list:
13 %if c.files_list:
14 @ R${c.rev_nr}:${c.cur_rev}
14 @ R${c.rev_nr}:${h.short_id(c.cur_rev)}
15 %endif
15 %endif
16 </%def>
16 </%def>
17
17
18 <%def name="page_nav()">
18 <%def name="page_nav()">
19 ${self.menu('files')}
19 ${self.menu('files')}
20 </%def>
20 </%def>
21
21
22 <%def name="main()">
22 <%def name="main()">
23 <div class="box">
23 <div class="box">
24 <!-- box / title -->
24 <!-- box / title -->
25 <div class="title">
25 <div class="title">
26 ${self.breadcrumbs()}
26 ${self.breadcrumbs()}
27 </div>
27 </div>
28 <div class="table">
28 <div class="table">
29 <div id="files_data">
29 <div id="files_data">
30 %if c.files_list:
30 %if c.files_list:
31 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cur_rev,c.files_list.path)}</h3>
31 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cur_rev,c.files_list.path)}</h3>
32 %if c.files_list.is_dir():
32 %if c.files_list.is_dir():
33 <%include file='files_browser.html'/>
33 <%include file='files_browser.html'/>
34 %else:
34 %else:
35 <%include file='files_source.html'/>
35 <%include file='files_source.html'/>
36 %endif
36 %endif
37 %else:
37 %else:
38 <h2>
38 <h2>
39 <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a>
39 <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a>
40 ${_('No files at given path')}: "${c.f_path or "/"}"
40 ${_('No files at given path')}: "${c.f_path or "/"}"
41 </h2>
41 </h2>
42 %endif
42 %endif
43
43
44 </div>
44 </div>
45 </div>
45 </div>
46 </div>
46 </div>
47
47
48 </%def> No newline at end of file
48 </%def>
@@ -1,61 +1,61 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('File annotate')} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('File annotate')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('annotate')} @ R${c.rev_nr}:${c.cur_rev}
12 ${_('annotate')} @ R${c.rev_nr}:${c.cur_rev}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('files')}
16 ${self.menu('files')}
17 </%def>
17 </%def>
18 <%def name="main()">
18 <%def name="main()">
19 <div class="box">
19 <div class="box">
20 <!-- box / title -->
20 <!-- box / title -->
21 <div class="title">
21 <div class="title">
22 ${self.breadcrumbs()}
22 ${self.breadcrumbs()}
23 </div>
23 </div>
24 <div class="table">
24 <div class="table">
25 <div id="files_data">
25 <div id="files_data">
26 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cur_rev,c.file.path)}</h3>
26 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cur_rev,c.file.path)}</h3>
27 <dl class="overview">
27 <dl class="overview">
28 <dt>${_('Last revision')}</dt>
28 <dt>${_('Last revision')}</dt>
29 <dd>${h.link_to("r%s:%s" % (c.file.last_changeset.revision,c.file.last_changeset.short_id),
29 <dd>${h.link_to("r%s:%s" % (c.file.last_changeset.revision,c.file.last_changeset.raw_id),
30 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.last_changeset.short_id,f_path=c.f_path))} </dd>
30 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.last_changeset.raw_id,f_path=c.f_path))} </dd>
31 <dt>${_('Size')}</dt>
31 <dt>${_('Size')}</dt>
32 <dd>${h.format_byte_size(c.file.size,binary=True)}</dd>
32 <dd>${h.format_byte_size(c.file.size,binary=True)}</dd>
33 <dt>${_('Mimetype')}</dt>
33 <dt>${_('Mimetype')}</dt>
34 <dd>${c.file.mimetype}</dd>
34 <dd>${c.file.mimetype}</dd>
35 <dt>${_('Options')}</dt>
35 <dt>${_('Options')}</dt>
36 <dd>${h.link_to(_('show source'),
36 <dd>${h.link_to(_('show source'),
37 h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
37 h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
38 / ${h.link_to(_('show as raw'),
38 / ${h.link_to(_('show as raw'),
39 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
39 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
40 / ${h.link_to(_('download as raw'),
40 / ${h.link_to(_('download as raw'),
41 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
41 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
42 </dd>
42 </dd>
43 </dl>
43 </dl>
44 <div id="body" class="codeblock">
44 <div id="body" class="codeblock">
45 <div class="code-header">
45 <div class="code-header">
46 <div class="revision">${c.file.name}@r${c.file.last_changeset.revision}:${c.file.last_changeset.short_id}</div>
46 <div class="revision">${c.file.name}@r${c.file.last_changeset.revision}:${c.file.last_changeset.raw_id}</div>
47 <div class="commit">"${c.file_msg}"</div>
47 <div class="commit">"${c.file_msg}"</div>
48 </div>
48 </div>
49 <div class="code-body">
49 <div class="code-body">
50 % if c.file.size < c.file_size_limit:
50 % if c.file.size < c.file_size_limit:
51 ${h.pygmentize_annotation(c.file,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
51 ${h.pygmentize_annotation(c.file,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
52 %else:
52 %else:
53 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
53 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
54 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
54 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
55 %endif
55 %endif
56 </div>
56 </div>
57 </div>
57 </div>
58 </div>
58 </div>
59 </div>
59 </div>
60 </div>
60 </div>
61 </%def> No newline at end of file
61 </%def>
@@ -1,57 +1,57 b''
1 <dl>
1 <dl>
2 <dt>${_('Last revision')}</dt>
2 <dt>${_('Last revision')}</dt>
3 <dd>
3 <dd>
4 ${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,c.files_list.last_changeset.short_id),
4 ${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,h.short_id(c.files_list.last_changeset.raw_id)),
5 h.url('files_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.short_id,f_path=c.f_path))}
5 h.url('files_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.raw_id,f_path=c.f_path))}
6 </dd>
6 </dd>
7 <dt>${_('Size')}</dt>
7 <dt>${_('Size')}</dt>
8 <dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
8 <dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
9 <dt>${_('Mimetype')}</dt>
9 <dt>${_('Mimetype')}</dt>
10 <dd>${c.files_list.mimetype}</dd>
10 <dd>${c.files_list.mimetype}</dd>
11 <dt>${_('Options')}</dt>
11 <dt>${_('Options')}</dt>
12 <dd>${h.link_to(_('show annotation'),
12 <dd>${h.link_to(_('show annotation'),
13 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
13 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
14 / ${h.link_to(_('show as raw'),
14 / ${h.link_to(_('show as raw'),
15 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
15 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
16 / ${h.link_to(_('download as raw'),
16 / ${h.link_to(_('download as raw'),
17 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
17 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
18 </dd>
18 </dd>
19 <dt>${_('History')}</dt>
19 <dt>${_('History')}</dt>
20 <dd>
20 <dd>
21 <div>
21 <div>
22 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
22 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
23 ${h.hidden('diff2',c.files_list.last_changeset.short_id)}
23 ${h.hidden('diff2',c.files_list.last_changeset.raw_id)}
24 ${h.select('diff1',c.files_list.last_changeset.short_id,c.file_history)}
24 ${h.select('diff1',c.files_list.last_changeset.raw_id,c.file_history)}
25 ${h.submit('diff','diff to revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
25 ${h.submit('diff','diff to revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
26 ${h.submit('show_rev','show at revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
26 ${h.submit('show_rev','show at revision',class_="ui-button ui-widget ui-state-default ui-corner-all")}
27 ${h.end_form()}
27 ${h.end_form()}
28 </div>
28 </div>
29 </dd>
29 </dd>
30 </dl>
30 </dl>
31
31
32
32
33 <div id="body" class="codeblock">
33 <div id="body" class="codeblock">
34 <div class="code-header">
34 <div class="code-header">
35 <div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${c.files_list.last_changeset.short_id}</div>
35 <div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${h.short_id(c.files_list.last_changeset.raw_id)}</div>
36 <div class="commit">"${c.files_list.last_changeset.message}"</div>
36 <div class="commit">"${c.files_list.last_changeset.message}"</div>
37 </div>
37 </div>
38 <div class="code-body">
38 <div class="code-body">
39 % if c.files_list.size < c.file_size_limit:
39 % if c.files_list.size < c.file_size_limit:
40 ${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
40 ${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
41 %else:
41 %else:
42 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
42 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
43 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
43 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=c.f_path))}
44 %endif
44 %endif
45 </div>
45 </div>
46 </div>
46 </div>
47
47
48 <script type="text/javascript">
48 <script type="text/javascript">
49 YAHOO.util.Event.onDOMReady(function(){
49 YAHOO.util.Event.onDOMReady(function(){
50 YAHOO.util.Event.addListener('show_rev','click',function(e){
50 YAHOO.util.Event.addListener('show_rev','click',function(e){
51 YAHOO.util.Event.preventDefault(e);
51 YAHOO.util.Event.preventDefault(e);
52 var cs = YAHOO.util.Dom.get('diff1').value;
52 var cs = YAHOO.util.Dom.get('diff1').value;
53 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
53 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
54 window.location = url;
54 window.location = url;
55 });
55 });
56 });
56 });
57 </script> No newline at end of file
57 </script>
@@ -1,107 +1,110 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/base.html"/>
2 <%inherit file="base/base.html"/>
3 <%def name="title()">
3 <%def name="title()">
4 ${_('Dashboard')} - ${c.rhodecode_name}
4 ${_('Dashboard')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6 <%def name="breadcrumbs()">
6 <%def name="breadcrumbs()">
7 ${c.rhodecode_name}
7 ${c.rhodecode_name}
8 </%def>
8 </%def>
9 <%def name="page_nav()">
9 <%def name="page_nav()">
10 ${self.menu('home')}
10 ${self.menu('home')}
11 </%def>
11 </%def>
12 <%def name="main()">
12 <%def name="main()">
13 <%def name="get_sort(name)">
13 <%def name="get_sort(name)">
14 <%name_slug = name.lower().replace(' ','_') %>
14 <%name_slug = name.lower().replace(' ','_') %>
15
15
16 %if name_slug == c.sort_slug:
16 %if name_slug == c.sort_slug:
17 %if c.sort_by.startswith('-'):
17 %if c.sort_by.startswith('-'):
18 <a href="?sort=${name_slug}">${name}&uarr;</a>
18 <a href="?sort=${name_slug}">${name}&uarr;</a>
19 %else:
19 %else:
20 <a href="?sort=-${name_slug}">${name}&darr;</a>
20 <a href="?sort=-${name_slug}">${name}&darr;</a>
21 %endif:
21 %endif:
22 %else:
22 %else:
23 <a href="?sort=${name_slug}">${name}</a>
23 <a href="?sort=${name_slug}">${name}</a>
24 %endif
24 %endif
25 </%def>
25 </%def>
26
26
27 <div class="box">
27 <div class="box">
28 <!-- box / title -->
28 <!-- box / title -->
29 <div class="title">
29 <div class="title">
30 <h5>${_('Dashboard')}</h5>
30 <h5>${_('Dashboard')}</h5>
31 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
31 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
32 <ul class="links">
32 <ul class="links">
33 <li>
33 <li>
34 <span>${h.link_to(_('ADD NEW REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
34 <span>${h.link_to(_('ADD NEW REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
35 </li>
35 </li>
36 </ul>
36 </ul>
37 %endif
37 %endif
38 </div>
38 </div>
39 <!-- end box / title -->
39 <!-- end box / title -->
40 <div class="table">
40 <div class="table">
41 <table>
41 <table>
42 <thead>
42 <thead>
43 <tr>
43 <tr>
44 <th class="left">${get_sort(_('Name'))}</th>
44 <th class="left">${get_sort(_('Name'))}</th>
45 <th class="left">${get_sort(_('Description'))}</th>
45 <th class="left">${get_sort(_('Description'))}</th>
46 <th class="left">${get_sort(_('Last change'))}</th>
46 <th class="left">${get_sort(_('Last change'))}</th>
47 <th class="left">${get_sort(_('Tip'))}</th>
47 <th class="left">${get_sort(_('Tip'))}</th>
48 <th class="left">${get_sort(_('Owner'))}</th>
48 <th class="left">${get_sort(_('Owner'))}</th>
49 <th class="left">${_('RSS')}</th>
49 <th class="left">${_('RSS')}</th>
50 <th class="left">${_('Atom')}</th>
50 <th class="left">${_('Atom')}</th>
51 </tr>
51 </tr>
52 </thead>
52 </thead>
53 <tbody>
53 <tbody>
54 %for cnt,repo in enumerate(c.repos_list):
54 %for cnt,repo in enumerate(c.repos_list):
55 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
55 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
56 <tr class="parity${cnt%2}">
56 <tr class="parity${cnt%2}">
57 <td>
57 <td>
58 %if repo['repo'].dbrepo.repo_type =='hg':
58 %if repo['repo'].dbrepo.repo_type =='hg':
59 <img class="icon" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
59 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
60 %elif repo['repo'].dbrepo.repo_type =='git':
60 %elif repo['repo'].dbrepo.repo_type =='git':
61 <img class="icon" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
61 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
62 %else:
62 %else:
63
63
64 %endif
64 %endif
65
65
66 %if repo['repo'].dbrepo.private:
66 %if repo['repo'].dbrepo.private:
67 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
67 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
68 %else:
68 %else:
69 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
69 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
70 %endif
70 %endif
71 ${h.link_to(repo['name'],
71 ${h.link_to(repo['name'],
72 h.url('summary_home',repo_name=repo['name']))}
72 h.url('summary_home',repo_name=repo['name']))}
73 %if repo['repo'].dbrepo.fork:
73 %if repo['repo'].dbrepo.fork:
74 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
74 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
75 <img class="icon" alt="${_('public')}"
75 <img class="icon" alt="${_('fork')}"
76 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
76 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
77 src="/images/icons/arrow_divide.png"/></a>
77 src="/images/icons/arrow_divide.png"/></a>
78 %endif
78 %endif
79 </td>
79 </td>
80 <td title="${repo['description']}">${h.truncate(repo['description'],60)}</td>
80 <td><span class="tooltip" tooltip_title="${repo['description']}">
81 ${h.truncate(repo['description'],60)}</span>
82 </td>
81 <td><span class="tooltip" tooltip_title="${repo['last_change']}">
83 <td><span class="tooltip" tooltip_title="${repo['last_change']}">
82 ${h.age(repo['last_change'])} </span></td>
84 ${h.age(repo['last_change'])} </span>
85 </td>
83 <td>
86 <td>
84 %if repo['rev']>=0:
87 %if repo['rev']>=0:
85 ${h.link_to('r%s:%s' % (repo['rev'],repo['tip']),
88 ${h.link_to('r%s:%s' % (repo['rev'],h.short_id(repo['tip'])),
86 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
89 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
87 class_="tooltip",
90 class_="tooltip",
88 tooltip_title=h.tooltip(repo['last_msg']))}
91 tooltip_title=h.tooltip(repo['last_msg']))}
89 %else:
92 %else:
90 ${_('No changesets yet')}
93 ${_('No changesets yet')}
91 %endif
94 %endif
92 </td>
95 </td>
93 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
96 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
94 <td>
97 <td>
95 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
98 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
96 </td>
99 </td>
97 <td>
100 <td>
98 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
101 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
99 </td>
102 </td>
100 </tr>
103 </tr>
101 %endif
104 %endif
102 %endfor
105 %endfor
103 </tbody>
106 </tbody>
104 </table>
107 </table>
105 </div>
108 </div>
106 </div>
109 </div>
107 </%def>
110 </%def>
@@ -1,63 +1,63 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 % if c.repo_changesets:
2 % if c.repo_changesets:
3 <table>
3 <table>
4 <tr>
4 <tr>
5 <th class="left">${_('date')}</th>
5 <th class="left">${_('date')}</th>
6 <th class="left">${_('commit message')}</th>
6 <th class="left">${_('author')}</th>
7 <th class="left">${_('author')}</th>
7 <th class="left">${_('revision')}</th>
8 <th class="left">${_('revision')}</th>
8 <th class="left">${_('commit message')}</th>
9 <th class="left">${_('branch')}</th>
9 <th class="left">${_('branch')}</th>
10 <th class="left">${_('tags')}</th>
10 <th class="left">${_('tags')}</th>
11 <th class="left">${_('links')}</th>
11 <th class="left">${_('links')}</th>
12
12
13 </tr>
13 </tr>
14 %for cnt,cs in enumerate(c.repo_changesets):
14 %for cnt,cs in enumerate(c.repo_changesets):
15 <tr class="parity${cnt%2}">
15 <tr class="parity${cnt%2}">
16 <td>${h.age(cs.date)} - ${cs.date} </td>
16 <td>${cs.date} - ${h.age(cs.date)}</td>
17 <td>
18 ${h.link_to(h.truncate(cs.message,60),
19 h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
20 title=cs.message)}
21 </td>
17 <td title="${cs.author}">${h.person(cs.author)}</td>
22 <td title="${cs.author}">${h.person(cs.author)}</td>
18 <td>r${cs.revision}:${cs.short_id}</td>
23 <td>r${cs.revision}:${h.short_id(cs.raw_id)}</td>
19 <td>
20 ${h.link_to(h.truncate(cs.message,60),
21 h.url('changeset_home',repo_name=c.repo_name,revision=cs.short_id),
22 title=cs.message)}
23 </td>
24 <td>
24 <td>
25 <span class="logtags">
25 <span class="logtags">
26 <span class="branchtag">${cs.branch}</span>
26 <span class="branchtag">${cs.branch}</span>
27 </span>
27 </span>
28 </td>
28 </td>
29 <td>
29 <td>
30 <span class="logtags">
30 <span class="logtags">
31 %for tag in cs.tags:
31 %for tag in cs.tags:
32 <span class="tagtag">${tag}</span>
32 <span class="tagtag">${tag}</span>
33 %endfor
33 %endfor
34 </span>
34 </span>
35 </td>
35 </td>
36 <td class="nowrap">
36 <td class="nowrap">
37 ${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=cs.short_id))}
37 ${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}
38 |
38 |
39 ${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=cs.short_id))}
39 ${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
40 </td>
40 </td>
41 </tr>
41 </tr>
42 %endfor
42 %endfor
43
43
44 </table>
44 </table>
45
45
46 <script type="text/javascript">
46 <script type="text/javascript">
47 var data_div = 'shortlog_data';
47 var data_div = 'shortlog_data';
48 YAHOO.util.Event.onDOMReady(function(){
48 YAHOO.util.Event.onDOMReady(function(){
49 YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
49 YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
50 YAHOO.util.Dom.setStyle('shortlog_data','opacity','0.3');});});
50 YAHOO.util.Dom.setStyle('shortlog_data','opacity','0.3');});});
51 </script>
51 </script>
52
52
53 <div class="pagination-wh pagination-left">
53 <div class="pagination-wh pagination-left">
54 ${c.repo_changesets.pager('$link_previous ~2~ $link_next',
54 ${c.repo_changesets.pager('$link_previous ~2~ $link_next',
55 onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
55 onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
56 success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
56 success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
57 YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
57 YAHOO.util.Event.addListener(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
58 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});
58 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});
59 YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
59 YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
60 </div>
60 </div>
61 %else:
61 %else:
62 ${_('There are no changes yet')}
62 ${_('There are no changes yet')}
63 %endif
63 %endif
@@ -1,584 +1,593 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('summary')}
12 ${_('summary')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('summary')}
16 ${self.menu('summary')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 <script type="text/javascript">
20 <script type="text/javascript">
21 var E = YAHOO.util.Event;
21 var E = YAHOO.util.Event;
22 var D = YAHOO.util.Dom;
22 var D = YAHOO.util.Dom;
23
23
24 E.onDOMReady(function(e){
24 E.onDOMReady(function(e){
25 id = 'clone_url';
25 id = 'clone_url';
26 E.addListener(id,'click',function(e){
26 E.addListener(id,'click',function(e){
27 D.get('clone_url').select();
27 D.get('clone_url').select();
28 })
28 })
29 })
29 })
30 </script>
30 </script>
31 <div class="box box-left">
31 <div class="box box-left">
32 <!-- box / title -->
32 <!-- box / title -->
33 <div class="title">
33 <div class="title">
34 ${self.breadcrumbs()}
34 ${self.breadcrumbs()}
35 </div>
35 </div>
36 <!-- end box / title -->
36 <!-- end box / title -->
37 <div class="form">
37 <div class="form">
38 <div class="fields">
38 <div class="fields">
39
39
40 <div class="field">
40 <div class="field">
41 <div class="label">
41 <div class="label">
42 <label>${_('Name')}:</label>
42 <label>${_('Name')}:</label>
43 </div>
43 </div>
44 <div class="input-short">
44 <div class="input-short">
45
46 %if c.repo_info.dbrepo.repo_type =='hg':
47 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
48 %elif c.repo_info.dbrepo.repo_type =='git':
49 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
50 %else:
51
52 %endif
53
45 %if c.repo_info.dbrepo.private:
54 %if c.repo_info.dbrepo.private:
46 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private')}" src="/images/icons/lock.png"/>
55 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
47 %else:
56 %else:
48 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public')}" src="/images/icons/lock_open.png"/>
57 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
49 %endif
58 %endif
50 <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo_info.name}</span>
59 <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo_info.name}</span>
51 <br/>
60 <br/>
52 %if c.repo_info.dbrepo.fork:
61 %if c.repo_info.dbrepo.fork:
53 <span style="margin-top:5px">
62 <span style="margin-top:5px">
54 <a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
63 <a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
55 <img class="icon" alt="${_('public')}"
64 <img class="icon" alt="${_('public')}"
56 title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}"
65 title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}"
57 src="/images/icons/arrow_divide.png"/>
66 src="/images/icons/arrow_divide.png"/>
58 ${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
67 ${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
59 </a>
68 </a>
60 </span>
69 </span>
61 %endif
70 %endif
62 </div>
71 </div>
63 </div>
72 </div>
64
73
65
74
66 <div class="field">
75 <div class="field">
67 <div class="label">
76 <div class="label">
68 <label>${_('Description')}:</label>
77 <label>${_('Description')}:</label>
69 </div>
78 </div>
70 <div class="input-short">
79 <div class="input-short">
71 ${c.repo_info.description}
80 ${c.repo_info.description}
72 </div>
81 </div>
73 </div>
82 </div>
74
83
75
84
76 <div class="field">
85 <div class="field">
77 <div class="label">
86 <div class="label">
78 <label>${_('Contact')}:</label>
87 <label>${_('Contact')}:</label>
79 </div>
88 </div>
80 <div class="input-short">
89 <div class="input-short">
81 <div class="gravatar">
90 <div class="gravatar">
82 <img alt="gravatar" src="${h.gravatar_url(c.repo_info.dbrepo.user.email)}"/>
91 <img alt="gravatar" src="${h.gravatar_url(c.repo_info.dbrepo.user.email)}"/>
83 </div>
92 </div>
84 ${_('Username')}: ${c.repo_info.dbrepo.user.username}<br/>
93 ${_('Username')}: ${c.repo_info.dbrepo.user.username}<br/>
85 ${_('Name')}: ${c.repo_info.dbrepo.user.name} ${c.repo_info.dbrepo.user.lastname}<br/>
94 ${_('Name')}: ${c.repo_info.dbrepo.user.name} ${c.repo_info.dbrepo.user.lastname}<br/>
86 ${_('Email')}: <a href="mailto:${c.repo_info.dbrepo.user.email}">${c.repo_info.dbrepo.user.email}</a>
95 ${_('Email')}: <a href="mailto:${c.repo_info.dbrepo.user.email}">${c.repo_info.dbrepo.user.email}</a>
87 </div>
96 </div>
88 </div>
97 </div>
89
98
90 <div class="field">
99 <div class="field">
91 <div class="label">
100 <div class="label">
92 <label>${_('Last change')}:</label>
101 <label>${_('Last change')}:</label>
93 </div>
102 </div>
94 <div class="input-short">
103 <div class="input-short">
95 ${h.age(c.repo_info.last_change)} - ${c.repo_info.last_change}
104 ${h.age(c.repo_info.last_change)} - ${c.repo_info.last_change}
96 ${_('by')} ${h.get_changeset_safe(c.repo_info,'tip').author}
105 ${_('by')} ${h.get_changeset_safe(c.repo_info,'tip').author}
97
106
98 </div>
107 </div>
99 </div>
108 </div>
100
109
101 <div class="field">
110 <div class="field">
102 <div class="label">
111 <div class="label">
103 <label>${_('Clone url')}:</label>
112 <label>${_('Clone url')}:</label>
104 </div>
113 </div>
105 <div class="input-short">
114 <div class="input-short">
106 <input type="text" id="clone_url" readonly="readonly" value="hg clone ${c.clone_repo_url}" size="70"/>
115 <input type="text" id="clone_url" readonly="readonly" value="hg clone ${c.clone_repo_url}" size="70"/>
107 </div>
116 </div>
108 </div>
117 </div>
109
118
110 <div class="field">
119 <div class="field">
111 <div class="label">
120 <div class="label">
112 <label>${_('Trending languages')}:</label>
121 <label>${_('Trending languages')}:</label>
113 </div>
122 </div>
114 <div class="input-short">
123 <div class="input-short">
115 <div id="lang_stats">
124 <div id="lang_stats">
116
125
117 </div>
126 </div>
118 <script type="text/javascript">
127 <script type="text/javascript">
119 var data = ${c.trending_languages|n};
128 var data = ${c.trending_languages|n};
120 var total = 0;
129 var total = 0;
121 var no_data = true;
130 var no_data = true;
122 for (k in data){
131 for (k in data){
123 total += data[k];
132 total += data[k];
124 no_data = false;
133 no_data = false;
125 }
134 }
126 var tbl = document.createElement('table');
135 var tbl = document.createElement('table');
127 tbl.setAttribute('class','trending_language_tbl');
136 tbl.setAttribute('class','trending_language_tbl');
128 for (k in data){
137 for (k in data){
129 var tr = document.createElement('tr');
138 var tr = document.createElement('tr');
130 var percentage = Math.round((data[k]/total*100),2);
139 var percentage = Math.round((data[k]/total*100),2);
131 var value = data[k];
140 var value = data[k];
132 var td1 = document.createElement('td');
141 var td1 = document.createElement('td');
133 td1.width=150;
142 td1.width=150;
134 var trending_language_label = document.createElement('div');
143 var trending_language_label = document.createElement('div');
135 trending_language_label.innerHTML = k;
144 trending_language_label.innerHTML = k;
136 td1.appendChild(trending_language_label);
145 td1.appendChild(trending_language_label);
137
146
138 var td2 = document.createElement('td');
147 var td2 = document.createElement('td');
139 var trending_language = document.createElement('div');
148 var trending_language = document.createElement('div');
140 trending_language.title = k;
149 trending_language.title = k;
141 trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>";
150 trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>";
142 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
151 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
143 trending_language.style.width=percentage+"%";
152 trending_language.style.width=percentage+"%";
144 td2.appendChild(trending_language);
153 td2.appendChild(trending_language);
145
154
146 tr.appendChild(td1);
155 tr.appendChild(td1);
147 tr.appendChild(td2);
156 tr.appendChild(td2);
148 tbl.appendChild(tr);
157 tbl.appendChild(tr);
149
158
150 }
159 }
151 if(no_data){
160 if(no_data){
152 var tr = document.createElement('tr');
161 var tr = document.createElement('tr');
153 var td1 = document.createElement('td');
162 var td1 = document.createElement('td');
154 td1.innerHTML = "${_('No data loaded yet')}";
163 td1.innerHTML = "${_('No data loaded yet')}";
155 tr.appendChild(td1);
164 tr.appendChild(td1);
156 tbl.appendChild(tr);
165 tbl.appendChild(tr);
157 }
166 }
158 YAHOO.util.Dom.get('lang_stats').appendChild(tbl);
167 YAHOO.util.Dom.get('lang_stats').appendChild(tbl);
159 </script>
168 </script>
160
169
161 </div>
170 </div>
162 </div>
171 </div>
163
172
164 <div class="field">
173 <div class="field">
165 <div class="label">
174 <div class="label">
166 <label>${_('Download')}:</label>
175 <label>${_('Download')}:</label>
167 </div>
176 </div>
168 <div class="input-short">
177 <div class="input-short">
169 %for cnt,archive in enumerate(c.repo_info._get_archives()):
178 %for cnt,archive in enumerate(c.repo_info._get_archives()):
170 %if cnt >=1:
179 %if cnt >=1:
171 |
180 |
172 %endif
181 %endif
173 ${h.link_to(c.repo_info.name+'.'+archive['type'],
182 ${h.link_to(c.repo_info.name+'.'+archive['type'],
174 h.url('files_archive_home',repo_name=c.repo_info.name,
183 h.url('files_archive_home',repo_name=c.repo_info.name,
175 revision='tip',fileformat=archive['extension']),class_="archive_icon")}
184 revision='tip',fileformat=archive['extension']),class_="archive_icon")}
176 %endfor
185 %endfor
177 </div>
186 </div>
178 </div>
187 </div>
179
188
180 <div class="field">
189 <div class="field">
181 <div class="label">
190 <div class="label">
182 <label>${_('Feeds')}:</label>
191 <label>${_('Feeds')}:</label>
183 </div>
192 </div>
184 <div class="input-short">
193 <div class="input-short">
185 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo_info.name),class_='rss_icon')}
194 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo_info.name),class_='rss_icon')}
186 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo_info.name),class_='atom_icon')}
195 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo_info.name),class_='atom_icon')}
187 </div>
196 </div>
188 </div>
197 </div>
189 </div>
198 </div>
190 </div>
199 </div>
191 </div>
200 </div>
192
201
193 <div class="box box-right" style="min-height:455px">
202 <div class="box box-right" style="min-height:455px">
194 <!-- box / title -->
203 <!-- box / title -->
195 <div class="title">
204 <div class="title">
196 <h5>${_('Commit activity by day / author')}</h5>
205 <h5>${_('Commit activity by day / author')}</h5>
197 </div>
206 </div>
198
207
199 <div class="table">
208 <div class="table">
200 <div id="commit_history" style="width:560px;height:300px;float:left"></div>
209 <div id="commit_history" style="width:560px;height:300px;float:left"></div>
201 <div style="clear: both;height: 10px"></div>
210 <div style="clear: both;height: 10px"></div>
202 <div id="overview" style="width:560px;height:100px;float:left"></div>
211 <div id="overview" style="width:560px;height:100px;float:left"></div>
203
212
204 <div id="legend_data" style="clear:both;margin-top:10px;">
213 <div id="legend_data" style="clear:both;margin-top:10px;">
205 <div id="legend_container"></div>
214 <div id="legend_container"></div>
206 <div id="legend_choices">
215 <div id="legend_choices">
207 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
216 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
208 </div>
217 </div>
209 </div>
218 </div>
210 <script type="text/javascript">
219 <script type="text/javascript">
211 /**
220 /**
212 * Plots summary graph
221 * Plots summary graph
213 *
222 *
214 * @class SummaryPlot
223 * @class SummaryPlot
215 * @param {from} initial from for detailed graph
224 * @param {from} initial from for detailed graph
216 * @param {to} initial to for detailed graph
225 * @param {to} initial to for detailed graph
217 * @param {dataset}
226 * @param {dataset}
218 * @param {overview_dataset}
227 * @param {overview_dataset}
219 */
228 */
220 function SummaryPlot(from,to,dataset,overview_dataset) {
229 function SummaryPlot(from,to,dataset,overview_dataset) {
221 var initial_ranges = {
230 var initial_ranges = {
222 "xaxis":{
231 "xaxis":{
223 "from":from,
232 "from":from,
224 "to":to,
233 "to":to,
225 },
234 },
226 };
235 };
227 var dataset = dataset;
236 var dataset = dataset;
228 var overview_dataset = [overview_dataset];
237 var overview_dataset = [overview_dataset];
229 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
238 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
230 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
239 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
231 var plotContainer = YAHOO.util.Dom.get('commit_history');
240 var plotContainer = YAHOO.util.Dom.get('commit_history');
232 var overviewContainer = YAHOO.util.Dom.get('overview');
241 var overviewContainer = YAHOO.util.Dom.get('overview');
233
242
234 var plot_options = {
243 var plot_options = {
235 bars: {show:true,align:'center',lineWidth:4},
244 bars: {show:true,align:'center',lineWidth:4},
236 legend: {show:true, container:"legend_container"},
245 legend: {show:true, container:"legend_container"},
237 points: {show:true,radius:0,fill:false},
246 points: {show:true,radius:0,fill:false},
238 yaxis: {tickDecimals:0,},
247 yaxis: {tickDecimals:0,},
239 xaxis: {
248 xaxis: {
240 mode: "time",
249 mode: "time",
241 timeformat: "%d/%m",
250 timeformat: "%d/%m",
242 min:from,
251 min:from,
243 max:to,
252 max:to,
244 },
253 },
245 grid: {
254 grid: {
246 hoverable: true,
255 hoverable: true,
247 clickable: true,
256 clickable: true,
248 autoHighlight:true,
257 autoHighlight:true,
249 color: "#999"
258 color: "#999"
250 },
259 },
251 //selection: {mode: "x"}
260 //selection: {mode: "x"}
252 };
261 };
253 var overview_options = {
262 var overview_options = {
254 legend:{show:false},
263 legend:{show:false},
255 bars: {show:true,barWidth: 2,},
264 bars: {show:true,barWidth: 2,},
256 shadowSize: 0,
265 shadowSize: 0,
257 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
266 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
258 yaxis: {ticks: 3, min: 0,},
267 yaxis: {ticks: 3, min: 0,},
259 grid: {color: "#999",},
268 grid: {color: "#999",},
260 selection: {mode: "x"}
269 selection: {mode: "x"}
261 };
270 };
262
271
263 /**
272 /**
264 *get dummy data needed in few places
273 *get dummy data needed in few places
265 */
274 */
266 function getDummyData(label){
275 function getDummyData(label){
267 return {"label":label,
276 return {"label":label,
268 "data":[{"time":0,
277 "data":[{"time":0,
269 "commits":0,
278 "commits":0,
270 "added":0,
279 "added":0,
271 "changed":0,
280 "changed":0,
272 "removed":0,
281 "removed":0,
273 }],
282 }],
274 "schema":["commits"],
283 "schema":["commits"],
275 "color":'#ffffff',
284 "color":'#ffffff',
276 }
285 }
277 }
286 }
278
287
279 /**
288 /**
280 * generate checkboxes accordindly to data
289 * generate checkboxes accordindly to data
281 * @param keys
290 * @param keys
282 * @returns
291 * @returns
283 */
292 */
284 function generateCheckboxes(data) {
293 function generateCheckboxes(data) {
285 //append checkboxes
294 //append checkboxes
286 var i = 0;
295 var i = 0;
287 choiceContainerTable.innerHTML = '';
296 choiceContainerTable.innerHTML = '';
288 for(var pos in data) {
297 for(var pos in data) {
289
298
290 data[pos].color = i;
299 data[pos].color = i;
291 i++;
300 i++;
292 if(data[pos].label != ''){
301 if(data[pos].label != ''){
293 choiceContainerTable.innerHTML += '<tr><td>'+
302 choiceContainerTable.innerHTML += '<tr><td>'+
294 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
303 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
295 +data[pos].label+
304 +data[pos].label+
296 '</td></tr>';
305 '</td></tr>';
297 }
306 }
298 }
307 }
299 }
308 }
300
309
301 /**
310 /**
302 * ToolTip show
311 * ToolTip show
303 */
312 */
304 function showTooltip(x, y, contents) {
313 function showTooltip(x, y, contents) {
305 var div=document.getElementById('tooltip');
314 var div=document.getElementById('tooltip');
306 if(!div) {
315 if(!div) {
307 div = document.createElement('div');
316 div = document.createElement('div');
308 div.id="tooltip";
317 div.id="tooltip";
309 div.style.position="absolute";
318 div.style.position="absolute";
310 div.style.border='1px solid #fdd';
319 div.style.border='1px solid #fdd';
311 div.style.padding='2px';
320 div.style.padding='2px';
312 div.style.backgroundColor='#fee';
321 div.style.backgroundColor='#fee';
313 document.body.appendChild(div);
322 document.body.appendChild(div);
314 }
323 }
315 YAHOO.util.Dom.setStyle(div, 'opacity', 0);
324 YAHOO.util.Dom.setStyle(div, 'opacity', 0);
316 div.innerHTML = contents;
325 div.innerHTML = contents;
317 div.style.top=(y + 5) + "px";
326 div.style.top=(y + 5) + "px";
318 div.style.left=(x + 5) + "px";
327 div.style.left=(x + 5) + "px";
319
328
320 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
329 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
321 anim.animate();
330 anim.animate();
322 }
331 }
323
332
324 /**
333 /**
325 * This function will detect if selected period has some changesets for this user
334 * This function will detect if selected period has some changesets for this user
326 if it does this data is then pushed for displaying
335 if it does this data is then pushed for displaying
327 Additionally it will only display users that are selected by the checkbox
336 Additionally it will only display users that are selected by the checkbox
328 */
337 */
329 function getDataAccordingToRanges(ranges) {
338 function getDataAccordingToRanges(ranges) {
330
339
331 var data = [];
340 var data = [];
332 var keys = [];
341 var keys = [];
333 for(var key in dataset){
342 for(var key in dataset){
334 var push = false;
343 var push = false;
335 //method1 slow !!
344 //method1 slow !!
336 ///*
345 ///*
337 for(var ds in dataset[key].data){
346 for(var ds in dataset[key].data){
338 commit_data = dataset[key].data[ds];
347 commit_data = dataset[key].data[ds];
339 //console.log(key);
348 //console.log(key);
340 //console.log(new Date(commit_data.time*1000));
349 //console.log(new Date(commit_data.time*1000));
341 //console.log(new Date(ranges.xaxis.from*1000));
350 //console.log(new Date(ranges.xaxis.from*1000));
342 //console.log(new Date(ranges.xaxis.to*1000));
351 //console.log(new Date(ranges.xaxis.to*1000));
343 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
352 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
344 push = true;
353 push = true;
345 break;
354 break;
346 }
355 }
347 }
356 }
348 //*/
357 //*/
349 /*//method2 sorted commit data !!!
358 /*//method2 sorted commit data !!!
350 var first_commit = dataset[key].data[0].time;
359 var first_commit = dataset[key].data[0].time;
351 var last_commit = dataset[key].data[dataset[key].data.length-1].time;
360 var last_commit = dataset[key].data[dataset[key].data.length-1].time;
352
361
353 console.log(first_commit);
362 console.log(first_commit);
354 console.log(last_commit);
363 console.log(last_commit);
355
364
356 if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
365 if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
357 push = true;
366 push = true;
358 }
367 }
359 */
368 */
360 if(push){
369 if(push){
361 data.push(dataset[key]);
370 data.push(dataset[key]);
362 }
371 }
363 }
372 }
364 if(data.length >= 1){
373 if(data.length >= 1){
365 return data;
374 return data;
366 }
375 }
367 else{
376 else{
368 //just return dummy data for graph to plot itself
377 //just return dummy data for graph to plot itself
369 return [getDummyData('')];
378 return [getDummyData('')];
370 }
379 }
371
380
372 }
381 }
373
382
374 /**
383 /**
375 * redraw using new checkbox data
384 * redraw using new checkbox data
376 */
385 */
377 function plotchoiced(e,args){
386 function plotchoiced(e,args){
378 var cur_data = args[0];
387 var cur_data = args[0];
379 var cur_ranges = args[1];
388 var cur_ranges = args[1];
380
389
381 var new_data = [];
390 var new_data = [];
382 var inputs = choiceContainer.getElementsByTagName("input");
391 var inputs = choiceContainer.getElementsByTagName("input");
383
392
384 //show only checked labels
393 //show only checked labels
385 for(var i=0; i<inputs.length; i++) {
394 for(var i=0; i<inputs.length; i++) {
386 var checkbox_key = inputs[i].name;
395 var checkbox_key = inputs[i].name;
387
396
388 if(inputs[i].checked){
397 if(inputs[i].checked){
389 for(var d in cur_data){
398 for(var d in cur_data){
390 if(cur_data[d].label == checkbox_key){
399 if(cur_data[d].label == checkbox_key){
391 new_data.push(cur_data[d]);
400 new_data.push(cur_data[d]);
392 }
401 }
393 }
402 }
394 }
403 }
395 else{
404 else{
396 //push dummy data to not hide the label
405 //push dummy data to not hide the label
397 new_data.push(getDummyData(checkbox_key));
406 new_data.push(getDummyData(checkbox_key));
398 }
407 }
399 }
408 }
400
409
401 var new_options = YAHOO.lang.merge(plot_options, {
410 var new_options = YAHOO.lang.merge(plot_options, {
402 xaxis: {
411 xaxis: {
403 min: cur_ranges.xaxis.from,
412 min: cur_ranges.xaxis.from,
404 max: cur_ranges.xaxis.to,
413 max: cur_ranges.xaxis.to,
405 mode:"time",
414 mode:"time",
406 timeformat: "%d/%m",
415 timeformat: "%d/%m",
407 }
416 }
408 });
417 });
409 if (!new_data){
418 if (!new_data){
410 new_data = [[0,1]];
419 new_data = [[0,1]];
411 }
420 }
412 // do the zooming
421 // do the zooming
413 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
422 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
414
423
415 plot.subscribe("plotselected", plotselected);
424 plot.subscribe("plotselected", plotselected);
416
425
417 //resubscribe plothover
426 //resubscribe plothover
418 plot.subscribe("plothover", plothover);
427 plot.subscribe("plothover", plothover);
419
428
420 // don't fire event on the overview to prevent eternal loop
429 // don't fire event on the overview to prevent eternal loop
421 overview.setSelection(cur_ranges, true);
430 overview.setSelection(cur_ranges, true);
422
431
423 }
432 }
424
433
425 /**
434 /**
426 * plot only selected items from overview
435 * plot only selected items from overview
427 * @param ranges
436 * @param ranges
428 * @returns
437 * @returns
429 */
438 */
430 function plotselected(ranges,cur_data) {
439 function plotselected(ranges,cur_data) {
431 //updates the data for new plot
440 //updates the data for new plot
432 data = getDataAccordingToRanges(ranges);
441 data = getDataAccordingToRanges(ranges);
433 generateCheckboxes(data);
442 generateCheckboxes(data);
434
443
435 var new_options = YAHOO.lang.merge(plot_options, {
444 var new_options = YAHOO.lang.merge(plot_options, {
436 xaxis: {
445 xaxis: {
437 min: ranges.xaxis.from,
446 min: ranges.xaxis.from,
438 max: ranges.xaxis.to,
447 max: ranges.xaxis.to,
439 mode:"time",
448 mode:"time",
440 timeformat: "%d/%m",
449 timeformat: "%d/%m",
441 }
450 }
442 });
451 });
443 // do the zooming
452 // do the zooming
444 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
453 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
445
454
446 plot.subscribe("plotselected", plotselected);
455 plot.subscribe("plotselected", plotselected);
447
456
448 //resubscribe plothover
457 //resubscribe plothover
449 plot.subscribe("plothover", plothover);
458 plot.subscribe("plothover", plothover);
450
459
451 // don't fire event on the overview to prevent eternal loop
460 // don't fire event on the overview to prevent eternal loop
452 overview.setSelection(ranges, true);
461 overview.setSelection(ranges, true);
453
462
454 //resubscribe choiced
463 //resubscribe choiced
455 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
464 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
456 }
465 }
457
466
458 var previousPoint = null;
467 var previousPoint = null;
459
468
460 function plothover(o) {
469 function plothover(o) {
461 var pos = o.pos;
470 var pos = o.pos;
462 var item = o.item;
471 var item = o.item;
463
472
464 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
473 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
465 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
474 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
466 if (item) {
475 if (item) {
467 if (previousPoint != item.datapoint) {
476 if (previousPoint != item.datapoint) {
468 previousPoint = item.datapoint;
477 previousPoint = item.datapoint;
469
478
470 var tooltip = YAHOO.util.Dom.get("tooltip");
479 var tooltip = YAHOO.util.Dom.get("tooltip");
471 if(tooltip) {
480 if(tooltip) {
472 tooltip.parentNode.removeChild(tooltip);
481 tooltip.parentNode.removeChild(tooltip);
473 }
482 }
474 var x = item.datapoint.x.toFixed(2);
483 var x = item.datapoint.x.toFixed(2);
475 var y = item.datapoint.y.toFixed(2);
484 var y = item.datapoint.y.toFixed(2);
476
485
477 if (!item.series.label){
486 if (!item.series.label){
478 item.series.label = 'commits';
487 item.series.label = 'commits';
479 }
488 }
480 var d = new Date(x*1000);
489 var d = new Date(x*1000);
481 var fd = d.toDateString()
490 var fd = d.toDateString()
482 var nr_commits = parseInt(y);
491 var nr_commits = parseInt(y);
483
492
484 var cur_data = dataset[item.series.label].data[item.dataIndex];
493 var cur_data = dataset[item.series.label].data[item.dataIndex];
485 var added = cur_data.added;
494 var added = cur_data.added;
486 var changed = cur_data.changed;
495 var changed = cur_data.changed;
487 var removed = cur_data.removed;
496 var removed = cur_data.removed;
488
497
489 var nr_commits_suffix = " ${_('commits')} ";
498 var nr_commits_suffix = " ${_('commits')} ";
490 var added_suffix = " ${_('files added')} ";
499 var added_suffix = " ${_('files added')} ";
491 var changed_suffix = " ${_('files changed')} ";
500 var changed_suffix = " ${_('files changed')} ";
492 var removed_suffix = " ${_('files removed')} ";
501 var removed_suffix = " ${_('files removed')} ";
493
502
494
503
495 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
504 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
496 if(added==1){added_suffix=" ${_('file added')} ";}
505 if(added==1){added_suffix=" ${_('file added')} ";}
497 if(changed==1){changed_suffix=" ${_('file changed')} ";}
506 if(changed==1){changed_suffix=" ${_('file changed')} ";}
498 if(removed==1){removed_suffix=" ${_('file removed')} ";}
507 if(removed==1){removed_suffix=" ${_('file removed')} ";}
499
508
500 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
509 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
501 +'<br/>'+
510 +'<br/>'+
502 nr_commits + nr_commits_suffix+'<br/>'+
511 nr_commits + nr_commits_suffix+'<br/>'+
503 added + added_suffix +'<br/>'+
512 added + added_suffix +'<br/>'+
504 changed + changed_suffix + '<br/>'+
513 changed + changed_suffix + '<br/>'+
505 removed + removed_suffix + '<br/>');
514 removed + removed_suffix + '<br/>');
506 }
515 }
507 }
516 }
508 else {
517 else {
509 var tooltip = YAHOO.util.Dom.get("tooltip");
518 var tooltip = YAHOO.util.Dom.get("tooltip");
510
519
511 if(tooltip) {
520 if(tooltip) {
512 tooltip.parentNode.removeChild(tooltip);
521 tooltip.parentNode.removeChild(tooltip);
513 }
522 }
514 previousPoint = null;
523 previousPoint = null;
515 }
524 }
516 }
525 }
517
526
518 /**
527 /**
519 * MAIN EXECUTION
528 * MAIN EXECUTION
520 */
529 */
521
530
522 var data = getDataAccordingToRanges(initial_ranges);
531 var data = getDataAccordingToRanges(initial_ranges);
523 generateCheckboxes(data);
532 generateCheckboxes(data);
524
533
525 //main plot
534 //main plot
526 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
535 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
527
536
528 //overview
537 //overview
529 var overview = YAHOO.widget.Flot(overviewContainer, overview_dataset, overview_options);
538 var overview = YAHOO.widget.Flot(overviewContainer, overview_dataset, overview_options);
530
539
531 //show initial selection on overview
540 //show initial selection on overview
532 overview.setSelection(initial_ranges);
541 overview.setSelection(initial_ranges);
533
542
534 plot.subscribe("plotselected", plotselected);
543 plot.subscribe("plotselected", plotselected);
535
544
536 overview.subscribe("plotselected", function (ranges) {
545 overview.subscribe("plotselected", function (ranges) {
537 plot.setSelection(ranges);
546 plot.setSelection(ranges);
538 });
547 });
539
548
540 plot.subscribe("plothover", plothover);
549 plot.subscribe("plothover", plothover);
541
550
542 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
551 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
543 }
552 }
544 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
553 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
545 </script>
554 </script>
546
555
547 </div>
556 </div>
548 </div>
557 </div>
549
558
550 <div class="box">
559 <div class="box">
551 <div class="title">
560 <div class="title">
552 <div class="breadcrumbs">${h.link_to(_('Last ten changes'),h.url('changelog_home',repo_name=c.repo_name))}</div>
561 <div class="breadcrumbs">${h.link_to(_('Last ten changes'),h.url('changelog_home',repo_name=c.repo_name))}</div>
553 </div>
562 </div>
554 <div class="table">
563 <div class="table">
555 <%include file='../shortlog/shortlog_data.html'/>
564 <%include file='../shortlog/shortlog_data.html'/>
556 %if c.repo_changesets:
565 %if c.repo_changesets:
557 ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
566 ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
558 %endif
567 %endif
559 </div>
568 </div>
560 </div>
569 </div>
561 <div class="box">
570 <div class="box">
562 <div class="title">
571 <div class="title">
563 <div class="breadcrumbs">${h.link_to(_('Last ten tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
572 <div class="breadcrumbs">${h.link_to(_('Last ten tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
564 </div>
573 </div>
565 <div class="table">
574 <div class="table">
566 <%include file='../tags/tags_data.html'/>
575 <%include file='../tags/tags_data.html'/>
567 %if c.repo_changesets:
576 %if c.repo_changesets:
568 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
577 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
569 %endif
578 %endif
570 </div>
579 </div>
571 </div>
580 </div>
572 <div class="box">
581 <div class="box">
573 <div class="title">
582 <div class="title">
574 <div class="breadcrumbs">${h.link_to(_('Last ten branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
583 <div class="breadcrumbs">${h.link_to(_('Last ten branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
575 </div>
584 </div>
576 <div class="table">
585 <div class="table">
577 <%include file='../branches/branches_data.html'/>
586 <%include file='../branches/branches_data.html'/>
578 %if c.repo_changesets:
587 %if c.repo_changesets:
579 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
588 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
580 %endif
589 %endif
581 </div>
590 </div>
582 </div>
591 </div>
583
592
584 </%def> No newline at end of file
593 </%def>
@@ -1,29 +1,31 b''
1 %if c.repo_tags:
1 %if c.repo_tags:
2 <table>
2 <table>
3 <tr>
3 <tr>
4 <th class="left">${_('date')}</th>
4 <th class="left">${_('date')}</th>
5 <th class="left">${_('revision')}</th>
5 <th class="left">${_('name')}</th>
6 <th class="left">${_('name')}</th>
6 <th class="left">${_('author')}</th>
7 <th class="left">${_('revision')}</th>
7 <th class="left">${_('links')}</th>
8 <th class="left">${_('links')}</th>
8 </tr>
9 </tr>
9 %for cnt,tag in enumerate(c.repo_tags.items()):
10 %for cnt,tag in enumerate(c.repo_tags.items()):
10 <tr class="parity${cnt%2}">
11 <tr class="parity${cnt%2}">
11 <td>${h.age(tag[1].date)}</td>
12 <td>${tag[1].date} - ${h.age(tag[1].date)}</td>
12 <td>r${tag[1].revision}:${tag[1].short_id}</td>
13 <td>
13 <td>
14 <span class="logtags">
14 <span class="logtags">
15 <span class="tagtag">${h.link_to(tag[0],
15 <span class="tagtag">${h.link_to(tag[0],
16 h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].raw_id))}</span>
16 h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].short_id))}</span>
17 </span>
17 </span>
18 </td>
18 </td>
19 <td title="${tag[1].author}">${h.person(tag[1].author)}</td>
20 <td>r${tag[1].revision}:${h.short_id(tag[1].raw_id)}</td>
19 <td class="nowrap">
21 <td class="nowrap">
20 ${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].short_id))}
22 ${h.link_to(_('changeset'),h.url('changeset_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
21 |
23 |
22 ${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=tag[1].short_id))}
24 ${h.link_to(_('files'),h.url('files_home',repo_name=c.repo_name,revision=tag[1].raw_id))}
23 </td>
25 </td>
24 </tr>
26 </tr>
25 %endfor
27 %endfor
26 </table>
28 </table>
27 %else:
29 %else:
28 ${_('There are no tags yet')}
30 ${_('There are no tags yet')}
29 %endif No newline at end of file
31 %endif
General Comments 0
You need to be logged in to leave comments. Login now