##// END OF EJS Templates
added useful system info + packages to settings page.
marcink -
r2192:a801c454 beta
parent child Browse files
Show More
@@ -1,414 +1,421 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.settings
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 settings controller for rhodecode admin
7 7
8 8 :created_on: Jul 14, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 import pkg_resources
30 import platform
29 31
30 32 from sqlalchemy import func
31 33 from formencode import htmlfill
32 34 from pylons import request, session, tmpl_context as c, url, config
33 35 from pylons.controllers.util import abort, redirect
34 36 from pylons.i18n.translation import _
35 37
36 38 from rhodecode.lib import helpers as h
37 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
38 40 HasPermissionAnyDecorator, NotAnonymous
39 41 from rhodecode.lib.base import BaseController, render
40 42 from rhodecode.lib.celerylib import tasks, run_task
41 43 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
42 44 set_rhodecode_config, repo_name_slug
43 45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
44 46 RhodeCodeSetting
45 47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
46 48 ApplicationUiSettingsForm
47 49 from rhodecode.model.scm import ScmModel
48 50 from rhodecode.model.user import UserModel
49 51 from rhodecode.model.db import User
50 52 from rhodecode.model.notification import EmailNotificationModel
51 53 from rhodecode.model.meta import Session
52 54
53 55 log = logging.getLogger(__name__)
54 56
55 57
56 58 class SettingsController(BaseController):
57 59 """REST Controller styled on the Atom Publishing Protocol"""
58 60 # To properly map this controller, ensure your config/routing.py
59 61 # file has a resource setup:
60 62 # map.resource('setting', 'settings', controller='admin/settings',
61 63 # path_prefix='/admin', name_prefix='admin_')
62 64
63 65 @LoginRequired()
64 66 def __before__(self):
65 67 c.admin_user = session.get('admin_user')
66 68 c.admin_username = session.get('admin_username')
69 c.modules = sorted([(p.project_name, p.version)
70 for p in pkg_resources.working_set])
71 c.py_version = platform.python_version()
72 c.platform = platform.platform()
67 73 super(SettingsController, self).__before__()
68 74
69 75 @HasPermissionAllDecorator('hg.admin')
70 76 def index(self, format='html'):
71 77 """GET /admin/settings: All items in the collection"""
72 78 # url('admin_settings')
73 79
74 80 defaults = RhodeCodeSetting.get_app_settings()
75 81 defaults.update(self.get_hg_ui_settings())
82
76 83 return htmlfill.render(
77 84 render('admin/settings/settings.html'),
78 85 defaults=defaults,
79 86 encoding="UTF-8",
80 87 force_defaults=False
81 88 )
82 89
83 90 @HasPermissionAllDecorator('hg.admin')
84 91 def create(self):
85 92 """POST /admin/settings: Create a new item"""
86 93 # url('admin_settings')
87 94
88 95 @HasPermissionAllDecorator('hg.admin')
89 96 def new(self, format='html'):
90 97 """GET /admin/settings/new: Form to create a new item"""
91 98 # url('admin_new_setting')
92 99
93 100 @HasPermissionAllDecorator('hg.admin')
94 101 def update(self, setting_id):
95 102 """PUT /admin/settings/setting_id: Update an existing item"""
96 103 # Forms posted to this method should contain a hidden field:
97 104 # <input type="hidden" name="_method" value="PUT" />
98 105 # Or using helpers:
99 106 # h.form(url('admin_setting', setting_id=ID),
100 107 # method='put')
101 108 # url('admin_setting', setting_id=ID)
102 109 if setting_id == 'mapping':
103 110 rm_obsolete = request.POST.get('destroy', False)
104 111 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
105 112 initial = ScmModel().repo_scan()
106 113 log.debug('invalidating all repositories')
107 114 for repo_name in initial.keys():
108 115 invalidate_cache('get_repo_cached_%s' % repo_name)
109 116
110 117 added, removed = repo2db_mapper(initial, rm_obsolete)
111 118
112 119 h.flash(_('Repositories successfully'
113 120 ' rescanned added: %s,removed: %s') % (added, removed),
114 121 category='success')
115 122
116 123 if setting_id == 'whoosh':
117 124 repo_location = self.get_hg_ui_settings()['paths_root_path']
118 125 full_index = request.POST.get('full_index', False)
119 126 run_task(tasks.whoosh_index, repo_location, full_index)
120 127
121 128 h.flash(_('Whoosh reindex task scheduled'), category='success')
122 129 if setting_id == 'global':
123 130
124 131 application_form = ApplicationSettingsForm()()
125 132 try:
126 133 form_result = application_form.to_python(dict(request.POST))
127 134
128 135 try:
129 136 hgsettings1 = RhodeCodeSetting.get_by_name('title')
130 137 hgsettings1.app_settings_value = \
131 138 form_result['rhodecode_title']
132 139
133 140 hgsettings2 = RhodeCodeSetting.get_by_name('realm')
134 141 hgsettings2.app_settings_value = \
135 142 form_result['rhodecode_realm']
136 143
137 144 hgsettings3 = RhodeCodeSetting.get_by_name('ga_code')
138 145 hgsettings3.app_settings_value = \
139 146 form_result['rhodecode_ga_code']
140 147
141 148 self.sa.add(hgsettings1)
142 149 self.sa.add(hgsettings2)
143 150 self.sa.add(hgsettings3)
144 151 self.sa.commit()
145 152 set_rhodecode_config(config)
146 153 h.flash(_('Updated application settings'),
147 154 category='success')
148 155
149 156 except Exception:
150 157 log.error(traceback.format_exc())
151 158 h.flash(_('error occurred during updating '
152 159 'application settings'),
153 160 category='error')
154 161
155 162 self.sa.rollback()
156 163
157 164 except formencode.Invalid, errors:
158 165 return htmlfill.render(
159 166 render('admin/settings/settings.html'),
160 167 defaults=errors.value,
161 168 errors=errors.error_dict or {},
162 169 prefix_error=False,
163 170 encoding="UTF-8")
164 171
165 172 if setting_id == 'mercurial':
166 173 application_form = ApplicationUiSettingsForm()()
167 174 try:
168 175 form_result = application_form.to_python(dict(request.POST))
169 176
170 177 try:
171 178
172 179 hgsettings1 = self.sa.query(RhodeCodeUi)\
173 180 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
174 181 hgsettings1.ui_value = form_result['web_push_ssl']
175 182
176 183 hgsettings2 = self.sa.query(RhodeCodeUi)\
177 184 .filter(RhodeCodeUi.ui_key == '/').one()
178 185 hgsettings2.ui_value = form_result['paths_root_path']
179 186
180 187 #HOOKS
181 188 hgsettings3 = self.sa.query(RhodeCodeUi)\
182 189 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
183 190 hgsettings3.ui_active = \
184 191 bool(form_result['hooks_changegroup_update'])
185 192
186 193 hgsettings4 = self.sa.query(RhodeCodeUi)\
187 194 .filter(RhodeCodeUi.ui_key ==
188 195 'changegroup.repo_size').one()
189 196 hgsettings4.ui_active = \
190 197 bool(form_result['hooks_changegroup_repo_size'])
191 198
192 199 hgsettings5 = self.sa.query(RhodeCodeUi)\
193 200 .filter(RhodeCodeUi.ui_key ==
194 201 'pretxnchangegroup.push_logger').one()
195 202 hgsettings5.ui_active = \
196 203 bool(form_result['hooks_pretxnchangegroup'
197 204 '_push_logger'])
198 205
199 206 hgsettings6 = self.sa.query(RhodeCodeUi)\
200 207 .filter(RhodeCodeUi.ui_key ==
201 208 'preoutgoing.pull_logger').one()
202 209 hgsettings6.ui_active = \
203 210 bool(form_result['hooks_preoutgoing_pull_logger'])
204 211
205 212 self.sa.add(hgsettings1)
206 213 self.sa.add(hgsettings2)
207 214 self.sa.add(hgsettings3)
208 215 self.sa.add(hgsettings4)
209 216 self.sa.add(hgsettings5)
210 217 self.sa.add(hgsettings6)
211 218 self.sa.commit()
212 219
213 220 h.flash(_('Updated mercurial settings'),
214 221 category='success')
215 222
216 223 except:
217 224 log.error(traceback.format_exc())
218 225 h.flash(_('error occurred during updating '
219 226 'application settings'), category='error')
220 227
221 228 self.sa.rollback()
222 229
223 230 except formencode.Invalid, errors:
224 231 return htmlfill.render(
225 232 render('admin/settings/settings.html'),
226 233 defaults=errors.value,
227 234 errors=errors.error_dict or {},
228 235 prefix_error=False,
229 236 encoding="UTF-8")
230 237
231 238 if setting_id == 'hooks':
232 239 ui_key = request.POST.get('new_hook_ui_key')
233 240 ui_value = request.POST.get('new_hook_ui_value')
234 241 try:
235 242
236 243 if ui_value and ui_key:
237 244 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
238 245 h.flash(_('Added new hook'),
239 246 category='success')
240 247
241 248 # check for edits
242 249 update = False
243 250 _d = request.POST.dict_of_lists()
244 251 for k, v in zip(_d.get('hook_ui_key', []),
245 252 _d.get('hook_ui_value_new', [])):
246 253 RhodeCodeUi.create_or_update_hook(k, v)
247 254 update = True
248 255
249 256 if update:
250 257 h.flash(_('Updated hooks'), category='success')
251 258 self.sa.commit()
252 259 except:
253 260 log.error(traceback.format_exc())
254 261 h.flash(_('error occurred during hook creation'),
255 262 category='error')
256 263
257 264 return redirect(url('admin_edit_setting', setting_id='hooks'))
258 265
259 266 if setting_id == 'email':
260 267 test_email = request.POST.get('test_email')
261 268 test_email_subj = 'RhodeCode TestEmail'
262 269 test_email_body = 'RhodeCode Email test'
263 270
264 271 test_email_html_body = EmailNotificationModel()\
265 272 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
266 273 body=test_email_body)
267 274
268 275 recipients = [test_email] if [test_email] else None
269 276
270 277 run_task(tasks.send_email, recipients, test_email_subj,
271 278 test_email_body, test_email_html_body)
272 279
273 280 h.flash(_('Email task created'), category='success')
274 281 return redirect(url('admin_settings'))
275 282
276 283 @HasPermissionAllDecorator('hg.admin')
277 284 def delete(self, setting_id):
278 285 """DELETE /admin/settings/setting_id: Delete an existing item"""
279 286 # Forms posted to this method should contain a hidden field:
280 287 # <input type="hidden" name="_method" value="DELETE" />
281 288 # Or using helpers:
282 289 # h.form(url('admin_setting', setting_id=ID),
283 290 # method='delete')
284 291 # url('admin_setting', setting_id=ID)
285 292 if setting_id == 'hooks':
286 293 hook_id = request.POST.get('hook_id')
287 294 RhodeCodeUi.delete(hook_id)
288 295 self.sa.commit()
289 296
290 297 @HasPermissionAllDecorator('hg.admin')
291 298 def show(self, setting_id, format='html'):
292 299 """
293 300 GET /admin/settings/setting_id: Show a specific item"""
294 301 # url('admin_setting', setting_id=ID)
295 302
296 303 @HasPermissionAllDecorator('hg.admin')
297 304 def edit(self, setting_id, format='html'):
298 305 """
299 306 GET /admin/settings/setting_id/edit: Form to
300 307 edit an existing item"""
301 308 # url('admin_edit_setting', setting_id=ID)
302 309
303 310 c.hooks = RhodeCodeUi.get_builtin_hooks()
304 311 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
305 312
306 313 return htmlfill.render(
307 314 render('admin/settings/hooks.html'),
308 315 defaults={},
309 316 encoding="UTF-8",
310 317 force_defaults=False
311 318 )
312 319
313 320 @NotAnonymous()
314 321 def my_account(self):
315 322 """
316 323 GET /_admin/my_account Displays info about my account
317 324 """
318 325 # url('admin_settings_my_account')
319 326
320 327 c.user = User.get(self.rhodecode_user.user_id)
321 328 all_repos = self.sa.query(Repository)\
322 329 .filter(Repository.user_id == c.user.user_id)\
323 330 .order_by(func.lower(Repository.repo_name)).all()
324 331
325 332 c.user_repos = ScmModel().get_repos(all_repos)
326 333
327 334 if c.user.username == 'default':
328 335 h.flash(_("You can't edit this user since it's"
329 336 " crucial for entire application"), category='warning')
330 337 return redirect(url('users'))
331 338
332 339 defaults = c.user.get_dict()
333 340 return htmlfill.render(
334 341 render('admin/users/user_edit_my_account.html'),
335 342 defaults=defaults,
336 343 encoding="UTF-8",
337 344 force_defaults=False
338 345 )
339 346
340 347 def my_account_update(self):
341 348 """PUT /_admin/my_account_update: Update an existing item"""
342 349 # Forms posted to this method should contain a hidden field:
343 350 # <input type="hidden" name="_method" value="PUT" />
344 351 # Or using helpers:
345 352 # h.form(url('admin_settings_my_account_update'),
346 353 # method='put')
347 354 # url('admin_settings_my_account_update', id=ID)
348 355 user_model = UserModel()
349 356 uid = self.rhodecode_user.user_id
350 357 _form = UserForm(edit=True,
351 358 old_data={'user_id': uid,
352 359 'email': self.rhodecode_user.email})()
353 360 form_result = {}
354 361 try:
355 362 form_result = _form.to_python(dict(request.POST))
356 363 user_model.update_my_account(uid, form_result)
357 364 h.flash(_('Your account was updated successfully'),
358 365 category='success')
359 366 Session.commit()
360 367 except formencode.Invalid, errors:
361 368 c.user = User.get(self.rhodecode_user.user_id)
362 369 all_repos = self.sa.query(Repository)\
363 370 .filter(Repository.user_id == c.user.user_id)\
364 371 .order_by(func.lower(Repository.repo_name))\
365 372 .all()
366 373 c.user_repos = ScmModel().get_repos(all_repos)
367 374
368 375 return htmlfill.render(
369 376 render('admin/users/user_edit_my_account.html'),
370 377 defaults=errors.value,
371 378 errors=errors.error_dict or {},
372 379 prefix_error=False,
373 380 encoding="UTF-8")
374 381 except Exception:
375 382 log.error(traceback.format_exc())
376 383 h.flash(_('error occurred during update of user %s') \
377 384 % form_result.get('username'), category='error')
378 385
379 386 return redirect(url('my_account'))
380 387
381 388 @NotAnonymous()
382 389 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
383 390 def create_repository(self):
384 391 """GET /_admin/create_repository: Form to create a new item"""
385 392
386 393 c.repo_groups = RepoGroup.groups_choices()
387 394 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
388 395
389 396 new_repo = request.GET.get('repo', '')
390 397 c.new_repo = repo_name_slug(new_repo)
391 398
392 399 return render('admin/repos/repo_add_create_repository.html')
393 400
394 401 def get_hg_ui_settings(self):
395 402 ret = self.sa.query(RhodeCodeUi).all()
396 403
397 404 if not ret:
398 405 raise Exception('Could not get application ui settings !')
399 406 settings = {}
400 407 for each in ret:
401 408 k = each.ui_key
402 409 v = each.ui_value
403 410 if k == '/':
404 411 k = 'root_path'
405 412
406 413 if k.find('.') != -1:
407 414 k = k.replace('.', '_')
408 415
409 416 if each.ui_section == 'hooks':
410 417 v = each.ui_active
411 418
412 419 settings[each.ui_section + '_' + k] = v
413 420
414 421 return settings
@@ -1,214 +1,246 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Settings administration')} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Settings')}
10 10 </%def>
11 11
12 12 <%def name="page_nav()">
13 13 ${self.menu('admin')}
14 14 </%def>
15 15
16 16 <%def name="main()">
17 17 <div class="box">
18 18 <!-- box / title -->
19 19 <div class="title">
20 20 ${self.breadcrumbs()}
21 21 </div>
22 22 <!-- end box / title -->
23 23
24 24 <h3>${_('Remap and rescan repositories')}</h3>
25 25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
26 26 <div class="form">
27 27 <!-- fields -->
28 28
29 29 <div class="fields">
30 30 <div class="field">
31 31 <div class="label label-checkbox">
32 32 <label for="destroy">${_('rescan option')}:</label>
33 33 </div>
34 34 <div class="checkboxes">
35 35 <div class="checkbox">
36 36 ${h.checkbox('destroy',True)}
37 37 <label for="destroy">
38 38 <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
39 39 ${_('destroy old data')}</span> </label>
40 40 </div>
41 41 </div>
42 42 </div>
43 43
44 44 <div class="buttons">
45 45 ${h.submit('rescan',_('Rescan repositories'),class_="ui-button")}
46 46 </div>
47 47 </div>
48 48 </div>
49 49 ${h.end_form()}
50 50
51 51 <h3>${_('Whoosh indexing')}</h3>
52 52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
53 53 <div class="form">
54 54 <!-- fields -->
55 55
56 56 <div class="fields">
57 57 <div class="field">
58 58 <div class="label label-checkbox">
59 59 <label>${_('index build option')}:</label>
60 60 </div>
61 61 <div class="checkboxes">
62 62 <div class="checkbox">
63 63 ${h.checkbox('full_index',True)}
64 64 <label for="full_index">${_('build from scratch')}</label>
65 65 </div>
66 66 </div>
67 67 </div>
68 68
69 69 <div class="buttons">
70 70 ${h.submit('reindex',_('Reindex'),class_="ui-button")}
71 71 </div>
72 72 </div>
73 73 </div>
74 74 ${h.end_form()}
75 75
76 76 <h3>${_('Global application settings')}</h3>
77 77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
78 78 <div class="form">
79 79 <!-- fields -->
80 80
81 81 <div class="fields">
82 82
83 83 <div class="field">
84 84 <div class="label">
85 85 <label for="rhodecode_title">${_('Application name')}:</label>
86 86 </div>
87 87 <div class="input">
88 88 ${h.text('rhodecode_title',size=30)}
89 89 </div>
90 90 </div>
91 91
92 92 <div class="field">
93 93 <div class="label">
94 94 <label for="rhodecode_realm">${_('Realm text')}:</label>
95 95 </div>
96 96 <div class="input">
97 97 ${h.text('rhodecode_realm',size=30)}
98 98 </div>
99 99 </div>
100 100
101 101 <div class="field">
102 102 <div class="label">
103 103 <label for="rhodecode_ga_code">${_('GA code')}:</label>
104 104 </div>
105 105 <div class="input">
106 106 ${h.text('rhodecode_ga_code',size=30)}
107 107 </div>
108 108 </div>
109 109
110 110 <div class="buttons">
111 111 ${h.submit('save',_('Save settings'),class_="ui-button")}
112 112 ${h.reset('reset',_('Reset'),class_="ui-button")}
113 113 </div>
114 114 </div>
115 115 </div>
116 116 ${h.end_form()}
117 117
118 118 <h3>${_('Mercurial settings')}</h3>
119 119 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
120 120 <div class="form">
121 121 <!-- fields -->
122 122
123 123 <div class="fields">
124 124
125 125 <div class="field">
126 126 <div class="label label-checkbox">
127 127 <label>${_('Web')}:</label>
128 128 </div>
129 129 <div class="checkboxes">
130 130 <div class="checkbox">
131 131 ${h.checkbox('web_push_ssl','true')}
132 132 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
133 133 </div>
134 134 </div>
135 135 </div>
136 136
137 137 <div class="field">
138 138 <div class="label label-checkbox">
139 139 <label>${_('Hooks')}:</label>
140 140 </div>
141 141 <div class="checkboxes">
142 142 <div class="checkbox">
143 143 ${h.checkbox('hooks_changegroup_update','True')}
144 144 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
145 145 </div>
146 146 <div class="checkbox">
147 147 ${h.checkbox('hooks_changegroup_repo_size','True')}
148 148 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
149 149 </div>
150 150 <div class="checkbox">
151 151 ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
152 152 <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
153 153 </div>
154 154 <div class="checkbox">
155 155 ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
156 156 <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
157 157 </div>
158 158 </div>
159 159 <div class="input" style="margin-top:10px">
160 160 ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'),class_="ui-btn")}
161 161 </div>
162 162 </div>
163 163 <div class="field">
164 164 <div class="label">
165 165 <label for="paths_root_path">${_('Repositories location')}:</label>
166 166 </div>
167 167 <div class="input">
168 168 ${h.text('paths_root_path',size=30,readonly="readonly")}
169 169 <span id="path_unlock" class="tooltip"
170 170 title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
171 171 ${_('unlock')}</span>
172 172 </div>
173 173 </div>
174 174
175 175 <div class="buttons">
176 176 ${h.submit('save',_('Save settings'),class_="ui-button")}
177 177 ${h.reset('reset',_('Reset'),class_="ui-button")}
178 178 </div>
179 179 </div>
180 180 </div>
181 181 ${h.end_form()}
182 182
183 183 <script type="text/javascript">
184 184 YAHOO.util.Event.onDOMReady(function(){
185 185 YAHOO.util.Event.addListener('path_unlock','click',function(){
186 186 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
187 187 });
188 188 });
189 189 </script>
190 190
191 191 <h3>${_('Test Email')}</h3>
192 192 ${h.form(url('admin_setting', setting_id='email'),method='put')}
193 193 <div class="form">
194 194 <!-- fields -->
195 195
196 196 <div class="fields">
197 197 <div class="field">
198 198 <div class="label">
199 199 <label for="test_email">${_('Email to')}:</label>
200 200 </div>
201 201 <div class="input">
202 202 ${h.text('test_email',size=30)}
203 203 </div>
204 204 </div>
205 205
206 206 <div class="buttons">
207 207 ${h.submit('send',_('Send'),class_="ui-button")}
208 208 </div>
209 209 </div>
210 210 </div>
211 211 ${h.end_form()}
212 212
213 <h3>${_('System Info and Packages')}</h3>
214 <div class="form">
215 <div>
216 <h5 id="expand_modules" style="cursor: pointer">&darr; ${_('show')} &darr;</h5>
217 </div>
218 <div id="expand_modules_table" style="display:none">
219 <h5>Python - ${c.py_version}</h5>
220 <h5>System - ${c.platform}</h5>
221
222 <table class="table" style="margin:0px 0px 0px 20px">
223 <colgroup>
224 <col style="width:220px">
225 </colgroup>
226 <tbody>
227 %for key, value in c.modules:
228 <tr>
229 <th>${key}</th>
230 <td>${value}</td>
231 </tr>
232 %endfor
233 </tbody>
234 </table>
235 </div>
236 </div>
237
238 <script type="text/javascript">
239 YUE.on('expand_modules','click',function(e){
240 YUD.setStyle('expand_modules_table','display','');
241 YUD.setStyle('expand_modules','display','none');
242 })
243 </script>
244
213 245 </div>
214 246 </%def>
General Comments 0
You need to be logged in to leave comments. Login now