Show More
@@ -1,366 +1,366 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.controllers.admin.repos_groups |
|
3 | rhodecode.controllers.admin.repos_groups | |
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | Repositories groups controller for RhodeCode |
|
6 | Repositories groups controller for RhodeCode | |
7 |
|
7 | |||
8 | :created_on: Mar 23, 2010 |
|
8 | :created_on: Mar 23, 2010 | |
9 | :author: marcink |
|
9 | :author: marcink | |
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> |
|
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> | |
11 | :license: GPLv3, see COPYING for more details. |
|
11 | :license: GPLv3, see COPYING for more details. | |
12 | """ |
|
12 | """ | |
13 | # This program is free software: you can redistribute it and/or modify |
|
13 | # This program is free software: you can redistribute it and/or modify | |
14 | # it under the terms of the GNU General Public License as published by |
|
14 | # it under the terms of the GNU General Public License as published by | |
15 | # the Free Software Foundation, either version 3 of the License, or |
|
15 | # the Free Software Foundation, either version 3 of the License, or | |
16 | # (at your option) any later version. |
|
16 | # (at your option) any later version. | |
17 | # |
|
17 | # | |
18 | # This program is distributed in the hope that it will be useful, |
|
18 | # This program is distributed in the hope that it will be useful, | |
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | # GNU General Public License for more details. |
|
21 | # GNU General Public License for more details. | |
22 | # |
|
22 | # | |
23 | # You should have received a copy of the GNU General Public License |
|
23 | # You should have received a copy of the GNU General Public License | |
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 |
|
25 | |||
26 | import logging |
|
26 | import logging | |
27 | import traceback |
|
27 | import traceback | |
28 | import formencode |
|
28 | import formencode | |
29 |
|
29 | |||
30 | from formencode import htmlfill |
|
30 | from formencode import htmlfill | |
31 |
|
31 | |||
32 | from pylons import request, tmpl_context as c, url |
|
32 | from pylons import request, tmpl_context as c, url | |
33 | from pylons.controllers.util import redirect |
|
33 | from pylons.controllers.util import redirect | |
34 | from pylons.i18n.translation import _ |
|
34 | from pylons.i18n.translation import _ | |
35 |
|
35 | |||
36 | from sqlalchemy.exc import IntegrityError |
|
36 | from sqlalchemy.exc import IntegrityError | |
37 |
|
37 | |||
38 | import rhodecode |
|
38 | import rhodecode | |
39 | from rhodecode.lib import helpers as h |
|
39 | from rhodecode.lib import helpers as h | |
40 | from rhodecode.lib.ext_json import json |
|
40 | from rhodecode.lib.ext_json import json | |
41 | from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\ |
|
41 | from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\ | |
42 | HasReposGroupPermissionAnyDecorator |
|
42 | HasReposGroupPermissionAnyDecorator | |
43 | from rhodecode.lib.base import BaseController, render |
|
43 | from rhodecode.lib.base import BaseController, render | |
44 | from rhodecode.model.db import RepoGroup, Repository |
|
44 | from rhodecode.model.db import RepoGroup, Repository | |
45 | from rhodecode.model.repos_group import ReposGroupModel |
|
45 | from rhodecode.model.repos_group import ReposGroupModel | |
46 | from rhodecode.model.forms import ReposGroupForm |
|
46 | from rhodecode.model.forms import ReposGroupForm | |
47 | from rhodecode.model.meta import Session |
|
47 | from rhodecode.model.meta import Session | |
48 | from rhodecode.model.repo import RepoModel |
|
48 | from rhodecode.model.repo import RepoModel | |
49 | from webob.exc import HTTPInternalServerError, HTTPNotFound |
|
49 | from webob.exc import HTTPInternalServerError, HTTPNotFound | |
50 | from rhodecode.lib.utils2 import str2bool |
|
50 | from rhodecode.lib.utils2 import str2bool | |
51 | from sqlalchemy.sql.expression import func |
|
51 | from sqlalchemy.sql.expression import func | |
52 |
|
52 | |||
53 | log = logging.getLogger(__name__) |
|
53 | log = logging.getLogger(__name__) | |
54 |
|
54 | |||
55 |
|
55 | |||
56 | class ReposGroupsController(BaseController): |
|
56 | class ReposGroupsController(BaseController): | |
57 | """REST Controller styled on the Atom Publishing Protocol""" |
|
57 | """REST Controller styled on the Atom Publishing Protocol""" | |
58 | # To properly map this controller, ensure your config/routing.py |
|
58 | # To properly map this controller, ensure your config/routing.py | |
59 | # file has a resource setup: |
|
59 | # file has a resource setup: | |
60 | # map.resource('repos_group', 'repos_groups') |
|
60 | # map.resource('repos_group', 'repos_groups') | |
61 |
|
61 | |||
62 | @LoginRequired() |
|
62 | @LoginRequired() | |
63 | def __before__(self): |
|
63 | def __before__(self): | |
64 | super(ReposGroupsController, self).__before__() |
|
64 | super(ReposGroupsController, self).__before__() | |
65 |
|
65 | |||
66 | def __load_defaults(self): |
|
66 | def __load_defaults(self): | |
67 | c.repo_groups = RepoGroup.groups_choices() |
|
67 | c.repo_groups = RepoGroup.groups_choices() | |
68 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) |
|
68 | c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups) | |
69 |
|
69 | |||
70 | repo_model = RepoModel() |
|
70 | repo_model = RepoModel() | |
71 | c.users_array = repo_model.get_users_js() |
|
71 | c.users_array = repo_model.get_users_js() | |
72 | c.users_groups_array = repo_model.get_users_groups_js() |
|
72 | c.users_groups_array = repo_model.get_users_groups_js() | |
73 |
|
73 | |||
74 | def __load_data(self, group_id): |
|
74 | def __load_data(self, group_id): | |
75 | """ |
|
75 | """ | |
76 | Load defaults settings for edit, and update |
|
76 | Load defaults settings for edit, and update | |
77 |
|
77 | |||
78 | :param group_id: |
|
78 | :param group_id: | |
79 | """ |
|
79 | """ | |
80 | self.__load_defaults() |
|
80 | self.__load_defaults() | |
81 | repo_group = RepoGroup.get_or_404(group_id) |
|
81 | repo_group = RepoGroup.get_or_404(group_id) | |
82 | data = repo_group.get_dict() |
|
82 | data = repo_group.get_dict() | |
83 | data['group_name'] = repo_group.name |
|
83 | data['group_name'] = repo_group.name | |
84 |
|
84 | |||
85 | # fill repository users |
|
85 | # fill repository users | |
86 | for p in repo_group.repo_group_to_perm: |
|
86 | for p in repo_group.repo_group_to_perm: | |
87 | data.update({'u_perm_%s' % p.user.username: |
|
87 | data.update({'u_perm_%s' % p.user.username: | |
88 | p.permission.permission_name}) |
|
88 | p.permission.permission_name}) | |
89 |
|
89 | |||
90 | # fill repository groups |
|
90 | # fill repository groups | |
91 | for p in repo_group.users_group_to_perm: |
|
91 | for p in repo_group.users_group_to_perm: | |
92 | data.update({'g_perm_%s' % p.users_group.users_group_name: |
|
92 | data.update({'g_perm_%s' % p.users_group.users_group_name: | |
93 | p.permission.permission_name}) |
|
93 | p.permission.permission_name}) | |
94 |
|
94 | |||
95 | return data |
|
95 | return data | |
96 |
|
96 | |||
97 | @HasPermissionAnyDecorator('hg.admin') |
|
97 | @HasPermissionAnyDecorator('hg.admin') | |
98 | def index(self, format='html'): |
|
98 | def index(self, format='html'): | |
99 | """GET /repos_groups: All items in the collection""" |
|
99 | """GET /repos_groups: All items in the collection""" | |
100 | # url('repos_groups') |
|
100 | # url('repos_groups') | |
101 | sk = lambda g: g.parents[0].group_name if g.parents else g.group_name |
|
101 | sk = lambda g: g.parents[0].group_name if g.parents else g.group_name | |
102 | c.groups = sorted(RepoGroup.query().all(), key=sk) |
|
102 | c.groups = sorted(RepoGroup.query().all(), key=sk) | |
103 | return render('admin/repos_groups/repos_groups_show.html') |
|
103 | return render('admin/repos_groups/repos_groups_show.html') | |
104 |
|
104 | |||
105 | @HasPermissionAnyDecorator('hg.admin') |
|
105 | @HasPermissionAnyDecorator('hg.admin') | |
106 | def create(self): |
|
106 | def create(self): | |
107 | """POST /repos_groups: Create a new item""" |
|
107 | """POST /repos_groups: Create a new item""" | |
108 | # url('repos_groups') |
|
108 | # url('repos_groups') | |
109 | self.__load_defaults() |
|
109 | self.__load_defaults() | |
110 | repos_group_form = ReposGroupForm(available_groups = |
|
110 | repos_group_form = ReposGroupForm(available_groups = | |
111 | c.repo_groups_choices)() |
|
111 | c.repo_groups_choices)() | |
112 | try: |
|
112 | try: | |
113 | form_result = repos_group_form.to_python(dict(request.POST)) |
|
113 | form_result = repos_group_form.to_python(dict(request.POST)) | |
114 | ReposGroupModel().create( |
|
114 | ReposGroupModel().create( | |
115 | group_name=form_result['group_name'], |
|
115 | group_name=form_result['group_name'], | |
116 | group_description=form_result['group_description'], |
|
116 | group_description=form_result['group_description'], | |
117 | parent=form_result['group_parent_id'] |
|
117 | parent=form_result['group_parent_id'] | |
118 | ) |
|
118 | ) | |
119 | Session().commit() |
|
119 | Session().commit() | |
120 | h.flash(_('created repos group %s') \ |
|
120 | h.flash(_('created repos group %s') \ | |
121 | % form_result['group_name'], category='success') |
|
121 | % form_result['group_name'], category='success') | |
122 | #TODO: in futureaction_logger(, '', '', '', self.sa) |
|
122 | #TODO: in futureaction_logger(, '', '', '', self.sa) | |
123 | except formencode.Invalid, errors: |
|
123 | except formencode.Invalid, errors: | |
124 |
|
124 | |||
125 | return htmlfill.render( |
|
125 | return htmlfill.render( | |
126 | render('admin/repos_groups/repos_groups_add.html'), |
|
126 | render('admin/repos_groups/repos_groups_add.html'), | |
127 | defaults=errors.value, |
|
127 | defaults=errors.value, | |
128 | errors=errors.error_dict or {}, |
|
128 | errors=errors.error_dict or {}, | |
129 | prefix_error=False, |
|
129 | prefix_error=False, | |
130 | encoding="UTF-8") |
|
130 | encoding="UTF-8") | |
131 | except Exception: |
|
131 | except Exception: | |
132 | log.error(traceback.format_exc()) |
|
132 | log.error(traceback.format_exc()) | |
133 | h.flash(_('error occurred during creation of repos group %s') \ |
|
133 | h.flash(_('error occurred during creation of repos group %s') \ | |
134 | % request.POST.get('group_name'), category='error') |
|
134 | % request.POST.get('group_name'), category='error') | |
135 |
|
135 | |||
136 | return redirect(url('repos_groups')) |
|
136 | return redirect(url('repos_groups')) | |
137 |
|
137 | |||
138 | @HasPermissionAnyDecorator('hg.admin') |
|
138 | @HasPermissionAnyDecorator('hg.admin') | |
139 | def new(self, format='html'): |
|
139 | def new(self, format='html'): | |
140 | """GET /repos_groups/new: Form to create a new item""" |
|
140 | """GET /repos_groups/new: Form to create a new item""" | |
141 | # url('new_repos_group') |
|
141 | # url('new_repos_group') | |
142 | self.__load_defaults() |
|
142 | self.__load_defaults() | |
143 | return render('admin/repos_groups/repos_groups_add.html') |
|
143 | return render('admin/repos_groups/repos_groups_add.html') | |
144 |
|
144 | |||
145 | @HasPermissionAnyDecorator('hg.admin') |
|
145 | @HasPermissionAnyDecorator('hg.admin') | |
146 | def update(self, id): |
|
146 | def update(self, id): | |
147 | """PUT /repos_groups/id: Update an existing item""" |
|
147 | """PUT /repos_groups/id: Update an existing item""" | |
148 | # Forms posted to this method should contain a hidden field: |
|
148 | # Forms posted to this method should contain a hidden field: | |
149 | # <input type="hidden" name="_method" value="PUT" /> |
|
149 | # <input type="hidden" name="_method" value="PUT" /> | |
150 | # Or using helpers: |
|
150 | # Or using helpers: | |
151 | # h.form(url('repos_group', id=ID), |
|
151 | # h.form(url('repos_group', id=ID), | |
152 | # method='put') |
|
152 | # method='put') | |
153 | # url('repos_group', id=ID) |
|
153 | # url('repos_group', id=ID) | |
154 |
|
154 | |||
155 | self.__load_defaults() |
|
155 | self.__load_defaults() | |
156 | c.repos_group = RepoGroup.get(id) |
|
156 | c.repos_group = RepoGroup.get(id) | |
157 |
|
157 | |||
158 | repos_group_form = ReposGroupForm( |
|
158 | repos_group_form = ReposGroupForm( | |
159 | edit=True, |
|
159 | edit=True, | |
160 | old_data=c.repos_group.get_dict(), |
|
160 | old_data=c.repos_group.get_dict(), | |
161 | available_groups=c.repo_groups_choices |
|
161 | available_groups=c.repo_groups_choices | |
162 | )() |
|
162 | )() | |
163 | try: |
|
163 | try: | |
164 | form_result = repos_group_form.to_python(dict(request.POST)) |
|
164 | form_result = repos_group_form.to_python(dict(request.POST)) | |
165 | ReposGroupModel().update(id, form_result) |
|
165 | ReposGroupModel().update(id, form_result) | |
166 | Session().commit() |
|
166 | Session().commit() | |
167 | h.flash(_('updated repos group %s') \ |
|
167 | h.flash(_('updated repos group %s') \ | |
168 | % form_result['group_name'], category='success') |
|
168 | % form_result['group_name'], category='success') | |
169 | #TODO: in future action_logger(, '', '', '', self.sa) |
|
169 | #TODO: in future action_logger(, '', '', '', self.sa) | |
170 | except formencode.Invalid, errors: |
|
170 | except formencode.Invalid, errors: | |
171 |
|
171 | |||
172 | return htmlfill.render( |
|
172 | return htmlfill.render( | |
173 | render('admin/repos_groups/repos_groups_edit.html'), |
|
173 | render('admin/repos_groups/repos_groups_edit.html'), | |
174 | defaults=errors.value, |
|
174 | defaults=errors.value, | |
175 | errors=errors.error_dict or {}, |
|
175 | errors=errors.error_dict or {}, | |
176 | prefix_error=False, |
|
176 | prefix_error=False, | |
177 | encoding="UTF-8") |
|
177 | encoding="UTF-8") | |
178 | except Exception: |
|
178 | except Exception: | |
179 | log.error(traceback.format_exc()) |
|
179 | log.error(traceback.format_exc()) | |
180 | h.flash(_('error occurred during update of repos group %s') \ |
|
180 | h.flash(_('error occurred during update of repos group %s') \ | |
181 | % request.POST.get('group_name'), category='error') |
|
181 | % request.POST.get('group_name'), category='error') | |
182 |
|
182 | |||
183 | return redirect(url('edit_repos_group', id=id)) |
|
183 | return redirect(url('edit_repos_group', id=id)) | |
184 |
|
184 | |||
185 | @HasPermissionAnyDecorator('hg.admin') |
|
185 | @HasPermissionAnyDecorator('hg.admin') | |
186 | def delete(self, id): |
|
186 | def delete(self, id): | |
187 | """DELETE /repos_groups/id: Delete an existing item""" |
|
187 | """DELETE /repos_groups/id: Delete an existing item""" | |
188 | # Forms posted to this method should contain a hidden field: |
|
188 | # Forms posted to this method should contain a hidden field: | |
189 | # <input type="hidden" name="_method" value="DELETE" /> |
|
189 | # <input type="hidden" name="_method" value="DELETE" /> | |
190 | # Or using helpers: |
|
190 | # Or using helpers: | |
191 | # h.form(url('repos_group', id=ID), |
|
191 | # h.form(url('repos_group', id=ID), | |
192 | # method='delete') |
|
192 | # method='delete') | |
193 | # url('repos_group', id=ID) |
|
193 | # url('repos_group', id=ID) | |
194 |
|
194 | |||
195 | gr = RepoGroup.get(id) |
|
195 | gr = RepoGroup.get(id) | |
196 | repos = gr.repositories.all() |
|
196 | repos = gr.repositories.all() | |
197 | if repos: |
|
197 | if repos: | |
198 | h.flash(_('This group contains %s repositores and cannot be ' |
|
198 | h.flash(_('This group contains %s repositores and cannot be ' | |
199 | 'deleted') % len(repos), |
|
199 | 'deleted') % len(repos), | |
200 | category='error') |
|
200 | category='error') | |
201 | return redirect(url('repos_groups')) |
|
201 | return redirect(url('repos_groups')) | |
202 |
|
202 | |||
203 | try: |
|
203 | try: | |
204 | ReposGroupModel().delete(id) |
|
204 | ReposGroupModel().delete(id) | |
205 | Session().commit() |
|
205 | Session().commit() | |
206 | h.flash(_('removed repos group %s') % gr.group_name, |
|
206 | h.flash(_('removed repos group %s') % gr.group_name, | |
207 | category='success') |
|
207 | category='success') | |
208 | #TODO: in future action_logger(, '', '', '', self.sa) |
|
208 | #TODO: in future action_logger(, '', '', '', self.sa) | |
209 | except IntegrityError, e: |
|
209 | except IntegrityError, e: | |
210 | if str(e.message).find('groups_group_parent_id_fkey') != -1: |
|
210 | if str(e.message).find('groups_group_parent_id_fkey') != -1: | |
211 | log.error(traceback.format_exc()) |
|
211 | log.error(traceback.format_exc()) | |
212 | h.flash(_('Cannot delete this group it still contains ' |
|
212 | h.flash(_('Cannot delete this group it still contains ' | |
213 | 'subgroups'), |
|
213 | 'subgroups'), | |
214 | category='warning') |
|
214 | category='warning') | |
215 | else: |
|
215 | else: | |
216 | log.error(traceback.format_exc()) |
|
216 | log.error(traceback.format_exc()) | |
217 | h.flash(_('error occurred during deletion of repos ' |
|
217 | h.flash(_('error occurred during deletion of repos ' | |
218 | 'group %s') % gr.group_name, category='error') |
|
218 | 'group %s') % gr.group_name, category='error') | |
219 |
|
219 | |||
220 | except Exception: |
|
220 | except Exception: | |
221 | log.error(traceback.format_exc()) |
|
221 | log.error(traceback.format_exc()) | |
222 | h.flash(_('error occurred during deletion of repos ' |
|
222 | h.flash(_('error occurred during deletion of repos ' | |
223 | 'group %s') % gr.group_name, category='error') |
|
223 | 'group %s') % gr.group_name, category='error') | |
224 |
|
224 | |||
225 | return redirect(url('repos_groups')) |
|
225 | return redirect(url('repos_groups')) | |
226 |
|
226 | |||
227 | @HasReposGroupPermissionAnyDecorator('group.admin') |
|
227 | @HasReposGroupPermissionAnyDecorator('group.admin') | |
228 | def delete_repos_group_user_perm(self, group_name): |
|
228 | def delete_repos_group_user_perm(self, group_name): | |
229 | """ |
|
229 | """ | |
230 | DELETE an existing repositories group permission user |
|
230 | DELETE an existing repositories group permission user | |
231 |
|
231 | |||
232 | :param group_name: |
|
232 | :param group_name: | |
233 | """ |
|
233 | """ | |
234 | try: |
|
234 | try: | |
235 | recursive = str2bool(request.POST.get('recursive', False)) |
|
235 | recursive = str2bool(request.POST.get('recursive', False)) | |
236 | ReposGroupModel().delete_permission( |
|
236 | ReposGroupModel().delete_permission( | |
237 | repos_group=group_name, obj=request.POST['user_id'], |
|
237 | repos_group=group_name, obj=request.POST['user_id'], | |
238 | obj_type='user', recursive=recursive |
|
238 | obj_type='user', recursive=recursive | |
239 | ) |
|
239 | ) | |
240 | Session().commit() |
|
240 | Session().commit() | |
241 | except Exception: |
|
241 | except Exception: | |
242 | log.error(traceback.format_exc()) |
|
242 | log.error(traceback.format_exc()) | |
243 | h.flash(_('An error occurred during deletion of group user'), |
|
243 | h.flash(_('An error occurred during deletion of group user'), | |
244 | category='error') |
|
244 | category='error') | |
245 | raise HTTPInternalServerError() |
|
245 | raise HTTPInternalServerError() | |
246 |
|
246 | |||
247 | @HasReposGroupPermissionAnyDecorator('group.admin') |
|
247 | @HasReposGroupPermissionAnyDecorator('group.admin') | |
248 | def delete_repos_group_users_group_perm(self, group_name): |
|
248 | def delete_repos_group_users_group_perm(self, group_name): | |
249 | """ |
|
249 | """ | |
250 | DELETE an existing repositories group permission users group |
|
250 | DELETE an existing repositories group permission users group | |
251 |
|
251 | |||
252 | :param group_name: |
|
252 | :param group_name: | |
253 | """ |
|
253 | """ | |
254 |
|
254 | |||
255 | try: |
|
255 | try: | |
256 | recursive = str2bool(request.POST.get('recursive', False)) |
|
256 | recursive = str2bool(request.POST.get('recursive', False)) | |
257 | ReposGroupModel().delete_permission( |
|
257 | ReposGroupModel().delete_permission( | |
258 | repos_group=group_name, obj=request.POST['users_group_id'], |
|
258 | repos_group=group_name, obj=request.POST['users_group_id'], | |
259 | obj_type='users_group', recursive=recursive |
|
259 | obj_type='users_group', recursive=recursive | |
260 | ) |
|
260 | ) | |
261 | Session().commit() |
|
261 | Session().commit() | |
262 | except Exception: |
|
262 | except Exception: | |
263 | log.error(traceback.format_exc()) |
|
263 | log.error(traceback.format_exc()) | |
264 | h.flash(_('An error occurred during deletion of group' |
|
264 | h.flash(_('An error occurred during deletion of group' | |
265 | ' users groups'), |
|
265 | ' users groups'), | |
266 | category='error') |
|
266 | category='error') | |
267 | raise HTTPInternalServerError() |
|
267 | raise HTTPInternalServerError() | |
268 |
|
268 | |||
269 | def show_by_name(self, group_name): |
|
269 | def show_by_name(self, group_name): | |
270 | """ |
|
270 | """ | |
271 | This is a proxy that does a lookup group_name -> id, and shows |
|
271 | This is a proxy that does a lookup group_name -> id, and shows | |
272 | the group by id view instead |
|
272 | the group by id view instead | |
273 | """ |
|
273 | """ | |
274 | group_name = group_name.rstrip('/') |
|
274 | group_name = group_name.rstrip('/') | |
275 | id_ = RepoGroup.get_by_group_name(group_name) |
|
275 | id_ = RepoGroup.get_by_group_name(group_name) | |
276 | if id_: |
|
276 | if id_: | |
277 | return self.show(id_.group_id) |
|
277 | return self.show(id_.group_id) | |
278 | raise HTTPNotFound |
|
278 | raise HTTPNotFound | |
279 |
|
279 | |||
280 | @HasReposGroupPermissionAnyDecorator('group.read', 'group.write', |
|
280 | @HasReposGroupPermissionAnyDecorator('group.read', 'group.write', | |
281 | 'group.admin') |
|
281 | 'group.admin') | |
282 | def show(self, id, format='html'): |
|
282 | def show(self, id, format='html'): | |
283 | """GET /repos_groups/id: Show a specific item""" |
|
283 | """GET /repos_groups/id: Show a specific item""" | |
284 | # url('repos_group', id=ID) |
|
284 | # url('repos_group', id=ID) | |
285 |
|
285 | |||
286 | c.group = RepoGroup.get_or_404(id) |
|
286 | c.group = RepoGroup.get_or_404(id) | |
287 | c.group_repos = c.group.repositories.all() |
|
287 | c.group_repos = c.group.repositories.all() | |
288 |
|
288 | |||
289 | #overwrite our cached list with current filter |
|
289 | #overwrite our cached list with current filter | |
290 | gr_filter = c.group_repos |
|
290 | gr_filter = c.group_repos | |
291 | c.repo_cnt = 0 |
|
291 | c.repo_cnt = 0 | |
292 |
|
292 | |||
293 | groups = RepoGroup.query().order_by(RepoGroup.group_name)\ |
|
293 | groups = RepoGroup.query().order_by(RepoGroup.group_name)\ | |
294 | .filter(RepoGroup.group_parent_id == id).all() |
|
294 | .filter(RepoGroup.group_parent_id == id).all() | |
295 | c.groups = self.scm_model.get_repos_groups(groups) |
|
295 | c.groups = self.scm_model.get_repos_groups(groups) | |
296 |
|
296 | |||
297 | if c.visual.lightweight_dashboard is False: |
|
297 | if c.visual.lightweight_dashboard is False: | |
298 | c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter) |
|
298 | c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter) | |
299 |
|
299 | |||
300 | c.repos_list = c.cached_repo_list |
|
300 | c.repos_list = c.cached_repo_list | |
301 | ## lightweight version of dashboard |
|
301 | ## lightweight version of dashboard | |
302 | else: |
|
302 | else: | |
303 | c.repos_list = Repository.query()\ |
|
303 | c.repos_list = Repository.query()\ | |
304 | .filter(Repository.group_id == id)\ |
|
304 | .filter(Repository.group_id == id)\ | |
305 | .order_by(func.lower(Repository.repo_name))\ |
|
305 | .order_by(func.lower(Repository.repo_name))\ | |
306 | .all() |
|
306 | .all() | |
307 | repos_data = [] |
|
307 | repos_data = [] | |
308 | total_records = len(c.repos_list) |
|
308 | total_records = len(c.repos_list) | |
309 |
|
309 | |||
310 | _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup |
|
310 | _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup | |
311 | template = _tmpl_lookup.get_template('data_table/_dt_elements.html') |
|
311 | template = _tmpl_lookup.get_template('data_table/_dt_elements.html') | |
312 |
|
312 | |||
313 | quick_menu = lambda repo_name: (template.get_def("quick_menu") |
|
313 | quick_menu = lambda repo_name: (template.get_def("quick_menu") | |
314 | .render(repo_name, _=_, h=h, c=c)) |
|
314 | .render(repo_name, _=_, h=h, c=c)) | |
315 | repo_lnk = lambda name, rtype, private, fork_of: ( |
|
315 | repo_lnk = lambda name, rtype, private, fork_of: ( | |
316 | template.get_def("repo_name") |
|
316 | template.get_def("repo_name") | |
317 | .render(name, rtype, private, fork_of, short_name=False, |
|
317 | .render(name, rtype, private, fork_of, short_name=False, | |
318 | admin=False, _=_, h=h, c=c)) |
|
318 | admin=False, _=_, h=h, c=c)) | |
319 | last_change = lambda last_change: (template.get_def("last_change") |
|
319 | last_change = lambda last_change: (template.get_def("last_change") | |
320 | .render(last_change, _=_, h=h, c=c)) |
|
320 | .render(last_change, _=_, h=h, c=c)) | |
321 | rss_lnk = lambda repo_name: (template.get_def("rss") |
|
321 | rss_lnk = lambda repo_name: (template.get_def("rss") | |
322 | .render(repo_name, _=_, h=h, c=c)) |
|
322 | .render(repo_name, _=_, h=h, c=c)) | |
323 | atom_lnk = lambda repo_name: (template.get_def("atom") |
|
323 | atom_lnk = lambda repo_name: (template.get_def("atom") | |
324 | .render(repo_name, _=_, h=h, c=c)) |
|
324 | .render(repo_name, _=_, h=h, c=c)) | |
325 |
|
325 | |||
326 | for repo in c.repos_list: |
|
326 | for repo in c.repos_list: | |
327 | repos_data.append({ |
|
327 | repos_data.append({ | |
328 | "menu": quick_menu(repo.repo_name), |
|
328 | "menu": quick_menu(repo.repo_name), | |
329 | "raw_name": repo.repo_name.lower(), |
|
329 | "raw_name": repo.repo_name.lower(), | |
330 | "name": repo_lnk(repo.repo_name, repo.repo_type, |
|
330 | "name": repo_lnk(repo.repo_name, repo.repo_type, | |
331 | repo.private, repo.fork), |
|
331 | repo.private, repo.fork), | |
332 | "last_change": last_change(repo.last_db_change), |
|
332 | "last_change": last_change(repo.last_db_change), | |
333 | "desc": repo.description, |
|
333 | "desc": repo.description, | |
334 | "owner": h.person(repo.user.username), |
|
334 | "owner": h.person(repo.user.username), | |
335 | "rss": rss_lnk(repo.repo_name), |
|
335 | "rss": rss_lnk(repo.repo_name), | |
336 | "atom": atom_lnk(repo.repo_name), |
|
336 | "atom": atom_lnk(repo.repo_name), | |
337 | }) |
|
337 | }) | |
338 |
|
338 | |||
339 | c.data = json.dumps({ |
|
339 | c.data = json.dumps({ | |
340 | "totalRecords": total_records, |
|
340 | "totalRecords": total_records, | |
341 | "startIndex": 0, |
|
341 | "startIndex": 0, | |
342 | "sort": "name", |
|
342 | "sort": "name", | |
343 | "dir": "asc", |
|
343 | "dir": "asc", | |
344 | "records": repos_data |
|
344 | "records": repos_data | |
345 |
}) |
|
345 | }) | |
346 |
|
346 | |||
347 | return render('admin/repos_groups/repos_groups.html') |
|
347 | return render('admin/repos_groups/repos_groups.html') | |
348 |
|
348 | |||
349 | @HasPermissionAnyDecorator('hg.admin') |
|
349 | @HasPermissionAnyDecorator('hg.admin') | |
350 | def edit(self, id, format='html'): |
|
350 | def edit(self, id, format='html'): | |
351 | """GET /repos_groups/id/edit: Form to edit an existing item""" |
|
351 | """GET /repos_groups/id/edit: Form to edit an existing item""" | |
352 | # url('edit_repos_group', id=ID) |
|
352 | # url('edit_repos_group', id=ID) | |
353 |
|
353 | |||
354 | c.repos_group = ReposGroupModel()._get_repos_group(id) |
|
354 | c.repos_group = ReposGroupModel()._get_repos_group(id) | |
355 | defaults = self.__load_data(c.repos_group.group_id) |
|
355 | defaults = self.__load_data(c.repos_group.group_id) | |
356 |
|
356 | |||
357 | # we need to exclude this group from the group list for editing |
|
357 | # we need to exclude this group from the group list for editing | |
358 | c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id, |
|
358 | c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id, | |
359 | c.repo_groups) |
|
359 | c.repo_groups) | |
360 |
|
360 | |||
361 | return htmlfill.render( |
|
361 | return htmlfill.render( | |
362 | render('admin/repos_groups/repos_groups_edit.html'), |
|
362 | render('admin/repos_groups/repos_groups_edit.html'), | |
363 | defaults=defaults, |
|
363 | defaults=defaults, | |
364 | encoding="UTF-8", |
|
364 | encoding="UTF-8", | |
365 | force_defaults=False |
|
365 | force_defaults=False | |
366 | ) |
|
366 | ) |
@@ -1,545 +1,545 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.controllers.files |
|
3 | rhodecode.controllers.files | |
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | Files controller for RhodeCode |
|
6 | Files controller for RhodeCode | |
7 |
|
7 | |||
8 | :created_on: Apr 21, 2010 |
|
8 | :created_on: Apr 21, 2010 | |
9 | :author: marcink |
|
9 | :author: marcink | |
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> |
|
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> | |
11 | :license: GPLv3, see COPYING for more details. |
|
11 | :license: GPLv3, see COPYING for more details. | |
12 | """ |
|
12 | """ | |
13 | # This program is free software: you can redistribute it and/or modify |
|
13 | # This program is free software: you can redistribute it and/or modify | |
14 | # it under the terms of the GNU General Public License as published by |
|
14 | # it under the terms of the GNU General Public License as published by | |
15 | # the Free Software Foundation, either version 3 of the License, or |
|
15 | # the Free Software Foundation, either version 3 of the License, or | |
16 | # (at your option) any later version. |
|
16 | # (at your option) any later version. | |
17 | # |
|
17 | # | |
18 | # This program is distributed in the hope that it will be useful, |
|
18 | # This program is distributed in the hope that it will be useful, | |
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | # GNU General Public License for more details. |
|
21 | # GNU General Public License for more details. | |
22 | # |
|
22 | # | |
23 | # You should have received a copy of the GNU General Public License |
|
23 | # You should have received a copy of the GNU General Public License | |
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 | from __future__ import with_statement |
|
25 | from __future__ import with_statement | |
26 | import os |
|
26 | import os | |
27 | import logging |
|
27 | import logging | |
28 | import traceback |
|
28 | import traceback | |
29 | import tempfile |
|
29 | import tempfile | |
30 |
|
30 | |||
31 | from pylons import request, response, tmpl_context as c, url |
|
31 | from pylons import request, response, tmpl_context as c, url | |
32 | from pylons.i18n.translation import _ |
|
32 | from pylons.i18n.translation import _ | |
33 | from pylons.controllers.util import redirect |
|
33 | from pylons.controllers.util import redirect | |
34 | from pylons.decorators import jsonify |
|
34 | from pylons.decorators import jsonify | |
35 |
|
35 | |||
36 | from rhodecode.lib import diffs |
|
36 | from rhodecode.lib import diffs | |
37 | from rhodecode.lib import helpers as h |
|
37 | from rhodecode.lib import helpers as h | |
38 |
|
38 | |||
39 | from rhodecode.lib.compat import OrderedDict |
|
39 | from rhodecode.lib.compat import OrderedDict | |
40 | from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\ |
|
40 | from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\ | |
41 | str2bool |
|
41 | str2bool | |
42 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
42 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
43 | from rhodecode.lib.base import BaseRepoController, render |
|
43 | from rhodecode.lib.base import BaseRepoController, render | |
44 | from rhodecode.lib.vcs.backends.base import EmptyChangeset |
|
44 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
45 | from rhodecode.lib.vcs.conf import settings |
|
45 | from rhodecode.lib.vcs.conf import settings | |
46 | from rhodecode.lib.vcs.exceptions import RepositoryError, \ |
|
46 | from rhodecode.lib.vcs.exceptions import RepositoryError, \ | |
47 | ChangesetDoesNotExistError, EmptyRepositoryError, \ |
|
47 | ChangesetDoesNotExistError, EmptyRepositoryError, \ | |
48 | ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError |
|
48 | ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError | |
49 | from rhodecode.lib.vcs.nodes import FileNode |
|
49 | from rhodecode.lib.vcs.nodes import FileNode | |
50 |
|
50 | |||
51 | from rhodecode.model.repo import RepoModel |
|
51 | from rhodecode.model.repo import RepoModel | |
52 | from rhodecode.model.scm import ScmModel |
|
52 | from rhodecode.model.scm import ScmModel | |
53 | from rhodecode.model.db import Repository |
|
53 | from rhodecode.model.db import Repository | |
54 |
|
54 | |||
55 | from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\ |
|
55 | from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\ | |
56 | _context_url, get_line_ctx, get_ignore_ws |
|
56 | _context_url, get_line_ctx, get_ignore_ws | |
57 |
|
57 | |||
58 |
|
58 | |||
59 | log = logging.getLogger(__name__) |
|
59 | log = logging.getLogger(__name__) | |
60 |
|
60 | |||
61 |
|
61 | |||
62 | class FilesController(BaseRepoController): |
|
62 | class FilesController(BaseRepoController): | |
63 |
|
63 | |||
64 | def __before__(self): |
|
64 | def __before__(self): | |
65 | super(FilesController, self).__before__() |
|
65 | super(FilesController, self).__before__() | |
66 | c.cut_off_limit = self.cut_off_limit |
|
66 | c.cut_off_limit = self.cut_off_limit | |
67 |
|
67 | |||
68 | def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True): |
|
68 | def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True): | |
69 | """ |
|
69 | """ | |
70 | Safe way to get changeset if error occur it redirects to tip with |
|
70 | Safe way to get changeset if error occur it redirects to tip with | |
71 | proper message |
|
71 | proper message | |
72 |
|
72 | |||
73 | :param rev: revision to fetch |
|
73 | :param rev: revision to fetch | |
74 | :param repo_name: repo name to redirect after |
|
74 | :param repo_name: repo name to redirect after | |
75 | """ |
|
75 | """ | |
76 |
|
76 | |||
77 | try: |
|
77 | try: | |
78 | return c.rhodecode_repo.get_changeset(rev) |
|
78 | return c.rhodecode_repo.get_changeset(rev) | |
79 | except EmptyRepositoryError, e: |
|
79 | except EmptyRepositoryError, e: | |
80 | if not redirect_after: |
|
80 | if not redirect_after: | |
81 | return None |
|
81 | return None | |
82 | url_ = url('files_add_home', |
|
82 | url_ = url('files_add_home', | |
83 | repo_name=c.repo_name, |
|
83 | repo_name=c.repo_name, | |
84 | revision=0, f_path='') |
|
84 | revision=0, f_path='') | |
85 | add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file')) |
|
85 | add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file')) | |
86 | h.flash(h.literal(_('There are no files yet %s') % add_new), |
|
86 | h.flash(h.literal(_('There are no files yet %s') % add_new), | |
87 | category='warning') |
|
87 | category='warning') | |
88 | redirect(h.url('summary_home', repo_name=repo_name)) |
|
88 | redirect(h.url('summary_home', repo_name=repo_name)) | |
89 |
|
89 | |||
90 | except RepositoryError, e: |
|
90 | except RepositoryError, e: | |
91 | h.flash(str(e), category='warning') |
|
91 | h.flash(str(e), category='warning') | |
92 | redirect(h.url('files_home', repo_name=repo_name, revision='tip')) |
|
92 | redirect(h.url('files_home', repo_name=repo_name, revision='tip')) | |
93 |
|
93 | |||
94 | def __get_filenode_or_redirect(self, repo_name, cs, path): |
|
94 | def __get_filenode_or_redirect(self, repo_name, cs, path): | |
95 | """ |
|
95 | """ | |
96 | Returns file_node, if error occurs or given path is directory, |
|
96 | Returns file_node, if error occurs or given path is directory, | |
97 | it'll redirect to top level path |
|
97 | it'll redirect to top level path | |
98 |
|
98 | |||
99 | :param repo_name: repo_name |
|
99 | :param repo_name: repo_name | |
100 | :param cs: given changeset |
|
100 | :param cs: given changeset | |
101 | :param path: path to lookup |
|
101 | :param path: path to lookup | |
102 | """ |
|
102 | """ | |
103 |
|
103 | |||
104 | try: |
|
104 | try: | |
105 | file_node = cs.get_node(path) |
|
105 | file_node = cs.get_node(path) | |
106 | if file_node.is_dir(): |
|
106 | if file_node.is_dir(): | |
107 | raise RepositoryError('given path is a directory') |
|
107 | raise RepositoryError('given path is a directory') | |
108 | except RepositoryError, e: |
|
108 | except RepositoryError, e: | |
109 | h.flash(str(e), category='warning') |
|
109 | h.flash(str(e), category='warning') | |
110 | redirect(h.url('files_home', repo_name=repo_name, |
|
110 | redirect(h.url('files_home', repo_name=repo_name, | |
111 | revision=cs.raw_id)) |
|
111 | revision=cs.raw_id)) | |
112 |
|
112 | |||
113 | return file_node |
|
113 | return file_node | |
114 |
|
114 | |||
115 | @LoginRequired() |
|
115 | @LoginRequired() | |
116 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
116 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
117 | 'repository.admin') |
|
117 | 'repository.admin') | |
118 | def index(self, repo_name, revision, f_path, annotate=False): |
|
118 | def index(self, repo_name, revision, f_path, annotate=False): | |
119 | # redirect to given revision from form if given |
|
119 | # redirect to given revision from form if given | |
120 | post_revision = request.POST.get('at_rev', None) |
|
120 | post_revision = request.POST.get('at_rev', None) | |
121 | if post_revision: |
|
121 | if post_revision: | |
122 | cs = self.__get_cs_or_redirect(post_revision, repo_name) |
|
122 | cs = self.__get_cs_or_redirect(post_revision, repo_name) | |
123 | redirect(url('files_home', repo_name=c.repo_name, |
|
123 | redirect(url('files_home', repo_name=c.repo_name, | |
124 | revision=cs.raw_id, f_path=f_path)) |
|
124 | revision=cs.raw_id, f_path=f_path)) | |
125 |
|
125 | |||
126 | c.changeset = self.__get_cs_or_redirect(revision, repo_name) |
|
126 | c.changeset = self.__get_cs_or_redirect(revision, repo_name) | |
127 | c.branch = request.GET.get('branch', None) |
|
127 | c.branch = request.GET.get('branch', None) | |
128 | c.f_path = f_path |
|
128 | c.f_path = f_path | |
129 | c.annotate = annotate |
|
129 | c.annotate = annotate | |
130 | cur_rev = c.changeset.revision |
|
130 | cur_rev = c.changeset.revision | |
131 |
|
131 | |||
132 | # prev link |
|
132 | # prev link | |
133 | try: |
|
133 | try: | |
134 | prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch) |
|
134 | prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch) | |
135 | c.url_prev = url('files_home', repo_name=c.repo_name, |
|
135 | c.url_prev = url('files_home', repo_name=c.repo_name, | |
136 | revision=prev_rev.raw_id, f_path=f_path) |
|
136 | revision=prev_rev.raw_id, f_path=f_path) | |
137 | if c.branch: |
|
137 | if c.branch: | |
138 | c.url_prev += '?branch=%s' % c.branch |
|
138 | c.url_prev += '?branch=%s' % c.branch | |
139 | except (ChangesetDoesNotExistError, VCSError): |
|
139 | except (ChangesetDoesNotExistError, VCSError): | |
140 | c.url_prev = '#' |
|
140 | c.url_prev = '#' | |
141 |
|
141 | |||
142 | # next link |
|
142 | # next link | |
143 | try: |
|
143 | try: | |
144 | next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch) |
|
144 | next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch) | |
145 | c.url_next = url('files_home', repo_name=c.repo_name, |
|
145 | c.url_next = url('files_home', repo_name=c.repo_name, | |
146 | revision=next_rev.raw_id, f_path=f_path) |
|
146 | revision=next_rev.raw_id, f_path=f_path) | |
147 | if c.branch: |
|
147 | if c.branch: | |
148 | c.url_next += '?branch=%s' % c.branch |
|
148 | c.url_next += '?branch=%s' % c.branch | |
149 | except (ChangesetDoesNotExistError, VCSError): |
|
149 | except (ChangesetDoesNotExistError, VCSError): | |
150 | c.url_next = '#' |
|
150 | c.url_next = '#' | |
151 |
|
151 | |||
152 | # files or dirs |
|
152 | # files or dirs | |
153 | try: |
|
153 | try: | |
154 | c.file = c.changeset.get_node(f_path) |
|
154 | c.file = c.changeset.get_node(f_path) | |
155 |
|
155 | |||
156 | if c.file.is_file(): |
|
156 | if c.file.is_file(): | |
157 | _hist = c.rhodecode_repo.get_changeset().get_file_history(f_path) |
|
157 | _hist = c.rhodecode_repo.get_changeset().get_file_history(f_path) | |
158 | c.file_changeset = c.changeset |
|
158 | c.file_changeset = c.changeset | |
159 | if _hist: |
|
159 | if _hist: | |
160 |
c.file_changeset = (c.changeset |
|
160 | c.file_changeset = (c.changeset | |
161 | if c.changeset.revision < _hist[0].revision |
|
161 | if c.changeset.revision < _hist[0].revision | |
162 | else _hist[0]) |
|
162 | else _hist[0]) | |
163 | c.file_history = self._get_node_history(None, f_path, _hist) |
|
163 | c.file_history = self._get_node_history(None, f_path, _hist) | |
164 | c.authors = [] |
|
164 | c.authors = [] | |
165 | for a in set([x.author for x in _hist]): |
|
165 | for a in set([x.author for x in _hist]): | |
166 | c.authors.append((h.email(a), h.person(a))) |
|
166 | c.authors.append((h.email(a), h.person(a))) | |
167 | else: |
|
167 | else: | |
168 | c.authors = c.file_history = [] |
|
168 | c.authors = c.file_history = [] | |
169 | except RepositoryError, e: |
|
169 | except RepositoryError, e: | |
170 | h.flash(str(e), category='warning') |
|
170 | h.flash(str(e), category='warning') | |
171 | redirect(h.url('files_home', repo_name=repo_name, |
|
171 | redirect(h.url('files_home', repo_name=repo_name, | |
172 | revision='tip')) |
|
172 | revision='tip')) | |
173 |
|
173 | |||
174 | if request.environ.get('HTTP_X_PARTIAL_XHR'): |
|
174 | if request.environ.get('HTTP_X_PARTIAL_XHR'): | |
175 | return render('files/files_ypjax.html') |
|
175 | return render('files/files_ypjax.html') | |
176 |
|
176 | |||
177 | return render('files/files.html') |
|
177 | return render('files/files.html') | |
178 |
|
178 | |||
179 | @LoginRequired() |
|
179 | @LoginRequired() | |
180 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
180 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
181 | 'repository.admin') |
|
181 | 'repository.admin') | |
182 | def rawfile(self, repo_name, revision, f_path): |
|
182 | def rawfile(self, repo_name, revision, f_path): | |
183 | cs = self.__get_cs_or_redirect(revision, repo_name) |
|
183 | cs = self.__get_cs_or_redirect(revision, repo_name) | |
184 | file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) |
|
184 | file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) | |
185 |
|
185 | |||
186 | response.content_disposition = 'attachment; filename=%s' % \ |
|
186 | response.content_disposition = 'attachment; filename=%s' % \ | |
187 | safe_str(f_path.split(Repository.url_sep())[-1]) |
|
187 | safe_str(f_path.split(Repository.url_sep())[-1]) | |
188 |
|
188 | |||
189 | response.content_type = file_node.mimetype |
|
189 | response.content_type = file_node.mimetype | |
190 | return file_node.content |
|
190 | return file_node.content | |
191 |
|
191 | |||
192 | @LoginRequired() |
|
192 | @LoginRequired() | |
193 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
193 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
194 | 'repository.admin') |
|
194 | 'repository.admin') | |
195 | def raw(self, repo_name, revision, f_path): |
|
195 | def raw(self, repo_name, revision, f_path): | |
196 | cs = self.__get_cs_or_redirect(revision, repo_name) |
|
196 | cs = self.__get_cs_or_redirect(revision, repo_name) | |
197 | file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) |
|
197 | file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) | |
198 |
|
198 | |||
199 | raw_mimetype_mapping = { |
|
199 | raw_mimetype_mapping = { | |
200 | # map original mimetype to a mimetype used for "show as raw" |
|
200 | # map original mimetype to a mimetype used for "show as raw" | |
201 | # you can also provide a content-disposition to override the |
|
201 | # you can also provide a content-disposition to override the | |
202 | # default "attachment" disposition. |
|
202 | # default "attachment" disposition. | |
203 | # orig_type: (new_type, new_dispo) |
|
203 | # orig_type: (new_type, new_dispo) | |
204 |
|
204 | |||
205 | # show images inline: |
|
205 | # show images inline: | |
206 | 'image/x-icon': ('image/x-icon', 'inline'), |
|
206 | 'image/x-icon': ('image/x-icon', 'inline'), | |
207 | 'image/png': ('image/png', 'inline'), |
|
207 | 'image/png': ('image/png', 'inline'), | |
208 | 'image/gif': ('image/gif', 'inline'), |
|
208 | 'image/gif': ('image/gif', 'inline'), | |
209 | 'image/jpeg': ('image/jpeg', 'inline'), |
|
209 | 'image/jpeg': ('image/jpeg', 'inline'), | |
210 | 'image/svg+xml': ('image/svg+xml', 'inline'), |
|
210 | 'image/svg+xml': ('image/svg+xml', 'inline'), | |
211 | } |
|
211 | } | |
212 |
|
212 | |||
213 | mimetype = file_node.mimetype |
|
213 | mimetype = file_node.mimetype | |
214 | try: |
|
214 | try: | |
215 | mimetype, dispo = raw_mimetype_mapping[mimetype] |
|
215 | mimetype, dispo = raw_mimetype_mapping[mimetype] | |
216 | except KeyError: |
|
216 | except KeyError: | |
217 | # we don't know anything special about this, handle it safely |
|
217 | # we don't know anything special about this, handle it safely | |
218 | if file_node.is_binary: |
|
218 | if file_node.is_binary: | |
219 | # do same as download raw for binary files |
|
219 | # do same as download raw for binary files | |
220 | mimetype, dispo = 'application/octet-stream', 'attachment' |
|
220 | mimetype, dispo = 'application/octet-stream', 'attachment' | |
221 | else: |
|
221 | else: | |
222 | # do not just use the original mimetype, but force text/plain, |
|
222 | # do not just use the original mimetype, but force text/plain, | |
223 | # otherwise it would serve text/html and that might be unsafe. |
|
223 | # otherwise it would serve text/html and that might be unsafe. | |
224 | # Note: underlying vcs library fakes text/plain mimetype if the |
|
224 | # Note: underlying vcs library fakes text/plain mimetype if the | |
225 | # mimetype can not be determined and it thinks it is not |
|
225 | # mimetype can not be determined and it thinks it is not | |
226 | # binary.This might lead to erroneous text display in some |
|
226 | # binary.This might lead to erroneous text display in some | |
227 | # cases, but helps in other cases, like with text files |
|
227 | # cases, but helps in other cases, like with text files | |
228 | # without extension. |
|
228 | # without extension. | |
229 | mimetype, dispo = 'text/plain', 'inline' |
|
229 | mimetype, dispo = 'text/plain', 'inline' | |
230 |
|
230 | |||
231 | if dispo == 'attachment': |
|
231 | if dispo == 'attachment': | |
232 | dispo = 'attachment; filename=%s' % \ |
|
232 | dispo = 'attachment; filename=%s' % \ | |
233 | safe_str(f_path.split(os.sep)[-1]) |
|
233 | safe_str(f_path.split(os.sep)[-1]) | |
234 |
|
234 | |||
235 | response.content_disposition = dispo |
|
235 | response.content_disposition = dispo | |
236 | response.content_type = mimetype |
|
236 | response.content_type = mimetype | |
237 | return file_node.content |
|
237 | return file_node.content | |
238 |
|
238 | |||
239 | @LoginRequired() |
|
239 | @LoginRequired() | |
240 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
240 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') | |
241 | def edit(self, repo_name, revision, f_path): |
|
241 | def edit(self, repo_name, revision, f_path): | |
242 | repo = Repository.get_by_repo_name(repo_name) |
|
242 | repo = Repository.get_by_repo_name(repo_name) | |
243 | if repo.enable_locking and repo.locked[0]: |
|
243 | if repo.enable_locking and repo.locked[0]: | |
244 | h.flash(_('This repository is has been locked by %s on %s') |
|
244 | h.flash(_('This repository is has been locked by %s on %s') | |
245 | % (h.person_by_id(repo.locked[0]), |
|
245 | % (h.person_by_id(repo.locked[0]), | |
246 | h.fmt_date(h.time_to_datetime(repo.locked[1]))), |
|
246 | h.fmt_date(h.time_to_datetime(repo.locked[1]))), | |
247 | 'warning') |
|
247 | 'warning') | |
248 | return redirect(h.url('files_home', |
|
248 | return redirect(h.url('files_home', | |
249 | repo_name=repo_name, revision='tip')) |
|
249 | repo_name=repo_name, revision='tip')) | |
250 |
|
250 | |||
251 | r_post = request.POST |
|
251 | r_post = request.POST | |
252 |
|
252 | |||
253 | c.cs = self.__get_cs_or_redirect(revision, repo_name) |
|
253 | c.cs = self.__get_cs_or_redirect(revision, repo_name) | |
254 | c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path) |
|
254 | c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path) | |
255 |
|
255 | |||
256 | if c.file.is_binary: |
|
256 | if c.file.is_binary: | |
257 | return redirect(url('files_home', repo_name=c.repo_name, |
|
257 | return redirect(url('files_home', repo_name=c.repo_name, | |
258 | revision=c.cs.raw_id, f_path=f_path)) |
|
258 | revision=c.cs.raw_id, f_path=f_path)) | |
259 |
|
259 | |||
260 | c.f_path = f_path |
|
260 | c.f_path = f_path | |
261 |
|
261 | |||
262 | if r_post: |
|
262 | if r_post: | |
263 |
|
263 | |||
264 | old_content = c.file.content |
|
264 | old_content = c.file.content | |
265 | sl = old_content.splitlines(1) |
|
265 | sl = old_content.splitlines(1) | |
266 | first_line = sl[0] if sl else '' |
|
266 | first_line = sl[0] if sl else '' | |
267 | # modes: 0 - Unix, 1 - Mac, 2 - DOS |
|
267 | # modes: 0 - Unix, 1 - Mac, 2 - DOS | |
268 | mode = detect_mode(first_line, 0) |
|
268 | mode = detect_mode(first_line, 0) | |
269 | content = convert_line_endings(r_post.get('content'), mode) |
|
269 | content = convert_line_endings(r_post.get('content'), mode) | |
270 |
|
270 | |||
271 | message = r_post.get('message') or (_('Edited %s via RhodeCode') |
|
271 | message = r_post.get('message') or (_('Edited %s via RhodeCode') | |
272 | % (f_path)) |
|
272 | % (f_path)) | |
273 | author = self.rhodecode_user.full_contact |
|
273 | author = self.rhodecode_user.full_contact | |
274 |
|
274 | |||
275 | if content == old_content: |
|
275 | if content == old_content: | |
276 | h.flash(_('No changes'), |
|
276 | h.flash(_('No changes'), | |
277 | category='warning') |
|
277 | category='warning') | |
278 | return redirect(url('changeset_home', repo_name=c.repo_name, |
|
278 | return redirect(url('changeset_home', repo_name=c.repo_name, | |
279 | revision='tip')) |
|
279 | revision='tip')) | |
280 |
|
280 | |||
281 | try: |
|
281 | try: | |
282 | self.scm_model.commit_change(repo=c.rhodecode_repo, |
|
282 | self.scm_model.commit_change(repo=c.rhodecode_repo, | |
283 | repo_name=repo_name, cs=c.cs, |
|
283 | repo_name=repo_name, cs=c.cs, | |
284 | user=self.rhodecode_user, |
|
284 | user=self.rhodecode_user, | |
285 | author=author, message=message, |
|
285 | author=author, message=message, | |
286 | content=content, f_path=f_path) |
|
286 | content=content, f_path=f_path) | |
287 | h.flash(_('Successfully committed to %s') % f_path, |
|
287 | h.flash(_('Successfully committed to %s') % f_path, | |
288 | category='success') |
|
288 | category='success') | |
289 |
|
289 | |||
290 | except Exception: |
|
290 | except Exception: | |
291 | log.error(traceback.format_exc()) |
|
291 | log.error(traceback.format_exc()) | |
292 | h.flash(_('Error occurred during commit'), category='error') |
|
292 | h.flash(_('Error occurred during commit'), category='error') | |
293 | return redirect(url('changeset_home', |
|
293 | return redirect(url('changeset_home', | |
294 | repo_name=c.repo_name, revision='tip')) |
|
294 | repo_name=c.repo_name, revision='tip')) | |
295 |
|
295 | |||
296 | return render('files/files_edit.html') |
|
296 | return render('files/files_edit.html') | |
297 |
|
297 | |||
298 | @LoginRequired() |
|
298 | @LoginRequired() | |
299 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
299 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') | |
300 | def add(self, repo_name, revision, f_path): |
|
300 | def add(self, repo_name, revision, f_path): | |
301 |
|
301 | |||
302 | repo = Repository.get_by_repo_name(repo_name) |
|
302 | repo = Repository.get_by_repo_name(repo_name) | |
303 | if repo.enable_locking and repo.locked[0]: |
|
303 | if repo.enable_locking and repo.locked[0]: | |
304 | h.flash(_('This repository is has been locked by %s on %s') |
|
304 | h.flash(_('This repository is has been locked by %s on %s') | |
305 | % (h.person_by_id(repo.locked[0]), |
|
305 | % (h.person_by_id(repo.locked[0]), | |
306 | h.fmt_date(h.time_to_datetime(repo.locked[1]))), |
|
306 | h.fmt_date(h.time_to_datetime(repo.locked[1]))), | |
307 | 'warning') |
|
307 | 'warning') | |
308 | return redirect(h.url('files_home', |
|
308 | return redirect(h.url('files_home', | |
309 | repo_name=repo_name, revision='tip')) |
|
309 | repo_name=repo_name, revision='tip')) | |
310 |
|
310 | |||
311 | r_post = request.POST |
|
311 | r_post = request.POST | |
312 | c.cs = self.__get_cs_or_redirect(revision, repo_name, |
|
312 | c.cs = self.__get_cs_or_redirect(revision, repo_name, | |
313 | redirect_after=False) |
|
313 | redirect_after=False) | |
314 | if c.cs is None: |
|
314 | if c.cs is None: | |
315 | c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias) |
|
315 | c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias) | |
316 |
|
316 | |||
317 | c.f_path = f_path |
|
317 | c.f_path = f_path | |
318 |
|
318 | |||
319 | if r_post: |
|
319 | if r_post: | |
320 | unix_mode = 0 |
|
320 | unix_mode = 0 | |
321 | content = convert_line_endings(r_post.get('content'), unix_mode) |
|
321 | content = convert_line_endings(r_post.get('content'), unix_mode) | |
322 |
|
322 | |||
323 | message = r_post.get('message') or (_('Added %s via RhodeCode') |
|
323 | message = r_post.get('message') or (_('Added %s via RhodeCode') | |
324 | % (f_path)) |
|
324 | % (f_path)) | |
325 | location = r_post.get('location') |
|
325 | location = r_post.get('location') | |
326 | filename = r_post.get('filename') |
|
326 | filename = r_post.get('filename') | |
327 | file_obj = r_post.get('upload_file', None) |
|
327 | file_obj = r_post.get('upload_file', None) | |
328 |
|
328 | |||
329 | if file_obj is not None and hasattr(file_obj, 'filename'): |
|
329 | if file_obj is not None and hasattr(file_obj, 'filename'): | |
330 | filename = file_obj.filename |
|
330 | filename = file_obj.filename | |
331 | content = file_obj.file |
|
331 | content = file_obj.file | |
332 |
|
332 | |||
333 | node_path = os.path.join(location, filename) |
|
333 | node_path = os.path.join(location, filename) | |
334 | author = self.rhodecode_user.full_contact |
|
334 | author = self.rhodecode_user.full_contact | |
335 |
|
335 | |||
336 | if not content: |
|
336 | if not content: | |
337 | h.flash(_('No content'), category='warning') |
|
337 | h.flash(_('No content'), category='warning') | |
338 | return redirect(url('changeset_home', repo_name=c.repo_name, |
|
338 | return redirect(url('changeset_home', repo_name=c.repo_name, | |
339 | revision='tip')) |
|
339 | revision='tip')) | |
340 | if not filename: |
|
340 | if not filename: | |
341 | h.flash(_('No filename'), category='warning') |
|
341 | h.flash(_('No filename'), category='warning') | |
342 | return redirect(url('changeset_home', repo_name=c.repo_name, |
|
342 | return redirect(url('changeset_home', repo_name=c.repo_name, | |
343 | revision='tip')) |
|
343 | revision='tip')) | |
344 |
|
344 | |||
345 | try: |
|
345 | try: | |
346 | self.scm_model.create_node(repo=c.rhodecode_repo, |
|
346 | self.scm_model.create_node(repo=c.rhodecode_repo, | |
347 | repo_name=repo_name, cs=c.cs, |
|
347 | repo_name=repo_name, cs=c.cs, | |
348 | user=self.rhodecode_user, |
|
348 | user=self.rhodecode_user, | |
349 | author=author, message=message, |
|
349 | author=author, message=message, | |
350 | content=content, f_path=node_path) |
|
350 | content=content, f_path=node_path) | |
351 | h.flash(_('Successfully committed to %s') % node_path, |
|
351 | h.flash(_('Successfully committed to %s') % node_path, | |
352 | category='success') |
|
352 | category='success') | |
353 | except NodeAlreadyExistsError, e: |
|
353 | except NodeAlreadyExistsError, e: | |
354 | h.flash(_(e), category='error') |
|
354 | h.flash(_(e), category='error') | |
355 | except Exception: |
|
355 | except Exception: | |
356 | log.error(traceback.format_exc()) |
|
356 | log.error(traceback.format_exc()) | |
357 | h.flash(_('Error occurred during commit'), category='error') |
|
357 | h.flash(_('Error occurred during commit'), category='error') | |
358 | return redirect(url('changeset_home', |
|
358 | return redirect(url('changeset_home', | |
359 | repo_name=c.repo_name, revision='tip')) |
|
359 | repo_name=c.repo_name, revision='tip')) | |
360 |
|
360 | |||
361 | return render('files/files_add.html') |
|
361 | return render('files/files_add.html') | |
362 |
|
362 | |||
363 | @LoginRequired() |
|
363 | @LoginRequired() | |
364 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
364 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
365 | 'repository.admin') |
|
365 | 'repository.admin') | |
366 | def archivefile(self, repo_name, fname): |
|
366 | def archivefile(self, repo_name, fname): | |
367 |
|
367 | |||
368 | fileformat = None |
|
368 | fileformat = None | |
369 | revision = None |
|
369 | revision = None | |
370 | ext = None |
|
370 | ext = None | |
371 | subrepos = request.GET.get('subrepos') == 'true' |
|
371 | subrepos = request.GET.get('subrepos') == 'true' | |
372 |
|
372 | |||
373 | for a_type, ext_data in settings.ARCHIVE_SPECS.items(): |
|
373 | for a_type, ext_data in settings.ARCHIVE_SPECS.items(): | |
374 | archive_spec = fname.split(ext_data[1]) |
|
374 | archive_spec = fname.split(ext_data[1]) | |
375 | if len(archive_spec) == 2 and archive_spec[1] == '': |
|
375 | if len(archive_spec) == 2 and archive_spec[1] == '': | |
376 | fileformat = a_type or ext_data[1] |
|
376 | fileformat = a_type or ext_data[1] | |
377 | revision = archive_spec[0] |
|
377 | revision = archive_spec[0] | |
378 | ext = ext_data[1] |
|
378 | ext = ext_data[1] | |
379 |
|
379 | |||
380 | try: |
|
380 | try: | |
381 | dbrepo = RepoModel().get_by_repo_name(repo_name) |
|
381 | dbrepo = RepoModel().get_by_repo_name(repo_name) | |
382 | if dbrepo.enable_downloads is False: |
|
382 | if dbrepo.enable_downloads is False: | |
383 | return _('downloads disabled') |
|
383 | return _('downloads disabled') | |
384 |
|
384 | |||
385 | if c.rhodecode_repo.alias == 'hg': |
|
385 | if c.rhodecode_repo.alias == 'hg': | |
386 | # patch and reset hooks section of UI config to not run any |
|
386 | # patch and reset hooks section of UI config to not run any | |
387 | # hooks on fetching archives with subrepos |
|
387 | # hooks on fetching archives with subrepos | |
388 | for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'): |
|
388 | for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'): | |
389 | c.rhodecode_repo._repo.ui.setconfig('hooks', k, None) |
|
389 | c.rhodecode_repo._repo.ui.setconfig('hooks', k, None) | |
390 |
|
390 | |||
391 | cs = c.rhodecode_repo.get_changeset(revision) |
|
391 | cs = c.rhodecode_repo.get_changeset(revision) | |
392 | content_type = settings.ARCHIVE_SPECS[fileformat][0] |
|
392 | content_type = settings.ARCHIVE_SPECS[fileformat][0] | |
393 | except ChangesetDoesNotExistError: |
|
393 | except ChangesetDoesNotExistError: | |
394 | return _('Unknown revision %s') % revision |
|
394 | return _('Unknown revision %s') % revision | |
395 | except EmptyRepositoryError: |
|
395 | except EmptyRepositoryError: | |
396 | return _('Empty repository') |
|
396 | return _('Empty repository') | |
397 | except (ImproperArchiveTypeError, KeyError): |
|
397 | except (ImproperArchiveTypeError, KeyError): | |
398 | return _('Unknown archive type') |
|
398 | return _('Unknown archive type') | |
399 |
|
399 | |||
400 | fd, archive = tempfile.mkstemp() |
|
400 | fd, archive = tempfile.mkstemp() | |
401 | t = open(archive, 'wb') |
|
401 | t = open(archive, 'wb') | |
402 | cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos) |
|
402 | cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos) | |
403 | t.close() |
|
403 | t.close() | |
404 |
|
404 | |||
405 | def get_chunked_archive(archive): |
|
405 | def get_chunked_archive(archive): | |
406 | stream = open(archive, 'rb') |
|
406 | stream = open(archive, 'rb') | |
407 | while True: |
|
407 | while True: | |
408 | data = stream.read(16 * 1024) |
|
408 | data = stream.read(16 * 1024) | |
409 | if not data: |
|
409 | if not data: | |
410 | stream.close() |
|
410 | stream.close() | |
411 | os.close(fd) |
|
411 | os.close(fd) | |
412 | os.remove(archive) |
|
412 | os.remove(archive) | |
413 | break |
|
413 | break | |
414 | yield data |
|
414 | yield data | |
415 |
|
415 | |||
416 | response.content_disposition = str('attachment; filename=%s-%s%s' \ |
|
416 | response.content_disposition = str('attachment; filename=%s-%s%s' \ | |
417 | % (repo_name, revision[:12], ext)) |
|
417 | % (repo_name, revision[:12], ext)) | |
418 | response.content_type = str(content_type) |
|
418 | response.content_type = str(content_type) | |
419 | return get_chunked_archive(archive) |
|
419 | return get_chunked_archive(archive) | |
420 |
|
420 | |||
421 | @LoginRequired() |
|
421 | @LoginRequired() | |
422 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
422 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
423 | 'repository.admin') |
|
423 | 'repository.admin') | |
424 | def diff(self, repo_name, f_path): |
|
424 | def diff(self, repo_name, f_path): | |
425 | ignore_whitespace = request.GET.get('ignorews') == '1' |
|
425 | ignore_whitespace = request.GET.get('ignorews') == '1' | |
426 | line_context = request.GET.get('context', 3) |
|
426 | line_context = request.GET.get('context', 3) | |
427 | diff1 = request.GET.get('diff1', '') |
|
427 | diff1 = request.GET.get('diff1', '') | |
428 | diff2 = request.GET.get('diff2', '') |
|
428 | diff2 = request.GET.get('diff2', '') | |
429 | c.action = request.GET.get('diff') |
|
429 | c.action = request.GET.get('diff') | |
430 | c.no_changes = diff1 == diff2 |
|
430 | c.no_changes = diff1 == diff2 | |
431 | c.f_path = f_path |
|
431 | c.f_path = f_path | |
432 | c.big_diff = False |
|
432 | c.big_diff = False | |
433 | c.anchor_url = anchor_url |
|
433 | c.anchor_url = anchor_url | |
434 | c.ignorews_url = _ignorews_url |
|
434 | c.ignorews_url = _ignorews_url | |
435 | c.context_url = _context_url |
|
435 | c.context_url = _context_url | |
436 | c.changes = OrderedDict() |
|
436 | c.changes = OrderedDict() | |
437 | c.changes[diff2] = [] |
|
437 | c.changes[diff2] = [] | |
438 |
|
438 | |||
439 | #special case if we want a show rev only, it's impl here |
|
439 | #special case if we want a show rev only, it's impl here | |
440 | #to reduce JS and callbacks |
|
440 | #to reduce JS and callbacks | |
441 | if request.GET.get('show_rev'): |
|
441 | if request.GET.get('show_rev'): | |
442 | if str2bool(request.GET.get('annotate', 'False')): |
|
442 | if str2bool(request.GET.get('annotate', 'False')): | |
443 | _url = url('files_annotate_home', repo_name=c.repo_name, |
|
443 | _url = url('files_annotate_home', repo_name=c.repo_name, | |
444 | revision=diff1, f_path=c.f_path) |
|
444 | revision=diff1, f_path=c.f_path) | |
445 | else: |
|
445 | else: | |
446 | _url = url('files_home', repo_name=c.repo_name, |
|
446 | _url = url('files_home', repo_name=c.repo_name, | |
447 | revision=diff1, f_path=c.f_path) |
|
447 | revision=diff1, f_path=c.f_path) | |
448 |
|
448 | |||
449 | return redirect(_url) |
|
449 | return redirect(_url) | |
450 | try: |
|
450 | try: | |
451 | if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: |
|
451 | if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: | |
452 | c.changeset_1 = c.rhodecode_repo.get_changeset(diff1) |
|
452 | c.changeset_1 = c.rhodecode_repo.get_changeset(diff1) | |
453 | node1 = c.changeset_1.get_node(f_path) |
|
453 | node1 = c.changeset_1.get_node(f_path) | |
454 | else: |
|
454 | else: | |
455 | c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo) |
|
455 | c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo) | |
456 | node1 = FileNode('.', '', changeset=c.changeset_1) |
|
456 | node1 = FileNode('.', '', changeset=c.changeset_1) | |
457 |
|
457 | |||
458 | if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]: |
|
458 | if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]: | |
459 | c.changeset_2 = c.rhodecode_repo.get_changeset(diff2) |
|
459 | c.changeset_2 = c.rhodecode_repo.get_changeset(diff2) | |
460 | node2 = c.changeset_2.get_node(f_path) |
|
460 | node2 = c.changeset_2.get_node(f_path) | |
461 | else: |
|
461 | else: | |
462 | c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo) |
|
462 | c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo) | |
463 | node2 = FileNode('.', '', changeset=c.changeset_2) |
|
463 | node2 = FileNode('.', '', changeset=c.changeset_2) | |
464 | except RepositoryError: |
|
464 | except RepositoryError: | |
465 | return redirect(url('files_home', repo_name=c.repo_name, |
|
465 | return redirect(url('files_home', repo_name=c.repo_name, | |
466 | f_path=f_path)) |
|
466 | f_path=f_path)) | |
467 |
|
467 | |||
468 | if c.action == 'download': |
|
468 | if c.action == 'download': | |
469 | _diff = diffs.get_gitdiff(node1, node2, |
|
469 | _diff = diffs.get_gitdiff(node1, node2, | |
470 | ignore_whitespace=ignore_whitespace, |
|
470 | ignore_whitespace=ignore_whitespace, | |
471 | context=line_context) |
|
471 | context=line_context) | |
472 | diff = diffs.DiffProcessor(_diff, format='gitdiff') |
|
472 | diff = diffs.DiffProcessor(_diff, format='gitdiff') | |
473 |
|
473 | |||
474 | diff_name = '%s_vs_%s.diff' % (diff1, diff2) |
|
474 | diff_name = '%s_vs_%s.diff' % (diff1, diff2) | |
475 | response.content_type = 'text/plain' |
|
475 | response.content_type = 'text/plain' | |
476 | response.content_disposition = ( |
|
476 | response.content_disposition = ( | |
477 | 'attachment; filename=%s' % diff_name |
|
477 | 'attachment; filename=%s' % diff_name | |
478 | ) |
|
478 | ) | |
479 | return diff.raw_diff() |
|
479 | return diff.raw_diff() | |
480 |
|
480 | |||
481 | elif c.action == 'raw': |
|
481 | elif c.action == 'raw': | |
482 | _diff = diffs.get_gitdiff(node1, node2, |
|
482 | _diff = diffs.get_gitdiff(node1, node2, | |
483 | ignore_whitespace=ignore_whitespace, |
|
483 | ignore_whitespace=ignore_whitespace, | |
484 | context=line_context) |
|
484 | context=line_context) | |
485 | diff = diffs.DiffProcessor(_diff, format='gitdiff') |
|
485 | diff = diffs.DiffProcessor(_diff, format='gitdiff') | |
486 | response.content_type = 'text/plain' |
|
486 | response.content_type = 'text/plain' | |
487 | return diff.raw_diff() |
|
487 | return diff.raw_diff() | |
488 |
|
488 | |||
489 | else: |
|
489 | else: | |
490 | fid = h.FID(diff2, node2.path) |
|
490 | fid = h.FID(diff2, node2.path) | |
491 | line_context_lcl = get_line_ctx(fid, request.GET) |
|
491 | line_context_lcl = get_line_ctx(fid, request.GET) | |
492 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) |
|
492 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) | |
493 |
|
493 | |||
494 | lim = request.GET.get('fulldiff') or self.cut_off_limit |
|
494 | lim = request.GET.get('fulldiff') or self.cut_off_limit | |
495 | _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1, |
|
495 | _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1, | |
496 | filenode_new=node2, |
|
496 | filenode_new=node2, | |
497 | cut_off_limit=lim, |
|
497 | cut_off_limit=lim, | |
498 | ignore_whitespace=ign_whitespace_lcl, |
|
498 | ignore_whitespace=ign_whitespace_lcl, | |
499 | line_context=line_context_lcl, |
|
499 | line_context=line_context_lcl, | |
500 | enable_comments=False) |
|
500 | enable_comments=False) | |
501 |
|
501 | |||
502 | c.changes = [('', node2, diff, cs1, cs2, st,)] |
|
502 | c.changes = [('', node2, diff, cs1, cs2, st,)] | |
503 |
|
503 | |||
504 | return render('files/file_diff.html') |
|
504 | return render('files/file_diff.html') | |
505 |
|
505 | |||
506 | def _get_node_history(self, cs, f_path, changesets=None): |
|
506 | def _get_node_history(self, cs, f_path, changesets=None): | |
507 | if cs is None: |
|
507 | if cs is None: | |
508 | # if we pass empty CS calculate history based on tip |
|
508 | # if we pass empty CS calculate history based on tip | |
509 | cs = c.rhodecode_repo.get_changeset() |
|
509 | cs = c.rhodecode_repo.get_changeset() | |
510 | if changesets is None: |
|
510 | if changesets is None: | |
511 | changesets = cs.get_file_history(f_path) |
|
511 | changesets = cs.get_file_history(f_path) | |
512 |
|
512 | |||
513 | hist_l = [] |
|
513 | hist_l = [] | |
514 |
|
514 | |||
515 | changesets_group = ([], _("Changesets")) |
|
515 | changesets_group = ([], _("Changesets")) | |
516 | branches_group = ([], _("Branches")) |
|
516 | branches_group = ([], _("Branches")) | |
517 | tags_group = ([], _("Tags")) |
|
517 | tags_group = ([], _("Tags")) | |
518 | _hg = cs.repository.alias == 'hg' |
|
518 | _hg = cs.repository.alias == 'hg' | |
519 | for chs in changesets: |
|
519 | for chs in changesets: | |
520 | _branch = '(%s)' % chs.branch if _hg else '' |
|
520 | _branch = '(%s)' % chs.branch if _hg else '' | |
521 | n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch) |
|
521 | n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch) | |
522 | changesets_group[0].append((chs.raw_id, n_desc,)) |
|
522 | changesets_group[0].append((chs.raw_id, n_desc,)) | |
523 |
|
523 | |||
524 | hist_l.append(changesets_group) |
|
524 | hist_l.append(changesets_group) | |
525 |
|
525 | |||
526 | for name, chs in c.rhodecode_repo.branches.items(): |
|
526 | for name, chs in c.rhodecode_repo.branches.items(): | |
527 | branches_group[0].append((chs, name),) |
|
527 | branches_group[0].append((chs, name),) | |
528 | hist_l.append(branches_group) |
|
528 | hist_l.append(branches_group) | |
529 |
|
529 | |||
530 | for name, chs in c.rhodecode_repo.tags.items(): |
|
530 | for name, chs in c.rhodecode_repo.tags.items(): | |
531 | tags_group[0].append((chs, name),) |
|
531 | tags_group[0].append((chs, name),) | |
532 | hist_l.append(tags_group) |
|
532 | hist_l.append(tags_group) | |
533 |
|
533 | |||
534 | return hist_l |
|
534 | return hist_l | |
535 |
|
535 | |||
536 | @LoginRequired() |
|
536 | @LoginRequired() | |
537 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
537 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
538 | 'repository.admin') |
|
538 | 'repository.admin') | |
539 | @jsonify |
|
539 | @jsonify | |
540 | def nodelist(self, repo_name, revision, f_path): |
|
540 | def nodelist(self, repo_name, revision, f_path): | |
541 | if request.environ.get('HTTP_X_PARTIAL_XHR'): |
|
541 | if request.environ.get('HTTP_X_PARTIAL_XHR'): | |
542 | cs = self.__get_cs_or_redirect(revision, repo_name) |
|
542 | cs = self.__get_cs_or_redirect(revision, repo_name) | |
543 | _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path, |
|
543 | _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path, | |
544 | flat=False) |
|
544 | flat=False) | |
545 | return {'nodes': _d + _f} |
|
545 | return {'nodes': _d + _f} |
@@ -1,31 +1,31 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.lib.middleware.errormator |
|
3 | rhodecode.lib.middleware.errormator | |
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | middleware to handle errormator publishing of errors |
|
6 | middleware to handle errormator publishing of errors | |
7 |
|
7 | |||
8 | :created_on: October 18, 2012 |
|
8 | :created_on: October 18, 2012 | |
9 | :author: marcink |
|
9 | :author: marcink | |
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> |
|
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> | |
11 | :license: GPLv3, see COPYING for more details. |
|
11 | :license: GPLv3, see COPYING for more details. | |
12 | """ |
|
12 | """ | |
13 | # This program is free software: you can redistribute it and/or modify |
|
13 | # This program is free software: you can redistribute it and/or modify | |
14 | # it under the terms of the GNU General Public License as published by |
|
14 | # it under the terms of the GNU General Public License as published by | |
15 | # the Free Software Foundation, either version 3 of the License, or |
|
15 | # the Free Software Foundation, either version 3 of the License, or | |
16 | # (at your option) any later version. |
|
16 | # (at your option) any later version. | |
17 | # |
|
17 | # | |
18 | # This program is distributed in the hope that it will be useful, |
|
18 | # This program is distributed in the hope that it will be useful, | |
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | # GNU General Public License for more details. |
|
21 | # GNU General Public License for more details. | |
22 | # |
|
22 | # | |
23 | # You should have received a copy of the GNU General Public License |
|
23 | # You should have received a copy of the GNU General Public License | |
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 |
|
25 | |||
26 | try: |
|
26 | try: | |
27 | from errormator_client import make_errormator_middleware |
|
27 | from errormator_client import make_errormator_middleware | |
28 | except ImportError: |
|
28 | except ImportError: | |
29 | Errormator = None |
|
29 | Errormator = None | |
30 | else: |
|
30 | else: | |
31 | Errormator = make_errormator_middleware No newline at end of file |
|
31 | Errormator = make_errormator_middleware |
@@ -1,47 +1,47 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.lib.middleware.sentry |
|
3 | rhodecode.lib.middleware.sentry | |
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | middleware to handle sentry/raven publishing of errors |
|
6 | middleware to handle sentry/raven publishing of errors | |
7 |
|
7 | |||
8 | :created_on: September 18, 2012 |
|
8 | :created_on: September 18, 2012 | |
9 | :author: marcink |
|
9 | :author: marcink | |
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> |
|
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> | |
11 | :license: GPLv3, see COPYING for more details. |
|
11 | :license: GPLv3, see COPYING for more details. | |
12 | """ |
|
12 | """ | |
13 | # This program is free software: you can redistribute it and/or modify |
|
13 | # This program is free software: you can redistribute it and/or modify | |
14 | # it under the terms of the GNU General Public License as published by |
|
14 | # it under the terms of the GNU General Public License as published by | |
15 | # the Free Software Foundation, either version 3 of the License, or |
|
15 | # the Free Software Foundation, either version 3 of the License, or | |
16 | # (at your option) any later version. |
|
16 | # (at your option) any later version. | |
17 | # |
|
17 | # | |
18 | # This program is distributed in the hope that it will be useful, |
|
18 | # This program is distributed in the hope that it will be useful, | |
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | # GNU General Public License for more details. |
|
21 | # GNU General Public License for more details. | |
22 | # |
|
22 | # | |
23 | # You should have received a copy of the GNU General Public License |
|
23 | # You should have received a copy of the GNU General Public License | |
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 |
|
25 | |||
26 | try: |
|
26 | try: | |
27 | from raven.base import Client |
|
27 | from raven.base import Client | |
28 | from raven.contrib.pylons import list_from_setting |
|
28 | from raven.contrib.pylons import list_from_setting | |
29 | from raven.middleware import Sentry as Middleware |
|
29 | from raven.middleware import Sentry as Middleware | |
30 | except ImportError: |
|
30 | except ImportError: | |
31 | Sentry = None |
|
31 | Sentry = None | |
32 | else: |
|
32 | else: | |
33 | class Sentry(Middleware): |
|
33 | class Sentry(Middleware): | |
34 | def __init__(self, app, config, client_cls=Client): |
|
34 | def __init__(self, app, config, client_cls=Client): | |
35 | client = client_cls( |
|
35 | client = client_cls( | |
36 | dsn=config.get('sentry.dsn'), |
|
36 | dsn=config.get('sentry.dsn'), | |
37 | servers=list_from_setting(config, 'sentry.servers'), |
|
37 | servers=list_from_setting(config, 'sentry.servers'), | |
38 | name=config.get('sentry.name'), |
|
38 | name=config.get('sentry.name'), | |
39 | key=config.get('sentry.key'), |
|
39 | key=config.get('sentry.key'), | |
40 | public_key=config.get('sentry.public_key'), |
|
40 | public_key=config.get('sentry.public_key'), | |
41 | secret_key=config.get('sentry.secret_key'), |
|
41 | secret_key=config.get('sentry.secret_key'), | |
42 | project=config.get('sentry.project'), |
|
42 | project=config.get('sentry.project'), | |
43 | site=config.get('sentry.site'), |
|
43 | site=config.get('sentry.site'), | |
44 | include_paths=list_from_setting(config, 'sentry.include_paths'), |
|
44 | include_paths=list_from_setting(config, 'sentry.include_paths'), | |
45 | exclude_paths=list_from_setting(config, 'sentry.exclude_paths'), |
|
45 | exclude_paths=list_from_setting(config, 'sentry.exclude_paths'), | |
46 | ) |
|
46 | ) | |
47 | super(Sentry, self).__init__(app, client) No newline at end of file |
|
47 | super(Sentry, self).__init__(app, client) |
@@ -1,302 +1,302 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 | ${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name} |
|
6 | ${_('%s Changelog') % c.repo_name} - ${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 | » |
|
11 | » | |
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 | » |
|
13 | » | |
14 | <% size = c.size if c.size <= c.total_cs else c.total_cs %> |
|
14 | <% size = c.size if c.size <= c.total_cs else c.total_cs %> | |
15 | ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)} |
|
15 | ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)} | |
16 | </%def> |
|
16 | </%def> | |
17 |
|
17 | |||
18 | <%def name="page_nav()"> |
|
18 | <%def name="page_nav()"> | |
19 | ${self.menu('changelog')} |
|
19 | ${self.menu('changelog')} | |
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 | % if c.pagination: |
|
29 | % if c.pagination: | |
30 | <div id="graph"> |
|
30 | <div id="graph"> | |
31 | <div id="graph_nodes"> |
|
31 | <div id="graph_nodes"> | |
32 | <canvas id="graph_canvas"></canvas> |
|
32 | <canvas id="graph_canvas"></canvas> | |
33 | </div> |
|
33 | </div> | |
34 | <div id="graph_content"> |
|
34 | <div id="graph_content"> | |
35 | <div class="info_box" style="clear: both;padding: 10px 6px;vertical-align: right;text-align: right;"> |
|
35 | <div class="info_box" style="clear: both;padding: 10px 6px;vertical-align: right;text-align: right;"> | |
36 | <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a> |
|
36 | <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a> | |
37 | <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a> |
|
37 | <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a> | |
38 |
|
38 | |||
39 | %if c.rhodecode_db_repo.fork: |
|
39 | %if c.rhodecode_db_repo.fork: | |
40 | <a title="${_('compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name)}" class="ui-btn small">${_('Compare fork')}</a> |
|
40 | <a title="${_('compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name)}" class="ui-btn small">${_('Compare fork')}</a> | |
41 | %endif |
|
41 | %endif | |
42 | %if h.is_hg(c.rhodecode_repo): |
|
42 | %if h.is_hg(c.rhodecode_repo): | |
43 | <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a> |
|
43 | <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a> | |
44 | %endif |
|
44 | %endif | |
45 | </div> |
|
45 | </div> | |
46 | <div class="container_header"> |
|
46 | <div class="container_header"> | |
47 | ${h.form(h.url.current(),method='get')} |
|
47 | ${h.form(h.url.current(),method='get')} | |
48 | <div class="info_box" style="float:left"> |
|
48 | <div class="info_box" style="float:left"> | |
49 | ${h.submit('set',_('Show'),class_="ui-btn")} |
|
49 | ${h.submit('set',_('Show'),class_="ui-btn")} | |
50 | ${h.text('size',size=1,value=c.size)} |
|
50 | ${h.text('size',size=1,value=c.size)} | |
51 | ${_('revisions')} |
|
51 | ${_('revisions')} | |
52 | </div> |
|
52 | </div> | |
53 | ${h.end_form()} |
|
53 | ${h.end_form()} | |
54 | <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div> |
|
54 | <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div> | |
55 | </div> |
|
55 | </div> | |
56 |
|
56 | |||
57 | %for cnt,cs in enumerate(c.pagination): |
|
57 | %for cnt,cs in enumerate(c.pagination): | |
58 | <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}"> |
|
58 | <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}"> | |
59 | <div class="left"> |
|
59 | <div class="left"> | |
60 | <div> |
|
60 | <div> | |
61 | ${h.checkbox(cs.raw_id,class_="changeset_range")} |
|
61 | ${h.checkbox(cs.raw_id,class_="changeset_range")} | |
62 | <span class="tooltip" title="${h.tooltip(h.age(cs.date))}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span> |
|
62 | <span class="tooltip" title="${h.tooltip(h.age(cs.date))}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span> | |
63 | </div> |
|
63 | </div> | |
64 | <div class="author"> |
|
64 | <div class="author"> | |
65 | <div class="gravatar"> |
|
65 | <div class="gravatar"> | |
66 | <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/> |
|
66 | <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/> | |
67 | </div> |
|
67 | </div> | |
68 | <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div> |
|
68 | <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div> | |
69 | </div> |
|
69 | </div> | |
70 | <div class="date">${h.fmt_date(cs.date)}</div> |
|
70 | <div class="date">${h.fmt_date(cs.date)}</div> | |
71 | </div> |
|
71 | </div> | |
72 | <div class="mid"> |
|
72 | <div class="mid"> | |
73 | <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div> |
|
73 | <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div> | |
74 | <div class="expand"><span class="expandtext">↓ ${_('show more')} ↓</span></div> |
|
74 | <div class="expand"><span class="expandtext">↓ ${_('show more')} ↓</span></div> | |
75 | </div> |
|
75 | </div> | |
76 | <div class="right"> |
|
76 | <div class="right"> | |
77 | <div class="changes"> |
|
77 | <div class="changes"> | |
78 | <div id="changed_total_${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${h.tooltip(_('Affected number of files, click to show more details'))}">${len(cs.affected_files)}</div> |
|
78 | <div id="changed_total_${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${h.tooltip(_('Affected number of files, click to show more details'))}">${len(cs.affected_files)}</div> | |
79 | <div class="comments-container"> |
|
79 | <div class="comments-container"> | |
80 | %if len(c.comments.get(cs.raw_id,[])) > 0: |
|
80 | %if len(c.comments.get(cs.raw_id,[])) > 0: | |
81 | <div class="comments-cnt" title="${('comments')}"> |
|
81 | <div class="comments-cnt" title="${('comments')}"> | |
82 | <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}"> |
|
82 | <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}"> | |
83 | <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div> |
|
83 | <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div> | |
84 | <img src="${h.url('/images/icons/comments.png')}"> |
|
84 | <img src="${h.url('/images/icons/comments.png')}"> | |
85 | </a> |
|
85 | </a> | |
86 | </div> |
|
86 | </div> | |
87 | %endif |
|
87 | %endif | |
88 | </div> |
|
88 | </div> | |
89 | <div class="changeset-status-container"> |
|
89 | <div class="changeset-status-container"> | |
90 | %if c.statuses.get(cs.raw_id): |
|
90 | %if c.statuses.get(cs.raw_id): | |
91 | <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div> |
|
91 | <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div> | |
92 | <div class="changeset-status-ico"> |
|
92 | <div class="changeset-status-ico"> | |
93 | %if c.statuses.get(cs.raw_id)[2]: |
|
93 | %if c.statuses.get(cs.raw_id)[2]: | |
94 | <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a> |
|
94 | <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a> | |
95 | %else: |
|
95 | %else: | |
96 | <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /> |
|
96 | <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /> | |
97 | %endif |
|
97 | %endif | |
98 | </div> |
|
98 | </div> | |
99 | %endif |
|
99 | %endif | |
100 | </div> |
|
100 | </div> | |
101 | </div> |
|
101 | </div> | |
102 | %if cs.parents: |
|
102 | %if cs.parents: | |
103 | %for p_cs in reversed(cs.parents): |
|
103 | %for p_cs in reversed(cs.parents): | |
104 | <div class="parent">${_('Parent')} |
|
104 | <div class="parent">${_('Parent')} | |
105 | <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id), |
|
105 | <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id), | |
106 | h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span> |
|
106 | h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span> | |
107 | </div> |
|
107 | </div> | |
108 | %endfor |
|
108 | %endfor | |
109 | %else: |
|
109 | %else: | |
110 | <div class="parent">${_('No parents')}</div> |
|
110 | <div class="parent">${_('No parents')}</div> | |
111 | %endif |
|
111 | %endif | |
112 |
|
112 | |||
113 | <span class="logtags"> |
|
113 | <span class="logtags"> | |
114 | %if len(cs.parents)>1: |
|
114 | %if len(cs.parents)>1: | |
115 | <span class="merge">${_('merge')}</span> |
|
115 | <span class="merge">${_('merge')}</span> | |
116 | %endif |
|
116 | %endif | |
117 | %if cs.branch: |
|
117 | %if cs.branch: | |
118 | <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}"> |
|
118 | <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}"> | |
119 | ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} |
|
119 | ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} | |
120 | </span> |
|
120 | </span> | |
121 | %endif |
|
121 | %endif | |
122 | %if h.is_hg(c.rhodecode_repo): |
|
122 | %if h.is_hg(c.rhodecode_repo): | |
123 | %for book in cs.bookmarks: |
|
123 | %for book in cs.bookmarks: | |
124 | <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}"> |
|
124 | <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}"> | |
125 | ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} |
|
125 | ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} | |
126 | </span> |
|
126 | </span> | |
127 | %endfor |
|
127 | %endfor | |
128 | %endif |
|
128 | %endif | |
129 | %for tag in cs.tags: |
|
129 | %for tag in cs.tags: | |
130 | <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}"> |
|
130 | <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}"> | |
131 | ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span> |
|
131 | ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span> | |
132 | %endfor |
|
132 | %endfor | |
133 | </span> |
|
133 | </span> | |
134 | </div> |
|
134 | </div> | |
135 | </div> |
|
135 | </div> | |
136 |
|
136 | |||
137 | %endfor |
|
137 | %endfor | |
138 | <div class="pagination-wh pagination-left"> |
|
138 | <div class="pagination-wh pagination-left"> | |
139 | ${c.pagination.pager('$link_previous ~2~ $link_next')} |
|
139 | ${c.pagination.pager('$link_previous ~2~ $link_next')} | |
140 | </div> |
|
140 | </div> | |
141 | </div> |
|
141 | </div> | |
142 | </div> |
|
142 | </div> | |
143 |
|
143 | |||
144 | <script type="text/javascript" src="${h.url('/js/graph.js')}"></script> |
|
144 | <script type="text/javascript" src="${h.url('/js/graph.js')}"></script> | |
145 | <script type="text/javascript"> |
|
145 | <script type="text/javascript"> | |
146 | YAHOO.util.Event.onDOMReady(function(){ |
|
146 | YAHOO.util.Event.onDOMReady(function(){ | |
147 |
|
147 | |||
148 | //Monitor range checkboxes and build a link to changesets |
|
148 | //Monitor range checkboxes and build a link to changesets | |
149 | //ranges |
|
149 | //ranges | |
150 | var checkboxes = YUD.getElementsByClassName('changeset_range'); |
|
150 | var checkboxes = YUD.getElementsByClassName('changeset_range'); | |
151 | var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}"; |
|
151 | var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}"; | |
152 | YUE.on(checkboxes,'click',function(e){ |
|
152 | YUE.on(checkboxes,'click',function(e){ | |
153 | var clicked_cb = e.currentTarget; |
|
153 | var clicked_cb = e.currentTarget; | |
154 | var checked_checkboxes = []; |
|
154 | var checked_checkboxes = []; | |
155 | for (pos in checkboxes){ |
|
155 | for (pos in checkboxes){ | |
156 | if(checkboxes[pos].checked){ |
|
156 | if(checkboxes[pos].checked){ | |
157 | checked_checkboxes.push(checkboxes[pos]); |
|
157 | checked_checkboxes.push(checkboxes[pos]); | |
158 | } |
|
158 | } | |
159 | } |
|
159 | } | |
160 |
|
160 | |||
161 | if(checked_checkboxes.length>0){ |
|
161 | if(checked_checkboxes.length>0){ | |
162 | // modify open pull request to show we have selected cs |
|
162 | // modify open pull request to show we have selected cs | |
163 | YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets']; |
|
163 | YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets']; | |
164 |
|
164 | |||
165 | }else{ |
|
165 | }else{ | |
166 |
YUD.get('open_new_pr').innerHTML = _TM['Open new pull request']; |
|
166 | YUD.get('open_new_pr').innerHTML = _TM['Open new pull request']; | |
167 | } |
|
167 | } | |
168 |
|
168 | |||
169 | if(checked_checkboxes.length>1){ |
|
169 | if(checked_checkboxes.length>1){ | |
170 | var rev_end = checked_checkboxes[0].name; |
|
170 | var rev_end = checked_checkboxes[0].name; | |
171 | var rev_start = checked_checkboxes[checked_checkboxes.length-1].name; |
|
171 | var rev_start = checked_checkboxes[checked_checkboxes.length-1].name; | |
172 |
|
172 | |||
173 | // now select all checkboxes in the middle. |
|
173 | // now select all checkboxes in the middle. | |
174 | var checked = false; |
|
174 | var checked = false; | |
175 | for (var i=0; i<checkboxes.length; i++){ |
|
175 | for (var i=0; i<checkboxes.length; i++){ | |
176 | var cb = checkboxes[i]; |
|
176 | var cb = checkboxes[i]; | |
177 | var rev = cb.name; |
|
177 | var rev = cb.name; | |
178 |
|
178 | |||
179 | if (rev == rev_end){ |
|
179 | if (rev == rev_end){ | |
180 | checked = true; |
|
180 | checked = true; | |
181 | } |
|
181 | } | |
182 | if (checked){ |
|
182 | if (checked){ | |
183 | cb.checked = true; |
|
183 | cb.checked = true; | |
184 | } |
|
184 | } | |
185 | else{ |
|
185 | else{ | |
186 | cb.checked = false; |
|
186 | cb.checked = false; | |
187 | } |
|
187 | } | |
188 | if (rev == rev_start){ |
|
188 | if (rev == rev_start){ | |
189 | checked = false; |
|
189 | checked = false; | |
190 | } |
|
190 | } | |
191 |
|
191 | |||
192 | } |
|
192 | } | |
193 |
|
193 | |||
194 | var url = url_tmpl.replace('__REVRANGE__', |
|
194 | var url = url_tmpl.replace('__REVRANGE__', | |
195 | rev_start+'...'+rev_end); |
|
195 | rev_start+'...'+rev_end); | |
196 |
|
196 | |||
197 | var link = _TM['Show selected changes __S -> __E']; |
|
197 | var link = _TM['Show selected changes __S -> __E']; | |
198 | link = link.replace('__S',rev_start.substr(0,6)); |
|
198 | link = link.replace('__S',rev_start.substr(0,6)); | |
199 | link = link.replace('__E',rev_end.substr(0,6)); |
|
199 | link = link.replace('__E',rev_end.substr(0,6)); | |
200 | YUD.get('rev_range_container').href = url; |
|
200 | YUD.get('rev_range_container').href = url; | |
201 | YUD.get('rev_range_container').innerHTML = link; |
|
201 | YUD.get('rev_range_container').innerHTML = link; | |
202 | YUD.setStyle('rev_range_container','display',''); |
|
202 | YUD.setStyle('rev_range_container','display',''); | |
203 | YUD.setStyle('rev_range_clear','display',''); |
|
203 | YUD.setStyle('rev_range_clear','display',''); | |
204 |
|
204 | |||
205 | } |
|
205 | } | |
206 | else{ |
|
206 | else{ | |
207 | YUD.setStyle('rev_range_container','display','none'); |
|
207 | YUD.setStyle('rev_range_container','display','none'); | |
208 | YUD.setStyle('rev_range_clear','display','none'); |
|
208 | YUD.setStyle('rev_range_clear','display','none'); | |
209 | } |
|
209 | } | |
210 | }); |
|
210 | }); | |
211 | YUE.on('rev_range_clear','click',function(e){ |
|
211 | YUE.on('rev_range_clear','click',function(e){ | |
212 | for (var i=0; i<checkboxes.length; i++){ |
|
212 | for (var i=0; i<checkboxes.length; i++){ | |
213 | var cb = checkboxes[i]; |
|
213 | var cb = checkboxes[i]; | |
214 | cb.checked = false; |
|
214 | cb.checked = false; | |
215 | } |
|
215 | } | |
216 | YUE.preventDefault(e); |
|
216 | YUE.preventDefault(e); | |
217 | }) |
|
217 | }) | |
218 | var msgs = YUQ('.message'); |
|
218 | var msgs = YUQ('.message'); | |
219 | // get first element height |
|
219 | // get first element height | |
220 | var el = YUQ('#graph_content .container')[0]; |
|
220 | var el = YUQ('#graph_content .container')[0]; | |
221 | var row_h = el.clientHeight; |
|
221 | var row_h = el.clientHeight; | |
222 | for(var i=0;i<msgs.length;i++){ |
|
222 | for(var i=0;i<msgs.length;i++){ | |
223 | var m = msgs[i]; |
|
223 | var m = msgs[i]; | |
224 |
|
224 | |||
225 | var h = m.clientHeight; |
|
225 | var h = m.clientHeight; | |
226 | var pad = YUD.getStyle(m,'padding'); |
|
226 | var pad = YUD.getStyle(m,'padding'); | |
227 | if(h > row_h){ |
|
227 | if(h > row_h){ | |
228 | var offset = row_h - (h+12); |
|
228 | var offset = row_h - (h+12); | |
229 | YUD.setStyle(m.nextElementSibling,'display','block'); |
|
229 | YUD.setStyle(m.nextElementSibling,'display','block'); | |
230 | YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px'); |
|
230 | YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px'); | |
231 | }; |
|
231 | }; | |
232 | } |
|
232 | } | |
233 | YUE.on(YUQ('.expand'),'click',function(e){ |
|
233 | YUE.on(YUQ('.expand'),'click',function(e){ | |
234 | var elem = e.currentTarget.parentNode.parentNode; |
|
234 | var elem = e.currentTarget.parentNode.parentNode; | |
235 | YUD.setStyle(e.currentTarget,'display','none'); |
|
235 | YUD.setStyle(e.currentTarget,'display','none'); | |
236 | YUD.setStyle(elem,'height','auto'); |
|
236 | YUD.setStyle(elem,'height','auto'); | |
237 |
|
237 | |||
238 | //redraw the graph, line_count and jsdata are global vars |
|
238 | //redraw the graph, line_count and jsdata are global vars | |
239 | set_canvas(100); |
|
239 | set_canvas(100); | |
240 |
|
240 | |||
241 | var r = new BranchRenderer(); |
|
241 | var r = new BranchRenderer(); | |
242 | r.render(jsdata,100,line_count); |
|
242 | r.render(jsdata,100,line_count); | |
243 |
|
243 | |||
244 | }) |
|
244 | }) | |
245 |
|
245 | |||
246 | // Fetch changeset details |
|
246 | // Fetch changeset details | |
247 | YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){ |
|
247 | YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){ | |
248 | var id = e.currentTarget.id; |
|
248 | var id = e.currentTarget.id; | |
249 | var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}"; |
|
249 | var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}"; | |
250 | var url = url.replace('__CS__',id.replace('changed_total_','')); |
|
250 | var url = url.replace('__CS__',id.replace('changed_total_','')); | |
251 | ypjax(url,id,function(){tooltip_activate()}); |
|
251 | ypjax(url,id,function(){tooltip_activate()}); | |
252 | }); |
|
252 | }); | |
253 |
|
253 | |||
254 | // change branch filter |
|
254 | // change branch filter | |
255 | YUE.on(YUD.get('branch_filter'),'change',function(e){ |
|
255 | YUE.on(YUD.get('branch_filter'),'change',function(e){ | |
256 | var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value; |
|
256 | var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value; | |
257 | var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}"; |
|
257 | var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}"; | |
258 | var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}"; |
|
258 | var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}"; | |
259 | var url = url.replace('__BRANCH__',selected_branch); |
|
259 | var url = url.replace('__BRANCH__',selected_branch); | |
260 | if(selected_branch != ''){ |
|
260 | if(selected_branch != ''){ | |
261 | window.location = url; |
|
261 | window.location = url; | |
262 | }else{ |
|
262 | }else{ | |
263 | window.location = url_main; |
|
263 | window.location = url_main; | |
264 | } |
|
264 | } | |
265 |
|
265 | |||
266 | }); |
|
266 | }); | |
267 |
|
267 | |||
268 | function set_canvas(width) { |
|
268 | function set_canvas(width) { | |
269 | var c = document.getElementById('graph_nodes'); |
|
269 | var c = document.getElementById('graph_nodes'); | |
270 | var t = document.getElementById('graph_content'); |
|
270 | var t = document.getElementById('graph_content'); | |
271 | canvas = document.getElementById('graph_canvas'); |
|
271 | canvas = document.getElementById('graph_canvas'); | |
272 | var div_h = t.clientHeight; |
|
272 | var div_h = t.clientHeight; | |
273 | c.style.height=div_h+'px'; |
|
273 | c.style.height=div_h+'px'; | |
274 | canvas.setAttribute('height',div_h); |
|
274 | canvas.setAttribute('height',div_h); | |
275 | c.style.height=width+'px'; |
|
275 | c.style.height=width+'px'; | |
276 | canvas.setAttribute('width',width); |
|
276 | canvas.setAttribute('width',width); | |
277 | }; |
|
277 | }; | |
278 | var heads = 1; |
|
278 | var heads = 1; | |
279 | var line_count = 0; |
|
279 | var line_count = 0; | |
280 | var jsdata = ${c.jsdata|n}; |
|
280 | var jsdata = ${c.jsdata|n}; | |
281 |
|
281 | |||
282 | for (var i=0;i<jsdata.length;i++) { |
|
282 | for (var i=0;i<jsdata.length;i++) { | |
283 | var in_l = jsdata[i][2]; |
|
283 | var in_l = jsdata[i][2]; | |
284 | for (var j in in_l) { |
|
284 | for (var j in in_l) { | |
285 | var m = in_l[j][1]; |
|
285 | var m = in_l[j][1]; | |
286 | if (m > line_count) |
|
286 | if (m > line_count) | |
287 | line_count = m; |
|
287 | line_count = m; | |
288 | } |
|
288 | } | |
289 | } |
|
289 | } | |
290 | set_canvas(100); |
|
290 | set_canvas(100); | |
291 |
|
291 | |||
292 | var r = new BranchRenderer(); |
|
292 | var r = new BranchRenderer(); | |
293 | r.render(jsdata,100,line_count); |
|
293 | r.render(jsdata,100,line_count); | |
294 |
|
294 | |||
295 | }); |
|
295 | }); | |
296 | </script> |
|
296 | </script> | |
297 | %else: |
|
297 | %else: | |
298 | ${_('There are no changes yet')} |
|
298 | ${_('There are no changes yet')} | |
299 | %endif |
|
299 | %endif | |
300 | </div> |
|
300 | </div> | |
301 | </div> |
|
301 | </div> | |
302 | </%def> |
|
302 | </%def> |
@@ -1,122 +1,122 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 | ${_('%s Changesets') % c.repo_name} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name} |
|
5 | ${_('%s Changesets') % c.repo_name} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name} | |
6 | </%def> |
|
6 | </%def> | |
7 |
|
7 | |||
8 | <%def name="breadcrumbs_links()"> |
|
8 | <%def name="breadcrumbs_links()"> | |
9 | ${h.link_to(_(u'Home'),h.url('/'))} |
|
9 | ${h.link_to(_(u'Home'),h.url('/'))} | |
10 | » |
|
10 | » | |
11 | ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))} |
|
11 | ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))} | |
12 | » |
|
12 | » | |
13 | ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} |
|
13 | ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} | |
14 | </%def> |
|
14 | </%def> | |
15 |
|
15 | |||
16 | <%def name="page_nav()"> |
|
16 | <%def name="page_nav()"> | |
17 | ${self.menu('changelog')} |
|
17 | ${self.menu('changelog')} | |
18 | </%def> |
|
18 | </%def> | |
19 |
|
19 | |||
20 | <%def name="main()"> |
|
20 | <%def name="main()"> | |
21 | <div class="box"> |
|
21 | <div class="box"> | |
22 | <!-- box / title --> |
|
22 | <!-- box / title --> | |
23 | <div class="title"> |
|
23 | <div class="title"> | |
24 | ${self.breadcrumbs()} |
|
24 | ${self.breadcrumbs()} | |
25 | </div> |
|
25 | </div> | |
26 | <div class="table"> |
|
26 | <div class="table"> | |
27 | <div id="body" class="diffblock"> |
|
27 | <div id="body" class="diffblock"> | |
28 | <div class="code-header cv"> |
|
28 | <div class="code-header cv"> | |
29 | <h3 class="code-header-title">${_('Compare View')}</h3> |
|
29 | <h3 class="code-header-title">${_('Compare View')}</h3> | |
30 | <div> |
|
30 | <div> | |
31 | ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} |
|
31 | ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} | |
32 | </div> |
|
32 | </div> | |
33 | </div> |
|
33 | </div> | |
34 | </div> |
|
34 | </div> | |
35 | <div id="changeset_compare_view_content"> |
|
35 | <div id="changeset_compare_view_content"> | |
36 | <div class="container"> |
|
36 | <div class="container"> | |
37 | <table class="compare_view_commits noborder"> |
|
37 | <table class="compare_view_commits noborder"> | |
38 | %for cnt,cs in enumerate(c.cs_ranges): |
|
38 | %for cnt,cs in enumerate(c.cs_ranges): | |
39 | <tr> |
|
39 | <tr> | |
40 | <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td> |
|
40 | <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td> | |
41 | <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td> |
|
41 | <td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td> | |
42 | <td><div class="author">${h.person(cs.author)}</div></td> |
|
42 | <td><div class="author">${h.person(cs.author)}</div></td> | |
43 | <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td> |
|
43 | <td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td> | |
44 | <td> |
|
44 | <td> | |
45 | %if c.statuses: |
|
45 | %if c.statuses: | |
46 | <div title="${h.tooltip(_('Changeset status'))}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cnt])}" /></div> |
|
46 | <div title="${h.tooltip(_('Changeset status'))}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cnt])}" /></div> | |
47 | %endif |
|
47 | %endif | |
48 | </td> |
|
48 | </td> | |
49 | <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td> |
|
49 | <td><div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message),c.repo_name)}</div></td> | |
50 | </tr> |
|
50 | </tr> | |
51 | %endfor |
|
51 | %endfor | |
52 | </table> |
|
52 | </table> | |
53 | </div> |
|
53 | </div> | |
54 | <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div> |
|
54 | <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div> | |
55 | <div class="cs_files"> |
|
55 | <div class="cs_files"> | |
56 | %for cs in c.cs_ranges: |
|
56 | %for cs in c.cs_ranges: | |
57 | <div class="cur_cs">${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div> |
|
57 | <div class="cur_cs">${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div> | |
58 | %for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]: |
|
58 | %for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]: | |
59 | <div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div> |
|
59 | <div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div> | |
60 | %endfor |
|
60 | %endfor | |
61 | %endfor |
|
61 | %endfor | |
62 | </div> |
|
62 | </div> | |
63 | </div> |
|
63 | </div> | |
64 |
|
64 | |||
65 | </div> |
|
65 | </div> | |
66 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
66 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> | |
67 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> |
|
67 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> | |
68 | %for cs in c.cs_ranges: |
|
68 | %for cs in c.cs_ranges: | |
69 | ##${comment.comment_inline_form(cs)} |
|
69 | ##${comment.comment_inline_form(cs)} | |
70 | ## diff block |
|
70 | ## diff block | |
71 | <div class="h3"> |
|
71 | <div class="h3"> | |
72 | <a class="tooltip" title="${h.tooltip(cs.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</a> |
|
72 | <a class="tooltip" title="${h.tooltip(cs.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</a> | |
73 | <div class="gravatar"> |
|
73 | <div class="gravatar"> | |
74 | <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),20)}"/> |
|
74 | <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),20)}"/> | |
75 | </div> |
|
75 | </div> | |
76 | <div class="right"> |
|
76 | <div class="right"> | |
77 | <span class="logtags"> |
|
77 | <span class="logtags"> | |
78 | %if len(cs.parents)>1: |
|
78 | %if len(cs.parents)>1: | |
79 | <span class="merge">${_('merge')}</span> |
|
79 | <span class="merge">${_('merge')}</span> | |
80 | %endif |
|
80 | %endif | |
81 | %if cs.branch: |
|
81 | %if cs.branch: | |
82 | <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}"> |
|
82 | <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}"> | |
83 | ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} |
|
83 | ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} | |
84 | </span> |
|
84 | </span> | |
85 | %endif |
|
85 | %endif | |
86 | %if h.is_hg(c.rhodecode_repo): |
|
86 | %if h.is_hg(c.rhodecode_repo): | |
87 | %for book in cs.bookmarks: |
|
87 | %for book in cs.bookmarks: | |
88 | <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}"> |
|
88 | <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}"> | |
89 | ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} |
|
89 | ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))} | |
90 | </span> |
|
90 | </span> | |
91 | %endfor |
|
91 | %endfor | |
92 | %endif |
|
92 | %endif | |
93 | %for tag in cs.tags: |
|
93 | %for tag in cs.tags: | |
94 | <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}"> |
|
94 | <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}"> | |
95 | ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span> |
|
95 | ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span> | |
96 | %endfor |
|
96 | %endfor | |
97 |
</span> |
|
97 | </span> | |
98 |
</div> |
|
98 | </div> | |
99 | </div> |
|
99 | </div> | |
100 | ${diff_block.diff_block(c.changes[cs.raw_id])} |
|
100 | ${diff_block.diff_block(c.changes[cs.raw_id])} | |
101 | ##${comment.comments(cs)} |
|
101 | ##${comment.comments(cs)} | |
102 |
|
102 | |||
103 | %endfor |
|
103 | %endfor | |
104 | <script type="text/javascript"> |
|
104 | <script type="text/javascript"> | |
105 |
|
105 | |||
106 | YUE.onDOMReady(function(){ |
|
106 | YUE.onDOMReady(function(){ | |
107 |
|
107 | |||
108 | YUE.on(YUQ('.diff-menu-activate'),'click',function(e){ |
|
108 | YUE.on(YUQ('.diff-menu-activate'),'click',function(e){ | |
109 | var act = e.currentTarget.nextElementSibling; |
|
109 | var act = e.currentTarget.nextElementSibling; | |
110 |
|
110 | |||
111 | if(YUD.hasClass(act,'active')){ |
|
111 | if(YUD.hasClass(act,'active')){ | |
112 | YUD.removeClass(act,'active'); |
|
112 | YUD.removeClass(act,'active'); | |
113 | YUD.setStyle(act,'display','none'); |
|
113 | YUD.setStyle(act,'display','none'); | |
114 | }else{ |
|
114 | }else{ | |
115 | YUD.addClass(act,'active'); |
|
115 | YUD.addClass(act,'active'); | |
116 | YUD.setStyle(act,'display',''); |
|
116 | YUD.setStyle(act,'display',''); | |
117 | } |
|
117 | } | |
118 | }); |
|
118 | }); | |
119 | }) |
|
119 | }) | |
120 | </script> |
|
120 | </script> | |
121 | </div> |
|
121 | </div> | |
122 | </%def> |
|
122 | </%def> |
@@ -1,32 +1,32 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 |
|
2 | |||
3 | % for f in c.followers_pager: |
|
3 | % for f in c.followers_pager: | |
4 | <div> |
|
4 | <div> | |
5 | <div class="follower_user"> |
|
5 | <div class="follower_user"> | |
6 | <div class="gravatar"> |
|
6 | <div class="gravatar"> | |
7 | <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/> |
|
7 | <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/> | |
8 | </div> |
|
8 | </div> | |
9 | <span style="font-size: 20px"> <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname})</span> |
|
9 | <span style="font-size: 20px"> <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname})</span> | |
10 | </div> |
|
10 | </div> | |
11 | <div style="clear:both;padding-top: 10px"></div> |
|
11 | <div style="clear:both;padding-top: 10px"></div> | |
12 | <div class="follower_date">${_('Started following -')} |
|
12 | <div class="follower_date">${_('Started following -')} | |
13 | <span class="tooltip" title="${h.tooltip(f.follows_from)}"> ${h.age(f.follows_from)}</span></div> |
|
13 | <span class="tooltip" title="${h.tooltip(f.follows_from)}"> ${h.age(f.follows_from)}</span></div> | |
14 | <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div> |
|
14 | <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div> | |
15 | </div> |
|
15 | </div> | |
16 | % endfor |
|
16 | % endfor | |
17 |
|
17 | |||
18 | <div class="pagination-wh pagination-left"> |
|
18 | <div class="pagination-wh pagination-left"> | |
19 | <script type="text/javascript"> |
|
19 | <script type="text/javascript"> | |
20 | YUE.onDOMReady(function(){ |
|
20 | YUE.onDOMReady(function(){ | |
21 | YUE.delegate("followers","click",function(e, matchedEl, container){ |
|
21 | YUE.delegate("followers","click",function(e, matchedEl, container){ | |
22 | ypjax(e.target.href,"followers",function(){ |
|
22 | ypjax(e.target.href,"followers",function(){ | |
23 | show_more_event(); |
|
23 | show_more_event(); | |
24 | tooltip_activate(); |
|
24 | tooltip_activate(); | |
25 |
show_changeset_tooltip(); |
|
25 | show_changeset_tooltip(); | |
26 | }); |
|
26 | }); | |
27 | YUE.preventDefault(e); |
|
27 | YUE.preventDefault(e); | |
28 | },'.pager_link'); |
|
28 | },'.pager_link'); | |
29 | }); |
|
29 | }); | |
30 | </script> |
|
30 | </script> | |
31 | ${c.followers_pager.pager('$link_previous ~2~ $link_next')} |
|
31 | ${c.followers_pager.pager('$link_previous ~2~ $link_next')} | |
32 | </div> |
|
32 | </div> |
@@ -1,43 +1,43 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 |
|
2 | |||
3 | % if c.forks_pager: |
|
3 | % if c.forks_pager: | |
4 | % for f in c.forks_pager: |
|
4 | % for f in c.forks_pager: | |
5 | <div> |
|
5 | <div> | |
6 | <div class="fork_user"> |
|
6 | <div class="fork_user"> | |
7 | <div class="gravatar"> |
|
7 | <div class="gravatar"> | |
8 | <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/> |
|
8 | <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/> | |
9 | </div> |
|
9 | </div> | |
10 | <span style="font-size: 20px"> |
|
10 | <span style="font-size: 20px"> | |
11 | <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname}) / |
|
11 | <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname}) / | |
12 | ${h.link_to(f.repo_name,h.url('summary_home',repo_name=f.repo_name))} |
|
12 | ${h.link_to(f.repo_name,h.url('summary_home',repo_name=f.repo_name))} | |
13 | </span> |
|
13 | </span> | |
14 | <div style="padding:5px 3px 3px 42px;">${f.description}</div> |
|
14 | <div style="padding:5px 3px 3px 42px;">${f.description}</div> | |
15 | </div> |
|
15 | </div> | |
16 | <div style="clear:both;padding-top: 10px"></div> |
|
16 | <div style="clear:both;padding-top: 10px"></div> | |
17 | <div class="follower_date">${_('forked')} - |
|
17 | <div class="follower_date">${_('forked')} - | |
18 | <span class="tooltip" title="${h.tooltip(h.fmt_date(f.created_on))}"> ${h.age(f.created_on)}</span> |
|
18 | <span class="tooltip" title="${h.tooltip(h.fmt_date(f.created_on))}"> ${h.age(f.created_on)}</span> | |
19 | <a title="${_('compare fork with %s' % c.repo_name)}" |
|
19 | <a title="${_('compare fork with %s' % c.repo_name)}" | |
20 | href="${h.url('compare_url',repo_name=f.repo_name,org_ref_type='branch',org_ref='default',other_ref_type='branch',other_ref='default', repo=c.repo_name)}" |
|
20 | href="${h.url('compare_url',repo_name=f.repo_name,org_ref_type='branch',org_ref='default',other_ref_type='branch',other_ref='default', repo=c.repo_name)}" | |
21 | class="ui-btn small">${_('Compare fork')}</a> |
|
21 | class="ui-btn small">${_('Compare fork')}</a> | |
22 | </div> |
|
22 | </div> | |
23 | <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div> |
|
23 | <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div> | |
24 | </div> |
|
24 | </div> | |
25 | % endfor |
|
25 | % endfor | |
26 | <div class="pagination-wh pagination-left"> |
|
26 | <div class="pagination-wh pagination-left"> | |
27 | <script type="text/javascript"> |
|
27 | <script type="text/javascript"> | |
28 | YUE.onDOMReady(function(){ |
|
28 | YUE.onDOMReady(function(){ | |
29 | YUE.delegate("forks","click",function(e, matchedEl, container){ |
|
29 | YUE.delegate("forks","click",function(e, matchedEl, container){ | |
30 | ypjax(e.target.href,"forks",function(){ |
|
30 | ypjax(e.target.href,"forks",function(){ | |
31 | show_more_event(); |
|
31 | show_more_event(); | |
32 | tooltip_activate(); |
|
32 | tooltip_activate(); | |
33 |
show_changeset_tooltip(); |
|
33 | show_changeset_tooltip(); | |
34 | }); |
|
34 | }); | |
35 | YUE.preventDefault(e); |
|
35 | YUE.preventDefault(e); | |
36 | },'.pager_link'); |
|
36 | },'.pager_link'); | |
37 | }); |
|
37 | }); | |
38 | </script> |
|
38 | </script> | |
39 | ${c.forks_pager.pager('$link_previous ~2~ $link_next')} |
|
39 | ${c.forks_pager.pager('$link_previous ~2~ $link_next')} | |
40 | </div> |
|
40 | </div> | |
41 | % else: |
|
41 | % else: | |
42 | ${_('There are no forks yet')} |
|
42 | ${_('There are no forks yet')} | |
43 | % endif |
|
43 | % endif |
@@ -1,332 +1,331 b'' | |||||
1 | <%page args="parent" /> |
|
1 | <%page args="parent" /> | |
2 | <div class="box"> |
|
2 | <div class="box"> | |
3 | <!-- box / title --> |
|
3 | <!-- box / title --> | |
4 | <div class="title"> |
|
4 | <div class="title"> | |
5 | <h5> |
|
5 | <h5> | |
6 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${parent.breadcrumbs()} <span id="repo_count">0</span> ${_('repositories')} |
|
6 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${parent.breadcrumbs()} <span id="repo_count">0</span> ${_('repositories')} | |
7 | </h5> |
|
7 | </h5> | |
8 | %if c.rhodecode_user.username != 'default': |
|
8 | %if c.rhodecode_user.username != 'default': | |
9 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): |
|
9 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): | |
10 | <ul class="links"> |
|
10 | <ul class="links"> | |
11 | <li> |
|
11 | <li> | |
12 | %if c.group: |
|
12 | %if c.group: | |
13 | <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository',parent_group=c.group.group_id))}</span> |
|
13 | <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository',parent_group=c.group.group_id))}</span> | |
14 | %else: |
|
14 | %else: | |
15 | <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span> |
|
15 | <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span> | |
16 | %endif |
|
16 | %endif | |
17 | </li> |
|
17 | </li> | |
18 | </ul> |
|
18 | </ul> | |
19 | %endif |
|
19 | %endif | |
20 | %endif |
|
20 | %endif | |
21 | </div> |
|
21 | </div> | |
22 | <!-- end box / title --> |
|
22 | <!-- end box / title --> | |
23 | <div class="table"> |
|
23 | <div class="table"> | |
24 | % if c.groups: |
|
24 | % if c.groups: | |
25 | <div id='groups_list_wrap' class="yui-skin-sam"> |
|
25 | <div id='groups_list_wrap' class="yui-skin-sam"> | |
26 | <table id="groups_list"> |
|
26 | <table id="groups_list"> | |
27 | <thead> |
|
27 | <thead> | |
28 | <tr> |
|
28 | <tr> | |
29 | <th class="left"><a href="#">${_('Group name')}</a></th> |
|
29 | <th class="left"><a href="#">${_('Group name')}</a></th> | |
30 | <th class="left"><a href="#">${_('Description')}</a></th> |
|
30 | <th class="left"><a href="#">${_('Description')}</a></th> | |
31 | ##<th class="left"><a href="#">${_('Number of repositories')}</a></th> |
|
31 | ##<th class="left"><a href="#">${_('Number of repositories')}</a></th> | |
32 | </tr> |
|
32 | </tr> | |
33 | </thead> |
|
33 | </thead> | |
34 |
|
34 | |||
35 | ## REPO GROUPS |
|
35 | ## REPO GROUPS | |
36 | % for gr in c.groups: |
|
36 | % for gr in c.groups: | |
37 | <tr> |
|
37 | <tr> | |
38 | <td> |
|
38 | <td> | |
39 | <div style="white-space: nowrap"> |
|
39 | <div style="white-space: nowrap"> | |
40 | <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/> |
|
40 | <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/> | |
41 | ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))} |
|
41 | ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))} | |
42 | </div> |
|
42 | </div> | |
43 | </td> |
|
43 | </td> | |
44 | %if c.visual.stylify_metatags: |
|
44 | %if c.visual.stylify_metatags: | |
45 | <td>${h.urlify_text(h.desc_stylize(gr.group_description))}</td> |
|
45 | <td>${h.urlify_text(h.desc_stylize(gr.group_description))}</td> | |
46 | %else: |
|
46 | %else: | |
47 | <td>${gr.group_description}</td> |
|
47 | <td>${gr.group_description}</td> | |
48 | %endif |
|
48 | %endif | |
49 | ## this is commented out since for multi nested repos can be HEAVY! |
|
49 | ## this is commented out since for multi nested repos can be HEAVY! | |
50 | ## in number of executed queries during traversing uncomment at will |
|
50 | ## in number of executed queries during traversing uncomment at will | |
51 | ##<td><b>${gr.repositories_recursive_count}</b></td> |
|
51 | ##<td><b>${gr.repositories_recursive_count}</b></td> | |
52 | </tr> |
|
52 | </tr> | |
53 | % endfor |
|
53 | % endfor | |
54 |
|
54 | |||
55 | </table> |
|
55 | </table> | |
56 | </div> |
|
56 | </div> | |
57 | <div style="height: 20px"></div> |
|
57 | <div style="height: 20px"></div> | |
58 | % endif |
|
58 | % endif | |
59 | <div id="welcome" style="display:none;text-align:center"> |
|
59 | <div id="welcome" style="display:none;text-align:center"> | |
60 | <h1><a href="${h.url('home')}">${c.rhodecode_name} ${c.rhodecode_version}</a></h1> |
|
60 | <h1><a href="${h.url('home')}">${c.rhodecode_name} ${c.rhodecode_version}</a></h1> | |
61 | </div> |
|
61 | </div> | |
62 | <%cnt=0%> |
|
62 | <%cnt=0%> | |
63 | <%namespace name="dt" file="/data_table/_dt_elements.html"/> |
|
63 | <%namespace name="dt" file="/data_table/_dt_elements.html"/> | |
64 | % if c.visual.lightweight_dashboard is False: |
|
64 | % if c.visual.lightweight_dashboard is False: | |
65 | ## old full detailed version |
|
65 | ## old full detailed version | |
66 | <div id='repos_list_wrap' class="yui-skin-sam"> |
|
66 | <div id='repos_list_wrap' class="yui-skin-sam"> | |
67 | <table id="repos_list"> |
|
67 | <table id="repos_list"> | |
68 | <thead> |
|
68 | <thead> | |
69 | <tr> |
|
69 | <tr> | |
70 | <th class="left"></th> |
|
70 | <th class="left"></th> | |
71 | <th class="left">${_('Name')}</th> |
|
71 | <th class="left">${_('Name')}</th> | |
72 | <th class="left">${_('Description')}</th> |
|
72 | <th class="left">${_('Description')}</th> | |
73 | <th class="left">${_('Last change')}</th> |
|
73 | <th class="left">${_('Last change')}</th> | |
74 | <th class="left">${_('Tip')}</th> |
|
74 | <th class="left">${_('Tip')}</th> | |
75 | <th class="left">${_('Owner')}</th> |
|
75 | <th class="left">${_('Owner')}</th> | |
76 | <th class="left">${_('RSS')}</th> |
|
76 | <th class="left">${_('RSS')}</th> | |
77 | <th class="left">${_('Atom')}</th> |
|
77 | <th class="left">${_('Atom')}</th> | |
78 | </tr> |
|
78 | </tr> | |
79 | </thead> |
|
79 | </thead> | |
80 | <tbody> |
|
80 | <tbody> | |
81 | %for cnt,repo in enumerate(c.repos_list): |
|
81 | %for cnt,repo in enumerate(c.repos_list): | |
82 | <tr class="parity${(cnt+1)%2}"> |
|
82 | <tr class="parity${(cnt+1)%2}"> | |
83 | ##QUICK MENU |
|
83 | ##QUICK MENU | |
84 | <td class="quick_repo_menu"> |
|
84 | <td class="quick_repo_menu"> | |
85 | ${dt.quick_menu(repo['name'])} |
|
85 | ${dt.quick_menu(repo['name'])} | |
86 | </td> |
|
86 | </td> | |
87 | ##REPO NAME AND ICONS |
|
87 | ##REPO NAME AND ICONS | |
88 | <td class="reponame"> |
|
88 | <td class="reponame"> | |
89 | ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']),pageargs.get('short_repo_names'))} |
|
89 | ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']),pageargs.get('short_repo_names'))} | |
90 | </td> |
|
90 | </td> | |
91 | ##DESCRIPTION |
|
91 | ##DESCRIPTION | |
92 | <td><span class="tooltip" title="${h.tooltip(repo['description'])}"> |
|
92 | <td><span class="tooltip" title="${h.tooltip(repo['description'])}"> | |
93 | %if c.visual.stylify_metatags: |
|
93 | %if c.visual.stylify_metatags: | |
94 | ${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))}</span> |
|
94 | ${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))}</span> | |
95 | %else: |
|
95 | %else: | |
96 | ${h.truncate(repo['description'],60)}</span> |
|
96 | ${h.truncate(repo['description'],60)}</span> | |
97 | %endif |
|
97 | %endif | |
98 | </td> |
|
98 | </td> | |
99 | ##LAST CHANGE DATE |
|
99 | ##LAST CHANGE DATE | |
100 | <td> |
|
100 | <td> | |
101 | ${dt.last_change(repo['last_change'])} |
|
101 | ${dt.last_change(repo['last_change'])} | |
102 | </td> |
|
102 | </td> | |
103 | ##LAST REVISION |
|
103 | ##LAST REVISION | |
104 | <td> |
|
104 | <td> | |
105 | ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])} |
|
105 | ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])} | |
106 | </td> |
|
106 | </td> | |
107 | ## |
|
107 | ## | |
108 | <td title="${repo['contact']}">${h.person(repo['contact'])}</td> |
|
108 | <td title="${repo['contact']}">${h.person(repo['contact'])}</td> | |
109 | <td> |
|
109 | <td> | |
110 | ${dt.rss(repo['name'])} |
|
110 | ${dt.rss(repo['name'])} | |
111 | </td> |
|
111 | </td> | |
112 | <td> |
|
112 | <td> | |
113 | ${dt.atom(repo['name'])} |
|
113 | ${dt.atom(repo['name'])} | |
114 | </td> |
|
114 | </td> | |
115 | </tr> |
|
115 | </tr> | |
116 | %endfor |
|
116 | %endfor | |
117 | </tbody> |
|
117 | </tbody> | |
118 | </table> |
|
118 | </table> | |
119 | </div> |
|
119 | </div> | |
120 | % else: |
|
120 | % else: | |
121 | ## lightweight version |
|
121 | ## lightweight version | |
122 | <div class="yui-skin-sam" id="repos_list_wrap"></div> |
|
122 | <div class="yui-skin-sam" id="repos_list_wrap"></div> | |
123 | <div id="user-paginator" style="padding: 0px 0px 0px 0px"></div> |
|
123 | <div id="user-paginator" style="padding: 0px 0px 0px 0px"></div> | |
124 | % endif |
|
124 | % endif | |
125 | </div> |
|
125 | </div> | |
126 | </div> |
|
126 | </div> | |
127 | % if c.visual.lightweight_dashboard is False: |
|
127 | % if c.visual.lightweight_dashboard is False: | |
128 | <script> |
|
128 | <script> | |
129 | YUD.get('repo_count').innerHTML = ${cnt+1 if cnt else 0}; |
|
129 | YUD.get('repo_count').innerHTML = ${cnt+1 if cnt else 0}; | |
130 | var func = function(node){ |
|
130 | var func = function(node){ | |
131 | return node.parentNode.parentNode.parentNode.parentNode; |
|
131 | return node.parentNode.parentNode.parentNode.parentNode; | |
132 | } |
|
132 | } | |
133 |
|
133 | |||
134 | // groups table sorting |
|
134 | // groups table sorting | |
135 | var myColumnDefs = [ |
|
135 | var myColumnDefs = [ | |
136 | {key:"name",label:"${_('Group name')}",sortable:true, |
|
136 | {key:"name",label:"${_('Group name')}",sortable:true, | |
137 | sortOptions: { sortFunction: groupNameSort }}, |
|
137 | sortOptions: { sortFunction: groupNameSort }}, | |
138 | {key:"desc",label:"${_('Description')}",sortable:true}, |
|
138 | {key:"desc",label:"${_('Description')}",sortable:true}, | |
139 | ]; |
|
139 | ]; | |
140 |
|
140 | |||
141 | var myDataSource = new YAHOO.util.DataSource(YUD.get("groups_list")); |
|
141 | var myDataSource = new YAHOO.util.DataSource(YUD.get("groups_list")); | |
142 |
|
142 | |||
143 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE; |
|
143 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE; | |
144 | myDataSource.responseSchema = { |
|
144 | myDataSource.responseSchema = { | |
145 | fields: [ |
|
145 | fields: [ | |
146 | {key:"name"}, |
|
146 | {key:"name"}, | |
147 | {key:"desc"}, |
|
147 | {key:"desc"}, | |
148 | ] |
|
148 | ] | |
149 | }; |
|
149 | }; | |
150 |
|
150 | |||
151 | var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,{ |
|
151 | var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,{ | |
152 | sortedBy:{key:"name",dir:"asc"}, |
|
152 | sortedBy:{key:"name",dir:"asc"}, | |
153 | paginator: new YAHOO.widget.Paginator({ |
|
153 | paginator: new YAHOO.widget.Paginator({ | |
154 | rowsPerPage: 5, |
|
154 | rowsPerPage: 5, | |
155 | alwaysVisible: false, |
|
155 | alwaysVisible: false, | |
156 | template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}", |
|
156 | template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}", | |
157 | pageLinks: 5, |
|
157 | pageLinks: 5, | |
158 | containerClass: 'pagination-wh', |
|
158 | containerClass: 'pagination-wh', | |
159 | currentPageClass: 'pager_curpage', |
|
159 | currentPageClass: 'pager_curpage', | |
160 | pageLinkClass: 'pager_link', |
|
160 | pageLinkClass: 'pager_link', | |
161 | nextPageLinkLabel: '>', |
|
161 | nextPageLinkLabel: '>', | |
162 | previousPageLinkLabel: '<', |
|
162 | previousPageLinkLabel: '<', | |
163 | firstPageLinkLabel: '<<', |
|
163 | firstPageLinkLabel: '<<', | |
164 | lastPageLinkLabel: '>>', |
|
164 | lastPageLinkLabel: '>>', | |
165 | containers:['user-paginator'] |
|
165 | containers:['user-paginator'] | |
166 |
}), |
|
166 | }), | |
167 | MSG_SORTASC:"${_('Click to sort ascending')}", |
|
167 | MSG_SORTASC:"${_('Click to sort ascending')}", | |
168 | MSG_SORTDESC:"${_('Click to sort descending')}" |
|
168 | MSG_SORTDESC:"${_('Click to sort descending')}" | |
169 | }); |
|
169 | }); | |
170 |
|
170 | |||
171 | // main table sorting |
|
171 | // main table sorting | |
172 | var myColumnDefs = [ |
|
172 | var myColumnDefs = [ | |
173 | {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"}, |
|
173 | {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"}, | |
174 | {key:"name",label:"${_('Name')}",sortable:true, |
|
174 | {key:"name",label:"${_('Name')}",sortable:true, | |
175 | sortOptions: { sortFunction: nameSort }}, |
|
175 | sortOptions: { sortFunction: nameSort }}, | |
176 | {key:"desc",label:"${_('Description')}",sortable:true}, |
|
176 | {key:"desc",label:"${_('Description')}",sortable:true}, | |
177 | {key:"last_change",label:"${_('Last Change')}",sortable:true, |
|
177 | {key:"last_change",label:"${_('Last Change')}",sortable:true, | |
178 | sortOptions: { sortFunction: ageSort }}, |
|
178 | sortOptions: { sortFunction: ageSort }}, | |
179 | {key:"tip",label:"${_('Tip')}",sortable:true, |
|
179 | {key:"tip",label:"${_('Tip')}",sortable:true, | |
180 | sortOptions: { sortFunction: revisionSort }}, |
|
180 | sortOptions: { sortFunction: revisionSort }}, | |
181 | {key:"owner",label:"${_('Owner')}",sortable:true}, |
|
181 | {key:"owner",label:"${_('Owner')}",sortable:true}, | |
182 | {key:"rss",label:"",sortable:false}, |
|
182 | {key:"rss",label:"",sortable:false}, | |
183 | {key:"atom",label:"",sortable:false}, |
|
183 | {key:"atom",label:"",sortable:false}, | |
184 | ]; |
|
184 | ]; | |
185 |
|
185 | |||
186 | var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list")); |
|
186 | var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list")); | |
187 |
|
187 | |||
188 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE; |
|
188 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE; | |
189 |
|
189 | |||
190 | myDataSource.responseSchema = { |
|
190 | myDataSource.responseSchema = { | |
191 | fields: [ |
|
191 | fields: [ | |
192 | {key:"menu"}, |
|
192 | {key:"menu"}, | |
193 | //{key:"raw_name"}, |
|
193 | //{key:"raw_name"}, | |
194 | {key:"name"}, |
|
194 | {key:"name"}, | |
195 | {key:"desc"}, |
|
195 | {key:"desc"}, | |
196 | {key:"last_change"}, |
|
196 | {key:"last_change"}, | |
197 | {key:"tip"}, |
|
197 | {key:"tip"}, | |
198 | {key:"owner"}, |
|
198 | {key:"owner"}, | |
199 | {key:"rss"}, |
|
199 | {key:"rss"}, | |
200 | {key:"atom"}, |
|
200 | {key:"atom"}, | |
201 | ] |
|
201 | ] | |
202 | }; |
|
202 | }; | |
203 |
|
203 | |||
204 | var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource, |
|
204 | var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource, | |
205 | { |
|
205 | { | |
206 | sortedBy:{key:"name",dir:"asc"}, |
|
206 | sortedBy:{key:"name",dir:"asc"}, | |
207 | MSG_SORTASC:"${_('Click to sort ascending')}", |
|
207 | MSG_SORTASC:"${_('Click to sort ascending')}", | |
208 | MSG_SORTDESC:"${_('Click to sort descending')}", |
|
208 | MSG_SORTDESC:"${_('Click to sort descending')}", | |
209 | MSG_EMPTY:"${_('No records found.')}", |
|
209 | MSG_EMPTY:"${_('No records found.')}", | |
210 | MSG_ERROR:"${_('Data error.')}", |
|
210 | MSG_ERROR:"${_('Data error.')}", | |
211 | MSG_LOADING:"${_('Loading...')}", |
|
211 | MSG_LOADING:"${_('Loading...')}", | |
212 | } |
|
212 | } | |
213 | ); |
|
213 | ); | |
214 | myDataTable.subscribe('postRenderEvent',function(oArgs) { |
|
214 | myDataTable.subscribe('postRenderEvent',function(oArgs) { | |
215 | tooltip_activate(); |
|
215 | tooltip_activate(); | |
216 | quick_repo_menu(); |
|
216 | quick_repo_menu(); | |
217 | q_filter('q_filter',YUQ('div.table tr td a.repo_name'),func); |
|
217 | q_filter('q_filter',YUQ('div.table tr td a.repo_name'),func); | |
218 | }); |
|
218 | }); | |
219 |
|
219 | |||
220 | </script> |
|
220 | </script> | |
221 | % else: |
|
221 | % else: | |
222 | <script> |
|
222 | <script> | |
223 | //var url = "${h.url('formatted_users', format='json')}"; |
|
223 | //var url = "${h.url('formatted_users', format='json')}"; | |
224 | var data = ${c.data|n}; |
|
224 | var data = ${c.data|n}; | |
225 | var myDataSource = new YAHOO.util.DataSource(data); |
|
225 | var myDataSource = new YAHOO.util.DataSource(data); | |
226 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON; |
|
226 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON; | |
227 |
|
227 | |||
228 | myDataSource.responseSchema = { |
|
228 | myDataSource.responseSchema = { | |
229 | resultsList: "records", |
|
229 | resultsList: "records", | |
230 | fields: [ |
|
230 | fields: [ | |
231 | {key:"menu"}, |
|
231 | {key:"menu"}, | |
232 | {key:"raw_name"}, |
|
232 | {key:"raw_name"}, | |
233 | {key:"name"}, |
|
233 | {key:"name"}, | |
234 | {key:"desc"}, |
|
234 | {key:"desc"}, | |
235 | {key:"last_change"}, |
|
235 | {key:"last_change"}, | |
236 | {key:"owner"}, |
|
236 | {key:"owner"}, | |
237 | {key:"rss"}, |
|
237 | {key:"rss"}, | |
238 | {key:"atom"}, |
|
238 | {key:"atom"}, | |
239 | ] |
|
239 | ] | |
240 | }; |
|
240 | }; | |
241 | myDataSource.doBeforeCallback = function(req,raw,res,cb) { |
|
241 | myDataSource.doBeforeCallback = function(req,raw,res,cb) { | |
242 | // This is the filter function |
|
242 | // This is the filter function | |
243 | var data = res.results || [], |
|
243 | var data = res.results || [], | |
244 | filtered = [], |
|
244 | filtered = [], | |
245 | i,l; |
|
245 | i,l; | |
246 |
|
246 | |||
247 | if (req) { |
|
247 | if (req) { | |
248 | req = req.toLowerCase(); |
|
248 | req = req.toLowerCase(); | |
249 | for (i = 0; i<data.length; i++) { |
|
249 | for (i = 0; i<data.length; i++) { | |
250 | var pos = data[i].raw_name.toLowerCase().indexOf(req) |
|
250 | var pos = data[i].raw_name.toLowerCase().indexOf(req) | |
251 | if (pos != -1) { |
|
251 | if (pos != -1) { | |
252 | filtered.push(data[i]); |
|
252 | filtered.push(data[i]); | |
253 | } |
|
253 | } | |
254 | } |
|
254 | } | |
255 | res.results = filtered; |
|
255 | res.results = filtered; | |
256 | } |
|
256 | } | |
257 | YUD.get('repo_count').innerHTML = res.results.length; |
|
257 | YUD.get('repo_count').innerHTML = res.results.length; | |
258 | return res; |
|
258 | return res; | |
259 | } |
|
259 | } | |
260 |
|
260 | |||
261 | // main table sorting |
|
261 | // main table sorting | |
262 | var myColumnDefs = [ |
|
262 | var myColumnDefs = [ | |
263 | {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"}, |
|
263 | {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"}, | |
264 | {key:"name",label:"${_('Name')}",sortable:true, |
|
264 | {key:"name",label:"${_('Name')}",sortable:true, | |
265 | sortOptions: { sortFunction: nameSort }}, |
|
265 | sortOptions: { sortFunction: nameSort }}, | |
266 | {key:"desc",label:"${_('Description')}",sortable:true}, |
|
266 | {key:"desc",label:"${_('Description')}",sortable:true}, | |
267 | {key:"last_change",label:"${_('Last Change')}",sortable:true, |
|
267 | {key:"last_change",label:"${_('Last Change')}",sortable:true, | |
268 | sortOptions: { sortFunction: ageSort }}, |
|
268 | sortOptions: { sortFunction: ageSort }}, | |
269 | {key:"owner",label:"${_('Owner')}",sortable:true}, |
|
269 | {key:"owner",label:"${_('Owner')}",sortable:true}, | |
270 | {key:"rss",label:"",sortable:false}, |
|
270 | {key:"rss",label:"",sortable:false}, | |
271 | {key:"atom",label:"",sortable:false}, |
|
271 | {key:"atom",label:"",sortable:false}, | |
272 | ]; |
|
272 | ]; | |
273 |
|
273 | |||
274 | var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{ |
|
274 | var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{ | |
275 | sortedBy:{key:"name",dir:"asc"}, |
|
275 | sortedBy:{key:"name",dir:"asc"}, | |
276 | paginator: new YAHOO.widget.Paginator({ |
|
276 | paginator: new YAHOO.widget.Paginator({ | |
277 | rowsPerPage: 15, |
|
277 | rowsPerPage: 15, | |
278 | alwaysVisible: false, |
|
278 | alwaysVisible: false, | |
279 | template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}", |
|
279 | template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}", | |
280 | pageLinks: 5, |
|
280 | pageLinks: 5, | |
281 | containerClass: 'pagination-wh', |
|
281 | containerClass: 'pagination-wh', | |
282 | currentPageClass: 'pager_curpage', |
|
282 | currentPageClass: 'pager_curpage', | |
283 | pageLinkClass: 'pager_link', |
|
283 | pageLinkClass: 'pager_link', | |
284 | nextPageLinkLabel: '>', |
|
284 | nextPageLinkLabel: '>', | |
285 | previousPageLinkLabel: '<', |
|
285 | previousPageLinkLabel: '<', | |
286 | firstPageLinkLabel: '<<', |
|
286 | firstPageLinkLabel: '<<', | |
287 | lastPageLinkLabel: '>>', |
|
287 | lastPageLinkLabel: '>>', | |
288 | containers:['user-paginator'] |
|
288 | containers:['user-paginator'] | |
289 | }), |
|
289 | }), | |
290 |
|
290 | |||
291 | MSG_SORTASC:"${_('Click to sort ascending')}", |
|
291 | MSG_SORTASC:"${_('Click to sort ascending')}", | |
292 | MSG_SORTDESC:"${_('Click to sort descending')}", |
|
292 | MSG_SORTDESC:"${_('Click to sort descending')}", | |
293 | MSG_EMPTY:"${_('No records found.')}", |
|
293 | MSG_EMPTY:"${_('No records found.')}", | |
294 | MSG_ERROR:"${_('Data error.')}", |
|
294 | MSG_ERROR:"${_('Data error.')}", | |
295 | MSG_LOADING:"${_('Loading...')}", |
|
295 | MSG_LOADING:"${_('Loading...')}", | |
296 | } |
|
296 | } | |
297 | ); |
|
297 | ); | |
298 | myDataTable.subscribe('postRenderEvent',function(oArgs) { |
|
298 | myDataTable.subscribe('postRenderEvent',function(oArgs) { | |
299 | tooltip_activate(); |
|
299 | tooltip_activate(); | |
300 | quick_repo_menu(); |
|
300 | quick_repo_menu(); | |
301 | }); |
|
301 | }); | |
302 |
|
302 | |||
303 | var filterTimeout = null; |
|
303 | var filterTimeout = null; | |
304 |
|
304 | |||
305 | updateFilter = function () { |
|
305 | updateFilter = function () { | |
306 | // Reset timeout |
|
306 | // Reset timeout | |
307 | filterTimeout = null; |
|
307 | filterTimeout = null; | |
308 |
|
308 | |||
309 | // Reset sort |
|
309 | // Reset sort | |
310 | var state = myDataTable.getState(); |
|
310 | var state = myDataTable.getState(); | |
311 | state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC}; |
|
311 | state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC}; | |
312 |
|
312 | |||
313 | // Get filtered data |
|
313 | // Get filtered data | |
314 | myDataSource.sendRequest(YUD.get('q_filter').value,{ |
|
314 | myDataSource.sendRequest(YUD.get('q_filter').value,{ | |
315 | success : myDataTable.onDataReturnInitializeTable, |
|
315 | success : myDataTable.onDataReturnInitializeTable, | |
316 | failure : myDataTable.onDataReturnInitializeTable, |
|
316 | failure : myDataTable.onDataReturnInitializeTable, | |
317 | scope : myDataTable, |
|
317 | scope : myDataTable, | |
318 | argument: state |
|
318 | argument: state | |
319 | }); |
|
319 | }); | |
320 |
|
320 | |||
321 | }; |
|
321 | }; | |
322 | YUE.on('q_filter','click',function(){ |
|
322 | YUE.on('q_filter','click',function(){ | |
323 | YUD.get('q_filter').value = ''; |
|
323 | YUD.get('q_filter').value = ''; | |
324 | }); |
|
324 | }); | |
325 |
|
325 | |||
326 | YUE.on('q_filter','keyup',function (e) { |
|
326 | YUE.on('q_filter','keyup',function (e) { | |
327 | clearTimeout(filterTimeout); |
|
327 | clearTimeout(filterTimeout); | |
328 | filterTimeout = setTimeout(updateFilter,600); |
|
328 | filterTimeout = setTimeout(updateFilter,600); | |
329 | }); |
|
329 | }); | |
330 | </script> |
|
330 | </script> | |
331 | % endif |
|
331 | % endif | |
332 | No newline at end of file |
|
@@ -1,210 +1,210 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 | ${_('Journal')} - ${c.rhodecode_name} |
|
4 | ${_('Journal')} - ${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="head_extra()"> |
|
12 | <%def name="head_extra()"> | |
13 | <link href="${h.url('journal_atom', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('ATOM journal feed')}" type="application/atom+xml" /> |
|
13 | <link href="${h.url('journal_atom', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('ATOM journal feed')}" type="application/atom+xml" /> | |
14 | <link href="${h.url('journal_rss', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('RSS journal feed')}" type="application/rss+xml" /> |
|
14 | <link href="${h.url('journal_rss', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('RSS journal feed')}" type="application/rss+xml" /> | |
15 | </%def> |
|
15 | </%def> | |
16 | <%def name="main()"> |
|
16 | <%def name="main()"> | |
17 |
|
17 | |||
18 | <div class="box box-left"> |
|
18 | <div class="box box-left"> | |
19 | <!-- box / title --> |
|
19 | <!-- box / title --> | |
20 | <div class="title"> |
|
20 | <div class="title"> | |
21 | <h5>${_('Journal')}</h5> |
|
21 | <h5>${_('Journal')}</h5> | |
22 | <ul class="links"> |
|
22 | <ul class="links"> | |
23 | <li> |
|
23 | <li> | |
24 | <span><a id="refresh" href="${h.url('journal')}"><img class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/></a></span> |
|
24 | <span><a id="refresh" href="${h.url('journal')}"><img class="icon" title="${_('Refresh')}" alt="${_('Refresh')}" src="${h.url('/images/icons/arrow_refresh.png')}"/></a></span> | |
25 | </li> |
|
25 | </li> | |
26 | <li> |
|
26 | <li> | |
27 | <span><a href="${h.url('journal_rss', api_key=c.rhodecode_user.api_key)}"><img class="icon" title="${_('RSS feed')}" alt="${_('RSS feed')}" src="${h.url('/images/icons/rss_16.png')}"/></a></span> |
|
27 | <span><a href="${h.url('journal_rss', api_key=c.rhodecode_user.api_key)}"><img class="icon" title="${_('RSS feed')}" alt="${_('RSS feed')}" src="${h.url('/images/icons/rss_16.png')}"/></a></span> | |
28 | </li> |
|
28 | </li> | |
29 | <li> |
|
29 | <li> | |
30 | <span><a href="${h.url('journal_atom', api_key=c.rhodecode_user.api_key)}"><img class="icon" title="${_('ATOM feed')}" alt="${_('ATOM feed')}" src="${h.url('/images/icons/atom.png')}"/></a></span> |
|
30 | <span><a href="${h.url('journal_atom', api_key=c.rhodecode_user.api_key)}"><img class="icon" title="${_('ATOM feed')}" alt="${_('ATOM feed')}" src="${h.url('/images/icons/atom.png')}"/></a></span> | |
31 | </li> |
|
31 | </li> | |
32 | </ul> |
|
32 | </ul> | |
33 | </div> |
|
33 | </div> | |
34 | <div id="journal">${c.journal_data}</div> |
|
34 | <div id="journal">${c.journal_data}</div> | |
35 | </div> |
|
35 | </div> | |
36 | <div class="box box-right"> |
|
36 | <div class="box box-right"> | |
37 | <!-- box / title --> |
|
37 | <!-- box / title --> | |
38 | <div class="title"> |
|
38 | <div class="title"> | |
39 | <h5> |
|
39 | <h5> | |
40 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> |
|
40 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> | |
41 |
<a id="show_watched" class="link-white" href="#watched">${_('Watched')}</a> / <a id="show_my" class="link-white" href="#my">${_('My repos')}</a> |
|
41 | <a id="show_watched" class="link-white" href="#watched">${_('Watched')}</a> / <a id="show_my" class="link-white" href="#my">${_('My repos')}</a> | |
42 | </h5> |
|
42 | </h5> | |
43 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): |
|
43 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): | |
44 | <ul class="links"> |
|
44 | <ul class="links"> | |
45 | <li> |
|
45 | <li> | |
46 | <span>${h.link_to(_('ADD'),h.url('admin_settings_create_repository'))}</span> |
|
46 | <span>${h.link_to(_('ADD'),h.url('admin_settings_create_repository'))}</span> | |
47 | </li> |
|
47 | </li> | |
48 | </ul> |
|
48 | </ul> | |
49 | %endif |
|
49 | %endif | |
50 | </div> |
|
50 | </div> | |
51 | <!-- end box / title --> |
|
51 | <!-- end box / title --> | |
52 | <div id="my" class="table" style="display:none"> |
|
52 | <div id="my" class="table" style="display:none"> | |
53 | ## loaded via AJAX |
|
53 | ## loaded via AJAX | |
54 | ${_('Loading...')} |
|
54 | ${_('Loading...')} | |
55 | </div> |
|
55 | </div> | |
56 |
|
56 | |||
57 | <div id="watched" class="table"> |
|
57 | <div id="watched" class="table"> | |
58 | %if c.following: |
|
58 | %if c.following: | |
59 | <table> |
|
59 | <table> | |
60 | <thead> |
|
60 | <thead> | |
61 | <tr> |
|
61 | <tr> | |
62 | <th class="left">${_('Name')}</th> |
|
62 | <th class="left">${_('Name')}</th> | |
63 | </thead> |
|
63 | </thead> | |
64 | <tbody> |
|
64 | <tbody> | |
65 | %for entry in c.following: |
|
65 | %for entry in c.following: | |
66 | <tr> |
|
66 | <tr> | |
67 | <td> |
|
67 | <td> | |
68 | %if entry.follows_user_id: |
|
68 | %if entry.follows_user_id: | |
69 | <img title="${_('following user')}" alt="${_('user')}" src="${h.url('/images/icons/user.png')}"/> |
|
69 | <img title="${_('following user')}" alt="${_('user')}" src="${h.url('/images/icons/user.png')}"/> | |
70 | ${entry.follows_user.full_contact} |
|
70 | ${entry.follows_user.full_contact} | |
71 | %endif |
|
71 | %endif | |
72 |
|
72 | |||
73 | %if entry.follows_repo_id: |
|
73 | %if entry.follows_repo_id: | |
74 | <div style="float:right;padding-right:5px"> |
|
74 | <div style="float:right;padding-right:5px"> | |
75 | <span id="follow_toggle_${entry.follows_repository.repo_id}" class="following" title="${_('Stop following this repository')}" |
|
75 | <span id="follow_toggle_${entry.follows_repository.repo_id}" class="following" title="${_('Stop following this repository')}" | |
76 | onclick="javascript:toggleFollowingRepo(this,${entry.follows_repository.repo_id},'${str(h.get_token())}')"> |
|
76 | onclick="javascript:toggleFollowingRepo(this,${entry.follows_repository.repo_id},'${str(h.get_token())}')"> | |
77 | </span> |
|
77 | </span> | |
78 | </div> |
|
78 | </div> | |
79 |
|
79 | |||
80 | %if h.is_hg(entry.follows_repository): |
|
80 | %if h.is_hg(entry.follows_repository): | |
81 | <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/> |
|
81 | <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/> | |
82 | %elif h.is_git(entry.follows_repository): |
|
82 | %elif h.is_git(entry.follows_repository): | |
83 | <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/> |
|
83 | <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/> | |
84 | %endif |
|
84 | %endif | |
85 |
|
85 | |||
86 | %if entry.follows_repository.private and c.visual.show_private_icon: |
|
86 | %if entry.follows_repository.private and c.visual.show_private_icon: | |
87 | <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/> |
|
87 | <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/> | |
88 | %elif not entry.follows_repository.private and c.visual.show_public_icon: |
|
88 | %elif not entry.follows_repository.private and c.visual.show_public_icon: | |
89 | <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/> |
|
89 | <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/> | |
90 | %endif |
|
90 | %endif | |
91 | <span class="watched_repo"> |
|
91 | <span class="watched_repo"> | |
92 | ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',repo_name=entry.follows_repository.repo_name))} |
|
92 | ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',repo_name=entry.follows_repository.repo_name))} | |
93 | </span> |
|
93 | </span> | |
94 | %endif |
|
94 | %endif | |
95 | </td> |
|
95 | </td> | |
96 | </tr> |
|
96 | </tr> | |
97 | %endfor |
|
97 | %endfor | |
98 | </tbody> |
|
98 | </tbody> | |
99 | </table> |
|
99 | </table> | |
100 | %else: |
|
100 | %else: | |
101 | <div style="padding:5px 0px 10px 0px;"> |
|
101 | <div style="padding:5px 0px 10px 0px;"> | |
102 | ${_('You are not following any users or repositories')} |
|
102 | ${_('You are not following any users or repositories')} | |
103 | </div> |
|
103 | </div> | |
104 | %endif |
|
104 | %endif | |
105 | </div> |
|
105 | </div> | |
106 | </div> |
|
106 | </div> | |
107 |
|
107 | |||
108 | <script type="text/javascript"> |
|
108 | <script type="text/javascript"> | |
109 | var show_my = function(e){ |
|
109 | var show_my = function(e){ | |
110 | YUD.setStyle('watched','display','none'); |
|
110 | YUD.setStyle('watched','display','none'); | |
111 | YUD.setStyle('my','display',''); |
|
111 | YUD.setStyle('my','display',''); | |
112 |
|
112 | |||
113 | var url = "${h.url('admin_settings_my_repos')}"; |
|
113 | var url = "${h.url('admin_settings_my_repos')}"; | |
114 | ypjax(url, 'my', function(){ |
|
114 | ypjax(url, 'my', function(){ | |
115 | tooltip_activate(); |
|
115 | tooltip_activate(); | |
116 | quick_repo_menu(); |
|
116 | quick_repo_menu(); | |
117 | var nodes = YUQ('#my tr td a.repo_name'); |
|
117 | var nodes = YUQ('#my tr td a.repo_name'); | |
118 | var func = function(node){ |
|
118 | var func = function(node){ | |
119 | return node.parentNode.parentNode.parentNode; |
|
119 | return node.parentNode.parentNode.parentNode; | |
120 |
} |
|
120 | } | |
121 | q_filter('q_filter',nodes,func); |
|
121 | q_filter('q_filter',nodes,func); | |
122 |
}); |
|
122 | }); | |
123 |
|
123 | |||
124 | } |
|
124 | } | |
125 | YUE.on('show_my','click',function(e){ |
|
125 | YUE.on('show_my','click',function(e){ | |
126 | show_my(e); |
|
126 | show_my(e); | |
127 | }) |
|
127 | }) | |
128 | var show_watched = function(e){ |
|
128 | var show_watched = function(e){ | |
129 | YUD.setStyle('my','display','none'); |
|
129 | YUD.setStyle('my','display','none'); | |
130 | YUD.setStyle('watched','display',''); |
|
130 | YUD.setStyle('watched','display',''); | |
131 | var nodes = YUQ('#watched .watched_repo a'); |
|
131 | var nodes = YUQ('#watched .watched_repo a'); | |
132 | var target = 'q_filter'; |
|
132 | var target = 'q_filter'; | |
133 | var func = function(node){ |
|
133 | var func = function(node){ | |
134 | return node.parentNode.parentNode; |
|
134 | return node.parentNode.parentNode; | |
135 | } |
|
135 | } | |
136 | q_filter(target,nodes,func); |
|
136 | q_filter(target,nodes,func); | |
137 | } |
|
137 | } | |
138 | YUE.on('show_watched','click',function(e){ |
|
138 | YUE.on('show_watched','click',function(e){ | |
139 | show_watched(e); |
|
139 | show_watched(e); | |
140 | }) |
|
140 | }) | |
141 | //init watched |
|
141 | //init watched | |
142 | show_watched(); |
|
142 | show_watched(); | |
143 |
|
143 | |||
144 | var tabs = { |
|
144 | var tabs = { | |
145 | 'watched': show_watched, |
|
145 | 'watched': show_watched, | |
146 | 'my': show_my, |
|
146 | 'my': show_my, | |
147 | } |
|
147 | } | |
148 | var url = location.href.split('#'); |
|
148 | var url = location.href.split('#'); | |
149 | if (url[1]) { |
|
149 | if (url[1]) { | |
150 | //We have a hash |
|
150 | //We have a hash | |
151 | var tabHash = url[1]; |
|
151 | var tabHash = url[1]; | |
152 | tabs[tabHash](); |
|
152 | tabs[tabHash](); | |
153 |
} |
|
153 | } | |
154 |
|
154 | |||
155 | YUE.on('refresh','click',function(e){ |
|
155 | YUE.on('refresh','click',function(e){ | |
156 | ypjax(e.currentTarget.href,"journal",function(){ |
|
156 | ypjax(e.currentTarget.href,"journal",function(){ | |
157 | show_more_event(); |
|
157 | show_more_event(); | |
158 | tooltip_activate(); |
|
158 | tooltip_activate(); | |
159 | show_changeset_tooltip(); |
|
159 | show_changeset_tooltip(); | |
160 | }); |
|
160 | }); | |
161 | YUE.preventDefault(e); |
|
161 | YUE.preventDefault(e); | |
162 | }); |
|
162 | }); | |
163 |
|
163 | |||
164 |
|
164 | |||
165 | // main table sorting |
|
165 | // main table sorting | |
166 | var myColumnDefs = [ |
|
166 | var myColumnDefs = [ | |
167 | {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"}, |
|
167 | {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"}, | |
168 | {key:"name",label:"${_('Name')}",sortable:true, |
|
168 | {key:"name",label:"${_('Name')}",sortable:true, | |
169 | sortOptions: { sortFunction: nameSort }}, |
|
169 | sortOptions: { sortFunction: nameSort }}, | |
170 | {key:"tip",label:"${_('Tip')}",sortable:true, |
|
170 | {key:"tip",label:"${_('Tip')}",sortable:true, | |
171 | sortOptions: { sortFunction: revisionSort }}, |
|
171 | sortOptions: { sortFunction: revisionSort }}, | |
172 | {key:"action1",label:"",sortable:false}, |
|
172 | {key:"action1",label:"",sortable:false}, | |
173 | {key:"action2",label:"",sortable:false}, |
|
173 | {key:"action2",label:"",sortable:false}, | |
174 | ]; |
|
174 | ]; | |
175 |
|
175 | |||
176 | var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list")); |
|
176 | var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list")); | |
177 |
|
177 | |||
178 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE; |
|
178 | myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE; | |
179 |
|
179 | |||
180 | myDataSource.responseSchema = { |
|
180 | myDataSource.responseSchema = { | |
181 | fields: [ |
|
181 | fields: [ | |
182 | {key:"menu"}, |
|
182 | {key:"menu"}, | |
183 | {key:"name"}, |
|
183 | {key:"name"}, | |
184 | {key:"tip"}, |
|
184 | {key:"tip"}, | |
185 | {key:"action1"}, |
|
185 | {key:"action1"}, | |
186 | {key:"action2"} |
|
186 | {key:"action2"} | |
187 | ] |
|
187 | ] | |
188 | }; |
|
188 | }; | |
189 |
|
189 | |||
190 | var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource, |
|
190 | var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource, | |
191 | { |
|
191 | { | |
192 | sortedBy:{key:"name",dir:"asc"}, |
|
192 | sortedBy:{key:"name",dir:"asc"}, | |
193 | MSG_SORTASC:"${_('Click to sort ascending')}", |
|
193 | MSG_SORTASC:"${_('Click to sort ascending')}", | |
194 | MSG_SORTDESC:"${_('Click to sort descending')}", |
|
194 | MSG_SORTDESC:"${_('Click to sort descending')}", | |
195 | MSG_EMPTY:"${_('No records found.')}", |
|
195 | MSG_EMPTY:"${_('No records found.')}", | |
196 | MSG_ERROR:"${_('Data error.')}", |
|
196 | MSG_ERROR:"${_('Data error.')}", | |
197 | MSG_LOADING:"${_('Loading...')}", |
|
197 | MSG_LOADING:"${_('Loading...')}", | |
198 | } |
|
198 | } | |
199 | ); |
|
199 | ); | |
200 | myDataTable.subscribe('postRenderEvent',function(oArgs) { |
|
200 | myDataTable.subscribe('postRenderEvent',function(oArgs) { | |
201 | tooltip_activate(); |
|
201 | tooltip_activate(); | |
202 | quick_repo_menu(); |
|
202 | quick_repo_menu(); | |
203 | var func = function(node){ |
|
203 | var func = function(node){ | |
204 | return node.parentNode.parentNode.parentNode.parentNode; |
|
204 | return node.parentNode.parentNode.parentNode.parentNode; | |
205 | } |
|
205 | } | |
206 | q_filter('q_filter',YUQ('#my tr td a.repo_name'),func); |
|
206 | q_filter('q_filter',YUQ('#my tr td a.repo_name'),func); | |
207 | }); |
|
207 | }); | |
208 |
|
208 | |||
209 | </script> |
|
209 | </script> | |
210 | </%def> |
|
210 | </%def> |
@@ -1,47 +1,47 b'' | |||||
1 | %if c.user_repos: |
|
1 | %if c.user_repos: | |
2 | <div id='repos_list_wrap' class="yui-skin-sam"> |
|
2 | <div id='repos_list_wrap' class="yui-skin-sam"> | |
3 | <table id="repos_list"> |
|
3 | <table id="repos_list"> | |
4 | <thead> |
|
4 | <thead> | |
5 | <tr> |
|
5 | <tr> | |
6 | <th></th> |
|
6 | <th></th> | |
7 | <th class="left">${_('Name')}</th> |
|
7 | <th class="left">${_('Name')}</th> | |
8 | <th class="left">${_('Revision')}</th> |
|
8 | <th class="left">${_('Revision')}</th> | |
9 | <th class="left">${_('Action')}</th> |
|
9 | <th class="left">${_('Action')}</th> | |
10 | <th class="left">${_('Action')}</th> |
|
10 | <th class="left">${_('Action')}</th> | |
11 | </thead> |
|
11 | </thead> | |
12 | <tbody> |
|
12 | <tbody> | |
13 | <%namespace name="dt" file="/data_table/_dt_elements.html"/> |
|
13 | <%namespace name="dt" file="/data_table/_dt_elements.html"/> | |
14 | %for repo in c.user_repos: |
|
14 | %for repo in c.user_repos: | |
15 | <tr> |
|
15 | <tr> | |
16 | ##QUICK MENU |
|
16 | ##QUICK MENU | |
17 | <td class="quick_repo_menu"> |
|
17 | <td class="quick_repo_menu"> | |
18 | ${dt.quick_menu(repo['name'])} |
|
18 | ${dt.quick_menu(repo['name'])} | |
19 | </td> |
|
19 | </td> | |
20 | ##REPO NAME AND ICONS |
|
20 | ##REPO NAME AND ICONS | |
21 | <td class="reponame"> |
|
21 | <td class="reponame"> | |
22 | ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']))} |
|
22 | ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']))} | |
23 | </td> |
|
23 | </td> | |
24 | ##LAST REVISION |
|
24 | ##LAST REVISION | |
25 | <td> |
|
25 | <td> | |
26 | ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])} |
|
26 | ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])} | |
27 | </td> |
|
27 | </td> | |
28 | ## |
|
28 | ## | |
29 | <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td> |
|
29 | <td><a href="${h.url('repo_settings_home',repo_name=repo['name'])}" title="${_('edit')}"><img class="icon" alt="${_('private')}" src="${h.url('/images/icons/application_form_edit.png')}"/></a></td> | |
30 | <td> |
|
30 | <td> | |
31 | ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')} |
|
31 | ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')} | |
32 | ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")} |
|
32 | ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")} | |
33 | ${h.end_form()} |
|
33 | ${h.end_form()} | |
34 | </td> |
|
34 | </td> | |
35 | </tr> |
|
35 | </tr> | |
36 | %endfor |
|
36 | %endfor | |
37 | </tbody> |
|
37 | </tbody> | |
38 | </table> |
|
38 | </table> | |
39 | </div> |
|
39 | </div> | |
40 | %else: |
|
40 | %else: | |
41 | <div style="padding:5px 0px 10px 0px;"> |
|
41 | <div style="padding:5px 0px 10px 0px;"> | |
42 | ${_('No repositories yet')} |
|
42 | ${_('No repositories yet')} | |
43 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): |
|
43 | %if h.HasPermissionAny('hg.admin','hg.create.repository')(): | |
44 | ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")} |
|
44 | ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")} | |
45 | %endif |
|
45 | %endif | |
46 | </div> |
|
46 | </div> | |
47 | %endif No newline at end of file |
|
47 | %endif |
@@ -1,207 +1,207 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} ${_('Pull request #%s') % c.pull_request.pull_request_id} |
|
4 | ${c.repo_name} ${_('Pull request #%s') % c.pull_request.pull_request_id} | |
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 | » |
|
9 | » | |
10 | ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))} |
|
10 | ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))} | |
11 | » |
|
11 | » | |
12 | ${_('Pull request #%s') % c.pull_request.pull_request_id} |
|
12 | ${_('Pull request #%s') % c.pull_request.pull_request_id} | |
13 | </%def> |
|
13 | </%def> | |
14 |
|
14 | |||
15 | <%def name="main()"> |
|
15 | <%def name="main()"> | |
16 |
|
16 | |||
17 | <div class="box"> |
|
17 | <div class="box"> | |
18 | <!-- box / title --> |
|
18 | <!-- box / title --> | |
19 | <div class="title"> |
|
19 | <div class="title"> | |
20 | ${self.breadcrumbs()} |
|
20 | ${self.breadcrumbs()} | |
21 | </div> |
|
21 | </div> | |
22 | %if c.pull_request.is_closed(): |
|
22 | %if c.pull_request.is_closed(): | |
23 | <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))} ${_('with status %s') % h.changeset_status_lbl(c.current_changeset_status)}</div> |
|
23 | <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))} ${_('with status %s') % h.changeset_status_lbl(c.current_changeset_status)}</div> | |
24 | %endif |
|
24 | %endif | |
25 | <h3>${_('Title')}: ${c.pull_request.title}</h3> |
|
25 | <h3>${_('Title')}: ${c.pull_request.title}</h3> | |
26 |
|
26 | |||
27 | <div class="form"> |
|
27 | <div class="form"> | |
28 | <div id="summary" class="fields"> |
|
28 | <div id="summary" class="fields"> | |
29 | <div class="field"> |
|
29 | <div class="field"> | |
30 | <div class="label-summary"> |
|
30 | <div class="label-summary"> | |
31 | <label>${_('Status')}:</label> |
|
31 | <label>${_('Status')}:</label> | |
32 | </div> |
|
32 | </div> | |
33 | <div class="input"> |
|
33 | <div class="input"> | |
34 | <div class="changeset-status-container" style="float:none;clear:both"> |
|
34 | <div class="changeset-status-container" style="float:none;clear:both"> | |
35 | %if c.current_changeset_status: |
|
35 | %if c.current_changeset_status: | |
36 | <div title="${_('Pull request status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.current_changeset_status)}]</div> |
|
36 | <div title="${_('Pull request status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.current_changeset_status)}]</div> | |
37 | <div class="changeset-status-ico" style="padding:1px 4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div> |
|
37 | <div class="changeset-status-ico" style="padding:1px 4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div> | |
38 | %endif |
|
38 | %endif | |
39 | </div> |
|
39 | </div> | |
40 | </div> |
|
40 | </div> | |
41 | </div> |
|
41 | </div> | |
42 | <div class="field"> |
|
42 | <div class="field"> | |
43 | <div class="label-summary"> |
|
43 | <div class="label-summary"> | |
44 | <label>${_('Still not reviewed by')}:</label> |
|
44 | <label>${_('Still not reviewed by')}:</label> | |
45 | </div> |
|
45 | </div> | |
46 | <div class="input"> |
|
46 | <div class="input"> | |
47 | % if len(c.pull_request_pending_reviewers) > 0: |
|
47 | % if len(c.pull_request_pending_reviewers) > 0: | |
48 | <div class="tooltip" title="${h.tooltip(','.join([x.username for x in c.pull_request_pending_reviewers]))}">${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div> |
|
48 | <div class="tooltip" title="${h.tooltip(','.join([x.username for x in c.pull_request_pending_reviewers]))}">${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div> | |
49 | %else: |
|
49 | %else: | |
50 | <div>${_('pull request was reviewed by all reviewers')}</div> |
|
50 | <div>${_('pull request was reviewed by all reviewers')}</div> | |
51 | %endif |
|
51 | %endif | |
52 | </div> |
|
52 | </div> | |
53 | </div> |
|
53 | </div> | |
54 | </div> |
|
54 | </div> | |
55 | </div> |
|
55 | </div> | |
56 | <div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div> |
|
56 | <div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div> | |
57 | <div style="padding:4px 4px 10px 20px"> |
|
57 | <div style="padding:4px 4px 10px 20px"> | |
58 | <div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div> |
|
58 | <div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div> | |
59 | </div> |
|
59 | </div> | |
60 |
|
60 | |||
61 | <div style="min-height:160px"> |
|
61 | <div style="min-height:160px"> | |
62 | ##DIFF |
|
62 | ##DIFF | |
63 | <div class="table" style="float:left;clear:none"> |
|
63 | <div class="table" style="float:left;clear:none"> | |
64 | <div id="body" class="diffblock"> |
|
64 | <div id="body" class="diffblock"> | |
65 | <div style="white-space:pre-wrap;padding:5px">${_('Compare view')}</div> |
|
65 | <div style="white-space:pre-wrap;padding:5px">${_('Compare view')}</div> | |
66 | </div> |
|
66 | </div> | |
67 | <div id="changeset_compare_view_content"> |
|
67 | <div id="changeset_compare_view_content"> | |
68 | ##CS |
|
68 | ##CS | |
69 | <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Incoming changesets')}</div> |
|
69 | <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Incoming changesets')}</div> | |
70 | <%include file="/compare/compare_cs.html" /> |
|
70 | <%include file="/compare/compare_cs.html" /> | |
71 |
|
71 | |||
72 | ## FILES |
|
72 | ## FILES | |
73 | <div id="affected_files"> |
|
73 | <div id="affected_files"> | |
74 | % if c.files: |
|
74 | % if c.files: | |
75 | <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div> |
|
75 | <div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div> | |
76 |
<div class="cs_files"> |
|
76 | <div class="cs_files"> | |
77 | %for fid, change, f, stat in c.files: |
|
77 | %for fid, change, f, stat in c.files: | |
78 | <div class="cs_${change}"> |
|
78 | <div class="cs_${change}"> | |
79 | <div class="node">${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}</div> |
|
79 | <div class="node">${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}</div> | |
80 | <div class="changes">${h.fancy_file_stats(stat)}</div> |
|
80 | <div class="changes">${h.fancy_file_stats(stat)}</div> | |
81 | </div> |
|
81 | </div> | |
82 | %endfor |
|
82 | %endfor | |
83 | </div> |
|
83 | </div> | |
84 | %else: |
|
84 | %else: | |
85 | <div class="ui-btn" style="text-align: center;margin-top:5px">${_('Click to load diff details')}</div> |
|
85 | <div class="ui-btn" style="text-align: center;margin-top:5px">${_('Click to load diff details')}</div> | |
86 | %endif |
|
86 | %endif | |
87 | </div> |
|
87 | </div> | |
88 | </div> |
|
88 | </div> | |
89 | </div> |
|
89 | </div> | |
90 | ## REVIEWERS |
|
90 | ## REVIEWERS | |
91 | <div style="float:left; border-left:1px dashed #eee"> |
|
91 | <div style="float:left; border-left:1px dashed #eee"> | |
92 | <h4>${_('Pull request reviewers')}</h4> |
|
92 | <h4>${_('Pull request reviewers')}</h4> | |
93 | <div id="reviewers" style="padding:0px 0px 0px 15px"> |
|
93 | <div id="reviewers" style="padding:0px 0px 0px 15px"> | |
94 | ## members goes here ! |
|
94 | ## members goes here ! | |
95 | <div class="group_members_wrap"> |
|
95 | <div class="group_members_wrap"> | |
96 | <ul id="review_members" class="group_members"> |
|
96 | <ul id="review_members" class="group_members"> | |
97 | %for member,status in c.pull_request_reviewers: |
|
97 | %for member,status in c.pull_request_reviewers: | |
98 | <li id="reviewer_${member.user_id}"> |
|
98 | <li id="reviewer_${member.user_id}"> | |
99 | <div class="reviewers_member"> |
|
99 | <div class="reviewers_member"> | |
100 | <div style="float:left;padding:0px 3px 0px 0px" class="tooltip" title="${h.tooltip(h.changeset_status_lbl(status[0][1].status if status else 'not_reviewed'))}"> |
|
100 | <div style="float:left;padding:0px 3px 0px 0px" class="tooltip" title="${h.tooltip(h.changeset_status_lbl(status[0][1].status if status else 'not_reviewed'))}"> | |
101 | <img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/> |
|
101 | <img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/> | |
102 | </div> |
|
102 | </div> | |
103 | <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div> |
|
103 | <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div> | |
104 | <div style="float:left">${member.full_name} (${_('owner')})</div> |
|
104 | <div style="float:left">${member.full_name} (${_('owner')})</div> | |
105 | <input type="hidden" value="${member.user_id}" name="review_members" /> |
|
105 | <input type="hidden" value="${member.user_id}" name="review_members" /> | |
106 | %if not c.pull_request.is_closed() and (h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id): |
|
106 | %if not c.pull_request.is_closed() and (h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id): | |
107 | <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span> |
|
107 | <span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span> | |
108 | %endif |
|
108 | %endif | |
109 | </div> |
|
109 | </div> | |
110 | </li> |
|
110 | </li> | |
111 | %endfor |
|
111 | %endfor | |
112 | </ul> |
|
112 | </ul> | |
113 | </div> |
|
113 | </div> | |
114 | %if not c.pull_request.is_closed(): |
|
114 | %if not c.pull_request.is_closed(): | |
115 | <div class='ac'> |
|
115 | <div class='ac'> | |
116 | %if h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id: |
|
116 | %if h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id: | |
117 | <div class="reviewer_ac"> |
|
117 | <div class="reviewer_ac"> | |
118 | ${h.text('user', class_='yui-ac-input')} |
|
118 | ${h.text('user', class_='yui-ac-input')} | |
119 | <span class="help-block">${_('Add reviewer to this pull request.')}</span> |
|
119 | <span class="help-block">${_('Add reviewer to this pull request.')}</span> | |
120 | <div id="reviewers_container"></div> |
|
120 | <div id="reviewers_container"></div> | |
121 | </div> |
|
121 | </div> | |
122 | <div style="padding:0px 10px"> |
|
122 | <div style="padding:0px 10px"> | |
123 | <span id="update_pull_request" class="ui-btn xsmall">${_('save')}</span> |
|
123 | <span id="update_pull_request" class="ui-btn xsmall">${_('save')}</span> | |
124 | </div> |
|
124 | </div> | |
125 | %endif |
|
125 | %endif | |
126 | </div> |
|
126 | </div> | |
127 | %endif |
|
127 | %endif | |
128 | </div> |
|
128 | </div> | |
129 | </div> |
|
129 | </div> | |
130 | </div> |
|
130 | </div> | |
131 | <script> |
|
131 | <script> | |
132 | var _USERS_AC_DATA = ${c.users_array|n}; |
|
132 | var _USERS_AC_DATA = ${c.users_array|n}; | |
133 | var _GROUPS_AC_DATA = ${c.users_groups_array|n}; |
|
133 | var _GROUPS_AC_DATA = ${c.users_groups_array|n}; | |
134 | AJAX_COMMENT_URL = "${url('pullrequest_comment',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}"; |
|
134 | AJAX_COMMENT_URL = "${url('pullrequest_comment',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}"; | |
135 | AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"; |
|
135 | AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"; | |
136 | AJAX_UPDATE_PULLREQUEST = "${url('pullrequest_update',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}" |
|
136 | AJAX_UPDATE_PULLREQUEST = "${url('pullrequest_update',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id)}" | |
137 | </script> |
|
137 | </script> | |
138 |
|
138 | |||
139 | ## diff block |
|
139 | ## diff block | |
140 | <div id="diff_block_container" style="clear:both;"> |
|
140 | <div id="diff_block_container" style="clear:both;"> | |
141 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> |
|
141 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> | |
142 | %for fid, change, f, stat in c.files: |
|
142 | %for fid, change, f, stat in c.files: | |
143 | ${diff_block.diff_block_simple([c.changes[fid]])} |
|
143 | ${diff_block.diff_block_simple([c.changes[fid]])} | |
144 | %endfor |
|
144 | %endfor | |
145 | </div> |
|
145 | </div> | |
146 |
|
146 | |||
147 | ## template for inline comment form |
|
147 | ## template for inline comment form | |
148 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
148 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> | |
149 | ${comment.comment_inline_form()} |
|
149 | ${comment.comment_inline_form()} | |
150 |
|
150 | |||
151 | ## render comments and inlines |
|
151 | ## render comments and inlines | |
152 | ${comment.generate_comments()} |
|
152 | ${comment.generate_comments()} | |
153 |
|
153 | |||
154 | % if not c.pull_request.is_closed(): |
|
154 | % if not c.pull_request.is_closed(): | |
155 | ## main comment form and it status |
|
155 | ## main comment form and it status | |
156 | ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name, |
|
156 | ${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name, | |
157 | pull_request_id=c.pull_request.pull_request_id), |
|
157 | pull_request_id=c.pull_request.pull_request_id), | |
158 | c.current_changeset_status, |
|
158 | c.current_changeset_status, | |
159 | close_btn=True)} |
|
159 | close_btn=True)} | |
160 | %endif |
|
160 | %endif | |
161 |
|
161 | |||
162 | <script type="text/javascript"> |
|
162 | <script type="text/javascript"> | |
163 | YUE.onDOMReady(function(){ |
|
163 | YUE.onDOMReady(function(){ | |
164 | PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA); |
|
164 | PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA); | |
165 |
|
165 | |||
166 | YUE.on(YUQ('.show-inline-comments'),'change',function(e){ |
|
166 | YUE.on(YUQ('.show-inline-comments'),'change',function(e){ | |
167 | var show = 'none'; |
|
167 | var show = 'none'; | |
168 | var target = e.currentTarget; |
|
168 | var target = e.currentTarget; | |
169 | if(target.checked){ |
|
169 | if(target.checked){ | |
170 | var show = '' |
|
170 | var show = '' | |
171 | } |
|
171 | } | |
172 | var boxid = YUD.getAttribute(target,'id_for'); |
|
172 | var boxid = YUD.getAttribute(target,'id_for'); | |
173 | var comments = YUQ('#{0} .inline-comments'.format(boxid)); |
|
173 | var comments = YUQ('#{0} .inline-comments'.format(boxid)); | |
174 | for(c in comments){ |
|
174 | for(c in comments){ | |
175 | YUD.setStyle(comments[c],'display',show); |
|
175 | YUD.setStyle(comments[c],'display',show); | |
176 | } |
|
176 | } | |
177 | var btns = YUQ('#{0} .inline-comments-button'.format(boxid)); |
|
177 | var btns = YUQ('#{0} .inline-comments-button'.format(boxid)); | |
178 | for(c in btns){ |
|
178 | for(c in btns){ | |
179 | YUD.setStyle(btns[c],'display',show); |
|
179 | YUD.setStyle(btns[c],'display',show); | |
180 | } |
|
180 | } | |
181 | }) |
|
181 | }) | |
182 |
|
182 | |||
183 | YUE.on(YUQ('.line'),'click',function(e){ |
|
183 | YUE.on(YUQ('.line'),'click',function(e){ | |
184 | var tr = e.currentTarget; |
|
184 | var tr = e.currentTarget; | |
185 | injectInlineForm(tr); |
|
185 | injectInlineForm(tr); | |
186 | }); |
|
186 | }); | |
187 |
|
187 | |||
188 | // inject comments into they proper positions |
|
188 | // inject comments into they proper positions | |
189 | var file_comments = YUQ('.inline-comment-placeholder'); |
|
189 | var file_comments = YUQ('.inline-comment-placeholder'); | |
190 | renderInlineComments(file_comments); |
|
190 | renderInlineComments(file_comments); | |
191 |
|
191 | |||
192 | YUE.on(YUD.get('update_pull_request'),'click',function(e){ |
|
192 | YUE.on(YUD.get('update_pull_request'),'click',function(e){ | |
193 |
|
193 | |||
194 | var reviewers_ids = []; |
|
194 | var reviewers_ids = []; | |
195 | var ids = YUQ('#review_members input'); |
|
195 | var ids = YUQ('#review_members input'); | |
196 | for(var i=0; i<ids.length;i++){ |
|
196 | for(var i=0; i<ids.length;i++){ | |
197 | var id = ids[i].value |
|
197 | var id = ids[i].value | |
198 | reviewers_ids.push(id); |
|
198 | reviewers_ids.push(id); | |
199 | } |
|
199 | } | |
200 | updateReviewers(reviewers_ids); |
|
200 | updateReviewers(reviewers_ids); | |
201 | }) |
|
201 | }) | |
202 | }) |
|
202 | }) | |
203 | </script> |
|
203 | </script> | |
204 |
|
204 | |||
205 | </div> |
|
205 | </div> | |
206 |
|
206 | |||
207 | </%def> |
|
207 | </%def> |
@@ -1,719 +1,719 b'' | |||||
1 | <%inherit file="/base/base.html"/> |
|
1 | <%inherit file="/base/base.html"/> | |
2 |
|
2 | |||
3 | <%def name="title()"> |
|
3 | <%def name="title()"> | |
4 | ${_('%s Summary') % c.repo_name} - ${c.rhodecode_name} |
|
4 | ${_('%s Summary') % c.repo_name} - ${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 | » |
|
9 | » | |
10 | ${h.repo_link(c.dbrepo.groups_and_repo)} |
|
10 | ${h.repo_link(c.dbrepo.groups_and_repo)} | |
11 | » |
|
11 | » | |
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="head_extra()"> |
|
19 | <%def name="head_extra()"> | |
20 | <link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" /> |
|
20 | <link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" /> | |
21 | <link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" /> |
|
21 | <link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" /> | |
22 | </%def> |
|
22 | </%def> | |
23 |
|
23 | |||
24 | <%def name="main()"> |
|
24 | <%def name="main()"> | |
25 | <% |
|
25 | <% | |
26 | summary = lambda n:{False:'summary-short'}.get(n) |
|
26 | summary = lambda n:{False:'summary-short'}.get(n) | |
27 | %> |
|
27 | %> | |
28 | %if c.show_stats: |
|
28 | %if c.show_stats: | |
29 | <div class="box box-left"> |
|
29 | <div class="box box-left"> | |
30 | %else: |
|
30 | %else: | |
31 | <div class="box"> |
|
31 | <div class="box"> | |
32 | %endif |
|
32 | %endif | |
33 | <!-- box / title --> |
|
33 | <!-- box / title --> | |
34 | <div class="title"> |
|
34 | <div class="title"> | |
35 | ${self.breadcrumbs()} |
|
35 | ${self.breadcrumbs()} | |
36 | </div> |
|
36 | </div> | |
37 | <!-- end box / title --> |
|
37 | <!-- end box / title --> | |
38 | <div class="form"> |
|
38 | <div class="form"> | |
39 | <div id="summary" class="fields"> |
|
39 | <div id="summary" class="fields"> | |
40 |
|
40 | |||
41 | <div class="field"> |
|
41 | <div class="field"> | |
42 | <div class="label-summary"> |
|
42 | <div class="label-summary"> | |
43 | <label>${_('Name')}:</label> |
|
43 | <label>${_('Name')}:</label> | |
44 | </div> |
|
44 | </div> | |
45 | <div class="input ${summary(c.show_stats)}"> |
|
45 | <div class="input ${summary(c.show_stats)}"> | |
46 | <div style="float:right;padding:5px 0px 0px 5px"> |
|
46 | <div style="float:right;padding:5px 0px 0px 5px"> | |
47 | %if c.rhodecode_user.username != 'default': |
|
47 | %if c.rhodecode_user.username != 'default': | |
48 | ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')} |
|
48 | ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')} | |
49 | ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')} |
|
49 | ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')} | |
50 | %else: |
|
50 | %else: | |
51 | ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')} |
|
51 | ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')} | |
52 | ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')} |
|
52 | ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')} | |
53 | %endif |
|
53 | %endif | |
54 | </div> |
|
54 | </div> | |
55 | %if c.rhodecode_user.username != 'default': |
|
55 | %if c.rhodecode_user.username != 'default': | |
56 | %if c.following: |
|
56 | %if c.following: | |
57 | <span id="follow_toggle" class="following tooltip" title="${_('Stop following this repository')}" |
|
57 | <span id="follow_toggle" class="following tooltip" title="${_('Stop following this repository')}" | |
58 | onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')"> |
|
58 | onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')"> | |
59 | </span> |
|
59 | </span> | |
60 | %else: |
|
60 | %else: | |
61 | <span id="follow_toggle" class="follow tooltip" title="${_('Start following this repository')}" |
|
61 | <span id="follow_toggle" class="follow tooltip" title="${_('Start following this repository')}" | |
62 | onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')"> |
|
62 | onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')"> | |
63 | </span> |
|
63 | </span> | |
64 | %endif |
|
64 | %endif | |
65 | %endif: |
|
65 | %endif: | |
66 |
|
66 | |||
67 | ## locking icon |
|
67 | ## locking icon | |
68 | %if c.rhodecode_db_repo.enable_locking: |
|
68 | %if c.rhodecode_db_repo.enable_locking: | |
69 | %if c.rhodecode_db_repo.locked[0]: |
|
69 | %if c.rhodecode_db_repo.locked[0]: | |
70 |
<span class="locking_locked tooltip" title="${_('Repository locked by %s') % h.person_by_id(c.rhodecode_db_repo.locked[0])}"></span> |
|
70 | <span class="locking_locked tooltip" title="${_('Repository locked by %s') % h.person_by_id(c.rhodecode_db_repo.locked[0])}"></span> | |
71 | %else: |
|
71 | %else: | |
72 | <span class="locking_unlocked tooltip" title="${_('Repository unlocked')}"></span> |
|
72 | <span class="locking_unlocked tooltip" title="${_('Repository unlocked')}"></span> | |
73 | %endif |
|
73 | %endif | |
74 |
%endif |
|
74 | %endif | |
75 | ##REPO TYPE |
|
75 | ##REPO TYPE | |
76 | %if h.is_hg(c.dbrepo): |
|
76 | %if h.is_hg(c.dbrepo): | |
77 | <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/> |
|
77 | <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/> | |
78 | %endif |
|
78 | %endif | |
79 | %if h.is_git(c.dbrepo): |
|
79 | %if h.is_git(c.dbrepo): | |
80 | <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/> |
|
80 | <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/> | |
81 | %endif |
|
81 | %endif | |
82 |
|
82 | |||
83 | ##PUBLIC/PRIVATE |
|
83 | ##PUBLIC/PRIVATE | |
84 | %if c.dbrepo.private: |
|
84 | %if c.dbrepo.private: | |
85 | <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/> |
|
85 | <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/> | |
86 | %else: |
|
86 | %else: | |
87 | <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/> |
|
87 | <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/> | |
88 | %endif |
|
88 | %endif | |
89 |
|
89 | |||
90 | ##REPO NAME |
|
90 | ##REPO NAME | |
91 | <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span> |
|
91 | <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span> | |
92 |
|
92 | |||
93 | ##FORK |
|
93 | ##FORK | |
94 | %if c.dbrepo.fork: |
|
94 | %if c.dbrepo.fork: | |
95 | <div style="margin-top:5px;clear:both""> |
|
95 | <div style="margin-top:5px;clear:both""> | |
96 | <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/> |
|
96 | <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/> | |
97 | ${_('Fork of')} ${c.dbrepo.fork.repo_name} |
|
97 | ${_('Fork of')} ${c.dbrepo.fork.repo_name} | |
98 | </a> |
|
98 | </a> | |
99 | </div> |
|
99 | </div> | |
100 | %endif |
|
100 | %endif | |
101 | ##REMOTE |
|
101 | ##REMOTE | |
102 | %if c.dbrepo.clone_uri: |
|
102 | %if c.dbrepo.clone_uri: | |
103 | <div style="margin-top:5px;clear:both"> |
|
103 | <div style="margin-top:5px;clear:both"> | |
104 | <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/> |
|
104 | <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/> | |
105 | ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)} |
|
105 | ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)} | |
106 | </a> |
|
106 | </a> | |
107 | </div> |
|
107 | </div> | |
108 | %endif |
|
108 | %endif | |
109 | </div> |
|
109 | </div> | |
110 | </div> |
|
110 | </div> | |
111 |
|
111 | |||
112 | <div class="field"> |
|
112 | <div class="field"> | |
113 | <div class="label-summary"> |
|
113 | <div class="label-summary"> | |
114 | <label>${_('Description')}:</label> |
|
114 | <label>${_('Description')}:</label> | |
115 | </div> |
|
115 | </div> | |
116 | %if c.visual.stylify_metatags: |
|
116 | %if c.visual.stylify_metatags: | |
117 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div> |
|
117 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div> | |
118 | %else: |
|
118 | %else: | |
119 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div> |
|
119 | <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div> | |
120 | %endif |
|
120 | %endif | |
121 | </div> |
|
121 | </div> | |
122 |
|
122 | |||
123 | <div class="field"> |
|
123 | <div class="field"> | |
124 | <div class="label-summary"> |
|
124 | <div class="label-summary"> | |
125 | <label>${_('Contact')}:</label> |
|
125 | <label>${_('Contact')}:</label> | |
126 | </div> |
|
126 | </div> | |
127 | <div class="input ${summary(c.show_stats)}"> |
|
127 | <div class="input ${summary(c.show_stats)}"> | |
128 | <div class="gravatar"> |
|
128 | <div class="gravatar"> | |
129 | <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/> |
|
129 | <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/> | |
130 | </div> |
|
130 | </div> | |
131 | ${_('Username')}: ${c.dbrepo.user.username}<br/> |
|
131 | ${_('Username')}: ${c.dbrepo.user.username}<br/> | |
132 | ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/> |
|
132 | ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/> | |
133 | ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a> |
|
133 | ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a> | |
134 | </div> |
|
134 | </div> | |
135 | </div> |
|
135 | </div> | |
136 |
|
136 | |||
137 | <div class="field"> |
|
137 | <div class="field"> | |
138 | <div class="label-summary"> |
|
138 | <div class="label-summary"> | |
139 | <label>${_('Clone url')}:</label> |
|
139 | <label>${_('Clone url')}:</label> | |
140 | </div> |
|
140 | </div> | |
141 | <div class="input ${summary(c.show_stats)}"> |
|
141 | <div class="input ${summary(c.show_stats)}"> | |
142 | <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div> |
|
142 | <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div> | |
143 | <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div> |
|
143 | <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div> | |
144 | <input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/> |
|
144 | <input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/> | |
145 | <input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/> |
|
145 | <input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/> | |
146 | </div> |
|
146 | </div> | |
147 | </div> |
|
147 | </div> | |
148 |
|
148 | |||
149 | <div class="field"> |
|
149 | <div class="field"> | |
150 | <div class="label-summary"> |
|
150 | <div class="label-summary"> | |
151 | <label>${_('Trending files')}:</label> |
|
151 | <label>${_('Trending files')}:</label> | |
152 | </div> |
|
152 | </div> | |
153 | <div class="input ${summary(c.show_stats)}"> |
|
153 | <div class="input ${summary(c.show_stats)}"> | |
154 | %if c.show_stats: |
|
154 | %if c.show_stats: | |
155 | <div id="lang_stats"></div> |
|
155 | <div id="lang_stats"></div> | |
156 | %else: |
|
156 | %else: | |
157 | ${_('Statistics are disabled for this repository')} |
|
157 | ${_('Statistics are disabled for this repository')} | |
158 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): |
|
158 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): | |
159 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")} |
|
159 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")} | |
160 | %endif |
|
160 | %endif | |
161 | %endif |
|
161 | %endif | |
162 | </div> |
|
162 | </div> | |
163 | </div> |
|
163 | </div> | |
164 |
|
164 | |||
165 | <div class="field"> |
|
165 | <div class="field"> | |
166 | <div class="label-summary"> |
|
166 | <div class="label-summary"> | |
167 | <label>${_('Download')}:</label> |
|
167 | <label>${_('Download')}:</label> | |
168 | </div> |
|
168 | </div> | |
169 | <div class="input ${summary(c.show_stats)}"> |
|
169 | <div class="input ${summary(c.show_stats)}"> | |
170 | %if len(c.rhodecode_repo.revisions) == 0: |
|
170 | %if len(c.rhodecode_repo.revisions) == 0: | |
171 | ${_('There are no downloads yet')} |
|
171 | ${_('There are no downloads yet')} | |
172 | %elif c.enable_downloads is False: |
|
172 | %elif c.enable_downloads is False: | |
173 | ${_('Downloads are disabled for this repository')} |
|
173 | ${_('Downloads are disabled for this repository')} | |
174 | %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'): |
|
174 | %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'): | |
175 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")} |
|
175 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")} | |
176 | %endif |
|
176 | %endif | |
177 | %else: |
|
177 | %else: | |
178 | ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)} |
|
178 | ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)} | |
179 | <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span> |
|
179 | <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span> | |
180 | <span style="vertical-align: bottom"> |
|
180 | <span style="vertical-align: bottom"> | |
181 | <input id="archive_subrepos" type="checkbox" name="subrepos" /> |
|
181 | <input id="archive_subrepos" type="checkbox" name="subrepos" /> | |
182 | <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label> |
|
182 | <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label> | |
183 | </span> |
|
183 | </span> | |
184 | %endif |
|
184 | %endif | |
185 | </div> |
|
185 | </div> | |
186 | </div> |
|
186 | </div> | |
187 | </div> |
|
187 | </div> | |
188 | </div> |
|
188 | </div> | |
189 | </div> |
|
189 | </div> | |
190 |
|
190 | |||
191 | %if c.show_stats: |
|
191 | %if c.show_stats: | |
192 | <div class="box box-right" style="min-height:455px"> |
|
192 | <div class="box box-right" style="min-height:455px"> | |
193 | <!-- box / title --> |
|
193 | <!-- box / title --> | |
194 | <div class="title"> |
|
194 | <div class="title"> | |
195 | <h5>${_('Commit activity by day / author')}</h5> |
|
195 | <h5>${_('Commit activity by day / author')}</h5> | |
196 | </div> |
|
196 | </div> | |
197 |
|
197 | |||
198 | <div class="graph"> |
|
198 | <div class="graph"> | |
199 | <div style="padding:0 10px 10px 17px;"> |
|
199 | <div style="padding:0 10px 10px 17px;"> | |
200 | %if c.no_data: |
|
200 | %if c.no_data: | |
201 | ${c.no_data_msg} |
|
201 | ${c.no_data_msg} | |
202 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): |
|
202 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): | |
203 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")} |
|
203 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")} | |
204 | %endif |
|
204 | %endif | |
205 | %else: |
|
205 | %else: | |
206 | ${_('Stats gathered: ')} ${c.stats_percentage}% |
|
206 | ${_('Stats gathered: ')} ${c.stats_percentage}% | |
207 | %endif |
|
207 | %endif | |
208 | </div> |
|
208 | </div> | |
209 | <div id="commit_history" style="width:450px;height:300px;float:left"></div> |
|
209 | <div id="commit_history" style="width:450px;height:300px;float:left"></div> | |
210 | <div style="clear: both;height: 10px"></div> |
|
210 | <div style="clear: both;height: 10px"></div> | |
211 | <div id="overview" style="width:450px;height:100px;float:left"></div> |
|
211 | <div id="overview" style="width:450px;height:100px;float:left"></div> | |
212 |
|
212 | |||
213 | <div id="legend_data" style="clear:both;margin-top:10px;"> |
|
213 | <div id="legend_data" style="clear:both;margin-top:10px;"> | |
214 | <div id="legend_container"></div> |
|
214 | <div id="legend_container"></div> | |
215 | <div id="legend_choices"> |
|
215 | <div id="legend_choices"> | |
216 | <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table> |
|
216 | <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table> | |
217 | </div> |
|
217 | </div> | |
218 | </div> |
|
218 | </div> | |
219 | </div> |
|
219 | </div> | |
220 | </div> |
|
220 | </div> | |
221 | %endif |
|
221 | %endif | |
222 |
|
222 | |||
223 | <div class="box"> |
|
223 | <div class="box"> | |
224 | <div class="title"> |
|
224 | <div class="title"> | |
225 | <div class="breadcrumbs"> |
|
225 | <div class="breadcrumbs"> | |
226 | %if c.repo_changesets: |
|
226 | %if c.repo_changesets: | |
227 | ${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))} |
|
227 | ${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))} | |
228 | %else: |
|
228 | %else: | |
229 | ${_('Quick start')} |
|
229 | ${_('Quick start')} | |
230 | %endif |
|
230 | %endif | |
231 | </div> |
|
231 | </div> | |
232 | </div> |
|
232 | </div> | |
233 | <div class="table"> |
|
233 | <div class="table"> | |
234 | <div id="shortlog_data"> |
|
234 | <div id="shortlog_data"> | |
235 | <%include file='../shortlog/shortlog_data.html'/> |
|
235 | <%include file='../shortlog/shortlog_data.html'/> | |
236 | </div> |
|
236 | </div> | |
237 | </div> |
|
237 | </div> | |
238 | </div> |
|
238 | </div> | |
239 |
|
239 | |||
240 | %if c.readme_data: |
|
240 | %if c.readme_data: | |
241 | <div id="readme" class="box header-pos-fix" style="background-color: #FAFAFA"> |
|
241 | <div id="readme" class="box header-pos-fix" style="background-color: #FAFAFA"> | |
242 | <div id="readme" class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}"> |
|
242 | <div id="readme" class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}"> | |
243 | <div class="breadcrumbs"> |
|
243 | <div class="breadcrumbs"> | |
244 | <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a> |
|
244 | <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a> | |
245 | <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">¶</a> |
|
245 | <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">¶</a> | |
246 | </div> |
|
246 | </div> | |
247 | </div> |
|
247 | </div> | |
248 | <div id="readme" class="readme"> |
|
248 | <div id="readme" class="readme"> | |
249 | <div class="readme_box"> |
|
249 | <div class="readme_box"> | |
250 | ${c.readme_data|n} |
|
250 | ${c.readme_data|n} | |
251 | </div> |
|
251 | </div> | |
252 | </div> |
|
252 | </div> | |
253 | </div> |
|
253 | </div> | |
254 | %endif |
|
254 | %endif | |
255 |
|
255 | |||
256 | <script type="text/javascript"> |
|
256 | <script type="text/javascript"> | |
257 | var clone_url = 'clone_url'; |
|
257 | var clone_url = 'clone_url'; | |
258 | YUE.on(clone_url,'click',function(e){ |
|
258 | YUE.on(clone_url,'click',function(e){ | |
259 | if(YUD.hasClass(clone_url,'selected')){ |
|
259 | if(YUD.hasClass(clone_url,'selected')){ | |
260 | return |
|
260 | return | |
261 | } |
|
261 | } | |
262 | else{ |
|
262 | else{ | |
263 | YUD.addClass(clone_url,'selected'); |
|
263 | YUD.addClass(clone_url,'selected'); | |
264 | YUD.get(clone_url).select(); |
|
264 | YUD.get(clone_url).select(); | |
265 | } |
|
265 | } | |
266 | }) |
|
266 | }) | |
267 |
|
267 | |||
268 | YUE.on('clone_by_name','click',function(e){ |
|
268 | YUE.on('clone_by_name','click',function(e){ | |
269 | // show url by name and hide name button |
|
269 | // show url by name and hide name button | |
270 | YUD.setStyle('clone_url','display',''); |
|
270 | YUD.setStyle('clone_url','display',''); | |
271 | YUD.setStyle('clone_by_name','display','none'); |
|
271 | YUD.setStyle('clone_by_name','display','none'); | |
272 |
|
272 | |||
273 | // hide url by id and show name button |
|
273 | // hide url by id and show name button | |
274 | YUD.setStyle('clone_by_id','display',''); |
|
274 | YUD.setStyle('clone_by_id','display',''); | |
275 | YUD.setStyle('clone_url_id','display','none'); |
|
275 | YUD.setStyle('clone_url_id','display','none'); | |
276 |
|
276 | |||
277 | }) |
|
277 | }) | |
278 | YUE.on('clone_by_id','click',function(e){ |
|
278 | YUE.on('clone_by_id','click',function(e){ | |
279 |
|
279 | |||
280 | // show url by id and hide id button |
|
280 | // show url by id and hide id button | |
281 | YUD.setStyle('clone_by_id','display','none'); |
|
281 | YUD.setStyle('clone_by_id','display','none'); | |
282 | YUD.setStyle('clone_url_id','display',''); |
|
282 | YUD.setStyle('clone_url_id','display',''); | |
283 |
|
283 | |||
284 | // hide url by name and show id button |
|
284 | // hide url by name and show id button | |
285 | YUD.setStyle('clone_by_name','display',''); |
|
285 | YUD.setStyle('clone_by_name','display',''); | |
286 | YUD.setStyle('clone_url','display','none'); |
|
286 | YUD.setStyle('clone_url','display','none'); | |
287 | }) |
|
287 | }) | |
288 |
|
288 | |||
289 |
|
289 | |||
290 | var tmpl_links = {}; |
|
290 | var tmpl_links = {}; | |
291 | %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()): |
|
291 | %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()): | |
292 | tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}'; |
|
292 | tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}'; | |
293 | %endfor |
|
293 | %endfor | |
294 |
|
294 | |||
295 | YUE.on(['download_options','archive_subrepos'],'change',function(e){ |
|
295 | YUE.on(['download_options','archive_subrepos'],'change',function(e){ | |
296 | var sm = YUD.get('download_options'); |
|
296 | var sm = YUD.get('download_options'); | |
297 | var new_cs = sm.options[sm.selectedIndex]; |
|
297 | var new_cs = sm.options[sm.selectedIndex]; | |
298 |
|
298 | |||
299 | for(k in tmpl_links){ |
|
299 | for(k in tmpl_links){ | |
300 | var s = YUD.get(k+'_link'); |
|
300 | var s = YUD.get(k+'_link'); | |
301 | if(s){ |
|
301 | if(s){ | |
302 | var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}"; |
|
302 | var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}"; | |
303 | title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text); |
|
303 | title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text); | |
304 | title_tmpl = title_tmpl.replace('__CS_EXT__',k); |
|
304 | title_tmpl = title_tmpl.replace('__CS_EXT__',k); | |
305 |
|
305 | |||
306 | var url = tmpl_links[k].replace('__CS__',new_cs.value); |
|
306 | var url = tmpl_links[k].replace('__CS__',new_cs.value); | |
307 | var subrepos = YUD.get('archive_subrepos').checked; |
|
307 | var subrepos = YUD.get('archive_subrepos').checked; | |
308 | url = url.replace('__SUB__',subrepos); |
|
308 | url = url.replace('__SUB__',subrepos); | |
309 | url = url.replace('__NAME__',title_tmpl); |
|
309 | url = url.replace('__NAME__',title_tmpl); | |
310 | s.innerHTML = url |
|
310 | s.innerHTML = url | |
311 | } |
|
311 | } | |
312 | } |
|
312 | } | |
313 | }); |
|
313 | }); | |
314 | </script> |
|
314 | </script> | |
315 | %if c.show_stats: |
|
315 | %if c.show_stats: | |
316 | <script type="text/javascript"> |
|
316 | <script type="text/javascript"> | |
317 | var data = ${c.trending_languages|n}; |
|
317 | var data = ${c.trending_languages|n}; | |
318 | var total = 0; |
|
318 | var total = 0; | |
319 | var no_data = true; |
|
319 | var no_data = true; | |
320 | var tbl = document.createElement('table'); |
|
320 | var tbl = document.createElement('table'); | |
321 | tbl.setAttribute('class','trending_language_tbl'); |
|
321 | tbl.setAttribute('class','trending_language_tbl'); | |
322 | var cnt = 0; |
|
322 | var cnt = 0; | |
323 | for (var i=0;i<data.length;i++){ |
|
323 | for (var i=0;i<data.length;i++){ | |
324 | total+= data[i][1].count; |
|
324 | total+= data[i][1].count; | |
325 | } |
|
325 | } | |
326 | for (var i=0;i<data.length;i++){ |
|
326 | for (var i=0;i<data.length;i++){ | |
327 | cnt += 1; |
|
327 | cnt += 1; | |
328 | no_data = false; |
|
328 | no_data = false; | |
329 |
|
329 | |||
330 | var hide = cnt>2; |
|
330 | var hide = cnt>2; | |
331 | var tr = document.createElement('tr'); |
|
331 | var tr = document.createElement('tr'); | |
332 | if (hide){ |
|
332 | if (hide){ | |
333 | tr.setAttribute('style','display:none'); |
|
333 | tr.setAttribute('style','display:none'); | |
334 | tr.setAttribute('class','stats_hidden'); |
|
334 | tr.setAttribute('class','stats_hidden'); | |
335 | } |
|
335 | } | |
336 | var k = data[i][0]; |
|
336 | var k = data[i][0]; | |
337 | var obj = data[i][1]; |
|
337 | var obj = data[i][1]; | |
338 | var percentage = Math.round((obj.count/total*100),2); |
|
338 | var percentage = Math.round((obj.count/total*100),2); | |
339 |
|
339 | |||
340 | var td1 = document.createElement('td'); |
|
340 | var td1 = document.createElement('td'); | |
341 | td1.width = 150; |
|
341 | td1.width = 150; | |
342 | var trending_language_label = document.createElement('div'); |
|
342 | var trending_language_label = document.createElement('div'); | |
343 | trending_language_label.innerHTML = obj.desc+" ("+k+")"; |
|
343 | trending_language_label.innerHTML = obj.desc+" ("+k+")"; | |
344 | td1.appendChild(trending_language_label); |
|
344 | td1.appendChild(trending_language_label); | |
345 |
|
345 | |||
346 | var td2 = document.createElement('td'); |
|
346 | var td2 = document.createElement('td'); | |
347 | td2.setAttribute('style','padding-right:14px !important'); |
|
347 | td2.setAttribute('style','padding-right:14px !important'); | |
348 | var trending_language = document.createElement('div'); |
|
348 | var trending_language = document.createElement('div'); | |
349 | var nr_files = obj.count+" ${_('files')}"; |
|
349 | var nr_files = obj.count+" ${_('files')}"; | |
350 |
|
350 | |||
351 | trending_language.title = k+" "+nr_files; |
|
351 | trending_language.title = k+" "+nr_files; | |
352 |
|
352 | |||
353 | if (percentage>22){ |
|
353 | if (percentage>22){ | |
354 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>"; |
|
354 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>"; | |
355 | } |
|
355 | } | |
356 | else{ |
|
356 | else{ | |
357 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>"; |
|
357 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>"; | |
358 | } |
|
358 | } | |
359 |
|
359 | |||
360 | trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner'); |
|
360 | trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner'); | |
361 | trending_language.style.width=percentage+"%"; |
|
361 | trending_language.style.width=percentage+"%"; | |
362 | td2.appendChild(trending_language); |
|
362 | td2.appendChild(trending_language); | |
363 |
|
363 | |||
364 | tr.appendChild(td1); |
|
364 | tr.appendChild(td1); | |
365 | tr.appendChild(td2); |
|
365 | tr.appendChild(td2); | |
366 | tbl.appendChild(tr); |
|
366 | tbl.appendChild(tr); | |
367 | if(cnt == 3){ |
|
367 | if(cnt == 3){ | |
368 | var show_more = document.createElement('tr'); |
|
368 | var show_more = document.createElement('tr'); | |
369 | var td = document.createElement('td'); |
|
369 | var td = document.createElement('td'); | |
370 | lnk = document.createElement('a'); |
|
370 | lnk = document.createElement('a'); | |
371 |
|
371 | |||
372 | lnk.href='#'; |
|
372 | lnk.href='#'; | |
373 | lnk.innerHTML = "${_('show more')}"; |
|
373 | lnk.innerHTML = "${_('show more')}"; | |
374 | lnk.id='code_stats_show_more'; |
|
374 | lnk.id='code_stats_show_more'; | |
375 | td.appendChild(lnk); |
|
375 | td.appendChild(lnk); | |
376 |
|
376 | |||
377 | show_more.appendChild(td); |
|
377 | show_more.appendChild(td); | |
378 | show_more.appendChild(document.createElement('td')); |
|
378 | show_more.appendChild(document.createElement('td')); | |
379 | tbl.appendChild(show_more); |
|
379 | tbl.appendChild(show_more); | |
380 | } |
|
380 | } | |
381 |
|
381 | |||
382 | } |
|
382 | } | |
383 |
|
383 | |||
384 | YUD.get('lang_stats').appendChild(tbl); |
|
384 | YUD.get('lang_stats').appendChild(tbl); | |
385 | YUE.on('code_stats_show_more','click',function(){ |
|
385 | YUE.on('code_stats_show_more','click',function(){ | |
386 | l = YUD.getElementsByClassName('stats_hidden') |
|
386 | l = YUD.getElementsByClassName('stats_hidden') | |
387 | for (e in l){ |
|
387 | for (e in l){ | |
388 | YUD.setStyle(l[e],'display',''); |
|
388 | YUD.setStyle(l[e],'display',''); | |
389 | }; |
|
389 | }; | |
390 | YUD.setStyle(YUD.get('code_stats_show_more'), |
|
390 | YUD.setStyle(YUD.get('code_stats_show_more'), | |
391 | 'display','none'); |
|
391 | 'display','none'); | |
392 | }); |
|
392 | }); | |
393 | </script> |
|
393 | </script> | |
394 | <script type="text/javascript"> |
|
394 | <script type="text/javascript"> | |
395 | /** |
|
395 | /** | |
396 | * Plots summary graph |
|
396 | * Plots summary graph | |
397 | * |
|
397 | * | |
398 | * @class SummaryPlot |
|
398 | * @class SummaryPlot | |
399 | * @param {from} initial from for detailed graph |
|
399 | * @param {from} initial from for detailed graph | |
400 | * @param {to} initial to for detailed graph |
|
400 | * @param {to} initial to for detailed graph | |
401 | * @param {dataset} |
|
401 | * @param {dataset} | |
402 | * @param {overview_dataset} |
|
402 | * @param {overview_dataset} | |
403 | */ |
|
403 | */ | |
404 | function SummaryPlot(from,to,dataset,overview_dataset) { |
|
404 | function SummaryPlot(from,to,dataset,overview_dataset) { | |
405 | var initial_ranges = { |
|
405 | var initial_ranges = { | |
406 | "xaxis":{ |
|
406 | "xaxis":{ | |
407 | "from":from, |
|
407 | "from":from, | |
408 | "to":to, |
|
408 | "to":to, | |
409 | }, |
|
409 | }, | |
410 | }; |
|
410 | }; | |
411 | var dataset = dataset; |
|
411 | var dataset = dataset; | |
412 | var overview_dataset = [overview_dataset]; |
|
412 | var overview_dataset = [overview_dataset]; | |
413 | var choiceContainer = YUD.get("legend_choices"); |
|
413 | var choiceContainer = YUD.get("legend_choices"); | |
414 | var choiceContainerTable = YUD.get("legend_choices_tables"); |
|
414 | var choiceContainerTable = YUD.get("legend_choices_tables"); | |
415 | var plotContainer = YUD.get('commit_history'); |
|
415 | var plotContainer = YUD.get('commit_history'); | |
416 | var overviewContainer = YUD.get('overview'); |
|
416 | var overviewContainer = YUD.get('overview'); | |
417 |
|
417 | |||
418 | var plot_options = { |
|
418 | var plot_options = { | |
419 | bars: {show:true,align:'center',lineWidth:4}, |
|
419 | bars: {show:true,align:'center',lineWidth:4}, | |
420 | legend: {show:true, container:"legend_container"}, |
|
420 | legend: {show:true, container:"legend_container"}, | |
421 | points: {show:true,radius:0,fill:false}, |
|
421 | points: {show:true,radius:0,fill:false}, | |
422 | yaxis: {tickDecimals:0,}, |
|
422 | yaxis: {tickDecimals:0,}, | |
423 | xaxis: { |
|
423 | xaxis: { | |
424 | mode: "time", |
|
424 | mode: "time", | |
425 | timeformat: "%d/%m", |
|
425 | timeformat: "%d/%m", | |
426 | min:from, |
|
426 | min:from, | |
427 | max:to, |
|
427 | max:to, | |
428 | }, |
|
428 | }, | |
429 | grid: { |
|
429 | grid: { | |
430 | hoverable: true, |
|
430 | hoverable: true, | |
431 | clickable: true, |
|
431 | clickable: true, | |
432 | autoHighlight:true, |
|
432 | autoHighlight:true, | |
433 | color: "#999" |
|
433 | color: "#999" | |
434 | }, |
|
434 | }, | |
435 | //selection: {mode: "x"} |
|
435 | //selection: {mode: "x"} | |
436 | }; |
|
436 | }; | |
437 | var overview_options = { |
|
437 | var overview_options = { | |
438 | legend:{show:false}, |
|
438 | legend:{show:false}, | |
439 | bars: {show:true,barWidth: 2,}, |
|
439 | bars: {show:true,barWidth: 2,}, | |
440 | shadowSize: 0, |
|
440 | shadowSize: 0, | |
441 | xaxis: {mode: "time", timeformat: "%d/%m/%y",}, |
|
441 | xaxis: {mode: "time", timeformat: "%d/%m/%y",}, | |
442 | yaxis: {ticks: 3, min: 0,tickDecimals:0,}, |
|
442 | yaxis: {ticks: 3, min: 0,tickDecimals:0,}, | |
443 | grid: {color: "#999",}, |
|
443 | grid: {color: "#999",}, | |
444 | selection: {mode: "x"} |
|
444 | selection: {mode: "x"} | |
445 | }; |
|
445 | }; | |
446 |
|
446 | |||
447 | /** |
|
447 | /** | |
448 | *get dummy data needed in few places |
|
448 | *get dummy data needed in few places | |
449 | */ |
|
449 | */ | |
450 | function getDummyData(label){ |
|
450 | function getDummyData(label){ | |
451 | return {"label":label, |
|
451 | return {"label":label, | |
452 | "data":[{"time":0, |
|
452 | "data":[{"time":0, | |
453 | "commits":0, |
|
453 | "commits":0, | |
454 | "added":0, |
|
454 | "added":0, | |
455 | "changed":0, |
|
455 | "changed":0, | |
456 | "removed":0, |
|
456 | "removed":0, | |
457 | }], |
|
457 | }], | |
458 | "schema":["commits"], |
|
458 | "schema":["commits"], | |
459 | "color":'#ffffff', |
|
459 | "color":'#ffffff', | |
460 | } |
|
460 | } | |
461 | } |
|
461 | } | |
462 |
|
462 | |||
463 | /** |
|
463 | /** | |
464 | * generate checkboxes accordindly to data |
|
464 | * generate checkboxes accordindly to data | |
465 | * @param keys |
|
465 | * @param keys | |
466 | * @returns |
|
466 | * @returns | |
467 | */ |
|
467 | */ | |
468 | function generateCheckboxes(data) { |
|
468 | function generateCheckboxes(data) { | |
469 | //append checkboxes |
|
469 | //append checkboxes | |
470 | var i = 0; |
|
470 | var i = 0; | |
471 | choiceContainerTable.innerHTML = ''; |
|
471 | choiceContainerTable.innerHTML = ''; | |
472 | for(var pos in data) { |
|
472 | for(var pos in data) { | |
473 |
|
473 | |||
474 | data[pos].color = i; |
|
474 | data[pos].color = i; | |
475 | i++; |
|
475 | i++; | |
476 | if(data[pos].label != ''){ |
|
476 | if(data[pos].label != ''){ | |
477 | choiceContainerTable.innerHTML += |
|
477 | choiceContainerTable.innerHTML += | |
478 | '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \ |
|
478 | '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \ | |
479 | <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label); |
|
479 | <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label); | |
480 | } |
|
480 | } | |
481 | } |
|
481 | } | |
482 | } |
|
482 | } | |
483 |
|
483 | |||
484 | /** |
|
484 | /** | |
485 | * ToolTip show |
|
485 | * ToolTip show | |
486 | */ |
|
486 | */ | |
487 | function showTooltip(x, y, contents) { |
|
487 | function showTooltip(x, y, contents) { | |
488 | var div=document.getElementById('tooltip'); |
|
488 | var div=document.getElementById('tooltip'); | |
489 | if(!div) { |
|
489 | if(!div) { | |
490 | div = document.createElement('div'); |
|
490 | div = document.createElement('div'); | |
491 | div.id="tooltip"; |
|
491 | div.id="tooltip"; | |
492 | div.style.position="absolute"; |
|
492 | div.style.position="absolute"; | |
493 | div.style.border='1px solid #fdd'; |
|
493 | div.style.border='1px solid #fdd'; | |
494 | div.style.padding='2px'; |
|
494 | div.style.padding='2px'; | |
495 | div.style.backgroundColor='#fee'; |
|
495 | div.style.backgroundColor='#fee'; | |
496 | document.body.appendChild(div); |
|
496 | document.body.appendChild(div); | |
497 | } |
|
497 | } | |
498 | YUD.setStyle(div, 'opacity', 0); |
|
498 | YUD.setStyle(div, 'opacity', 0); | |
499 | div.innerHTML = contents; |
|
499 | div.innerHTML = contents; | |
500 | div.style.top=(y + 5) + "px"; |
|
500 | div.style.top=(y + 5) + "px"; | |
501 | div.style.left=(x + 5) + "px"; |
|
501 | div.style.left=(x + 5) + "px"; | |
502 |
|
502 | |||
503 | var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2); |
|
503 | var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2); | |
504 | anim.animate(); |
|
504 | anim.animate(); | |
505 | } |
|
505 | } | |
506 |
|
506 | |||
507 | /** |
|
507 | /** | |
508 | * This function will detect if selected period has some changesets |
|
508 | * This function will detect if selected period has some changesets | |
509 | for this user if it does this data is then pushed for displaying |
|
509 | for this user if it does this data is then pushed for displaying | |
510 | Additionally it will only display users that are selected by the checkbox |
|
510 | Additionally it will only display users that are selected by the checkbox | |
511 | */ |
|
511 | */ | |
512 | function getDataAccordingToRanges(ranges) { |
|
512 | function getDataAccordingToRanges(ranges) { | |
513 |
|
513 | |||
514 | var data = []; |
|
514 | var data = []; | |
515 | var new_dataset = {}; |
|
515 | var new_dataset = {}; | |
516 | var keys = []; |
|
516 | var keys = []; | |
517 | var max_commits = 0; |
|
517 | var max_commits = 0; | |
518 | for(var key in dataset){ |
|
518 | for(var key in dataset){ | |
519 |
|
519 | |||
520 | for(var ds in dataset[key].data){ |
|
520 | for(var ds in dataset[key].data){ | |
521 | commit_data = dataset[key].data[ds]; |
|
521 | commit_data = dataset[key].data[ds]; | |
522 | if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){ |
|
522 | if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){ | |
523 |
|
523 | |||
524 | if(new_dataset[key] === undefined){ |
|
524 | if(new_dataset[key] === undefined){ | |
525 | new_dataset[key] = {data:[],schema:["commits"],label:key}; |
|
525 | new_dataset[key] = {data:[],schema:["commits"],label:key}; | |
526 | } |
|
526 | } | |
527 | new_dataset[key].data.push(commit_data); |
|
527 | new_dataset[key].data.push(commit_data); | |
528 | } |
|
528 | } | |
529 | } |
|
529 | } | |
530 | if (new_dataset[key] !== undefined){ |
|
530 | if (new_dataset[key] !== undefined){ | |
531 | data.push(new_dataset[key]); |
|
531 | data.push(new_dataset[key]); | |
532 | } |
|
532 | } | |
533 | } |
|
533 | } | |
534 |
|
534 | |||
535 | if (data.length > 0){ |
|
535 | if (data.length > 0){ | |
536 | return data; |
|
536 | return data; | |
537 | } |
|
537 | } | |
538 | else{ |
|
538 | else{ | |
539 | //just return dummy data for graph to plot itself |
|
539 | //just return dummy data for graph to plot itself | |
540 | return [getDummyData('')]; |
|
540 | return [getDummyData('')]; | |
541 | } |
|
541 | } | |
542 | } |
|
542 | } | |
543 |
|
543 | |||
544 | /** |
|
544 | /** | |
545 | * redraw using new checkbox data |
|
545 | * redraw using new checkbox data | |
546 | */ |
|
546 | */ | |
547 | function plotchoiced(e,args){ |
|
547 | function plotchoiced(e,args){ | |
548 | var cur_data = args[0]; |
|
548 | var cur_data = args[0]; | |
549 | var cur_ranges = args[1]; |
|
549 | var cur_ranges = args[1]; | |
550 |
|
550 | |||
551 | var new_data = []; |
|
551 | var new_data = []; | |
552 | var inputs = choiceContainer.getElementsByTagName("input"); |
|
552 | var inputs = choiceContainer.getElementsByTagName("input"); | |
553 |
|
553 | |||
554 | //show only checked labels |
|
554 | //show only checked labels | |
555 | for(var i=0; i<inputs.length; i++) { |
|
555 | for(var i=0; i<inputs.length; i++) { | |
556 | var checkbox_key = inputs[i].name; |
|
556 | var checkbox_key = inputs[i].name; | |
557 |
|
557 | |||
558 | if(inputs[i].checked){ |
|
558 | if(inputs[i].checked){ | |
559 | for(var d in cur_data){ |
|
559 | for(var d in cur_data){ | |
560 | if(cur_data[d].label == checkbox_key){ |
|
560 | if(cur_data[d].label == checkbox_key){ | |
561 | new_data.push(cur_data[d]); |
|
561 | new_data.push(cur_data[d]); | |
562 | } |
|
562 | } | |
563 | } |
|
563 | } | |
564 | } |
|
564 | } | |
565 | else{ |
|
565 | else{ | |
566 | //push dummy data to not hide the label |
|
566 | //push dummy data to not hide the label | |
567 | new_data.push(getDummyData(checkbox_key)); |
|
567 | new_data.push(getDummyData(checkbox_key)); | |
568 | } |
|
568 | } | |
569 | } |
|
569 | } | |
570 |
|
570 | |||
571 | var new_options = YAHOO.lang.merge(plot_options, { |
|
571 | var new_options = YAHOO.lang.merge(plot_options, { | |
572 | xaxis: { |
|
572 | xaxis: { | |
573 | min: cur_ranges.xaxis.from, |
|
573 | min: cur_ranges.xaxis.from, | |
574 | max: cur_ranges.xaxis.to, |
|
574 | max: cur_ranges.xaxis.to, | |
575 | mode:"time", |
|
575 | mode:"time", | |
576 | timeformat: "%d/%m", |
|
576 | timeformat: "%d/%m", | |
577 | }, |
|
577 | }, | |
578 | }); |
|
578 | }); | |
579 | if (!new_data){ |
|
579 | if (!new_data){ | |
580 | new_data = [[0,1]]; |
|
580 | new_data = [[0,1]]; | |
581 | } |
|
581 | } | |
582 | // do the zooming |
|
582 | // do the zooming | |
583 | plot = YAHOO.widget.Flot(plotContainer, new_data, new_options); |
|
583 | plot = YAHOO.widget.Flot(plotContainer, new_data, new_options); | |
584 |
|
584 | |||
585 | plot.subscribe("plotselected", plotselected); |
|
585 | plot.subscribe("plotselected", plotselected); | |
586 |
|
586 | |||
587 | //resubscribe plothover |
|
587 | //resubscribe plothover | |
588 | plot.subscribe("plothover", plothover); |
|
588 | plot.subscribe("plothover", plothover); | |
589 |
|
589 | |||
590 | // don't fire event on the overview to prevent eternal loop |
|
590 | // don't fire event on the overview to prevent eternal loop | |
591 | overview.setSelection(cur_ranges, true); |
|
591 | overview.setSelection(cur_ranges, true); | |
592 |
|
592 | |||
593 | } |
|
593 | } | |
594 |
|
594 | |||
595 | /** |
|
595 | /** | |
596 | * plot only selected items from overview |
|
596 | * plot only selected items from overview | |
597 | * @param ranges |
|
597 | * @param ranges | |
598 | * @returns |
|
598 | * @returns | |
599 | */ |
|
599 | */ | |
600 | function plotselected(ranges,cur_data) { |
|
600 | function plotselected(ranges,cur_data) { | |
601 | //updates the data for new plot |
|
601 | //updates the data for new plot | |
602 | var data = getDataAccordingToRanges(ranges); |
|
602 | var data = getDataAccordingToRanges(ranges); | |
603 | generateCheckboxes(data); |
|
603 | generateCheckboxes(data); | |
604 |
|
604 | |||
605 | var new_options = YAHOO.lang.merge(plot_options, { |
|
605 | var new_options = YAHOO.lang.merge(plot_options, { | |
606 | xaxis: { |
|
606 | xaxis: { | |
607 | min: ranges.xaxis.from, |
|
607 | min: ranges.xaxis.from, | |
608 | max: ranges.xaxis.to, |
|
608 | max: ranges.xaxis.to, | |
609 | mode:"time", |
|
609 | mode:"time", | |
610 | timeformat: "%d/%m", |
|
610 | timeformat: "%d/%m", | |
611 | }, |
|
611 | }, | |
612 | }); |
|
612 | }); | |
613 | // do the zooming |
|
613 | // do the zooming | |
614 | plot = YAHOO.widget.Flot(plotContainer, data, new_options); |
|
614 | plot = YAHOO.widget.Flot(plotContainer, data, new_options); | |
615 |
|
615 | |||
616 | plot.subscribe("plotselected", plotselected); |
|
616 | plot.subscribe("plotselected", plotselected); | |
617 |
|
617 | |||
618 | //resubscribe plothover |
|
618 | //resubscribe plothover | |
619 | plot.subscribe("plothover", plothover); |
|
619 | plot.subscribe("plothover", plothover); | |
620 |
|
620 | |||
621 | // don't fire event on the overview to prevent eternal loop |
|
621 | // don't fire event on the overview to prevent eternal loop | |
622 | overview.setSelection(ranges, true); |
|
622 | overview.setSelection(ranges, true); | |
623 |
|
623 | |||
624 | //resubscribe choiced |
|
624 | //resubscribe choiced | |
625 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]); |
|
625 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]); | |
626 | } |
|
626 | } | |
627 |
|
627 | |||
628 | var previousPoint = null; |
|
628 | var previousPoint = null; | |
629 |
|
629 | |||
630 | function plothover(o) { |
|
630 | function plothover(o) { | |
631 | var pos = o.pos; |
|
631 | var pos = o.pos; | |
632 | var item = o.item; |
|
632 | var item = o.item; | |
633 |
|
633 | |||
634 | //YUD.get("x").innerHTML = pos.x.toFixed(2); |
|
634 | //YUD.get("x").innerHTML = pos.x.toFixed(2); | |
635 | //YUD.get("y").innerHTML = pos.y.toFixed(2); |
|
635 | //YUD.get("y").innerHTML = pos.y.toFixed(2); | |
636 | if (item) { |
|
636 | if (item) { | |
637 | if (previousPoint != item.datapoint) { |
|
637 | if (previousPoint != item.datapoint) { | |
638 | previousPoint = item.datapoint; |
|
638 | previousPoint = item.datapoint; | |
639 |
|
639 | |||
640 | var tooltip = YUD.get("tooltip"); |
|
640 | var tooltip = YUD.get("tooltip"); | |
641 | if(tooltip) { |
|
641 | if(tooltip) { | |
642 | tooltip.parentNode.removeChild(tooltip); |
|
642 | tooltip.parentNode.removeChild(tooltip); | |
643 | } |
|
643 | } | |
644 | var x = item.datapoint.x.toFixed(2); |
|
644 | var x = item.datapoint.x.toFixed(2); | |
645 | var y = item.datapoint.y.toFixed(2); |
|
645 | var y = item.datapoint.y.toFixed(2); | |
646 |
|
646 | |||
647 | if (!item.series.label){ |
|
647 | if (!item.series.label){ | |
648 | item.series.label = 'commits'; |
|
648 | item.series.label = 'commits'; | |
649 | } |
|
649 | } | |
650 | var d = new Date(x*1000); |
|
650 | var d = new Date(x*1000); | |
651 | var fd = d.toDateString() |
|
651 | var fd = d.toDateString() | |
652 | var nr_commits = parseInt(y); |
|
652 | var nr_commits = parseInt(y); | |
653 |
|
653 | |||
654 | var cur_data = dataset[item.series.label].data[item.dataIndex]; |
|
654 | var cur_data = dataset[item.series.label].data[item.dataIndex]; | |
655 | var added = cur_data.added; |
|
655 | var added = cur_data.added; | |
656 | var changed = cur_data.changed; |
|
656 | var changed = cur_data.changed; | |
657 | var removed = cur_data.removed; |
|
657 | var removed = cur_data.removed; | |
658 |
|
658 | |||
659 | var nr_commits_suffix = " ${_('commits')} "; |
|
659 | var nr_commits_suffix = " ${_('commits')} "; | |
660 | var added_suffix = " ${_('files added')} "; |
|
660 | var added_suffix = " ${_('files added')} "; | |
661 | var changed_suffix = " ${_('files changed')} "; |
|
661 | var changed_suffix = " ${_('files changed')} "; | |
662 | var removed_suffix = " ${_('files removed')} "; |
|
662 | var removed_suffix = " ${_('files removed')} "; | |
663 |
|
663 | |||
664 |
|
664 | |||
665 | if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";} |
|
665 | if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";} | |
666 | if(added==1){added_suffix=" ${_('file added')} ";} |
|
666 | if(added==1){added_suffix=" ${_('file added')} ";} | |
667 | if(changed==1){changed_suffix=" ${_('file changed')} ";} |
|
667 | if(changed==1){changed_suffix=" ${_('file changed')} ";} | |
668 | if(removed==1){removed_suffix=" ${_('file removed')} ";} |
|
668 | if(removed==1){removed_suffix=" ${_('file removed')} ";} | |
669 |
|
669 | |||
670 | showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd |
|
670 | showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd | |
671 | +'<br/>'+ |
|
671 | +'<br/>'+ | |
672 | nr_commits + nr_commits_suffix+'<br/>'+ |
|
672 | nr_commits + nr_commits_suffix+'<br/>'+ | |
673 | added + added_suffix +'<br/>'+ |
|
673 | added + added_suffix +'<br/>'+ | |
674 | changed + changed_suffix + '<br/>'+ |
|
674 | changed + changed_suffix + '<br/>'+ | |
675 | removed + removed_suffix + '<br/>'); |
|
675 | removed + removed_suffix + '<br/>'); | |
676 | } |
|
676 | } | |
677 | } |
|
677 | } | |
678 | else { |
|
678 | else { | |
679 | var tooltip = YUD.get("tooltip"); |
|
679 | var tooltip = YUD.get("tooltip"); | |
680 |
|
680 | |||
681 | if(tooltip) { |
|
681 | if(tooltip) { | |
682 | tooltip.parentNode.removeChild(tooltip); |
|
682 | tooltip.parentNode.removeChild(tooltip); | |
683 | } |
|
683 | } | |
684 | previousPoint = null; |
|
684 | previousPoint = null; | |
685 | } |
|
685 | } | |
686 | } |
|
686 | } | |
687 |
|
687 | |||
688 | /** |
|
688 | /** | |
689 | * MAIN EXECUTION |
|
689 | * MAIN EXECUTION | |
690 | */ |
|
690 | */ | |
691 |
|
691 | |||
692 | var data = getDataAccordingToRanges(initial_ranges); |
|
692 | var data = getDataAccordingToRanges(initial_ranges); | |
693 | generateCheckboxes(data); |
|
693 | generateCheckboxes(data); | |
694 |
|
694 | |||
695 | //main plot |
|
695 | //main plot | |
696 | var plot = YAHOO.widget.Flot(plotContainer,data,plot_options); |
|
696 | var plot = YAHOO.widget.Flot(plotContainer,data,plot_options); | |
697 |
|
697 | |||
698 | //overview |
|
698 | //overview | |
699 | var overview = YAHOO.widget.Flot(overviewContainer, |
|
699 | var overview = YAHOO.widget.Flot(overviewContainer, | |
700 | overview_dataset, overview_options); |
|
700 | overview_dataset, overview_options); | |
701 |
|
701 | |||
702 | //show initial selection on overview |
|
702 | //show initial selection on overview | |
703 | overview.setSelection(initial_ranges); |
|
703 | overview.setSelection(initial_ranges); | |
704 |
|
704 | |||
705 | plot.subscribe("plotselected", plotselected); |
|
705 | plot.subscribe("plotselected", plotselected); | |
706 | plot.subscribe("plothover", plothover) |
|
706 | plot.subscribe("plothover", plothover) | |
707 |
|
707 | |||
708 | overview.subscribe("plotselected", function (ranges) { |
|
708 | overview.subscribe("plotselected", function (ranges) { | |
709 | plot.setSelection(ranges); |
|
709 | plot.setSelection(ranges); | |
710 | }); |
|
710 | }); | |
711 |
|
711 | |||
712 | // user choices on overview |
|
712 | // user choices on overview | |
713 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]); |
|
713 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]); | |
714 | } |
|
714 | } | |
715 | SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n}); |
|
715 | SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n}); | |
716 | </script> |
|
716 | </script> | |
717 | %endif |
|
717 | %endif | |
718 |
|
718 | |||
719 | </%def> |
|
719 | </%def> |
@@ -1,79 +1,78 b'' | |||||
1 | import time |
|
1 | import time | |
2 | from rhodecode.tests import * |
|
2 | from rhodecode.tests import * | |
3 | from rhodecode.model.meta import Session |
|
3 | from rhodecode.model.meta import Session | |
4 | from rhodecode.model.db import User, RhodeCodeSetting, Repository |
|
4 | from rhodecode.model.db import User, RhodeCodeSetting, Repository | |
5 | from rhodecode.lib.utils import set_rhodecode_config |
|
5 | from rhodecode.lib.utils import set_rhodecode_config | |
6 |
|
6 | |||
7 |
|
7 | |||
8 | class TestHomeController(TestController): |
|
8 | class TestHomeController(TestController): | |
9 |
|
9 | |||
10 | def test_index(self): |
|
10 | def test_index(self): | |
11 | self.log_user() |
|
11 | self.log_user() | |
12 | response = self.app.get(url(controller='home', action='index')) |
|
12 | response = self.app.get(url(controller='home', action='index')) | |
13 | #if global permission is set |
|
13 | #if global permission is set | |
14 | response.mustcontain('ADD REPOSITORY') |
|
14 | response.mustcontain('ADD REPOSITORY') | |
15 | response.mustcontain('href="/%s/summary"' % HG_REPO) |
|
15 | response.mustcontain('href="/%s/summary"' % HG_REPO) | |
16 |
|
16 | |||
17 | response.mustcontain("""<img class="icon" title="Mercurial repository" """ |
|
17 | response.mustcontain("""<img class="icon" title="Mercurial repository" """ | |
18 | """alt="Mercurial repository" src="/images/icons/hg""" |
|
18 | """alt="Mercurial repository" src="/images/icons/hg""" | |
19 | """icon.png"/>""") |
|
19 | """icon.png"/>""") | |
20 | response.mustcontain("""<img class="icon" title="public repository" """ |
|
20 | response.mustcontain("""<img class="icon" title="public repository" """ | |
21 | """alt="public repository" src="/images/icons/lock_""" |
|
21 | """alt="public repository" src="/images/icons/lock_""" | |
22 | """open.png"/>""") |
|
22 | """open.png"/>""") | |
23 |
|
23 | |||
24 | response.mustcontain( |
|
24 | response.mustcontain( | |
25 | """<a title="Marcin Kuzminski &lt;marcin@python-works.com&gt;:\n |
|
25 | """<a title="Marcin Kuzminski &lt;marcin@python-works.com&gt;:\n | |
26 | merge" class="tooltip" href="/vcs_test_hg/changeset/27cd5cce30c96924232""" |
|
26 | merge" class="tooltip" href="/vcs_test_hg/changeset/27cd5cce30c96924232""" | |
27 | """dffcd24178a07ffeb5dfc">r173:27cd5cce30c9</a>""" |
|
27 | """dffcd24178a07ffeb5dfc">r173:27cd5cce30c9</a>""" | |
28 | ) |
|
28 | ) | |
29 |
|
29 | |||
30 | def test_repo_summary_with_anonymous_access_disabled(self): |
|
30 | def test_repo_summary_with_anonymous_access_disabled(self): | |
31 | anon = User.get_by_username('default') |
|
31 | anon = User.get_by_username('default') | |
32 | anon.active = False |
|
32 | anon.active = False | |
33 | Session().add(anon) |
|
33 | Session().add(anon) | |
34 | Session().commit() |
|
34 | Session().commit() | |
35 | time.sleep(1.5) # must sleep for cache (1s to expire) |
|
35 | time.sleep(1.5) # must sleep for cache (1s to expire) | |
36 | try: |
|
36 | try: | |
37 | response = self.app.get(url(controller='summary', |
|
37 | response = self.app.get(url(controller='summary', | |
38 | action='index', repo_name=HG_REPO), |
|
38 | action='index', repo_name=HG_REPO), | |
39 | status=302) |
|
39 | status=302) | |
40 | assert 'login' in response.location |
|
40 | assert 'login' in response.location | |
41 |
|
41 | |||
42 | finally: |
|
42 | finally: | |
43 | anon = User.get_by_username('default') |
|
43 | anon = User.get_by_username('default') | |
44 | anon.active = True |
|
44 | anon.active = True | |
45 | Session().add(anon) |
|
45 | Session().add(anon) | |
46 | Session().commit() |
|
46 | Session().commit() | |
47 |
|
47 | |||
48 | def test_index_with_anonymous_access_disabled(self): |
|
48 | def test_index_with_anonymous_access_disabled(self): | |
49 | anon = User.get_by_username('default') |
|
49 | anon = User.get_by_username('default') | |
50 | anon.active = False |
|
50 | anon.active = False | |
51 | Session().add(anon) |
|
51 | Session().add(anon) | |
52 | Session().commit() |
|
52 | Session().commit() | |
53 | time.sleep(1.5) # must sleep for cache (1s to expire) |
|
53 | time.sleep(1.5) # must sleep for cache (1s to expire) | |
54 | try: |
|
54 | try: | |
55 | response = self.app.get(url(controller='home', action='index'), |
|
55 | response = self.app.get(url(controller='home', action='index'), | |
56 | status=302) |
|
56 | status=302) | |
57 | assert 'login' in response.location |
|
57 | assert 'login' in response.location | |
58 | finally: |
|
58 | finally: | |
59 | anon = User.get_by_username('default') |
|
59 | anon = User.get_by_username('default') | |
60 | anon.active = True |
|
60 | anon.active = True | |
61 | Session().add(anon) |
|
61 | Session().add(anon) | |
62 | Session().commit() |
|
62 | Session().commit() | |
63 |
|
63 | |||
64 | def test_index_with_lightweight_dashboard(self): |
|
64 | def test_index_with_lightweight_dashboard(self): | |
65 | self.log_user() |
|
65 | self.log_user() | |
66 |
|
66 | |||
67 | def set_l_dash(set_to): |
|
67 | def set_l_dash(set_to): | |
68 | self.app.post(url('admin_setting', setting_id='visual'), |
|
68 | self.app.post(url('admin_setting', setting_id='visual'), | |
69 | params=dict(_method='put', |
|
69 | params=dict(_method='put', | |
70 | rhodecode_lightweight_dashboard=set_to,)) |
|
70 | rhodecode_lightweight_dashboard=set_to,)) | |
71 |
|
71 | |||
72 | set_l_dash(True) |
|
72 | set_l_dash(True) | |
73 |
|
73 | |||
74 | try: |
|
74 | try: | |
75 | response = self.app.get(url(controller='home', action='index')) |
|
75 | response = self.app.get(url(controller='home', action='index')) | |
76 | response.mustcontain("""var data = {"totalRecords": %s""" % len(Repository.getAll())) |
|
76 | response.mustcontain("""var data = {"totalRecords": %s""" % len(Repository.getAll())) | |
77 | finally: |
|
77 | finally: | |
78 | set_l_dash(False) |
|
78 | set_l_dash(False) | |
79 |
|
General Comments 0
You need to be logged in to leave comments.
Login now